kern_ksyms.c revision 1.4 1 /* $NetBSD: kern_ksyms.c,v 1.4 2003/04/26 10:24:58 ragge Exp $ */
2 /*
3 * Copyright (c) 2001, 2003 Anders Magnusson (ragge (at) ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * Code to deal with in-kernel symbol table management + /dev/ksyms.
31 *
32 * For each loaded module the symbol table info is kept track of by a
33 * struct, placed in a circular list. The first entry is the kernel
34 * symbol table.
35 */
36
37 /*
38 * TODO:
39 * Fix quick-search of symbols. (comes with linker)
40 * Change the ugly way of adding new symbols (comes with linker)
41 * Add kernel locking stuff.
42 * (Ev) add support for poll.
43 * (Ev) fix support for mmap.
44 *
45 * Export ksyms internal logic for use in post-mortem debuggers?
46 * Need to move struct symtab to ksyms.h for that.
47 */
48
49 #ifdef _KERNEL
50 #include "opt_ddb.h"
51 #include "opt_ddbparam.h" /* for SYMTAB_SPACE */
52 #endif
53
54 #include <sys/param.h>
55 #include <sys/errno.h>
56 #include <sys/queue.h>
57 #include <sys/exec.h>
58 #include <sys/systm.h>
59 #include <sys/conf.h>
60 #include <sys/device.h>
61 #include <sys/malloc.h>
62 #include <sys/proc.h>
63
64 #include <machine/elf_machdep.h> /* XXX */
65 #define ELFSIZE ARCH_ELFSIZE
66
67 #include <sys/exec_elf.h>
68 #include <sys/ksyms.h>
69
70 #include <lib/libkern/libkern.h>
71
72 #ifdef DDB
73 #include <ddb/db_output.h>
74 #endif
75
76 #include "ksyms.h"
77
78 static int ksymsinited = 0;
79
80 #if NKSYMS
81 static void ksyms_hdr_init(caddr_t hdraddr);
82 static void ksyms_sizes_calc(void);
83 static int ksyms_isopen;
84 #endif
85
86 #ifdef KSYMS_DEBUG
87 #define FOLLOW_CALLS 1
88 #define FOLLOW_MORE_CALLS 2
89 #define FOLLOW_DEVKSYMS 4
90 static int ksyms_debug;
91 #endif
92
93 #if NKSYMS
94 dev_type_open(ksymsopen);
95 dev_type_close(ksymsclose);
96 dev_type_read(ksymsread);
97 dev_type_write(ksymswrite);
98 dev_type_ioctl(ksymsioctl);
99
100 const struct cdevsw ksyms_cdevsw = {
101 ksymsopen, ksymsclose, ksymsread, ksymswrite, ksymsioctl,
102 nullstop, notty, nopoll, nommap, nullkqfilter, DV_DULL
103 };
104 #endif
105
106 #ifdef SYMTAB_SPACE
107 #define SYMTAB_FILLER "|This is the symbol table!"
108
109 char db_symtab[SYMTAB_SPACE] = SYMTAB_FILLER;
110 int db_symtabsize = SYMTAB_SPACE;
111 #endif
112
113 /*
114 * Store the different symbol tables in a double-linked list.
115 */
116 struct symtab {
117 CIRCLEQ_ENTRY(symtab) sd_queue;
118 char *sd_name; /* Name of this table */
119 Elf_Sym *sd_symstart; /* Address of symbol table */
120 caddr_t sd_strstart; /* Adderss of corresponding string table */
121 int sd_symsize; /* Size in bytes of symbol table */
122 int sd_strsize; /* Size of string table */
123 int *sd_symnmoff; /* Used when calculating the name offset */
124 };
125
126 static CIRCLEQ_HEAD(, symtab) symtab_queue =
127 CIRCLEQ_HEAD_INITIALIZER(symtab_queue);
128
129 static struct symtab kernel_symtab;
130
131 /*
132 * Finds a certain symbol name in a certain symbol table.
133 * XXX - symbol hashing must be rewritten (missing)
134 */
135 static Elf_Sym *
136 findsym(char *name, struct symtab *table)
137 {
138 Elf_Sym *start = table->sd_symstart;
139 int i, sz = table->sd_symsize/sizeof(Elf_Sym);
140 char *np;
141
142 for (i = 0; i < sz; i++) {
143 np = table->sd_strstart + start[i].st_name;
144 if (name[0] == np[0] && name[1] == np[1] &&
145 strcmp(name, np) == 0)
146 return &start[i];
147 }
148 return NULL;
149 }
150
151 /*
152 * The "attach" is in reality done in ksyms_init().
153 */
154 void ksymsattach(int);
155 void
156 ksymsattach(int arg)
157 {
158 }
159
160 /*
161 * Add a symbol table named name.
162 * This is intended for use when the kernel loader enters the table.
163 */
164 static void
165 addsymtab(char *name, Elf_Ehdr *ehdr, struct symtab *tab)
166 {
167 caddr_t start = (caddr_t)ehdr;
168 Elf_Shdr *shdr;
169 Elf_Sym *sym;
170 int i, j;
171
172 /* Find the symbol table and the corresponding string table. */
173 shdr = (Elf_Shdr *)(start + ehdr->e_shoff);
174 for (i = 1; i < ehdr->e_shnum; i++) {
175 if (shdr[i].sh_type != SHT_SYMTAB)
176 continue;
177 if (shdr[i].sh_offset == 0)
178 continue;
179 tab->sd_symstart = (Elf_Sym *)(start + shdr[i].sh_offset);
180 tab->sd_symsize = shdr[i].sh_size;
181 j = shdr[i].sh_link;
182 if (shdr[j].sh_offset == 0)
183 continue; /* Can this happen? */
184 tab->sd_strstart = start + shdr[j].sh_offset;
185 tab->sd_strsize = shdr[j].sh_size;
186 break;
187 }
188 tab->sd_name = name;
189
190 /* Change all symbols to be absolute references */
191 sym = (Elf_Sym *)tab->sd_symstart;
192 for (i = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++)
193 sym[i].st_shndx = SHN_ABS;
194
195 CIRCLEQ_INSERT_HEAD(&symtab_queue, tab, sd_queue);
196 }
197
198 /*
199 * Setup the kernel symbol table stuff.
200 */
201 void
202 ksyms_init(int symsize, void *start, void *end)
203 {
204 Elf_Ehdr *ehdr;
205
206 #ifdef SYMTAB_SPACE
207 if (symsize <= 0 &&
208 strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) {
209 symsize = db_symtabsize;
210 start = db_symtab;
211 end = db_symtab + db_symtabsize;
212 }
213 #endif
214 if (symsize <= 0) {
215 printf("[ Kernel symbol table missing! ]\n");
216 return;
217 }
218
219 /* Sanity check */
220 if (ALIGNED_POINTER(start, long) == 0) {
221 printf("[ Kernel symbol table has bad start address %p ]\n",
222 start);
223 return;
224 }
225
226 ehdr = (Elf_Ehdr *)start;
227
228 /* check if this is a valid ELF header */
229 /* No reason to verify arch type, the kernel is actually running! */
230 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) ||
231 ehdr->e_ident[EI_CLASS] != ELFCLASS ||
232 ehdr->e_version > 1) {
233 #ifdef notyet /* DDB */
234 if (ddb_init(symsize, start, end))
235 return; /* old-style symbol table */
236 #endif
237 printf("[ Kernel symbol table invalid! ]\n");
238 return; /* nothing to do */
239 }
240
241 addsymtab("netbsd", ehdr, &kernel_symtab);
242 #if NKSYMS
243 ksyms_sizes_calc();
244 #endif
245 ksymsinited = 1;
246 #ifdef DEBUG
247 printf("Loaded initial symtab at %p, strtab at %p, # entries %ld\n",
248 kernel_symtab.sd_symstart, kernel_symtab.sd_strstart,
249 (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym));
250 #endif
251
252 #if NKSYMS
253 ksyms_hdr_init(start);
254 #endif
255 }
256
257 /*
258 * Get the value associated with a symbol.
259 * "mod" is the module name, or null if any module.
260 * "sym" is the symbol name.
261 * "val" is a pointer to the corresponding value, if call succeeded.
262 * Returns 0 if success or ENOENT if no such entry.
263 */
264 int
265 ksyms_getval(char *mod, char *sym, unsigned long *val, int type)
266 {
267 struct symtab *st;
268 Elf_Sym *es;
269
270 if (ksymsinited == 0)
271 return ENOENT;
272
273 #ifdef KSYMS_DEBUG
274 if (ksyms_debug & FOLLOW_CALLS)
275 printf("ksyms_getval: mod %s sym %s valp %p\n", mod, sym, val);
276 #endif
277
278 /* XXX search order XXX */
279 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
280 if (mod && strcmp(st->sd_name, mod))
281 continue;
282 if ((es = findsym(sym, st)) == NULL)
283 continue;
284
285 /* Skip if bad binding */
286 if (type == KSYMS_EXTERN &&
287 ELF_ST_BIND(es->st_info) != STB_GLOBAL)
288 continue;
289
290 if (val)
291 *val = es->st_value;
292 return 0;
293 }
294 return ENOENT;
295 }
296
297 /*
298 * Get "mod" and "symbol" associated with an address.
299 * Returns 0 if success or ENOENT if no such entry.
300 */
301 int
302 ksyms_getname(char **mod, char **sym, vaddr_t v, int f)
303 {
304 struct symtab *st;
305 Elf_Sym *les, *es = NULL;
306 vaddr_t laddr = 0;
307 char *lmod, *stable;
308 int type, i, sz;
309
310 if (ksymsinited == 0)
311 return ENOENT;
312
313 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
314 sz = st->sd_symsize/sizeof(Elf_Sym);
315 for (i = 0; i < sz; i++) {
316 les = st->sd_symstart + i;
317 type = ELF_ST_TYPE(les->st_info);
318
319 if ((f & KSYMS_PROC) && (type != STT_FUNC))
320 continue;
321
322 if (type == STT_NOTYPE)
323 continue;
324
325 if (((f & KSYMS_ANY) == 0) &&
326 (type != STT_FUNC) && (type != STT_OBJECT))
327 continue;
328
329 if ((les->st_value <= v) && (les->st_value > laddr)) {
330 laddr = les->st_value;
331 es = les;
332 lmod = st->sd_name;
333 stable = st->sd_strstart;
334 }
335 }
336 }
337 if (es == NULL)
338 return ENOENT;
339 if ((f & KSYMS_EXACT) && (v != es->st_value))
340 return ENOENT;
341 if (mod)
342 *mod = lmod;
343 if (sym)
344 *sym = stable + es->st_name;
345 return 0;
346 }
347
348 #if NKSYMS
349 static int symsz, strsz;
350
351 static void
352 ksyms_sizes_calc(void)
353 {
354 struct symtab *st;
355 int i;
356
357 symsz = strsz = 0;
358 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
359 if (st != &kernel_symtab) {
360 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
361 st->sd_symstart[i].st_name =
362 strsz + st->sd_symnmoff[i];
363 }
364 symsz += st->sd_symsize;
365 strsz += st->sd_strsize;
366 }
367 }
368 #endif
369
370 /*
371 * Temporary work buffers for dynamic loaded symbol tables.
372 * Will go away when in-kernel linker is in place.
373 */
374 #define NSAVEDSYMS 512
375 #define SZSYMNAMES NSAVEDSYMS*8 /* Just an approximation */
376 static Elf_Sym savedsyms[NSAVEDSYMS];
377 static int symnmoff[NSAVEDSYMS];
378 static char symnames[SZSYMNAMES];
379 static int cursyms, curnamep;
380
381 /*
382 * Add a symbol to the temporary save area for symbols.
383 * This routine will go away when the in-kernel linker is in place.
384 */
385 static void
386 addsym(Elf_Sym *sym, char *name)
387 {
388 int len;
389
390 #ifdef KSYMS_DEBUG
391 if (ksyms_debug & FOLLOW_MORE_CALLS)
392 printf("addsym: name %s val %lx\n", name, (long)sym->st_value);
393 #endif
394 if (cursyms == NSAVEDSYMS ||
395 ((len = strlen(name)) + curnamep + 1) > SZSYMNAMES) {
396 printf("addsym: too many sumbols, skipping '%s'\n", name);
397 return;
398 }
399 strcpy(&symnames[curnamep], name);
400 savedsyms[cursyms] = *sym;
401 symnmoff[cursyms] = savedsyms[cursyms].st_name = curnamep;
402 curnamep += (len + 1);
403 cursyms++;
404 }
405 /*
406 * Adds a symbol table.
407 * "name" is the module name, "start" and "size" is where the symbol table
408 * is located, and "type" is in which binary format the symbol table is.
409 * New memory for keeping the symbol table is allocated in this function.
410 * Returns 0 if success and EEXIST if the module name is in use.
411 */
412 int
413 ksyms_addsymtab(char *mod, void *symstart, vsize_t symsize,
414 char *strstart, vsize_t strsize)
415 {
416 Elf_Sym *sym = symstart;
417 struct symtab *st;
418 long rval;
419 int i;
420 char *str;
421
422 #ifdef KSYMS_DEBUG
423 if (ksyms_debug & FOLLOW_CALLS)
424 printf("ksyms_addsymtab: mod %s symsize %lx strsize %lx\n",
425 mod, symsize, strsize);
426 #endif
427
428 #if NKSYMS
429 /*
430 * Do not try to add a symbol table while someone is reading
431 * from /dev/ksyms.
432 */
433 while (ksyms_isopen != 0)
434 tsleep(&ksyms_isopen, PWAIT, "ksyms", 0);
435 #endif
436
437 /* Check if this symtab already loaded */
438 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
439 if (strcmp(mod, st->sd_name) == 0)
440 return EEXIST;
441 }
442
443 /*
444 * XXX - Only add a symbol if it do not exist already.
445 * This is because of a flaw in the current LKM implementation,
446 * the loop will be removed once the in-kernel linker is in place.
447 */
448 cursyms = curnamep = 0;
449 for (i = 0; i < symsize/sizeof(Elf_Sym); i++) {
450 if (sym[i].st_name == 0)
451 continue; /* Just ignore */
452
453 /* check validity of the symbol */
454 /* XXX - save local symbols if DDB */
455 if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
456 continue;
457
458 /* Check if the symbol exists */
459 if (ksyms_getval(NULL, strstart + sym[i].st_name,
460 &rval, KSYMS_EXTERN) == 0) {
461 /* Check (and complain) about differing values */
462 if (sym[i].st_value != rval) {
463 printf("%s: symbol '%s' redeclared with "
464 "different value (%lx != %lx)\n",
465 mod, strstart + sym[i].st_name,
466 rval, (long)sym[i].st_value);
467 }
468 } else
469 /* Ok, save this symbol */
470 addsym(&sym[i], strstart + sym[i].st_name);
471 }
472 sym = malloc(sizeof(Elf_Sym)*cursyms, M_DEVBUF, M_WAITOK);
473 str = malloc(curnamep, M_DEVBUF, M_WAITOK);
474 memcpy(sym, savedsyms, sizeof(Elf_Sym)*cursyms);
475 memcpy(str, symnames, curnamep);
476
477 st = malloc(sizeof(struct symtab), M_DEVBUF, M_WAITOK);
478 st->sd_name = malloc(strlen(mod)+1, M_DEVBUF, M_WAITOK);
479 strcpy(st->sd_name, mod);
480 st->sd_symnmoff = malloc(sizeof(int)*cursyms, M_DEVBUF, M_WAITOK);
481 memcpy(st->sd_symnmoff, symnmoff, sizeof(int)*cursyms);
482 st->sd_symstart = sym;
483 st->sd_symsize = sizeof(Elf_Sym)*cursyms;
484 st->sd_strstart = str;
485 st->sd_strsize = curnamep;
486
487 /* Make them absolute references */
488 sym = st->sd_symstart;
489 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
490 sym[i].st_shndx = SHN_ABS;
491
492 CIRCLEQ_INSERT_TAIL(&symtab_queue, st, sd_queue);
493 #if NKSYMS
494 ksyms_sizes_calc();
495 #endif
496 return 0;
497 }
498
499 /*
500 * Remove a symbol table specified by name.
501 * Returns 0 if success, EBUSY if device open and ENOENT if no such name.
502 */
503 int
504 ksyms_delsymtab(char *mod)
505 {
506 struct symtab *st;
507 int found = 0;
508
509 #if NKSYMS
510 /*
511 * Do not try to delete a symbol table while someone is reading
512 * from /dev/ksyms.
513 */
514 while (ksyms_isopen != 0)
515 tsleep(&ksyms_isopen, PWAIT, "ksyms", 0);
516 #endif
517
518 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
519 if (strcmp(mod, st->sd_name) == 0) {
520 found = 1;
521 break;
522 }
523 }
524 if (found == 0)
525 return ENOENT;
526 CIRCLEQ_REMOVE(&symtab_queue, st, sd_queue);
527 free(st->sd_symstart, M_DEVBUF);
528 free(st->sd_strstart, M_DEVBUF);
529 free(st->sd_symnmoff, M_DEVBUF);
530 free(st->sd_name, M_DEVBUF);
531 free(st, M_DEVBUF);
532 #if NKSYMS
533 ksyms_sizes_calc();
534 #endif
535 return 0;
536 }
537
538 #ifdef DDB
539
540 /*
541 * Keep sifting stuff here, to avoid export of ksyms internals.
542 */
543 int
544 ksyms_sift(char *mod, char *sym, int mode)
545 {
546 struct symtab *st;
547 char *sb;
548 int i, sz;
549
550 if (ksymsinited == 0)
551 return ENOENT;
552
553 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
554 if (mod && strcmp(mod, st->sd_name))
555 continue;
556 sb = st->sd_strstart;
557
558 sz = st->sd_symsize/sizeof(Elf_Sym);
559 for (i = 0; i < sz; i++) {
560 Elf_Sym *les = st->sd_symstart + i;
561 char c;
562
563 if (strstr(sb + les->st_name, sym) == NULL)
564 continue;
565
566 if (mode == 'F') {
567 switch (ELF_ST_TYPE(les->st_info)) {
568 case STT_OBJECT:
569 c = '+';
570 break;
571 case STT_FUNC:
572 c = '*';
573 break;
574 case STT_SECTION:
575 c = '&';
576 break;
577 case STT_FILE:
578 c = '/';
579 break;
580 default:
581 c = ' ';
582 break;
583 }
584 db_printf("%s%c ", sb + les->st_name, c);
585 } else
586 db_printf("%s ", sb + les->st_name);
587 }
588 }
589 return ENOENT;
590 }
591 #endif
592
593 #if NKSYMS
594
595 /*
596 * Static allocated ELF header.
597 * Basic info is filled in at attach, sizes at open.
598 */
599 #define SYMTAB 1
600 #define STRTAB 2
601 #define SHSTRTAB 3
602 #define NSECHDR 4
603
604 #define NPRGHDR 2
605 #define SHSTRSIZ 28
606
607 static struct ksyms_hdr {
608 Elf_Ehdr kh_ehdr;
609 Elf_Phdr kh_phdr[NPRGHDR];
610 Elf_Shdr kh_shdr[NSECHDR];
611 char kh_strtab[SHSTRSIZ];
612 } ksyms_hdr;
613
614
615 void
616 ksyms_hdr_init(caddr_t hdraddr)
617 {
618
619 /* Copy the loaded elf exec header */
620 memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr));
621
622 /* Set correct program/section header sizes, offsets and numbers */
623 ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]);
624 ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr);
625 ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR;
626 ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]);
627 ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr);
628 ksyms_hdr.kh_ehdr.e_shnum = NSECHDR;
629 ksyms_hdr.kh_ehdr.e_shstrndx = NSECHDR - 1; /* Last section */
630
631 /*
632 * Keep program headers zeroed (unused).
633 * The section headers are hand-crafted.
634 * First section is section zero.
635 */
636
637 /* Second section header; ".symtab" */
638 ksyms_hdr.kh_shdr[SYMTAB].sh_name = 1; /* Section 3 offset */
639 ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB;
640 ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr);
641 /* ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */
642 ksyms_hdr.kh_shdr[SYMTAB].sh_link = 2; /* Corresponding strtab */
643 ksyms_hdr.kh_shdr[SYMTAB].sh_info = 0; /* XXX */
644 ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long);
645 ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym);
646
647 /* Third section header; ".strtab" */
648 ksyms_hdr.kh_shdr[STRTAB].sh_name = 9; /* Section 3 offset */
649 ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB;
650 /* ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */
651 /* ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */
652 /* ksyms_hdr.kh_shdr[STRTAB].sh_link = kept zero */
653 ksyms_hdr.kh_shdr[STRTAB].sh_info = 0;
654 ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char);
655 ksyms_hdr.kh_shdr[STRTAB].sh_entsize = 0;
656
657 /* Fourth section, ".shstrtab" */
658 ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = 17; /* This section name offset */
659 ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB;
660 ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset =
661 offsetof(struct ksyms_hdr, kh_strtab);
662 ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ;
663 ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char);
664
665 /* Set section names */
666 strcpy(&ksyms_hdr.kh_strtab[1], ".symtab");
667 strcpy(&ksyms_hdr.kh_strtab[9], ".strtab");
668 strcpy(&ksyms_hdr.kh_strtab[17], ".shstrtab");
669 };
670
671 int
672 ksymsopen(dev_t dev, int oflags, int devtype, struct proc *p)
673 {
674
675 if (minor(dev))
676 return ENXIO;
677
678 ksyms_hdr.kh_shdr[SYMTAB].sh_size = symsz;
679 ksyms_hdr.kh_shdr[STRTAB].sh_offset = symsz +
680 ksyms_hdr.kh_shdr[SYMTAB].sh_offset;
681 ksyms_hdr.kh_shdr[STRTAB].sh_size = strsz;
682 ksyms_isopen = 1;
683
684 #ifdef KSYMS_DEBUG
685 if (ksyms_debug & FOLLOW_DEVKSYMS)
686 printf("ksymsopen: symsz 0x%x strsz 0x%x\n", symsz, strsz);
687 #endif
688
689 return 0;
690 }
691
692 int
693 ksymsclose(dev_t dev, int oflags, int devtype, struct proc *p)
694 {
695
696 #ifdef KSYMS_DEBUG
697 if (ksyms_debug & FOLLOW_DEVKSYMS)
698 printf("ksymsclose\n");
699 #endif
700
701 ksyms_isopen = 0;
702 wakeup(&ksyms_isopen);
703 return 0;
704 }
705
706 #define HDRSIZ sizeof(struct ksyms_hdr)
707
708 int
709 ksymsread(dev_t dev, struct uio *uio, int ioflag)
710 {
711 struct symtab *st;
712 size_t filepos, inpos, off;
713
714 #ifdef KSYMS_DEBUG
715 if (ksyms_debug & FOLLOW_DEVKSYMS)
716 printf("ksymsread: offset 0x%llx resid 0x%lx\n",
717 (long long)uio->uio_offset, uio->uio_resid);
718 #endif
719 if (ksymsinited == 0)
720 return ENXIO;
721
722 off = uio->uio_offset;
723 if (off >= (strsz + symsz + HDRSIZ))
724 return 0; /* End of symtab */
725 /*
726 * First: Copy out the ELF header.
727 */
728 if (off < HDRSIZ)
729 uiomove((char *)&ksyms_hdr + off, HDRSIZ - off, uio);
730
731 /*
732 * Copy out the symbol table.
733 */
734 filepos = HDRSIZ;
735 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
736 if (uio->uio_resid == 0)
737 return 0;
738 if (uio->uio_offset <= st->sd_symsize + filepos) {
739 inpos = uio->uio_offset - filepos;
740 uiomove((char *)st->sd_symstart + inpos,
741 st->sd_symsize - inpos, uio);
742 }
743 filepos += st->sd_symsize;
744 }
745
746 if (filepos != HDRSIZ + symsz)
747 panic("ksymsread: unsunc");
748
749 /*
750 * Copy out the string table
751 */
752 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
753 if (uio->uio_resid == 0)
754 return 0;
755 if (uio->uio_offset <= st->sd_strsize + filepos) {
756 inpos = uio->uio_offset - filepos;
757 uiomove((char *)st->sd_strstart + inpos,
758 st->sd_strsize - inpos, uio);
759 }
760 filepos += st->sd_strsize;
761 }
762 return 0;
763 }
764
765 int
766 ksymswrite(dev_t dev, struct uio *uio, int ioflag)
767 {
768 return EROFS;
769 }
770
771 int
772 ksymsioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
773 {
774 #ifdef notyet
775 struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data;
776 struct symtab *st;
777 Elf_Sym *sym;
778 unsigned long val;
779 int error = 0;
780
781 switch (cmd) {
782 case KIOCGVALUE:
783 /*
784 * Use the in-kernel symbol lookup code for fast
785 * retreival of a value.
786 */
787 if (error = copyinstr(kg->kg_name, symnm, maxsymnmsz, NULL))
788 break;
789 if (error = ksyms_getval(NULL, symnm, &val, KSYMS_EXTERN))
790 break;
791 error = copyout(&val, kg->kg_value, sizeof(long));
792 break;
793
794 case KIOCGSYMBOL:
795 /*
796 * Use the in-kernel symbol lookup code for fast
797 * retreival of a symbol.
798 */
799 if (error = copyinstr(kg->kg_name, symnm, maxsymnmsz, NULL))
800 break;
801 CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
802 if ((sym = findsym(symnm, st)) == NULL)
803 continue;
804
805 /* Skip if bad binding */
806 if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) {
807 sym = NULL;
808 continue;
809 }
810 break;
811 }
812 if (sym != NULL)
813 error = copyout(sym, kg->kg_sym, sizeof(Elf_Sym));
814 else
815 error = ENOENT;
816 break;
817
818 case KIOCGSIZE:
819 /*
820 * Get total size of symbol table.
821 */
822 *(int *)data = strsz + symsz + HDRSIZ;
823 break;
824
825 default:
826 error = ENOTTY;
827 break;
828 }
829 #endif
830 return ENOTTY;
831 }
832 #endif
833