FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_elf.c
1 /* $NetBSD: db_elf.c,v 1.22 2002/11/13 05:59:28 yamt 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/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: db_elf.c,v 1.22 2002/11/13 05:59:28 yamt Exp $");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/proc.h>
46
47 #include <machine/db_machdep.h>
48
49 #include <ddb/db_sym.h>
50 #include <ddb/db_output.h>
51 #include <ddb/db_extern.h>
52
53 #ifdef DB_ELF_SYMBOLS
54
55 #ifndef DB_ELFSIZE
56 #error Must define DB_ELFSIZE!
57 #endif
58
59 #define ELFSIZE DB_ELFSIZE
60
61 #include <sys/exec_elf.h>
62
63 static char *db_elf_find_strtab(db_symtab_t *);
64
65 #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start))
66 #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end))
67 #define STAB_TO_EHDR(stab) ((Elf_Ehdr *)((stab)->private))
68 #define STAB_TO_SHDR(stab, e) ((Elf_Shdr *)((stab)->private + (e)->e_shoff))
69
70 static boolean_t db_elf_sym_init(int, void *, void *, const char *);
71 static db_sym_t db_elf_lookup(db_symtab_t *, char *);
72 static db_sym_t db_elf_search_symbol(db_symtab_t *, db_addr_t, db_strategy_t,
73 db_expr_t *);
74 static void db_elf_symbol_values(db_symtab_t *, db_sym_t, char **,
75 db_expr_t *);
76 static boolean_t db_elf_line_at_pc(db_symtab_t *, db_sym_t, char **, int *,
77 db_expr_t);
78 static boolean_t db_elf_sym_numargs(db_symtab_t *, db_sym_t, int *, char **);
79 static void db_elf_forall(db_symtab_t *, db_forall_func_t db_forall_func,
80 void *);
81
82 const 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 db_elf_forall
91 };
92
93 /*
94 * Find the symbol table and strings; tell ddb about them.
95 */
96 static boolean_t
97 db_elf_sym_init(
98 int symsize, /* size of symbol table */
99 void *symtab, /* pointer to start of symbol table */
100 void *esymtab, /* pointer to end of string table,
101 for checking - rounded up to integer
102 boundary */
103 const char *name
104 )
105 {
106 Elf_Ehdr *elf;
107 Elf_Shdr *shp;
108 Elf_Sym *symp, *symtab_start, *symtab_end;
109 char *strtab_start, *strtab_end;
110 int i, j;
111
112 if (ALIGNED_POINTER(symtab, long) == 0) {
113 printf("[ %s symbol table has bad start address %p ]\n",
114 name, symtab);
115 return (FALSE);
116 }
117
118 symtab_start = symtab_end = NULL;
119 strtab_start = strtab_end = NULL;
120
121 /*
122 * The format of the symbols loaded by the boot program is:
123 *
124 * Elf exec header
125 * first section header
126 * . . .
127 * . . .
128 * last section header
129 * first symbol or string table section
130 * . . .
131 * . . .
132 * last symbol or string table section
133 */
134
135 /*
136 * Validate the Elf header.
137 */
138 elf = (Elf_Ehdr *)symtab;
139 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
140 elf->e_ident[EI_CLASS] != ELFCLASS)
141 goto badheader;
142
143 switch (elf->e_machine) {
144
145 ELFDEFNNAME(MACHDEP_ID_CASES)
146
147 default:
148 goto badheader;
149 }
150
151 /*
152 * Find the first (and, we hope, only) SHT_SYMTAB section in
153 * the file, and the SHT_STRTAB section that goes with it.
154 */
155 if (elf->e_shoff == 0)
156 goto badheader;
157 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
158 for (i = 0; i < elf->e_shnum; i++) {
159 if (shp[i].sh_type == SHT_SYMTAB) {
160 if (shp[i].sh_offset == 0)
161 continue;
162 /* Got the symbol table. */
163 symtab_start = (Elf_Sym *)((char *)symtab +
164 shp[i].sh_offset);
165 symtab_end = (Elf_Sym *)((char *)symtab +
166 shp[i].sh_offset + shp[i].sh_size);
167 /* Find the string table to go with it. */
168 j = shp[i].sh_link;
169 if (shp[j].sh_offset == 0)
170 continue;
171 strtab_start = (char *)symtab + shp[j].sh_offset;
172 strtab_end = (char *)symtab + shp[j].sh_offset +
173 shp[j].sh_size;
174 /* There should only be one symbol table. */
175 break;
176 }
177 }
178
179 /*
180 * Now, sanity check the symbols against the string table.
181 */
182 if (symtab_start == NULL || strtab_start == NULL ||
183 ALIGNED_POINTER(symtab_start, long) == 0 ||
184 ALIGNED_POINTER(strtab_start, long) == 0)
185 goto badheader;
186 for (symp = symtab_start; symp < symtab_end; symp++)
187 if (symp->st_name + strtab_start > strtab_end)
188 goto badheader;
189
190 /*
191 * Link the symbol table into the debugger.
192 */
193 if (db_add_symbol_table((char *)symtab_start,
194 (char *)symtab_end, name, (char *)symtab) != -1) {
195 printf("[ using %lu bytes of %s ELF symbol table ]\n",
196 (u_long)roundup(((char *)esymtab - (char *)symtab),
197 sizeof(u_long)), name);
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 *
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 /*
220 * We don't load ELF header for ELF modules.
221 * Find out if this is a loadable module. If so,
222 * string table comes right after symbol table.
223 */
224 if ((Elf_Sym *)elf == STAB_TO_SYMSTART(stab)) {
225 return ((char *)STAB_TO_SYMEND(stab));
226 }
227 for (i = 0; i < elf->e_shnum; i++) {
228 if (shp[i].sh_type == SHT_SYMTAB)
229 return ((char*)elf + shp[shp[i].sh_link].sh_offset);
230 }
231
232 return (NULL);
233 }
234
235 /*
236 * Lookup the symbol with the given name.
237 */
238 static db_sym_t
239 db_elf_lookup(db_symtab_t *stab, char *symstr)
240 {
241 Elf_Sym *symp, *symtab_start, *symtab_end;
242 char *strtab;
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 ((db_sym_t)0);
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 ((db_sym_t)symp);
255 }
256
257 return ((db_sym_t)0);
258 }
259
260 /*
261 * Search for the symbol with the given address (matching within the
262 * provided threshold).
263 */
264 static db_sym_t
265 db_elf_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strategy,
266 db_expr_t *diffp)
267 {
268 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
269 db_addr_t diff = *diffp;
270
271 symtab_start = STAB_TO_SYMSTART(symtab);
272 symtab_end = STAB_TO_SYMEND(symtab);
273
274 rsymp = NULL;
275
276 for (symp = symtab_start; symp < symtab_end; symp++) {
277 if (symp->st_name == 0)
278 continue;
279 #if 0
280 /* This prevents me from seeing anythin in locore.s -- eeh */
281 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
282 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
283 continue;
284 #endif
285
286 if (off >= symp->st_value) {
287 if (off - symp->st_value < diff) {
288 diff = off - symp->st_value;
289 rsymp = symp;
290 if (diff == 0) {
291 if (strategy == DB_STGY_PROC &&
292 ELFDEFNNAME(ST_TYPE)(symp->st_info)
293 == STT_FUNC &&
294 ELFDEFNNAME(ST_BIND)(symp->st_info)
295 != STB_LOCAL)
296 break;
297 if (strategy == DB_STGY_ANY &&
298 ELFDEFNNAME(ST_BIND)(symp->st_info)
299 != STB_LOCAL)
300 break;
301 }
302 } else if (off - symp->st_value == diff) {
303 if (rsymp == NULL)
304 rsymp = symp;
305 else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info)
306 == STB_LOCAL &&
307 ELFDEFNNAME(ST_BIND)(symp->st_info)
308 != STB_LOCAL) {
309 /* pick the external symbol */
310 rsymp = symp;
311 }
312 }
313 }
314 }
315
316 if (rsymp == NULL)
317 *diffp = off;
318 else
319 *diffp = diff;
320
321 return ((db_sym_t)rsymp);
322 }
323
324 /*
325 * Return the name and value for a symbol.
326 */
327 static void
328 db_elf_symbol_values(db_symtab_t *symtab, db_sym_t sym, char **namep,
329 db_expr_t *valuep)
330 {
331 Elf_Sym *symp = (Elf_Sym *)sym;
332 char *strtab;
333
334 if (namep) {
335 strtab = db_elf_find_strtab(symtab);
336 if (strtab == NULL)
337 *namep = NULL;
338 else
339 *namep = strtab + symp->st_name;
340 }
341
342 if (valuep)
343 *valuep = symp->st_value;
344 }
345
346 /*
347 * Return the file and line number of the current program counter
348 * if we can find the appropriate debugging symbol.
349 */
350 static boolean_t
351 db_elf_line_at_pc(symtab, cursym, filename, linenum, off)
352 db_symtab_t *symtab;
353 db_sym_t cursym;
354 char **filename;
355 int *linenum;
356 db_expr_t off;
357 {
358
359 /*
360 * XXX We don't support this (yet).
361 */
362 return (FALSE);
363 }
364
365 /*
366 * Returns the number of arguments to a function and their
367 * names if we can find the appropriate debugging symbol.
368 */
369 static boolean_t
370 db_elf_sym_numargs(db_symtab_t *symtab, db_sym_t cursym, int *nargp,
371 char **argnamep)
372 {
373
374 /*
375 * XXX We don't support this (yet).
376 */
377 return (FALSE);
378 }
379
380 static void
381 db_elf_forall(db_symtab_t *stab, db_forall_func_t db_forall_func, void *arg)
382 {
383 char *strtab;
384 static char suffix[2];
385 Elf_Sym *symp, *symtab_start, *symtab_end;
386
387 symtab_start = STAB_TO_SYMSTART(stab);
388 symtab_end = STAB_TO_SYMEND(stab);
389
390 strtab = db_elf_find_strtab(stab);
391 if (strtab == NULL)
392 return;
393
394 for (symp = symtab_start; symp < symtab_end; symp++)
395 if (symp->st_name != 0) {
396 suffix[1] = '\0';
397 switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
398 case STT_OBJECT:
399 suffix[0] = '+';
400 break;
401 case STT_FUNC:
402 suffix[0] = '*';
403 break;
404 case STT_SECTION:
405 suffix[0] = '&';
406 break;
407 case STT_FILE:
408 suffix[0] = '/';
409 break;
410 default:
411 suffix[0] = '\0';
412 }
413 (*db_forall_func)(stab, (db_sym_t)symp,
414 strtab + symp->st_name, suffix, 0, arg);
415 }
416 return;
417 }
418 #endif /* DB_ELF_SYMBOLS */
Cache object: 929a8a9ea837bf4189d261af1948c329
|