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