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