Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / ddb / db_sym.c
blobc764fdf28e6960bedcbcd5baca6f95b6e98a1f5d
1 /* $NetBSD: db_sym.c,v 1.58 2008/11/30 18:21:36 martin Exp $ */
3 /*
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
6 * All Rights Reserved.
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.
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.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: db_sym.c,v 1.58 2008/11/30 18:21:36 martin Exp $");
32 #ifdef _KERNEL_OPT
33 #include "opt_ddbparam.h"
34 #endif
36 #include <sys/param.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 #include <sys/ksyms.h>
41 #include <ddb/ddb.h>
43 static void db_symsplit(char *, char **, char **);
46 #ifdef DB_AOUT_SYMBOLS
47 #define TBLNAME "netbsd"
49 static int using_aout_symtab;
50 const db_symformat_t *db_symformat;
51 static db_forall_func_t db_sift;
52 extern db_symformat_t db_symformat_aout;
53 extern db_symformat_t db_symformat_elf;
54 #endif
58 * Initialize the kernel debugger by initializing the master symbol
59 * table. Note that if initializing the master symbol table fails,
60 * no other symbol tables can be loaded.
62 void
63 ddb_init(int symsize, void *vss, void *vse)
65 #ifdef _KERNEL
66 # ifdef DB_AOUT_SYMBOLS
67 db_symformat = &db_symformat_aout;
68 if ((*db_symformat->sym_init)(symsize, vss, vse, TBLNAME) == true) {
69 using_aout_symtab = true;
70 return;
72 # endif
73 ksyms_addsyms_elf(symsize, vss, vse); /* Will complain if necessary */
74 #else /* _KERNEL */
75 db_symformat = &db_symformat_elf;
76 if ((*db_symformat->sym_init)(symsize, vss, vse, TBLNAME) == true) {
77 using_aout_symtab = true;
78 return;
80 #endif /* _KERNEL */
83 bool
84 db_eqname(const char *src, const char *dst, int c)
87 if (!strcmp(src, dst))
88 return (true);
89 if (src[0] == c)
90 return (!strcmp(src+1,dst));
91 return (false);
94 bool
95 db_value_of_name(const char *name, db_expr_t *valuep)
97 char symbol[128];
98 char *mod, *sym;
99 #ifdef _KERNEL
100 unsigned long uval;
101 long val;
102 #endif
104 #ifdef DB_AOUT_SYMBOLS
105 db_sym_t ssym;
107 if (using_aout_symtab) {
109 * Cannot load symtabs in a.out kernels, so the ':'
110 * style of selecting modules is irrelevant.
112 ssym = (*db_symformat->sym_lookup)(NULL, name);
113 if (ssym == DB_SYM_NULL)
114 return (false);
115 db_symbol_values(ssym, &name, valuep);
116 return (true);
118 #endif
119 (void)strlcpy(symbol, name, sizeof(symbol));
120 db_symsplit(symbol, &mod, &sym);
121 #ifdef _KERNEL
122 if (ksyms_getval_unlocked(mod, sym, &uval, KSYMS_EXTERN) == 0) {
123 val = (long) uval;
124 *valuep = (db_expr_t)val;
125 return true;
127 if (ksyms_getval_unlocked(mod, sym, &uval, KSYMS_ANY) == 0) {
128 val = (long) uval;
129 *valuep = (db_expr_t)val;
130 return true;
132 #endif
133 return false;
136 #ifdef DB_AOUT_SYMBOLS
137 /* Private structure for passing args to db_sift() from db_sifting(). */
138 struct db_sift_args {
139 char *symstr;
140 int mode;
144 * Does the work of db_sifting(), called once for each
145 * symbol via db_forall(), prints out symbols matching
146 * criteria.
148 static void
149 db_sift(db_symtab_t *stab, db_sym_t sym, char *name,
150 char *suffix, int prefix, void *arg)
152 char c, sc;
153 char *find, *p;
154 size_t len;
155 struct db_sift_args *dsa;
157 dsa = (struct db_sift_args*)arg;
159 find = dsa->symstr; /* String we're looking for. */
160 p = name; /* String we're searching within. */
162 /* Matching algorithm cribbed from strstr(), which is not
163 in the kernel. */
164 if ((c = *find++) != 0) {
165 len = strlen(find);
166 do {
167 do {
168 if ((sc = *p++) == 0)
169 return;
170 } while (sc != c);
171 } while (strncmp(p, find, len) != 0);
173 if (dsa->mode=='F') /* ala ls -F */
174 db_printf("%s%s ", name, suffix);
175 else
176 db_printf("%s ", name);
178 #endif
181 * "Sift" for a partial symbol.
182 * Named for the Sun OpenPROM command ("sifting").
183 * If the symbol has a qualifier (e.g., ux:vm_map),
184 * then only the specified symbol table will be searched;
185 * otherwise, all symbol tables will be searched..
187 * "mode" is how-to-display, set from modifiers.
189 void
190 db_sifting(char *symstr, int mode)
192 #ifdef _KERNEL
193 char *mod, *sym;
194 #endif
196 #ifdef DB_AOUT_SYMBOLS
197 struct db_sift_args dsa;
199 if (using_aout_symtab) {
200 dsa.symstr = symstr;
201 dsa.mode = mode;
202 (*db_symformat->sym_forall)(NULL, db_sift, &dsa);
203 db_printf("\n");
204 return;
206 #endif
208 #ifdef _KERNEL
209 db_symsplit(symstr, &mod, &sym);
210 if (ksyms_sift(mod, sym, mode) == ENODEV)
211 db_error("invalid symbol table name");
212 #endif
216 * Find the closest symbol to val, and return its name
217 * and the difference between val and the symbol found.
219 db_sym_t
220 db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp)
222 unsigned int diff;
223 db_sym_t ret = DB_SYM_NULL;
224 #ifdef _KERNEL
225 unsigned long naddr;
226 const char *mod;
227 const char *sym;
228 #endif
230 #ifdef DB_AOUT_SYMBOLS
231 db_expr_t newdiff;
232 db_sym_t ssym;
234 if (using_aout_symtab) {
235 newdiff = diff = ~0;
236 ssym = (*db_symformat->sym_search)
237 (NULL, val, strategy, &newdiff);
238 if ((unsigned int) newdiff < diff) {
239 diff = newdiff;
240 ret = ssym;
242 *offp = diff;
243 return ret;
245 #endif
247 #ifdef _KERNEL
248 if (ksyms_getname(&mod, &sym, (vaddr_t)val, strategy) == 0) {
249 (void)ksyms_getval_unlocked(mod, sym, &naddr, KSYMS_ANY);
250 diff = val - (db_addr_t)naddr;
251 ret = (db_sym_t)naddr;
252 } else
253 #endif
254 diff = 0;
255 *offp = diff;
256 return ret;
260 * Return name and value of a symbol
262 void
263 db_symbol_values(db_sym_t sym, const char **namep, db_expr_t *valuep)
265 #ifdef _KERNEL
266 const char *mod;
267 #endif
269 if (sym == DB_SYM_NULL) {
270 *namep = 0;
271 return;
274 #ifdef DB_AOUT_SYMBOLS
275 if (using_aout_symtab) {
276 db_expr_t value;
277 (*db_symformat->sym_value)(NULL, sym, namep, &value);
278 if (valuep)
279 *valuep = value;
280 return;
282 #endif
284 #ifdef _KERNEL
285 if (ksyms_getname(&mod, namep, (vaddr_t)sym,
286 KSYMS_ANY|KSYMS_EXACT) == 0) {
287 if (valuep)
288 *valuep = sym;
289 } else
290 #endif
291 *namep = NULL;
296 * Print a the closest symbol to value
298 * After matching the symbol according to the given strategy
299 * we print it in the name+offset format, provided the symbol's
300 * value is close enough (eg smaller than db_maxoff).
301 * We also attempt to print [filename:linenum] when applicable
302 * (eg for procedure names).
304 * If we could not find a reasonable name+offset representation,
305 * then we just print the value in hex. Small values might get
306 * bogus symbol associations, e.g. 3 might get some absolute
307 * value like _INCLUDE_VERSION or something, therefore we do
308 * not accept symbols whose value is zero (and use plain hex).
309 * Also, avoid printing as "end+0x????" which is useless.
310 * The variable db_lastsym is used instead of "end" in case we
311 * add support for symbols in loadable driver modules.
313 extern char end[];
314 unsigned long db_lastsym = (unsigned long)end;
315 unsigned int db_maxoff = 0x100000;
317 void
318 db_symstr(char *buf, size_t buflen, db_expr_t off, db_strategy_t strategy)
320 const char *name;
321 #ifdef _KERNEL
322 const char *mod;
323 unsigned long val;
324 #endif
326 #ifdef DB_AOUT_SYMBOLS
327 if (using_aout_symtab) {
328 db_expr_t d;
329 char *filename;
330 db_expr_t value;
331 int linenum;
332 db_sym_t cursym;
334 if ((unsigned long) off <= db_lastsym) {
335 cursym = db_search_symbol(off, strategy, &d);
336 db_symbol_values(cursym, &name, &value);
337 if (name != NULL &&
338 ((unsigned int) d < db_maxoff) &&
339 value != 0) {
340 strlcpy(buf, name, buflen);
341 if (d) {
342 strlcat(buf, "+", buflen);
343 db_format_radix(buf+strlen(buf),
344 24, d, true);
346 if (strategy == DB_STGY_PROC) {
347 if ((*db_symformat->sym_line_at_pc)
348 (NULL, cursym, &filename,
349 &linenum, off))
350 snprintf(buf + strlen(buf),
351 buflen - strlen(buf),
352 " [%s:%d]",
353 filename, linenum);
355 return;
358 strlcpy(buf, db_num_to_str(off), buflen);
359 return;
361 #endif
362 #ifdef _KERNEL
363 if (ksyms_getname(&mod, &name, (vaddr_t)off,
364 strategy|KSYMS_CLOSEST) == 0) {
365 (void)ksyms_getval_unlocked(mod, name, &val, KSYMS_ANY);
366 if (((off - val) < db_maxoff) && val) {
367 snprintf(buf, buflen, "%s:%s", mod, name);
368 if (off - val) {
369 strlcat(buf, "+", buflen);
370 db_format_radix(buf+strlen(buf),
371 24, off - val, true);
373 #ifdef notyet
374 if (strategy & KSYMS_PROC) {
375 if (ksyms_fmaddr(off, &filename, &linenum) == 0)
376 snprintf(buf + strlen(buf),
377 buflen - strlen(buf),
378 " [%s:%d]", filename, linenum);
380 #endif
381 return;
384 strlcpy(buf, db_num_to_str(off), buflen);
385 #endif
388 void
389 db_printsym(db_expr_t off, db_strategy_t strategy,
390 void (*pr)(const char *, ...))
392 const char *name;
393 #ifdef _KERNEL
394 const char *mod;
395 unsigned long uval;
396 long val;
397 #endif
398 #ifdef notyet
399 char *filename;
400 int linenum;
401 #endif
403 #ifdef DB_AOUT_SYMBOLS
404 if (using_aout_symtab) {
405 db_expr_t d;
406 char *filename;
407 db_expr_t value;
408 int linenum;
409 db_sym_t cursym;
410 if ((unsigned long) off <= db_lastsym) {
411 cursym = db_search_symbol(off, strategy, &d);
412 db_symbol_values(cursym, &name, &value);
413 if (name != NULL &&
414 ((unsigned int) d < db_maxoff) &&
415 value != 0) {
416 (*pr)("%s", name);
417 if (d) {
418 char tbuf[24];
420 db_format_radix(tbuf, 24, d, true);
421 (*pr)("+%s", tbuf);
423 if (strategy == DB_STGY_PROC) {
424 if ((*db_symformat->sym_line_at_pc)
425 (NULL, cursym, &filename,
426 &linenum, off))
427 (*pr)(" [%s:%d]",
428 filename, linenum);
430 return;
433 (*pr)(db_num_to_str(off));
434 return;
436 #endif
437 #ifdef _KERNEL
438 if (ksyms_getname(&mod, &name, (vaddr_t)off,
439 strategy|KSYMS_CLOSEST) == 0) {
440 (void)ksyms_getval_unlocked(mod, name, &uval, KSYMS_ANY);
441 val = (long) uval;
442 if (((off - val) < db_maxoff) && val) {
443 (*pr)("%s:%s", mod, name);
444 if (off - val) {
445 char tbuf[24];
447 db_format_radix(tbuf, 24, off - val, true);
448 (*pr)("+%s", tbuf);
450 #ifdef notyet
451 if (strategy & KSYMS_PROC) {
452 if (ksyms_fmaddr(off, &filename, &linenum) == 0)
453 (*pr)(" [%s:%d]", filename, linenum);
455 #endif
456 return;
459 #endif
460 (*pr)(db_num_to_str(off));
461 return;
465 * Splits a string in the form "mod:sym" to two strings.
467 static void
468 db_symsplit(char *str, char **mod, char **sym)
470 char *cp;
472 if ((cp = strchr(str, ':')) != NULL) {
473 *cp++ = '\0';
474 *mod = str;
475 *sym = cp;
476 } else {
477 *mod = NULL;
478 *sym = str;
482 bool
483 db_sym_numargs(db_sym_t cursym, int *nargp, char **argnamep)
485 #ifdef DB_AOUT_SYMBOLS
486 if (using_aout_symtab)
487 return ((*db_symformat->sym_numargs)(NULL, cursym, nargp,
488 argnamep));
489 #endif
490 return (false);