Home | History | Annotate | Line # | Download | only in ddb
db_sym.c revision 1.12
      1 /*	$NetBSD: db_sym.c,v 1.12 1996/02/05 01:57:15 christos 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 (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/param.h>
     30 #include <sys/proc.h>
     31 
     32 #include <machine/db_machdep.h>
     33 
     34 #include <ddb/db_sym.h>
     35 #include <ddb/db_output.h>
     36 #include <ddb/db_extern.h>
     37 #include <ddb/db_command.h>
     38 
     39 /*
     40  * Multiple symbol tables
     41  */
     42 #ifndef MAXLKMS
     43 #define MAXLKMS 20
     44 #endif
     45 
     46 #ifndef MAXNOSYMTABS
     47 #define	MAXNOSYMTABS	MAXLKMS+1	/* Room for kernel + LKM's */
     48 #endif
     49 
     50 db_symtab_t	db_symtabs[MAXNOSYMTABS] = {{0,},};
     51 
     52 db_symtab_t	*db_last_symtab;
     53 
     54 static char *db_qualify __P((db_sym_t, char *));
     55 
     56 /*
     57  * Add symbol table, with given name, to list of symbol tables.
     58  */
     59 int
     60 db_add_symbol_table(start, end, name, ref)
     61 	char *start;
     62 	char *end;
     63 	char *name;
     64 	char *ref;
     65 {
     66 	int slot;
     67 
     68 	for (slot = 0; slot < MAXNOSYMTABS; slot++) {
     69 		if (db_symtabs[slot].name == NULL)
     70 			break;
     71 	}
     72 	if (slot >= MAXNOSYMTABS) {
     73 		db_printf("No slots left for %s symbol table", name);
     74 		return(-1);
     75 	}
     76 
     77 	db_symtabs[slot].start = start;
     78 	db_symtabs[slot].end = end;
     79 	db_symtabs[slot].name = name;
     80 	db_symtabs[slot].private = ref;
     81 
     82 	return(slot);
     83 }
     84 
     85 /*
     86  * Delete a symbol table. Caller is responsible for freeing storage.
     87  */
     88 void
     89 db_del_symbol_table(name)
     90 	char *name;
     91 {
     92 	int slot;
     93 
     94 	for (slot = 0; slot < MAXNOSYMTABS; slot++) {
     95 		if (db_symtabs[slot].name &&
     96 		    ! strcmp(db_symtabs[slot].name, name))
     97 			break;
     98 	}
     99 	if (slot >= MAXNOSYMTABS) {
    100 		db_printf("Unable to find symbol table slot for %s.", name);
    101 		return;
    102 	}
    103 
    104 	db_symtabs[slot].start = 0;
    105 	db_symtabs[slot].end = 0;
    106 	db_symtabs[slot].name = 0;
    107 	db_symtabs[slot].private = 0;
    108 }
    109 
    110 /*
    111  *  db_qualify("vm_map", "netbsd") returns "netbsd:vm_map".
    112  *
    113  *  Note: return value points to static data whose content is
    114  *  overwritten by each call... but in practice this seems okay.
    115  */
    116 static char *
    117 db_qualify(sym, symtabname)
    118 	db_sym_t	sym;
    119 	register char	*symtabname;
    120 {
    121 	char		*symname;
    122 	static char     tmp[256];
    123 	register char	*s;
    124 
    125 	db_symbol_values(sym, &symname, 0);
    126 	s = tmp;
    127 	while ((*s++ = *symtabname++) != '\0')
    128 		;
    129 	s[-1] = ':';
    130 	while ((*s++ = *symname++) != '\0')
    131 		;
    132 	return tmp;
    133 }
    134 
    135 
    136 boolean_t
    137 db_eqname(src, dst, c)
    138 	char *src;
    139 	char *dst;
    140 	int c;
    141 {
    142 	if (!strcmp(src, dst))
    143 	    return (TRUE);
    144 	if (src[0] == c)
    145 	    return (!strcmp(src+1,dst));
    146 	return (FALSE);
    147 }
    148 
    149 boolean_t
    150 db_value_of_name(name, valuep)
    151 	char		*name;
    152 	db_expr_t	*valuep;
    153 {
    154 	db_sym_t	sym;
    155 
    156 	sym = db_lookup(name);
    157 	if (sym == DB_SYM_NULL)
    158 	    return (FALSE);
    159 	db_symbol_values(sym, &name, valuep);
    160 	return (TRUE);
    161 }
    162 
    163 
    164 /*
    165  * Lookup a symbol.
    166  * If the symbol has a qualifier (e.g., ux:vm_map),
    167  * then only the specified symbol table will be searched;
    168  * otherwise, all symbol tables will be searched.
    169  */
    170 db_sym_t
    171 db_lookup(symstr)
    172 	char *symstr;
    173 {
    174 	db_sym_t sp;
    175 	register int i;
    176 	int symtab_start = 0;
    177 	int symtab_end = MAXNOSYMTABS;
    178 	register char *cp;
    179 
    180 	/*
    181 	 * Look for, remove, and remember any symbol table specifier.
    182 	 */
    183 	for (cp = symstr; *cp; cp++) {
    184 		if (*cp == ':') {
    185 			*cp = '\0';
    186 			for (i = 0; i < MAXNOSYMTABS; i++) {
    187 				if (db_symtabs[i].name &&
    188 				    ! strcmp(symstr, db_symtabs[i].name)) {
    189 					symtab_start = i;
    190 					symtab_end = i + 1;
    191 					break;
    192 				}
    193 			}
    194 			*cp = ':';
    195 			if (i == MAXNOSYMTABS) {
    196 				db_error("invalid symbol table name");
    197 				/*NOTREACHED*/
    198 			}
    199 			symstr = cp+1;
    200 		}
    201 	}
    202 
    203 	/*
    204 	 * Look in the specified set of symbol tables.
    205 	 * Return on first match.
    206 	 */
    207 	for (i = symtab_start; i < symtab_end; i++) {
    208 		if (db_symtabs[i].name &&
    209 		    (sp = X_db_lookup(&db_symtabs[i], symstr))) {
    210 			db_last_symtab = &db_symtabs[i];
    211 			return sp;
    212 		}
    213 	}
    214 	return 0;
    215 }
    216 
    217 /*
    218  * Does this symbol name appear in more than one symbol table?
    219  * Used by db_symbol_values to decide whether to qualify a symbol.
    220  */
    221 boolean_t db_qualify_ambiguous_names = FALSE;
    222 
    223 boolean_t
    224 db_symbol_is_ambiguous(sym)
    225 	db_sym_t	sym;
    226 {
    227 	char		*sym_name;
    228 	register int	i;
    229 	register
    230 	boolean_t	found_once = FALSE;
    231 
    232 	if (!db_qualify_ambiguous_names)
    233 		return FALSE;
    234 
    235 	db_symbol_values(sym, &sym_name, 0);
    236 	for (i = 0; i < MAXNOSYMTABS; i++) {
    237 		if (db_symtabs[i].name &&
    238 		    X_db_lookup(&db_symtabs[i], sym_name)) {
    239 			if (found_once)
    240 				return TRUE;
    241 			found_once = TRUE;
    242 		}
    243 	}
    244 	return FALSE;
    245 }
    246 
    247 /*
    248  * Find the closest symbol to val, and return its name
    249  * and the difference between val and the symbol found.
    250  */
    251 db_sym_t
    252 db_search_symbol( val, strategy, offp)
    253 	register db_addr_t	val;
    254 	db_strategy_t		strategy;
    255 	db_expr_t		*offp;
    256 {
    257 	register
    258 	unsigned int	diff;
    259 	unsigned int	newdiff;
    260 	register int	i;
    261 	db_sym_t	ret = DB_SYM_NULL, sym;
    262 
    263 	newdiff = diff = ~0;
    264 	db_last_symtab = 0;
    265 	for (i = 0; i < MAXNOSYMTABS; i++) {
    266 	    if (!db_symtabs[i].name)
    267 	        continue;
    268 	    sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
    269 	    if (newdiff < diff) {
    270 		db_last_symtab = &db_symtabs[i];
    271 		diff = newdiff;
    272 		ret = sym;
    273 	    }
    274 	}
    275 	*offp = diff;
    276 	return ret;
    277 }
    278 
    279 /*
    280  * Return name and value of a symbol
    281  */
    282 void
    283 db_symbol_values(sym, namep, valuep)
    284 	db_sym_t	sym;
    285 	char		**namep;
    286 	db_expr_t	*valuep;
    287 {
    288 	db_expr_t	value;
    289 
    290 	if (sym == DB_SYM_NULL) {
    291 		*namep = 0;
    292 		return;
    293 	}
    294 
    295 	X_db_symbol_values(sym, namep, &value);
    296 
    297 	if (db_symbol_is_ambiguous(sym))
    298 		*namep = db_qualify(sym, db_last_symtab->name);
    299 	if (valuep)
    300 		*valuep = value;
    301 }
    302 
    303 
    304 /*
    305  * Print a the closest symbol to value
    306  *
    307  * After matching the symbol according to the given strategy
    308  * we print it in the name+offset format, provided the symbol's
    309  * value is close enough (eg smaller than db_maxoff).
    310  * We also attempt to print [filename:linenum] when applicable
    311  * (eg for procedure names).
    312  *
    313  * If we could not find a reasonable name+offset representation,
    314  * then we just print the value in hex.  Small values might get
    315  * bogus symbol associations, e.g. 3 might get some absolute
    316  * value like _INCLUDE_VERSION or something, therefore we do
    317  * not accept symbols whose value is zero (and use plain hex).
    318  * Also, avoid printing as "end+0x????" which is useless.
    319  * The variable db_lastsym is used instead of "end" in case we
    320  * add support for symbols in loadable driver modules.
    321  */
    322 extern char end[];
    323 unsigned int	db_lastsym = (unsigned long)end;
    324 db_expr_t db_maxoff = 0x10000000;
    325 
    326 
    327 void
    328 db_printsym(off, strategy)
    329 	db_expr_t	off;
    330 	db_strategy_t	strategy;
    331 {
    332 	db_expr_t	d;
    333 	char 		*filename;
    334 	char		*name;
    335 	db_expr_t	value;
    336 	int 		linenum;
    337 	db_sym_t	cursym;
    338 
    339 	if (off <= db_lastsym) {
    340 		cursym = db_search_symbol(off, strategy, &d);
    341 		db_symbol_values(cursym, &name, &value);
    342 		if (name && (d < db_maxoff) && value) {
    343 			db_printf("%s", name);
    344 			if (d)
    345 				db_printf("+%#r", d);
    346 			if (strategy == DB_STGY_PROC) {
    347 				if (db_line_at_pc(cursym, &filename, &linenum, off))
    348 					db_printf(" [%s:%d]", filename, linenum);
    349 			}
    350 			return;
    351 		}
    352 	}
    353 	db_printf("%#n", off);
    354 	return;
    355 }
    356 
    357 
    358 boolean_t
    359 db_line_at_pc( sym, filename, linenum, pc)
    360 	db_sym_t	sym;
    361 	char		**filename;
    362 	int		*linenum;
    363 	db_expr_t	pc;
    364 {
    365 	return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc);
    366 }
    367 
    368 int
    369 db_sym_numargs(sym, nargp, argnames)
    370 	db_sym_t	sym;
    371 	int		*nargp;
    372 	char		**argnames;
    373 {
    374 	return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames);
    375 }
    376