Line data Source code
1 : /* $OpenBSD: db_elf.c,v 1.28 2017/09/08 05:36:52 deraadt 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 boundry
58 : */
59 : int
60 0 : 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 0 : elf = (Elf_Ehdr *)symtab;
96 0 : if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
97 0 : elf->e_ident[EI_CLASS] != ELFCLASS) {
98 : errstr = "bad magic";
99 0 : goto badheader;
100 : }
101 :
102 0 : if (elf->e_machine != ELF_TARG_MACH) {
103 : errstr = "bad e_machine";
104 0 : 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 0 : shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
115 0 : shstrtab = (char *)symtab + shp[elf->e_shstrndx].sh_offset;
116 0 : for (i = 0; i < elf->e_shnum; i++) {
117 0 : if (shp[i].sh_type == SHT_SYMTAB) {
118 : int j;
119 :
120 0 : if (shp[i].sh_offset == 0)
121 0 : continue;
122 0 : symtab_start = (Elf_Sym *)((char *)symtab +
123 : shp[i].sh_offset);
124 0 : symtab_end = (Elf_Sym *)((char *)symtab +
125 0 : shp[i].sh_offset + shp[i].sh_size);
126 0 : j = shp[i].sh_link;
127 0 : if (shp[j].sh_offset == 0)
128 0 : continue;
129 0 : strtab_start = (char *)symtab + shp[j].sh_offset;
130 0 : strtab_end = (char *)symtab + shp[j].sh_offset +
131 0 : shp[j].sh_size;
132 0 : break;
133 : }
134 :
135 : /*
136 : * This is the old way of doing things.
137 : * XXX - verify that it's not needed.
138 : */
139 0 : if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
140 0 : strtab_start = (char *)symtab + shp[i].sh_offset;
141 0 : strtab_end = (char *)symtab + shp[i].sh_offset +
142 0 : shp[i].sh_size;
143 0 : } else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
144 0 : symtab_start = (Elf_Sym *)((char *)symtab +
145 0 : shp[i].sh_offset);
146 0 : symtab_end = (Elf_Sym *)((char *)symtab +
147 0 : shp[i].sh_offset + shp[i].sh_size);
148 0 : }
149 : }
150 :
151 : /*
152 : * Now, sanity check the symbols against the string table.
153 : */
154 0 : if (symtab_start == NULL || strtab_start == NULL ||
155 : ALIGNED_POINTER(symtab_start, long) == 0 ||
156 : ALIGNED_POINTER(strtab_start, long) == 0) {
157 : errstr = "symtab unaligned";
158 0 : goto badheader;
159 : }
160 0 : for (symp = symtab_start; symp < symtab_end; symp++)
161 0 : if (symp->st_name + strtab_start > strtab_end) {
162 : errstr = "symtab corrupted";
163 0 : goto badheader;
164 : }
165 :
166 : /*
167 : * Link the symbol table into the debugger.
168 : */
169 0 : db_symtab.start = (char *)symtab_start;
170 0 : db_symtab.end = (char *)symtab_end;
171 0 : db_symtab.name = name;
172 0 : db_symtab.private = (char *)symtab;
173 :
174 0 : db_printf("[ using %lu bytes of %s ELF symbol table ]\n",
175 0 : (u_long)roundup(((char *)esymtab - (char *)symtab), sizeof(u_long)),
176 : name);
177 :
178 0 : return (1);
179 :
180 : badheader:
181 0 : db_printf("[ %s ELF symbol table not valid: %s ]\n", name, errstr);
182 0 : return (0);
183 0 : }
184 :
185 : /*
186 : * Internal helper function - return a pointer to the string table
187 : * for the current symbol table.
188 : */
189 : char *
190 0 : db_elf_find_strtab(db_symtab_t *stab)
191 : {
192 0 : Elf_Ehdr *elf = STAB_TO_EHDR(stab);
193 0 : Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
194 : char *shstrtab;
195 : int i;
196 :
197 0 : shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
198 0 : for (i = 0; i < elf->e_shnum; i++) {
199 0 : if (shp[i].sh_type == SHT_SYMTAB)
200 0 : return ((char *)elf + shp[shp[i].sh_link].sh_offset);
201 0 : if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
202 0 : return ((char *)elf + shp[i].sh_offset);
203 : }
204 :
205 0 : return (NULL);
206 0 : }
207 :
208 : /*
209 : * Internal helper function - return a pointer to the section
210 : * named ``sname''.
211 : */
212 : const char *
213 0 : db_elf_find_section(db_symtab_t *stab, size_t *size, const char *sname)
214 : {
215 0 : Elf_Ehdr *elf = STAB_TO_EHDR(stab);
216 0 : Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
217 : char *shstrtab;
218 : int i;
219 :
220 0 : shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
221 0 : for (i = 0; i < elf->e_shnum; i++) {
222 0 : if ((shp[i].sh_flags & SHF_ALLOC) != 0 &&
223 0 : strcmp(sname, shstrtab+shp[i].sh_name) == 0) {
224 0 : *size = shp[i].sh_size;
225 0 : return ((char *)elf + shp[i].sh_offset);
226 : }
227 : }
228 :
229 0 : return (NULL);
230 0 : }
231 :
232 : /*
233 : * Lookup the symbol with the given name.
234 : */
235 : Elf_Sym *
236 0 : db_elf_sym_lookup(char *symstr)
237 : {
238 : db_symtab_t *stab = &db_symtab;
239 : Elf_Sym *symp, *symtab_start, *symtab_end;
240 : char *strtab;
241 :
242 0 : if (stab->private == NULL)
243 0 : return (NULL);
244 :
245 0 : symtab_start = STAB_TO_SYMSTART(stab);
246 0 : symtab_end = STAB_TO_SYMEND(stab);
247 :
248 0 : strtab = db_elf_find_strtab(stab);
249 0 : if (strtab == NULL)
250 0 : return (NULL);
251 :
252 0 : for (symp = symtab_start; symp < symtab_end; symp++) {
253 0 : if (symp->st_name != 0 &&
254 0 : db_eqname(strtab + symp->st_name, symstr, 0))
255 0 : return (symp);
256 : }
257 :
258 0 : return (NULL);
259 0 : }
260 :
261 : /*
262 : * Search for the symbol with the given address (matching within the
263 : * provided threshold).
264 : */
265 : Elf_Sym *
266 0 : db_elf_sym_search(db_addr_t off, db_strategy_t strategy,
267 : db_expr_t *diffp)
268 : {
269 : db_symtab_t *stab = &db_symtab;
270 : Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
271 0 : db_expr_t diff = *diffp;
272 :
273 0 : if (stab->private == NULL)
274 0 : return (NULL);
275 :
276 0 : symtab_start = STAB_TO_SYMSTART(stab);
277 0 : symtab_end = STAB_TO_SYMEND(stab);
278 :
279 : rsymp = NULL;
280 :
281 0 : for (symp = symtab_start; symp < symtab_end; symp++) {
282 0 : if (symp->st_name == 0)
283 : continue;
284 : #if 0
285 : /* This prevents me from seeing anythin in locore.s -- eeh */
286 : if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
287 : ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
288 : continue;
289 : #endif
290 :
291 0 : if (off >= symp->st_value) {
292 0 : if ((off - symp->st_value) < diff) {
293 : diff = off - symp->st_value;
294 : rsymp = symp;
295 0 : if (diff == 0) {
296 0 : if (strategy == DB_STGY_PROC &&
297 0 : ELF_ST_TYPE(symp->st_info)
298 0 : == STT_FUNC &&
299 0 : ELF_ST_BIND(symp->st_info)
300 0 : != STB_LOCAL)
301 : break;
302 0 : if (strategy == DB_STGY_ANY &&
303 0 : ELF_ST_BIND(symp->st_info)
304 0 : != STB_LOCAL)
305 : break;
306 : }
307 0 : } else if ((off - symp->st_value) == diff) {
308 0 : if (rsymp == NULL)
309 0 : rsymp = symp;
310 0 : else if (ELF_ST_BIND(rsymp->st_info)
311 0 : == STB_LOCAL &&
312 0 : ELF_ST_BIND(symp->st_info)
313 0 : != STB_LOCAL) {
314 : /* pick the external symbol */
315 : rsymp = symp;
316 0 : }
317 : }
318 : }
319 : }
320 :
321 0 : if (rsymp == NULL)
322 0 : *diffp = off;
323 : else
324 0 : *diffp = diff;
325 :
326 0 : return (rsymp);
327 0 : }
328 :
329 : /*
330 : * Return the name and value for a symbol.
331 : */
332 : void
333 0 : db_symbol_values(Elf_Sym *sym, char **namep, db_expr_t *valuep)
334 : {
335 : db_symtab_t *stab = &db_symtab;
336 : Elf_Sym *symp = (Elf_Sym *)sym;
337 : char *strtab;
338 :
339 0 : if (sym == NULL) {
340 0 : *namep = NULL;
341 0 : return;
342 : }
343 :
344 0 : if (stab->private == NULL)
345 0 : return;
346 :
347 0 : if (namep) {
348 0 : strtab = db_elf_find_strtab(stab);
349 0 : if (strtab == NULL)
350 0 : *namep = NULL;
351 : else
352 0 : *namep = strtab + symp->st_name;
353 : }
354 :
355 0 : if (valuep)
356 0 : *valuep = symp->st_value;
357 0 : }
358 :
359 : /*
360 : * Return the file and line number of the current program counter
361 : * if we can find the appropriate debugging symbol.
362 : */
363 : int
364 0 : db_elf_line_at_pc(Elf_Sym *cursym, char **filename,
365 : int *linenum, db_expr_t off)
366 : {
367 : db_symtab_t *stab = &db_symtab;
368 : static char path[PATH_MAX];
369 0 : const char *linetab, *dirname, *basename;
370 0 : size_t linetab_size;
371 :
372 0 : if (stab->private == NULL)
373 0 : return (0);
374 :
375 0 : linetab = db_elf_find_section(stab, &linetab_size, ".debug_line");
376 0 : if (linetab == NULL)
377 0 : return (0);
378 :
379 0 : if (!db_dwarf_line_at_pc(linetab, linetab_size, off,
380 : &dirname, &basename, linenum))
381 0 : return (0);
382 :
383 0 : if (dirname == NULL)
384 0 : strlcpy(path, basename, sizeof(path));
385 : else
386 0 : snprintf(path, sizeof(path), "%s/%s", dirname, basename);
387 0 : *filename = path;
388 0 : return (1);
389 0 : }
390 :
391 : void
392 0 : db_elf_sym_forall(db_forall_func_t db_forall_func, void *arg)
393 : {
394 : db_symtab_t *stab = &db_symtab;
395 : char *strtab;
396 : static char suffix[2];
397 : Elf_Sym *symp, *symtab_start, *symtab_end;
398 :
399 0 : if (stab->private == NULL)
400 0 : return;
401 :
402 0 : symtab_start = STAB_TO_SYMSTART(stab);
403 0 : symtab_end = STAB_TO_SYMEND(stab);
404 :
405 0 : strtab = db_elf_find_strtab(stab);
406 0 : if (strtab == NULL)
407 0 : return;
408 :
409 0 : for (symp = symtab_start; symp < symtab_end; symp++)
410 0 : if (symp->st_name != 0) {
411 0 : suffix[1] = '\0';
412 0 : switch (ELF_ST_TYPE(symp->st_info)) {
413 : case STT_OBJECT:
414 0 : suffix[0] = '+';
415 0 : break;
416 : case STT_FUNC:
417 0 : suffix[0] = '*';
418 0 : break;
419 : case STT_SECTION:
420 0 : suffix[0] = '&';
421 0 : break;
422 : case STT_FILE:
423 0 : suffix[0] = '/';
424 0 : break;
425 : default:
426 0 : suffix[0] = '\0';
427 0 : }
428 0 : (*db_forall_func)(symp,
429 0 : strtab + symp->st_name, suffix, 0, arg);
430 0 : }
431 0 : }
432 :
433 : Elf_Sym *
434 0 : db_symbol_by_name(char *name, db_expr_t *valuep)
435 : {
436 : Elf_Sym *sym;
437 :
438 0 : sym = db_elf_sym_lookup(name);
439 0 : if (sym == NULL)
440 0 : return (NULL);
441 0 : db_symbol_values(sym, &name, valuep);
442 0 : return (sym);
443 0 : }
|