db_elf.c revision 1.14 1 /* $NetBSD: db_elf.c,v 1.14 2001/01/17 19:50:03 jdolecek 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/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44
45 #include <machine/db_machdep.h>
46
47 #include <ddb/db_sym.h>
48 #include <ddb/db_output.h>
49 #include <ddb/db_extern.h>
50
51 #ifdef DB_ELF_SYMBOLS
52
53 #ifndef DB_ELFSIZE
54 #error Must define DB_ELFSIZE!
55 #endif
56
57 #define ELFSIZE DB_ELFSIZE
58
59 #include <sys/exec_elf.h>
60
61 static char *db_elf_find_strtab __P((db_symtab_t *));
62
63 #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start))
64 #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end))
65 #define STAB_TO_EHDR(stab) ((Elf_Ehdr *)((stab)->private))
66 #define STAB_TO_SHDR(stab, e) ((Elf_Shdr *)((stab)->private + (e)->e_shoff))
67
68 boolean_t db_elf_sym_init __P((int, void *, void *, const char *));
69 db_sym_t db_elf_lookup __P((db_symtab_t *, char *));
70 db_sym_t db_elf_search_symbol __P((db_symtab_t *, db_addr_t,
71 db_strategy_t, db_expr_t *));
72 void db_elf_symbol_values __P((db_symtab_t *, db_sym_t,
73 char **, db_expr_t *));
74 boolean_t db_elf_line_at_pc __P((db_symtab_t *, db_sym_t,
75 char **, int *, db_expr_t));
76 boolean_t db_elf_sym_numargs __P((db_symtab_t *, db_sym_t, int *,
77 char **));
78 void db_elf_forall __P((db_symtab_t *,
79 db_forall_func_t db_forall_func, void *));
80
81 const db_symformat_t db_symformat_elf = {
82 "ELF",
83 db_elf_sym_init,
84 db_elf_lookup,
85 db_elf_search_symbol,
86 db_elf_symbol_values,
87 db_elf_line_at_pc,
88 db_elf_sym_numargs,
89 db_elf_forall
90 };
91
92 /*
93 * Find the symbol table and strings; tell ddb about them.
94 */
95 boolean_t
96 db_elf_sym_init(symsize, symtab, esymtab, name)
97 int symsize; /* size of symbol table */
98 void *symtab; /* pointer to start of symbol table */
99 void *esymtab; /* pointer to end of string table,
100 for checking - rounded up to integer
101 boundary */
102 const char *name;
103 {
104 Elf_Ehdr *elf;
105 Elf_Shdr *shp;
106 Elf_Sym *symp, *symtab_start, *symtab_end;
107 char *shstrtab, *strtab_start, *strtab_end;
108 int i;
109
110 if (ALIGNED_POINTER(symtab, long) == 0) {
111 printf("[ %s symbol table has bad start address %p ]\n",
112 name, symtab);
113 return (FALSE);
114 }
115
116 symtab_start = symtab_end = NULL;
117 strtab_start = strtab_end = NULL;
118
119 /*
120 * The format of the symbols loaded by the boot program is:
121 *
122 * Elf exec header
123 * first section header
124 * . . .
125 * . . .
126 * last section header
127 * first symbol or string table section
128 * . . .
129 * . . .
130 * last symbol or string table section
131 */
132
133 /*
134 * Validate the Elf header.
135 */
136 elf = (Elf_Ehdr *)symtab;
137 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
138 elf->e_ident[EI_CLASS] != ELFCLASS)
139 goto badheader;
140
141 switch (elf->e_machine) {
142
143 ELFDEFNNAME(MACHDEP_ID_CASES)
144
145 default:
146 goto badheader;
147 }
148
149 /*
150 * Find the section header string table (.shstrtab), and look up
151 * the symbol table (.symtab) and string table (.strtab) via their
152 * names in shstrtab, rather than by table type.
153 * This works in the presence of multiple string tables, such as
154 * stabs data found when booting netbsd.gdb.
155 */
156 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
157 shstrtab = (char*)symtab + shp[elf->e_shstrndx].sh_offset;
158 for (i = 0; i < elf->e_shnum; i++) {
159 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
160 strtab_start = (char *)symtab + shp[i].sh_offset;
161 strtab_end = (char *)symtab + shp[i].sh_offset +
162 shp[i].sh_size;
163 } else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
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 }
169 }
170
171 /*
172 * Now, sanity check the symbols against the string table.
173 */
174 if (symtab_start == NULL || strtab_start == NULL ||
175 ALIGNED_POINTER(symtab_start, long) == 0 ||
176 ALIGNED_POINTER(strtab_start, long) == 0)
177 goto badheader;
178 for (symp = symtab_start; symp < symtab_end; symp++)
179 if (symp->st_name + strtab_start > strtab_end)
180 goto badheader;
181
182 /*
183 * Link the symbol table into the debugger.
184 */
185 if (db_add_symbol_table((char *)symtab_start,
186 (char *)symtab_end, name, (char *)symtab) != -1) {
187 printf("[ using %lu bytes of %s ELF symbol table ]\n",
188 (u_long)roundup(((char *)esymtab - (char *)symtab),
189 sizeof(u_long)), name);
190 return (TRUE);
191 }
192
193 return (FALSE);
194
195 badheader:
196 printf("[ %s ELF symbol table not valid ]\n", name);
197 return (FALSE);
198 }
199
200 /*
201 * Internal helper function - return a pointer to the string table
202 * for the current symbol table.
203 */
204 static char *
205 db_elf_find_strtab(stab)
206 db_symtab_t *stab;
207 {
208 Elf_Ehdr *elf = STAB_TO_EHDR(stab);
209 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
210 char *shstrtab;
211 int i;
212
213 shstrtab = (char*)elf + shp[elf->e_shstrndx].sh_offset;
214 for (i = 0; i < elf->e_shnum; i++) {
215 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
216 return ((char*)elf + shp[i].sh_offset);
217 }
218
219 return (NULL);
220 }
221
222 /*
223 * Lookup the symbol with the given name.
224 */
225 db_sym_t
226 db_elf_lookup(stab, symstr)
227 db_symtab_t *stab;
228 char *symstr;
229 {
230 Elf_Sym *symp, *symtab_start, *symtab_end;
231 char *strtab;
232
233 symtab_start = STAB_TO_SYMSTART(stab);
234 symtab_end = STAB_TO_SYMEND(stab);
235
236 strtab = db_elf_find_strtab(stab);
237 if (strtab == NULL)
238 return ((db_sym_t)0);
239
240 for (symp = symtab_start; symp < symtab_end; symp++) {
241 if (symp->st_name != 0 &&
242 db_eqname(strtab + symp->st_name, symstr, 0))
243 return ((db_sym_t)symp);
244 }
245
246 return ((db_sym_t)0);
247 }
248
249 /*
250 * Search for the symbol with the given address (matching within the
251 * provided threshold).
252 */
253 db_sym_t
254 db_elf_search_symbol(symtab, off, strategy, diffp)
255 db_symtab_t *symtab;
256 db_addr_t off;
257 db_strategy_t strategy;
258 db_expr_t *diffp; /* in/out */
259 {
260 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
261 db_expr_t diff = *diffp;
262
263 symtab_start = STAB_TO_SYMSTART(symtab);
264 symtab_end = STAB_TO_SYMEND(symtab);
265
266 rsymp = NULL;
267
268 for (symp = symtab_start; symp < symtab_end; symp++) {
269 if (symp->st_name == 0)
270 continue;
271 #if 0
272 /* This prevents me from seeing anythin in locore.s -- eeh */
273 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
274 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
275 continue;
276 #endif
277
278 if (off >= symp->st_value) {
279 if ((off - symp->st_value) < diff) {
280 diff = off - symp->st_value;
281 rsymp = symp;
282 if (diff == 0) {
283 if (strategy == DB_STGY_PROC &&
284 ELFDEFNNAME(ST_TYPE)(symp->st_info)
285 == STT_FUNC &&
286 ELFDEFNNAME(ST_BIND)(symp->st_info)
287 != STB_LOCAL)
288 break;
289 if (strategy == DB_STGY_ANY &&
290 ELFDEFNNAME(ST_BIND)(symp->st_info)
291 != STB_LOCAL)
292 break;
293 }
294 } else if ((off - symp->st_value) == diff) {
295 if (rsymp == NULL)
296 rsymp = symp;
297 else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info)
298 == STB_LOCAL &&
299 ELFDEFNNAME(ST_BIND)(symp->st_info)
300 != STB_LOCAL) {
301 /* pick the external symbol */
302 rsymp = symp;
303 }
304 }
305 }
306 }
307
308 if (rsymp == NULL)
309 *diffp = off;
310 else
311 *diffp = diff;
312
313 return ((db_sym_t)rsymp);
314 }
315
316 /*
317 * Return the name and value for a symbol.
318 */
319 void
320 db_elf_symbol_values(symtab, sym, namep, valuep)
321 db_symtab_t *symtab;
322 db_sym_t sym;
323 char **namep;
324 db_expr_t *valuep;
325 {
326 Elf_Sym *symp = (Elf_Sym *)sym;
327 char *strtab;
328
329 if (namep) {
330 strtab = db_elf_find_strtab(symtab);
331 if (strtab == NULL)
332 *namep = NULL;
333 else
334 *namep = strtab + symp->st_name;
335 }
336
337 if (valuep)
338 *valuep = symp->st_value;
339 }
340
341 /*
342 * Return the file and line number of the current program counter
343 * if we can find the appropriate debugging symbol.
344 */
345 boolean_t
346 db_elf_line_at_pc(symtab, cursym, filename, linenum, off)
347 db_symtab_t *symtab;
348 db_sym_t cursym;
349 char **filename;
350 int *linenum;
351 db_expr_t off;
352 {
353
354 /*
355 * XXX We don't support this (yet).
356 */
357 return (FALSE);
358 }
359
360 /*
361 * Returns the number of arguments to a function and their
362 * names if we can find the appropriate debugging symbol.
363 */
364 boolean_t
365 db_elf_sym_numargs(symtab, cursym, nargp, argnamep)
366 db_symtab_t *symtab;
367 db_sym_t cursym;
368 int *nargp;
369 char **argnamep;
370 {
371
372 /*
373 * XXX We don't support this (yet).
374 */
375 return (FALSE);
376 }
377
378 void
379 db_elf_forall(stab, db_forall_func, arg)
380 db_symtab_t *stab;
381 db_forall_func_t db_forall_func;
382 void *arg;
383 {
384 char *strtab;
385 static char suffix[2];
386 Elf_Sym *symp, *symtab_start, *symtab_end;
387
388 symtab_start = STAB_TO_SYMSTART(stab);
389 symtab_end = STAB_TO_SYMEND(stab);
390
391 strtab = db_elf_find_strtab(stab);
392 if (strtab == NULL)
393 return;
394
395 for (symp = symtab_start; symp < symtab_end; symp++)
396 if (symp->st_name != 0) {
397 suffix[1] = '\0';
398 switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
399 case STT_OBJECT:
400 suffix[0] = '+';
401 break;
402 case STT_FUNC:
403 suffix[0] = '*';
404 break;
405 case STT_SECTION:
406 suffix[0] = '&';
407 break;
408 case STT_FILE:
409 suffix[0] = '/';
410 break;
411 default:
412 suffix[0] = '\0';
413 }
414 (*db_forall_func)(stab, (db_sym_t)symp,
415 strtab + symp->st_name, suffix, 0, arg);
416 }
417 return;
418 }
419 #endif /* DB_ELF_SYMBOLS */
420