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