xref: /netbsd-src/sys/ddb/db_sym.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: db_sym.c,v 1.14 1997/06/26 01:19:07 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 
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 	db_expr_t	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(db_last_symtab, 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 long	db_lastsym = (unsigned long)end;
324 unsigned int	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("+%#lr", 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("%#ln", 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