xref: /netbsd/sys/ddb/db_sym.c (revision bf9ec67e)
1 /*	$NetBSD: db_sym.c,v 1.31 2002/02/15 07:33:52 simonb 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.31 2002/02/15 07:33:52 simonb 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 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