db_elf.c revision 1.11 1 /* $NetBSD: db_elf.c,v 1.11 2000/05/22 14:49:10 jhawk 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 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 *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 * We need to avoid the section header string table (small string
151 * table which names the sections). We do this by assuming that
152 * the following two conditions will be true:
153 *
154 * (1) .shstrtab will be smaller than one page.
155 * (2) .strtab will be larger than one page.
156 *
157 * When we encounter what we think is the .shstrtab, we change
158 * its section type Elf_sht_null so that it will be ignored
159 * later.
160 */
161 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
162 for (i = 0; i < elf->e_shnum; i++) {
163 switch (shp[i].sh_type) {
164 case SHT_STRTAB:
165 if (shp[i].sh_size < NBPG) {
166 shp[i].sh_type = SHT_NULL;
167 continue;
168 }
169 if (strtab_start != NULL)
170 goto multiple_strtab;
171 strtab_start = (char *)symtab + shp[i].sh_offset;
172 strtab_end = (char *)symtab + shp[i].sh_offset +
173 shp[i].sh_size;
174 break;
175
176 case SHT_SYMTAB:
177 if (symtab_start != NULL)
178 goto multiple_symtab;
179 symtab_start = (Elf_Sym *)((char *)symtab +
180 shp[i].sh_offset);
181 symtab_end = (Elf_Sym *)((char *)symtab +
182 shp[i].sh_offset + shp[i].sh_size);
183 break;
184
185 default:
186 /* Ignore all other sections. */
187 break;
188 }
189 }
190
191 /*
192 * Now, sanity check the symbols against the string table.
193 */
194 if (symtab_start == NULL || strtab_start == NULL ||
195 ALIGNED_POINTER(symtab_start, long) == 0 ||
196 ALIGNED_POINTER(strtab_start, long) == 0)
197 goto badheader;
198 for (symp = symtab_start; symp < symtab_end; symp++)
199 if (symp->st_name + strtab_start > strtab_end)
200 goto badheader;
201
202 /*
203 * Link the symbol table into the debugger.
204 */
205 if (db_add_symbol_table((char *)symtab_start,
206 (char *)symtab_end, name, (char *)symtab) != -1) {
207 printf("[ preserving %lu bytes of %s ELF symbol table ]\n",
208 (u_long)roundup(((char *)esymtab - (char *)symtab),
209 sizeof(u_long)), name);
210 return (TRUE);
211 }
212
213 return (FALSE);
214
215 badheader:
216 printf("[ %s ELF symbol table not valid ]\n", name);
217 return (FALSE);
218
219 multiple_strtab:
220 printf("[ %s has multiple ELF string tables ]\n", name);
221 return (FALSE);
222
223 multiple_symtab:
224 printf("[ %s has multiple ELF symbol tables ]\n", name);
225 return (FALSE);
226 }
227
228 /*
229 * Internal helper function - return a pointer to the string table
230 * for the current symbol table.
231 */
232 static char *
233 db_elf_find_strtab(stab)
234 db_symtab_t *stab;
235 {
236 Elf_Ehdr *elf = STAB_TO_EHDR(stab);
237 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
238 int i;
239
240 for (i = 0; i < elf->e_shnum; i++) {
241 if (shp[i].sh_type == SHT_STRTAB)
242 return (stab->private + shp[i].sh_offset);
243 }
244
245 return (NULL);
246 }
247
248 /*
249 * Lookup the symbol with the given name.
250 */
251 db_sym_t
252 db_elf_lookup(stab, symstr)
253 db_symtab_t *stab;
254 char *symstr;
255 {
256 Elf_Sym *symp, *symtab_start, *symtab_end;
257 char *strtab;
258
259 symtab_start = STAB_TO_SYMSTART(stab);
260 symtab_end = STAB_TO_SYMEND(stab);
261
262 strtab = db_elf_find_strtab(stab);
263 if (strtab == NULL)
264 return ((db_sym_t)0);
265
266 for (symp = symtab_start; symp < symtab_end; symp++) {
267 if (symp->st_name != 0 &&
268 db_eqname(strtab + symp->st_name, symstr, 0))
269 return ((db_sym_t)symp);
270 }
271
272 return ((db_sym_t)0);
273 }
274
275 /*
276 * Search for the symbol with the given address (matching within the
277 * provided threshold).
278 */
279 db_sym_t
280 db_elf_search_symbol(symtab, off, strategy, diffp)
281 db_symtab_t *symtab;
282 db_addr_t off;
283 db_strategy_t strategy;
284 db_expr_t *diffp; /* in/out */
285 {
286 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
287 db_expr_t diff = *diffp;
288
289 symtab_start = STAB_TO_SYMSTART(symtab);
290 symtab_end = STAB_TO_SYMEND(symtab);
291
292 rsymp = NULL;
293
294 for (symp = symtab_start; symp < symtab_end; symp++) {
295 if (symp->st_name == 0)
296 continue;
297 #if 0
298 /* This prevents me from seeing anythin in locore.s -- eeh */
299 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
300 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
301 continue;
302 #endif
303
304 if (off >= symp->st_value) {
305 if ((off - symp->st_value) < diff) {
306 diff = off - symp->st_value;
307 rsymp = symp;
308 if (diff == 0) {
309 if (strategy == DB_STGY_PROC &&
310 ELFDEFNNAME(ST_TYPE)(symp->st_info)
311 == STT_FUNC &&
312 ELFDEFNNAME(ST_BIND)(symp->st_info)
313 != STB_LOCAL)
314 break;
315 if (strategy == DB_STGY_ANY &&
316 ELFDEFNNAME(ST_BIND)(symp->st_info)
317 != STB_LOCAL)
318 break;
319 }
320 } else if ((off - symp->st_value) == diff) {
321 if (rsymp == NULL)
322 rsymp = symp;
323 else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info)
324 == STB_LOCAL &&
325 ELFDEFNNAME(ST_BIND)(symp->st_info)
326 != STB_LOCAL) {
327 /* pick the external symbol */
328 rsymp = symp;
329 }
330 }
331 }
332 }
333
334 if (rsymp == NULL)
335 *diffp = off;
336 else
337 *diffp = diff;
338
339 return ((db_sym_t)rsymp);
340 }
341
342 /*
343 * Return the name and value for a symbol.
344 */
345 void
346 db_elf_symbol_values(symtab, sym, namep, valuep)
347 db_symtab_t *symtab;
348 db_sym_t sym;
349 char **namep;
350 db_expr_t *valuep;
351 {
352 Elf_Sym *symp = (Elf_Sym *)sym;
353 char *strtab;
354
355 if (namep) {
356 strtab = db_elf_find_strtab(symtab);
357 if (strtab == NULL)
358 *namep = NULL;
359 else
360 *namep = strtab + symp->st_name;
361 }
362
363 if (valuep)
364 *valuep = symp->st_value;
365 }
366
367 /*
368 * Return the file and line number of the current program counter
369 * if we can find the appropriate debugging symbol.
370 */
371 boolean_t
372 db_elf_line_at_pc(symtab, cursym, filename, linenum, off)
373 db_symtab_t *symtab;
374 db_sym_t cursym;
375 char **filename;
376 int *linenum;
377 db_expr_t off;
378 {
379
380 /*
381 * XXX We don't support this (yet).
382 */
383 return (FALSE);
384 }
385
386 /*
387 * Returns the number of arguments to a function and their
388 * names if we can find the appropriate debugging symbol.
389 */
390 boolean_t
391 db_elf_sym_numargs(symtab, cursym, nargp, argnamep)
392 db_symtab_t *symtab;
393 db_sym_t cursym;
394 int *nargp;
395 char **argnamep;
396 {
397
398 /*
399 * XXX We don't support this (yet).
400 */
401 return (FALSE);
402 }
403
404 void
405 db_elf_forall(stab, db_forall_func, arg)
406 db_symtab_t *stab;
407 db_forall_func_t db_forall_func;
408 void *arg;
409 {
410 char *strtab;
411 static char suffix[2];
412 Elf_Sym *symp, *symtab_start, *symtab_end;
413
414 symtab_start = STAB_TO_SYMSTART(stab);
415 symtab_end = STAB_TO_SYMEND(stab);
416
417 strtab = db_elf_find_strtab(stab);
418 if (strtab == NULL)
419 return;
420
421 for (symp = symtab_start; symp < symtab_end; symp++)
422 if (symp->st_name != 0) {
423 suffix[1] = '\0';
424 switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
425 case STT_OBJECT:
426 suffix[0] = '+';
427 break;
428 case STT_FUNC:
429 suffix[0] = '*';
430 break;
431 case STT_SECTION:
432 suffix[0] = '&';
433 break;
434 case STT_FILE:
435 suffix[0] = '/';
436 break;
437 default:
438 suffix[0] = '\0';
439 }
440 (*db_forall_func)(stab, (db_sym_t)symp,
441 strtab + symp->st_name, suffix, 0, arg);
442 }
443 return;
444 }
445 #endif /* DB_ELF_SYMBOLS */
446