|
|
1.1 root 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 [email protected]
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: * Author: David B. Golub, Carnegie Mellon University
28: * Date: 7/90
29: */
30: #include "mach_kdb.h"
31: #if MACH_KDB
32:
33: /*
34: * Symbol table routines for a.out format files.
35: */
36:
37: #include <mach/std_types.h>
38: #include <machine/db_machdep.h> /* data types */
39: #include <ddb/db_sym.h>
40:
41: #ifndef DB_NO_AOUT
42:
43: #include <ddb/nlist.h> /* a.out symbol table */
44: #include <ddb/stab.h>
45:
46: #define private static
47:
48: /*
49: * An a.out symbol table as loaded into the kernel debugger:
50: *
51: * symtab -> size of symbol entries, in bytes
52: * sp -> first symbol entry
53: * ...
54: * ep -> last symbol entry + 1
55: * strtab == start of string table
56: * size of string table in bytes,
57: * including this word
58: * -> strings
59: */
60:
61: /*
62: * Find pointers to the start and end of the symbol entries,
63: * given a pointer to the start of the symbol table.
64: */
65: #define db_get_aout_symtab(symtab, sp, ep) \
66: (sp = (struct nlist *)((vm_offset_t *)(symtab) + 1), \
67: ep = (struct nlist *)((char *)sp + *((int*)symtab)))
68:
69: boolean_t
70: aout_db_sym_init(symtab, esymtab, name, task_addr)
71: char * symtab; /* pointer to start of symbol table */
72: char * esymtab; /* pointer to end of string table,
73: for checking - may be rounded up to
74: integer boundary */
75: char * name;
76: char * task_addr; /* use for this task only */
77: {
78: register struct nlist *sym_start, *sym_end;
79: register struct nlist *sp;
80: register char * strtab;
81: register int strlen;
82: char * estrtab;
83:
84: db_get_aout_symtab(symtab, sym_start, sym_end);
85:
86: strtab = (char *)sym_end;
87: strlen = *(int *)strtab;
88: estrtab = strtab + strlen;
89:
90: #define round_to_size(x) \
91: (((vm_offset_t)(x) + sizeof(vm_size_t) - 1) & ~(sizeof(vm_size_t) - 1))
92:
93: if (round_to_size(estrtab) != round_to_size(esymtab)) {
94: db_printf("[ %s symbol table not valid ]\n", name);
95: return (FALSE);
96: }
97:
98: #undef round_to_size
99:
100: for (sp = sym_start; sp < sym_end; sp++) {
101: register long strx;
102: strx = sp->n_un.n_strx;
103: if (strx != 0) {
104: if (strx > strlen) {
105: db_printf("Bad string table index (%#x)\n", strx);
106: sp->n_un.n_name = 0;
107: continue;
108: }
109: sp->n_un.n_name = strtab + strx;
110: }
111: }
112:
113: if (db_add_symbol_table(SYMTAB_AOUT,
114: (char *)sym_start,
115: (char *)sym_end,
116: name,
117: symtab,
118: task_addr))
119: {
120: /* Successfully added symbol table */
121: db_printf("[ preserving %d bytes of %s symbol table ]\n",
122: esymtab - (char *)symtab, name);
123: return TRUE;
124: }
125: else
126: return FALSE;
127: }
128:
129: /*
130: * check file name or not (check xxxx.x pattern)
131: */
132: private boolean_t
133: aout_db_is_filename(name)
134: register char *name;
135: {
136: while (*name) {
137: if (*name == '.') {
138: if (name[1])
139: return(TRUE);
140: }
141: name++;
142: }
143: return(FALSE);
144: }
145:
146: /*
147: * special name comparison routine with a name in the symbol table entry
148: */
149: private boolean_t
150: aout_db_eq_name(sp, name)
151: struct nlist *sp;
152: char *name;
153: {
154: register char *s1, *s2;
155:
156: s1 = sp->n_un.n_name;
157: s2 = name;
158: if (*s1 == '_' && *s2 && *s2 != '_')
159: s1++;
160: while (*s2) {
161: if (*s1++ != *s2++) {
162: /*
163: * check .c .o file name comparison case
164: */
165: if (*s2 == 0 && sp->n_un.n_name <= s1 - 2
166: && s1[-2] == '.' && s1[-1] == 'o')
167: return(TRUE);
168: return(FALSE);
169: }
170: }
171: /*
172: * do special check for
173: * xxx:yyy for N_FUN
174: * xxx.ttt for N_DATA and N_BSS
175: */
176: return(*s1 == 0 || (*s1 == ':' && sp->n_type == N_FUN) ||
177: (*s1 == '.' && (sp->n_type == N_DATA || sp->n_type == N_BSS)));
178: }
179:
180: /*
181: * search a symbol table with name and type
182: * fp(in,out): last found text file name symbol entry
183: */
184: private struct nlist *
185: aout_db_search_name(sp, ep, name, type, fp)
186: register struct nlist *sp;
187: struct nlist *ep;
188: char *name;
189: int type;
190: struct nlist **fp;
191: {
192: struct nlist *file_sp = *fp;
193: struct nlist *found_sp = 0;
194:
195: for ( ; sp < ep; sp++) {
196: if (sp->n_type == N_TEXT && aout_db_is_filename(sp->n_un.n_name))
197: *fp = sp;
198: if (type) {
199: if (sp->n_type == type) {
200: if (aout_db_eq_name(sp, name))
201: return(sp);
202: }
203: if (sp->n_type == N_SO)
204: *fp = sp;
205: continue;
206: }
207: if (sp->n_type & N_STAB)
208: continue;
209: if (sp->n_un.n_name && aout_db_eq_name(sp, name)) {
210: /*
211: * In case of qaulified search by a file,
212: * return it immediately with some check.
213: * Otherwise, search external one
214: */
215: if (file_sp) {
216: if ((file_sp == *fp) || (sp->n_type & N_EXT))
217: return(sp);
218: } else if (sp->n_type & N_EXT)
219: return(sp);
220: else
221: found_sp = sp;
222: }
223: }
224: return(found_sp);
225: }
226:
227: /*
228: * search a symbol with file, func and line qualification
229: */
230: private db_sym_t
231: aout_db_qualified_search(stab, file, sym, line)
232: db_symtab_t *stab;
233: char *file;
234: char *sym;
235: int line;
236: {
237: register struct nlist *sp = (struct nlist *)stab->start;
238: struct nlist *ep = (struct nlist *)stab->end;
239: struct nlist *fp = 0;
240: struct nlist *found_sp;
241: unsigned long func_top;
242: boolean_t in_file;
243:
244: if (file == 0 && sym == 0)
245: return(0);
246: if (file) {
247: if ((sp = aout_db_search_name(sp, ep, file, N_TEXT, &fp)) == 0)
248: return(0);
249: }
250: if (sym) {
251: sp = aout_db_search_name(sp, ep, sym, (line > 0)? N_FUN: 0, &fp);
252: if (sp == 0)
253: return(0);
254: }
255: if (line > 0) {
256: if (file && !aout_db_eq_name(fp, file))
257: return(0);
258: found_sp = 0;
259: if (sp->n_type == N_FUN) {
260: /*
261: * qualified by function name
262: * search backward because line number entries
263: * for the function are above it in this case.
264: */
265: func_top = sp->n_value;
266: for (sp--; sp >= (struct nlist *)stab->start; sp--) {
267: if (sp->n_type != N_SLINE)
268: continue;
269: if (sp->n_value < func_top)
270: break;
271: if (sp->n_desc <= line) {
272: if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
273: found_sp = sp;
274: if (sp->n_desc == line)
275: break;
276: }
277: }
278: if (sp->n_type != N_SLINE || sp->n_value < func_top)
279: return(0);
280: } else {
281: /*
282: * qualified by only file name
283: * search forward in this case
284: */
285: in_file = TRUE;
286: for (sp++; sp < ep; sp++) {
287: if (sp->n_type == N_TEXT
288: && aout_db_is_filename(sp->n_un.n_name))
289: break; /* enter into another file */
290: if (sp->n_type == N_SOL) {
291: in_file = aout_db_eq_name(sp, file);
292: continue;
293: }
294: if (!in_file || sp->n_type != N_SLINE)
295: continue;
296: if (sp->n_desc <= line) {
297: if (found_sp == 0 || found_sp->n_desc < sp->n_desc)
298: found_sp = sp;
299: if (sp->n_desc == line)
300: break;
301: }
302: }
303: }
304: sp = found_sp;
305: }
306: return((db_sym_t) sp);
307: }
308:
309: /*
310: * lookup symbol by name
311: */
312: db_sym_t
313: aout_db_lookup(stab, symstr)
314: db_symtab_t *stab;
315: char * symstr;
316: {
317: db_sym_t db_sym_parse_and_lookup();
318:
319: return(db_sym_parse_and_lookup(aout_db_qualified_search, stab, symstr));
320: }
321:
322: db_sym_t
323: aout_db_search_symbol(symtab, off, strategy, diffp)
324: db_symtab_t * symtab;
325: register
326: db_addr_t off;
327: db_strategy_t strategy;
328: db_expr_t *diffp; /* in/out */
329: {
330: register unsigned long diff = *diffp;
331: register struct nlist *symp = 0;
332: register struct nlist *sp, *ep;
333:
334: sp = (struct nlist *)symtab->start;
335: ep = (struct nlist *)symtab->end;
336:
337: for (; sp < ep; sp++) {
338: if (sp->n_un.n_name == 0)
339: continue;
340: if ((sp->n_type & N_STAB) != 0)
341: continue;
342: if (strategy == DB_STGY_XTRN && (sp->n_type & N_EXT) == 0)
343: continue;
344: if (off >= sp->n_value) {
345:
346: unsigned int type = sp->n_type;
347:
348: if (type == N_FN) continue;
349: if (off - sp->n_value < diff) {
350: diff = off - sp->n_value;
351: symp = sp;
352: if (diff == 0 && (type & N_EXT))
353: break;
354: }
355: else if (off - sp->n_value == diff) {
356: if (symp == 0)
357: symp = sp;
358: else if ((symp->n_type & N_EXT) == 0 &&
359: (type & N_EXT) != 0)
360: symp = sp; /* pick the external symbol */
361: }
362: }
363: }
364: if (symp == 0) {
365: *diffp = off;
366: }
367: else {
368: *diffp = diff;
369: }
370: return ((db_sym_t)symp);
371: }
372:
373: /*
374: * Return the name and value for a symbol.
375: */
376: void
377: aout_db_symbol_values(sym, namep, valuep)
378: db_sym_t sym;
379: char **namep;
380: db_expr_t *valuep;
381: {
382: register struct nlist *sp;
383:
384: sp = (struct nlist *)sym;
385: if (namep)
386: *namep = sp->n_un.n_name;
387: if (valuep)
388: *valuep = sp->n_value;
389: }
390:
391: #define X_DB_MAX_DIFF 8 /* maximum allowable diff at the end of line */
392:
393: /*
394: * search symbol by value
395: */
396: private boolean_t
397: aout_db_search_by_addr(stab, addr, file, func, line, diff)
398: db_symtab_t *stab;
399: register vm_offset_t addr;
400: char **file;
401: char **func;
402: int *line;
403: unsigned long *diff;
404: {
405: register struct nlist *sp;
406: register struct nlist *line_sp, *func_sp, *file_sp, *line_func;
407: register vm_size_t func_diff, line_diff;
408: boolean_t found_line = FALSE;
409: struct nlist *ep = (struct nlist *)stab->end;
410:
411: line_sp = func_sp = file_sp = line_func = 0;
412: *file = *func = 0;
413: *line = 0;
414: func_diff = line_diff = ~0;
415: for (sp = (struct nlist *)stab->start; sp < ep; sp++) {
416: switch(sp->n_type) {
417: case N_SLINE:
418: if (sp->n_value <= addr) {
419: if (line_sp == 0 || line_diff >= addr - sp->n_value) {
420: if (line_func)
421: line_func = 0;
422: line_sp = sp;
423: line_diff = addr - sp->n_value;
424: }
425: }
426: if (sp->n_value >= addr && line_sp)
427: found_line = TRUE;
428: continue;
429: case N_FUN:
430: if ((found_line || (line_sp && line_diff < X_DB_MAX_DIFF))
431: && line_func == 0)
432: line_func = sp;
433: continue;
434: case N_SO:
435: if (sp->n_value > addr)
436: continue;
437: if (file_sp == 0 || file_sp->n_value <= sp->n_value)
438: file_sp = sp;
439: continue;
440: case N_TEXT:
441: if (aout_db_is_filename(sp->n_un.n_name)) {
442: if (sp->n_value > addr)
443: continue;
444: if (file_sp == 0 || file_sp->n_value <= sp->n_value)
445: file_sp = sp;
446: } else if (sp->n_value <= addr &&
447: (func_sp == 0 || func_diff > addr - sp->n_value)) {
448: func_sp = sp;
449: func_diff = addr - sp->n_value;
450: }
451: continue;
452: case N_TEXT|N_EXT:
453: if (sp->n_value <= addr &&
454: (func_sp == 0 || func_diff >= addr - sp->n_value)) {
455: func_sp = sp;
456: func_diff = addr - sp->n_value;
457: if (func_diff == 0 && file_sp && func_sp)
458: break;
459: }
460: default:
461: continue;
462: }
463: break;
464: }
465: if (line_sp) {
466: if (line_func == 0 || func_sp == 0
467: || line_func->n_value != func_sp->n_value)
468: line_sp = 0;
469: }
470: if (file_sp) {
471: *diff = addr - file_sp->n_value;
472: *file = file_sp->n_un.n_name;
473: }
474: if (func_sp) {
475: *diff = addr - func_sp->n_value;
476: *func = (func_sp->n_un.n_name[0] == '_')?
477: func_sp->n_un.n_name + 1: func_sp->n_un.n_name;
478: }
479: if (line_sp) {
480: *diff = addr - line_sp->n_value;
481: *line = line_sp->n_desc;
482: }
483: return(file_sp || func_sp || line_sp);
484: }
485:
486: /*
487: * Find filename and lineno within, given the current pc.
488: */
489: boolean_t
490: aout_db_line_at_pc(stab, sym, file, line, pc)
491: db_symtab_t *stab;
492: db_sym_t sym;
493: char **file;
494: int *line;
495: db_expr_t pc;
496: {
497: char *func;
498: unsigned long diff;
499: boolean_t found;
500:
501: found = aout_db_search_by_addr(stab,(vm_offset_t)pc,file,&func,line,&diff);
502: return(found && func && *file);
503: }
504:
505: #endif /* DB_NO_AOUT */
506:
507: #endif MACH_KDB
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.