xref: /openbsd-src/sys/ddb/db_sym.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: db_sym.c,v 1.32 2006/03/13 06:23:20 jsg Exp $	*/
2 /*	$NetBSD: db_sym.c,v 1.24 2000/08/11 22:50:47 tv Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  */
29 
30 #include <sys/param.h>
31 #include <sys/proc.h>
32 #include <sys/systm.h>
33 
34 #include <machine/db_machdep.h>
35 
36 #include <ddb/db_lex.h>
37 #include <ddb/db_sym.h>
38 #include <ddb/db_output.h>
39 #include <ddb/db_extern.h>
40 #include <ddb/db_command.h>
41 
42 /*
43  * Multiple symbol tables
44  */
45 #ifndef MAXLKMS
46 #define MAXLKMS 20
47 #endif
48 
49 #ifndef MAXNOSYMTABS
50 #define	MAXNOSYMTABS	MAXLKMS+1	/* Room for kernel + LKM's */
51 #endif
52 
53 db_symtab_t	db_symtabs[MAXNOSYMTABS] = {{0,},};
54 
55 db_symtab_t	*db_last_symtab;
56 
57 static db_forall_func_t db_sift;
58 
59 extern char end[];
60 
61 /*
62  * Put the most picky symbol table formats at the top!
63  */
64 const db_symformat_t *db_symformats[] = {
65 #ifdef DB_ELF_SYMBOLS
66 	&db_symformat_elf,
67 #endif
68 #ifdef DB_AOUT_SYMBOLS
69 	&db_symformat_aout,
70 #endif
71 	NULL,
72 };
73 
74 const db_symformat_t *db_symformat;
75 
76 boolean_t	X_db_sym_init(int, void *, void *, const char *);
77 db_sym_t	X_db_lookup(db_symtab_t *, char *);
78 db_sym_t	X_db_search_symbol(db_symtab_t *, db_addr_t,
79 		    db_strategy_t, db_expr_t *);
80 void		X_db_symbol_values(db_symtab_t *, db_sym_t, char **,
81 		    db_expr_t *);
82 boolean_t	X_db_line_at_pc(db_symtab_t *, db_sym_t, char **,
83 		    int *, db_expr_t);
84 int		X_db_sym_numargs(db_symtab_t *, db_sym_t, int *,
85 		    char **);
86 
87 /*
88  * Initialize the kernel debugger by initializing the master symbol
89  * table.  Note that if initializing the master symbol table fails,
90  * no other symbol tables can be loaded.
91  */
92 #if 0
93 void
94 ddb_init(int symsize, void *vss, void *vse)
95 {
96 	const db_symformat_t **symf;
97 	const char *name = "bsd";
98 
99 	if (symsize <= 0) {
100 		printf(" [ no symbols available ]\n");
101 		return;
102 	}
103 
104 	/*
105 	 * Do this check now for the master symbol table to avoid printing
106 	 * the message N times.
107 	 */
108 	if (ALIGNED_POINTER(vss, long) == 0) {
109 		printf("[ %s symbol table has bad start address %p ]\n",
110 		    name, vss);
111 		return;
112 	}
113 
114 	for (symf = db_symformats; *symf != NULL; symf++) {
115 		db_symformat = *symf;
116 		if (X_db_sym_init(symsize, vss, vse, name) == TRUE)
117 			return;
118 	}
119 
120 	db_symformat = NULL;
121 	printf("[ no symbol table formats found ]\n");
122 }
123 #else
124 void
125 ddb_init(void)
126 {
127 	const db_symformat_t **symf;
128 	const char *name = "bsd";
129 	extern char *esym;
130 #if defined(__sparc64__) || defined(__mips__)
131 	extern char *ssym;
132 #endif
133 	char *xssym, *xesym;
134 
135 	xesym = esym;
136 #if defined(__sparc64__) || defined(__mips__)
137 	xssym = ssym;
138 #else
139 	xssym = (char *)&end;
140 #endif
141 	/*
142 	 * Do this check now for the master symbol table to avoid printing
143 	 * the message N times.
144 	 */
145 	if ((((vaddr_t)xssym) & (sizeof(long) - 1)) != 0) {
146 		printf("[ %s symbol table has bad start address %p ]\n",
147 		    name, xssym);
148 		return;
149 	}
150 
151 	if (xesym != NULL && xesym != xssym)
152 		for (symf = db_symformats; *symf != NULL; symf++) {
153 			db_symformat = *symf;
154 			if (X_db_sym_init((vaddr_t)xesym - (vaddr_t)xssym,
155 			    xssym, xesym, name) == TRUE)
156 			return;
157 		}
158 
159 	db_symformat = NULL;
160 	printf("[ no symbol table formats found ]\n");
161 }
162 #endif
163 
164 /*
165  * Add symbol table, with given name, to list of symbol tables.
166  */
167 int
168 db_add_symbol_table(char *start, char *end, const char *name, char *ref)
169 {
170 	int slot;
171 
172 	for (slot = 0; slot < MAXNOSYMTABS; slot++) {
173 		if (db_symtabs[slot].name == NULL)
174 			break;
175 	}
176 	if (slot >= MAXNOSYMTABS) {
177 		db_printf("No slots left for %s symbol table", name);
178 		return(-1);
179 	}
180 
181 	db_symtabs[slot].start = start;
182 	db_symtabs[slot].end = end;
183 	db_symtabs[slot].name = name;
184 	db_symtabs[slot].private = ref;
185 
186 	return(slot);
187 }
188 
189 /*
190  * Delete a symbol table. Caller is responsible for freeing storage.
191  */
192 void
193 db_del_symbol_table(char *name)
194 {
195 	int slot;
196 
197 	for (slot = 0; slot < MAXNOSYMTABS; slot++) {
198 		if (db_symtabs[slot].name &&
199 		    ! strcmp(db_symtabs[slot].name, name))
200 			break;
201 	}
202 	if (slot >= MAXNOSYMTABS) {
203 		db_printf("Unable to find symbol table slot for %s.", name);
204 		return;
205 	}
206 
207 	db_symtabs[slot].start = 0;
208 	db_symtabs[slot].end = 0;
209 	db_symtabs[slot].name = 0;
210 	db_symtabs[slot].private = 0;
211 }
212 
213 /*
214  *  db_qualify("vm_map", "bsd") returns "bsd:vm_map".
215  *
216  *  Note: return value points to static data whose content is
217  *  overwritten by each call... but in practice this seems okay.
218  */
219 char *
220 db_qualify(db_sym_t sym, const char *symtabname)
221 {
222 	char		*symname;
223 	static char     tmp[256];
224 	char	*s;
225 
226 	db_symbol_values(sym, &symname, 0);
227 	s = tmp;
228 	while ((*s++ = *symtabname++) != '\0')
229 		;
230 	s[-1] = ':';
231 	while ((*s++ = *symname++) != '\0')
232 		;
233 	return tmp;
234 }
235 
236 
237 boolean_t
238 db_eqname(char *src, char *dst, int c)
239 {
240 	if (!strcmp(src, dst))
241 	    return (TRUE);
242 	if (src[0] == c)
243 	    return (!strcmp(src+1,dst));
244 	return (FALSE);
245 }
246 
247 boolean_t
248 db_value_of_name(char *name, db_expr_t *valuep)
249 {
250 	db_sym_t	sym;
251 
252 	sym = db_lookup(name);
253 	if (sym == DB_SYM_NULL)
254 	    return (FALSE);
255 	db_symbol_values(sym, &name, valuep);
256 	return (TRUE);
257 }
258 
259 
260 /*
261  * Lookup a symbol.
262  * If the symbol has a qualifier (e.g., ux:vm_map),
263  * then only the specified symbol table will be searched;
264  * otherwise, all symbol tables will be searched.
265  */
266 db_sym_t
267 db_lookup(char *symstr)
268 {
269 	db_sym_t sp;
270 	int i;
271 	int symtab_start = 0;
272 	int symtab_end = MAXNOSYMTABS;
273 	char *cp;
274 
275 	/*
276 	 * Look for, remove, and remember any symbol table specifier.
277 	 */
278 	for (cp = symstr; *cp; cp++) {
279 		if (*cp == ':') {
280 			*cp = '\0';
281 			for (i = 0; i < MAXNOSYMTABS; i++) {
282 				if (db_symtabs[i].name &&
283 				    ! strcmp(symstr, db_symtabs[i].name)) {
284 					symtab_start = i;
285 					symtab_end = i + 1;
286 					break;
287 				}
288 			}
289 			*cp = ':';
290 			if (i == MAXNOSYMTABS) {
291 				db_error("invalid symbol table name");
292 				/*NOTREACHED*/
293 			}
294 			symstr = cp+1;
295 		}
296 	}
297 
298 	/*
299 	 * Look in the specified set of symbol tables.
300 	 * Return on first match.
301 	 */
302 	for (i = symtab_start; i < symtab_end; i++) {
303 		if (db_symtabs[i].name &&
304 		    (sp = X_db_lookup(&db_symtabs[i], symstr))) {
305 			db_last_symtab = &db_symtabs[i];
306 			return sp;
307 		}
308 	}
309 	return 0;
310 }
311 
312 /* Private structure for passing args to db_sift() from db_sifting(). */
313 struct db_sift_args {
314 	char	*symstr;
315 	int	mode;
316 };
317 
318 /*
319  * Does the work of db_sifting(), called once for each
320  * symbol via X_db_forall(), prints out symbols matching
321  * criteria.
322  */
323 static void
324 db_sift(db_symtab_t *stab, db_sym_t sym, char *name, char *suffix, int prefix,
325     void *arg)
326 {
327 	char c, sc;
328 	char *find, *p;
329 	size_t len;
330 	struct db_sift_args *dsa;
331 
332 	dsa = (struct db_sift_args*)arg;
333 
334 	find = dsa->symstr;	/* String we're looking for. */
335 	p = name;		/* String we're searching within. */
336 
337 	/* Matching algorithm cribbed from strstr(), which is not
338 	   in the kernel. */
339 	if ((c = *find++) != 0) {
340 		len = strlen(find);
341 		do {
342 			do {
343 				if ((sc = *p++) == 0)
344 					return;
345 			} while (sc != c);
346 		} while (strncmp(p, find, len) != 0);
347 	}
348 	if (dsa->mode=='F')	/* ala ls -F */
349 		db_printf("%s%s ", name, suffix);
350 	else
351 		db_printf("%s ", name);
352 }
353 
354 /*
355  * "Sift" for a partial symbol.
356  * Named for the Sun OpenPROM command ("sifting").
357  * If the symbol has a qualifier (e.g., ux:vm_map),
358  * then only the specified symbol table will be searched;
359  * otherwise, all symbol tables will be searched..
360  *
361  * "mode" is how-to-display, set from modifiers.
362  */
363 void
364 db_sifting(char *symstr, int mode)
365 {
366 	char *cp;
367 	int i;
368 	int symtab_start = 0;
369 	int symtab_end = MAXNOSYMTABS;
370 	struct db_sift_args dsa;
371 
372 	/*
373 	 * Look for, remove, and remember any symbol table specifier.
374 	 */
375 	for (cp = symstr; *cp; cp++) {
376 		if (*cp == ':') {
377 			*cp = '\0';
378 			for (i = 0; i < MAXNOSYMTABS; i++) {
379 				if (db_symtabs[i].name &&
380 				    ! strcmp(symstr, db_symtabs[i].name)) {
381 					symtab_start = i;
382 					symtab_end = i + 1;
383 					break;
384 				}
385 			}
386 			*cp = ':';
387 			if (i == MAXNOSYMTABS) {
388 				db_error("invalid symbol table name");
389 				/*NOTREACHED*/
390 			}
391 			symstr = cp+1;
392 		}
393 	}
394 
395 	/* Pass args to db_sift(). */
396 	dsa.symstr = symstr;
397 	dsa.mode = mode;
398 
399 	/*
400 	 * Look in the specified set of symbol tables.
401 	 */
402 	for (i = symtab_start; i < symtab_end; i++)
403 		if (db_symtabs[i].name) {
404 			db_printf("Sifting table %s:\n", db_symtabs[i].name);
405 			X_db_forall(&db_symtabs[i], db_sift, &dsa);
406 		}
407 
408 	return;
409 }
410 
411 
412 /*
413  * Does this symbol name appear in more than one symbol table?
414  * Used by db_symbol_values to decide whether to qualify a symbol.
415  */
416 boolean_t db_qualify_ambiguous_names = FALSE;
417 
418 boolean_t
419 db_symbol_is_ambiguous(db_sym_t sym)
420 {
421 	char		*sym_name;
422 	int	i;
423 	boolean_t	found_once = FALSE;
424 
425 	if (!db_qualify_ambiguous_names)
426 		return FALSE;
427 
428 	db_symbol_values(sym, &sym_name, 0);
429 	for (i = 0; i < MAXNOSYMTABS; i++) {
430 		if (db_symtabs[i].name &&
431 		    X_db_lookup(&db_symtabs[i], sym_name)) {
432 			if (found_once)
433 				return TRUE;
434 			found_once = TRUE;
435 		}
436 	}
437 	return FALSE;
438 }
439 
440 /*
441  * Find the closest symbol to val, and return its name
442  * and the difference between val and the symbol found.
443  */
444 db_sym_t
445 db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp)
446 {
447 	unsigned int	diff;
448 	db_expr_t	newdiff;
449 	int		i;
450 	db_sym_t	ret = DB_SYM_NULL, sym;
451 
452 	newdiff = diff = ~0;
453 	db_last_symtab = 0;
454 	for (i = 0; i < MAXNOSYMTABS; i++) {
455 	    if (!db_symtabs[i].name)
456 	        continue;
457 	    sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
458 	    if (newdiff < diff) {
459 		db_last_symtab = &db_symtabs[i];
460 		diff = newdiff;
461 		ret = sym;
462 	    }
463 	}
464 	*offp = diff;
465 	return ret;
466 }
467 
468 /*
469  * Return name and value of a symbol
470  */
471 void
472 db_symbol_values(db_sym_t sym, char **namep, db_expr_t *valuep)
473 {
474 	db_expr_t	value;
475 
476 	if (sym == DB_SYM_NULL) {
477 		*namep = 0;
478 		return;
479 	}
480 
481 	X_db_symbol_values(db_last_symtab, sym, namep, &value);
482 
483 	if (db_symbol_is_ambiguous(sym))
484 		*namep = db_qualify(sym, db_last_symtab->name);
485 	if (valuep)
486 		*valuep = value;
487 }
488 
489 
490 /*
491  * Print a the closest symbol to value
492  *
493  * After matching the symbol according to the given strategy
494  * we print it in the name+offset format, provided the symbol's
495  * value is close enough (eg smaller than db_maxoff).
496  * We also attempt to print [filename:linenum] when applicable
497  * (eg for procedure names).
498  *
499  * If we could not find a reasonable name+offset representation,
500  * then we just print the value in hex.  Small values might get
501  * bogus symbol associations, e.g. 3 might get some absolute
502  * value like _INCLUDE_VERSION or something, therefore we do
503  * not accept symbols whose value is zero (and use plain hex).
504  * Also, avoid printing as "end+0x????" which is useless.
505  * The variable db_lastsym is used instead of "end" in case we
506  * add support for symbols in loadable driver modules.
507  */
508 unsigned long	db_lastsym = (unsigned long)end;
509 unsigned int	db_maxoff = 0x10000000;
510 
511 
512 void
513 db_printsym(db_expr_t off, db_strategy_t strategy,
514     int (*pr)(const char *, ...))
515 {
516 	db_expr_t	d;
517 	char 		*filename;
518 	char		*name;
519 	db_expr_t	value;
520 	int 		linenum;
521 	db_sym_t	cursym;
522 	char		buf[DB_FORMAT_BUF_SIZE];
523 
524 	if (off <= db_lastsym) {
525 		cursym = db_search_symbol(off, strategy, &d);
526 		db_symbol_values(cursym, &name, &value);
527 		if (name && (d < db_maxoff) && value) {
528 			(*pr)("%s", name);
529 			if (d) {
530 				(*pr)("+%s", db_format(buf, sizeof(buf),
531 				    d, DB_FORMAT_R, 1, 0));
532 			}
533 			if (strategy == DB_STGY_PROC) {
534 				if (db_line_at_pc(cursym, &filename, &linenum, off))
535 					(*pr)(" [%s:%d]", filename, linenum);
536 			}
537 			return;
538 		}
539 	}
540 
541 	(*pr)("%s", db_format(buf, sizeof(buf), off, DB_FORMAT_N, 1, 0));
542 	return;
543 }
544 
545 
546 boolean_t
547 db_line_at_pc(db_sym_t sym, char **filename, int *linenum, db_expr_t pc)
548 {
549 	return X_db_line_at_pc(db_last_symtab, sym, filename, linenum, pc);
550 }
551 
552 int
553 db_sym_numargs(db_sym_t sym, int *nargp, char **argnames)
554 {
555 	return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames);
556 }
557 
558 boolean_t
559 X_db_sym_init(int symsize, void *vss, void *vse, const char *name)
560 {
561 
562 	if (db_symformat != NULL)
563 		return ((*db_symformat->sym_init)(symsize, vss, vse, name));
564 	return (FALSE);
565 }
566 
567 db_sym_t
568 X_db_lookup(db_symtab_t *stab, char *symstr)
569 {
570 
571 	if (db_symformat != NULL)
572 		return ((*db_symformat->sym_lookup)(stab, symstr));
573 	return ((db_sym_t)0);
574 }
575 
576 db_sym_t
577 X_db_search_symbol(db_symtab_t *stab, db_addr_t off, db_strategy_t strategy,
578     db_expr_t *diffp)
579 {
580 
581 	if (db_symformat != NULL)
582 		return ((*db_symformat->sym_search)(stab, off, strategy,
583 		    diffp));
584 	return ((db_sym_t)0);
585 }
586 
587 void
588 X_db_symbol_values(db_symtab_t *stab, db_sym_t sym, char **namep,
589     db_expr_t *valuep)
590 {
591 
592 	if (db_symformat != NULL)
593 		(*db_symformat->sym_value)(stab, sym, namep, valuep);
594 }
595 
596 boolean_t
597 X_db_line_at_pc(db_symtab_t *stab, db_sym_t cursym, char **filename,
598     int *linenum, db_expr_t off)
599 {
600 
601 	if (db_symformat != NULL)
602 		return ((*db_symformat->sym_line_at_pc)(stab, cursym,
603 		    filename, linenum, off));
604 	return (FALSE);
605 }
606 
607 boolean_t
608 X_db_sym_numargs(db_symtab_t *stab, db_sym_t cursym, int *nargp,
609     char **argnamep)
610 {
611 
612 	if (db_symformat != NULL)
613 		return ((*db_symformat->sym_numargs)(stab, cursym, nargp,
614 		    argnamep));
615 	return (FALSE);
616 }
617 
618 void
619 X_db_forall(db_symtab_t *stab, db_forall_func_t db_forall_func, void *arg)
620 {
621 	if (db_symformat != NULL)
622 		(*db_symformat->sym_forall)(stab, db_forall_func, arg);
623 }
624