db_sym.c revision 1.12 1 /* $NetBSD: db_sym.c,v 1.12 1996/02/05 01:57:15 christos 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 (at) 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
32 #include <machine/db_machdep.h>
33
34 #include <ddb/db_sym.h>
35 #include <ddb/db_output.h>
36 #include <ddb/db_extern.h>
37 #include <ddb/db_command.h>
38
39 /*
40 * Multiple symbol tables
41 */
42 #ifndef MAXLKMS
43 #define MAXLKMS 20
44 #endif
45
46 #ifndef MAXNOSYMTABS
47 #define MAXNOSYMTABS MAXLKMS+1 /* Room for kernel + LKM's */
48 #endif
49
50 db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},};
51
52 db_symtab_t *db_last_symtab;
53
54 static char *db_qualify __P((db_sym_t, char *));
55
56 /*
57 * Add symbol table, with given name, to list of symbol tables.
58 */
59 int
60 db_add_symbol_table(start, end, name, ref)
61 char *start;
62 char *end;
63 char *name;
64 char *ref;
65 {
66 int slot;
67
68 for (slot = 0; slot < MAXNOSYMTABS; slot++) {
69 if (db_symtabs[slot].name == NULL)
70 break;
71 }
72 if (slot >= MAXNOSYMTABS) {
73 db_printf("No slots left for %s symbol table", name);
74 return(-1);
75 }
76
77 db_symtabs[slot].start = start;
78 db_symtabs[slot].end = end;
79 db_symtabs[slot].name = name;
80 db_symtabs[slot].private = ref;
81
82 return(slot);
83 }
84
85 /*
86 * Delete a symbol table. Caller is responsible for freeing storage.
87 */
88 void
89 db_del_symbol_table(name)
90 char *name;
91 {
92 int slot;
93
94 for (slot = 0; slot < MAXNOSYMTABS; slot++) {
95 if (db_symtabs[slot].name &&
96 ! strcmp(db_symtabs[slot].name, name))
97 break;
98 }
99 if (slot >= MAXNOSYMTABS) {
100 db_printf("Unable to find symbol table slot for %s.", name);
101 return;
102 }
103
104 db_symtabs[slot].start = 0;
105 db_symtabs[slot].end = 0;
106 db_symtabs[slot].name = 0;
107 db_symtabs[slot].private = 0;
108 }
109
110 /*
111 * db_qualify("vm_map", "netbsd") returns "netbsd:vm_map".
112 *
113 * Note: return value points to static data whose content is
114 * overwritten by each call... but in practice this seems okay.
115 */
116 static char *
117 db_qualify(sym, symtabname)
118 db_sym_t sym;
119 register char *symtabname;
120 {
121 char *symname;
122 static char tmp[256];
123 register char *s;
124
125 db_symbol_values(sym, &symname, 0);
126 s = tmp;
127 while ((*s++ = *symtabname++) != '\0')
128 ;
129 s[-1] = ':';
130 while ((*s++ = *symname++) != '\0')
131 ;
132 return tmp;
133 }
134
135
136 boolean_t
137 db_eqname(src, dst, c)
138 char *src;
139 char *dst;
140 int c;
141 {
142 if (!strcmp(src, dst))
143 return (TRUE);
144 if (src[0] == c)
145 return (!strcmp(src+1,dst));
146 return (FALSE);
147 }
148
149 boolean_t
150 db_value_of_name(name, valuep)
151 char *name;
152 db_expr_t *valuep;
153 {
154 db_sym_t sym;
155
156 sym = db_lookup(name);
157 if (sym == DB_SYM_NULL)
158 return (FALSE);
159 db_symbol_values(sym, &name, valuep);
160 return (TRUE);
161 }
162
163
164 /*
165 * Lookup a symbol.
166 * If the symbol has a qualifier (e.g., ux:vm_map),
167 * then only the specified symbol table will be searched;
168 * otherwise, all symbol tables will be searched.
169 */
170 db_sym_t
171 db_lookup(symstr)
172 char *symstr;
173 {
174 db_sym_t sp;
175 register int i;
176 int symtab_start = 0;
177 int symtab_end = MAXNOSYMTABS;
178 register char *cp;
179
180 /*
181 * Look for, remove, and remember any symbol table specifier.
182 */
183 for (cp = symstr; *cp; cp++) {
184 if (*cp == ':') {
185 *cp = '\0';
186 for (i = 0; i < MAXNOSYMTABS; i++) {
187 if (db_symtabs[i].name &&
188 ! strcmp(symstr, db_symtabs[i].name)) {
189 symtab_start = i;
190 symtab_end = i + 1;
191 break;
192 }
193 }
194 *cp = ':';
195 if (i == MAXNOSYMTABS) {
196 db_error("invalid symbol table name");
197 /*NOTREACHED*/
198 }
199 symstr = cp+1;
200 }
201 }
202
203 /*
204 * Look in the specified set of symbol tables.
205 * Return on first match.
206 */
207 for (i = symtab_start; i < symtab_end; i++) {
208 if (db_symtabs[i].name &&
209 (sp = X_db_lookup(&db_symtabs[i], symstr))) {
210 db_last_symtab = &db_symtabs[i];
211 return sp;
212 }
213 }
214 return 0;
215 }
216
217 /*
218 * Does this symbol name appear in more than one symbol table?
219 * Used by db_symbol_values to decide whether to qualify a symbol.
220 */
221 boolean_t db_qualify_ambiguous_names = FALSE;
222
223 boolean_t
224 db_symbol_is_ambiguous(sym)
225 db_sym_t sym;
226 {
227 char *sym_name;
228 register int i;
229 register
230 boolean_t found_once = FALSE;
231
232 if (!db_qualify_ambiguous_names)
233 return FALSE;
234
235 db_symbol_values(sym, &sym_name, 0);
236 for (i = 0; i < MAXNOSYMTABS; i++) {
237 if (db_symtabs[i].name &&
238 X_db_lookup(&db_symtabs[i], sym_name)) {
239 if (found_once)
240 return TRUE;
241 found_once = TRUE;
242 }
243 }
244 return FALSE;
245 }
246
247 /*
248 * Find the closest symbol to val, and return its name
249 * and the difference between val and the symbol found.
250 */
251 db_sym_t
252 db_search_symbol( val, strategy, offp)
253 register db_addr_t val;
254 db_strategy_t strategy;
255 db_expr_t *offp;
256 {
257 register
258 unsigned int diff;
259 unsigned int newdiff;
260 register int i;
261 db_sym_t ret = DB_SYM_NULL, sym;
262
263 newdiff = diff = ~0;
264 db_last_symtab = 0;
265 for (i = 0; i < MAXNOSYMTABS; i++) {
266 if (!db_symtabs[i].name)
267 continue;
268 sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
269 if (newdiff < diff) {
270 db_last_symtab = &db_symtabs[i];
271 diff = newdiff;
272 ret = sym;
273 }
274 }
275 *offp = diff;
276 return ret;
277 }
278
279 /*
280 * Return name and value of a symbol
281 */
282 void
283 db_symbol_values(sym, namep, valuep)
284 db_sym_t sym;
285 char **namep;
286 db_expr_t *valuep;
287 {
288 db_expr_t value;
289
290 if (sym == DB_SYM_NULL) {
291 *namep = 0;
292 return;
293 }
294
295 X_db_symbol_values(sym, namep, &value);
296
297 if (db_symbol_is_ambiguous(sym))
298 *namep = db_qualify(sym, db_last_symtab->name);
299 if (valuep)
300 *valuep = value;
301 }
302
303
304 /*
305 * Print a the closest symbol to value
306 *
307 * After matching the symbol according to the given strategy
308 * we print it in the name+offset format, provided the symbol's
309 * value is close enough (eg smaller than db_maxoff).
310 * We also attempt to print [filename:linenum] when applicable
311 * (eg for procedure names).
312 *
313 * If we could not find a reasonable name+offset representation,
314 * then we just print the value in hex. Small values might get
315 * bogus symbol associations, e.g. 3 might get some absolute
316 * value like _INCLUDE_VERSION or something, therefore we do
317 * not accept symbols whose value is zero (and use plain hex).
318 * Also, avoid printing as "end+0x????" which is useless.
319 * The variable db_lastsym is used instead of "end" in case we
320 * add support for symbols in loadable driver modules.
321 */
322 extern char end[];
323 unsigned int db_lastsym = (unsigned long)end;
324 db_expr_t db_maxoff = 0x10000000;
325
326
327 void
328 db_printsym(off, strategy)
329 db_expr_t off;
330 db_strategy_t strategy;
331 {
332 db_expr_t d;
333 char *filename;
334 char *name;
335 db_expr_t value;
336 int linenum;
337 db_sym_t cursym;
338
339 if (off <= db_lastsym) {
340 cursym = db_search_symbol(off, strategy, &d);
341 db_symbol_values(cursym, &name, &value);
342 if (name && (d < db_maxoff) && value) {
343 db_printf("%s", name);
344 if (d)
345 db_printf("+%#r", d);
346 if (strategy == DB_STGY_PROC) {
347 if (db_line_at_pc(cursym, &filename, &linenum, off))
348 db_printf(" [%s:%d]", filename, linenum);
349 }
350 return;
351 }
352 }
353 db_printf("%#n", off);
354 return;
355 }
356
357
358 boolean_t
359 db_line_at_pc( sym, filename, linenum, pc)
360 db_sym_t sym;
361 char **filename;
362 int *linenum;
363 db_expr_t pc;
364 {
365 return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc);
366 }
367
368 int
369 db_sym_numargs(sym, nargp, argnames)
370 db_sym_t sym;
371 int *nargp;
372 char **argnames;
373 {
374 return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames);
375 }
376