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