kern_ksyms.c revision 1.99 1 /* $NetBSD: kern_ksyms.c,v 1.99 2021/09/07 10:59:46 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software developed for The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 2001, 2003 Anders Magnusson (ragge (at) ludd.luth.se).
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. The name of the author may not be used to endorse or promote products
45 * derived from this software without specific prior written permission
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58
59 /*
60 * Code to deal with in-kernel symbol table management + /dev/ksyms.
61 *
62 * For each loaded module the symbol table info is kept track of by a
63 * struct, placed in a circular list. The first entry is the kernel
64 * symbol table.
65 */
66
67 /*
68 * TODO:
69 *
70 * Add support for mmap, poll.
71 * Constify tables.
72 * Constify db_symtab and move it to .rodata.
73 */
74
75 #include <sys/cdefs.h>
76 __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.99 2021/09/07 10:59:46 riastradh Exp $");
77
78 #if defined(_KERNEL) && defined(_KERNEL_OPT)
79 #include "opt_copy_symtab.h"
80 #include "opt_ddb.h"
81 #include "opt_dtrace.h"
82 #endif
83
84 #define _KSYMS_PRIVATE
85
86 #include <sys/param.h>
87 #include <sys/queue.h>
88 #include <sys/exec.h>
89 #include <sys/systm.h>
90 #include <sys/conf.h>
91 #include <sys/kmem.h>
92 #include <sys/proc.h>
93 #include <sys/atomic.h>
94 #include <sys/ksyms.h>
95 #include <sys/kernel.h>
96 #include <sys/intr.h>
97
98 #ifdef DDB
99 #include <ddb/db_output.h>
100 #endif
101
102 #include "ksyms.h"
103 #if NKSYMS > 0
104 #include "ioconf.h"
105 #endif
106
107 #define KSYMS_MAX_ID 98304
108 #ifdef KDTRACE_HOOKS
109 static uint32_t ksyms_nmap[KSYMS_MAX_ID]; /* sorted symbol table map */
110 #else
111 static uint32_t *ksyms_nmap = NULL;
112 #endif
113
114 static int ksyms_maxlen;
115 static uint64_t ksyms_opencnt;
116 static struct ksyms_symtab *ksyms_last_snapshot;
117 static bool ksyms_initted;
118 static bool ksyms_loaded;
119 static kmutex_t ksyms_lock __cacheline_aligned;
120 static kcondvar_t ksyms_cv;
121 static struct ksyms_symtab kernel_symtab;
122
123 static void ksyms_hdr_init(const void *);
124 static void ksyms_sizes_calc(void);
125
126 #ifdef KSYMS_DEBUG
127 #define FOLLOW_CALLS 1
128 #define FOLLOW_MORE_CALLS 2
129 #define FOLLOW_DEVKSYMS 4
130 static int ksyms_debug;
131 #endif
132
133 #define SYMTAB_FILLER "|This is the symbol table!"
134
135 #ifdef makeoptions_COPY_SYMTAB
136 extern char db_symtab[];
137 extern int db_symtabsize;
138 #endif
139
140 /*
141 * used by savecore(8) so non-static
142 */
143 struct ksyms_hdr ksyms_hdr;
144 int ksyms_symsz;
145 int ksyms_strsz;
146 int ksyms_ctfsz; /* this is not currently used by savecore(8) */
147 TAILQ_HEAD(ksyms_symtab_queue, ksyms_symtab) ksyms_symtabs =
148 TAILQ_HEAD_INITIALIZER(ksyms_symtabs);
149
150 static int
151 ksyms_verify(const void *symstart, const void *strstart)
152 {
153 #if defined(DIAGNOSTIC) || defined(DEBUG)
154 if (symstart == NULL)
155 printf("ksyms: Symbol table not found\n");
156 if (strstart == NULL)
157 printf("ksyms: String table not found\n");
158 if (symstart == NULL || strstart == NULL)
159 printf("ksyms: Perhaps the kernel is stripped?\n");
160 #endif
161 if (symstart == NULL || strstart == NULL)
162 return 0;
163 return 1;
164 }
165
166 /*
167 * Finds a certain symbol name in a certain symbol table.
168 */
169 static Elf_Sym *
170 findsym(const char *name, struct ksyms_symtab *table, int type)
171 {
172 Elf_Sym *sym, *maxsym;
173 int low, mid, high, nglob;
174 char *str, *cmp;
175
176 sym = table->sd_symstart;
177 str = table->sd_strstart - table->sd_usroffset;
178 nglob = table->sd_nglob;
179 low = 0;
180 high = nglob;
181
182 /*
183 * Start with a binary search of all global symbols in this table.
184 * Global symbols must have unique names.
185 */
186 while (low < high) {
187 mid = (low + high) >> 1;
188 cmp = sym[mid].st_name + str;
189 if (cmp[0] < name[0] || strcmp(cmp, name) < 0) {
190 low = mid + 1;
191 } else {
192 high = mid;
193 }
194 }
195 KASSERT(low == high);
196 if (__predict_true(low < nglob &&
197 strcmp(sym[low].st_name + str, name) == 0)) {
198 KASSERT(ELF_ST_BIND(sym[low].st_info) == STB_GLOBAL);
199 return &sym[low];
200 }
201
202 /*
203 * Perform a linear search of local symbols (rare). Many local
204 * symbols with the same name can exist so are not included in
205 * the binary search.
206 */
207 if (type != KSYMS_EXTERN) {
208 maxsym = sym + table->sd_symsize / sizeof(Elf_Sym);
209 for (sym += nglob; sym < maxsym; sym++) {
210 if (strcmp(name, sym->st_name + str) == 0) {
211 return sym;
212 }
213 }
214 }
215 return NULL;
216 }
217
218 /*
219 * The "attach" is in reality done in ksyms_init().
220 */
221 #if NKSYMS > 0
222 /*
223 * ksyms can be loaded even if the kernel has a missing "pseudo-device ksyms"
224 * statement because ddb and modules require it. Fixing it properly requires
225 * fixing config to warn about required, but missing preudo-devices. For now,
226 * if we don't have the pseudo-device we don't need the attach function; this
227 * is fine, as it does nothing.
228 */
229 void
230 ksymsattach(int arg)
231 {
232 }
233 #endif
234
235 void
236 ksyms_init(void)
237 {
238
239 #ifdef makeoptions_COPY_SYMTAB
240 if (!ksyms_loaded &&
241 strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) {
242 ksyms_addsyms_elf(db_symtabsize, db_symtab,
243 db_symtab + db_symtabsize);
244 }
245 #endif
246
247 if (!ksyms_initted) {
248 mutex_init(&ksyms_lock, MUTEX_DEFAULT, IPL_NONE);
249 cv_init(&ksyms_cv, "ksyms");
250 ksyms_initted = true;
251 }
252 }
253
254 /*
255 * Are any symbols available?
256 */
257 bool
258 ksyms_available(void)
259 {
260
261 return ksyms_loaded;
262 }
263
264 /*
265 * Add a symbol table.
266 * This is intended for use when the symbol table and its corresponding
267 * string table are easily available. If they are embedded in an ELF
268 * image, use addsymtab_elf() instead.
269 *
270 * name - Symbol's table name.
271 * symstart, symsize - Address and size of the symbol table.
272 * strstart, strsize - Address and size of the string table.
273 * tab - Symbol table to be updated with this information.
274 * newstart - Address to which the symbol table has to be copied during
275 * shrinking. If NULL, it is not moved.
276 */
277 static const char *addsymtab_strstart;
278
279 static int
280 addsymtab_compar(const void *a, const void *b)
281 {
282 const Elf_Sym *sa, *sb;
283
284 sa = a;
285 sb = b;
286
287 /*
288 * Split the symbol table into two, with globals at the start
289 * and locals at the end.
290 */
291 if (ELF_ST_BIND(sa->st_info) != ELF_ST_BIND(sb->st_info)) {
292 if (ELF_ST_BIND(sa->st_info) == STB_GLOBAL) {
293 return -1;
294 }
295 if (ELF_ST_BIND(sb->st_info) == STB_GLOBAL) {
296 return 1;
297 }
298 }
299
300 /* Within each band, sort by name. */
301 return strcmp(sa->st_name + addsymtab_strstart,
302 sb->st_name + addsymtab_strstart);
303 }
304
305 static void
306 addsymtab(const char *name, void *symstart, size_t symsize,
307 void *strstart, size_t strsize, struct ksyms_symtab *tab,
308 void *newstart, void *ctfstart, size_t ctfsize, uint32_t *nmap)
309 {
310 Elf_Sym *sym, *nsym, ts;
311 int i, j, n, nglob;
312 char *str;
313 int nsyms = symsize / sizeof(Elf_Sym);
314 int s;
315
316 /* Sanity check for pre-allocated map table used during startup. */
317 if ((nmap == ksyms_nmap) && (nsyms >= KSYMS_MAX_ID)) {
318 printf("kern_ksyms: ERROR %d > %d, increase KSYMS_MAX_ID\n",
319 nsyms, KSYMS_MAX_ID);
320
321 /* truncate for now */
322 nsyms = KSYMS_MAX_ID - 1;
323 }
324
325 tab->sd_symstart = symstart;
326 tab->sd_symsize = symsize;
327 tab->sd_strstart = strstart;
328 tab->sd_strsize = strsize;
329 tab->sd_name = name;
330 tab->sd_minsym = UINTPTR_MAX;
331 tab->sd_maxsym = 0;
332 tab->sd_usroffset = 0;
333 tab->sd_ctfstart = ctfstart;
334 tab->sd_ctfsize = ctfsize;
335 tab->sd_nmap = nmap;
336 tab->sd_nmapsize = nsyms;
337 #ifdef KSYMS_DEBUG
338 printf("newstart %p sym %p ksyms_symsz %zu str %p strsz %zu send %p\n",
339 newstart, symstart, symsize, strstart, strsize,
340 tab->sd_strstart + tab->sd_strsize);
341 #endif
342
343 if (nmap) {
344 memset(nmap, 0, nsyms * sizeof(uint32_t));
345 }
346
347 /* Pack symbol table by removing all file name references. */
348 sym = tab->sd_symstart;
349 nsym = (Elf_Sym *)newstart;
350 str = tab->sd_strstart;
351 nglob = 0;
352 for (i = n = 0; i < nsyms; i++) {
353
354 /*
355 * This breaks CTF mapping, so don't do it when
356 * DTrace is enabled.
357 */
358 #ifndef KDTRACE_HOOKS
359 /*
360 * Remove useless symbols.
361 * Should actually remove all typeless symbols.
362 */
363 if (sym[i].st_name == 0)
364 continue; /* Skip nameless entries */
365 if (sym[i].st_shndx == SHN_UNDEF)
366 continue; /* Skip external references */
367 if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE)
368 continue; /* Skip filenames */
369 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
370 sym[i].st_value == 0 &&
371 strcmp(str + sym[i].st_name, "*ABS*") == 0)
372 continue; /* XXX */
373 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
374 strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0)
375 continue; /* XXX */
376 #endif
377
378 /* Save symbol. Set it as an absolute offset */
379 nsym[n] = sym[i];
380
381 #ifdef KDTRACE_HOOKS
382 if (nmap != NULL) {
383 /*
384 * Save the size, replace it with the symbol id so
385 * the mapping can be done after the cleanup and sort.
386 */
387 nmap[i] = nsym[n].st_size;
388 nsym[n].st_size = i + 1; /* zero is reserved */
389 }
390 #endif
391
392 if (sym[i].st_shndx != SHN_ABS) {
393 nsym[n].st_shndx = SHBSS;
394 } else {
395 /* SHN_ABS is a magic value, don't overwrite it */
396 }
397
398 j = strlen(nsym[n].st_name + str) + 1;
399 if (j > ksyms_maxlen)
400 ksyms_maxlen = j;
401 nglob += (ELF_ST_BIND(nsym[n].st_info) == STB_GLOBAL);
402
403 /* Compute min and max symbols. */
404 if (strcmp(str + sym[i].st_name, "*ABS*") != 0
405 && ELF_ST_TYPE(nsym[n].st_info) != STT_NOTYPE) {
406 if (nsym[n].st_value < tab->sd_minsym) {
407 tab->sd_minsym = nsym[n].st_value;
408 }
409 if (nsym[n].st_value > tab->sd_maxsym) {
410 tab->sd_maxsym = nsym[n].st_value;
411 }
412 }
413 n++;
414 }
415
416 /* Fill the rest of the record, and sort the symbols. */
417 tab->sd_symstart = nsym;
418 tab->sd_symsize = n * sizeof(Elf_Sym);
419 tab->sd_nglob = nglob;
420
421 addsymtab_strstart = str;
422 if (kheapsort(nsym, n, sizeof(Elf_Sym), addsymtab_compar, &ts) != 0)
423 panic("addsymtab");
424
425 #ifdef KDTRACE_HOOKS
426 /*
427 * Build the mapping from original symbol id to new symbol table.
428 * Deleted symbols will have a zero map, indices will be one based
429 * instead of zero based.
430 * Resulting map is sd_nmap[original_index] = new_index + 1
431 */
432 if (nmap != NULL) {
433 int new;
434 for (new = 0; new < n; new++) {
435 uint32_t orig = nsym[new].st_size - 1;
436 uint32_t size = nmap[orig];
437
438 nmap[orig] = new + 1;
439
440 /* restore the size */
441 nsym[new].st_size = size;
442 }
443 }
444 #endif
445
446 KASSERT(strcmp(name, "netbsd") == 0 || mutex_owned(&ksyms_lock));
447 KASSERT(cold || mutex_owned(&ksyms_lock));
448
449 /*
450 * Publish the symtab. Do this at splhigh to ensure ddb never
451 * witnesses an inconsistent state of the queue, unless memory
452 * is so corrupt that we crash in TAILQ_INSERT_TAIL.
453 */
454 s = splhigh();
455 TAILQ_INSERT_TAIL(&ksyms_symtabs, tab, sd_queue);
456 splx(s);
457
458 ksyms_sizes_calc();
459 ksyms_loaded = true;
460 }
461
462 /*
463 * Setup the kernel symbol table stuff.
464 */
465 void
466 ksyms_addsyms_elf(int symsize, void *start, void *end)
467 {
468 int i, j;
469 Elf_Shdr *shdr;
470 char *symstart = NULL, *strstart = NULL;
471 size_t strsize = 0;
472 Elf_Ehdr *ehdr;
473 char *ctfstart = NULL;
474 size_t ctfsize = 0;
475
476 if (symsize <= 0) {
477 printf("[ Kernel symbol table missing! ]\n");
478 return;
479 }
480
481 /* Sanity check */
482 if (ALIGNED_POINTER(start, long) == 0) {
483 printf("[ Kernel symbol table has bad start address %p ]\n",
484 start);
485 return;
486 }
487
488 ehdr = (Elf_Ehdr *)start;
489
490 /* check if this is a valid ELF header */
491 /* No reason to verify arch type, the kernel is actually running! */
492 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
493 ehdr->e_ident[EI_CLASS] != ELFCLASS ||
494 ehdr->e_version > 1) {
495 printf("[ Kernel symbol table invalid! ]\n");
496 return; /* nothing to do */
497 }
498
499 /* Loaded header will be scratched in addsymtab */
500 ksyms_hdr_init(start);
501
502 /* Find the symbol table and the corresponding string table. */
503 shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff);
504 for (i = 1; i < ehdr->e_shnum; i++) {
505 if (shdr[i].sh_type != SHT_SYMTAB)
506 continue;
507 if (shdr[i].sh_offset == 0)
508 continue;
509 symstart = (uint8_t *)start + shdr[i].sh_offset;
510 symsize = shdr[i].sh_size;
511 j = shdr[i].sh_link;
512 if (shdr[j].sh_offset == 0)
513 continue; /* Can this happen? */
514 strstart = (uint8_t *)start + shdr[j].sh_offset;
515 strsize = shdr[j].sh_size;
516 break;
517 }
518
519 #ifdef KDTRACE_HOOKS
520 /* Find the CTF section */
521 shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff);
522 if (ehdr->e_shstrndx != 0) {
523 char *shstr = (uint8_t *)start +
524 shdr[ehdr->e_shstrndx].sh_offset;
525 for (i = 1; i < ehdr->e_shnum; i++) {
526 #ifdef DEBUG
527 printf("ksyms: checking %s\n", &shstr[shdr[i].sh_name]);
528 #endif
529 if (shdr[i].sh_type != SHT_PROGBITS)
530 continue;
531 if (strncmp(".SUNW_ctf", &shstr[shdr[i].sh_name], 10)
532 != 0)
533 continue;
534 ctfstart = (uint8_t *)start + shdr[i].sh_offset;
535 ctfsize = shdr[i].sh_size;
536 ksyms_ctfsz = ctfsize;
537 #ifdef DEBUG
538 aprint_normal("Found CTF at %p, size 0x%zx\n",
539 ctfstart, ctfsize);
540 #endif
541 break;
542 }
543 #ifdef DEBUG
544 } else {
545 printf("ksyms: e_shstrndx == 0\n");
546 #endif
547 }
548 #endif
549
550 if (!ksyms_verify(symstart, strstart))
551 return;
552
553 addsymtab("netbsd", symstart, symsize, strstart, strsize,
554 &kernel_symtab, symstart, ctfstart, ctfsize, ksyms_nmap);
555
556 #ifdef DEBUG
557 aprint_normal("Loaded initial symtab at %p, strtab at %p, # entries %ld\n",
558 kernel_symtab.sd_symstart, kernel_symtab.sd_strstart,
559 (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym));
560 #endif
561 }
562
563 /*
564 * Setup the kernel symbol table stuff.
565 * Use this when the address of the symbol and string tables are known;
566 * otherwise use ksyms_init with an ELF image.
567 * We need to pass a minimal ELF header which will later be completed by
568 * ksyms_hdr_init and handed off to userland through /dev/ksyms. We use
569 * a void *rather than a pointer to avoid exposing the Elf_Ehdr type.
570 */
571 void
572 ksyms_addsyms_explicit(void *ehdr, void *symstart, size_t symsize,
573 void *strstart, size_t strsize)
574 {
575 if (!ksyms_verify(symstart, strstart))
576 return;
577
578 ksyms_hdr_init(ehdr);
579 addsymtab("netbsd", symstart, symsize, strstart, strsize,
580 &kernel_symtab, symstart, NULL, 0, ksyms_nmap);
581 }
582
583 /*
584 * Get the value associated with a symbol.
585 * "mod" is the module name, or null if any module.
586 * "sym" is the symbol name.
587 * "val" is a pointer to the corresponding value, if call succeeded.
588 * Returns 0 if success or ENOENT if no such entry.
589 *
590 * Call with ksyms_lock, unless known that the symbol table can't change.
591 */
592 int
593 ksyms_getval_unlocked(const char *mod, const char *sym, Elf_Sym **symp,
594 unsigned long *val, int type)
595 {
596 struct ksyms_symtab *st;
597 Elf_Sym *es;
598
599 #ifdef KSYMS_DEBUG
600 if (ksyms_debug & FOLLOW_CALLS)
601 printf("%s: mod %s sym %s valp %p\n", __func__, mod, sym, val);
602 #endif
603
604 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
605 if (mod != NULL && strcmp(st->sd_name, mod))
606 continue;
607 if ((es = findsym(sym, st, type)) != NULL) {
608 *val = es->st_value;
609 if (symp)
610 *symp = es;
611 return 0;
612 }
613 }
614 return ENOENT;
615 }
616
617 int
618 ksyms_getval(const char *mod, const char *sym, unsigned long *val, int type)
619 {
620 int rc;
621
622 if (!ksyms_loaded)
623 return ENOENT;
624
625 mutex_enter(&ksyms_lock);
626 rc = ksyms_getval_unlocked(mod, sym, NULL, val, type);
627 mutex_exit(&ksyms_lock);
628 return rc;
629 }
630
631 struct ksyms_symtab *
632 ksyms_get_mod(const char *mod)
633 {
634 struct ksyms_symtab *st;
635
636 mutex_enter(&ksyms_lock);
637 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
638 if (mod != NULL && strcmp(st->sd_name, mod))
639 continue;
640 break;
641 }
642 mutex_exit(&ksyms_lock);
643
644 return st;
645 }
646
647
648 /*
649 * ksyms_mod_foreach()
650 *
651 * Iterate over the symbol table of the specified module, calling the callback
652 * handler for each symbol. Stop iterating if the handler return is non-zero.
653 *
654 */
655
656 int
657 ksyms_mod_foreach(const char *mod, ksyms_callback_t callback, void *opaque)
658 {
659 struct ksyms_symtab *st;
660 Elf_Sym *sym, *maxsym;
661 char *str;
662 int symindx;
663
664 if (!ksyms_loaded)
665 return ENOENT;
666
667 mutex_enter(&ksyms_lock);
668
669 /* find the module */
670 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
671 if (mod != NULL && strcmp(st->sd_name, mod))
672 continue;
673
674 sym = st->sd_symstart;
675 str = st->sd_strstart - st->sd_usroffset;
676
677 /* now iterate through the symbols */
678 maxsym = sym + st->sd_symsize / sizeof(Elf_Sym);
679 for (symindx = 0; sym < maxsym; sym++, symindx++) {
680 if (callback(str + sym->st_name, symindx,
681 (void *)sym->st_value,
682 sym->st_size,
683 sym->st_info,
684 opaque) != 0) {
685 break;
686 }
687 }
688 }
689 mutex_exit(&ksyms_lock);
690
691 return 0;
692 }
693
694 /*
695 * Get "mod" and "symbol" associated with an address.
696 * Returns 0 if success or ENOENT if no such entry.
697 *
698 * Call with ksyms_lock, unless known that the symbol table can't change.
699 */
700 int
701 ksyms_getname(const char **mod, const char **sym, vaddr_t v, int f)
702 {
703 struct ksyms_symtab *st;
704 Elf_Sym *les, *es = NULL;
705 vaddr_t laddr = 0;
706 const char *lmod = NULL;
707 char *stable = NULL;
708 int type, i, sz;
709
710 if (!ksyms_loaded)
711 return ENOENT;
712
713 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
714 if (v < st->sd_minsym || v > st->sd_maxsym)
715 continue;
716 sz = st->sd_symsize/sizeof(Elf_Sym);
717 for (i = 0; i < sz; i++) {
718 les = st->sd_symstart + i;
719 type = ELF_ST_TYPE(les->st_info);
720
721 if ((f & KSYMS_PROC) && (type != STT_FUNC))
722 continue;
723
724 if (type == STT_NOTYPE)
725 continue;
726
727 if (((f & KSYMS_ANY) == 0) &&
728 (type != STT_FUNC) && (type != STT_OBJECT))
729 continue;
730
731 if ((les->st_value <= v) && (les->st_value > laddr)) {
732 laddr = les->st_value;
733 es = les;
734 lmod = st->sd_name;
735 stable = st->sd_strstart - st->sd_usroffset;
736 }
737 }
738 }
739 if (es == NULL)
740 return ENOENT;
741 if ((f & KSYMS_EXACT) && (v != es->st_value))
742 return ENOENT;
743 if (mod)
744 *mod = lmod;
745 if (sym)
746 *sym = stable + es->st_name;
747 return 0;
748 }
749
750 /*
751 * Add a symbol table from a loadable module.
752 */
753 void
754 ksyms_modload(const char *name, void *symstart, vsize_t symsize,
755 char *strstart, vsize_t strsize)
756 {
757 struct ksyms_symtab *st;
758 void *nmap;
759
760 st = kmem_zalloc(sizeof(*st), KM_SLEEP);
761 nmap = kmem_zalloc(symsize / sizeof(Elf_Sym) * sizeof (uint32_t),
762 KM_SLEEP);
763 mutex_enter(&ksyms_lock);
764 addsymtab(name, symstart, symsize, strstart, strsize, st, symstart,
765 NULL, 0, nmap);
766 mutex_exit(&ksyms_lock);
767 }
768
769 /*
770 * Remove a symbol table from a loadable module.
771 */
772 void
773 ksyms_modunload(const char *name)
774 {
775 struct ksyms_symtab *st;
776 int s;
777
778 mutex_enter(&ksyms_lock);
779 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
780 if (strcmp(name, st->sd_name) != 0)
781 continue;
782 break;
783 }
784 KASSERT(st != NULL);
785
786 /*
787 * Wait for last /dev/ksyms close -- readers may be in the
788 * middle of viewing a snapshot including this module. (We
789 * could skip this if it's past ksyms_last_snapshot, but it's
790 * not clear that's worth the effort.)
791 */
792 while (ksyms_opencnt)
793 cv_wait(&ksyms_cv, &ksyms_lock);
794
795 /*
796 * Remove the symtab. Do this at splhigh to ensure ddb never
797 * witnesses an inconsistent state of the queue, unless memory
798 * is so corrupt that we crash in TAILQ_REMOVE.
799 */
800 s = splhigh();
801 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
802 splx(s);
803
804 /* Recompute the ksyms sizes now that we've removed st. */
805 ksyms_sizes_calc();
806 mutex_exit(&ksyms_lock);
807
808 /*
809 * No more references are possible. Free the name map and the
810 * symtab itself, which we had allocated in ksyms_modload.
811 */
812 kmem_free(st->sd_nmap, st->sd_nmapsize * sizeof(uint32_t));
813 kmem_free(st, sizeof(*st));
814 }
815
816 #ifdef DDB
817 /*
818 * Keep sifting stuff here, to avoid export of ksyms internals.
819 *
820 * Systems is expected to be quiescent, so no locking done.
821 */
822 int
823 ksyms_sift(char *mod, char *sym, int mode)
824 {
825 struct ksyms_symtab *st;
826 char *sb;
827 int i, sz;
828
829 if (!ksyms_loaded)
830 return ENOENT;
831
832 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
833 if (mod && strcmp(mod, st->sd_name))
834 continue;
835 sb = st->sd_strstart - st->sd_usroffset;
836
837 sz = st->sd_symsize/sizeof(Elf_Sym);
838 for (i = 0; i < sz; i++) {
839 Elf_Sym *les = st->sd_symstart + i;
840 char c;
841
842 if (strstr(sb + les->st_name, sym) == NULL)
843 continue;
844
845 if (mode == 'F') {
846 switch (ELF_ST_TYPE(les->st_info)) {
847 case STT_OBJECT:
848 c = '+';
849 break;
850 case STT_FUNC:
851 c = '*';
852 break;
853 case STT_SECTION:
854 c = '&';
855 break;
856 case STT_FILE:
857 c = '/';
858 break;
859 default:
860 c = ' ';
861 break;
862 }
863 db_printf("%s%c ", sb + les->st_name, c);
864 } else
865 db_printf("%s ", sb + les->st_name);
866 }
867 }
868 return ENOENT;
869 }
870 #endif /* DDB */
871
872 /*
873 * In case we exposing the symbol table to the userland using the pseudo-
874 * device /dev/ksyms, it is easier to provide all the tables as one.
875 * However, it means we have to change all the st_name fields for the
876 * symbols so they match the ELF image that the userland will read
877 * through the device.
878 *
879 * The actual (correct) value of st_name is preserved through a global
880 * offset stored in the symbol table structure.
881 *
882 * Call with ksyms_lock held.
883 */
884 static void
885 ksyms_sizes_calc(void)
886 {
887 struct ksyms_symtab *st;
888 int i, delta;
889
890 KASSERT(cold || mutex_owned(&ksyms_lock));
891
892 ksyms_symsz = ksyms_strsz = 0;
893 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
894 delta = ksyms_strsz - st->sd_usroffset;
895 if (delta != 0) {
896 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
897 st->sd_symstart[i].st_name += delta;
898 st->sd_usroffset = ksyms_strsz;
899 }
900 ksyms_symsz += st->sd_symsize;
901 ksyms_strsz += st->sd_strsize;
902 }
903 }
904
905 static void
906 ksyms_fill_note(void)
907 {
908 int32_t *note = ksyms_hdr.kh_note;
909 note[0] = ELF_NOTE_NETBSD_NAMESZ;
910 note[1] = ELF_NOTE_NETBSD_DESCSZ;
911 note[2] = ELF_NOTE_TYPE_NETBSD_TAG;
912 memcpy(¬e[3], "NetBSD\0", 8);
913 note[5] = __NetBSD_Version__;
914 }
915
916 static void
917 ksyms_hdr_init(const void *hdraddr)
918 {
919 /* Copy the loaded elf exec header */
920 memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr));
921
922 /* Set correct program/section header sizes, offsets and numbers */
923 ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]);
924 ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr);
925 ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR;
926 ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]);
927 ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr);
928 ksyms_hdr.kh_ehdr.e_shnum = NSECHDR;
929 ksyms_hdr.kh_ehdr.e_shstrndx = SHSTRTAB;
930
931 /* Text/data - fake */
932 ksyms_hdr.kh_phdr[0].p_type = PT_LOAD;
933 ksyms_hdr.kh_phdr[0].p_memsz = (unsigned long)-1L;
934 ksyms_hdr.kh_phdr[0].p_flags = PF_R | PF_X | PF_W;
935
936 #define SHTCOPY(name) strlcpy(&ksyms_hdr.kh_strtab[offs], (name), \
937 sizeof(ksyms_hdr.kh_strtab) - offs), offs += sizeof(name)
938
939 uint32_t offs = 1;
940 /* First section header ".note.netbsd.ident" */
941 ksyms_hdr.kh_shdr[SHNOTE].sh_name = offs;
942 ksyms_hdr.kh_shdr[SHNOTE].sh_type = SHT_NOTE;
943 ksyms_hdr.kh_shdr[SHNOTE].sh_offset =
944 offsetof(struct ksyms_hdr, kh_note[0]);
945 ksyms_hdr.kh_shdr[SHNOTE].sh_size = sizeof(ksyms_hdr.kh_note);
946 ksyms_hdr.kh_shdr[SHNOTE].sh_addralign = sizeof(int);
947 SHTCOPY(".note.netbsd.ident");
948 ksyms_fill_note();
949
950 /* Second section header; ".symtab" */
951 ksyms_hdr.kh_shdr[SYMTAB].sh_name = offs;
952 ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB;
953 ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr);
954 /* ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */
955 ksyms_hdr.kh_shdr[SYMTAB].sh_link = STRTAB; /* Corresponding strtab */
956 ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long);
957 ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym);
958 SHTCOPY(".symtab");
959
960 /* Third section header; ".strtab" */
961 ksyms_hdr.kh_shdr[STRTAB].sh_name = offs;
962 ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB;
963 /* ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */
964 /* ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */
965 ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char);
966 SHTCOPY(".strtab");
967
968 /* Fourth section, ".shstrtab" */
969 ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = offs;
970 ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB;
971 ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset =
972 offsetof(struct ksyms_hdr, kh_strtab);
973 ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ;
974 ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char);
975 SHTCOPY(".shstrtab");
976
977 /* Fifth section, ".bss". All symbols reside here. */
978 ksyms_hdr.kh_shdr[SHBSS].sh_name = offs;
979 ksyms_hdr.kh_shdr[SHBSS].sh_type = SHT_NOBITS;
980 ksyms_hdr.kh_shdr[SHBSS].sh_offset = 0;
981 ksyms_hdr.kh_shdr[SHBSS].sh_size = (unsigned long)-1L;
982 ksyms_hdr.kh_shdr[SHBSS].sh_addralign = PAGE_SIZE;
983 ksyms_hdr.kh_shdr[SHBSS].sh_flags = SHF_ALLOC | SHF_EXECINSTR;
984 SHTCOPY(".bss");
985
986 /* Sixth section header; ".SUNW_ctf" */
987 ksyms_hdr.kh_shdr[SHCTF].sh_name = offs;
988 ksyms_hdr.kh_shdr[SHCTF].sh_type = SHT_PROGBITS;
989 /* ksyms_hdr.kh_shdr[SHCTF].sh_offset = filled in at open */
990 /* ksyms_hdr.kh_shdr[SHCTF].sh_size = filled in at open */
991 ksyms_hdr.kh_shdr[SHCTF].sh_link = SYMTAB; /* Corresponding symtab */
992 ksyms_hdr.kh_shdr[SHCTF].sh_addralign = sizeof(char);
993 SHTCOPY(".SUNW_ctf");
994 }
995
996 static int
997 ksymsopen(dev_t dev, int oflags, int devtype, struct lwp *l)
998 {
999 if (minor(dev) != 0 || !ksyms_loaded)
1000 return ENXIO;
1001
1002 /*
1003 * Create a "snapshot" of the kernel symbol table. Bumping
1004 * ksyms_opencnt will prevent symbol tables from being freed.
1005 */
1006 mutex_enter(&ksyms_lock);
1007 if (ksyms_opencnt++)
1008 goto out;
1009 ksyms_hdr.kh_shdr[SYMTAB].sh_size = ksyms_symsz;
1010 ksyms_hdr.kh_shdr[SYMTAB].sh_info = ksyms_symsz / sizeof(Elf_Sym);
1011 ksyms_hdr.kh_shdr[STRTAB].sh_offset = ksyms_symsz +
1012 ksyms_hdr.kh_shdr[SYMTAB].sh_offset;
1013 ksyms_hdr.kh_shdr[STRTAB].sh_size = ksyms_strsz;
1014 ksyms_hdr.kh_shdr[SHCTF].sh_offset = ksyms_strsz +
1015 ksyms_hdr.kh_shdr[STRTAB].sh_offset;
1016 ksyms_hdr.kh_shdr[SHCTF].sh_size = ksyms_ctfsz;
1017 ksyms_last_snapshot = TAILQ_LAST(&ksyms_symtabs, ksyms_symtab_queue);
1018 out: mutex_exit(&ksyms_lock);
1019
1020 return 0;
1021 }
1022
1023 static int
1024 ksymsclose(dev_t dev, int oflags, int devtype, struct lwp *l)
1025 {
1026
1027 mutex_enter(&ksyms_lock);
1028 if (--ksyms_opencnt)
1029 goto out;
1030 ksyms_last_snapshot = NULL;
1031 cv_broadcast(&ksyms_cv);
1032 out: mutex_exit(&ksyms_lock);
1033
1034 return 0;
1035 }
1036
1037 static int
1038 ksymsread(dev_t dev, struct uio *uio, int ioflag)
1039 {
1040 struct ksyms_symtab *st;
1041 size_t filepos, inpos, off;
1042 int error;
1043
1044 /*
1045 * First: Copy out the ELF header.
1046 */
1047 off = uio->uio_offset;
1048 if (off < sizeof(struct ksyms_hdr)) {
1049 error = uiomove((char *)&ksyms_hdr + off,
1050 sizeof(struct ksyms_hdr) - off, uio);
1051 if (error != 0)
1052 return error;
1053 }
1054
1055 /*
1056 * Copy out the symbol table. The list of symtabs is
1057 * guaranteed to be nonempty because we always have an entry
1058 * for the main kernel. We stop at ksyms_last_snapshot, not at
1059 * the end of the tailq or NULL, because entries beyond
1060 * ksyms_last_snapshot are not included in this snapshot (and
1061 * may not be fully initialized memory as we witness it).
1062 */
1063 filepos = sizeof(struct ksyms_hdr);
1064 for (st = TAILQ_FIRST(&ksyms_symtabs);
1065 ;
1066 st = TAILQ_NEXT(st, sd_queue)) {
1067 if (uio->uio_resid == 0)
1068 return 0;
1069 if (uio->uio_offset <= st->sd_symsize + filepos) {
1070 inpos = uio->uio_offset - filepos;
1071 error = uiomove((char *)st->sd_symstart + inpos,
1072 st->sd_symsize - inpos, uio);
1073 if (error != 0)
1074 return error;
1075 }
1076 filepos += st->sd_symsize;
1077 if (st == ksyms_last_snapshot)
1078 break;
1079 }
1080
1081 /*
1082 * Copy out the string table
1083 */
1084 KASSERT(filepos == sizeof(struct ksyms_hdr) +
1085 ksyms_hdr.kh_shdr[SYMTAB].sh_size);
1086 for (st = TAILQ_FIRST(&ksyms_symtabs);
1087 ;
1088 st = TAILQ_NEXT(st, sd_queue)) {
1089 if (uio->uio_resid == 0)
1090 return 0;
1091 if (uio->uio_offset <= st->sd_strsize + filepos) {
1092 inpos = uio->uio_offset - filepos;
1093 error = uiomove((char *)st->sd_strstart + inpos,
1094 st->sd_strsize - inpos, uio);
1095 if (error != 0)
1096 return error;
1097 }
1098 filepos += st->sd_strsize;
1099 if (st == ksyms_last_snapshot)
1100 break;
1101 }
1102
1103 /*
1104 * Copy out the CTF table.
1105 *
1106 * XXX Why does this only copy out the first symtab's CTF?
1107 */
1108 st = TAILQ_FIRST(&ksyms_symtabs);
1109 if (st->sd_ctfstart != NULL) {
1110 if (uio->uio_resid == 0)
1111 return 0;
1112 if (uio->uio_offset <= st->sd_ctfsize + filepos) {
1113 inpos = uio->uio_offset - filepos;
1114 error = uiomove((char *)st->sd_ctfstart + inpos,
1115 st->sd_ctfsize - inpos, uio);
1116 if (error != 0)
1117 return error;
1118 }
1119 filepos += st->sd_ctfsize;
1120 }
1121
1122 return 0;
1123 }
1124
1125 static int
1126 ksymswrite(dev_t dev, struct uio *uio, int ioflag)
1127 {
1128 return EROFS;
1129 }
1130
1131 __CTASSERT(offsetof(struct ksyms_ogsymbol, kg_name) == offsetof(struct ksyms_gsymbol, kg_name));
1132 __CTASSERT(offsetof(struct ksyms_gvalue, kv_name) == offsetof(struct ksyms_gsymbol, kg_name));
1133
1134 static int
1135 ksymsioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l)
1136 {
1137 struct ksyms_ogsymbol *okg = (struct ksyms_ogsymbol *)data;
1138 struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data;
1139 struct ksyms_gvalue *kv = (struct ksyms_gvalue *)data;
1140 struct ksyms_symtab *st;
1141 Elf_Sym *sym = NULL, copy;
1142 unsigned long val;
1143 int error = 0;
1144 char *str = NULL;
1145 int len;
1146
1147 /* Read ksyms_maxlen only once while not holding the lock. */
1148 len = ksyms_maxlen;
1149
1150 if (cmd == OKIOCGVALUE || cmd == OKIOCGSYMBOL ||
1151 cmd == KIOCGVALUE || cmd == KIOCGSYMBOL) {
1152 str = kmem_alloc(len, KM_SLEEP);
1153 if ((error = copyinstr(kg->kg_name, str, len, NULL)) != 0) {
1154 kmem_free(str, len);
1155 return error;
1156 }
1157 }
1158
1159 switch (cmd) {
1160 case OKIOCGVALUE:
1161 /*
1162 * Use the in-kernel symbol lookup code for fast
1163 * retreival of a value.
1164 */
1165 error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN);
1166 if (error == 0)
1167 error = copyout(&val, okg->kg_value, sizeof(long));
1168 kmem_free(str, len);
1169 break;
1170
1171 case OKIOCGSYMBOL:
1172 /*
1173 * Use the in-kernel symbol lookup code for fast
1174 * retreival of a symbol.
1175 */
1176 mutex_enter(&ksyms_lock);
1177 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
1178 if ((sym = findsym(str, st, KSYMS_ANY)) == NULL)
1179 continue;
1180 #ifdef notdef
1181 /* Skip if bad binding */
1182 if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
1183 sym = NULL;
1184 continue;
1185 }
1186 #endif
1187 break;
1188 }
1189 if (sym != NULL) {
1190 memcpy(©, sym, sizeof(copy));
1191 mutex_exit(&ksyms_lock);
1192 error = copyout(©, okg->kg_sym, sizeof(Elf_Sym));
1193 } else {
1194 mutex_exit(&ksyms_lock);
1195 error = ENOENT;
1196 }
1197 kmem_free(str, len);
1198 break;
1199
1200 case KIOCGVALUE:
1201 /*
1202 * Use the in-kernel symbol lookup code for fast
1203 * retreival of a value.
1204 */
1205 error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN);
1206 if (error == 0)
1207 kv->kv_value = val;
1208 kmem_free(str, len);
1209 break;
1210
1211 case KIOCGSYMBOL:
1212 /*
1213 * Use the in-kernel symbol lookup code for fast
1214 * retreival of a symbol.
1215 */
1216 mutex_enter(&ksyms_lock);
1217 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
1218 if ((sym = findsym(str, st, KSYMS_ANY)) == NULL)
1219 continue;
1220 #ifdef notdef
1221 /* Skip if bad binding */
1222 if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
1223 sym = NULL;
1224 continue;
1225 }
1226 #endif
1227 break;
1228 }
1229 if (sym != NULL) {
1230 kg->kg_sym = *sym;
1231 } else {
1232 error = ENOENT;
1233 }
1234 mutex_exit(&ksyms_lock);
1235 kmem_free(str, len);
1236 break;
1237
1238 case KIOCGSIZE:
1239 /*
1240 * Get total size of symbol table.
1241 */
1242 mutex_enter(&ksyms_lock);
1243 *(int *)data = ksyms_strsz + ksyms_symsz +
1244 sizeof(struct ksyms_hdr);
1245 mutex_exit(&ksyms_lock);
1246 break;
1247
1248 default:
1249 error = ENOTTY;
1250 break;
1251 }
1252
1253 return error;
1254 }
1255
1256 const struct cdevsw ksyms_cdevsw = {
1257 .d_open = ksymsopen,
1258 .d_close = ksymsclose,
1259 .d_read = ksymsread,
1260 .d_write = ksymswrite,
1261 .d_ioctl = ksymsioctl,
1262 .d_stop = nullstop,
1263 .d_tty = notty,
1264 .d_poll = nopoll,
1265 .d_mmap = nommap,
1266 .d_kqfilter = nullkqfilter,
1267 .d_discard = nodiscard,
1268 .d_flag = D_OTHER | D_MPSAFE
1269 };
1270