FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_sym.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_sym.c,v $
29 * Revision 2.18 93/11/17 16:25:12 dbg
30 * Added ANSI function prototypes.
31 * [93/10/11 dbg]
32 *
33 * Revision 2.17 93/03/09 10:53:50 danner
34 * String protos.
35 * [93/03/07 af]
36 *
37 * Revision 2.16 93/01/14 17:25:45 danner
38 * Handle multiple, coexisting symbol table types.
39 * 64bit cleanup.
40 * [92/11/30 af]
41 *
42 * Check for null db_last_symtab in db_line_at_pc.
43 * [92/10/06 jvh]
44 *
45 * Revision 2.15 92/08/03 17:32:03 jfriedl
46 * removed silly prototypes
47 * [92/08/02 jfriedl]
48 *
49 * Revision 2.14 92/05/21 17:07:47 jfriedl
50 * Cleanup to quiet gcc warnings.
51 * Changed CHAR arg of db_eqname to UNSIGNED.
52 * Made arg types proper for db_line_at_pc().
53 * [92/05/16 jfriedl]
54 *
55 * Revision 2.13 92/05/05 11:05:16 danner
56 * typo correction
57 *
58 * Revision 2.12 92/05/05 10:52:16 danner
59 * Bulletproof db_search_in_task_symbol against symbol tables that return
60 * success and huge offsets for address outside of their domain.
61 *
62 * Revision 2.11 92/05/04 13:48:25 danner
63 * Rewrote db_search_task_symbol to deal more reasonably
64 * with overlapping user and kernel address ranges.
65 * [92/03/23 15:03:21 danner]
66 * Complete rewrite of db_search_task_symbol logic to deal
67 * gracefully with the case of overlapping user and kernel address
68 * space.
69 * [92/03/21 danner]
70 * Upped MAXNOSYMTABS from 3 to 5. Now there is space for kernel,
71 * bootstrap, server, and emulator symbols - plus one for future
72 * expansion.
73 * [92/03/21 danner]
74 *
75 * Revision 2.10 91/10/09 16:02:30 af
76 * Changed symbol table name qualification syntax from "xxx:yyy"
77 * to "xxx::yyy" to allow "file:func:line" in "yyy" part.
78 * "db_sym_parse_and_lookup" is also added for "yyy" part parsing.
79 * Replaced db_search_symbol with db_search_task_symbol, and moved
80 * it to "db_sym.h" as a macro.
81 * Added db_task_printsym, and changed db_printsym to call it.
82 * Added include "db_task_thread.h".
83 * Fixed infinite recursion of db_symbol_values.
84 * [91/08/29 tak]
85 *
86 * Revision 2.9 91/07/31 17:31:14 dbg
87 * Add task pointer and space for string storage to symbol table
88 * descriptor.
89 * [91/07/31 dbg]
90 *
91 * Revision 2.8 91/07/09 23:16:08 danner
92 * Changed a printf.
93 * [91/07/08 danner]
94 *
95 * Revision 2.7 91/05/14 15:35:54 mrt
96 * Correcting copyright
97 *
98 * Revision 2.6 91/03/16 14:42:40 rpd
99 * Changed the default db_maxoff to 4K.
100 * [91/03/10 rpd]
101 *
102 * Revision 2.5 91/02/05 17:07:07 mrt
103 * Changed to new Mach copyright
104 * [91/01/31 16:19:17 mrt]
105 *
106 * Revision 2.4 90/10/25 14:44:05 rwd
107 * Changed db_printsym to print unsigned.
108 * [90/10/19 rpd]
109 *
110 * Revision 2.3 90/09/09 23:19:56 rpd
111 * Avoid totally incorrect guesses of symbol names for small values.
112 * [90/08/30 17:39:48 af]
113 *
114 * Revision 2.2 90/08/27 21:52:18 dbg
115 * Removed nlist.h. Fixed some type declarations.
116 * Qualifier character is ':'.
117 * [90/08/20 dbg]
118 * Modularized symtab info into a new db_symtab_t type.
119 * Modified db_add_symbol_table and others accordingly.
120 * Defined db_sym_t, a new (opaque) type used to represent
121 * symbols. This should support all sort of future symtable
122 * formats. Functions like db_qualify take a db_sym_t now.
123 * New db_symbol_values() function to explode the content
124 * of a db_sym_t.
125 * db_search_symbol() replaces db_find_sym_and_offset(), which is
126 * now a macro defined in our (new) header file. This new
127 * function accepts more restrictive searches, which are
128 * entirely delegated to the symtab-specific code.
129 * Accordingly, db_printsym() accepts a strategy parameter.
130 * New db_line_at_pc() function.
131 * Renamed misleading db_eqsym into db_eqname.
132 * [90/08/20 10:47:06 af]
133 *
134 * Created.
135 * [90/07/25 dbg]
136 *
137 * Revision 2.1 90/07/26 16:43:52 dbg
138 * Created.
139 *
140 */
141 /*
142 * Author: David B. Golub, Carnegie Mellon University
143 * Date: 7/90
144 */
145
146 #include <mach/std_types.h>
147 #include <kern/strings.h>
148 #include <machine/db_machdep.h>
149 #include <ddb/db_sym.h>
150 #include <ddb/db_task_thread.h>
151 #include <ddb/db_command.h>
152 #include <ddb/db_output.h>
153
154 #include <vm/vm_map.h> /* vm_map_t */
155
156 /*
157 * Multiple symbol tables
158 */
159 #define MAXNOSYMTABS 5 /* mach, bootstrap, ux, emulator, 1 spare */
160
161 db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},};
162 int db_nsymtab = 0;
163
164 db_symtab_t *db_last_symtab;
165
166 db_sym_t db_lookup(char *symstr); /* forward */
167
168 /*
169 * Add symbol table, with given name, to list of symbol tables.
170 */
171 boolean_t
172 db_add_symbol_table(
173 int type,
174 char *start,
175 char *end,
176 char *name,
177 char *ref,
178 char *map_pointer)
179 {
180 register db_symtab_t *st;
181 extern vm_map_t kernel_map;
182
183 if (db_nsymtab >= MAXNOSYMTABS)
184 return FALSE;
185
186 st = &db_symtabs[db_nsymtab];
187 st->type = type;
188 st->start = start;
189 st->end = end;
190 st->private = ref;
191 st->map_pointer = (map_pointer == (char *)kernel_map)? 0: map_pointer;
192 strcpy(st->name, name);
193
194 db_nsymtab++;
195
196 return TRUE;
197 }
198
199 /*
200 * db_qualify("vm_map", "ux") returns "ux::vm_map".
201 *
202 * Note: return value points to static data whose content is
203 * overwritten by each call... but in practice this seems okay.
204 */
205 static char *
206 db_qualify(
207 char *symname,
208 register char *symtabname)
209 {
210 static char tmp[256];
211 register char *s;
212
213 s = tmp;
214 while ((*s++ = *symtabname++) != '\0')
215 continue;
216 s[-1] = ':';
217 *s++ = ':';
218 while ((*s++ = *symname++) != '\0')
219 continue;
220 return tmp;
221 }
222
223
224 boolean_t
225 db_eqname( char* src, char* dst, char c )
226 {
227 if (!strcmp(src, dst))
228 return TRUE;
229 if (src[0] == c)
230 return !strcmp(src+1,dst);
231 return FALSE;
232 }
233
234 boolean_t
235 db_value_of_name(
236 char *name,
237 db_expr_t *valuep)
238 {
239 db_sym_t sym;
240
241 sym = db_lookup(name);
242 if (sym == DB_SYM_NULL)
243 return FALSE;
244 db_symbol_values(0, sym, &name, valuep);
245 return TRUE;
246 }
247
248 /*
249 * Lookup a symbol.
250 * If the symbol has a qualifier (e.g., ux::vm_map),
251 * then only the specified symbol table will be searched;
252 * otherwise, all symbol tables will be searched.
253 */
254 db_sym_t
255 db_lookup(
256 char *symstr)
257 {
258 db_sym_t sp;
259 register int i;
260 int symtab_start = 0;
261 int symtab_end = db_nsymtab;
262 register char *cp;
263
264 /*
265 * Look for, remove, and remember any symbol table specifier.
266 */
267 for (cp = symstr; *cp; cp++) {
268 if (*cp == ':' && cp[1] == ':') {
269 *cp = '\0';
270 for (i = 0; i < db_nsymtab; i++) {
271 if (! strcmp(symstr, db_symtabs[i].name)) {
272 symtab_start = i;
273 symtab_end = i + 1;
274 break;
275 }
276 }
277 *cp = ':';
278 if (i == db_nsymtab)
279 db_error("Invalid symbol table name\n");
280 symstr = cp+2;
281 }
282 }
283
284 /*
285 * Look in the specified set of symbol tables.
286 * Return on first match.
287 */
288 for (i = symtab_start; i < symtab_end; i++) {
289 if ((sp = X_db_lookup(&db_symtabs[i], symstr)) != 0) {
290 db_last_symtab = &db_symtabs[i];
291 return sp;
292 }
293 }
294 return 0;
295 }
296
297 /*
298 * Common utility routine to parse a symbol string into a file
299 * name, a symbol name and line number.
300 * This routine is called from X_db_lookup if the object dependent
301 * handler supports qualified search with a file name or a line number.
302 * It parses the symbol string, and call an object dependent routine
303 * with parsed file name, symbol name and line number.
304 */
305 db_sym_t
306 db_sym_parse_and_lookup(
307 db_sym_t (*func)(
308 db_symtab_t *symtab,
309 char *file_name,
310 char *sym_name,
311 int line_number),
312 db_symtab_t *symtab,
313 char *symstr)
314 {
315 register char * p;
316 register int n;
317 int n_name;
318 int line_number;
319 char *file_name = 0;
320 char *sym_name = 0;
321 char *component[3];
322 db_sym_t found = DB_SYM_NULL;
323
324 /*
325 * disassemble the symbol into components:
326 * [file_name:]symbol[:line_nubmer]
327 */
328 component[0] = symstr;
329 component[1] = component[2] = 0;
330 for (p = symstr, n = 1; *p; p++) {
331 if (*p == ':') {
332 if (n >= 3)
333 break;
334 *p = 0;
335 component[n++] = p+1;
336 }
337 }
338 if (*p != 0)
339 goto out;
340 line_number = 0;
341 n_name = n;
342 p = component[n-1];
343 if (*p >= '' && *p <= '9') {
344 if (n == 1)
345 goto out;
346 for (line_number = 0; *p; p++) {
347 if (*p < '' || *p > '9')
348 goto out;
349 line_number = line_number*10 + *p - '';
350 }
351 n_name--;
352 } else if (n >= 3)
353 goto out;
354 if (n_name == 1) {
355 for (p = component[0]; *p && *p != '.'; p++);
356 if (*p == '.') {
357 file_name = component[0];
358 sym_name = 0;
359 } else {
360 file_name = 0;
361 sym_name = component[0];
362 }
363 } else {
364 file_name = component[0];
365 sym_name = component[1];
366 }
367 found = func(symtab, file_name, sym_name, line_number);
368
369 out:
370 while (--n >= 1)
371 component[n][-1] = ':';
372 return found;
373 }
374
375 /*
376 * Does this symbol name appear in more than one symbol table?
377 * Used by db_symbol_values to decide whether to qualify a symbol.
378 */
379 boolean_t db_qualify_ambiguous_names = FALSE;
380
381 boolean_t
382 db_name_is_ambiguous(
383 char *sym_name)
384 {
385 register int i;
386 register
387 boolean_t found_once = FALSE;
388
389 if (!db_qualify_ambiguous_names)
390 return FALSE;
391
392 for (i = 0; i < db_nsymtab; i++) {
393 if (X_db_lookup(&db_symtabs[i], sym_name)) {
394 if (found_once)
395 return TRUE;
396 found_once = TRUE;
397 }
398 }
399 return FALSE;
400 }
401
402
403 db_sym_t
404 db_search_in_task_symbol(
405 register db_addr_t val,
406 db_strategy_t strategy,
407 db_addr_t *offp,
408 task_t task); /* forward */
409
410 /*
411 * Find the closest symbol to val, and return its name
412 * and the difference between val and the symbol found.
413 *
414 * Logic change. If the task argument is non NULL and a
415 * matching symbol is found in a symbol table which explictly
416 * specifies its map to be task->map, that symbol will have
417 * precedence over any symbol from a symbol table will a null
418 * map. This allows overlapping kernel/user maps to work correctly.
419 *
420 */
421 db_sym_t
422 db_search_task_symbol(
423 register db_addr_t val,
424 db_strategy_t strategy,
425 db_addr_t *offp, /* better be unsigned */
426 task_t task)
427 {
428 db_sym_t ret;
429
430 if (task != TASK_NULL)
431 ret = db_search_in_task_symbol(val, strategy, offp, task);
432 else
433 {
434 ret = db_search_in_task_symbol(val, strategy, offp, task);
435 /*
436 db_search_in_task_symbol will return success with
437 a very large offset when it should have failed.
438 */
439 if (ret == DB_SYM_NULL || (*offp) > 0x1000000)
440 {
441 task = db_current_task();
442 ret = db_search_in_task_symbol(val, strategy, offp, task);
443 }
444 }
445
446 return ret;
447 }
448
449 db_sym_t
450 db_search_in_task_symbol(
451 register db_addr_t val,
452 db_strategy_t strategy,
453 db_addr_t *offp,
454 task_t task)
455 {
456 register vm_size_t diff;
457 vm_size_t newdiff;
458 register int i;
459 db_symtab_t *sp;
460 db_sym_t ret = DB_SYM_NULL, sym;
461 vm_map_t map_for_val;
462
463 map_for_val = (task == TASK_NULL)? VM_MAP_NULL: task->map;
464 newdiff = diff = ~0;
465 db_last_symtab = (db_symtab_t *) 0;
466 for (sp = &db_symtabs[0], i = 0; i < db_nsymtab; sp++, i++)
467 {
468 newdiff = ~0;
469 if ((vm_map_t)sp->map_pointer == VM_MAP_NULL ||
470 (vm_map_t)sp->map_pointer == map_for_val)
471 {
472 sym = X_db_search_symbol(sp, val, strategy, (db_expr_t*)&newdiff);
473 if (sym == DB_SYM_NULL)
474 continue;
475 if (db_last_symtab == (db_symtab_t *) 0)
476 { /* first hit */
477 db_last_symtab = sp;
478 diff = newdiff;
479 ret = sym;
480 continue;
481 }
482 if ((vm_map_t) sp->map_pointer == VM_MAP_NULL &&
483 (vm_map_t) db_last_symtab->map_pointer == VM_MAP_NULL &&
484 newdiff < diff )
485 { /* closer null map match */
486 db_last_symtab = sp;
487 diff = newdiff;
488 ret = sym;
489 continue;
490 }
491 if ((vm_map_t) sp->map_pointer != VM_MAP_NULL &&
492 (newdiff < 0x100000) &&
493 ((vm_map_t) db_last_symtab->map_pointer == VM_MAP_NULL ||
494 newdiff < diff ))
495 {
496 /*
497 * update if new is in matching map and symbol is "close",
498 * and
499 * old is VM_MAP_NULL or old in is matching map
500 * but is further away
501 */
502 db_last_symtab = sp;
503 diff = newdiff;
504 ret = sym;
505 continue;
506 }
507 }
508 }
509
510 *offp = diff;
511 return ret;
512 }
513
514 /*
515 * Return name and value of a symbol
516 */
517 void
518 db_symbol_values(
519 db_symtab_t *stab,
520 db_sym_t sym,
521 char **namep,
522 db_expr_t *valuep)
523 {
524 db_expr_t value;
525 char *name;
526
527 if (sym == DB_SYM_NULL) {
528 *namep = 0;
529 return;
530 }
531 if (stab == 0)
532 stab = db_last_symtab;
533
534 X_db_symbol_values(stab, sym, &name, &value);
535
536 if (db_name_is_ambiguous(name))
537 *namep = db_qualify(name, db_last_symtab->name);
538 else
539 *namep = name;
540 if (valuep)
541 *valuep = value;
542 }
543
544
545 /*
546 * Print the closest symbol to value
547 *
548 * After matching the symbol according to the given strategy
549 * we print it in the name+offset format, provided the symbol's
550 * value is close enough (eg smaller than db_maxoff).
551 * We also attempt to print [filename:linenum] when applicable
552 * (eg for procedure names).
553 *
554 * If we could not find a reasonable name+offset representation,
555 * then we just print the value in hex. Small values might get
556 * bogus symbol associations, e.g. 3 might get some absolute
557 * value like _INCLUDE_VERSION or something, therefore we do
558 * not accept symbols whose value is zero (and use plain hex).
559 */
560
561 unsigned int db_maxoff = 0x4000;
562
563 void
564 db_task_printsym(
565 db_expr_t off,
566 db_strategy_t strategy,
567 task_t task)
568 {
569 db_addr_t d;
570 char *filename;
571 char *name;
572 db_expr_t value;
573 int linenum;
574 db_sym_t cursym;
575
576 cursym = db_search_task_symbol(off, strategy, &d, task);
577 db_symbol_values(0, cursym, &name, &value);
578 if (name == 0 || d >= db_maxoff || value == 0) {
579 db_printf("%#n", off);
580 return;
581 }
582 db_printf("%s", name);
583 if (d)
584 db_printf("+0x%x", d);
585 if (strategy == DB_STGY_PROC) {
586 if (db_line_at_pc(cursym, &filename, &linenum, off)) {
587 db_printf(" [%s", filename);
588 if (linenum > 0)
589 db_printf(":%d", linenum);
590 db_printf("]");
591 }
592 }
593 }
594
595 void
596 db_printsym(
597 db_expr_t off,
598 db_strategy_t strategy)
599 {
600 db_task_printsym(off, strategy, TASK_NULL);
601 }
602
603 boolean_t
604 db_line_at_pc(
605 db_sym_t sym,
606 char **filename,
607 int *linenum,
608 db_expr_t pc)
609 {
610 return (db_last_symtab) ?
611 X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc) :
612 FALSE;
613 }
614
615 /*
616 * Switch into symbol-table specific routines
617 */
618
619 #ifdef DB_NO_AOUT
620 #else
621 extern boolean_t aout_db_sym_init(), aout_db_line_at_pc();
622 extern db_sym_t aout_db_lookup(), aout_db_search_symbol();
623 extern void aout_db_symbol_values();
624 #endif /* DB_NO_AOUT */
625
626 #ifdef DB_NO_COFF
627 #else
628 extern boolean_t coff_db_sym_init(), coff_db_line_at_pc();
629 extern db_sym_t coff_db_lookup(), coff_db_search_symbol();
630 extern void coff_db_symbol_values();
631 #endif /* DB_NO_COFF */
632
633 struct db_sym_switch x_db[] = {
634
635 /* BSD a.out format (really, sdb/dbx(1) symtabs) */
636 #ifdef DB_NO_AOUT
637 { 0,},
638 #else /* DB_NO_AOUT */
639 { aout_db_sym_init, aout_db_lookup, aout_db_search_symbol,
640 aout_db_line_at_pc, aout_db_symbol_values },
641 #endif /* DB_NO_AOUT */
642
643 #ifdef DB_NO_COFF
644 { 0,},
645 #else /* DB_NO_COFF */
646 { coff_db_sym_init, coff_db_lookup, coff_db_search_symbol,
647 coff_db_line_at_pc, coff_db_symbol_values },
648 #endif /* DB_NO_COFF */
649
650 /* Machdep, not inited here */
651 { 0,}
652
653 };
Cache object: 36b09d773dedbb4ea967023f6751e058
|