db_elf.c revision 1.7 1 /* $NetBSD: db_elf.c,v 1.7 1998/12/04 20:18:05 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1997 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.
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 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/proc.h>
44
45 #include <machine/db_machdep.h>
46
47 #include <ddb/db_sym.h>
48 #include <ddb/db_output.h>
49 #include <ddb/db_extern.h>
50
51 #ifdef DB_ELF_SYMBOLS
52
53 #ifndef DB_ELFSIZE
54 #error Must define DB_ELFSIZE!
55 #endif
56
57 #define ELFSIZE DB_ELFSIZE
58
59 #include <sys/exec_elf.h>
60
61 #define CONCAT(x,y) __CONCAT(x,y)
62 #define ELFDEFNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
63
64 static char *db_elf_find_strtab __P((db_symtab_t *));
65
66 #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start))
67 #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end))
68 #define STAB_TO_EHDR(stab) ((Elf_Ehdr *)((stab)->private))
69 #define STAB_TO_SHDR(stab, e) ((Elf_Shdr *)((stab)->private + (e)->e_shoff))
70
71 boolean_t db_elf_sym_init __P((int, void *, void *, const char *));
72 db_sym_t db_elf_lookup __P((db_symtab_t *, char *));
73 db_sym_t db_elf_search_symbol __P((db_symtab_t *, db_addr_t,
74 db_strategy_t, db_expr_t *));
75 void db_elf_symbol_values __P((db_symtab_t *, db_sym_t,
76 char **, db_expr_t *));
77 boolean_t db_elf_line_at_pc __P((db_symtab_t *, db_sym_t,
78 char **, int *, db_expr_t));
79 boolean_t db_elf_sym_numargs __P((db_symtab_t *, db_sym_t, int *,
80 char **));
81
82 db_symformat_t db_symformat_elf = {
83 "ELF",
84 db_elf_sym_init,
85 db_elf_lookup,
86 db_elf_search_symbol,
87 db_elf_symbol_values,
88 db_elf_line_at_pc,
89 db_elf_sym_numargs,
90 };
91
92 /*
93 * Find the symbol table and strings; tell ddb about them.
94 */
95 boolean_t
96 db_elf_sym_init(symsize, symtab, esymtab, name)
97 int symsize; /* size of symbol table */
98 void *symtab; /* pointer to start of symbol table */
99 void *esymtab; /* pointer to end of string table,
100 for checking - rounded up to integer
101 boundary */
102 const char *name;
103 {
104 Elf_Ehdr *elf;
105 Elf_Shdr *shp;
106 Elf_Sym *symp, *symtab_start, *symtab_end;
107 char *strtab_start, *strtab_end;
108 int i;
109
110 if (ALIGNED_POINTER(symtab, long) == 0) {
111 printf("[ %s symbol table has bad start address %p ]\n",
112 name, symtab);
113 return (FALSE);
114 }
115
116 symtab_start = symtab_end = NULL;
117 strtab_start = strtab_end = NULL;
118
119 /*
120 * The format of the symbols loaded by the boot program is:
121 *
122 * Elf exec header
123 * first section header
124 * . . .
125 * . . .
126 * last section header
127 * first symbol or string table section
128 * . . .
129 * . . .
130 * last symbol or string table section
131 */
132
133 /*
134 * Validate the Elf header.
135 */
136 elf = (Elf_Ehdr *)symtab;
137 if (memcmp(elf->e_ident, Elf_e_ident, Elf_e_siz) != 0)
138 goto badheader;
139
140 switch (elf->e_machine) {
141
142 ELFDEFNAME(MACHDEP_ID_CASES)
143
144 default:
145 goto badheader;
146 }
147
148 /*
149 * We need to avoid the section header string table (small string
150 * table which names the sections). We do this by assuming that
151 * the following two conditions will be true:
152 *
153 * (1) .shstrtab will be smaller than one page.
154 * (2) .strtab will be larger than one page.
155 *
156 * When we encounter what we think is the .shstrtab, we change
157 * its section type Elf_sht_null so that it will be ignored
158 * later.
159 */
160 shp = (Elf_Shdr *)(symtab + elf->e_shoff);
161 for (i = 0; i < elf->e_shnum; i++) {
162 switch (shp[i].sh_type) {
163 case Elf_sht_strtab:
164 if (shp[i].sh_size < NBPG) {
165 shp[i].sh_type = Elf_sht_null;
166 continue;
167 }
168 if (strtab_start != NULL)
169 goto multiple_strtab;
170 strtab_start = (char *)(symtab + shp[i].sh_offset);
171 strtab_end = (char *)(symtab + shp[i].sh_offset +
172 shp[i].sh_size);
173 break;
174
175 case Elf_sht_symtab:
176 if (symtab_start != NULL)
177 goto multiple_symtab;
178 symtab_start = (Elf_Sym *)(symtab + shp[i].sh_offset);
179 symtab_end = (Elf_Sym *)(symtab + shp[i].sh_offset +
180 shp[i].sh_size);
181 break;
182
183 default:
184 /* Ignore all other sections. */
185 break;
186 }
187 }
188
189 /*
190 * Now, sanity check the symbols against the string table.
191 */
192 if (symtab_start == NULL || strtab_start == NULL ||
193 ALIGNED_POINTER(symtab_start, long) == 0 ||
194 ALIGNED_POINTER(strtab_start, long) == 0)
195 goto badheader;
196 for (symp = symtab_start; symp < symtab_end; symp++)
197 if (symp->st_name + strtab_start > strtab_end)
198 goto badheader;
199
200 /*
201 * Link the symbol table into the debugger.
202 */
203 if (db_add_symbol_table((char *)symtab_start,
204 (char *)symtab_end, name, (char *)symtab) != -1) {
205 printf("[ preserving %lu bytes of %s ELF symbol table ]\n",
206 (u_long)roundup((esymtab - symtab), sizeof(u_long)), name);
207 return (TRUE);
208 }
209
210 return (FALSE);
211
212 badheader:
213 printf("[ %s ELF symbol table not valid ]\n", name);
214 return (FALSE);
215
216 multiple_strtab:
217 printf("[ %s has multiple ELF string tables ]\n", name);
218 return (FALSE);
219
220 multiple_symtab:
221 printf("[ %s has multiple ELF symbol tables ]\n", name);
222 return (FALSE);
223 }
224
225 /*
226 * Internal helper function - return a pointer to the string table
227 * for the current symbol table.
228 */
229 static char *
230 db_elf_find_strtab(stab)
231 db_symtab_t *stab;
232 {
233 Elf_Ehdr *elf = STAB_TO_EHDR(stab);
234 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
235 int i;
236
237 for (i = 0; i < elf->e_shnum; i++) {
238 if (shp[i].sh_type == Elf_sht_strtab)
239 return (stab->private + shp[i].sh_offset);
240 }
241
242 return (NULL);
243 }
244
245 /*
246 * Lookup the symbol with the given name.
247 */
248 db_sym_t
249 db_elf_lookup(stab, symstr)
250 db_symtab_t *stab;
251 char *symstr;
252 {
253 Elf_Sym *symp, *symtab_start, *symtab_end;
254 char *strtab;
255
256 symtab_start = STAB_TO_SYMSTART(stab);
257 symtab_end = STAB_TO_SYMEND(stab);
258
259 strtab = db_elf_find_strtab(stab);
260 if (strtab == NULL)
261 return ((db_sym_t)0);
262
263 for (symp = symtab_start; symp < symtab_end; symp++) {
264 if (symp->st_name != 0 &&
265 db_eqname(strtab + symp->st_name, symstr, 0))
266 return ((db_sym_t)symp);
267 }
268
269 return ((db_sym_t)0);
270 }
271
272 /*
273 * Search for the symbol with the given address (matching within the
274 * provided threshold).
275 */
276 db_sym_t
277 db_elf_search_symbol(symtab, off, strategy, diffp)
278 db_symtab_t *symtab;
279 db_addr_t off;
280 db_strategy_t strategy;
281 db_expr_t *diffp; /* in/out */
282 {
283 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
284 db_expr_t diff = *diffp;
285
286 symtab_start = STAB_TO_SYMSTART(symtab);
287 symtab_end = STAB_TO_SYMEND(symtab);
288
289 rsymp = NULL;
290
291 for (symp = symtab_start; symp < symtab_end; symp++) {
292 if (symp->st_name == 0)
293 continue;
294 #if 0
295 /* This prevents me from seeing anythin in locore.s -- eeh */
296 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
297 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
298 continue;
299 #endif
300
301 if (off >= symp->st_value) {
302 if ((off - symp->st_value) < diff) {
303 diff = off - symp->st_value;
304 rsymp = symp;
305 if (diff == 0) {
306 if (strategy == DB_STGY_PROC &&
307 ELF_SYM_TYPE(symp->st_info) ==
308 Elf_estt_func &&
309 ELF_SYM_BIND(symp->st_info) !=
310 Elf_estb_local)
311 break;
312 if (strategy == DB_STGY_ANY &&
313 ELF_SYM_BIND(symp->st_info) !=
314 Elf_estb_local)
315 break;
316 }
317 } else if ((off - symp->st_value) == diff) {
318 if (rsymp == NULL)
319 rsymp = symp;
320 else if (ELF_SYM_BIND(rsymp->st_info) ==
321 Elf_estb_local &&
322 ELF_SYM_BIND(symp->st_info) !=
323 Elf_estb_local) {
324 /* pick the external symbol */
325 rsymp = symp;
326 }
327 }
328 }
329 }
330
331 if (rsymp == NULL)
332 *diffp = off;
333 else
334 *diffp = diff;
335
336 return ((db_sym_t)rsymp);
337 }
338
339 /*
340 * Return the name and value for a symbol.
341 */
342 void
343 db_elf_symbol_values(symtab, sym, namep, valuep)
344 db_symtab_t *symtab;
345 db_sym_t sym;
346 char **namep;
347 db_expr_t *valuep;
348 {
349 Elf_Sym *symp = (Elf_Sym *)sym;
350 char *strtab;
351
352 if (namep) {
353 strtab = db_elf_find_strtab(symtab);
354 if (strtab == NULL)
355 *namep = NULL;
356 else
357 *namep = strtab + symp->st_name;
358 }
359
360 if (valuep)
361 *valuep = symp->st_value;
362 }
363
364 /*
365 * Return the file and line number of the current program counter
366 * if we can find the appropriate debugging symbol.
367 */
368 boolean_t
369 db_elf_line_at_pc(symtab, cursym, filename, linenum, off)
370 db_symtab_t *symtab;
371 db_sym_t cursym;
372 char **filename;
373 int *linenum;
374 db_expr_t off;
375 {
376
377 /*
378 * XXX We don't support this (yet).
379 */
380 return (FALSE);
381 }
382
383 /*
384 * Returns the number of arguments to a function and their
385 * names if we can find the appropriate debugging symbol.
386 */
387 boolean_t
388 db_elf_sym_numargs(symtab, cursym, nargp, argnamep)
389 db_symtab_t *symtab;
390 db_sym_t cursym;
391 int *nargp;
392 char **argnamep;
393 {
394
395 /*
396 * XXX We don't support this (yet).
397 */
398 return (FALSE);
399 }
400 #endif /* DB_ELF_SYMBOLS */
401