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