FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_elf.c
1 /* $OpenBSD: db_elf.c,v 1.32 2021/03/12 10:22:46 jsg 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(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
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 char *
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 char *shstrtab;
194 int i;
195
196 shstrtab = (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 ((char *)elf + shp[shp[i].sh_link].sh_offset);
200 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
201 return ((char *)elf + shp[i].sh_offset);
202 }
203
204 return (NULL);
205 }
206
207 /*
208 * Internal helper function - return a pointer to the section
209 * named ``sname''.
210 */
211 const char *
212 db_elf_find_section(db_symtab_t *stab, size_t *size, const char *sname)
213 {
214 Elf_Ehdr *elf = STAB_TO_EHDR(stab);
215 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
216 char *shstrtab;
217 int i;
218
219 shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
220 for (i = 0; i < elf->e_shnum; i++) {
221 if ((shp[i].sh_flags & SHF_ALLOC) != 0 &&
222 strcmp(sname, shstrtab+shp[i].sh_name) == 0) {
223 *size = shp[i].sh_size;
224 return ((char *)elf + shp[i].sh_offset);
225 }
226 }
227
228 return (NULL);
229 }
230
231 /*
232 * Lookup the symbol with the given name.
233 */
234 Elf_Sym *
235 db_elf_sym_lookup(char *symstr)
236 {
237 db_symtab_t *stab = &db_symtab;
238 Elf_Sym *symp, *symtab_start, *symtab_end;
239 char *strtab;
240
241 if (stab->private == NULL)
242 return (NULL);
243
244 symtab_start = STAB_TO_SYMSTART(stab);
245 symtab_end = STAB_TO_SYMEND(stab);
246
247 strtab = db_elf_find_strtab(stab);
248 if (strtab == NULL)
249 return (NULL);
250
251 for (symp = symtab_start; symp < symtab_end; symp++) {
252 if (symp->st_name != 0 &&
253 db_eqname(strtab + symp->st_name, symstr, 0))
254 return (symp);
255 }
256
257 return (NULL);
258 }
259
260 /*
261 * Search for the symbol with the given address (matching within the
262 * provided threshold).
263 */
264 Elf_Sym *
265 db_elf_sym_search(vaddr_t off, db_strategy_t strategy, db_expr_t *diffp)
266 {
267 db_symtab_t *stab = &db_symtab;
268 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
269 db_expr_t diff = *diffp;
270
271 if (stab->private == NULL)
272 return (NULL);
273
274 symtab_start = STAB_TO_SYMSTART(stab);
275 symtab_end = STAB_TO_SYMEND(stab);
276
277 rsymp = NULL;
278
279 for (symp = symtab_start; symp < symtab_end; symp++) {
280 if (symp->st_name == 0)
281 continue;
282 #if 0
283 /* This prevents me from seeing anythin in locore.s -- eeh */
284 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
285 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
286 continue;
287 #endif
288
289 if (off >= symp->st_value) {
290 if ((off - symp->st_value) < diff) {
291 diff = off - symp->st_value;
292 rsymp = symp;
293 if (diff == 0) {
294 if (strategy == DB_STGY_PROC &&
295 ELF_ST_TYPE(symp->st_info)
296 == STT_FUNC &&
297 ELF_ST_BIND(symp->st_info)
298 != STB_LOCAL)
299 break;
300 if (strategy == DB_STGY_ANY &&
301 ELF_ST_BIND(symp->st_info)
302 != STB_LOCAL)
303 break;
304 }
305 } else if ((off - symp->st_value) == diff) {
306 if (rsymp == NULL)
307 rsymp = symp;
308 else if (ELF_ST_BIND(rsymp->st_info)
309 == STB_LOCAL &&
310 ELF_ST_BIND(symp->st_info)
311 != STB_LOCAL) {
312 /* pick the external symbol */
313 rsymp = symp;
314 }
315 }
316 }
317 }
318
319 if (rsymp == NULL)
320 *diffp = off;
321 else
322 *diffp = diff;
323
324 return (rsymp);
325 }
326
327 /*
328 * Return the name and value for a symbol.
329 */
330 void
331 db_symbol_values(Elf_Sym *sym, char **namep, db_expr_t *valuep)
332 {
333 db_symtab_t *stab = &db_symtab;
334 Elf_Sym *symp = (Elf_Sym *)sym;
335 char *strtab;
336
337 if (sym == NULL) {
338 *namep = NULL;
339 return;
340 }
341
342 if (stab->private == NULL)
343 return;
344
345 if (namep) {
346 strtab = db_elf_find_strtab(stab);
347 if (strtab == NULL)
348 *namep = NULL;
349 else
350 *namep = strtab + symp->st_name;
351 }
352
353 if (valuep)
354 *valuep = symp->st_value;
355 }
356
357 /*
358 * Return the file and line number of the current program counter
359 * if we can find the appropriate debugging symbol.
360 */
361 int
362 db_elf_line_at_pc(Elf_Sym *cursym, char **filename,
363 int *linenum, db_expr_t off)
364 {
365 db_symtab_t *stab = &db_symtab;
366 static char path[PATH_MAX];
367 const char *linetab, *dirname, *basename;
368 size_t linetab_size;
369
370 if (stab->private == NULL)
371 return (0);
372
373 linetab = db_elf_find_section(stab, &linetab_size, ".debug_line");
374 if (linetab == NULL)
375 return (0);
376
377 if (!db_dwarf_line_at_pc(linetab, linetab_size, off,
378 &dirname, &basename, linenum))
379 return (0);
380
381 if (dirname == NULL)
382 strlcpy(path, basename, sizeof(path));
383 else
384 snprintf(path, sizeof(path), "%s/%s", dirname, basename);
385 *filename = path;
386 return (1);
387 }
388
389 void
390 db_elf_sym_forall(db_forall_func_t db_forall_func, void *arg)
391 {
392 db_symtab_t *stab = &db_symtab;
393 char *strtab;
394 static char suffix[2];
395 Elf_Sym *symp, *symtab_start, *symtab_end;
396
397 if (stab->private == NULL)
398 return;
399
400 symtab_start = STAB_TO_SYMSTART(stab);
401 symtab_end = STAB_TO_SYMEND(stab);
402
403 strtab = db_elf_find_strtab(stab);
404 if (strtab == NULL)
405 return;
406
407 for (symp = symtab_start; symp < symtab_end; symp++)
408 if (symp->st_name != 0) {
409 suffix[1] = '\0';
410 switch (ELF_ST_TYPE(symp->st_info)) {
411 case STT_OBJECT:
412 suffix[0] = '+';
413 break;
414 case STT_FUNC:
415 suffix[0] = '*';
416 break;
417 case STT_SECTION:
418 suffix[0] = '&';
419 break;
420 case STT_FILE:
421 suffix[0] = '/';
422 break;
423 default:
424 suffix[0] = '\0';
425 }
426 (*db_forall_func)(symp,
427 strtab + symp->st_name, suffix, 0, arg);
428 }
429 }
430
431 Elf_Sym *
432 db_symbol_by_name(char *name, db_expr_t *valuep)
433 {
434 Elf_Sym *sym;
435
436 sym = db_elf_sym_lookup(name);
437 if (sym == NULL)
438 return (NULL);
439 db_symbol_values(sym, &name, valuep);
440 return (sym);
441 }
Cache object: 7da2b6ef92d7a7677748e04ef87a0759
|