xref: /openbsd-src/sys/ddb/db_elf.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: db_elf.c,v 1.10 2014/03/16 20:31:46 guenther 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 #include <sys/exec_elf.h>
47 
48 static char *db_elf_find_strtab(db_symtab_t *);
49 
50 #define	STAB_TO_SYMSTART(stab)	((Elf_Sym *)((stab)->start))
51 #define	STAB_TO_SYMEND(stab)	((Elf_Sym *)((stab)->end))
52 #define	STAB_TO_EHDR(stab)	((Elf_Ehdr *)((stab)->private))
53 #define	STAB_TO_SHDR(stab, e)	((Elf_Shdr *)((stab)->private + (e)->e_shoff))
54 
55 boolean_t	db_elf_sym_init(int, void *, void *, const char *);
56 db_sym_t	db_elf_lookup(db_symtab_t *, char *);
57 db_sym_t	db_elf_search_symbol(db_symtab_t *, db_addr_t,
58 		    db_strategy_t, db_expr_t *);
59 void		db_elf_symbol_values(db_symtab_t *, db_sym_t,
60 		    char **, db_expr_t *);
61 boolean_t	db_elf_line_at_pc(db_symtab_t *, db_sym_t,
62 		    char **, int *, db_expr_t);
63 boolean_t	db_elf_sym_numargs(db_symtab_t *, db_sym_t, int *,
64 		    char **);
65 void		db_elf_forall(db_symtab_t *,
66 		    db_forall_func_t db_forall_func, void *);
67 
68 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 /*
80  * Find the symbol table and strings; tell ddb about them.
81  *
82  * symsize:	size of symbol table
83  * symtab:	pointer to start of symbol table
84  * esymtab:	pointer to end of string table, for checking - rounded up to
85  *		    integer boundry
86  */
87 boolean_t
88 db_elf_sym_init(int symsize, void *symtab, void *esymtab, const char *name)
89 {
90 	Elf_Ehdr *elf;
91 	Elf_Shdr *shp;
92 	Elf_Sym *symp, *symtab_start, *symtab_end;
93 	char *shstrtab, *strtab_start, *strtab_end;
94 	int i;
95 	char *errstr = "";
96 
97 	if (ALIGNED_POINTER(symtab, long) == 0) {
98 		db_printf("[ %s symbol table has bad start address %p ]\n",
99 		    name, symtab);
100 		return (FALSE);
101 	}
102 
103 	symtab_start = symtab_end = NULL;
104 	strtab_start = strtab_end = NULL;
105 
106 	/*
107 	 * The format of the symbols loaded by the boot program is:
108 	 *
109 	 *	Elf exec header
110 	 *	first section header
111 	 *	. . .
112 	 *	. . .
113 	 *	last section header
114 	 *	first symbol or string table section
115 	 *	. . .
116 	 *	. . .
117 	 *	last symbol or string table section
118 	 */
119 
120 	/*
121 	 * Validate the Elf header.
122 	 */
123 	elf = (Elf_Ehdr *)symtab;
124 	if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
125 	    elf->e_ident[EI_CLASS] != ELFCLASS) {
126 		errstr = "bad magic";
127 		goto badheader;
128 	}
129 
130 	if (elf->e_machine != ELF_TARG_MACH) {
131 		errstr = "bad e_machine";
132 		goto badheader;
133 	}
134 
135 	/*
136 	 * Find the section header string table (.shstrtab), and look up
137 	 * the symbol table (.symtab) and string table (.strtab) via their
138 	 * names in shstrtab, rather than by table type.
139 	 * This works in the presence of multiple string tables, such as
140 	 * stabs data found when booting bsd.gdb.
141 	 */
142 	shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
143 	shstrtab = (char *)symtab + shp[elf->e_shstrndx].sh_offset;
144 	for (i = 0; i < elf->e_shnum; i++) {
145 		if (shp[i].sh_type == SHT_SYMTAB) {
146 			int j;
147 
148 			if (shp[i].sh_offset == 0)
149 				continue;
150 			symtab_start = (Elf_Sym *)((char *)symtab +
151 			    shp[i].sh_offset);
152 			symtab_end = (Elf_Sym *)((char *)symtab +
153 			    shp[i].sh_offset + shp[i].sh_size);
154 			j = shp[i].sh_link;
155 			if (shp[j].sh_offset == 0)
156 				continue;
157 			strtab_start = (char *)symtab + shp[j].sh_offset;
158 			strtab_end = (char *)symtab + shp[j].sh_offset +
159 			    shp[j].sh_size;
160 			break;
161 		}
162 
163 		/*
164 		 * This is the old way of doing things.
165 		 * XXX - verify that it's not needed.
166 		 */
167 		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
168 			strtab_start = (char *)symtab + shp[i].sh_offset;
169 			strtab_end = (char *)symtab + shp[i].sh_offset +
170 			    shp[i].sh_size;
171 		} else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
172 			symtab_start = (Elf_Sym *)((char *)symtab +
173 			    shp[i].sh_offset);
174 			symtab_end = (Elf_Sym *)((char *)symtab +
175 			    shp[i].sh_offset + shp[i].sh_size);
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 		errstr = "symtab unaligned";
186 		goto badheader;
187 	}
188 	for (symp = symtab_start; symp < symtab_end; symp++)
189 		if (symp->st_name + strtab_start > strtab_end) {
190 			errstr = "symtab corrupted";
191 			goto badheader;
192 		}
193 
194 	/*
195 	 * Link the symbol table into the debugger.
196 	 */
197 	if (db_add_symbol_table((char *)symtab_start,
198 	    (char *)symtab_end, name, (char *)symtab) != -1) {
199 		db_printf("[ using %lu bytes of %s ELF symbol table ]\n",
200 		    (u_long)roundup(((char *)esymtab - (char *)symtab),
201 				    sizeof(u_long)), name);
202 		return (TRUE);
203 	}
204 
205 	return (FALSE);
206 
207  badheader:
208 	db_printf("[ %s ELF symbol table not valid: %s ]\n", name, errstr);
209 	return (FALSE);
210 }
211 
212 /*
213  * Internal helper function - return a pointer to the string table
214  * for the current symbol table.
215  */
216 static char *
217 db_elf_find_strtab(db_symtab_t *stab)
218 {
219 	Elf_Ehdr *elf = STAB_TO_EHDR(stab);
220 	Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
221 	char *shstrtab;
222 	int i;
223 
224 	shstrtab = (char *)elf + shp[elf->e_shstrndx].sh_offset;
225 	for (i = 0; i < elf->e_shnum; i++) {
226 		if (shp[i].sh_type == SHT_SYMTAB)
227 			return ((char *)elf + shp[shp[i].sh_link].sh_offset);
228 		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
229 			return ((char *)elf + shp[i].sh_offset);
230 	}
231 
232 	return (NULL);
233 }
234 
235 /*
236  * Lookup the symbol with the given name.
237  */
238 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 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_expr_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 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 boolean_t
351 db_elf_line_at_pc(db_symtab_t *symtab, db_sym_t cursym, char **filename,
352     int *linenum, db_expr_t off)
353 {
354 
355 	/*
356 	 * XXX We don't support this (yet).
357 	 */
358 	return (FALSE);
359 }
360 
361 /*
362  * Returns the number of arguments to a function and their
363  * names if we can find the appropriate debugging symbol.
364  */
365 boolean_t
366 db_elf_sym_numargs(db_symtab_t *symtab, db_sym_t cursym, int *nargp,
367     char **argnamep)
368 {
369 
370 	/*
371 	 * XXX We don't support this (yet).
372 	 */
373 	return (FALSE);
374 }
375 
376 void
377 db_elf_forall(db_symtab_t *stab, db_forall_func_t db_forall_func, void *arg)
378 {
379 	char *strtab;
380 	static char suffix[2];
381 	Elf_Sym *symp, *symtab_start, *symtab_end;
382 
383 	symtab_start = STAB_TO_SYMSTART(stab);
384 	symtab_end = STAB_TO_SYMEND(stab);
385 
386 	strtab = db_elf_find_strtab(stab);
387 	if (strtab == NULL)
388 		return;
389 
390 	for (symp = symtab_start; symp < symtab_end; symp++)
391 		if (symp->st_name != 0) {
392 			suffix[1] = '\0';
393 			switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
394 			case STT_OBJECT:
395 				suffix[0] = '+';
396 				break;
397 			case STT_FUNC:
398 				suffix[0] = '*';
399 				break;
400 			case STT_SECTION:
401 				suffix[0] = '&';
402 				break;
403 			case STT_FILE:
404 				suffix[0] = '/';
405 				break;
406 			default:
407 				suffix[0] = '\0';
408 			}
409 			(*db_forall_func)(stab, (db_sym_t)symp,
410 			    strtab + symp->st_name, suffix, 0, arg);
411 		}
412 	return;
413 }
414