1 /* $NetBSD: db_sym.c,v 1.30 2002/01/05 20:09:52 jhawk Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1991,1990 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie the 26 * rights to redistribute these changes. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: db_sym.c,v 1.30 2002/01/05 20:09:52 jhawk Exp $"); 31 32 #include "opt_ddb.h" 33 34 #include <sys/param.h> 35 #include <sys/proc.h> 36 #include <sys/systm.h> 37 38 #include <machine/db_machdep.h> 39 40 #include <ddb/db_lex.h> 41 #include <ddb/db_sym.h> 42 #include <ddb/db_output.h> 43 #include <ddb/db_extern.h> 44 #include <ddb/db_command.h> 45 46 /* 47 * Multiple symbol tables 48 */ 49 #ifndef MAXLKMS 50 #define MAXLKMS 20 51 #endif 52 53 #ifndef MAXNOSYMTABS 54 #define MAXNOSYMTABS MAXLKMS+1 /* Room for kernel + LKM's */ 55 #endif 56 57 db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; 58 59 db_symtab_t *db_last_symtab; 60 61 #ifdef SYMTAB_SPACE 62 #define SYMTAB_FILLER "|This is the symbol table!" 63 64 char db_symtab[SYMTAB_SPACE] = SYMTAB_FILLER; 65 int db_symtabsize = SYMTAB_SPACE; 66 #endif 67 68 static char *db_qualify __P((db_sym_t, const char *)); 69 static db_forall_func_t db_sift; 70 71 /* 72 * Put the most picky symbol table formats at the top! 73 */ 74 const db_symformat_t * const db_symformats[] = { 75 #ifdef DB_ELF_SYMBOLS 76 &db_symformat_elf, 77 #endif 78 #ifdef DB_AOUT_SYMBOLS 79 &db_symformat_aout, 80 #endif 81 NULL, 82 }; 83 84 const db_symformat_t *db_symformat; 85 86 boolean_t X_db_sym_init __P((int, void *, void *, const char *)); 87 db_sym_t X_db_lookup __P((db_symtab_t *, char *)); 88 db_sym_t X_db_search_symbol __P((db_symtab_t *, db_addr_t, 89 db_strategy_t, db_expr_t *)); 90 void X_db_symbol_values __P((db_symtab_t *, db_sym_t, char **, 91 db_expr_t *)); 92 boolean_t X_db_line_at_pc __P((db_symtab_t *, db_sym_t, char **, 93 int *, db_expr_t)); 94 int X_db_sym_numargs __P((db_symtab_t *, db_sym_t, int *, 95 char **)); 96 void X_db_forall __P((db_symtab_t *, 97 db_forall_func_t db_forall_func, void *)); 98 99 /* 100 * Initialize the kernel debugger by initializing the master symbol 101 * table. Note that if initializing the master symbol table fails, 102 * no other symbol tables can be loaded. 103 */ 104 void 105 ddb_init(symsize, vss, vse) 106 int symsize; 107 void *vss, *vse; 108 { 109 const db_symformat_t * const *symf; 110 const char *name = "netbsd"; 111 112 if (symsize <= 0) { 113 #ifdef SYMTAB_SPACE 114 if (strncmp(db_symtab, SYMTAB_FILLER, sizeof(SYMTAB_FILLER))) { 115 symsize = db_symtabsize; 116 vss = db_symtab; 117 vse = db_symtab + db_symtabsize; 118 } else { 119 #endif 120 printf(" [ no symbols available ]\n"); 121 return; 122 #ifdef SYMTAB_SPACE 123 } 124 #endif 125 } 126 127 /* 128 * Do this check now for the master symbol table to avoid printing 129 * the message N times. 130 */ 131 if (ALIGNED_POINTER(vss, long) == 0) { 132 printf("[ %s symbol table has bad start address %p ]\n", 133 name, vss); 134 return; 135 } 136 137 for (symf = db_symformats; *symf != NULL; symf++) { 138 db_symformat = *symf; 139 if (X_db_sym_init(symsize, vss, vse, name) == TRUE) 140 return; 141 } 142 143 db_symformat = NULL; 144 printf("[ no symbol table formats found ]\n"); 145 146 /* XXX: try SYMTAB_SPACE if we get this far? */ 147 } 148 149 /* 150 * Add symbol table, with given name, to list of symbol tables. 151 */ 152 int 153 db_add_symbol_table(start, end, name, ref) 154 char *start; 155 char *end; 156 const char *name; 157 char *ref; 158 { 159 int slot; 160 161 for (slot = 0; slot < MAXNOSYMTABS; slot++) { 162 if (db_symtabs[slot].name == NULL) 163 break; 164 } 165 if (slot >= MAXNOSYMTABS) { 166 db_printf("No slots left for %s symbol table", name); 167 return(-1); 168 } 169 170 db_symtabs[slot].start = start; 171 db_symtabs[slot].end = end; 172 db_symtabs[slot].name = name; 173 db_symtabs[slot].private = ref; 174 175 return(slot); 176 } 177 178 /* 179 * Delete a symbol table. Caller is responsible for freeing storage. 180 */ 181 void 182 db_del_symbol_table(name) 183 char *name; 184 { 185 int slot; 186 187 for (slot = 0; slot < MAXNOSYMTABS; slot++) { 188 if (db_symtabs[slot].name && 189 ! strcmp(db_symtabs[slot].name, name)) 190 break; 191 } 192 if (slot >= MAXNOSYMTABS) { 193 db_printf("Unable to find symbol table slot for %s.", name); 194 return; 195 } 196 197 db_symtabs[slot].start = 0; 198 db_symtabs[slot].end = 0; 199 db_symtabs[slot].name = 0; 200 db_symtabs[slot].private = 0; 201 } 202 203 /* 204 * db_qualify("vm_map", "netbsd") returns "netbsd:vm_map". 205 * 206 * Note: return value points to static data whose content is 207 * overwritten by each call... but in practice this seems okay. 208 */ 209 static char * 210 db_qualify(sym, symtabname) 211 db_sym_t sym; 212 const char *symtabname; 213 { 214 char *symname; 215 static char tmp[256]; 216 char *s; 217 218 db_symbol_values(sym, &symname, 0); 219 s = tmp; 220 while ((*s++ = *symtabname++) != '\0') 221 ; 222 s[-1] = ':'; 223 while ((*s++ = *symname++) != '\0') 224 ; 225 return tmp; 226 } 227 228 229 boolean_t 230 db_eqname(src, dst, c) 231 char *src; 232 char *dst; 233 int c; 234 { 235 if (!strcmp(src, dst)) 236 return (TRUE); 237 if (src[0] == c) 238 return (!strcmp(src+1,dst)); 239 return (FALSE); 240 } 241 242 boolean_t 243 db_value_of_name(name, valuep) 244 char *name; 245 db_expr_t *valuep; 246 { 247 db_sym_t sym; 248 249 sym = db_lookup(name); 250 if (sym == DB_SYM_NULL) 251 return (FALSE); 252 db_symbol_values(sym, &name, valuep); 253 return (TRUE); 254 } 255 256 257 /* 258 * Lookup a symbol. 259 * If the symbol has a qualifier (e.g., ux:vm_map), 260 * then only the specified symbol table will be searched; 261 * otherwise, all symbol tables will be searched. 262 */ 263 db_sym_t 264 db_lookup(symstr) 265 char *symstr; 266 { 267 db_sym_t sp; 268 int i; 269 int symtab_start = 0; 270 int symtab_end = MAXNOSYMTABS; 271 char *cp; 272 273 /* 274 * Look for, remove, and remember any symbol table specifier. 275 */ 276 for (cp = symstr; *cp; cp++) { 277 if (*cp == ':') { 278 *cp = '\0'; 279 for (i = 0; i < MAXNOSYMTABS; i++) { 280 if (db_symtabs[i].name && 281 ! strcmp(symstr, db_symtabs[i].name)) { 282 symtab_start = i; 283 symtab_end = i + 1; 284 break; 285 } 286 } 287 *cp = ':'; 288 if (i == MAXNOSYMTABS) { 289 db_error("invalid symbol table name"); 290 /*NOTREACHED*/ 291 } 292 symstr = cp+1; 293 } 294 } 295 296 /* 297 * Look in the specified set of symbol tables. 298 * Return on first match. 299 */ 300 for (i = symtab_start; i < symtab_end; i++) { 301 if (db_symtabs[i].name && 302 (sp = X_db_lookup(&db_symtabs[i], symstr))) { 303 db_last_symtab = &db_symtabs[i]; 304 return sp; 305 } 306 } 307 return 0; 308 } 309 310 /* Private structure for passing args to db_sift() from db_sifting(). */ 311 struct db_sift_args { 312 char *symstr; 313 int mode; 314 }; 315 316 /* 317 * Does the work of db_sifting(), called once for each 318 * symbol via X_db_forall(), prints out symbols matching 319 * criteria. 320 */ 321 static void 322 db_sift(stab, sym, name, suffix, prefix, arg) 323 db_symtab_t *stab; 324 db_sym_t sym; 325 char *name; 326 char *suffix; 327 int prefix; 328 void *arg; 329 { 330 char c, sc; 331 char *find, *p; 332 size_t len; 333 struct db_sift_args *dsa; 334 335 dsa = (struct db_sift_args*)arg; 336 337 find = dsa->symstr; /* String we're looking for. */ 338 p = name; /* String we're searching within. */ 339 340 /* Matching algorithm cribbed from strstr(), which is not 341 in the kernel. */ 342 if ((c = *find++) != 0) { 343 len = strlen(find); 344 do { 345 do { 346 if ((sc = *p++) == 0) 347 return; 348 } while (sc != c); 349 } while (strncmp(p, find, len) != 0); 350 } 351 if (dsa->mode=='F') /* ala ls -F */ 352 db_printf("%s%s ", name, suffix); 353 else 354 db_printf("%s ", name); 355 } 356 357 /* 358 * "Sift" for a partial symbol. 359 * Named for the Sun OpenPROM command ("sifting"). 360 * If the symbol has a qualifier (e.g., ux:vm_map), 361 * then only the specified symbol table will be searched; 362 * otherwise, all symbol tables will be searched.. 363 * 364 * "mode" is how-to-display, set from modifiers. 365 */ 366 void 367 db_sifting(symstr, mode) 368 char *symstr; 369 int mode; 370 { 371 char *cp; 372 int i; 373 int symtab_start = 0; 374 int symtab_end = MAXNOSYMTABS; 375 struct db_sift_args dsa; 376 377 /* 378 * Look for, remove, and remember any symbol table specifier. 379 */ 380 for (cp = symstr; *cp; cp++) { 381 if (*cp == ':') { 382 *cp = '\0'; 383 for (i = 0; i < MAXNOSYMTABS; i++) { 384 if (db_symtabs[i].name && 385 ! strcmp(symstr, db_symtabs[i].name)) { 386 symtab_start = i; 387 symtab_end = i + 1; 388 break; 389 } 390 } 391 *cp = ':'; 392 if (i == MAXNOSYMTABS) { 393 db_error("invalid symbol table name"); 394 /*NOTREACHED*/ 395 } 396 symstr = cp+1; 397 } 398 } 399 400 /* Pass args to db_sift(). */ 401 dsa.symstr = symstr; 402 dsa.mode = mode; 403 404 /* 405 * Look in the specified set of symbol tables. 406 */ 407 for (i = symtab_start; i < symtab_end; i++) 408 if (db_symtabs[i].name) { 409 db_printf("Sifting table %s:\n", db_symtabs[i].name); 410 X_db_forall(&db_symtabs[i], db_sift, &dsa); 411 db_printf("\n"); 412 } 413 414 return; 415 } 416 417 418 /* 419 * Does this symbol name appear in more than one symbol table? 420 * Used by db_symbol_values to decide whether to qualify a symbol. 421 */ 422 boolean_t db_qualify_ambiguous_names = FALSE; 423 424 boolean_t 425 db_symbol_is_ambiguous(sym) 426 db_sym_t sym; 427 { 428 char *sym_name; 429 int i; 430 boolean_t found_once = FALSE; 431 432 if (!db_qualify_ambiguous_names) 433 return FALSE; 434 435 db_symbol_values(sym, &sym_name, 0); 436 for (i = 0; i < MAXNOSYMTABS; i++) { 437 if (db_symtabs[i].name && 438 X_db_lookup(&db_symtabs[i], sym_name)) { 439 if (found_once) 440 return TRUE; 441 found_once = TRUE; 442 } 443 } 444 return FALSE; 445 } 446 447 /* 448 * Find the closest symbol to val, and return its name 449 * and the difference between val and the symbol found. 450 */ 451 db_sym_t 452 db_search_symbol( val, strategy, offp) 453 db_addr_t val; 454 db_strategy_t strategy; 455 db_expr_t *offp; 456 { 457 unsigned int diff; 458 db_expr_t newdiff; 459 int i; 460 db_sym_t ret = DB_SYM_NULL, sym; 461 462 newdiff = diff = ~0; 463 db_last_symtab = 0; 464 for (i = 0; i < MAXNOSYMTABS; i++) { 465 if (!db_symtabs[i].name) 466 continue; 467 sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff); 468 if (newdiff < diff) { 469 db_last_symtab = &db_symtabs[i]; 470 diff = newdiff; 471 ret = sym; 472 } 473 } 474 *offp = diff; 475 return ret; 476 } 477 478 /* 479 * Return name and value of a symbol 480 */ 481 void 482 db_symbol_values(sym, namep, valuep) 483 db_sym_t sym; 484 char **namep; 485 db_expr_t *valuep; 486 { 487 db_expr_t value; 488 489 if (sym == DB_SYM_NULL) { 490 *namep = 0; 491 return; 492 } 493 494 X_db_symbol_values(db_last_symtab, sym, namep, &value); 495 496 if (db_symbol_is_ambiguous(sym)) 497 *namep = db_qualify(sym, db_last_symtab->name); 498 if (valuep) 499 *valuep = value; 500 } 501 502 503 /* 504 * Print a the closest symbol to value 505 * 506 * After matching the symbol according to the given strategy 507 * we print it in the name+offset format, provided the symbol's 508 * value is close enough (eg smaller than db_maxoff). 509 * We also attempt to print [filename:linenum] when applicable 510 * (eg for procedure names). 511 * 512 * If we could not find a reasonable name+offset representation, 513 * then we just print the value in hex. Small values might get 514 * bogus symbol associations, e.g. 3 might get some absolute 515 * value like _INCLUDE_VERSION or something, therefore we do 516 * not accept symbols whose value is zero (and use plain hex). 517 * Also, avoid printing as "end+0x????" which is useless. 518 * The variable db_lastsym is used instead of "end" in case we 519 * add support for symbols in loadable driver modules. 520 */ 521 extern char end[]; 522 unsigned long db_lastsym = (unsigned long)end; 523 unsigned int db_maxoff = 0x10000000; 524 525 void 526 db_symstr(buf, off, strategy) 527 char *buf; 528 db_expr_t off; 529 db_strategy_t strategy; 530 { 531 db_expr_t d; 532 char *filename; 533 char *name; 534 db_expr_t value; 535 int linenum; 536 db_sym_t cursym; 537 538 if (off <= db_lastsym) { 539 cursym = db_search_symbol(off, strategy, &d); 540 db_symbol_values(cursym, &name, &value); 541 if (name && (d < db_maxoff) && value) { 542 strcpy(buf, name); 543 if (d) { 544 strcat(buf, "+"); 545 db_format_radix(buf+strlen(buf), 24, d, TRUE); 546 } 547 if (strategy == DB_STGY_PROC) { 548 if (db_line_at_pc(cursym, &filename, &linenum, 549 off)) 550 sprintf(buf+strlen(buf), 551 " [%s:%d]", filename, linenum); 552 } 553 return; 554 } 555 } 556 strcpy(buf, db_num_to_str(off)); 557 return; 558 } 559 560 void 561 db_printsym(off, strategy, pr) 562 db_expr_t off; 563 db_strategy_t strategy; 564 void (*pr) __P((const char *, ...)); 565 { 566 db_expr_t d; 567 char *filename; 568 char *name; 569 db_expr_t value; 570 int linenum; 571 db_sym_t cursym; 572 573 if (off <= db_lastsym) { 574 cursym = db_search_symbol(off, strategy, &d); 575 db_symbol_values(cursym, &name, &value); 576 if (name && (d < db_maxoff) && value) { 577 (*pr)("%s", name); 578 if (d) { 579 char tbuf[24]; 580 581 db_format_radix(tbuf, 24, d, TRUE); 582 (*pr)("+%s", tbuf); 583 } 584 if (strategy == DB_STGY_PROC) { 585 if (db_line_at_pc(cursym, &filename, &linenum, off)) 586 (*pr)(" [%s:%d]", filename, linenum); 587 } 588 return; 589 } 590 } 591 (*pr)(db_num_to_str(off)); 592 return; 593 } 594 595 596 boolean_t 597 db_line_at_pc( sym, filename, linenum, pc) 598 db_sym_t sym; 599 char **filename; 600 int *linenum; 601 db_expr_t pc; 602 { 603 return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc); 604 } 605 606 int 607 db_sym_numargs(sym, nargp, argnames) 608 db_sym_t sym; 609 int *nargp; 610 char **argnames; 611 { 612 return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames); 613 } 614 615 boolean_t 616 X_db_sym_init(symsize, vss, vse, name) 617 int symsize; 618 void *vss, *vse; 619 const char *name; 620 { 621 622 if (db_symformat != NULL) 623 return ((*db_symformat->sym_init)(symsize, vss, vse, name)); 624 return (FALSE); 625 } 626 627 db_sym_t 628 X_db_lookup(stab, symstr) 629 db_symtab_t *stab; 630 char *symstr; 631 { 632 633 if (db_symformat != NULL) 634 return ((*db_symformat->sym_lookup)(stab, symstr)); 635 return ((db_sym_t)0); 636 } 637 638 db_sym_t 639 X_db_search_symbol(stab, off, strategy, diffp) 640 db_symtab_t *stab; 641 db_addr_t off; 642 db_strategy_t strategy; 643 db_expr_t *diffp; 644 { 645 646 if (db_symformat != NULL) 647 return ((*db_symformat->sym_search)(stab, off, strategy, 648 diffp)); 649 return ((db_sym_t)0); 650 } 651 652 void 653 X_db_symbol_values(stab, sym, namep, valuep) 654 db_symtab_t *stab; 655 db_sym_t sym; 656 char **namep; 657 db_expr_t *valuep; 658 { 659 660 if (db_symformat != NULL) 661 (*db_symformat->sym_value)(stab, sym, namep, valuep); 662 } 663 664 boolean_t 665 X_db_line_at_pc(stab, cursym, filename, linenum, off) 666 db_symtab_t *stab; 667 db_sym_t cursym; 668 char **filename; 669 int *linenum; 670 db_expr_t off; 671 { 672 673 if (db_symformat != NULL) 674 return ((*db_symformat->sym_line_at_pc)(stab, cursym, 675 filename, linenum, off)); 676 return (FALSE); 677 } 678 679 boolean_t 680 X_db_sym_numargs(stab, cursym, nargp, argnamep) 681 db_symtab_t *stab; 682 db_sym_t cursym; 683 int *nargp; 684 char **argnamep; 685 { 686 687 if (db_symformat != NULL) 688 return ((*db_symformat->sym_numargs)(stab, cursym, nargp, 689 argnamep)); 690 return (FALSE); 691 } 692 693 void 694 X_db_forall(stab, db_forall_func, arg) 695 db_symtab_t *stab; 696 db_forall_func_t db_forall_func; 697 void *arg; 698 { 699 if (db_symformat != NULL) 700 (*db_symformat->sym_forall)(stab, db_forall_func, arg); 701 } 702