xref: /openbsd/sys/ddb/db_sym.c (revision 949c1c4e)
1 /*	$OpenBSD: db_sym.c,v 1.57 2024/11/07 16:02:29 miod 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/systm.h>
32 
33 #include <machine/db_machdep.h>
34 
35 #include <ddb/db_lex.h>
36 #include <ddb/db_sym.h>
37 #include <ddb/db_output.h>
38 #include <ddb/db_command.h>
39 
40 extern char end[];
41 
42 /*
43  * Initialize the kernel debugger by initializing the master symbol
44  * table.  Note that if initializing the master symbol table fails,
45  * no other symbol tables can be loaded.
46  */
47 void
ddb_init(void)48 ddb_init(void)
49 {
50 	const char *name = "bsd";
51 	extern char *esym;
52 #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) || \
53     defined(__i386__)
54 	extern char *ssym;
55 #endif
56 	char *xssym, *xesym;
57 
58 	xesym = esym;
59 #if defined(__sparc64__) || defined(__mips__) || defined(__amd64__) || \
60     defined(__i386__)
61 	xssym = ssym;
62 #else
63 	xssym = (char *)&end;
64 #endif
65 	/*
66 	 * Do this check now for the master symbol table to avoid printing
67 	 * the message N times.
68 	 */
69 	if ((((vaddr_t)xssym) & (sizeof(long) - 1)) != 0) {
70 		printf("[ %s symbol table has bad start address %p ]\n",
71 		    name, xssym);
72 		return;
73 	}
74 
75 	if (xesym != NULL && xesym != xssym) {
76 		if (db_elf_sym_init((vaddr_t)xesym - (vaddr_t)xssym, xssym,
77 		    xesym, name) == 1)
78 			return;
79 	}
80 
81 	printf("[ no symbol table formats found ]\n");
82 }
83 
84 int
db_eqname(const char * src,const char * dst,int c)85 db_eqname(const char *src, const char *dst, int c)
86 {
87 	if (!strcmp(src, dst))
88 		return (1);
89 	if (src[0] == c)
90 		return (!strcmp(src+1,dst));
91 	return (0);
92 }
93 
94 /*
95  * Find the closest symbol to val, and return its name
96  * and the difference between val and the symbol found.
97  */
98 Elf_Sym *
db_search_symbol(vaddr_t val,db_strategy_t strategy,db_expr_t * offp)99 db_search_symbol(vaddr_t val, db_strategy_t strategy, db_expr_t *offp)
100 {
101 	unsigned int	diff;
102 	db_expr_t	newdiff;
103 	Elf_Sym		*ret = NULL, *sym;
104 
105 	newdiff = diff = ~0;
106 	sym = db_elf_sym_search(val, strategy, &newdiff);
107 	if (newdiff < diff) {
108 		diff = newdiff;
109 		ret = sym;
110 	}
111 	*offp = diff;
112 	return ret;
113 }
114 
115 /*
116  * Print the closest symbol to a value.
117  *
118  * After matching the symbol according to the given strategy
119  * we print it in the name+offset format, provided the symbol's
120  * value is close enough (eg smaller than db_maxoff).
121  * We also attempt to print [filename:linenum] when applicable
122  * (eg for procedure names).
123  *
124  * If we could not find a reasonable name+offset representation,
125  * then we just print the value in hex.  Small values might get
126  * bogus symbol associations, e.g. 3 might get some absolute
127  * value like _INCLUDE_VERSION or something, therefore we do
128  * not accept symbols whose value is zero (and use plain hex).
129  * Also, avoid printing as "end+0x????" which is useless.
130  * The variable db_lastsym is used instead of "end" in case we
131  * add support for symbols in loadable driver modules.
132  */
133 unsigned long	db_lastsym = (unsigned long)end;
134 unsigned int	db_maxoff = 0x10000000;
135 
136 
137 void
db_printsym(db_expr_t off,db_strategy_t strategy,int (* pr)(const char *,...))138 db_printsym(db_expr_t off, db_strategy_t strategy,
139     int (*pr)(const char *, ...))
140 {
141 	db_expr_t	d;
142 	const char	*filename;
143 	const char	*name;
144 	db_expr_t	value;
145 	int		linenum;
146 	Elf_Sym		*cursym;
147 	char		buf[DB_FORMAT_BUF_SIZE];
148 
149 	if (off <= db_lastsym) {
150 		cursym = db_search_symbol(off, strategy, &d);
151 		db_symbol_values(cursym, &name, &value);
152 		if (name && (d < db_maxoff) && value) {
153 			(*pr)("%s", name);
154 			if (d) {
155 				(*pr)("+%s", db_format(buf, sizeof(buf),
156 				    d, DB_FORMAT_R, 1, 0));
157 			}
158 			if (strategy == DB_STGY_PROC) {
159 				if (db_elf_line_at_pc(cursym, &filename,
160 				    &linenum, off))
161 					(*pr)(" [%s:%d]", filename, linenum);
162 			}
163 			return;
164 		}
165 	}
166 
167 	(*pr)("%s", db_format(buf, sizeof(buf), off, DB_FORMAT_N, 1, 0));
168 	return;
169 }
170