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