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