1 /* $NetBSD: kern_ksyms.c,v 1.71 2014/03/16 05:20:30 dholland 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 * Add support for mmap, poll. 71 */ 72 73 #include <sys/cdefs.h> 74 __KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.71 2014/03/16 05:20:30 dholland Exp $"); 75 76 #if defined(_KERNEL) && defined(_KERNEL_OPT) 77 #include "opt_ddb.h" 78 #include "opt_dtrace.h" 79 #include "opt_ksyms.h" 80 #endif 81 82 #define _KSYMS_PRIVATE 83 84 #include <sys/param.h> 85 #include <sys/queue.h> 86 #include <sys/exec.h> 87 #include <sys/systm.h> 88 #include <sys/conf.h> 89 #include <sys/kmem.h> 90 #include <sys/proc.h> 91 #include <sys/atomic.h> 92 #include <sys/ksyms.h> 93 94 #ifdef DDB 95 #include <ddb/db_output.h> 96 #endif 97 98 #include "ksyms.h" 99 100 #define KSYMS_MAX_ID 65536 101 #ifdef KDTRACE_HOOKS 102 static uint32_t ksyms_nmap[KSYMS_MAX_ID]; /* sorted symbol table map */ 103 #else 104 static uint32_t *ksyms_nmap = NULL; 105 #endif 106 107 static int ksyms_maxlen; 108 static bool ksyms_isopen; 109 static bool ksyms_initted; 110 static bool ksyms_loaded; 111 static kmutex_t ksyms_lock __cacheline_aligned; 112 static struct ksyms_symtab kernel_symtab; 113 114 void ksymsattach(int); 115 static void ksyms_hdr_init(void *); 116 static void ksyms_sizes_calc(void); 117 118 #ifdef KSYMS_DEBUG 119 #define FOLLOW_CALLS 1 120 #define FOLLOW_MORE_CALLS 2 121 #define FOLLOW_DEVKSYMS 4 122 static int ksyms_debug; 123 #endif 124 125 #ifdef SYMTAB_SPACE 126 #define SYMTAB_FILLER "|This is the symbol table!" 127 128 char db_symtab[SYMTAB_SPACE] = SYMTAB_FILLER; 129 int db_symtabsize = SYMTAB_SPACE; 130 #endif 131 132 /* 133 * used by savecore(8) so non-static 134 */ 135 struct ksyms_hdr ksyms_hdr; 136 int ksyms_symsz; 137 int ksyms_strsz; 138 int ksyms_ctfsz; /* this is not currently used by savecore(8) */ 139 TAILQ_HEAD(, ksyms_symtab) ksyms_symtabs = 140 TAILQ_HEAD_INITIALIZER(ksyms_symtabs); 141 142 static int 143 ksyms_verify(void *symstart, void *strstart) 144 { 145 #if defined(DIAGNOSTIC) || defined(DEBUG) 146 if (symstart == NULL) 147 printf("ksyms: Symbol table not found\n"); 148 if (strstart == NULL) 149 printf("ksyms: String table not found\n"); 150 if (symstart == NULL || strstart == NULL) 151 printf("ksyms: Perhaps the kernel is stripped?\n"); 152 #endif 153 if (symstart == NULL || strstart == NULL) 154 return 0; 155 return 1; 156 } 157 158 /* 159 * Finds a certain symbol name in a certain symbol table. 160 */ 161 static Elf_Sym * 162 findsym(const char *name, struct ksyms_symtab *table, int type) 163 { 164 Elf_Sym *sym, *maxsym; 165 int low, mid, high, nglob; 166 char *str, *cmp; 167 168 sym = table->sd_symstart; 169 str = table->sd_strstart - table->sd_usroffset; 170 nglob = table->sd_nglob; 171 low = 0; 172 high = nglob; 173 174 /* 175 * Start with a binary search of all global symbols in this table. 176 * Global symbols must have unique names. 177 */ 178 while (low < high) { 179 mid = (low + high) >> 1; 180 cmp = sym[mid].st_name + str; 181 if (cmp[0] < name[0] || strcmp(cmp, name) < 0) { 182 low = mid + 1; 183 } else { 184 high = mid; 185 } 186 } 187 KASSERT(low == high); 188 if (__predict_true(low < nglob && 189 strcmp(sym[low].st_name + str, name) == 0)) { 190 KASSERT(ELF_ST_BIND(sym[low].st_info) == STB_GLOBAL); 191 return &sym[low]; 192 } 193 194 /* 195 * Perform a linear search of local symbols (rare). Many local 196 * symbols with the same name can exist so are not included in 197 * the binary search. 198 */ 199 if (type != KSYMS_EXTERN) { 200 maxsym = sym + table->sd_symsize / sizeof(Elf_Sym); 201 for (sym += nglob; sym < maxsym; sym++) { 202 if (strcmp(name, sym->st_name + str) == 0) { 203 return sym; 204 } 205 } 206 } 207 return NULL; 208 } 209 210 /* 211 * The "attach" is in reality done in ksyms_init(). 212 */ 213 void 214 ksymsattach(int arg) 215 { 216 217 } 218 219 void 220 ksyms_init(void) 221 { 222 223 #ifdef SYMTAB_SPACE 224 if (!ksyms_loaded && 225 strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) { 226 ksyms_addsyms_elf(db_symtabsize, db_symtab, 227 db_symtab + db_symtabsize); 228 } 229 #endif 230 231 if (!ksyms_initted) { 232 mutex_init(&ksyms_lock, MUTEX_DEFAULT, IPL_NONE); 233 ksyms_initted = true; 234 } 235 } 236 237 /* 238 * Add a symbol table. 239 * This is intended for use when the symbol table and its corresponding 240 * string table are easily available. If they are embedded in an ELF 241 * image, use addsymtab_elf() instead. 242 * 243 * name - Symbol's table name. 244 * symstart, symsize - Address and size of the symbol table. 245 * strstart, strsize - Address and size of the string table. 246 * tab - Symbol table to be updated with this information. 247 * newstart - Address to which the symbol table has to be copied during 248 * shrinking. If NULL, it is not moved. 249 */ 250 static const char *addsymtab_strstart; 251 252 static int 253 addsymtab_compar(const void *a, const void *b) 254 { 255 const Elf_Sym *sa, *sb; 256 257 sa = a; 258 sb = b; 259 260 /* 261 * Split the symbol table into two, with globals at the start 262 * and locals at the end. 263 */ 264 if (ELF_ST_BIND(sa->st_info) != ELF_ST_BIND(sb->st_info)) { 265 if (ELF_ST_BIND(sa->st_info) == STB_GLOBAL) { 266 return -1; 267 } 268 if (ELF_ST_BIND(sb->st_info) == STB_GLOBAL) { 269 return 1; 270 } 271 } 272 273 /* Within each band, sort by name. */ 274 return strcmp(sa->st_name + addsymtab_strstart, 275 sb->st_name + addsymtab_strstart); 276 } 277 278 static void 279 addsymtab(const char *name, void *symstart, size_t symsize, 280 void *strstart, size_t strsize, struct ksyms_symtab *tab, 281 void *newstart, void *ctfstart, size_t ctfsize, uint32_t *nmap) 282 { 283 Elf_Sym *sym, *nsym, ts; 284 int i, j, n, nglob; 285 char *str; 286 int nsyms = symsize / sizeof(Elf_Sym); 287 288 /* Sanity check for pre-allocated map table used during startup. */ 289 if ((nmap == ksyms_nmap) && (nsyms >= KSYMS_MAX_ID)) { 290 printf("kern_ksyms: ERROR %d > %d, increase KSYMS_MAX_ID\n", 291 nsyms, KSYMS_MAX_ID); 292 293 /* truncate for now */ 294 nsyms = KSYMS_MAX_ID - 1; 295 } 296 297 tab->sd_symstart = symstart; 298 tab->sd_symsize = symsize; 299 tab->sd_strstart = strstart; 300 tab->sd_strsize = strsize; 301 tab->sd_name = name; 302 tab->sd_minsym = UINTPTR_MAX; 303 tab->sd_maxsym = 0; 304 tab->sd_usroffset = 0; 305 tab->sd_gone = false; 306 tab->sd_ctfstart = ctfstart; 307 tab->sd_ctfsize = ctfsize; 308 tab->sd_nmap = nmap; 309 tab->sd_nmapsize = nsyms; 310 #ifdef KSYMS_DEBUG 311 printf("newstart %p sym %p ksyms_symsz %zu str %p strsz %zu send %p\n", 312 newstart, symstart, symsize, strstart, strsize, 313 tab->sd_strstart + tab->sd_strsize); 314 #endif 315 316 if (nmap) { 317 memset(nmap, 0, nsyms * sizeof(uint32_t)); 318 } 319 320 /* Pack symbol table by removing all file name references. */ 321 sym = tab->sd_symstart; 322 nsym = (Elf_Sym *)newstart; 323 str = tab->sd_strstart; 324 nglob = 0; 325 for (i = n = 0; i < nsyms; i++) { 326 327 /* This breaks CTF mapping, so don't do it when 328 * DTrace is enabled 329 */ 330 #ifndef KDTRACE_HOOKS 331 /* 332 * Remove useless symbols. 333 * Should actually remove all typeless symbols. 334 */ 335 if (sym[i].st_name == 0) 336 continue; /* Skip nameless entries */ 337 if (sym[i].st_shndx == SHN_UNDEF) 338 continue; /* Skip external references */ 339 if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE) 340 continue; /* Skip filenames */ 341 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE && 342 sym[i].st_value == 0 && 343 strcmp(str + sym[i].st_name, "*ABS*") == 0) 344 continue; /* XXX */ 345 if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE && 346 strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0) 347 continue; /* XXX */ 348 #endif 349 350 /* Save symbol. Set it as an absolute offset */ 351 nsym[n] = sym[i]; 352 353 #ifdef KDTRACE_HOOKS 354 if (nmap != NULL) { 355 /* 356 * Save the size, replace it with the symbol id so 357 * the mapping can be done after the cleanup and sort. 358 */ 359 nmap[i] = nsym[n].st_size; 360 nsym[n].st_size = i + 1; /* zero is reserved */ 361 } 362 #endif 363 364 nsym[n].st_shndx = SHBSS; 365 j = strlen(nsym[n].st_name + str) + 1; 366 if (j > ksyms_maxlen) 367 ksyms_maxlen = j; 368 nglob += (ELF_ST_BIND(nsym[n].st_info) == STB_GLOBAL); 369 370 /* Compute min and max symbols. */ 371 if (strcmp(str + sym[i].st_name, "*ABS*") != 0 372 && ELF_ST_TYPE(nsym[n].st_info) != STT_NOTYPE) { 373 if (nsym[n].st_value < tab->sd_minsym) { 374 tab->sd_minsym = nsym[n].st_value; 375 } 376 if (nsym[n].st_value > tab->sd_maxsym) { 377 tab->sd_maxsym = nsym[n].st_value; 378 } 379 } 380 n++; 381 } 382 383 /* Fill the rest of the record, and sort the symbols. */ 384 tab->sd_symstart = nsym; 385 tab->sd_symsize = n * sizeof(Elf_Sym); 386 tab->sd_nglob = nglob; 387 addsymtab_strstart = str; 388 if (kheapsort(nsym, n, sizeof(Elf_Sym), addsymtab_compar, &ts) != 0) 389 panic("addsymtab"); 390 391 #ifdef KDTRACE_HOOKS 392 /* 393 * Build the mapping from original symbol id to new symbol table. 394 * Deleted symbols will have a zero map, indices will be one based 395 * instead of zero based. 396 * Resulting map is sd_nmap[original_index] = new_index + 1 397 */ 398 if (nmap != NULL) { 399 int new; 400 for (new = 0; new < n; new++) { 401 uint32_t orig = nsym[new].st_size - 1; 402 uint32_t size = nmap[orig]; 403 404 nmap[orig] = new + 1; 405 406 /* restore the size */ 407 nsym[new].st_size = size; 408 } 409 } 410 #endif 411 412 /* ksymsread() is unlocked, so membar. */ 413 membar_producer(); 414 TAILQ_INSERT_TAIL(&ksyms_symtabs, tab, sd_queue); 415 ksyms_sizes_calc(); 416 ksyms_loaded = true; 417 } 418 419 /* 420 * Setup the kernel symbol table stuff. 421 */ 422 void 423 ksyms_addsyms_elf(int symsize, void *start, void *end) 424 { 425 int i, j; 426 Elf_Shdr *shdr; 427 char *symstart = NULL, *strstart = NULL; 428 size_t strsize = 0; 429 Elf_Ehdr *ehdr; 430 char *ctfstart = NULL; 431 size_t ctfsize = 0; 432 433 if (symsize <= 0) { 434 printf("[ Kernel symbol table missing! ]\n"); 435 return; 436 } 437 438 /* Sanity check */ 439 if (ALIGNED_POINTER(start, long) == 0) { 440 printf("[ Kernel symbol table has bad start address %p ]\n", 441 start); 442 return; 443 } 444 445 ehdr = (Elf_Ehdr *)start; 446 447 /* check if this is a valid ELF header */ 448 /* No reason to verify arch type, the kernel is actually running! */ 449 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || 450 ehdr->e_ident[EI_CLASS] != ELFCLASS || 451 ehdr->e_version > 1) { 452 printf("[ Kernel symbol table invalid! ]\n"); 453 return; /* nothing to do */ 454 } 455 456 /* Loaded header will be scratched in addsymtab */ 457 ksyms_hdr_init(start); 458 459 /* Find the symbol table and the corresponding string table. */ 460 shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff); 461 for (i = 1; i < ehdr->e_shnum; i++) { 462 if (shdr[i].sh_type != SHT_SYMTAB) 463 continue; 464 if (shdr[i].sh_offset == 0) 465 continue; 466 symstart = (uint8_t *)start + shdr[i].sh_offset; 467 symsize = shdr[i].sh_size; 468 j = shdr[i].sh_link; 469 if (shdr[j].sh_offset == 0) 470 continue; /* Can this happen? */ 471 strstart = (uint8_t *)start + shdr[j].sh_offset; 472 strsize = shdr[j].sh_size; 473 break; 474 } 475 476 #ifdef KDTRACE_HOOKS 477 /* Find the CTF section */ 478 shdr = (Elf_Shdr *)((uint8_t *)start + ehdr->e_shoff); 479 if (ehdr->e_shstrndx != 0) { 480 char *shstr = (uint8_t *)start + 481 shdr[ehdr->e_shstrndx].sh_offset; 482 for (i = 1; i < ehdr->e_shnum; i++) { 483 #ifdef DEBUG 484 printf("ksyms: checking %s\n", &shstr[shdr[i].sh_name]); 485 #endif 486 if (shdr[i].sh_type != SHT_PROGBITS) 487 continue; 488 if (strncmp(".SUNW_ctf", &shstr[shdr[i].sh_name], 10) 489 != 0) 490 continue; 491 ctfstart = (uint8_t *)start + shdr[i].sh_offset; 492 ctfsize = shdr[i].sh_size; 493 ksyms_ctfsz = ctfsize; 494 #ifdef DEBUG 495 aprint_normal("Found CTF at %p, size 0x%zx\n", 496 ctfstart, ctfsize); 497 #endif 498 break; 499 } 500 #ifdef DEBUG 501 } else { 502 printf("ksyms: e_shstrndx == 0\n"); 503 #endif 504 } 505 #endif 506 507 if (!ksyms_verify(symstart, strstart)) 508 return; 509 510 addsymtab("netbsd", symstart, symsize, strstart, strsize, 511 &kernel_symtab, symstart, ctfstart, ctfsize, ksyms_nmap); 512 513 #ifdef DEBUG 514 aprint_normal("Loaded initial symtab at %p, strtab at %p, # entries %ld\n", 515 kernel_symtab.sd_symstart, kernel_symtab.sd_strstart, 516 (long)kernel_symtab.sd_symsize/sizeof(Elf_Sym)); 517 #endif 518 } 519 520 /* 521 * Setup the kernel symbol table stuff. 522 * Use this when the address of the symbol and string tables are known; 523 * otherwise use ksyms_init with an ELF image. 524 * We need to pass a minimal ELF header which will later be completed by 525 * ksyms_hdr_init and handed off to userland through /dev/ksyms. We use 526 * a void *rather than a pointer to avoid exposing the Elf_Ehdr type. 527 */ 528 void 529 ksyms_addsyms_explicit(void *ehdr, void *symstart, size_t symsize, 530 void *strstart, size_t strsize) 531 { 532 533 if (!ksyms_verify(symstart, strstart)) 534 return; 535 536 ksyms_hdr_init(ehdr); 537 addsymtab("netbsd", symstart, symsize, strstart, strsize, 538 &kernel_symtab, symstart, NULL, 0, ksyms_nmap); 539 } 540 541 /* 542 * Get the value associated with a symbol. 543 * "mod" is the module name, or null if any module. 544 * "sym" is the symbol name. 545 * "val" is a pointer to the corresponding value, if call succeeded. 546 * Returns 0 if success or ENOENT if no such entry. 547 * 548 * Call with ksyms_lock, unless known that the symbol table can't change. 549 */ 550 int 551 ksyms_getval_unlocked(const char *mod, const char *sym, unsigned long *val, 552 int type) 553 { 554 struct ksyms_symtab *st; 555 Elf_Sym *es; 556 557 #ifdef KSYMS_DEBUG 558 if (ksyms_debug & FOLLOW_CALLS) 559 printf("ksyms_getval_unlocked: mod %s sym %s valp %p\n", 560 mod, sym, val); 561 #endif 562 563 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 564 if (__predict_false(st->sd_gone)) 565 continue; 566 if (mod != NULL && strcmp(st->sd_name, mod)) 567 continue; 568 if ((es = findsym(sym, st, type)) != NULL) { 569 *val = es->st_value; 570 return 0; 571 } 572 } 573 return ENOENT; 574 } 575 576 int 577 ksyms_getval(const char *mod, const char *sym, unsigned long *val, int type) 578 { 579 int rc; 580 581 if (!ksyms_loaded) 582 return ENOENT; 583 584 mutex_enter(&ksyms_lock); 585 rc = ksyms_getval_unlocked(mod, sym, val, type); 586 mutex_exit(&ksyms_lock); 587 return rc; 588 } 589 590 struct ksyms_symtab * 591 ksyms_get_mod(const char *mod) 592 { 593 struct ksyms_symtab *st; 594 595 mutex_enter(&ksyms_lock); 596 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 597 if (__predict_false(st->sd_gone)) 598 continue; 599 if (mod != NULL && strcmp(st->sd_name, mod)) 600 continue; 601 break; 602 } 603 mutex_exit(&ksyms_lock); 604 605 return st; 606 } 607 608 609 /* 610 * ksyms_mod_foreach() 611 * 612 * Iterate over the symbol table of the specified module, calling the callback 613 * handler for each symbol. Stop iterating if the handler return is non-zero. 614 * 615 */ 616 617 int 618 ksyms_mod_foreach(const char *mod, ksyms_callback_t callback, void *opaque) 619 { 620 struct ksyms_symtab *st; 621 Elf_Sym *sym, *maxsym; 622 char *str; 623 int symindx; 624 625 if (!ksyms_loaded) 626 return ENOENT; 627 628 mutex_enter(&ksyms_lock); 629 630 /* find the module */ 631 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 632 if (__predict_false(st->sd_gone)) 633 continue; 634 if (mod != NULL && strcmp(st->sd_name, mod)) 635 continue; 636 637 sym = st->sd_symstart; 638 str = st->sd_strstart - st->sd_usroffset; 639 640 /* now iterate through the symbols */ 641 maxsym = sym + st->sd_symsize / sizeof(Elf_Sym); 642 for (symindx = 0; sym < maxsym; sym++, symindx++) { 643 if (callback(str + sym->st_name, symindx, 644 (void *)sym->st_value, 645 sym->st_size, 646 sym->st_info, 647 opaque) != 0) { 648 break; 649 } 650 } 651 } 652 mutex_exit(&ksyms_lock); 653 654 return 0; 655 } 656 657 /* 658 * Get "mod" and "symbol" associated with an address. 659 * Returns 0 if success or ENOENT if no such entry. 660 * 661 * Call with ksyms_lock, unless known that the symbol table can't change. 662 */ 663 int 664 ksyms_getname(const char **mod, const char **sym, vaddr_t v, int f) 665 { 666 struct ksyms_symtab *st; 667 Elf_Sym *les, *es = NULL; 668 vaddr_t laddr = 0; 669 const char *lmod = NULL; 670 char *stable = NULL; 671 int type, i, sz; 672 673 if (!ksyms_loaded) 674 return ENOENT; 675 676 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 677 if (st->sd_gone) 678 continue; 679 if (v < st->sd_minsym || v > st->sd_maxsym) 680 continue; 681 sz = st->sd_symsize/sizeof(Elf_Sym); 682 for (i = 0; i < sz; i++) { 683 les = st->sd_symstart + i; 684 type = ELF_ST_TYPE(les->st_info); 685 686 if ((f & KSYMS_PROC) && (type != STT_FUNC)) 687 continue; 688 689 if (type == STT_NOTYPE) 690 continue; 691 692 if (((f & KSYMS_ANY) == 0) && 693 (type != STT_FUNC) && (type != STT_OBJECT)) 694 continue; 695 696 if ((les->st_value <= v) && (les->st_value > laddr)) { 697 laddr = les->st_value; 698 es = les; 699 lmod = st->sd_name; 700 stable = st->sd_strstart - st->sd_usroffset; 701 } 702 } 703 } 704 if (es == NULL) 705 return ENOENT; 706 if ((f & KSYMS_EXACT) && (v != es->st_value)) 707 return ENOENT; 708 if (mod) 709 *mod = lmod; 710 if (sym) 711 *sym = stable + es->st_name; 712 return 0; 713 } 714 715 /* 716 * Add a symbol table from a loadable module. 717 */ 718 void 719 ksyms_modload(const char *name, void *symstart, vsize_t symsize, 720 char *strstart, vsize_t strsize) 721 { 722 struct ksyms_symtab *st; 723 724 st = kmem_zalloc(sizeof(*st), KM_SLEEP); 725 mutex_enter(&ksyms_lock); 726 addsymtab(name, symstart, symsize, strstart, strsize, st, symstart, 727 NULL, 0, NULL); 728 mutex_exit(&ksyms_lock); 729 } 730 731 /* 732 * Remove a symbol table from a loadable module. 733 */ 734 void 735 ksyms_modunload(const char *name) 736 { 737 struct ksyms_symtab *st; 738 739 mutex_enter(&ksyms_lock); 740 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 741 if (st->sd_gone) 742 continue; 743 if (strcmp(name, st->sd_name) != 0) 744 continue; 745 st->sd_gone = true; 746 if (!ksyms_isopen) { 747 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue); 748 ksyms_sizes_calc(); 749 kmem_free(st, sizeof(*st)); 750 } 751 break; 752 } 753 mutex_exit(&ksyms_lock); 754 KASSERT(st != NULL); 755 } 756 757 #ifdef DDB 758 /* 759 * Keep sifting stuff here, to avoid export of ksyms internals. 760 * 761 * Systems is expected to be quiescent, so no locking done. 762 */ 763 int 764 ksyms_sift(char *mod, char *sym, int mode) 765 { 766 struct ksyms_symtab *st; 767 char *sb; 768 int i, sz; 769 770 if (!ksyms_loaded) 771 return ENOENT; 772 773 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 774 if (st->sd_gone) 775 continue; 776 if (mod && strcmp(mod, st->sd_name)) 777 continue; 778 sb = st->sd_strstart - st->sd_usroffset; 779 780 sz = st->sd_symsize/sizeof(Elf_Sym); 781 for (i = 0; i < sz; i++) { 782 Elf_Sym *les = st->sd_symstart + i; 783 char c; 784 785 if (strstr(sb + les->st_name, sym) == NULL) 786 continue; 787 788 if (mode == 'F') { 789 switch (ELF_ST_TYPE(les->st_info)) { 790 case STT_OBJECT: 791 c = '+'; 792 break; 793 case STT_FUNC: 794 c = '*'; 795 break; 796 case STT_SECTION: 797 c = '&'; 798 break; 799 case STT_FILE: 800 c = '/'; 801 break; 802 default: 803 c = ' '; 804 break; 805 } 806 db_printf("%s%c ", sb + les->st_name, c); 807 } else 808 db_printf("%s ", sb + les->st_name); 809 } 810 } 811 return ENOENT; 812 } 813 #endif /* DDB */ 814 815 /* 816 * In case we exposing the symbol table to the userland using the pseudo- 817 * device /dev/ksyms, it is easier to provide all the tables as one. 818 * However, it means we have to change all the st_name fields for the 819 * symbols so they match the ELF image that the userland will read 820 * through the device. 821 * 822 * The actual (correct) value of st_name is preserved through a global 823 * offset stored in the symbol table structure. 824 * 825 * Call with ksyms_lock held. 826 */ 827 static void 828 ksyms_sizes_calc(void) 829 { 830 struct ksyms_symtab *st; 831 int i, delta; 832 833 ksyms_symsz = ksyms_strsz = 0; 834 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 835 delta = ksyms_strsz - st->sd_usroffset; 836 if (delta != 0) { 837 for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++) 838 st->sd_symstart[i].st_name += delta; 839 st->sd_usroffset = ksyms_strsz; 840 } 841 ksyms_symsz += st->sd_symsize; 842 ksyms_strsz += st->sd_strsize; 843 } 844 } 845 846 static void 847 ksyms_hdr_init(void *hdraddr) 848 { 849 850 /* Copy the loaded elf exec header */ 851 memcpy(&ksyms_hdr.kh_ehdr, hdraddr, sizeof(Elf_Ehdr)); 852 853 /* Set correct program/section header sizes, offsets and numbers */ 854 ksyms_hdr.kh_ehdr.e_phoff = offsetof(struct ksyms_hdr, kh_phdr[0]); 855 ksyms_hdr.kh_ehdr.e_phentsize = sizeof(Elf_Phdr); 856 ksyms_hdr.kh_ehdr.e_phnum = NPRGHDR; 857 ksyms_hdr.kh_ehdr.e_shoff = offsetof(struct ksyms_hdr, kh_shdr[0]); 858 ksyms_hdr.kh_ehdr.e_shentsize = sizeof(Elf_Shdr); 859 ksyms_hdr.kh_ehdr.e_shnum = NSECHDR; 860 ksyms_hdr.kh_ehdr.e_shstrndx = SHSTRTAB; 861 862 /* Text/data - fake */ 863 ksyms_hdr.kh_phdr[0].p_type = PT_LOAD; 864 ksyms_hdr.kh_phdr[0].p_memsz = (unsigned long)-1L; 865 ksyms_hdr.kh_phdr[0].p_flags = PF_R | PF_X | PF_W; 866 867 /* First section is null */ 868 869 /* Second section header; ".symtab" */ 870 ksyms_hdr.kh_shdr[SYMTAB].sh_name = 1; /* Section 3 offset */ 871 ksyms_hdr.kh_shdr[SYMTAB].sh_type = SHT_SYMTAB; 872 ksyms_hdr.kh_shdr[SYMTAB].sh_offset = sizeof(struct ksyms_hdr); 873 /* ksyms_hdr.kh_shdr[SYMTAB].sh_size = filled in at open */ 874 ksyms_hdr.kh_shdr[SYMTAB].sh_link = 2; /* Corresponding strtab */ 875 ksyms_hdr.kh_shdr[SYMTAB].sh_addralign = sizeof(long); 876 ksyms_hdr.kh_shdr[SYMTAB].sh_entsize = sizeof(Elf_Sym); 877 878 /* Third section header; ".strtab" */ 879 ksyms_hdr.kh_shdr[STRTAB].sh_name = 9; /* Section 3 offset */ 880 ksyms_hdr.kh_shdr[STRTAB].sh_type = SHT_STRTAB; 881 /* ksyms_hdr.kh_shdr[STRTAB].sh_offset = filled in at open */ 882 /* ksyms_hdr.kh_shdr[STRTAB].sh_size = filled in at open */ 883 ksyms_hdr.kh_shdr[STRTAB].sh_addralign = sizeof(char); 884 885 /* Fourth section, ".shstrtab" */ 886 ksyms_hdr.kh_shdr[SHSTRTAB].sh_name = 17; /* This section name offset */ 887 ksyms_hdr.kh_shdr[SHSTRTAB].sh_type = SHT_STRTAB; 888 ksyms_hdr.kh_shdr[SHSTRTAB].sh_offset = 889 offsetof(struct ksyms_hdr, kh_strtab); 890 ksyms_hdr.kh_shdr[SHSTRTAB].sh_size = SHSTRSIZ; 891 ksyms_hdr.kh_shdr[SHSTRTAB].sh_addralign = sizeof(char); 892 893 /* Fifth section, ".bss". All symbols reside here. */ 894 ksyms_hdr.kh_shdr[SHBSS].sh_name = 27; /* This section name offset */ 895 ksyms_hdr.kh_shdr[SHBSS].sh_type = SHT_NOBITS; 896 ksyms_hdr.kh_shdr[SHBSS].sh_offset = 0; 897 ksyms_hdr.kh_shdr[SHBSS].sh_size = (unsigned long)-1L; 898 ksyms_hdr.kh_shdr[SHBSS].sh_addralign = PAGE_SIZE; 899 ksyms_hdr.kh_shdr[SHBSS].sh_flags = SHF_ALLOC | SHF_EXECINSTR; 900 901 /* Sixth section header; ".SUNW_ctf" */ 902 ksyms_hdr.kh_shdr[SHCTF].sh_name = 32; /* Section 6 offset */ 903 ksyms_hdr.kh_shdr[SHCTF].sh_type = SHT_PROGBITS; 904 /* ksyms_hdr.kh_shdr[SHCTF].sh_offset = filled in at open */ 905 /* ksyms_hdr.kh_shdr[SHCTF].sh_size = filled in at open */ 906 ksyms_hdr.kh_shdr[SHCTF].sh_link = SYMTAB; /* Corresponding symtab */ 907 ksyms_hdr.kh_shdr[SHCTF].sh_addralign = sizeof(char); 908 909 /* Set section names */ 910 strlcpy(&ksyms_hdr.kh_strtab[1], ".symtab", 911 sizeof(ksyms_hdr.kh_strtab) - 1); 912 strlcpy(&ksyms_hdr.kh_strtab[9], ".strtab", 913 sizeof(ksyms_hdr.kh_strtab) - 9); 914 strlcpy(&ksyms_hdr.kh_strtab[17], ".shstrtab", 915 sizeof(ksyms_hdr.kh_strtab) - 17); 916 strlcpy(&ksyms_hdr.kh_strtab[27], ".bss", 917 sizeof(ksyms_hdr.kh_strtab) - 27); 918 strlcpy(&ksyms_hdr.kh_strtab[32], ".SUNW_ctf", 919 sizeof(ksyms_hdr.kh_strtab) - 32); 920 } 921 922 static int 923 ksymsopen(dev_t dev, int oflags, int devtype, struct lwp *l) 924 { 925 926 if (minor(dev) != 0 || !ksyms_loaded) 927 return ENXIO; 928 929 /* 930 * Create a "snapshot" of the kernel symbol table. Setting 931 * ksyms_isopen will prevent symbol tables from being freed. 932 */ 933 mutex_enter(&ksyms_lock); 934 ksyms_hdr.kh_shdr[SYMTAB].sh_size = ksyms_symsz; 935 ksyms_hdr.kh_shdr[SYMTAB].sh_info = ksyms_symsz / sizeof(Elf_Sym); 936 ksyms_hdr.kh_shdr[STRTAB].sh_offset = ksyms_symsz + 937 ksyms_hdr.kh_shdr[SYMTAB].sh_offset; 938 ksyms_hdr.kh_shdr[STRTAB].sh_size = ksyms_strsz; 939 ksyms_hdr.kh_shdr[SHCTF].sh_offset = ksyms_strsz + 940 ksyms_hdr.kh_shdr[STRTAB].sh_offset; 941 ksyms_hdr.kh_shdr[SHCTF].sh_size = ksyms_ctfsz; 942 ksyms_isopen = true; 943 mutex_exit(&ksyms_lock); 944 945 return 0; 946 } 947 948 static int 949 ksymsclose(dev_t dev, int oflags, int devtype, struct lwp *l) 950 { 951 struct ksyms_symtab *st, *next; 952 bool resize; 953 954 /* Discard refernces to symbol tables. */ 955 mutex_enter(&ksyms_lock); 956 ksyms_isopen = false; 957 resize = false; 958 for (st = TAILQ_FIRST(&ksyms_symtabs); st != NULL; st = next) { 959 next = TAILQ_NEXT(st, sd_queue); 960 if (st->sd_gone) { 961 TAILQ_REMOVE(&ksyms_symtabs, st, sd_queue); 962 kmem_free(st, sizeof(*st)); 963 resize = true; 964 } 965 } 966 if (resize) 967 ksyms_sizes_calc(); 968 mutex_exit(&ksyms_lock); 969 970 return 0; 971 } 972 973 static int 974 ksymsread(dev_t dev, struct uio *uio, int ioflag) 975 { 976 struct ksyms_symtab *st; 977 size_t filepos, inpos, off; 978 int error; 979 980 /* 981 * First: Copy out the ELF header. XXX Lose if ksymsopen() 982 * occurs during read of the header. 983 */ 984 off = uio->uio_offset; 985 if (off < sizeof(struct ksyms_hdr)) { 986 error = uiomove((char *)&ksyms_hdr + off, 987 sizeof(struct ksyms_hdr) - off, uio); 988 if (error != 0) 989 return error; 990 } 991 992 /* 993 * Copy out the symbol table. 994 */ 995 filepos = sizeof(struct ksyms_hdr); 996 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 997 if (uio->uio_resid == 0) 998 return 0; 999 if (uio->uio_offset <= st->sd_symsize + filepos) { 1000 inpos = uio->uio_offset - filepos; 1001 error = uiomove((char *)st->sd_symstart + inpos, 1002 st->sd_symsize - inpos, uio); 1003 if (error != 0) 1004 return error; 1005 } 1006 filepos += st->sd_symsize; 1007 } 1008 1009 /* 1010 * Copy out the string table 1011 */ 1012 KASSERT(filepos == sizeof(struct ksyms_hdr) + 1013 ksyms_hdr.kh_shdr[SYMTAB].sh_size); 1014 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 1015 if (uio->uio_resid == 0) 1016 return 0; 1017 if (uio->uio_offset <= st->sd_strsize + filepos) { 1018 inpos = uio->uio_offset - filepos; 1019 error = uiomove((char *)st->sd_strstart + inpos, 1020 st->sd_strsize - inpos, uio); 1021 if (error != 0) 1022 return error; 1023 } 1024 filepos += st->sd_strsize; 1025 } 1026 1027 /* 1028 * Copy out the CTF table. 1029 */ 1030 st = TAILQ_FIRST(&ksyms_symtabs); 1031 if (st->sd_ctfstart != NULL) { 1032 if (uio->uio_resid == 0) 1033 return 0; 1034 if (uio->uio_offset <= st->sd_ctfsize + filepos) { 1035 inpos = uio->uio_offset - filepos; 1036 error = uiomove((char *)st->sd_ctfstart + inpos, 1037 st->sd_ctfsize - inpos, uio); 1038 if (error != 0) 1039 return error; 1040 } 1041 filepos += st->sd_ctfsize; 1042 } 1043 1044 return 0; 1045 } 1046 1047 static int 1048 ksymswrite(dev_t dev, struct uio *uio, int ioflag) 1049 { 1050 1051 return EROFS; 1052 } 1053 1054 static int 1055 ksymsioctl(dev_t dev, u_long cmd, void *data, int fflag, struct lwp *l) 1056 { 1057 struct ksyms_gsymbol *kg = (struct ksyms_gsymbol *)data; 1058 struct ksyms_symtab *st; 1059 Elf_Sym *sym = NULL, copy; 1060 unsigned long val; 1061 int error = 0; 1062 char *str = NULL; 1063 int len; 1064 1065 /* Read ksyms_maxlen only once while not holding the lock. */ 1066 len = ksyms_maxlen; 1067 1068 if (cmd == KIOCGVALUE || cmd == KIOCGSYMBOL) { 1069 str = kmem_alloc(len, KM_SLEEP); 1070 if ((error = copyinstr(kg->kg_name, str, len, NULL)) != 0) { 1071 kmem_free(str, len); 1072 return error; 1073 } 1074 } 1075 1076 switch (cmd) { 1077 case KIOCGVALUE: 1078 /* 1079 * Use the in-kernel symbol lookup code for fast 1080 * retreival of a value. 1081 */ 1082 error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN); 1083 if (error == 0) 1084 error = copyout(&val, kg->kg_value, sizeof(long)); 1085 kmem_free(str, len); 1086 break; 1087 1088 case KIOCGSYMBOL: 1089 /* 1090 * Use the in-kernel symbol lookup code for fast 1091 * retreival of a symbol. 1092 */ 1093 mutex_enter(&ksyms_lock); 1094 TAILQ_FOREACH(st, &ksyms_symtabs, sd_queue) { 1095 if (st->sd_gone) 1096 continue; 1097 if ((sym = findsym(str, st, KSYMS_ANY)) == NULL) 1098 continue; 1099 #ifdef notdef 1100 /* Skip if bad binding */ 1101 if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL) { 1102 sym = NULL; 1103 continue; 1104 } 1105 #endif 1106 break; 1107 } 1108 if (sym != NULL) { 1109 memcpy(©, sym, sizeof(copy)); 1110 mutex_exit(&ksyms_lock); 1111 error = copyout(©, kg->kg_sym, sizeof(Elf_Sym)); 1112 } else { 1113 mutex_exit(&ksyms_lock); 1114 error = ENOENT; 1115 } 1116 kmem_free(str, len); 1117 break; 1118 1119 case KIOCGSIZE: 1120 /* 1121 * Get total size of symbol table. 1122 */ 1123 mutex_enter(&ksyms_lock); 1124 *(int *)data = ksyms_strsz + ksyms_symsz + 1125 sizeof(struct ksyms_hdr); 1126 mutex_exit(&ksyms_lock); 1127 break; 1128 1129 default: 1130 error = ENOTTY; 1131 break; 1132 } 1133 1134 return error; 1135 } 1136 1137 const struct cdevsw ksyms_cdevsw = { 1138 .d_open = ksymsopen, 1139 .d_close = ksymsclose, 1140 .d_read = ksymsread, 1141 .d_write = ksymswrite, 1142 .d_ioctl = ksymsioctl, 1143 .d_stop = nullstop, 1144 .d_tty = notty, 1145 .d_poll = nopoll, 1146 .d_mmap = nommap, 1147 .d_kqfilter = nullkqfilter, 1148 .d_flag = D_OTHER | D_MPSAFE 1149 }; 1150