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