db_elf.c revision 1.14.2.2 1 /* $NetBSD: db_elf.c,v 1.14.2.2 2001/11/14 19:13:38 nathanw Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: db_elf.c,v 1.14.2.2 2001/11/14 19:13:38 nathanw Exp $");
42
43 #include <sys/types.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/proc.h>
47
48 #include <machine/db_machdep.h>
49
50 #include <ddb/db_sym.h>
51 #include <ddb/db_output.h>
52 #include <ddb/db_extern.h>
53
54 #ifdef DB_ELF_SYMBOLS
55
56 #ifndef DB_ELFSIZE
57 #error Must define DB_ELFSIZE!
58 #endif
59
60 #define ELFSIZE DB_ELFSIZE
61
62 #include <sys/exec_elf.h>
63
64 static char *db_elf_find_strtab __P((db_symtab_t *));
65
66 #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start))
67 #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end))
68 #define STAB_TO_EHDR(stab) ((Elf_Ehdr *)((stab)->private))
69 #define STAB_TO_SHDR(stab, e) ((Elf_Shdr *)((stab)->private + (e)->e_shoff))
70
71 boolean_t db_elf_sym_init __P((int, void *, void *, const char *));
72 db_sym_t db_elf_lookup __P((db_symtab_t *, char *));
73 db_sym_t db_elf_search_symbol __P((db_symtab_t *, db_addr_t,
74 db_strategy_t, db_expr_t *));
75 void db_elf_symbol_values __P((db_symtab_t *, db_sym_t,
76 char **, db_expr_t *));
77 boolean_t db_elf_line_at_pc __P((db_symtab_t *, db_sym_t,
78 char **, int *, db_expr_t));
79 boolean_t db_elf_sym_numargs __P((db_symtab_t *, db_sym_t, int *,
80 char **));
81 void db_elf_forall __P((db_symtab_t *,
82 db_forall_func_t db_forall_func, void *));
83
84 const db_symformat_t db_symformat_elf = {
85 "ELF",
86 db_elf_sym_init,
87 db_elf_lookup,
88 db_elf_search_symbol,
89 db_elf_symbol_values,
90 db_elf_line_at_pc,
91 db_elf_sym_numargs,
92 db_elf_forall
93 };
94
95 /*
96 * Find the symbol table and strings; tell ddb about them.
97 */
98 boolean_t
99 db_elf_sym_init(symsize, symtab, esymtab, name)
100 int symsize; /* size of symbol table */
101 void *symtab; /* pointer to start of symbol table */
102 void *esymtab; /* pointer to end of string table,
103 for checking - rounded up to integer
104 boundary */
105 const char *name;
106 {
107 Elf_Ehdr *elf;
108 Elf_Shdr *shp;
109 Elf_Sym *symp, *symtab_start, *symtab_end;
110 char *strtab_start, *strtab_end;
111 int i, j;
112
113 if (ALIGNED_POINTER(symtab, long) == 0) {
114 printf("[ %s symbol table has bad start address %p ]\n",
115 name, symtab);
116 return (FALSE);
117 }
118
119 symtab_start = symtab_end = NULL;
120 strtab_start = strtab_end = NULL;
121
122 /*
123 * The format of the symbols loaded by the boot program is:
124 *
125 * Elf exec header
126 * first section header
127 * . . .
128 * . . .
129 * last section header
130 * first symbol or string table section
131 * . . .
132 * . . .
133 * last symbol or string table section
134 */
135
136 /*
137 * Validate the Elf header.
138 */
139 elf = (Elf_Ehdr *)symtab;
140 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
141 elf->e_ident[EI_CLASS] != ELFCLASS)
142 goto badheader;
143
144 switch (elf->e_machine) {
145
146 ELFDEFNNAME(MACHDEP_ID_CASES)
147
148 default:
149 goto badheader;
150 }
151
152 /*
153 * Find the first (and, we hope, only) SHT_SYMTAB section in
154 * the file, and the SHT_STRTAB section that goes with it.
155 */
156 if (elf->e_shoff == 0)
157 goto badheader;
158 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
159 for (i = 0; i < elf->e_shnum; i++) {
160 if (shp[i].sh_type == SHT_SYMTAB) {
161 if (shp[i].sh_offset == 0)
162 continue;
163 /* Got the symbol table. */
164 symtab_start = (Elf_Sym *)((char *)symtab +
165 shp[i].sh_offset);
166 symtab_end = (Elf_Sym *)((char *)symtab +
167 shp[i].sh_offset + shp[i].sh_size);
168 /* Find the string table to go with it. */
169 j = shp[i].sh_link;
170 if (shp[j].sh_offset == 0)
171 continue;
172 strtab_start = (char *)symtab + shp[j].sh_offset;
173 strtab_end = (char *)symtab + shp[j].sh_offset +
174 shp[j].sh_size;
175 /* There should only be one symbol table. */
176 break;
177 }
178 }
179
180 /*
181 * Now, sanity check the symbols against the string table.
182 */
183 if (symtab_start == NULL || strtab_start == NULL ||
184 ALIGNED_POINTER(symtab_start, long) == 0 ||
185 ALIGNED_POINTER(strtab_start, long) == 0)
186 goto badheader;
187 for (symp = symtab_start; symp < symtab_end; symp++)
188 if (symp->st_name + strtab_start > strtab_end)
189 goto badheader;
190
191 /*
192 * Link the symbol table into the debugger.
193 */
194 if (db_add_symbol_table((char *)symtab_start,
195 (char *)symtab_end, name, (char *)symtab) != -1) {
196 printf("[ using %lu bytes of %s ELF symbol table ]\n",
197 (u_long)roundup(((char *)esymtab - (char *)symtab),
198 sizeof(u_long)), name);
199 return (TRUE);
200 }
201
202 return (FALSE);
203
204 badheader:
205 printf("[ %s ELF symbol table not valid ]\n", name);
206 return (FALSE);
207 }
208
209 /*
210 * Internal helper function - return a pointer to the string table
211 * for the current symbol table.
212 */
213 static char *
214 db_elf_find_strtab(stab)
215 db_symtab_t *stab;
216 {
217 Elf_Ehdr *elf = STAB_TO_EHDR(stab);
218 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
219 int i;
220
221 /*
222 * We don't load ELF header for ELF modules.
223 * Find out if this is a loadable module. If so,
224 * string table comes right after symbol table.
225 */
226 if ((Elf_Sym *)elf == STAB_TO_SYMSTART(stab)) {
227 return ((char *)STAB_TO_SYMEND(stab));
228 }
229 for (i = 0; i < elf->e_shnum; i++) {
230 if (shp[i].sh_type == SHT_SYMTAB)
231 return ((char*)elf + shp[shp[i].sh_link].sh_offset);
232 }
233
234 return (NULL);
235 }
236
237 /*
238 * Lookup the symbol with the given name.
239 */
240 db_sym_t
241 db_elf_lookup(stab, symstr)
242 db_symtab_t *stab;
243 char *symstr;
244 {
245 Elf_Sym *symp, *symtab_start, *symtab_end;
246 char *strtab;
247
248 symtab_start = STAB_TO_SYMSTART(stab);
249 symtab_end = STAB_TO_SYMEND(stab);
250
251 strtab = db_elf_find_strtab(stab);
252 if (strtab == NULL)
253 return ((db_sym_t)0);
254
255 for (symp = symtab_start; symp < symtab_end; symp++) {
256 if (symp->st_name != 0 &&
257 db_eqname(strtab + symp->st_name, symstr, 0))
258 return ((db_sym_t)symp);
259 }
260
261 return ((db_sym_t)0);
262 }
263
264 /*
265 * Search for the symbol with the given address (matching within the
266 * provided threshold).
267 */
268 db_sym_t
269 db_elf_search_symbol(symtab, off, strategy, diffp)
270 db_symtab_t *symtab;
271 db_addr_t off;
272 db_strategy_t strategy;
273 db_expr_t *diffp; /* in/out */
274 {
275 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
276 db_expr_t diff = *diffp;
277
278 symtab_start = STAB_TO_SYMSTART(symtab);
279 symtab_end = STAB_TO_SYMEND(symtab);
280
281 rsymp = NULL;
282
283 for (symp = symtab_start; symp < symtab_end; symp++) {
284 if (symp->st_name == 0)
285 continue;
286 #if 0
287 /* This prevents me from seeing anythin in locore.s -- eeh */
288 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
289 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
290 continue;
291 #endif
292
293 if (off >= symp->st_value) {
294 if ((off - symp->st_value) < diff) {
295 diff = off - symp->st_value;
296 rsymp = symp;
297 if (diff == 0) {
298 if (strategy == DB_STGY_PROC &&
299 ELFDEFNNAME(ST_TYPE)(symp->st_info)
300 == STT_FUNC &&
301 ELFDEFNNAME(ST_BIND)(symp->st_info)
302 != STB_LOCAL)
303 break;
304 if (strategy == DB_STGY_ANY &&
305 ELFDEFNNAME(ST_BIND)(symp->st_info)
306 != STB_LOCAL)
307 break;
308 }
309 } else if ((off - symp->st_value) == diff) {
310 if (rsymp == NULL)
311 rsymp = symp;
312 else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info)
313 == STB_LOCAL &&
314 ELFDEFNNAME(ST_BIND)(symp->st_info)
315 != STB_LOCAL) {
316 /* pick the external symbol */
317 rsymp = symp;
318 }
319 }
320 }
321 }
322
323 if (rsymp == NULL)
324 *diffp = off;
325 else
326 *diffp = diff;
327
328 return ((db_sym_t)rsymp);
329 }
330
331 /*
332 * Return the name and value for a symbol.
333 */
334 void
335 db_elf_symbol_values(symtab, sym, namep, valuep)
336 db_symtab_t *symtab;
337 db_sym_t sym;
338 char **namep;
339 db_expr_t *valuep;
340 {
341 Elf_Sym *symp = (Elf_Sym *)sym;
342 char *strtab;
343
344 if (namep) {
345 strtab = db_elf_find_strtab(symtab);
346 if (strtab == NULL)
347 *namep = NULL;
348 else
349 *namep = strtab + symp->st_name;
350 }
351
352 if (valuep)
353 *valuep = symp->st_value;
354 }
355
356 /*
357 * Return the file and line number of the current program counter
358 * if we can find the appropriate debugging symbol.
359 */
360 boolean_t
361 db_elf_line_at_pc(symtab, cursym, filename, linenum, off)
362 db_symtab_t *symtab;
363 db_sym_t cursym;
364 char **filename;
365 int *linenum;
366 db_expr_t off;
367 {
368
369 /*
370 * XXX We don't support this (yet).
371 */
372 return (FALSE);
373 }
374
375 /*
376 * Returns the number of arguments to a function and their
377 * names if we can find the appropriate debugging symbol.
378 */
379 boolean_t
380 db_elf_sym_numargs(symtab, cursym, nargp, argnamep)
381 db_symtab_t *symtab;
382 db_sym_t cursym;
383 int *nargp;
384 char **argnamep;
385 {
386
387 /*
388 * XXX We don't support this (yet).
389 */
390 return (FALSE);
391 }
392
393 void
394 db_elf_forall(stab, db_forall_func, arg)
395 db_symtab_t *stab;
396 db_forall_func_t db_forall_func;
397 void *arg;
398 {
399 char *strtab;
400 static char suffix[2];
401 Elf_Sym *symp, *symtab_start, *symtab_end;
402
403 symtab_start = STAB_TO_SYMSTART(stab);
404 symtab_end = STAB_TO_SYMEND(stab);
405
406 strtab = db_elf_find_strtab(stab);
407 if (strtab == NULL)
408 return;
409
410 for (symp = symtab_start; symp < symtab_end; symp++)
411 if (symp->st_name != 0) {
412 suffix[1] = '\0';
413 switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
414 case STT_OBJECT:
415 suffix[0] = '+';
416 break;
417 case STT_FUNC:
418 suffix[0] = '*';
419 break;
420 case STT_SECTION:
421 suffix[0] = '&';
422 break;
423 case STT_FILE:
424 suffix[0] = '/';
425 break;
426 default:
427 suffix[0] = '\0';
428 }
429 (*db_forall_func)(stab, (db_sym_t)symp,
430 strtab + symp->st_name, suffix, 0, arg);
431 }
432 return;
433 }
434 #endif /* DB_ELF_SYMBOLS */
435