db_sym.c revision 1.15
1/* $NetBSD: db_sym.c,v 1.15 1998/12/04 20:18:05 thorpej 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 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/param.h> 30#include <sys/proc.h> 31#include <sys/systm.h> 32 33#include <machine/db_machdep.h> 34 35#include <ddb/db_sym.h> 36#include <ddb/db_output.h> 37#include <ddb/db_extern.h> 38#include <ddb/db_command.h> 39 40/* 41 * Multiple symbol tables 42 */ 43#ifndef MAXLKMS 44#define MAXLKMS 20 45#endif 46 47#ifndef MAXNOSYMTABS 48#define MAXNOSYMTABS MAXLKMS+1 /* Room for kernel + LKM's */ 49#endif 50 51db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},}; 52 53db_symtab_t *db_last_symtab; 54 55static char *db_qualify __P((db_sym_t, const char *)); 56 57/* 58 * Put the most picky symbol table formats at the top! 59 */ 60const db_symformat_t *db_symformats[] = { 61#ifdef DB_ELF_SYMBOLS 62 &db_symformat_elf, 63#endif 64#ifdef DB_AOUT_SYMBOLS 65 &db_symformat_aout, 66#endif 67 NULL, 68}; 69 70const db_symformat_t *db_symformat; 71 72boolean_t X_db_sym_init __P((int, void *, void *, const char *)); 73db_sym_t X_db_lookup __P((db_symtab_t *, char *)); 74db_sym_t X_db_search_symbol __P((db_symtab_t *, db_addr_t, 75 db_strategy_t, db_expr_t *)); 76void X_db_symbol_values __P((db_symtab_t *, db_sym_t, char **, 77 db_expr_t *)); 78boolean_t X_db_line_at_pc __P((db_symtab_t *, db_sym_t, char **, 79 int *, db_expr_t)); 80int X_db_sym_numargs __P((db_symtab_t *, db_sym_t, int *, 81 char **)); 82 83/* 84 * Initialize the kernel debugger by initializing the master symbol 85 * table. Note that if initializing the master symbol table fails, 86 * no other symbol tables can be loaded. 87 */ 88void 89ddb_init(symsize, vss, vse) 90 int symsize; 91 void *vss, *vse; 92{ 93 const db_symformat_t **symf; 94 const char *name = "netbsd"; 95 96 if (symsize <= 0) { 97 printf(" [ no symbols available ]\n"); 98 return; 99 } 100 101 /* 102 * Do this check now for the master symbol table to avoid printing 103 * the message N times. 104 */ 105 if (ALIGNED_POINTER(vss, long) == 0) { 106 printf("[ %s symbol table nas bad start address %p ]\n", 107 name, vss); 108 return; 109 } 110 111 for (symf = db_symformats; *symf != NULL; symf++) { 112 db_symformat = *symf; 113 if (X_db_sym_init(symsize, vss, vse, name) == TRUE) 114 return; 115 } 116 117 db_symformat = NULL; 118 printf("[ no symbol table formats found ]\n"); 119} 120 121/* 122 * Add symbol table, with given name, to list of symbol tables. 123 */ 124int 125db_add_symbol_table(start, end, name, ref) 126 char *start; 127 char *end; 128 const char *name; 129 char *ref; 130{ 131 int slot; 132 133 for (slot = 0; slot < MAXNOSYMTABS; slot++) { 134 if (db_symtabs[slot].name == NULL) 135 break; 136 } 137 if (slot >= MAXNOSYMTABS) { 138 db_printf("No slots left for %s symbol table", name); 139 return(-1); 140 } 141 142 db_symtabs[slot].start = start; 143 db_symtabs[slot].end = end; 144 db_symtabs[slot].name = name; 145 db_symtabs[slot].private = ref; 146 147 return(slot); 148} 149 150/* 151 * Delete a symbol table. Caller is responsible for freeing storage. 152 */ 153void 154db_del_symbol_table(name) 155 char *name; 156{ 157 int slot; 158 159 for (slot = 0; slot < MAXNOSYMTABS; slot++) { 160 if (db_symtabs[slot].name && 161 ! strcmp(db_symtabs[slot].name, name)) 162 break; 163 } 164 if (slot >= MAXNOSYMTABS) { 165 db_printf("Unable to find symbol table slot for %s.", name); 166 return; 167 } 168 169 db_symtabs[slot].start = 0; 170 db_symtabs[slot].end = 0; 171 db_symtabs[slot].name = 0; 172 db_symtabs[slot].private = 0; 173} 174 175/* 176 * db_qualify("vm_map", "netbsd") returns "netbsd:vm_map". 177 * 178 * Note: return value points to static data whose content is 179 * overwritten by each call... but in practice this seems okay. 180 */ 181static char * 182db_qualify(sym, symtabname) 183 db_sym_t sym; 184 const char *symtabname; 185{ 186 char *symname; 187 static char tmp[256]; 188 register char *s; 189 190 db_symbol_values(sym, &symname, 0); 191 s = tmp; 192 while ((*s++ = *symtabname++) != '\0') 193 ; 194 s[-1] = ':'; 195 while ((*s++ = *symname++) != '\0') 196 ; 197 return tmp; 198} 199 200 201boolean_t 202db_eqname(src, dst, c) 203 char *src; 204 char *dst; 205 int c; 206{ 207 if (!strcmp(src, dst)) 208 return (TRUE); 209 if (src[0] == c) 210 return (!strcmp(src+1,dst)); 211 return (FALSE); 212} 213 214boolean_t 215db_value_of_name(name, valuep) 216 char *name; 217 db_expr_t *valuep; 218{ 219 db_sym_t sym; 220 221 sym = db_lookup(name); 222 if (sym == DB_SYM_NULL) 223 return (FALSE); 224 db_symbol_values(sym, &name, valuep); 225 return (TRUE); 226} 227 228 229/* 230 * Lookup a symbol. 231 * If the symbol has a qualifier (e.g., ux:vm_map), 232 * then only the specified symbol table will be searched; 233 * otherwise, all symbol tables will be searched. 234 */ 235db_sym_t 236db_lookup(symstr) 237 char *symstr; 238{ 239 db_sym_t sp; 240 register int i; 241 int symtab_start = 0; 242 int symtab_end = MAXNOSYMTABS; 243 register char *cp; 244 245 /* 246 * Look for, remove, and remember any symbol table specifier. 247 */ 248 for (cp = symstr; *cp; cp++) { 249 if (*cp == ':') { 250 *cp = '\0'; 251 for (i = 0; i < MAXNOSYMTABS; i++) { 252 if (db_symtabs[i].name && 253 ! strcmp(symstr, db_symtabs[i].name)) { 254 symtab_start = i; 255 symtab_end = i + 1; 256 break; 257 } 258 } 259 *cp = ':'; 260 if (i == MAXNOSYMTABS) { 261 db_error("invalid symbol table name"); 262 /*NOTREACHED*/ 263 } 264 symstr = cp+1; 265 } 266 } 267 268 /* 269 * Look in the specified set of symbol tables. 270 * Return on first match. 271 */ 272 for (i = symtab_start; i < symtab_end; i++) { 273 if (db_symtabs[i].name && 274 (sp = X_db_lookup(&db_symtabs[i], symstr))) { 275 db_last_symtab = &db_symtabs[i]; 276 return sp; 277 } 278 } 279 return 0; 280} 281 282/* 283 * Does this symbol name appear in more than one symbol table? 284 * Used by db_symbol_values to decide whether to qualify a symbol. 285 */ 286boolean_t db_qualify_ambiguous_names = FALSE; 287 288boolean_t 289db_symbol_is_ambiguous(sym) 290 db_sym_t sym; 291{ 292 char *sym_name; 293 register int i; 294 register 295 boolean_t found_once = FALSE; 296 297 if (!db_qualify_ambiguous_names) 298 return FALSE; 299 300 db_symbol_values(sym, &sym_name, 0); 301 for (i = 0; i < MAXNOSYMTABS; i++) { 302 if (db_symtabs[i].name && 303 X_db_lookup(&db_symtabs[i], sym_name)) { 304 if (found_once) 305 return TRUE; 306 found_once = TRUE; 307 } 308 } 309 return FALSE; 310} 311 312/* 313 * Find the closest symbol to val, and return its name 314 * and the difference between val and the symbol found. 315 */ 316db_sym_t 317db_search_symbol( val, strategy, offp) 318 register db_addr_t val; 319 db_strategy_t strategy; 320 db_expr_t *offp; 321{ 322 register 323 unsigned int diff; 324 db_expr_t newdiff; 325 register int i; 326 db_sym_t ret = DB_SYM_NULL, sym; 327 328 newdiff = diff = ~0; 329 db_last_symtab = 0; 330 for (i = 0; i < MAXNOSYMTABS; i++) { 331 if (!db_symtabs[i].name) 332 continue; 333 sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff); 334 if (newdiff < diff) { 335 db_last_symtab = &db_symtabs[i]; 336 diff = newdiff; 337 ret = sym; 338 } 339 } 340 *offp = diff; 341 return ret; 342} 343 344/* 345 * Return name and value of a symbol 346 */ 347void 348db_symbol_values(sym, namep, valuep) 349 db_sym_t sym; 350 char **namep; 351 db_expr_t *valuep; 352{ 353 db_expr_t value; 354 355 if (sym == DB_SYM_NULL) { 356 *namep = 0; 357 return; 358 } 359 360 X_db_symbol_values(db_last_symtab, sym, namep, &value); 361 362 if (db_symbol_is_ambiguous(sym)) 363 *namep = db_qualify(sym, db_last_symtab->name); 364 if (valuep) 365 *valuep = value; 366} 367 368 369/* 370 * Print a the closest symbol to value 371 * 372 * After matching the symbol according to the given strategy 373 * we print it in the name+offset format, provided the symbol's 374 * value is close enough (eg smaller than db_maxoff). 375 * We also attempt to print [filename:linenum] when applicable 376 * (eg for procedure names). 377 * 378 * If we could not find a reasonable name+offset representation, 379 * then we just print the value in hex. Small values might get 380 * bogus symbol associations, e.g. 3 might get some absolute 381 * value like _INCLUDE_VERSION or something, therefore we do 382 * not accept symbols whose value is zero (and use plain hex). 383 * Also, avoid printing as "end+0x????" which is useless. 384 * The variable db_lastsym is used instead of "end" in case we 385 * add support for symbols in loadable driver modules. 386 */ 387extern char end[]; 388unsigned long db_lastsym = (unsigned long)end; 389unsigned int db_maxoff = 0x10000000; 390 391 392void 393db_printsym(off, strategy) 394 db_expr_t off; 395 db_strategy_t strategy; 396{ 397 db_expr_t d; 398 char *filename; 399 char *name; 400 db_expr_t value; 401 int linenum; 402 db_sym_t cursym; 403 404 if (off <= db_lastsym) { 405 cursym = db_search_symbol(off, strategy, &d); 406 db_symbol_values(cursym, &name, &value); 407 if (name && (d < db_maxoff) && value) { 408 db_printf("%s", name); 409 if (d) 410 db_printf("+%#lr", d); 411 if (strategy == DB_STGY_PROC) { 412 if (db_line_at_pc(cursym, &filename, &linenum, off)) 413 db_printf(" [%s:%d]", filename, linenum); 414 } 415 return; 416 } 417 } 418 db_printf("%#ln", off); 419 return; 420} 421 422 423boolean_t 424db_line_at_pc( sym, filename, linenum, pc) 425 db_sym_t sym; 426 char **filename; 427 int *linenum; 428 db_expr_t pc; 429{ 430 return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc); 431} 432 433int 434db_sym_numargs(sym, nargp, argnames) 435 db_sym_t sym; 436 int *nargp; 437 char **argnames; 438{ 439 return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames); 440} 441 442boolean_t 443X_db_sym_init(symsize, vss, vse, name) 444 int symsize; 445 void *vss, *vse; 446 const char *name; 447{ 448 449 if (db_symformat != NULL) 450 return ((*db_symformat->sym_init)(symsize, vss, vse, name)); 451 return (FALSE); 452} 453 454db_sym_t 455X_db_lookup(stab, symstr) 456 db_symtab_t *stab; 457 char *symstr; 458{ 459 460 if (db_symformat != NULL) 461 return ((*db_symformat->sym_lookup)(stab, symstr)); 462 return ((db_sym_t)0); 463} 464 465db_sym_t 466X_db_search_symbol(stab, off, strategy, diffp) 467 db_symtab_t *stab; 468 db_addr_t off; 469 db_strategy_t strategy; 470 db_expr_t *diffp; 471{ 472 473 if (db_symformat != NULL) 474 return ((*db_symformat->sym_search)(stab, off, strategy, 475 diffp)); 476 return ((db_sym_t)0); 477} 478 479void 480X_db_symbol_values(stab, sym, namep, valuep) 481 db_symtab_t *stab; 482 db_sym_t sym; 483 char **namep; 484 db_expr_t *valuep; 485{ 486 487 if (db_symformat != NULL) 488 (*db_symformat->sym_value)(stab, sym, namep, valuep); 489} 490 491boolean_t 492X_db_line_at_pc(stab, cursym, filename, linenum, off) 493 db_symtab_t *stab; 494 db_sym_t cursym; 495 char **filename; 496 int *linenum; 497 db_expr_t off; 498{ 499 500 if (db_symformat != NULL) 501 return ((*db_symformat->sym_line_at_pc)(stab, cursym, 502 filename, linenum, off)); 503 return (FALSE); 504} 505 506boolean_t 507X_db_sym_numargs(stab, cursym, nargp, argnamep) 508 db_symtab_t *stab; 509 db_sym_t cursym; 510 int *nargp; 511 char **argnamep; 512{ 513 514 if (db_symformat != NULL) 515 return ((*db_symformat->sym_numargs)(stab, cursym, nargp, 516 argnamep)); 517 return (FALSE); 518} 519