xref: /netbsd-src/sys/ddb/db_sym.c (revision 9fbd88883c38d0c0fbfcbe66d76fe6b0fab3f9de)
1 /*	$NetBSD: db_sym.c,v 1.30 2002/01/05 20:09:52 jhawk 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@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.30 2002/01/05 20:09:52 jhawk Exp $");
31 
32 #include "opt_ddb.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 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 __P((db_sym_t, const char *));
69 static db_forall_func_t db_sift;
70 
71 /*
72  * Put the most picky symbol table formats at the top!
73  */
74 const db_symformat_t * const db_symformats[] = {
75 #ifdef DB_ELF_SYMBOLS
76 	&db_symformat_elf,
77 #endif
78 #ifdef DB_AOUT_SYMBOLS
79 	&db_symformat_aout,
80 #endif
81 	NULL,
82 };
83 
84 const db_symformat_t *db_symformat;
85 
86 boolean_t	X_db_sym_init __P((int, void *, void *, const char *));
87 db_sym_t	X_db_lookup __P((db_symtab_t *, char *));
88 db_sym_t	X_db_search_symbol __P((db_symtab_t *, db_addr_t,
89 		    db_strategy_t, db_expr_t *));
90 void		X_db_symbol_values __P((db_symtab_t *, db_sym_t, char **,
91 		    db_expr_t *));
92 boolean_t	X_db_line_at_pc __P((db_symtab_t *, db_sym_t, char **,
93 		    int *, db_expr_t));
94 int		X_db_sym_numargs __P((db_symtab_t *, db_sym_t, int *,
95 		    char **));
96 void		X_db_forall __P((db_symtab_t *,
97 		    db_forall_func_t db_forall_func, void *));
98 
99 /*
100  * Initialize the kernel debugger by initializing the master symbol
101  * table.  Note that if initializing the master symbol table fails,
102  * no other symbol tables can be loaded.
103  */
104 void
105 ddb_init(symsize, vss, vse)
106 	int symsize;
107 	void *vss, *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(start, end, name, ref)
154 	char *start;
155 	char *end;
156 	const char *name;
157 	char *ref;
158 {
159 	int slot;
160 
161 	for (slot = 0; slot < MAXNOSYMTABS; slot++) {
162 		if (db_symtabs[slot].name == NULL)
163 			break;
164 	}
165 	if (slot >= MAXNOSYMTABS) {
166 		db_printf("No slots left for %s symbol table", name);
167 		return(-1);
168 	}
169 
170 	db_symtabs[slot].start = start;
171 	db_symtabs[slot].end = end;
172 	db_symtabs[slot].name = name;
173 	db_symtabs[slot].private = ref;
174 
175 	return(slot);
176 }
177 
178 /*
179  * Delete a symbol table. Caller is responsible for freeing storage.
180  */
181 void
182 db_del_symbol_table(name)
183 	char *name;
184 {
185 	int slot;
186 
187 	for (slot = 0; slot < MAXNOSYMTABS; slot++) {
188 		if (db_symtabs[slot].name &&
189 		    ! strcmp(db_symtabs[slot].name, name))
190 			break;
191 	}
192 	if (slot >= MAXNOSYMTABS) {
193 		db_printf("Unable to find symbol table slot for %s.", name);
194 		return;
195 	}
196 
197 	db_symtabs[slot].start = 0;
198 	db_symtabs[slot].end = 0;
199 	db_symtabs[slot].name = 0;
200 	db_symtabs[slot].private = 0;
201 }
202 
203 /*
204  *  db_qualify("vm_map", "netbsd") returns "netbsd:vm_map".
205  *
206  *  Note: return value points to static data whose content is
207  *  overwritten by each call... but in practice this seems okay.
208  */
209 static char *
210 db_qualify(sym, symtabname)
211 	db_sym_t	sym;
212 	const char	*symtabname;
213 {
214 	char		*symname;
215 	static char     tmp[256];
216 	char	*s;
217 
218 	db_symbol_values(sym, &symname, 0);
219 	s = tmp;
220 	while ((*s++ = *symtabname++) != '\0')
221 		;
222 	s[-1] = ':';
223 	while ((*s++ = *symname++) != '\0')
224 		;
225 	return tmp;
226 }
227 
228 
229 boolean_t
230 db_eqname(src, dst, c)
231 	char *src;
232 	char *dst;
233 	int c;
234 {
235 	if (!strcmp(src, dst))
236 	    return (TRUE);
237 	if (src[0] == c)
238 	    return (!strcmp(src+1,dst));
239 	return (FALSE);
240 }
241 
242 boolean_t
243 db_value_of_name(name, valuep)
244 	char		*name;
245 	db_expr_t	*valuep;
246 {
247 	db_sym_t	sym;
248 
249 	sym = db_lookup(name);
250 	if (sym == DB_SYM_NULL)
251 	    return (FALSE);
252 	db_symbol_values(sym, &name, valuep);
253 	return (TRUE);
254 }
255 
256 
257 /*
258  * Lookup a symbol.
259  * If the symbol has a qualifier (e.g., ux:vm_map),
260  * then only the specified symbol table will be searched;
261  * otherwise, all symbol tables will be searched.
262  */
263 db_sym_t
264 db_lookup(symstr)
265 	char *symstr;
266 {
267 	db_sym_t sp;
268 	int i;
269 	int symtab_start = 0;
270 	int symtab_end = MAXNOSYMTABS;
271 	char *cp;
272 
273 	/*
274 	 * Look for, remove, and remember any symbol table specifier.
275 	 */
276 	for (cp = symstr; *cp; cp++) {
277 		if (*cp == ':') {
278 			*cp = '\0';
279 			for (i = 0; i < MAXNOSYMTABS; i++) {
280 				if (db_symtabs[i].name &&
281 				    ! strcmp(symstr, db_symtabs[i].name)) {
282 					symtab_start = i;
283 					symtab_end = i + 1;
284 					break;
285 				}
286 			}
287 			*cp = ':';
288 			if (i == MAXNOSYMTABS) {
289 				db_error("invalid symbol table name");
290 				/*NOTREACHED*/
291 			}
292 			symstr = cp+1;
293 		}
294 	}
295 
296 	/*
297 	 * Look in the specified set of symbol tables.
298 	 * Return on first match.
299 	 */
300 	for (i = symtab_start; i < symtab_end; i++) {
301 		if (db_symtabs[i].name &&
302 		    (sp = X_db_lookup(&db_symtabs[i], symstr))) {
303 			db_last_symtab = &db_symtabs[i];
304 			return sp;
305 		}
306 	}
307 	return 0;
308 }
309 
310 /* Private structure for passing args to db_sift() from db_sifting(). */
311 struct db_sift_args {
312 	char	*symstr;
313 	int	mode;
314 };
315 
316 /*
317  * Does the work of db_sifting(), called once for each
318  * symbol via X_db_forall(), prints out symbols matching
319  * criteria.
320  */
321 static void
322 db_sift(stab, sym, name, suffix, prefix, arg)
323 	db_symtab_t	*stab;
324 	db_sym_t	sym;
325 	char		*name;
326 	char		*suffix;
327 	int		prefix;
328 	void		*arg;
329 {
330 	char c, sc;
331 	char *find, *p;
332 	size_t len;
333 	struct db_sift_args *dsa;
334 
335 	dsa = (struct db_sift_args*)arg;
336 
337 	find = dsa->symstr;	/* String we're looking for. */
338 	p = name;		/* String we're searching within. */
339 
340 	/* Matching algorithm cribbed from strstr(), which is not
341 	   in the kernel. */
342 	if ((c = *find++) != 0) {
343 		len = strlen(find);
344 		do {
345 			do {
346 				if ((sc = *p++) == 0)
347 					return;
348 			} while (sc != c);
349 		} while (strncmp(p, find, len) != 0);
350 	}
351 	if (dsa->mode=='F')	/* ala ls -F */
352 		db_printf("%s%s ", name, suffix);
353 	else
354 		db_printf("%s ", name);
355 }
356 
357 /*
358  * "Sift" for a partial symbol.
359  * Named for the Sun OpenPROM command ("sifting").
360  * If the symbol has a qualifier (e.g., ux:vm_map),
361  * then only the specified symbol table will be searched;
362  * otherwise, all symbol tables will be searched..
363  *
364  * "mode" is how-to-display, set from modifiers.
365  */
366 void
367 db_sifting(symstr, mode)
368 	char	*symstr;
369 	int	mode;
370 {
371 	char *cp;
372 	int i;
373 	int symtab_start = 0;
374 	int symtab_end = MAXNOSYMTABS;
375 	struct db_sift_args dsa;
376 
377 	/*
378 	 * Look for, remove, and remember any symbol table specifier.
379 	 */
380 	for (cp = symstr; *cp; cp++) {
381 		if (*cp == ':') {
382 			*cp = '\0';
383 			for (i = 0; i < MAXNOSYMTABS; i++) {
384 				if (db_symtabs[i].name &&
385 				    ! strcmp(symstr, db_symtabs[i].name)) {
386 					symtab_start = i;
387 					symtab_end = i + 1;
388 					break;
389 				}
390 			}
391 			*cp = ':';
392 			if (i == MAXNOSYMTABS) {
393 				db_error("invalid symbol table name");
394 				/*NOTREACHED*/
395 			}
396 			symstr = cp+1;
397 		}
398 	}
399 
400 	/* Pass args to db_sift(). */
401 	dsa.symstr = symstr;
402 	dsa.mode = mode;
403 
404 	/*
405 	 * Look in the specified set of symbol tables.
406 	 */
407 	for (i = symtab_start; i < symtab_end; i++)
408 		if (db_symtabs[i].name) {
409 			db_printf("Sifting table %s:\n", db_symtabs[i].name);
410 			X_db_forall(&db_symtabs[i], db_sift, &dsa);
411 			db_printf("\n");
412 		}
413 
414 	return;
415 }
416 
417 
418 /*
419  * Does this symbol name appear in more than one symbol table?
420  * Used by db_symbol_values to decide whether to qualify a symbol.
421  */
422 boolean_t db_qualify_ambiguous_names = FALSE;
423 
424 boolean_t
425 db_symbol_is_ambiguous(sym)
426 	db_sym_t	sym;
427 {
428 	char		*sym_name;
429 	int	i;
430 	boolean_t	found_once = FALSE;
431 
432 	if (!db_qualify_ambiguous_names)
433 		return FALSE;
434 
435 	db_symbol_values(sym, &sym_name, 0);
436 	for (i = 0; i < MAXNOSYMTABS; i++) {
437 		if (db_symtabs[i].name &&
438 		    X_db_lookup(&db_symtabs[i], sym_name)) {
439 			if (found_once)
440 				return TRUE;
441 			found_once = TRUE;
442 		}
443 	}
444 	return FALSE;
445 }
446 
447 /*
448  * Find the closest symbol to val, and return its name
449  * and the difference between val and the symbol found.
450  */
451 db_sym_t
452 db_search_symbol( val, strategy, offp)
453 	db_addr_t		val;
454 	db_strategy_t		strategy;
455 	db_expr_t		*offp;
456 {
457 	unsigned int	diff;
458 	db_expr_t	newdiff;
459 	int		i;
460 	db_sym_t	ret = DB_SYM_NULL, sym;
461 
462 	newdiff = diff = ~0;
463 	db_last_symtab = 0;
464 	for (i = 0; i < MAXNOSYMTABS; i++) {
465 	    if (!db_symtabs[i].name)
466 	        continue;
467 	    sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
468 	    if (newdiff < diff) {
469 		db_last_symtab = &db_symtabs[i];
470 		diff = newdiff;
471 		ret = sym;
472 	    }
473 	}
474 	*offp = diff;
475 	return ret;
476 }
477 
478 /*
479  * Return name and value of a symbol
480  */
481 void
482 db_symbol_values(sym, namep, valuep)
483 	db_sym_t	sym;
484 	char		**namep;
485 	db_expr_t	*valuep;
486 {
487 	db_expr_t	value;
488 
489 	if (sym == DB_SYM_NULL) {
490 		*namep = 0;
491 		return;
492 	}
493 
494 	X_db_symbol_values(db_last_symtab, sym, namep, &value);
495 
496 	if (db_symbol_is_ambiguous(sym))
497 		*namep = db_qualify(sym, db_last_symtab->name);
498 	if (valuep)
499 		*valuep = value;
500 }
501 
502 
503 /*
504  * Print a the closest symbol to value
505  *
506  * After matching the symbol according to the given strategy
507  * we print it in the name+offset format, provided the symbol's
508  * value is close enough (eg smaller than db_maxoff).
509  * We also attempt to print [filename:linenum] when applicable
510  * (eg for procedure names).
511  *
512  * If we could not find a reasonable name+offset representation,
513  * then we just print the value in hex.  Small values might get
514  * bogus symbol associations, e.g. 3 might get some absolute
515  * value like _INCLUDE_VERSION or something, therefore we do
516  * not accept symbols whose value is zero (and use plain hex).
517  * Also, avoid printing as "end+0x????" which is useless.
518  * The variable db_lastsym is used instead of "end" in case we
519  * add support for symbols in loadable driver modules.
520  */
521 extern char end[];
522 unsigned long	db_lastsym = (unsigned long)end;
523 unsigned int	db_maxoff = 0x10000000;
524 
525 void
526 db_symstr(buf, off, strategy)
527 	char		*buf;
528 	db_expr_t	off;
529 	db_strategy_t	strategy;
530 {
531 	db_expr_t	d;
532 	char 		*filename;
533 	char		*name;
534 	db_expr_t	value;
535 	int 		linenum;
536 	db_sym_t	cursym;
537 
538 	if (off <= db_lastsym) {
539 		cursym = db_search_symbol(off, strategy, &d);
540 		db_symbol_values(cursym, &name, &value);
541 		if (name && (d < db_maxoff) && value) {
542 			strcpy(buf, name);
543 			if (d) {
544 				strcat(buf, "+");
545 				db_format_radix(buf+strlen(buf), 24, d, TRUE);
546 			}
547 			if (strategy == DB_STGY_PROC) {
548 				if (db_line_at_pc(cursym, &filename, &linenum,
549 				    off))
550 					sprintf(buf+strlen(buf),
551 					    " [%s:%d]", filename, linenum);
552 			}
553 			return;
554 		}
555 	}
556 	strcpy(buf, db_num_to_str(off));
557 	return;
558 }
559 
560 void
561 db_printsym(off, strategy, pr)
562 	db_expr_t	off;
563 	db_strategy_t	strategy;
564 	void (*pr) __P((const char *, ...));
565 {
566 	db_expr_t	d;
567 	char 		*filename;
568 	char		*name;
569 	db_expr_t	value;
570 	int 		linenum;
571 	db_sym_t	cursym;
572 
573 	if (off <= db_lastsym) {
574 		cursym = db_search_symbol(off, strategy, &d);
575 		db_symbol_values(cursym, &name, &value);
576 		if (name && (d < db_maxoff) && value) {
577 			(*pr)("%s", name);
578 			if (d) {
579 				char tbuf[24];
580 
581 				db_format_radix(tbuf, 24, d, TRUE);
582 				(*pr)("+%s", tbuf);
583 			}
584 			if (strategy == DB_STGY_PROC) {
585 				if (db_line_at_pc(cursym, &filename, &linenum, off))
586 					(*pr)(" [%s:%d]", filename, linenum);
587 			}
588 			return;
589 		}
590 	}
591 	(*pr)(db_num_to_str(off));
592 	return;
593 }
594 
595 
596 boolean_t
597 db_line_at_pc( sym, filename, linenum, pc)
598 	db_sym_t	sym;
599 	char		**filename;
600 	int		*linenum;
601 	db_expr_t	pc;
602 {
603 	return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc);
604 }
605 
606 int
607 db_sym_numargs(sym, nargp, argnames)
608 	db_sym_t	sym;
609 	int		*nargp;
610 	char		**argnames;
611 {
612 	return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames);
613 }
614 
615 boolean_t
616 X_db_sym_init(symsize, vss, vse, name)
617 	int symsize;
618 	void *vss, *vse;
619 	const char *name;
620 {
621 
622 	if (db_symformat != NULL)
623 		return ((*db_symformat->sym_init)(symsize, vss, vse, name));
624 	return (FALSE);
625 }
626 
627 db_sym_t
628 X_db_lookup(stab, symstr)
629 	db_symtab_t *stab;
630 	char *symstr;
631 {
632 
633 	if (db_symformat != NULL)
634 		return ((*db_symformat->sym_lookup)(stab, symstr));
635 	return ((db_sym_t)0);
636 }
637 
638 db_sym_t
639 X_db_search_symbol(stab, off, strategy, diffp)
640 	db_symtab_t *stab;
641 	db_addr_t off;
642 	db_strategy_t strategy;
643 	db_expr_t *diffp;
644 {
645 
646 	if (db_symformat != NULL)
647 		return ((*db_symformat->sym_search)(stab, off, strategy,
648 		    diffp));
649 	return ((db_sym_t)0);
650 }
651 
652 void
653 X_db_symbol_values(stab, sym, namep, valuep)
654 	db_symtab_t *stab;
655 	db_sym_t sym;
656 	char **namep;
657 	db_expr_t *valuep;
658 {
659 
660 	if (db_symformat != NULL)
661 		(*db_symformat->sym_value)(stab, sym, namep, valuep);
662 }
663 
664 boolean_t
665 X_db_line_at_pc(stab, cursym, filename, linenum, off)
666 	db_symtab_t *stab;
667 	db_sym_t cursym;
668 	char **filename;
669 	int *linenum;
670 	db_expr_t off;
671 {
672 
673 	if (db_symformat != NULL)
674 		return ((*db_symformat->sym_line_at_pc)(stab, cursym,
675 		    filename, linenum, off));
676 	return (FALSE);
677 }
678 
679 boolean_t
680 X_db_sym_numargs(stab, cursym, nargp, argnamep)
681 	db_symtab_t *stab;
682 	db_sym_t cursym;
683 	int *nargp;
684 	char **argnamep;
685 {
686 
687 	if (db_symformat != NULL)
688 		return ((*db_symformat->sym_numargs)(stab, cursym, nargp,
689 		    argnamep));
690 	return (FALSE);
691 }
692 
693 void
694 X_db_forall(stab, db_forall_func, arg)
695 	db_symtab_t	*stab;
696 	db_forall_func_t db_forall_func;
697 	void *arg;
698 {
699 	if (db_symformat != NULL)
700 		(*db_symformat->sym_forall)(stab, db_forall_func, arg);
701 }
702