FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_aout.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_aout.c,v $
29 * Revision 2.16 93/11/17 16:19:36 dbg
30 * ANSI-fied.
31 * [93/10/13 dbg]
32 *
33 * Revision 2.15 93/03/09 10:53:19 danner
34 * Make searching slightly less confusing if the symtab has not
35 * been xstripped.
36 * [93/03/05 af]
37 *
38 * Revision 2.14 93/02/01 09:55:09 danner
39 * aout_db_search_by_addr returns boolean_t.
40 * [93/01/25 jfriedl]
41 *
42 * Revision 2.13 93/01/14 17:24:24 danner
43 * Support for coexhistance of multiple symbol table types.
44 * 64bit cleanup.
45 * [92/11/30 af]
46 *
47 * Revision 2.12 92/08/03 17:30:27 jfriedl
48 * removed silly prototypes
49 * [92/08/02 jfriedl]
50 *
51 * Revision 2.11 92/05/21 17:06:15 jfriedl
52 * Added init for func_diff and line_diff in X_db_search_by_addr().
53 * Also added proper declaration for that function.
54 * [92/05/16 jfriedl]
55 *
56 * Revision 2.10 92/01/03 20:02:21 dbg
57 * Don't print 'preserving symbols' if loading symbol table fails.
58 * [91/11/29 dbg]
59 *
60 * Use kern_sym_start, kern_sym_size to locate kernel symbol table.
61 * Rename routine to ddb_init.
62 * [91/10/30 dbg]
63 *
64 * Revision 2.9 91/10/09 15:57:16 af
65 * Supported address lookup with line number.
66 * Changed X_db_line_at_pc to get file name without compiled
67 * with -g option.
68 * Included "stab.h" for symbol type definitions.
69 * [91/08/29 tak]
70 *
71 * Revision 2.8 91/08/28 11:10:58 jsb
72 * Added line number support, via X_db_line_at_pc.
73 * [91/08/13 18:12:37 jsb]
74 *
75 * Revision 2.7 91/07/31 17:29:43 dbg
76 * Removed read_symtab_from_file.
77 * Added task argument to X_db_sym_init.
78 * [91/07/30 16:42:51 dbg]
79 *
80 * Revision 2.6 91/07/09 23:15:35 danner
81 * On luna, kdb_init needs to be called ddb_init. Add ifndef
82 * DB_SYMBOLS_PRELOADED for machines that use a.out format but
83 * whose prom loaders load generously load the symbol table.
84 * [91/07/08 danner]
85 *
86 * Revision 2.5 91/05/14 15:32:00 mrt
87 * Correcting copyright
88 *
89 * Revision 2.4 91/03/16 14:42:23 rpd
90 * Updated for new kmem_alloc interface.
91 * [91/03/03 rpd]
92 *
93 * Revision 2.3 91/02/05 17:05:55 mrt
94 * Changed to new Mach copyright
95 * [91/01/31 16:16:44 mrt]
96 *
97 * Revision 2.2 90/08/27 21:48:35 dbg
98 * Created.
99 * [90/08/17 dbg]
100 *
101 */
102 /*
103 * Author: David B. Golub, Carnegie Mellon University
104 * Date: 7/90
105 */
106 /*
107 * Symbol table routines for a.out format files.
108 */
109
110 #include <mach/std_types.h>
111 #include <machine/db_machdep.h> /* data types */
112 #include <ddb/db_sym.h>
113 #include <ddb/db_output.h>
114
115 #ifndef DB_NO_AOUT
116
117 #include <ddb/nlist.h> /* a.out symbol table */
118 #include <ddb/stab.h>
119
120 #define private static
121
122 /*
123 * An a.out symbol table as loaded into the kernel debugger:
124 *
125 * symtab -> size of symbol entries, in bytes
126 * sp -> first symbol entry
127 * ...
128 * ep -> last symbol entry + 1
129 * strtab == start of string table
130 * size of string table in bytes,
131 * including this word
132 * -> strings
133 */
134
135 /*
136 * Find pointers to the start and end of the symbol entries,
137 * given a pointer to the start of the symbol table.
138 */
139 #define db_get_aout_symtab(symtab, sp, ep) \
140 (sp = (struct nlist *)((vm_offset_t *)(symtab) + 1), \
141 ep = (struct nlist *)((char *)sp + *((int*)symtab)))
142
143 boolean_t
144 aout_db_sym_init(
145 char * symtab, /* pointer to start of symbol table */
146 char * esymtab, /* pointer to end of string table,
147 for checking - may be rounded up to
148 integer boundary */
149 char * name,
150 char * task_addr) /* use for this task only */
151 {
152 register struct nlist *sym_start, *sym_end;
153 register struct nlist *sp;
154 register char * strtab;
155 register int strlen;
156 char * estrtab;
157
158 db_get_aout_symtab(symtab, sym_start, sym_end);
159
160 strtab = (char *)sym_end;
161 strlen = *(int *)strtab;
162 estrtab = strtab + strlen;
163
164 #define round_to_size(x) \
165 (((vm_offset_t)(x) + sizeof(vm_size_t) - 1) & ~(sizeof(vm_size_t) - 1))
166
167 if (round_to_size(estrtab) != round_to_size(esymtab)) {
168 db_printf("[ %s symbol table not valid ]\n", name);
169 return FALSE;
170 }
171
172 #undef round_to_size
173
174 for (sp = sym_start; sp < sym_end; sp++) {
175 register long strx;
176 strx = sp->n_un.n_strx;
177 if (strx != 0) {
178 if (strx > strlen) {
179 db_printf("Bad string table index (%#x)\n", strx);
180 sp->n_un.n_name = 0;
181 continue;
182 }
183 sp->n_un.n_name = strtab + strx;
184 }
185 }
186
187 if (db_add_symbol_table(SYMTAB_AOUT,
188 (char *)sym_start,
189 (char *)sym_end,
190 name,
191 symtab,
192 task_addr))
193 {
194 /* Successfully added symbol table */
195 db_printf("[ preserving %d bytes of %s symbol table ]\n",
196 esymtab - (char *)symtab, name);
197 return TRUE;
198 }
199 else
200 return FALSE;
201 }
202
203 /*
204 * check file name or not (check xxxx.x pattern)
205 */
206 private boolean_t
207 aout_db_is_filename(
208 register char *name)
209 {
210 while (*name) {
211 if (*name == '.') {
212 if (name[1])
213 return TRUE;
214 }
215 name++;
216 }
217 return FALSE;
218 }
219
220 /*
221 * special name comparison routine with a name in the symbol table entry
222 */
223 private boolean_t
224 aout_db_eq_name(
225 struct nlist *sp,
226 char *name)
227 {
228 register char *s1, *s2;
229
230 s1 = sp->n_un.n_name;
231 s2 = name;
232 if (*s1 == '_' && *s2 && *s2 != '_')
233 s1++;
234 while (*s2) {
235 if (*s1++ != *s2++) {
236 /*
237 * check .c .o file name comparison case
238 */
239 if (*s2 == 0 && sp->n_un.n_name <= s1 - 2
240 && s1[-2] == '.' && s1[-1] == 'o')
241 return TRUE;
242 return FALSE;
243 }
244 }
245 /*
246 * do special check for
247 * xxx:yyy for N_FUN
248 * xxx.ttt for N_DATA and N_BSS
249 */
250 return (*s1 == 0 || (*s1 == ':' && sp->n_type == N_FUN) ||
251 (*s1 == '.' && (sp->n_type == N_DATA || sp->n_type == N_BSS)));
252 }
253
254 /*
255 * search a symbol table with name and type
256 * fp(in,out): last found text file name symbol entry
257 */
258 private struct nlist *
259 aout_db_search_name(
260 register struct nlist *sp,
261 struct nlist *ep,
262 char *name,
263 int type,
264 struct nlist **fp)
265 {
266 struct nlist *file_sp = *fp;
267 struct nlist *found_sp = 0;
268
269 for ( ; sp < ep; sp++) {
270 if (sp->n_type == N_TEXT && aout_db_is_filename(sp->n_un.n_name))
271 *fp = sp;
272 if (type) {
273 if (sp->n_type == type) {
274 if (aout_db_eq_name(sp, name))
275 return sp;
276 }
277 if (sp->n_type == N_SO)
278 *fp = sp;
279 continue;
280 }
281 if (sp->n_type & N_STAB)
282 continue;
283 if (sp->n_un.n_name && aout_db_eq_name(sp, name)) {
284 /*
285 * In case of qaulified search by a file,
286 * return it immediately with some check.
287 * Otherwise, search external one
288 */
289 if (file_sp) {
290 if ((file_sp == *fp) || (sp->n_type & N_EXT))
291 return sp;
292 } else if (sp->n_type & N_EXT)
293 return sp;
294 else
295 found_sp = sp;
296 }
297 }
298 return found_sp;
299 }
300
301 /*
302 * search a symbol with file, func and line qualification
303 */
304 private db_sym_t
305 aout_db_qualified_search(
306 db_symtab_t *stab,
307 char *file,
308 char *sym,
309 int line)
310 {
311 register struct nlist *sp = (struct nlist *)stab->start;
312 struct nlist *ep = (struct nlist *)stab->end;
313 struct nlist *fp = 0;
314 struct nlist *found_sp;
315 unsigned long func_top;
316 boolean_t in_file;
317
318 if (file == 0 && sym == 0)
319 return 0;
320 if (file) {
321 if ((sp = aout_db_search_name(sp, ep, file, N_TEXT, &fp)) == 0)
322 return 0;
323 }
324 if (sym) {
325 sp = aout_db_search_name(sp, ep, sym, (line > 0)? N_FUN: 0, &fp);
326 if (sp == 0)
327 return 0;
328 }
329 if (line > 0) {
330 if (file && !aout_db_eq_name(fp, file))
331 return 0;
332 found_sp = 0;
333 if (sp->n_type == N_FUN) {
334 /*
335 * qualified by function name
336 * search backward because line number entries
337 * for the function are above it in this case.
338 */
339 func_top = sp->n_value;
340 for (sp--; sp >= (struct nlist *)stab->start; sp--) {
341 if (sp->n_type != N_SLINE)
342 continue;
343 if (sp->n_value < func_top)
344 break;
345 if (sp->n_desc <= line) {
346 if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
347 found_sp = sp;
348 if (sp->n_desc == line)
349 break;
350 }
351 }
352 if (sp->n_type != N_SLINE || sp->n_value < func_top)
353 return 0;
354 } else {
355 /*
356 * qualified by only file name
357 * search forward in this case
358 */
359 in_file = TRUE;
360 for (sp++; sp < ep; sp++) {
361 if (sp->n_type == N_TEXT
362 && aout_db_is_filename(sp->n_un.n_name))
363 break; /* enter into another file */
364 if (sp->n_type == N_SOL) {
365 in_file = aout_db_eq_name(sp, file);
366 continue;
367 }
368 if (!in_file || sp->n_type != N_SLINE)
369 continue;
370 if (sp->n_desc <= line) {
371 if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
372 found_sp = sp;
373 if (sp->n_desc == line)
374 break;
375 }
376 }
377 }
378 sp = found_sp;
379 }
380 return (db_sym_t) sp;
381 }
382
383 /*
384 * lookup symbol by name
385 */
386 db_sym_t
387 aout_db_lookup(
388 db_symtab_t *stab,
389 char * symstr)
390 {
391 return db_sym_parse_and_lookup(aout_db_qualified_search, stab, symstr);
392 }
393
394 db_sym_t
395 aout_db_search_symbol(
396 db_symtab_t * symtab,
397 register
398 db_addr_t off,
399 db_strategy_t strategy,
400 db_expr_t *diffp) /* in/out */
401 {
402 register unsigned long diff = *diffp;
403 register struct nlist *symp = 0;
404 register struct nlist *sp, *ep;
405
406 sp = (struct nlist *)symtab->start;
407 ep = (struct nlist *)symtab->end;
408
409 for (; sp < ep; sp++) {
410 if (sp->n_un.n_name == 0)
411 continue;
412 if ((sp->n_type & N_STAB) != 0)
413 continue;
414 if (strategy == DB_STGY_XTRN && (sp->n_type & N_EXT) == 0)
415 continue;
416 if (off >= sp->n_value) {
417
418 unsigned int type = sp->n_type;
419
420 if (type == N_FN) continue;
421 if (off - sp->n_value < diff) {
422 diff = off - sp->n_value;
423 symp = sp;
424 if (diff == 0 && (type & N_EXT))
425 break;
426 }
427 else if (off - sp->n_value == diff) {
428 if (symp == 0)
429 symp = sp;
430 else if ((symp->n_type & N_EXT) == 0 &&
431 (type & N_EXT) != 0)
432 symp = sp; /* pick the external symbol */
433 }
434 }
435 }
436 if (symp == 0) {
437 *diffp = off;
438 }
439 else {
440 *diffp = diff;
441 }
442 return (db_sym_t)symp;
443 }
444
445 /*
446 * Return the name and value for a symbol.
447 */
448 void
449 aout_db_symbol_values(
450 db_sym_t sym,
451 char **namep,
452 db_expr_t *valuep)
453 {
454 register struct nlist *sp;
455
456 sp = (struct nlist *)sym;
457 if (namep)
458 *namep = sp->n_un.n_name;
459 if (valuep)
460 *valuep = sp->n_value;
461 }
462
463 #define X_DB_MAX_DIFF 8 /* maximum allowable diff at the end of line */
464
465 /*
466 * search symbol by value
467 */
468 private boolean_t
469 aout_db_search_by_addr(
470 db_symtab_t *stab,
471 register vm_offset_t addr,
472 char **file,
473 char **func,
474 int *line,
475 unsigned long *diff)
476 {
477 register struct nlist *sp;
478 register struct nlist *line_sp, *func_sp, *file_sp, *line_func;
479 register vm_size_t func_diff, line_diff;
480 boolean_t found_line = FALSE;
481 struct nlist *ep = (struct nlist *)stab->end;
482
483 line_sp = func_sp = file_sp = line_func = 0;
484 *file = *func = 0;
485 *line = 0;
486 func_diff = line_diff = ~0;
487 for (sp = (struct nlist *)stab->start; sp < ep; sp++) {
488 switch(sp->n_type) {
489 case N_SLINE:
490 if (sp->n_value <= addr) {
491 if (line_sp == 0 || line_diff >= addr - sp->n_value) {
492 if (line_func)
493 line_func = 0;
494 line_sp = sp;
495 line_diff = addr - sp->n_value;
496 }
497 }
498 if (sp->n_value >= addr && line_sp)
499 found_line = TRUE;
500 continue;
501 case N_FUN:
502 if ((found_line || (line_sp && line_diff < X_DB_MAX_DIFF))
503 && line_func == 0)
504 line_func = sp;
505 continue;
506 case N_SO:
507 if (sp->n_value > addr)
508 continue;
509 if (file_sp == 0 || file_sp->n_value <= sp->n_value)
510 file_sp = sp;
511 continue;
512 case N_TEXT:
513 if (aout_db_is_filename(sp->n_un.n_name)) {
514 if (sp->n_value > addr)
515 continue;
516 if (file_sp == 0 || file_sp->n_value <= sp->n_value)
517 file_sp = sp;
518 } else if (sp->n_value <= addr &&
519 (func_sp == 0 || func_diff > addr - sp->n_value)) {
520 func_sp = sp;
521 func_diff = addr - sp->n_value;
522 }
523 continue;
524 case N_TEXT|N_EXT:
525 if (sp->n_value <= addr &&
526 (func_sp == 0 || func_diff >= addr - sp->n_value)) {
527 func_sp = sp;
528 func_diff = addr - sp->n_value;
529 if (func_diff == 0 && file_sp && func_sp)
530 break;
531 }
532 default:
533 continue;
534 }
535 break;
536 }
537 if (line_sp) {
538 if (line_func == 0 || func_sp == 0
539 || line_func->n_value != func_sp->n_value)
540 line_sp = 0;
541 }
542 if (file_sp) {
543 *diff = addr - file_sp->n_value;
544 *file = file_sp->n_un.n_name;
545 }
546 if (func_sp) {
547 *diff = addr - func_sp->n_value;
548 *func = (func_sp->n_un.n_name[0] == '_')?
549 func_sp->n_un.n_name + 1: func_sp->n_un.n_name;
550 }
551 if (line_sp) {
552 *diff = addr - line_sp->n_value;
553 *line = line_sp->n_desc;
554 }
555 return (file_sp || func_sp || line_sp);
556 }
557
558 /*
559 * Find filename and lineno within, given the current pc.
560 */
561 boolean_t
562 aout_db_line_at_pc(
563 db_symtab_t *stab,
564 db_sym_t sym,
565 char **file,
566 int *line,
567 db_expr_t pc)
568 {
569 char *func;
570 unsigned long diff;
571 boolean_t found;
572
573 found = aout_db_search_by_addr(stab,
574 (vm_offset_t)pc,
575 file,
576 &func,
577 line,
578 &diff);
579 return (found && func && *file);
580 }
581
582 /*
583 * Initialization routine for a.out files.
584 */
585 void
586 ddb_init(void)
587 {
588 extern vm_offset_t kern_sym_start;
589 extern vm_size_t kern_sym_size;
590
591 if (kern_sym_size != 0) {
592 aout_db_sym_init((char *) kern_sym_start,
593 (char *)(kern_sym_start + kern_sym_size),
594 "mach",
595 (char *)0);
596 }
597 }
598
599 #endif /* DB_NO_AOUT */
Cache object: 782c4e8b7a2006cdda7cf8fe2535f424
|