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