Initial import from FreeBSD RELENG_4:
[dragonfly.git] / 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
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 the
24  * rights to redistribute these changes.
25  *
26  * $FreeBSD: src/sys/ddb/db_aout.c,v 1.27 1999/08/28 00:41:05 peter Exp $
27  */
28
29 /*
30  *      Author: David B. Golub, Carnegie Mellon University
31  *      Date:   7/90
32  */
33 /*
34  * Symbol table routines for a.out format files.
35  */
36
37 #if !defined(__ELF__) && !defined(__alpha__)
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41
42 #include <machine/bootinfo.h>
43
44 #include <ddb/ddb.h>
45 #include <ddb/db_sym.h>
46
47 #define _AOUT_INCLUDE_
48 #include <nlist.h>
49 #include <stab.h>
50
51 /*
52  * An a.out symbol table as loaded into the kernel debugger:
53  *
54  * symtab       -> size of symbol entries, in bytes
55  * sp           -> first symbol entry
56  *                 ...
57  * ep           -> last symbol entry + 1
58  * strtab       == start of string table
59  *                 size of string table in bytes,
60  *                 including this word
61  *              -> strings
62  */
63
64 static void     X_db_sym_init __P((int *symtab, char *esymtab, char *name));
65 /*
66  * Find pointers to the start and end of the symbol entries,
67  * given a pointer to the start of the symbol table.
68  */
69 #define db_get_aout_symtab(symtab, sp, ep) \
70         (sp = (struct nlist *)((symtab) + 1), \
71          ep = (struct nlist *)((char *)sp + *(symtab)))
72
73 static void
74 X_db_sym_init(symtab, esymtab, name)
75         int *   symtab;         /* pointer to start of symbol table */
76         char *  esymtab;        /* pointer to end of string table,
77                                    for checking - rounded up to integer
78                                    boundary */
79         char *  name;
80 {
81         register struct nlist   *sym_start, *sym_end;
82         register struct nlist   *sp;
83         register char * strtab;
84         register int    strlen;
85
86         if (*symtab < 4) {
87                 printf ("DDB: no symbols\n");
88                 return;
89         }
90
91         db_get_aout_symtab(symtab, sym_start, sym_end);
92
93         strtab = (char *)sym_end;
94         strlen = *(int *)strtab;
95
96         if (strtab + ((strlen + sizeof(int) - 1) & ~(sizeof(int)-1))
97             != esymtab)
98         {
99             db_printf("[ %s symbol table not valid ]\n", name);
100             return;
101         }
102
103         db_printf("[ preserving %#x bytes of %s symbol table ]\n",
104                 esymtab - (char *)symtab, name);
105
106         for (sp = sym_start; sp < sym_end; sp++) {
107             register int strx;
108             strx = sp->n_un.n_strx;
109             if (strx != 0) {
110                 if (strx > strlen) {
111                     db_printf("Bad string table index (%#x)\n", strx);
112                     sp->n_un.n_name = 0;
113                     continue;
114                 }
115                 sp->n_un.n_name = strtab + strx;
116             }
117         }
118
119         db_add_symbol_table((char *)sym_start, (char *)sym_end, name,
120                             (char *)symtab);
121 }
122
123 c_db_sym_t
124 X_db_lookup(stab, symstr)
125         db_symtab_t     *stab;
126         const char *    symstr;
127 {
128         register struct nlist *sp, *ep;
129
130         sp = (struct nlist *)stab->start;
131         ep = (struct nlist *)stab->end;
132
133         for (; sp < ep; sp++) {
134             if (sp->n_un.n_name == 0)
135                 continue;
136             if ((sp->n_type & N_STAB) == 0 &&
137                 sp->n_un.n_name != 0 &&
138                 db_eqname(sp->n_un.n_name, symstr, '_'))
139             {
140                 return ((db_sym_t)sp);
141             }
142         }
143         return ((db_sym_t)0);
144 }
145
146 c_db_sym_t
147 X_db_search_symbol(symtab, off, strategy, diffp)
148         db_symtab_t *   symtab;
149         register
150         db_addr_t       off;
151         db_strategy_t   strategy;
152         db_expr_t       *diffp;         /* in/out */
153 {
154         register unsigned int   diff = *diffp;
155         register struct nlist   *symp = 0;
156         register struct nlist   *sp, *ep;
157
158         sp = (struct nlist *)symtab->start;
159         ep = (struct nlist *)symtab->end;
160
161         for (; sp < ep; sp++) {
162             if (sp->n_un.n_name == 0)
163                 continue;
164             if ((sp->n_type & N_STAB) != 0 || (sp->n_type & N_TYPE) == N_FN)
165                 continue;
166             if (off >= sp->n_value) {
167                 if (off - sp->n_value < diff) {
168                     diff = off - sp->n_value;
169                     symp = sp;
170                     if (diff == 0) {
171                         if (strategy == DB_STGY_PROC &&
172                                         sp->n_type == (N_TEXT|N_EXT))
173                             break;
174                         if (strategy == DB_STGY_ANY &&
175                                         (sp->n_type & N_EXT))
176                             break;
177                     }
178                 }
179                 else if (off - sp->n_value == diff) {
180                     if (symp == 0)
181                         symp = sp;
182                     else if ((symp->n_type & N_EXT) == 0 &&
183                                 (sp->n_type & N_EXT) != 0)
184                         symp = sp;      /* pick the external symbol */
185                 }
186             }
187         }
188         if (symp == 0) {
189             *diffp = off;
190         }
191         else {
192             *diffp = diff;
193         }
194         return ((db_sym_t)symp);
195 }
196
197 /*
198  * Return the name and value for a symbol.
199  */
200 void
201 X_db_symbol_values(symtab, sym, namep, valuep)
202         db_symtab_t     *symtab;
203         c_db_sym_t      sym;
204         const char      **namep;
205         db_expr_t       *valuep;
206 {
207         register const struct nlist *sp;
208
209         sp = (const struct nlist *)sym;
210         if (namep)
211             *namep = sp->n_un.n_name;
212         if (valuep)
213             *valuep = sp->n_value;
214 }
215
216
217 boolean_t
218 X_db_line_at_pc(symtab, cursym, filename, linenum, off)
219         db_symtab_t *   symtab;
220         c_db_sym_t      cursym;
221         char            **filename;
222         int             *linenum;
223         db_expr_t       off;
224 {
225         register struct nlist   *sp, *ep;
226         unsigned long           sodiff = -1UL, lndiff = -1UL, ln = 0;
227         char                    *fname = NULL;
228
229         sp = (struct nlist *)symtab->start;
230         ep = (struct nlist *)symtab->end;
231
232 /*
233  * XXX - this used to remove "gcc_compiled.", but that is obsolete.  We
234  * now remove unwanted names using symorder.
235  */
236 #define NEWSRC(str)     0
237
238         for (; sp < ep; sp++) {
239
240             /*
241              * Prevent bogus linenumbers in case module not compiled
242              * with debugging options
243              */
244 #if 0
245             if (sp->n_value <= off && (off - sp->n_value) <= sodiff &&
246                 NEWSRC(sp->n_un.n_name)) {
247 #endif
248             if ((sp->n_type & N_TYPE) == N_FN || NEWSRC(sp->n_un.n_name)) {
249                 sodiff = lndiff = -1UL;
250                 ln = 0;
251                 fname = NULL;
252             }
253
254             if (sp->n_type == N_SO && *sp->n_un.n_name != '/') {
255                 if (sp->n_value <= off && (off - sp->n_value) < sodiff) {
256                         sodiff = off - sp->n_value;
257                         fname = sp->n_un.n_name;
258                 }
259                 continue;
260             }
261
262             if (sp->n_type != N_SLINE)
263                 continue;
264
265             if (sp->n_value > off)
266                 break;
267
268             if (off - sp->n_value < lndiff) {
269                 lndiff = off - sp->n_value;
270                 ln = sp->n_desc;
271             }
272         }
273
274         if (fname != NULL && ln != 0) {
275                 *filename = fname;
276                 *linenum = ln;
277                 return TRUE;
278         }
279
280         return (FALSE);
281 }
282
283 boolean_t
284 X_db_sym_numargs(symtab, cursym, nargp, argnamep)
285         db_symtab_t *   symtab;
286         c_db_sym_t      cursym;
287         int             *nargp;
288         char            **argnamep;
289 {
290         register struct nlist   *sp, *ep;
291         u_long                  addr;
292         int                     maxnarg = *nargp, nargs = 0;
293
294         if (cursym == NULL)
295                 return FALSE;
296
297         addr = ((const struct nlist *)cursym)->n_value;
298         sp = (struct nlist *)symtab->start;
299         ep = (struct nlist *)symtab->end;
300
301         for (; sp < ep; sp++) {
302             if (sp->n_type == N_FUN && sp->n_value == addr) {
303                 while (++sp < ep && sp->n_type == N_PSYM) {
304                         if (nargs >= maxnarg)
305                                 break;
306                         nargs++;
307                         *argnamep++ = sp->n_un.n_name?sp->n_un.n_name:"???";
308                         {
309                         /* XXX - remove trailers */
310                         char *cp = *(argnamep-1);
311                         while (*cp != '\0' && *cp != ':') cp++;
312                         if (*cp == ':') *cp = '\0';
313                         }
314                 }
315                 *nargp = nargs;
316                 return TRUE;
317             }
318         }
319         return FALSE;
320 }
321
322 /*
323  * Initialization routine for a.out files.
324  */
325 void
326 kdb_init()
327 {
328 #ifdef __i386__
329         if (bootinfo.bi_esymtab != bootinfo.bi_symtab)
330                 X_db_sym_init((int *)bootinfo.bi_symtab,
331                               (char *)((bootinfo.bi_esymtab + sizeof(int) - 1)
332                                        & ~(sizeof(int) - 1)),
333                               "kernel");
334 #endif
335 }
336
337 #if 0
338 /*
339  * Read symbol table from file.
340  * (should be somewhere else)
341  */
342 #include <boot_ufs/file_io.h>
343 #include <vm/vm_kern.h>
344
345 read_symtab_from_file(fp, symtab_name)
346         struct file     *fp;
347         char *          symtab_name;
348 {
349         vm_size_t       resid;
350         kern_return_t   result;
351         vm_offset_t     symoff;
352         vm_size_t       symsize;
353         vm_offset_t     stroff;
354         vm_size_t       strsize;
355         vm_size_t       table_size;
356         vm_offset_t     symtab;
357
358         if (!get_symtab(fp, &symoff, &symsize)) {
359             boot_printf("[ error %d reading %s file header ]\n",
360                         result, symtab_name);
361             return;
362         }
363
364         stroff = symoff + symsize;
365         result = read_file(fp, (vm_offset_t)stroff,
366                         (vm_offset_t)&strsize, sizeof(strsize), &resid);
367         if (result || resid) {
368             boot_printf("[ no valid symbol table present for %s ]\n",
369                 symtab_name);
370                 return;
371         }
372
373         table_size = sizeof(int) + symsize + strsize;
374         table_size = (table_size + sizeof(int)-1) & ~(sizeof(int)-1);
375
376         symtab = kmem_alloc_wired(kernel_map, table_size);
377
378         *(int *)symtab = symsize;
379
380         result = read_file(fp, symoff,
381                         symtab + sizeof(int), symsize, &resid);
382         if (result || resid) {
383             boot_printf("[ error %d reading %s symbol table ]\n",
384                         result, symtab_name);
385             return;
386         }
387
388         result = read_file(fp, stroff,
389                         symtab + sizeof(int) + symsize, strsize, &resid);
390         if (result || resid) {
391             boot_printf("[ error %d reading %s string table ]\n",
392                         result, symtab_name);
393             return;
394         }
395
396         X_db_sym_init((int *)symtab,
397                         (char *)(symtab + table_size),
398                         symtab_name);
399
400 }
401 #endif
402 #endif