1 /* $OpenBSD: db_elf.c,v 1.34 2024/11/07 16:02:29 miod 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 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/stdint.h>
36 #include <sys/systm.h>
37 #include <sys/exec.h>
38
39 #include <machine/db_machdep.h>
40
41 #include <ddb/db_elf.h>
42 #include <ddb/db_sym.h>
43 #include <ddb/db_output.h>
44
45 #include <sys/exec_elf.h>
46
47 db_symtab_t db_symtab;
48
49 Elf_Sym *db_elf_sym_lookup(const char *);
50
51 /*
52 * Find the symbol table and strings; tell ddb about them.
53 *
54 * symsize: size of symbol table
55 * symtab: pointer to start of symbol table
56 * esymtab: pointer to end of string table, for checking - rounded up to
57 * integer boundary
58 */
59 int
db_elf_sym_init(int symsize,void * symtab,void * esymtab,const char * name)60 db_elf_sym_init(int symsize, void *symtab, void *esymtab, const char *name)
61 {
62 Elf_Ehdr *elf;
63 Elf_Shdr *shp;
64 Elf_Sym *symp, *symtab_start, *symtab_end;
65 char *shstrtab, *strtab_start, *strtab_end;
66 int i;
67 char *errstr = "";
68
69 if (ALIGNED_POINTER(symtab, long) == 0) {
70 db_printf("[ %s symbol table has bad start address %p ]\n",
71 name, symtab);
72 return (0);
73 }
74
75 symtab_start = symtab_end = NULL;
76 strtab_start = strtab_end = NULL;
77
78 /*
79 * The format of the symbols loaded by the boot program is:
80 *
81 * Elf exec header
82 * first section header
83 * . . .
84 * . . .
85 * last section header
86 * first symbol, string, or line table section
87 * . . .
88 * . . .
89 * last symbol, string, or line table section
90 */
91
92 /*
93 * Validate the Elf header.
94 */
95 elf = (Elf_Ehdr *)symtab;
96 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
97 elf->e_ident[EI_CLASS] != ELFCLASS) {
98 errstr = "bad magic";
99 goto badheader;
100 }
101
102 if (elf->e_machine != ELF_TARG_MACH) {
103 errstr = "bad e_machine";
104 goto badheader;
105 }
106
107 /*
108 * Find the section header string table (.shstrtab), and look up
109 * the symbol table (.symtab) and string table (.strtab) via their
110 * names in shstrtab, rather than by table type.
111 * This works in the presence of multiple string tables, such as
112 * stabs data found when booting bsd.gdb.
113 */
114 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
115 shstrtab = (char *)symtab + shp[elf->e_shstrndx].sh_offset;
116 for (i = 0; i < elf->e_shnum; i++) {
117 if (shp[i].sh_type == SHT_SYMTAB) {
118 int j;
119
120 if (shp[i].sh_offset == 0)
121 continue;
122 symtab_start = (Elf_Sym *)((char *)symtab +
123 shp[i].sh_offset);
124 symtab_end = (Elf_Sym *)((char *)symtab +
125 shp[i].sh_offset + shp[i].sh_size);
126 j = shp[i].sh_link;
127 if (shp[j].sh_offset == 0)
128 continue;
129 strtab_start = (char *)symtab + shp[j].sh_offset;
130 strtab_end = (char *)symtab + shp[j].sh_offset +
131 shp[j].sh_size;
132 break;
133 }
134
135 /*
136 * This is the old way of doing things.
137 * XXX - verify that it's not needed.
138 */
139 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
140 strtab_start = (char *)symtab + shp[i].sh_offset;
141 strtab_end = (char *)symtab + shp[i].sh_offset +
142 shp[i].sh_size;
143 } else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
144 symtab_start = (Elf_Sym *)((char *)symtab +
145 shp[i].sh_offset);
146 symtab_end = (Elf_Sym *)((char *)symtab +
147 shp[i].sh_offset + shp[i].sh_size);
148 }
149 }
150
151 /*
152 * Now, sanity check the symbols against the string table.
153 */
154 if (symtab_start == NULL || strtab_start == NULL ||
155 ALIGNED_POINTER(symtab_start, long) == 0) {
156 errstr = "symtab unaligned";
157 goto badheader;
158 }
159 for (symp = symtab_start; symp < symtab_end; symp++)
160 if (symp->st_name + strtab_start > strtab_end) {
161 errstr = "symtab corrupted";
162 goto badheader;
163 }
164
165 /*
166 * Link the symbol table into the debugger.
167 */
168 db_symtab.start = (char *)symtab_start;
169 db_symtab.end = (char *)symtab_end;
170 db_symtab.name = name;
171 db_symtab.private = (char *)symtab;
172
173 db_printf("[ using %lu bytes of %s ELF symbol table ]\n",
174 (u_long)roundup(((char *)esymtab - (char *)symtab), sizeof(u_long)),
175 name);
176
177 return (1);
178
179 badheader:
180 db_printf("[ %s ELF symbol table not valid: %s ]\n", name, errstr);
181 return (0);
182 }
183
184 /*
185 * Internal helper function - return a pointer to the string table
186 * for the current symbol table.
187 */
188 const char *
db_elf_find_strtab(db_symtab_t * stab)189 db_elf_find_strtab(db_symtab_t *stab)
190 {
191 Elf_Ehdr *elf = STAB_TO_EHDR(stab);
192 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
193 const char *shstrtab;
194 int i;
195
196 shstrtab = (const char *)elf + shp[elf->e_shstrndx].sh_offset;
197 for (i = 0; i < elf->e_shnum; i++) {
198 if (shp[i].sh_type == SHT_SYMTAB)
199 return ((const char *)elf +
200 shp[shp[i].sh_link].sh_offset);
201 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
202 return ((const char *)elf + shp[i].sh_offset);
203 }
204
205 return (NULL);
206 }
207
208 /*
209 * Internal helper function - return a pointer to the section
210 * named ``sname''.
211 */
212 const char *
db_elf_find_section(db_symtab_t * stab,size_t * size,const char * sname)213 db_elf_find_section(db_symtab_t *stab, size_t *size, const char *sname)
214 {
215 Elf_Ehdr *elf = STAB_TO_EHDR(stab);
216 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
217 char *shstrtab;
218 int i;
219
220 shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
221 for (i = 0; i < elf->e_shnum; i++) {
222 if ((shp[i].sh_flags & SHF_ALLOC) != 0 &&
223 strcmp(sname, shstrtab+shp[i].sh_name) == 0) {
224 *size = shp[i].sh_size;
225 return ((char *)elf + shp[i].sh_offset);
226 }
227 }
228
229 return (NULL);
230 }
231
232 /*
233 * Lookup the symbol with the given name.
234 */
235 Elf_Sym *
db_elf_sym_lookup(const char * symstr)236 db_elf_sym_lookup(const char *symstr)
237 {
238 db_symtab_t *stab = &db_symtab;
239 Elf_Sym *symp, *symtab_start, *symtab_end;
240 const char *strtab;
241
242 if (stab->private == NULL)
243 return (NULL);
244
245 symtab_start = STAB_TO_SYMSTART(stab);
246 symtab_end = STAB_TO_SYMEND(stab);
247
248 strtab = db_elf_find_strtab(stab);
249 if (strtab == NULL)
250 return (NULL);
251
252 for (symp = symtab_start; symp < symtab_end; symp++) {
253 if (symp->st_name != 0 &&
254 db_eqname(strtab + symp->st_name, symstr, 0))
255 return (symp);
256 }
257
258 return (NULL);
259 }
260
261 /*
262 * Search for the symbol with the given address (matching within the
263 * provided threshold).
264 */
265 Elf_Sym *
db_elf_sym_search(vaddr_t off,db_strategy_t strategy,db_expr_t * diffp)266 db_elf_sym_search(vaddr_t off, db_strategy_t strategy, db_expr_t *diffp)
267 {
268 db_symtab_t *stab = &db_symtab;
269 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
270 db_expr_t diff = *diffp;
271
272 if (stab->private == NULL)
273 return (NULL);
274
275 symtab_start = STAB_TO_SYMSTART(stab);
276 symtab_end = STAB_TO_SYMEND(stab);
277
278 rsymp = NULL;
279
280 for (symp = symtab_start; symp < symtab_end; symp++) {
281 if (symp->st_name == 0)
282 continue;
283 #if 0
284 /* This prevents me from seeing anything in locore.s -- eeh */
285 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
286 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
287 continue;
288 #endif
289
290 if (off >= symp->st_value) {
291 if ((off - symp->st_value) < diff) {
292 diff = off - symp->st_value;
293 rsymp = symp;
294 if (diff == 0) {
295 if (strategy == DB_STGY_PROC &&
296 ELF_ST_TYPE(symp->st_info)
297 == STT_FUNC &&
298 ELF_ST_BIND(symp->st_info)
299 != STB_LOCAL)
300 break;
301 if (strategy == DB_STGY_ANY &&
302 ELF_ST_BIND(symp->st_info)
303 != STB_LOCAL)
304 break;
305 }
306 } else if ((off - symp->st_value) == diff) {
307 if (rsymp == NULL)
308 rsymp = symp;
309 else if (ELF_ST_BIND(rsymp->st_info)
310 == STB_LOCAL &&
311 ELF_ST_BIND(symp->st_info)
312 != STB_LOCAL) {
313 /* pick the external symbol */
314 rsymp = symp;
315 }
316 }
317 }
318 }
319
320 if (rsymp == NULL)
321 *diffp = off;
322 else
323 *diffp = diff;
324
325 return (rsymp);
326 }
327
328 /*
329 * Return the name and value for a symbol.
330 */
331 void
db_symbol_values(Elf_Sym * sym,const char ** namep,db_expr_t * valuep)332 db_symbol_values(Elf_Sym *sym, const char **namep, db_expr_t *valuep)
333 {
334 db_symtab_t *stab = &db_symtab;
335 Elf_Sym *symp = (Elf_Sym *)sym;
336 const char *strtab;
337
338 if (sym == NULL) {
339 *namep = NULL;
340 return;
341 }
342
343 if (stab->private == NULL)
344 return;
345
346 if (namep) {
347 strtab = db_elf_find_strtab(stab);
348 if (strtab == NULL)
349 *namep = NULL;
350 else
351 *namep = strtab + symp->st_name;
352 }
353
354 if (valuep)
355 *valuep = symp->st_value;
356 }
357
358 /*
359 * Return the file and line number of the current program counter
360 * if we can find the appropriate debugging symbol.
361 */
362 int
db_elf_line_at_pc(Elf_Sym * cursym,const char ** filename,int * linenum,db_expr_t off)363 db_elf_line_at_pc(Elf_Sym *cursym, const char **filename,
364 int *linenum, db_expr_t off)
365 {
366 db_symtab_t *stab = &db_symtab;
367 static char path[PATH_MAX];
368 const char *linetab, *dirname, *basename;
369 size_t linetab_size;
370
371 if (stab->private == NULL)
372 return (0);
373
374 linetab = db_elf_find_section(stab, &linetab_size, ".debug_line");
375 if (linetab == NULL)
376 return (0);
377
378 if (!db_dwarf_line_at_pc(linetab, linetab_size, off,
379 &dirname, &basename, linenum))
380 return (0);
381
382 if (dirname == NULL)
383 strlcpy(path, basename, sizeof(path));
384 else
385 snprintf(path, sizeof(path), "%s/%s", dirname, basename);
386 *filename = path;
387 return (1);
388 }
389
390 void
db_elf_sym_forall(db_forall_func_t db_forall_func,void * arg)391 db_elf_sym_forall(db_forall_func_t db_forall_func, void *arg)
392 {
393 db_symtab_t *stab = &db_symtab;
394 const char *strtab;
395 static char suffix[2];
396 Elf_Sym *symp, *symtab_start, *symtab_end;
397
398 if (stab->private == NULL)
399 return;
400
401 symtab_start = STAB_TO_SYMSTART(stab);
402 symtab_end = STAB_TO_SYMEND(stab);
403
404 strtab = db_elf_find_strtab(stab);
405 if (strtab == NULL)
406 return;
407
408 for (symp = symtab_start; symp < symtab_end; symp++)
409 if (symp->st_name != 0) {
410 suffix[1] = '\0';
411 switch (ELF_ST_TYPE(symp->st_info)) {
412 case STT_OBJECT:
413 suffix[0] = '+';
414 break;
415 case STT_FUNC:
416 suffix[0] = '*';
417 break;
418 case STT_SECTION:
419 suffix[0] = '&';
420 break;
421 case STT_FILE:
422 suffix[0] = '/';
423 break;
424 default:
425 suffix[0] = '\0';
426 }
427 (*db_forall_func)(symp,
428 strtab + symp->st_name, suffix, arg);
429 }
430 }
431
432 Elf_Sym *
db_symbol_by_name(const char * name,db_expr_t * valuep)433 db_symbol_by_name(const char *name, db_expr_t *valuep)
434 {
435 Elf_Sym *sym;
436
437 sym = db_elf_sym_lookup(name);
438 if (sym == NULL)
439 return (NULL);
440 db_symbol_values(sym, &name, valuep);
441 return (sym);
442 }
443