FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_ksyms.c
1 /* $NetBSD: kern_ksyms.c,v 1.41.4.2 2010/02/14 13:35:43 bouyer 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@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 * Consider replacing patricia tree with simpler binary search
71 * for symbol tables.
72 *
73 * Add support for mmap, poll.
74 */
75
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.41.4.2 2010/02/14 13:35:43 bouyer Exp $");
78
79 #ifdef _KERNEL
80 #include "opt_ddb.h"
81 #include "opt_ddbparam.h" /* for SYMTAB_SPACE */
82 #endif
83
84 #define _KSYMS_PRIVATE
85
86 #include <sys/param.h>
87 #include <sys/errno.h>
88 #include <sys/queue.h>
89 #include <sys/exec.h>
90 #include <sys/systm.h>
91 #include <sys/conf.h>
92 #include <sys/malloc.h>
93 #include <sys/kmem.h>
94 #include <sys/proc.h>
95 #include <sys/module.h>
96 #include <sys/atomic.h>
97 #include <sys/ksyms.h>
98
99 #include <lib/libkern/libkern.h>
100
101 #ifdef DDB
102 #include <ddb/db_output.h>
103 #endif
104
105 #include "ksyms.h"
106
107 static int ksyms_maxlen;
108 static bool ksyms_isopen;
109 static bool ksyms_initted;
110 static struct ksyms_hdr ksyms_hdr;
111 static kmutex_t ksyms_lock;
112
113 void ksymsattach(int);
114 static void ksyms_hdr_init(void *);
115 static void ksyms_sizes_calc(void);
116
117 #ifdef KSYMS_DEBUG
118 #define FOLLOW_CALLS 1
119 #define FOLLOW_MORE_CALLS 2
120 #define FOLLOW_DEVKSYMS 4
121 static int ksyms_debug;
122 #endif
123
124 #ifdef SYMTAB_SPACE
125 #define SYMTAB_FILLER "|This is the symbol table!"
126
127 char db_symtab[SYMTAB_SPACE] = SYMTAB_FILLER;
128 int db_symtabsize = SYMTAB_SPACE;
129 #endif
130
131 int ksyms_symsz;
132 int ksyms_strsz;
133 TAILQ_HEAD(, ksyms_symtab) ksyms_symtabs =
134 TAILQ_HEAD_INITIALIZER(ksyms_symtabs);
135 static struct ksyms_symtab kernel_symtab;
136
137 /*
138 * Patricia-tree-based lookup structure for the in-kernel global symbols.
139 * Based on a design by Mikael Sundstrom, msm@sm.luth.se.
140 */
141 struct ptree {
142 int16_t bitno;
143 int16_t lr[2];
144 } *symb;
145 static int16_t baseidx;
146 static int treex = 1;
147
148 #define P_BIT(key, bit) ((key[bit >> 3] >> (bit & 7)) & 1)
149 #define STRING(idx) (kernel_symtab.sd_symstart[idx].st_name + \
150 kernel_symtab.sd_strstart)
151
152 static int
153 ksyms_verify(void *symstart, void *strstart)
154 {
155 #if defined(DIAGNOSTIC) || defined(DEBUG)
156 if (symstart == NULL)
157 printf("ksyms: Symbol table not found\n");
158 if (strstart == NULL)
159 printf("ksyms: String table not found\n");
160 if (symstart == NULL || strstart == NULL)
161 printf("ksyms: Perhaps the kernel is stripped?\n");
162 #endif
163 if (symstart == NULL || strstart == NULL)
164 return 0;
165 KASSERT(symstart <= strstart);
166 return 1;
167 }
168
169 /*
170 * Walk down the tree until a terminal node is found.
171 */
172 static int
173 symbol_traverse(const char *key)
174 {
175 int16_t nb, rbit = baseidx;
176
177 while (rbit > 0) {
178 nb = symb[rbit].bitno;
179 rbit = symb[rbit].lr[P_BIT(key, nb)];
180 }
181 return -rbit;
182 }
183
184 static int
185 ptree_add(char *key, int val)
186 {
187 int idx;
188 int nix, cix, bit, rbit, sb, lastrbit, svbit = 0, ix;
189 char *m, *k;
190
191 if (baseidx == 0) {
192 baseidx = -val;
193 return 0; /* First element */
194 }
195
196 /* Get string to match against */
197 idx = symbol_traverse(key);
198
199 /* Find first mismatching bit */
200 m = STRING(idx);
201 k = key;
202 if (strcmp(m, k) == 0)
203 return 1;
204
205 for (cix = 0; *m && *k && *m == *k; m++, k++, cix += 8)
206 ;
207 ix = ffs((int)*m ^ (int)*k) - 1;
208 cix += ix;
209
210 /* Create new node */
211 nix = treex++;
212 bit = P_BIT(key, cix);
213 symb[nix].bitno = cix;
214 symb[nix].lr[bit] = -val;
215
216 /* Find where to insert node */
217 rbit = baseidx;
218 lastrbit = 0;
219 for (;;) {
220 if (rbit < 0)
221 break;
222 sb = symb[rbit].bitno;
223 if (sb > cix)
224 break;
225 if (sb == cix)
226 printf("symb[rbit].bitno == cix!!!\n");
227 lastrbit = rbit;
228 svbit = P_BIT(key, sb);
229 rbit = symb[rbit].lr[svbit];
230 }
231
232 /* Do the actual insertion */
233 if (lastrbit == 0) {
234 /* first element */
235 symb[nix].lr[!bit] = baseidx;
236 baseidx = nix;
237 } else {
238 symb[nix].lr[!bit] = rbit;
239 symb[lastrbit].lr[svbit] = nix;
240 }
241 return 0;
242 }
243
244 static int
245 ptree_find(const char *key)
246 {
247 int idx;
248
249 if (baseidx == 0)
250 return 0;
251 idx = symbol_traverse(key);
252
253 if (strcmp(key, STRING(idx)) == 0)
254 return idx;
255 return 0;
256 }
257
258 static void
259 ptree_gen(char *off, struct ksyms_symtab *tab)
260 {
261 Elf_Sym *sym;
262 int i, nsym;
263
264 if (off != NULL)
265 symb = (struct ptree *)ALIGN(off);
266 else
267 symb = malloc((tab->sd_symsize/sizeof(Elf_Sym)) *
268 sizeof(struct ptree), M_DEVBUF, M_WAITOK);
269 symb--; /* sym index won't be 0 */
270
271 sym = tab->sd_symstart;
272 if ((nsym = tab->sd_symsize/sizeof(Elf_Sym)) > INT16_MAX) {
273 printf("Too many symbols for tree, skipping %d symbols\n",
274 nsym-INT16_MAX);
275 nsym = INT16_MAX;
276 }
277 for (i = 1; i < nsym; i++) {
278 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
279 continue;
280 ptree_add(tab->sd_strstart+sym[i].st_name, i);
281 if (tab->sd_minsym == NULL ||
282 sym[i].st_value < tab->sd_minsym->st_value)
283 tab->sd_minsym = &sym[i];
284 if (tab->sd_maxsym == NULL ||
285 sym[i].st_value > tab->sd_maxsym->st_value)
286 tab->sd_maxsym = &sym[i];
287 }
288 }
289
290 /*
291 * Finds a certain symbol name in a certain symbol table.
292 */
293 static Elf_Sym *
294 findsym(const char *name, struct ksyms_symtab *table)
295 {
296 Elf_Sym *start = table->sd_symstart;
297 int i, sz = table->sd_symsize/sizeof(Elf_Sym);
298 char *np;
299 char *realstart = table->sd_strstart - table->sd_usroffset;
300
301 if (table == &kernel_symtab && (i = ptree_find(name)) != 0)
302 return &start[i];
303
304 for (i = 0; i < sz; i++) {
305 np = realstart + start[i].st_name;
306 if (name[0] == np[0] && name[1] == np[1] &&
307 strcmp(name, np) == 0)
308 return &start[i];
309 }
310 return NULL;
311 }
312
313 /*
314 * The "attach" is in reality done in ksyms_init().
315 */
316 void
317 ksymsattach(int arg)
318 {
319 if (baseidx == 0)
320 ptree_gen(0, &kernel_symtab);
321 }
322
323 /*
324 * Add a symbol table.
325 * This is intended for use when the symbol table and its corresponding
326 * string table are easily available. If they are embedded in an ELF
327 * image, use addsymtab_elf() instead.
328 *
329 * name - Symbol's table name.
330 * symstart, symsize - Address and size of the symbol table.
331 * strstart, strsize - Address and size of the string table.
332 * tab - Symbol table to be updated with this information.
333 * newstart - Address to which the symbol table has to be copied during
334 * shrinking. If NULL, it is not moved.
335 */
336 static void
337 addsymtab(const char *name, void *symstart, size_t symsize,
338 void *strstart, size_t strsize, struct ksyms_symtab *tab,
339 void *newstart)
340 {
341 Elf_Sym *sym, *nsym;
342 int i, j, n;
343 char *str;
344
345 tab->sd_symstart = symstart;
346 tab->sd_symsize = symsize;
347 tab->sd_strstart = strstart;
348 tab->sd_strsize = strsize;
349 tab->sd_name = name;
350 tab->sd_minsym = NULL;
351 tab->sd_maxsym = NULL;
352 tab->sd_usroffset = 0;
353 tab->sd_gone = false;
354 tab->sd_malloc = false; /* XXXLKM */
355 #ifdef KSYMS_DEBUG
356 printf("newstart %p sym %p ksyms_symsz %d str %p strsz %d send %p\n",
357 newstart, symstart, symsize, strstart, strsize,
358 tab->sd_strstart + tab->sd_strsize);
359 #endif
360
361 /* Pack symbol table by removing all file name references. */
362 sym = tab->sd_symstart;
363 nsym = (Elf_Sym *)newstart;
364 str = tab->sd_strstart;
365 for (i = n = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
366 /*
367 * Remove useless symbols.
368 * Should actually remove all typeless symbols.
369 */
370 if (sym[i].st_name == 0)
371 continue; /* Skip nameless entries */
372 if (sym[i].st_shndx == SHN_UNDEF)
373 continue; /* Skip external references */
374 if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE)
375 continue; /* Skip filenames */
376 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
377 sym[i].st_value == 0 &&
378 strcmp(str + sym[i].st_name, "*ABS*") == 0)
379 continue; /* XXX */
380 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
381 strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0)
382 continue; /* XXX */
383
384 /* Save symbol. Set it as an absolute offset */
385 nsym[n] = sym[i];
386 nsym[n].st_shndx = SHN_ABS;
387 j = strlen(nsym[n].st_name + tab->sd_strstart) + 1;
388 if (j > ksyms_maxlen)
389 ksyms_maxlen = j;
390 n++;
391
392 }
393 tab->sd_symstart = nsym;
394 tab->sd_symsize = n * sizeof(Elf_Sym);
395 /* ksymsread() is unlocked, so membar. */
396 membar_producer();
397 TAILQ_INSERT_TAIL(&ksyms_symtabs, tab, sd_queue);
398 ksyms_sizes_calc();
399 ksyms_initted = true;
400 }
401
402 void
403 ksyms_init_finalize()
404 {
405 mutex_init(&ksyms_lock, MUTEX_DEFAULT, IPL_NONE);
406 }
407
408 /*
409 * Setup the kernel symbol table stuff.
410 */
411 void
412 ksyms_init(int symsize, void *start, void *end)
413 {
414 int i, j;
415 Elf_Shdr *shdr;
416 char *symstart = NULL, *strstart = NULL;
417 size_t strsize = 0;
418 Elf_Ehdr *ehdr;
419
420 #ifdef SYMTAB_SPACE
421 if (symsize <= 0 &&
422 strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) {
423 symsize = db_symtabsize;
424 start = db_symtab;
425 end = db_symtab + db_symtabsize;
426 }
427 #endif
428 if (symsize <= 0) {
429 printf("[ Kernel symbol table missing! ]\n");
430 return;
431 }
432
433 /* Sanity check */
434 if (ALIGNED_POINTER(start, long) == 0) {
435 printf("[ Kernel symbol table has bad start address %p ]\n",
436 start);
437 return;
438 }
439
440 ehdr = (Elf_Ehdr *)start;
441
442 /* check if this is a valid ELF header */
443 /* No reason to verify arch type, the kernel is actually running! */
444 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
445 ehdr->e_ident[EI_CLASS] != ELFCLASS ||
446 ehdr->e_version > 1) {
447 printf("[ Kernel symbol table invalid! ]\n");
448 return; /* nothing to do */
449 }
450
451 /* Loaded header will be scratched in addsymtab */
452 ksyms_hdr_init(start);
453
454 /* Find the symbol table and the corresponding string table. */
455 shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff);
456 for (i = 1; i < ehdr->e_shnum; i++) {
457 if (shdr[i].sh_type != SHT_SYMTAB)
458 continue;
459 if (shdr[i].sh_offset == 0)
460 continue;
461 symstart = (uint8_t *)start + shdr[i].sh_offset;
462 symsize = shdr[i].sh_size;
463 j = shdr[i].sh_link;
464 if (shdr[j].sh_offset == 0)
465 continue; /* Can this happen? */
466 strstart = (uint8_t *)start + shdr[j].sh_offset;
467 strsize = shdr[j].sh_size;
468 break;
469 }
470
471 if (!ksyms_verify(symstart, strstart))
472 return;
473 addsymtab("netbsd", symstart, symsize, strstart, strsize,
474 &kernel_symtab, start);
475
476 #ifdef DEBUG
477 aprint_normal("Loaded initial symtab at %p, strtab at %p, # entries %ld\n",
478 kernel_symtab.sd_symstart, kernel_symtab.sd_strstart,
479 (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym));
480 #endif
481 }
482
483 /*
484 * Setup the kernel symbol table stuff.
485 * Use this when the address of the symbol and string tables are known;
486 * otherwise use ksyms_init with an ELF image.
487 * We need to pass a minimal ELF header which will later be completed by
488 * ksyms_hdr_init and handed off to userland through /dev/ksyms. We use
489 * a void *rather than a pointer to avoid exposing the Elf_Ehdr type.
490 */
491 void
492 ksyms_init_explicit(void *ehdr, void *symstart, size_t symsize,
493 void *strstart, size_t strsize)
494 {
495
496 if (!ksyms_verify(symstart, strstart))
497 return;
498
499 ksyms_hdr_init(ehdr);
500 addsymtab("netbsd", symstart, symsize, strstart, strsize,
501 &kernel_symtab, symstart);
502 }
503
504 /*
505 * Get the value associated with a symbol.
506 * "mod" is the module name, or null if any module.
507 * "sym" is the symbol name.
508 * "val" is a pointer to the corresponding value, if call succeeded.
509 * Returns 0 if success or ENOENT if no such entry.
510 *
511 * Call with ksyms_lock, unless known that the symbol table can't change.
512 */
513 int
514 ksyms_getval_unlocked(const char *mod, const char *sym, unsigned long *val,
515 int type)
516 {
517 struct ksyms_symtab *st;
518 Elf_Sym *es;
519
520 if (!ksyms_initted)
521 return ENOENT;
522
523 #ifdef KSYMS_DEBUG
524 if (ksyms_debug & FOLLOW_CALLS)
525 printf("ksyms_getval_unlocked: mod %s sym %s valp %p\n",
526 mod, sym, val);
527 #endif
528
529 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
530 if (st->sd_gone)
531 continue;
532 if (mod && strcmp(st->sd_name, mod))
533 continue;
534 if ((es = findsym(sym, st)) == NULL)
535 continue;
536 if (es->st_shndx == SHN_UNDEF)
537 continue;
538
539 /* Skip if bad binding */
540 if (type == KSYMS_EXTERN &&
541 ELF_ST_BIND(es->st_info) != STB_GLOBAL)
542 continue;
543
544 if (val)
545 *val = es->st_value;
546 return 0;
547 }
548 return ENOENT;
549 }
550
551 int
552 ksyms_getval(const char *mod, const char *sym, unsigned long *val, int type)
553 {
554 int rc;
555
556 mutex_enter(&ksyms_lock);
557 rc = ksyms_getval_unlocked(mod, sym, val, type);
558 mutex_exit(&ksyms_lock);
559 return rc;
560 }
561
562
563 /*
564 * Get "mod" and "symbol" associated with an address.
565 * Returns 0 if success or ENOENT if no such entry.
566 *
567 * Call with ksyms_lock, unless known that the symbol table can't change.
568 */
569 int
570 ksyms_getname(const char **mod, const char **sym, vaddr_t v, int f)
571 {
572 struct ksyms_symtab *st;
573 Elf_Sym *les, *es = NULL;
574 vaddr_t laddr = 0;
575 const char *lmod = NULL;
576 char *stable = NULL;
577 int type, i, sz;
578
579 if (!ksyms_initted)
580 return ENOENT;
581
582 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
583 if (st->sd_gone)
584 continue;
585 if (st->sd_minsym != NULL && v < st->sd_minsym->st_value)
586 continue;
587 if (st->sd_maxsym != NULL && v > st->sd_maxsym->st_value)
588 continue;
589 sz = st->sd_symsize/sizeof(Elf_Sym);
590 for (i = 0; i < sz; i++) {
591 les = st->sd_symstart + i;
592 type = ELF_ST_TYPE(les->st_info);
593
594 if ((f & KSYMS_PROC) && (type != STT_FUNC))
595 continue;
596
597 if (type == STT_NOTYPE)
598 continue;
599
600 if (((f & KSYMS_ANY) == 0) &&
601 (type != STT_FUNC) && (type != STT_OBJECT))
602 continue;
603
604 if ((les->st_value <= v) && (les->st_value > laddr)) {
605 laddr = les->st_value;
606 es = les;
607 lmod = st->sd_name;
608 stable = st->sd_strstart - st->sd_usroffset;
609 }
610 }
611 }
612 if (es == NULL)
613 return ENOENT;
614 if ((f & KSYMS_EXACT) && (v != es->st_value))
615 return ENOENT;
616 if (mod)
617 *mod = lmod;
618 if (sym)
619 *sym = stable + es->st_name;
620 return 0;
621 }
622
623 /*
624 * Temporary work structure for dynamic loaded symbol tables.
625 *
626 * XXX REMOVE WHEN LKMS GO.
627 */
628 struct syminfo {
629 size_t cursyms;
630 size_t curnamep;
631 size_t maxsyms;
632 size_t maxnamep;
633 Elf_Sym *syms;
634 char *symnames;
635 };
636
637 /*
638 * Add a symbol to the temporary save area for symbols.
639 *
640 * XXX REMOVE WHEN LKMS GO.
641 */
642 static void
643 addsym(struct syminfo *info, const Elf_Sym *sym, const char *name,
644 const char *mod)
645 {
646 int len, mlen;
647
648 #ifdef KSYMS_DEBUG
649 if (ksyms_debug & FOLLOW_MORE_CALLS)
650 printf("addsym: name %s val %lx\n", name, (long)sym->st_value);
651 #endif
652 len = strlen(name) + 1;
653 if (mod)
654 mlen = 1 + strlen(mod);
655 else
656 mlen = 0;
657 if (info->cursyms == info->maxsyms ||
658 (len + mlen + info->curnamep) > info->maxnamep) {
659 printf("addsym: too many symbols, skipping '%s'\n", name);
660 return;
661 }
662 strlcpy(&info->symnames[info->curnamep], name,
663 info->maxnamep - info->curnamep);
664 if (mlen) {
665 info->symnames[info->curnamep + len - 1] = '.';
666 strlcpy(&info->symnames[info->curnamep + len], mod,
667 info->maxnamep - (info->curnamep + len));
668 len += mlen;
669 }
670 info->syms[info->cursyms] = *sym;
671 info->syms[info->cursyms].st_name = info->curnamep;
672 info->curnamep += len;
673 if (len > ksyms_maxlen)
674 ksyms_maxlen = len;
675 info->cursyms++;
676 }
677
678 /*
679 * XXX REMOVE WHEN LKMS GO.
680 */
681 static int
682 specialsym(const char *symname)
683 {
684
685 return !strcmp(symname, "_bss_start") ||
686 !strcmp(symname, "__bss_start") ||
687 !strcmp(symname, "_bss_end__") ||
688 !strcmp(symname, "__bss_end__") ||
689 !strcmp(symname, "_edata") ||
690 !strcmp(symname, "_end") ||
691 !strcmp(symname, "__end") ||
692 !strcmp(symname, "__end__") ||
693 !strncmp(symname, "__start_link_set_", 17) ||
694 !strncmp(symname, "__stop_link_set_", 16);
695 }
696
697 /*
698 * Adds a symbol table.
699 * "name" is the module name, "start" and "size" is where the symbol table
700 * is located, and "type" is in which binary format the symbol table is.
701 * New memory for keeping the symbol table is allocated in this function.
702 * Returns 0 if success and EEXIST if the module name is in use.
703 *
704 * XXX REMOVE WHEN LKMS GO.
705 */
706 int
707 ksyms_addsymtab(const char *mod, void *symstart, vsize_t symsize,
708 char *strstart, vsize_t strsize)
709 {
710 Elf_Sym *sym = symstart;
711 struct ksyms_symtab *st;
712 unsigned long rval;
713 int i;
714 char *name;
715 struct syminfo info;
716
717 #ifdef KSYMS_DEBUG
718 if (ksyms_debug & FOLLOW_CALLS)
719 printf("ksyms_addsymtab: mod %s symsize %lx strsize %lx\n",
720 mod, symsize, strsize);
721 #endif
722
723 mutex_enter(&ksyms_lock);
724
725 /* Check if this symtab already loaded */
726 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
727 if (st->sd_gone)
728 continue;
729 if (strcmp(mod, st->sd_name) == 0) {
730 mutex_exit(&ksyms_lock);
731 return EEXIST;
732 }
733 }
734
735 /*
736 * XXX - Only add a symbol if it do not exist already.
737 * This is because of a flaw in the current LKM implementation,
738 * these loops will be removed once the in-kernel linker is in place.
739 */
740 memset(&info, 0, sizeof(info));
741 for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
742 char * const symname = strstart + sym[i].st_name;
743 if (sym[i].st_name == 0)
744 continue; /* Just ignore */
745
746 /* check validity of the symbol */
747 /* XXX - save local symbols if DDB */
748 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
749 continue;
750
751 /* Check if the symbol exists */
752 if (ksyms_getval_unlocked(NULL, symname, &rval, KSYMS_EXTERN)
753 == 0) {
754 /* Check (and complain) about differing values */
755 if (sym[i].st_value != rval &&
756 sym[i].st_shndx != SHN_UNDEF) {
757 if (specialsym(symname)) {
758 info.maxsyms++;
759 info.maxnamep += strlen(symname) + 1 +
760 strlen(mod) + 1;
761 } else {
762 printf("%s: symbol '%s' redeclared with"
763 " different value (%lx != %lx)\n",
764 mod, symname,
765 rval, (long)sym[i].st_value);
766 }
767 }
768 } else {
769 /*
770 * Count this symbol
771 */
772 info.maxsyms++;
773 info.maxnamep += strlen(symname) + 1;
774 }
775 }
776
777 /*
778 * Now that we know the sizes, malloc the structures.
779 */
780 info.syms = malloc(sizeof(Elf_Sym)*info.maxsyms, M_DEVBUF, M_WAITOK);
781 info.symnames = malloc(info.maxnamep, M_DEVBUF, M_WAITOK);
782
783 /*
784 * Now that we have the symbols, actually fill in the structures.
785 */
786 for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
787 char * const symname = strstart + sym[i].st_name;
788 if (sym[i].st_name == 0)
789 continue; /* Just ignore */
790
791 /* check validity of the symbol */
792 /* XXX - save local symbols if DDB */
793 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
794 continue;
795
796 /* Check if the symbol exists */
797 if (ksyms_getval_unlocked(NULL, symname, &rval, KSYMS_EXTERN)
798 == 0) {
799 if ((sym[i].st_value != rval) && specialsym(symname)) {
800 addsym(&info, &sym[i], symname, mod);
801 }
802 } else
803 /* Ok, save this symbol */
804 addsym(&info, &sym[i], symname, NULL);
805 }
806
807 st = kmem_zalloc(sizeof(*st), KM_SLEEP);
808 i = strlen(mod) + 1;
809 name = malloc(i, M_DEVBUF, M_WAITOK);
810 strlcpy(name, mod, i);
811 st->sd_name = name;
812 st->sd_symstart = info.syms;
813 st->sd_symsize = sizeof(Elf_Sym)*info.maxsyms;
814 st->sd_strstart = info.symnames;
815 st->sd_strsize = info.maxnamep;
816 st->sd_malloc = true;
817
818 /* Make them absolute references */
819 sym = st->sd_symstart;
820 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
821 sym[i].st_shndx = SHN_ABS;
822
823 /* ksymsread() is unlocked, so membar. */
824 membar_producer();
825 TAILQ_INSERT_TAIL(&ksyms_symtabs, st, sd_queue);
826 ksyms_sizes_calc();
827 mutex_exit(&ksyms_lock);
828
829 return 0;
830 }
831
832 /*
833 * Remove a symbol table specified by name.
834 * Returns 0 if success, EBUSY if device open and ENOENT if no such name.
835 *
836 * XXX REMOVE WHEN LKMS GO.
837 */
838 int
839 ksyms_delsymtab(const char *mod)
840 {
841 struct ksyms_symtab *st;
842
843 mutex_enter(&ksyms_lock);
844 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
845 if (st->sd_gone)
846 continue;
847 if (strcmp(mod, st->sd_name) != 0)
848 continue;
849 if (ksyms_isopen) {
850 st->sd_gone = true;
851 mutex_exit(&ksyms_lock);
852 return 0;
853 }
854 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
855 ksyms_sizes_calc();
856 mutex_exit(&ksyms_lock);
857 KASSERT(st->sd_malloc);
858 free(st->sd_symstart, M_DEVBUF);
859 free(st->sd_strstart, M_DEVBUF);
860 /* XXXUNCONST LINTED - const castaway */
861 free(__UNCONST(st->sd_name), M_DEVBUF);
862 kmem_free(st, sizeof(*st));
863 return 0;
864 }
865 mutex_exit(&ksyms_lock);
866 return ENOENT;
867 }
868
869 /*
870 * Add a symbol table from a loadable module.
871 */
872 void
873 ksyms_modload(const char *name, void *symstart, vsize_t symsize,
874 char *strstart, vsize_t strsize)
875 {
876 struct ksyms_symtab *st;
877
878 st = kmem_zalloc(sizeof(*st), KM_SLEEP);
879 mutex_enter(&ksyms_lock);
880 addsymtab(name, symstart, symsize, strstart, strsize, st, symstart);
881 mutex_exit(&ksyms_lock);
882 }
883
884 /*
885 * Remove a symbol table from a loadable module.
886 */
887 void
888 ksyms_modunload(const char *name)
889 {
890 struct ksyms_symtab *st;
891
892 mutex_enter(&ksyms_lock);
893 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
894 if (st->sd_gone)
895 continue;
896 if (strcmp(name, st->sd_name) != 0)
897 continue;
898 KASSERT(!st->sd_malloc); /* XXXLKM */
899 st->sd_gone = true;
900 if (!ksyms_isopen) {
901 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
902 ksyms_sizes_calc();
903 kmem_free(st, sizeof(*st));
904 }
905 break;
906 }
907 mutex_exit(&ksyms_lock);
908 KASSERT(st != NULL);
909 }
910
911 #ifdef DDB
912 /*
913 * Keep sifting stuff here, to avoid export of ksyms internals.
914 *
915 * Systems is expected to be quiescent, so no locking done.
916 */
917 int
918 ksyms_sift(char *mod, char *sym, int mode)
919 {
920 struct ksyms_symtab *st;
921 char *sb;
922 int i, sz;
923
924 if (!ksyms_initted)
925 return ENOENT;
926
927 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
928 if (st->sd_gone)
929 continue;
930 if (mod && strcmp(mod, st->sd_name))
931 continue;
932 sb = st->sd_strstart - st->sd_usroffset;
933
934 sz = st->sd_symsize/sizeof(Elf_Sym);
935 for (i = 0; i < sz; i++) {
936 Elf_Sym *les = st->sd_symstart + i;
937 char c;
938
939 if (strstr(sb + les->st_name, sym) == NULL)
940 continue;
941
942 if (mode == 'F') {
943 switch (ELF_ST_TYPE(les->st_info)) {
944 case STT_OBJECT:
945 c = '+';
946 break;
947 case STT_FUNC:
948 c = '*';
949 break;
950 case STT_SECTION:
951 c = '&';
952 break;
953 case STT_FILE:
954 c = '/';
955 break;
956 default:
957 c = ' ';
958 break;
959 }
960 db_printf("%s%c ", sb + les->st_name, c);
961 } else
962 db_printf("%s ", sb + les->st_name);
963 }
964 }
965 return ENOENT;
966 }
967 #endif /* DDB */
968
969 /*
970 * In case we exposing the symbol table to the userland using the pseudo-
971 * device /dev/ksyms, it is easier to provide all the tables as one.
972 * However, it means we have to change all the st_name fields for the
973 * symbols so they match the ELF image that the userland will read
974 * through the device.
975 *
976 * The actual (correct) value of st_name is preserved through a global
977 * offset stored in the symbol table structure.
978 *
979 * Call with ksyms_lock held.
980 */
981 static void
982 ksyms_sizes_calc(void)
983 {
984 struct ksyms_symtab *st;
985 int i, delta;
986
987 ksyms_symsz = ksyms_strsz = 0;
988 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
989 delta = ksyms_strsz - st->sd_usroffset;
990 if (delta != 0) {
991 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
992 st->sd_symstart[i].st_name += delta;
993 st->sd_usroffset = ksyms_strsz;
994 }
995 ksyms_symsz += st->sd_symsize;
996 ksyms_strsz += st->sd_strsize;
997 }
998 }
999
1000 static void
1001 ksyms_hdr_init(void *hdraddr)
1002 {
1003
1004 /* Copy the loaded elf exec header */
1005 memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr));
1006
1007 /* Set correct program/section header sizes, offsets and numbers */
1008 ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]);
1009 ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr);
1010 ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR;
1011 ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]);
1012 ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr);
1013 ksyms_hdr.kh_ehdr.e_shnum = NSECHDR;
1014 ksyms_hdr.kh_ehdr.e_shstrndx = NSECHDR - 1; /* Last section */
1015
1016 /* Text */
1017 ksyms_hdr.kh_phdr[0].p_type = PT_LOAD;
1018 ksyms_hdr.kh_phdr[0].p_memsz = (unsigned long)-1L;
1019 ksyms_hdr.kh_phdr[0].p_flags = PF_R | PF_X;
1020
1021 /* Data */
1022 ksyms_hdr.kh_phdr[1].p_type = PT_LOAD;
1023 ksyms_hdr.kh_phdr[1].p_memsz = (unsigned long)-1L;
1024 ksyms_hdr.kh_phdr[1].p_flags = PF_R | PF_W | PF_X;
1025
1026 /* First section is null */
1027
1028 /* Second section header; ".symtab" */
1029 ksyms_hdr.kh_shdr[SYMTAB].sh_name = 1; /* Section 3 offset */
1030 ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB;
1031 ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr);
1032 /* ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */
1033 ksyms_hdr.kh_shdr[SYMTAB].sh_link = 2; /* Corresponding strtab */
1034 ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long);
1035 ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym);
1036
1037 /* Third section header; ".strtab" */
1038 ksyms_hdr.kh_shdr[STRTAB].sh_name = 9; /* Section 3 offset */
1039 ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB;
1040 /* ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */
1041 /* ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */
1042 ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char);
1043
1044 /* Fourth section, ".shstrtab" */
1045 ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = 17; /* This section name offset */
1046 ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB;
1047 ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset =
1048 offsetof(struct ksyms_hdr, kh_strtab);
1049 ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ;
1050 ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char);
1051
1052 /* Set section names */
1053 strlcpy(&ksyms_hdr.kh_strtab[1], ".symtab",
1054 sizeof(ksyms_hdr.kh_strtab) - 1);
1055 strlcpy(&ksyms_hdr.kh_strtab[9], ".strtab",
1056 sizeof(ksyms_hdr.kh_strtab) - 9);
1057 strlcpy(&ksyms_hdr.kh_strtab[17], ".shstrtab",
1058 sizeof(ksyms_hdr.kh_strtab) - 17);
1059 }
1060
1061 static int
1062 ksymsopen(dev_t dev, int oflags, int devtype, struct lwp *l)
1063 {
1064
1065 if (minor(dev) != 0 || !ksyms_initted)
1066 return ENXIO;
1067
1068 /*
1069 * Create a "snapshot" of the kernel symbol table. Setting
1070 * ksyms_isopen will prevent symbol tables from being freed.
1071 */
1072 mutex_enter(&ksyms_lock);
1073 ksyms_hdr.kh_shdr[SYMTAB].sh_size = ksyms_symsz;
1074 ksyms_hdr.kh_shdr[SYMTAB].sh_info = ksyms_symsz / sizeof(Elf_Sym);
1075 ksyms_hdr.kh_shdr[STRTAB].sh_offset = ksyms_symsz +
1076 ksyms_hdr.kh_shdr[SYMTAB].sh_offset;
1077 ksyms_hdr.kh_shdr[STRTAB].sh_size = ksyms_strsz;
1078 ksyms_isopen = true;
1079 mutex_exit(&ksyms_lock);
1080
1081 return 0;
1082 }
1083
1084 static int
1085 ksymsclose(dev_t dev, int oflags, int devtype, struct lwp *l)
1086 {
1087 struct ksyms_symtab *st, *next;
1088 bool resize;
1089
1090 /* Discard refernces to symbol tables. */
1091 mutex_enter(&ksyms_lock);
1092 ksyms_isopen = false;
1093 resize = false;
1094 for (st = TAILQ_FIRST(&ksyms_symtabs); st != NULL; st = next) {
1095 next = TAILQ_NEXT(st, sd_queue);
1096 if (st->sd_gone) {
1097 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue);
1098 kmem_free(st, sizeof(*st));
1099 if (st->sd_malloc) { /* XXXLKM */
1100 free(st->sd_symstart, M_DEVBUF);
1101 free(st->sd_strstart, M_DEVBUF);
1102 /* XXXUNCONST LINTED - const castaway */
1103 free(__UNCONST(st->sd_name), M_DEVBUF);
1104 }
1105 resize = true;
1106 }
1107 }
1108 if (resize)
1109 ksyms_sizes_calc();
1110 mutex_exit(&ksyms_lock);
1111
1112 return 0;
1113 }
1114
1115 static int
1116 ksymsread(dev_t dev, struct uio *uio, int ioflag)
1117 {
1118 struct ksyms_symtab *st;
1119 size_t filepos, inpos, off;
1120 int error;
1121
1122 /*
1123 * First: Copy out the ELF header. XXX Lose if ksymsopen()
1124 * occurs during read of the header.
1125 */
1126 off = uio->uio_offset;
1127 if (off < sizeof(struct ksyms_hdr)) {
1128 error = uiomove((char *)&ksyms_hdr + off,
1129 sizeof(struct ksyms_hdr) - off, uio);
1130 if (error != 0)
1131 return error;
1132 }
1133
1134 /*
1135 * Copy out the symbol table.
1136 */
1137 filepos = sizeof(struct ksyms_hdr);
1138 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
1139 if (uio->uio_resid == 0)
1140 return 0;
1141 if (uio->uio_offset <= st->sd_symsize + filepos) {
1142 inpos = uio->uio_offset - filepos;
1143 error = uiomove((char *)st->sd_symstart + inpos,
1144 st->sd_symsize - inpos, uio);
1145 if (error != 0)
1146 return error;
1147 }
1148 filepos += st->sd_symsize;
1149 }
1150
1151 /*
1152 * Copy out the string table
1153 */
1154 KASSERT(filepos == sizeof(struct ksyms_hdr) +
1155 ksyms_hdr.kh_shdr[SYMTAB].sh_size);
1156 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
1157 if (uio->uio_resid == 0)
1158 return 0;
1159 if (uio->uio_offset <= st->sd_strsize + filepos) {
1160 inpos = uio->uio_offset - filepos;
1161 error = uiomove((char *)st->sd_strstart + inpos,
1162 st->sd_strsize - inpos, uio);
1163 if (error != 0)
1164 return error;
1165 }
1166 filepos += st->sd_strsize;
1167 }
1168
1169 return 0;
1170 }
1171
1172 static int
1173 ksymswrite(dev_t dev, struct uio *uio, int ioflag)
1174 {
1175
1176 return EROFS;
1177 }
1178
1179 static int
1180 ksymsioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l)
1181 {
1182 struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data;
1183 struct ksyms_symtab *st;
1184 Elf_Sym *sym = NULL, copy;
1185 unsigned long val;
1186 int error = 0;
1187 char *str = NULL;
1188 int len;
1189
1190 /* Read ksyms_maxlen only once while not holding the lock. */
1191 len = ksyms_maxlen;
1192
1193 if (cmd == KIOCGVALUE || cmd == KIOCGSYMBOL) {
1194 str = kmem_alloc(len, KM_SLEEP);
1195 if ((error = copyinstr(kg->kg_name, str, len, NULL)) != 0) {
1196 kmem_free(str, len);
1197 return error;
1198 }
1199 }
1200
1201 switch (cmd) {
1202 case KIOCGVALUE:
1203 /*
1204 * Use the in-kernel symbol lookup code for fast
1205 * retreival of a value.
1206 */
1207 error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN);
1208 if (error == 0)
1209 error = copyout(&val, kg->kg_value, sizeof(long));
1210 kmem_free(str, len);
1211 break;
1212
1213 case KIOCGSYMBOL:
1214 /*
1215 * Use the in-kernel symbol lookup code for fast
1216 * retreival of a symbol.
1217 */
1218 mutex_enter(&ksyms_lock);
1219 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) {
1220 if (st->sd_gone)
1221 continue;
1222 if ((sym = findsym(str, st)) == NULL)
1223 continue;
1224 #ifdef notdef
1225 /* Skip if bad binding */
1226 if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
1227 sym = NULL;
1228 continue;
1229 }
1230 #endif
1231 break;
1232 }
1233 if (sym != NULL) {
1234 memcpy(©, sym, sizeof(copy));
1235 mutex_exit(&ksyms_lock);
1236 error = copyout(©, kg->kg_sym, sizeof(Elf_Sym));
1237 } else {
1238 mutex_exit(&ksyms_lock);
1239 error = ENOENT;
1240 }
1241 kmem_free(str, len);
1242 break;
1243
1244 case KIOCGSIZE:
1245 /*
1246 * Get total size of symbol table.
1247 */
1248 mutex_enter(&ksyms_lock);
1249 *(int *)data = ksyms_strsz + ksyms_symsz +
1250 sizeof(struct ksyms_hdr);
1251 mutex_exit(&ksyms_lock);
1252 break;
1253
1254 default:
1255 error = ENOTTY;
1256 break;
1257 }
1258
1259 return error;
1260 }
1261
1262 const struct cdevsw ksyms_cdevsw = {
1263 ksymsopen, ksymsclose, ksymsread, ksymswrite, ksymsioctl,
1264 nullstop, notty, nopoll, nommap, nullkqfilter, D_OTHER | D_MPSAFE
1265 };
Cache object: 69ed25ae016d8f863ffb6715fddc364d
|