db_sym.c revision 1.37 1 /* $NetBSD: db_sym.c,v 1.37 2003/04/25 20:30:58 ragge 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 (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/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: db_sym.c,v 1.37 2003/04/25 20:30:58 ragge Exp $");
31
32 #include "opt_ddbparam.h"
33
34 #include <sys/param.h>
35 #include <sys/proc.h>
36 #include <sys/systm.h>
37 #include <sys/ksyms.h>
38
39 #include <machine/db_machdep.h>
40
41 #include <ddb/db_lex.h>
42 #include <ddb/db_sym.h>
43 #include <ddb/db_output.h>
44 #include <ddb/db_extern.h>
45 #include <ddb/db_command.h>
46
47 static void db_symsplit(char *, char **, char **);
48
49
50 #ifdef DB_AOUT_SYMBOLS
51 #define TBLNAME "netbsd"
52
53 static int using_aout_symtab;
54 const db_symformat_t *db_symformat;
55 static db_forall_func_t db_sift;
56 extern db_symformat_t db_symformat_aout;
57 #endif
58
59
60 /*
61 * Initialize the kernel debugger by initializing the master symbol
62 * table. Note that if initializing the master symbol table fails,
63 * no other symbol tables can be loaded.
64 */
65 void
66 ddb_init(int symsize, void *vss, void *vse)
67 {
68 #ifdef DB_AOUT_SYMBOLS
69 db_symformat = &db_symformat_aout;
70 if ((*db_symformat->sym_init)(symsize, vss, vse, TBLNAME) == TRUE) {
71 using_aout_symtab = TRUE;
72 return;
73 }
74 #endif
75 ksyms_init(symsize, vss, vse); /* Will complain if necessary */
76 }
77
78 boolean_t
79 db_eqname(char *src, char *dst, int c)
80 {
81
82 if (!strcmp(src, dst))
83 return (TRUE);
84 if (src[0] == c)
85 return (!strcmp(src+1,dst));
86 return (FALSE);
87 }
88
89 boolean_t
90 db_value_of_name(char *name, db_expr_t *valuep)
91 {
92 char *mod, *sym;
93
94 #ifdef DB_AOUT_SYMBOLS
95 db_sym_t ssym;
96
97 if (using_aout_symtab) {
98 /*
99 * Cannot load symtabs in a.out kernels, so the ':'
100 * style of selecting modules is irrelevant.
101 */
102 ssym = (*db_symformat->sym_lookup)(NULL, name);
103 if (ssym == DB_SYM_NULL)
104 return (FALSE);
105 db_symbol_values(ssym, &name, valuep);
106 return (TRUE);
107 }
108 #endif
109 db_symsplit(name, &mod, &sym);
110 if (ksyms_getval(mod, sym, valuep, KSYMS_EXTERN) == 0)
111 return TRUE;
112 if (ksyms_getval(mod, sym, valuep, KSYMS_ANY) == 0)
113 return TRUE;
114 return FALSE;
115 }
116
117 #ifdef DB_AOUT_SYMBOLS
118 /* Private structure for passing args to db_sift() from db_sifting(). */
119 struct db_sift_args {
120 char *symstr;
121 int mode;
122 };
123
124 /*
125 * Does the work of db_sifting(), called once for each
126 * symbol via db_forall(), prints out symbols matching
127 * criteria.
128 */
129 static void
130 db_sift(db_symtab_t *stab, db_sym_t sym, char *name, char *suffix, int prefix,
131 void *arg)
132 {
133 char c, sc;
134 char *find, *p;
135 size_t len;
136 struct db_sift_args *dsa;
137
138 dsa = (struct db_sift_args*)arg;
139
140 find = dsa->symstr; /* String we're looking for. */
141 p = name; /* String we're searching within. */
142
143 /* Matching algorithm cribbed from strstr(), which is not
144 in the kernel. */
145 if ((c = *find++) != 0) {
146 len = strlen(find);
147 do {
148 do {
149 if ((sc = *p++) == 0)
150 return;
151 } while (sc != c);
152 } while (strncmp(p, find, len) != 0);
153 }
154 if (dsa->mode=='F') /* ala ls -F */
155 db_printf("%s%s ", name, suffix);
156 else
157 db_printf("%s ", name);
158 }
159 #endif
160
161 /*
162 * "Sift" for a partial symbol.
163 * Named for the Sun OpenPROM command ("sifting").
164 * If the symbol has a qualifier (e.g., ux:vm_map),
165 * then only the specified symbol table will be searched;
166 * otherwise, all symbol tables will be searched..
167 *
168 * "mode" is how-to-display, set from modifiers.
169 */
170 void
171 db_sifting(char *symstr, int mode)
172 {
173 char *mod, *sym;
174
175 #ifdef DB_AOUT_SYMBOLS
176 struct db_sift_args dsa;
177
178 if (using_aout_symtab) {
179 dsa.symstr = symstr;
180 dsa.mode = mode;
181 (*db_symformat->sym_forall)(NULL, db_sift, &dsa);
182 db_printf("\n");
183 return;
184 }
185 #endif
186
187 db_symsplit(symstr, &mod, &sym);
188 if (ksyms_sift(mod, sym, mode) == ENODEV)
189 db_error("invalid symbol table name");
190 }
191
192 /*
193 * Find the closest symbol to val, and return its name
194 * and the difference between val and the symbol found.
195 */
196 db_sym_t
197 db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp)
198 {
199 unsigned int diff;
200 db_sym_t ret = DB_SYM_NULL;
201 db_addr_t naddr;
202 char *mod, *sym;
203
204 #ifdef DB_AOUT_SYMBOLS
205 db_expr_t newdiff;
206 db_sym_t ssym;
207
208 if (using_aout_symtab) {
209 newdiff = diff = ~0;
210 ssym = (*db_symformat->sym_search)
211 (NULL, val, strategy, &newdiff);
212 if ((unsigned int) newdiff < diff) {
213 diff = newdiff;
214 ret = ssym;
215 }
216 *offp = diff;
217 return ret;
218 }
219 #endif
220
221 if (ksyms_getname(&mod, &sym, val, strategy) == 0) {
222 (void)ksyms_getval(mod, sym, &naddr, KSYMS_ANY);
223 diff = val - naddr;
224 ret = naddr;
225 }
226 *offp = diff;
227 return ret;
228 }
229
230 /*
231 * Return name and value of a symbol
232 */
233 void
234 db_symbol_values(db_sym_t sym, char **namep, db_expr_t *valuep)
235 {
236 char *mod;
237
238 if (sym == DB_SYM_NULL) {
239 *namep = 0;
240 return;
241 }
242
243 #ifdef DB_AOUT_SYMBOLS
244 if (using_aout_symtab) {
245 db_expr_t value;
246 (*db_symformat->sym_value)(NULL, sym, namep, &value);
247 if (valuep)
248 *valuep = value;
249 return;
250 }
251 #endif
252
253 if (ksyms_getname(&mod, namep, sym, KSYMS_ANY|KSYMS_EXACT) == 0) {
254 if (valuep)
255 *valuep = sym;
256 } else
257 *namep = NULL;
258 }
259
260
261 /*
262 * Print a the closest symbol to value
263 *
264 * After matching the symbol according to the given strategy
265 * we print it in the name+offset format, provided the symbol's
266 * value is close enough (eg smaller than db_maxoff).
267 * We also attempt to print [filename:linenum] when applicable
268 * (eg for procedure names).
269 *
270 * If we could not find a reasonable name+offset representation,
271 * then we just print the value in hex. Small values might get
272 * bogus symbol associations, e.g. 3 might get some absolute
273 * value like _INCLUDE_VERSION or something, therefore we do
274 * not accept symbols whose value is zero (and use plain hex).
275 * Also, avoid printing as "end+0x????" which is useless.
276 * The variable db_lastsym is used instead of "end" in case we
277 * add support for symbols in loadable driver modules.
278 */
279 extern char end[];
280 unsigned long db_lastsym = (unsigned long)end;
281 unsigned int db_maxoff = 0x10000000;
282
283 #if 0
284 void
285 db_symstr(char *buf, db_expr_t off, db_strategy_t strategy)
286 {
287 db_expr_t d;
288 char *filename;
289 char *name;
290 db_expr_t value;
291 int linenum;
292 db_sym_t cursym;
293
294 if ((unsigned long) off <= db_lastsym) {
295 cursym = db_search_symbol(off, strategy, &d);
296 db_symbol_values(cursym, &name, &value);
297 if (name != NULL &&
298 ((unsigned int) d < db_maxoff) &&
299 value != 0) {
300 strcpy(buf, name);
301 if (d) {
302 strcat(buf, "+");
303 db_format_radix(buf+strlen(buf), 24, d, TRUE);
304 }
305 if (strategy == DB_STGY_PROC) {
306 if (db_line_at_pc(cursym, &filename, &linenum,
307 off))
308 sprintf(buf+strlen(buf),
309 " [%s:%d]", filename, linenum);
310 }
311 return;
312 }
313 }
314 strcpy(buf, db_num_to_str(off));
315 return;
316 }
317 #endif
318
319 void
320 db_printsym(db_expr_t off, db_strategy_t strategy,
321 void (*pr)(const char *, ...))
322 {
323 char *name, *mod;
324 long val;
325 #ifdef notyet
326 char *filename;
327 int linenum;
328 #endif
329
330 #ifdef DB_AOUT_SYMBOLS
331 if (using_aout_symtab) {
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 if ((unsigned long) off <= db_lastsym) {
339 cursym = db_search_symbol(off, strategy, &d);
340 db_symbol_values(cursym, &name, &value);
341 if (name != NULL &&
342 ((unsigned int) d < db_maxoff) &&
343 value != 0) {
344 (*pr)("%s", name);
345 if (d) {
346 char tbuf[24];
347
348 db_format_radix(tbuf, 24, d, TRUE);
349 (*pr)("+%s", tbuf);
350 }
351 if (strategy == DB_STGY_PROC) {
352 if ((*db_symformat->sym_line_at_pc)
353 (NULL, cursym, &filename,
354 &linenum, off))
355 (*pr)(" [%s:%d]",
356 filename, linenum);
357 }
358 return;
359 }
360 }
361 (*pr)(db_num_to_str(off));
362 return;
363 }
364 #endif
365 if (ksyms_getname(&mod, &name, off, strategy|KSYMS_CLOSEST) == 0) {
366 (void)ksyms_getval(mod, name, &val, KSYMS_ANY);
367 if (((off - val) < db_maxoff) && val) {
368 (*pr)("%s:%s", mod, name);
369 if (off - val) {
370 char tbuf[24];
371
372 db_format_radix(tbuf, 24, off - val, TRUE);
373 (*pr)("+%s", tbuf);
374 }
375 #ifdef notyet
376 if (strategy & KSYMS_PROC) {
377 if (ksyms_fmaddr(off, &filename, &linenum) == 0)
378 (*pr)(" [%s:%d]", filename, linenum);
379 }
380 #endif
381 return;
382 }
383 }
384 (*pr)(db_num_to_str(off));
385 return;
386 }
387
388 /*
389 * Splits a string in the form "mod:sym" to two strings.
390 */
391 static void
392 db_symsplit(char *str, char **mod, char **sym)
393 {
394 char *cp;
395
396 if ((cp = strchr(str, ':')) != NULL) {
397 *cp++ = '\0';
398 *mod = str;
399 *sym = cp;
400 } else {
401 *mod = NULL;
402 *sym = str;
403 }
404 }
405
406 boolean_t
407 db_sym_numargs(db_sym_t cursym, int *nargp, char **argnamep)
408 {
409 #ifdef DB_AOUT_SYMBOLS
410 if (using_aout_symtab)
411 return ((*db_symformat->sym_numargs)(NULL, cursym, nargp,
412 argnamep));
413 #endif
414 return (FALSE);
415 }
416
417