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