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