Home | History | Annotate | Line # | Download | only in ddb
db_sym.c revision 1.32
      1 /*	$NetBSD: db_sym.c,v 1.32 2002/11/04 06:24:41 itohy 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 (at) 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.32 2002/11/04 06:24:41 itohy Exp $");
     31 
     32 #include "opt_ddbparam.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