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