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