1 /* $OpenBSD: db_aout.c,v 1.28 2002/03/14 01:26:51 millert Exp $ */
2 /* $NetBSD: db_aout.c,v 1.29 2000/07/07 21:55:18 jhawk Exp $ */
3
4 /*
5 * Mach Operating System
6 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7 * All Rights Reserved.
8 *
9 * Permission to use, copy, modify and distribute this software and its
10 * documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
14 *
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 *
19 * Carnegie Mellon requests users of this software to return to
20 *
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
25 *
26 * any improvements or extensions that they make and grant Carnegie Mellon
27 * the rights to redistribute these changes.
28 */
29
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/proc.h>
34
35 #include <machine/db_machdep.h> /* data types */
36
37 #include <ddb/db_sym.h>
38 #include <ddb/db_output.h>
39 #include <ddb/db_extern.h>
40
41 #ifdef DB_AOUT_SYMBOLS
42
43 #include <ddb/db_aout.h>
44
45 boolean_t db_aout_sym_init(int, void *, void *, const char *);
46 db_sym_t db_aout_lookup(db_symtab_t *, char *);
47 db_sym_t db_aout_search_symbol(db_symtab_t *, db_addr_t,
48 db_strategy_t, db_expr_t *);
49 void db_aout_symbol_values(db_symtab_t *, db_sym_t,
50 char **, db_expr_t *);
51 boolean_t db_aout_line_at_pc(db_symtab_t *, db_sym_t,
52 char **, int *, db_expr_t);
53 boolean_t db_aout_sym_numargs(db_symtab_t *, db_sym_t, int *,
54 char **);
55 void db_aout_forall(db_symtab_t *,
56 db_forall_func_t db_forall_func, void *);
57
58 db_symformat_t db_symformat_aout = {
59 "a.out",
60 db_aout_sym_init,
61 db_aout_lookup,
62 db_aout_search_symbol,
63 db_aout_symbol_values,
64 db_aout_line_at_pc,
65 db_aout_sym_numargs,
66 db_aout_forall
67 };
68
69 /*
70 * An a.out symbol table as loaded into the kernel debugger:
71 *
72 * symtab -> size of symbol entries, in bytes
73 * sp -> first symbol entry
74 * ...
75 * ep -> last symbol entry + 1
76 * strtab == start of string table
77 * size of string table in bytes,
78 * including this word
79 * -> strings
80 */
81 static char *strtab;
82 static int slen;
83
84 #define X_db_getname(t, s) (s->n_un.n_strx ? t->end + s->n_un.n_strx : NULL)
85
86 /* XXX */
87 #ifndef ALIGNED_POINTER
88 #define ALIGNED_POINTER(p,t) ((((u_long)(p)) & (sizeof(t)-1)) == 0)
89 #endif
90
91 /*
92 * Find the symbol table and strings; tell ddb about them.
93 */
94 boolean_t
db_aout_sym_init(symsize,vsymtab,vesymtab,name)95 db_aout_sym_init(symsize, vsymtab, vesymtab, name)
96 int symsize; /* size of symbol table */
97 void *vsymtab; /* pointer to start of symbol table */
98 void *vesymtab; /* pointer to end of string table,
99 for checking - rounded up to integer
100 boundary */
101 const char *name;
102 {
103 struct nlist *sym_start, *sym_end;
104 struct nlist *sp;
105 int bad = 0;
106 char *estrtab;
107
108 /*
109 * XXX - ddb_init should take arguments.
110 * Fixup the arguments.
111 */
112 symsize = *(long *)vsymtab;
113 vsymtab = (void *)((long *)vsymtab + 1);
114
115
116 if (ALIGNED_POINTER(vsymtab, long) == 0) {
117 printf("[ %s symbol table has bad start address %p ]\n",
118 name, vsymtab);
119 return (FALSE);
120 }
121
122 /*
123 * Find pointers to the start and end of the symbol entries,
124 * given a pointer to the start of the symbol table.
125 */
126 sym_start = (struct nlist *)vsymtab;
127 sym_end = (struct nlist *)((char *)sym_start + symsize);
128
129 strtab = (char *)sym_end;
130 if (ALIGNED_POINTER(strtab, int) == 0) {
131 printf("[ %s symbol table has bad string table address %p ]\n",
132 name, strtab);
133 return (FALSE);
134 }
135 slen = *(int *)strtab;
136
137 estrtab = strtab + slen;
138
139 #define round_to_size(x) \
140 (((vaddr_t)(x) + sizeof(vsize_t) - 1) & ~(sizeof(vsize_t) - 1))
141
142 if (round_to_size(estrtab) != round_to_size(vesymtab)) {
143 printf("[ %s a.out symbol table not valid ]\n", name);
144 return (FALSE);
145 }
146 #undef round_to_size
147
148 for (sp = sym_start; sp < sym_end; sp++) {
149 int strx;
150 strx = sp->n_un.n_strx;
151 if (strx != 0) {
152 if (strx > slen) {
153 printf("[ %s has bad a.out string table index "
154 "(0x%x) ]\n",
155 name, strx);
156 bad = 1;
157 continue;
158 }
159 }
160 }
161
162 if (bad)
163 return (FALSE);
164
165 if (db_add_symbol_table((char *)sym_start, (char *)sym_end, name,
166 NULL) != -1) {
167 printf("[ using %ld bytes of %s a.out symbol table ]\n",
168 (long)vesymtab - (long)vsymtab, name);
169 return (TRUE);
170 }
171
172 return (FALSE);
173 }
174
175 db_sym_t
db_aout_lookup(stab,symstr)176 db_aout_lookup(stab, symstr)
177 db_symtab_t *stab;
178 char * symstr;
179 {
180 struct nlist *sp, *ep;
181 char *n_name;
182
183 sp = (struct nlist *)stab->start;
184 ep = (struct nlist *)stab->end;
185
186 for (; sp < ep; sp++) {
187 if ((n_name = X_db_getname(stab, sp)) == 0)
188 continue;
189 if ((sp->n_type & N_STAB) == 0 &&
190 db_eqname(n_name, symstr, '_'))
191 return ((db_sym_t)sp);
192 }
193 return ((db_sym_t)0);
194 }
195
196 db_sym_t
db_aout_search_symbol(symtab,off,strategy,diffp)197 db_aout_search_symbol(symtab, off, strategy, diffp)
198 db_symtab_t * symtab;
199 db_addr_t off;
200 db_strategy_t strategy;
201 db_expr_t *diffp; /* in/out */
202 {
203 unsigned int diff = *diffp;
204 struct nlist *symp = 0;
205 struct nlist *sp, *ep;
206
207 sp = (struct nlist *)symtab->start;
208 ep = (struct nlist *)symtab->end;
209
210 for (; sp < ep; sp++) {
211 if ((sp->n_type & N_STAB) != 0 ||
212 (sp->n_type & N_TYPE) == N_FN)
213 continue;
214 if (X_db_getname(symtab, sp) == 0)
215 continue;
216 if (off >= sp->n_value) {
217 if (off - sp->n_value < diff) {
218 diff = off - sp->n_value;
219 symp = sp;
220 if (diff == 0 && ((strategy == DB_STGY_PROC &&
221 sp->n_type == (N_TEXT|N_EXT)) ||
222 (strategy == DB_STGY_ANY &&
223 (sp->n_type & N_EXT))))
224 break;
225 } else if (off - sp->n_value == diff) {
226 if (symp == 0)
227 symp = sp;
228 else if ((symp->n_type & N_EXT) == 0 &&
229 (sp->n_type & N_EXT) != 0)
230 symp = sp; /* pick the ext. sym */
231 }
232 }
233 }
234 if (symp == 0) {
235 *diffp = off;
236 } else {
237 *diffp = diff;
238 }
239 return ((db_sym_t)symp);
240 }
241
242 /*
243 * Return the name and value for a symbol.
244 */
245 void
db_aout_symbol_values(symtab,sym,namep,valuep)246 db_aout_symbol_values(symtab, sym, namep, valuep)
247 db_symtab_t *symtab;
248 db_sym_t sym;
249 char **namep;
250 db_expr_t *valuep;
251 {
252 struct nlist *sp;
253
254 sp = (struct nlist *)sym;
255 if (namep)
256 *namep = X_db_getname(symtab, sp);
257 if (valuep)
258 *valuep = sp->n_value;
259 }
260
261
262 boolean_t
db_aout_line_at_pc(symtab,cursym,filename,linenum,off)263 db_aout_line_at_pc(symtab, cursym, filename, linenum, off)
264 db_symtab_t * symtab;
265 db_sym_t cursym;
266 char **filename;
267 int *linenum;
268 db_expr_t off;
269 {
270 struct nlist *sp, *ep;
271 unsigned long sodiff = -1UL, lndiff = -1UL, ln = 0;
272 char *fname = NULL;
273
274 sp = (struct nlist *)symtab->start;
275 ep = (struct nlist *)symtab->end;
276
277 /* XXX - gcc specific */
278 #define NEWSRC(str) ((str) != NULL && \
279 (str)[0] == 'g' && strcmp((str), "gcc_compiled.") == 0)
280
281 for (; sp < ep; sp++) {
282
283 /*
284 * Prevent bogus linenumbers in case module not compiled
285 * with debugging options
286 */
287 #if 0
288 if (sp->n_value <= off && (off - sp->n_value) <= sodiff &&
289 NEWSRC(X_db_getname(symtab, sp))) {
290 #endif
291 if ((sp->n_type & N_TYPE) == N_FN ||
292 NEWSRC(X_db_getname(symtab, sp))) {
293 sodiff = lndiff = -1UL;
294 ln = 0;
295 fname = NULL;
296 }
297
298 if (sp->n_type == N_SO) {
299 if (sp->n_value <= off &&
300 (off - sp->n_value) < sodiff) {
301 sodiff = off - sp->n_value;
302 fname = X_db_getname(symtab, sp);
303 }
304 continue;
305 }
306
307 if (sp->n_type != N_SLINE)
308 continue;
309
310 if (sp->n_value > off)
311 break;
312
313 if (off - sp->n_value < lndiff) {
314 lndiff = off - sp->n_value;
315 ln = sp->n_desc;
316 }
317 }
318
319 if (fname != NULL && ln != 0) {
320 *filename = fname;
321 *linenum = ln;
322 return (TRUE);
323 }
324
325 return (FALSE);
326 }
327
328 boolean_t
db_aout_sym_numargs(symtab,cursym,nargp,argnamep)329 db_aout_sym_numargs(symtab, cursym, nargp, argnamep)
330 db_symtab_t * symtab;
331 db_sym_t cursym;
332 int *nargp;
333 char **argnamep;
334 {
335 struct nlist *sp, *ep;
336 u_long addr;
337 int maxnarg = *nargp, nargs = 0;
338 char *n_name;
339
340 if (cursym == NULL)
341 return (FALSE);
342
343 addr = ((struct nlist *)cursym)->n_value;
344 sp = (struct nlist *)symtab->start;
345 ep = (struct nlist *)symtab->end;
346
347 for (; sp < ep; sp++) {
348 if (sp->n_type == N_FUN && sp->n_value == addr) {
349 while (++sp < ep && sp->n_type == N_PSYM) {
350 if (nargs >= maxnarg)
351 break;
352 nargs++;
353 n_name = X_db_getname(symtab, sp);
354 *argnamep++ = n_name ? n_name : "???";
355 {
356 /* XXX - remove trailers */
357 char *cp = *(argnamep - 1);
358
359 while (*cp != '\0' && *cp != ':')
360 cp++;
361 if (*cp == ':') *cp = '\0';
362 }
363 }
364 *nargp = nargs;
365 return (TRUE);
366 }
367 }
368 return (FALSE);
369 }
370
371 void
db_aout_forall(stab,db_forall_func,arg)372 db_aout_forall(stab, db_forall_func, arg)
373 db_symtab_t *stab;
374 db_forall_func_t db_forall_func;
375 void *arg;
376 {
377 static char suffix[2];
378 struct nlist *sp, *ep;
379
380 sp = (struct nlist *)stab->start;
381 ep = (struct nlist *)stab->end;
382
383 for (; sp < ep; sp++) {
384 if (X_db_getname(stab, sp) == 0)
385 continue;
386 if ((sp->n_type & N_STAB) == 0) {
387 suffix[1] = '\0';
388 switch(sp->n_type & N_TYPE) {
389 case N_ABS:
390 suffix[0] = '@';
391 break;
392 case N_TEXT:
393 suffix[0] = '*';
394 break;
395 case N_DATA:
396 suffix[0] = '+';
397 break;
398 case N_BSS:
399 suffix[0] = '-';
400 break;
401 case N_FN:
402 suffix[0] = '/';
403 break;
404 default:
405 suffix[0] = '\0';
406 }
407 (*db_forall_func)(stab, (db_sym_t)sp,
408 X_db_getname(stab, sp), suffix, '_', arg);
409 }
410 }
411 return;
412 }
413
414
415 #endif /* DB_AOUT_SYMBOLS */
416