1 /* $NetBSD: db_sym.c,v 1.58 2008/11/30 18:21:36 martin Exp $ */
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
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 $");
33 #include "opt_ddbparam.h"
36 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/ksyms.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
;
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.
63 ddb_init(int symsize
, void *vss
, void *vse
)
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;
73 ksyms_addsyms_elf(symsize
, vss
, vse
); /* Will complain if necessary */
75 db_symformat
= &db_symformat_elf
;
76 if ((*db_symformat
->sym_init
)(symsize
, vss
, vse
, TBLNAME
) == true) {
77 using_aout_symtab
= true;
84 db_eqname(const char *src
, const char *dst
, int c
)
87 if (!strcmp(src
, dst
))
90 return (!strcmp(src
+1,dst
));
95 db_value_of_name(const char *name
, db_expr_t
*valuep
)
104 #ifdef DB_AOUT_SYMBOLS
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
)
115 db_symbol_values(ssym
, &name
, valuep
);
119 (void)strlcpy(symbol
, name
, sizeof(symbol
));
120 db_symsplit(symbol
, &mod
, &sym
);
122 if (ksyms_getval_unlocked(mod
, sym
, &uval
, KSYMS_EXTERN
) == 0) {
124 *valuep
= (db_expr_t
)val
;
127 if (ksyms_getval_unlocked(mod
, sym
, &uval
, KSYMS_ANY
) == 0) {
129 *valuep
= (db_expr_t
)val
;
136 #ifdef DB_AOUT_SYMBOLS
137 /* Private structure for passing args to db_sift() from db_sifting(). */
138 struct db_sift_args
{
144 * Does the work of db_sifting(), called once for each
145 * symbol via db_forall(), prints out symbols matching
149 db_sift(db_symtab_t
*stab
, db_sym_t sym
, char *name
,
150 char *suffix
, int prefix
, void *arg
)
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
164 if ((c
= *find
++) != 0) {
168 if ((sc
= *p
++) == 0)
171 } while (strncmp(p
, find
, len
) != 0);
173 if (dsa
->mode
=='F') /* ala ls -F */
174 db_printf("%s%s ", name
, suffix
);
176 db_printf("%s ", name
);
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.
190 db_sifting(char *symstr
, int mode
)
196 #ifdef DB_AOUT_SYMBOLS
197 struct db_sift_args dsa
;
199 if (using_aout_symtab
) {
202 (*db_symformat
->sym_forall
)(NULL
, db_sift
, &dsa
);
209 db_symsplit(symstr
, &mod
, &sym
);
210 if (ksyms_sift(mod
, sym
, mode
) == ENODEV
)
211 db_error("invalid symbol table name");
216 * Find the closest symbol to val, and return its name
217 * and the difference between val and the symbol found.
220 db_search_symbol(db_addr_t val
, db_strategy_t strategy
, db_expr_t
*offp
)
223 db_sym_t ret
= DB_SYM_NULL
;
230 #ifdef DB_AOUT_SYMBOLS
234 if (using_aout_symtab
) {
236 ssym
= (*db_symformat
->sym_search
)
237 (NULL
, val
, strategy
, &newdiff
);
238 if ((unsigned int) newdiff
< diff
) {
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
;
260 * Return name and value of a symbol
263 db_symbol_values(db_sym_t sym
, const char **namep
, db_expr_t
*valuep
)
269 if (sym
== DB_SYM_NULL
) {
274 #ifdef DB_AOUT_SYMBOLS
275 if (using_aout_symtab
) {
277 (*db_symformat
->sym_value
)(NULL
, sym
, namep
, &value
);
285 if (ksyms_getname(&mod
, namep
, (vaddr_t
)sym
,
286 KSYMS_ANY
|KSYMS_EXACT
) == 0) {
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.
314 unsigned long db_lastsym
= (unsigned long)end
;
315 unsigned int db_maxoff
= 0x100000;
318 db_symstr(char *buf
, size_t buflen
, db_expr_t off
, db_strategy_t strategy
)
326 #ifdef DB_AOUT_SYMBOLS
327 if (using_aout_symtab
) {
334 if ((unsigned long) off
<= db_lastsym
) {
335 cursym
= db_search_symbol(off
, strategy
, &d
);
336 db_symbol_values(cursym
, &name
, &value
);
338 ((unsigned int) d
< db_maxoff
) &&
340 strlcpy(buf
, name
, buflen
);
342 strlcat(buf
, "+", buflen
);
343 db_format_radix(buf
+strlen(buf
),
346 if (strategy
== DB_STGY_PROC
) {
347 if ((*db_symformat
->sym_line_at_pc
)
348 (NULL
, cursym
, &filename
,
350 snprintf(buf
+ strlen(buf
),
351 buflen
- strlen(buf
),
358 strlcpy(buf
, db_num_to_str(off
), buflen
);
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
);
369 strlcat(buf
, "+", buflen
);
370 db_format_radix(buf
+strlen(buf
),
371 24, off
- val
, true);
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
);
384 strlcpy(buf
, db_num_to_str(off
), buflen
);
389 db_printsym(db_expr_t off
, db_strategy_t strategy
,
390 void (*pr
)(const char *, ...))
403 #ifdef DB_AOUT_SYMBOLS
404 if (using_aout_symtab
) {
410 if ((unsigned long) off
<= db_lastsym
) {
411 cursym
= db_search_symbol(off
, strategy
, &d
);
412 db_symbol_values(cursym
, &name
, &value
);
414 ((unsigned int) d
< db_maxoff
) &&
420 db_format_radix(tbuf
, 24, d
, true);
423 if (strategy
== DB_STGY_PROC
) {
424 if ((*db_symformat
->sym_line_at_pc
)
425 (NULL
, cursym
, &filename
,
433 (*pr
)(db_num_to_str(off
));
438 if (ksyms_getname(&mod
, &name
, (vaddr_t
)off
,
439 strategy
|KSYMS_CLOSEST
) == 0) {
440 (void)ksyms_getval_unlocked(mod
, name
, &uval
, KSYMS_ANY
);
442 if (((off
- val
) < db_maxoff
) && val
) {
443 (*pr
)("%s:%s", mod
, name
);
447 db_format_radix(tbuf
, 24, off
- val
, true);
451 if (strategy
& KSYMS_PROC
) {
452 if (ksyms_fmaddr(off
, &filename
, &linenum
) == 0)
453 (*pr
)(" [%s:%d]", filename
, linenum
);
460 (*pr
)(db_num_to_str(off
));
465 * Splits a string in the form "mod:sym" to two strings.
468 db_symsplit(char *str
, char **mod
, char **sym
)
472 if ((cp
= strchr(str
, ':')) != NULL
) {
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
,