xref: /openbsd-src/sys/ddb/db_elf.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: db_elf.c,v 1.9 2008/06/26 05:42:14 ray 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/types.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38 #include <sys/exec.h>
39 
40 #include <machine/db_machdep.h>
41 
42 #include <ddb/db_sym.h>
43 #include <ddb/db_output.h>
44 #include <ddb/db_extern.h>
45 
46 #ifdef DB_ELF_SYMBOLS
47 
48 #ifndef DB_ELFSIZE
49 #error Must define DB_ELFSIZE!
50 #endif
51 
52 #define	ELFSIZE		DB_ELFSIZE
53 
54 #include <sys/exec_elf.h>
55 
56 static char *db_elf_find_strtab(db_symtab_t *);
57 
58 #define	STAB_TO_SYMSTART(stab)	((Elf_Sym *)((stab)->start))
59 #define	STAB_TO_SYMEND(stab)	((Elf_Sym *)((stab)->end))
60 #define	STAB_TO_EHDR(stab)	((Elf_Ehdr *)((stab)->private))
61 #define	STAB_TO_SHDR(stab, e)	((Elf_Shdr *)((stab)->private + (e)->e_shoff))
62 
63 boolean_t	db_elf_sym_init(int, void *, void *, const char *);
64 db_sym_t	db_elf_lookup(db_symtab_t *, char *);
65 db_sym_t	db_elf_search_symbol(db_symtab_t *, db_addr_t,
66 		    db_strategy_t, db_expr_t *);
67 void		db_elf_symbol_values(db_symtab_t *, db_sym_t,
68 		    char **, db_expr_t *);
69 boolean_t	db_elf_line_at_pc(db_symtab_t *, db_sym_t,
70 		    char **, int *, db_expr_t);
71 boolean_t	db_elf_sym_numargs(db_symtab_t *, db_sym_t, int *,
72 		    char **);
73 void		db_elf_forall(db_symtab_t *,
74 		    db_forall_func_t db_forall_func, void *);
75 
76 db_symformat_t db_symformat_elf = {
77 	"ELF",
78 	db_elf_sym_init,
79 	db_elf_lookup,
80 	db_elf_search_symbol,
81 	db_elf_symbol_values,
82 	db_elf_line_at_pc,
83 	db_elf_sym_numargs,
84 	db_elf_forall
85 };
86 
87 /*
88  * Find the symbol table and strings; tell ddb about them.
89  *
90  * symsize:	size of symbol table
91  * symtab:	pointer to start of symbol table
92  * esymtab:	pointer to end of string table, for checking - rounded up to
93  *		    integer boundry
94  */
95 boolean_t
96 db_elf_sym_init(int symsize, void *symtab, void *esymtab, const char *name)
97 {
98 	Elf_Ehdr *elf;
99 	Elf_Shdr *shp;
100 	Elf_Sym *symp, *symtab_start, *symtab_end;
101 	char *shstrtab, *strtab_start, *strtab_end;
102 	int i;
103 	char *errstr = "";
104 
105 	if (ALIGNED_POINTER(symtab, long) == 0) {
106 		db_printf("[ %s symbol table has bad start address %p ]\n",
107 		    name, symtab);
108 		return (FALSE);
109 	}
110 
111 	symtab_start = symtab_end = NULL;
112 	strtab_start = strtab_end = NULL;
113 
114 	/*
115 	 * The format of the symbols loaded by the boot program is:
116 	 *
117 	 *	Elf exec header
118 	 *	first section header
119 	 *	. . .
120 	 *	. . .
121 	 *	last section header
122 	 *	first symbol or string table section
123 	 *	. . .
124 	 *	. . .
125 	 *	last symbol or string table section
126 	 */
127 
128 	/*
129 	 * Validate the Elf header.
130 	 */
131 	elf = (Elf_Ehdr *)symtab;
132 	if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
133 	    elf->e_ident[EI_CLASS] != ELFCLASS) {
134 		errstr = "bad magic";
135 		goto badheader;
136 	}
137 
138 	if (elf->e_machine != ELF_TARG_MACH) {
139 		errstr = "bad e_machine";
140 		goto badheader;
141 	}
142 
143 	/*
144 	 * Find the section header string table (.shstrtab), and look up
145 	 * the symbol table (.symtab) and string table (.strtab) via their
146 	 * names in shstrtab, rather than by table type.
147 	 * This works in the presence of multiple string tables, such as
148 	 * stabs data found when booting bsd.gdb.
149 	 */
150 	shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
151 	shstrtab = (char *)symtab + shp[elf->e_shstrndx].sh_offset;
152 	for (i = 0; i < elf->e_shnum; i++) {
153 		if (shp[i].sh_type == SHT_SYMTAB) {
154 			int j;
155 
156 			if (shp[i].sh_offset == 0)
157 				continue;
158 			symtab_start = (Elf_Sym *)((char *)symtab +
159 			    shp[i].sh_offset);
160 			symtab_end = (Elf_Sym *)((char *)symtab +
161 			    shp[i].sh_offset + shp[i].sh_size);
162 			j = shp[i].sh_link;
163 			if (shp[j].sh_offset == 0)
164 				continue;
165 			strtab_start = (char *)symtab + shp[j].sh_offset;
166 			strtab_end = (char *)symtab + shp[j].sh_offset +
167 			    shp[j].sh_size;
168 			break;
169 		}
170 
171 		/*
172 		 * This is the old way of doing things.
173 		 * XXX - verify that it's not needed.
174 		 */
175 		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
176 			strtab_start = (char *)symtab + shp[i].sh_offset;
177 			strtab_end = (char *)symtab + shp[i].sh_offset +
178 			    shp[i].sh_size;
179 		} else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
180 			symtab_start = (Elf_Sym *)((char *)symtab +
181 			    shp[i].sh_offset);
182 			symtab_end = (Elf_Sym *)((char *)symtab +
183 			    shp[i].sh_offset + shp[i].sh_size);
184 		}
185 	}
186 
187 	/*
188 	 * Now, sanity check the symbols against the string table.
189 	 */
190 	if (symtab_start == NULL || strtab_start == NULL ||
191 	    ALIGNED_POINTER(symtab_start, long) == 0 ||
192 	    ALIGNED_POINTER(strtab_start, long) == 0) {
193 		errstr = "symtab unaligned";
194 		goto badheader;
195 	}
196 	for (symp = symtab_start; symp < symtab_end; symp++)
197 		if (symp->st_name + strtab_start > strtab_end) {
198 			errstr = "symtab corrupted";
199 			goto badheader;
200 		}
201 
202 	/*
203 	 * Link the symbol table into the debugger.
204 	 */
205 	if (db_add_symbol_table((char *)symtab_start,
206 	    (char *)symtab_end, name, (char *)symtab) != -1) {
207 		db_printf("[ using %lu bytes of %s ELF symbol table ]\n",
208 		    (u_long)roundup(((char *)esymtab - (char *)symtab),
209 				    sizeof(u_long)), name);
210 		return (TRUE);
211 	}
212 
213 	return (FALSE);
214 
215  badheader:
216 	db_printf("[ %s ELF symbol table not valid: %s ]\n", name, errstr);
217 	return (FALSE);
218 }
219 
220 /*
221  * Internal helper function - return a pointer to the string table
222  * for the current symbol table.
223  */
224 static char *
225 db_elf_find_strtab(db_symtab_t *stab)
226 {
227 	Elf_Ehdr *elf = STAB_TO_EHDR(stab);
228 	Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
229 	char *shstrtab;
230 	int i;
231 
232 	shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
233 	for (i = 0; i < elf->e_shnum; i++) {
234 		if (shp[i].sh_type == SHT_SYMTAB)
235 			return ((char *)elf + shp[shp[i].sh_link].sh_offset);
236 		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
237 			return ((char *)elf + shp[i].sh_offset);
238 	}
239 
240 	return (NULL);
241 }
242 
243 /*
244  * Lookup the symbol with the given name.
245  */
246 db_sym_t
247 db_elf_lookup(db_symtab_t *stab, char *symstr)
248 {
249 	Elf_Sym *symp, *symtab_start, *symtab_end;
250 	char *strtab;
251 
252 	symtab_start = STAB_TO_SYMSTART(stab);
253 	symtab_end = STAB_TO_SYMEND(stab);
254 
255 	strtab = db_elf_find_strtab(stab);
256 	if (strtab == NULL)
257 		return ((db_sym_t)0);
258 
259 	for (symp = symtab_start; symp < symtab_end; symp++) {
260 		if (symp->st_name != 0 &&
261 		    db_eqname(strtab + symp->st_name, symstr, 0))
262 			return ((db_sym_t)symp);
263 	}
264 
265 	return ((db_sym_t)0);
266 }
267 
268 /*
269  * Search for the symbol with the given address (matching within the
270  * provided threshold).
271  */
272 db_sym_t
273 db_elf_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strategy,
274     db_expr_t *diffp)
275 {
276 	Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
277 	db_expr_t diff = *diffp;
278 
279 	symtab_start = STAB_TO_SYMSTART(symtab);
280 	symtab_end = STAB_TO_SYMEND(symtab);
281 
282 	rsymp = NULL;
283 
284 	for (symp = symtab_start; symp < symtab_end; symp++) {
285 		if (symp->st_name == 0)
286 			continue;
287 #if 0
288 		/* This prevents me from seeing anythin in locore.s -- eeh */
289 		if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object &&
290 		    ELF_SYM_TYPE(symp->st_info) != Elf_estt_func)
291 			continue;
292 #endif
293 
294 		if (off >= symp->st_value) {
295 			if ((off - symp->st_value) < diff) {
296 				diff = off - symp->st_value;
297 				rsymp = symp;
298 				if (diff == 0) {
299 					if (strategy == DB_STGY_PROC &&
300 					    ELFDEFNNAME(ST_TYPE)(symp->st_info)
301 					      == STT_FUNC &&
302 					    ELFDEFNNAME(ST_BIND)(symp->st_info)
303 					      != STB_LOCAL)
304 						break;
305 					if (strategy == DB_STGY_ANY &&
306 					    ELFDEFNNAME(ST_BIND)(symp->st_info)
307 					      != STB_LOCAL)
308 						break;
309 				}
310 			} else if ((off - symp->st_value) == diff) {
311 				if (rsymp == NULL)
312 					rsymp = symp;
313 				else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info)
314 				      == STB_LOCAL &&
315 				    ELFDEFNNAME(ST_BIND)(symp->st_info)
316 				      != STB_LOCAL) {
317 					/* pick the external symbol */
318 					rsymp = symp;
319 				}
320 			}
321 		}
322 	}
323 
324 	if (rsymp == NULL)
325 		*diffp = off;
326 	else
327 		*diffp = diff;
328 
329 	return ((db_sym_t)rsymp);
330 }
331 
332 /*
333  * Return the name and value for a symbol.
334  */
335 void
336 db_elf_symbol_values(db_symtab_t *symtab, db_sym_t sym, char **namep,
337     db_expr_t *valuep)
338 {
339 	Elf_Sym *symp = (Elf_Sym *)sym;
340 	char *strtab;
341 
342 	if (namep) {
343 		strtab = db_elf_find_strtab(symtab);
344 		if (strtab == NULL)
345 			*namep = NULL;
346 		else
347 			*namep = strtab + symp->st_name;
348 	}
349 
350 	if (valuep)
351 		*valuep = symp->st_value;
352 }
353 
354 /*
355  * Return the file and line number of the current program counter
356  * if we can find the appropriate debugging symbol.
357  */
358 boolean_t
359 db_elf_line_at_pc(db_symtab_t *symtab, db_sym_t cursym, char **filename,
360     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 boolean_t
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 void
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 	symtab_start = STAB_TO_SYMSTART(stab);
392 	symtab_end = STAB_TO_SYMEND(stab);
393 
394 	strtab = db_elf_find_strtab(stab);
395 	if (strtab == NULL)
396 		return;
397 
398 	for (symp = symtab_start; symp < symtab_end; symp++)
399 		if (symp->st_name != 0) {
400 			suffix[1] = '\0';
401 			switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
402 			case STT_OBJECT:
403 				suffix[0] = '+';
404 				break;
405 			case STT_FUNC:
406 				suffix[0] = '*';
407 				break;
408 			case STT_SECTION:
409 				suffix[0] = '&';
410 				break;
411 			case STT_FILE:
412 				suffix[0] = '/';
413 				break;
414 			default:
415 				suffix[0] = '\0';
416 			}
417 			(*db_forall_func)(stab, (db_sym_t)symp,
418 			    strtab + symp->st_name, suffix, 0, arg);
419 		}
420 	return;
421 }
422 #endif /* DB_ELF_SYMBOLS */
423