xref: /netbsd/sys/ddb/db_elf.c (revision 849b7079)
1 /*	$NetBSD: db_elf.c,v 1.29 2017/11/06 04:08:02 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997, 2009 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, and by Andrew Doran.
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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: db_elf.c,v 1.29 2017/11/06 04:08:02 christos Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 
40 #include <machine/db_machdep.h>
41 #include <machine/pmap.h>
42 #include <machine/vmparam.h>
43 
44 #ifdef DB_ELF_SYMBOLS
45 
46 #include <ddb/ddb.h>
47 #include <sys/exec_elf.h>
48 
49 static char	*db_elf_find_strtab(db_symtab_t *);
50 
51 #define	STAB_TO_SYMSTART(stab)	((Elf_Sym *)((stab)->start))
52 #define	STAB_TO_SYMEND(stab)	((Elf_Sym *)((stab)->end))
53 #define	STAB_TO_EHDR(stab)	((Elf_Ehdr *)((stab)->private))
54 #define	STAB_TO_SHDR(stab, e)	((Elf_Shdr *)((stab)->private + (e)->e_shoff))
55 
56 static bool db_elf_sym_init(int, void *, void *, const char *);
57 static db_sym_t	db_elf_lookup(db_symtab_t *, const char *);
58 static db_sym_t	db_elf_search_symbol(db_symtab_t *, db_addr_t, db_strategy_t,
59 		    db_expr_t *);
60 static void	db_elf_symbol_values(db_symtab_t *, db_sym_t, const char **,
61 		    db_expr_t *);
62 static bool db_elf_line_at_pc(db_symtab_t *, db_sym_t, char **, int *,
63 		    db_expr_t);
64 static bool db_elf_sym_numargs(db_symtab_t *, db_sym_t, int *, char **);
65 static void	db_elf_forall(db_symtab_t *, db_forall_func_t db_forall_func,
66 		    void *);
67 
68 const 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 static db_symtab_t db_symtabs;
80 
81 /*
82  * Add symbol table, with given name, to symbol tables.
83  */
84 static int
db_add_symbol_table(char * start,char * end,const char * name,char * ref)85 db_add_symbol_table(char *start, char *end, const char *name, char *ref)
86 {
87 
88 	db_symtabs.start = start;
89 	db_symtabs.end = end;
90 	db_symtabs.name = name;
91 	db_symtabs.private = ref;
92 
93 	return(0);
94 }
95 
96 /*
97  * Find the symbol table and strings; tell ddb about them.
98  */
99 static bool
db_elf_sym_init(int symsize,void * symtab,void * esymtab,const char * name)100 db_elf_sym_init(
101 	int symsize,		/* size of symbol table */
102 	void *symtab,		/* pointer to start of symbol table */
103 	void *esymtab,		/* pointer to end of string table,
104 				   for checking - rounded up to integer
105 				   boundary */
106 	const char *name
107 )
108 {
109 	Elf_Ehdr *elf;
110 	Elf_Shdr *shp;
111 	Elf_Sym *symp, *symtab_start, *symtab_end;
112 	char *strtab_start, *strtab_end;
113 	int i, j;
114 
115 	if (ALIGNED_POINTER(symtab, long) == 0) {
116 		printf("[ %s symbol table has bad start address %p ]\n",
117 		    name, symtab);
118 		return (false);
119 	}
120 
121 	symtab_start = symtab_end = NULL;
122 	strtab_start = strtab_end = NULL;
123 
124 	/*
125 	 * The format of the symbols loaded by the boot program is:
126 	 *
127 	 *	Elf exec header
128 	 *	first section header
129 	 *	. . .
130 	 *	. . .
131 	 *	last section header
132 	 *	first symbol or string table section
133 	 *	. . .
134 	 *	. . .
135 	 *	last symbol or string table section
136 	 */
137 
138 	/*
139 	 * Validate the Elf header.
140 	 */
141 	elf = (Elf_Ehdr *)symtab;
142 	if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 ||
143 	    elf->e_ident[EI_CLASS] != ELFCLASS)
144 		goto badheader;
145 
146 	switch (elf->e_machine) {
147 
148 	ELFDEFNNAME(MACHDEP_ID_CASES)
149 
150 	default:
151 		goto badheader;
152 	}
153 
154 	/*
155 	 * Find the first (and, we hope, only) SHT_SYMTAB section in
156 	 * the file, and the SHT_STRTAB section that goes with it.
157 	 */
158 	if (elf->e_shoff == 0)
159 		goto badheader;
160 	shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
161 	for (i = 0; i < elf->e_shnum; i++) {
162 		if (shp[i].sh_type == SHT_SYMTAB) {
163 			if (shp[i].sh_offset == 0)
164 				continue;
165 			/* Got the symbol table. */
166 			symtab_start = (Elf_Sym *)((char *)symtab +
167 			    shp[i].sh_offset);
168 			symtab_end = (Elf_Sym *)((char *)symtab +
169 			    shp[i].sh_offset + shp[i].sh_size);
170 			/* Find the string table to go with it. */
171 			j = shp[i].sh_link;
172 			if (shp[j].sh_offset == 0)
173 				continue;
174 			strtab_start = (char *)symtab + shp[j].sh_offset;
175 			strtab_end = (char *)symtab + shp[j].sh_offset +
176 			    shp[j].sh_size;
177 			/* There should only be one symbol table. */
178 			break;
179 		}
180 	}
181 
182 	/*
183 	 * Now, sanity check the symbols against the string table.
184 	 */
185 	if (symtab_start == NULL || strtab_start == NULL ||
186 	    ALIGNED_POINTER(symtab_start, long) == 0 ||
187 	    ALIGNED_POINTER(strtab_start, long) == 0)
188 		goto badheader;
189 	for (symp = symtab_start; symp < symtab_end; symp++)
190 		if (symp->st_name + strtab_start > strtab_end)
191 			goto badheader;
192 
193 	/*
194 	 * Link the symbol table into the debugger.
195 	 */
196 	if (db_add_symbol_table((char *)symtab_start,
197 	    (char *)symtab_end, name, (char *)symtab) != -1) {
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 *
db_elf_find_strtab(db_symtab_t * stab)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 	stab = &db_symtabs;
220 
221 	/*
222 	 * We don't load ELF header for ELF modules.
223 	 * Find out if this is a loadable module. If so,
224 	 * string table comes right after symbol table.
225 	 */
226 	if ((Elf_Sym *)elf == STAB_TO_SYMSTART(stab)) {
227 		return ((char *)STAB_TO_SYMEND(stab));
228 	}
229 	for (i = 0; i < elf->e_shnum; i++) {
230 		if (shp[i].sh_type == SHT_SYMTAB)
231 			return ((char*)elf + shp[shp[i].sh_link].sh_offset);
232 	}
233 
234 	return (NULL);
235 }
236 
237 /*
238  * Lookup the symbol with the given name.
239  */
240 static db_sym_t
db_elf_lookup(db_symtab_t * stab,const char * symstr)241 db_elf_lookup(db_symtab_t *stab, const char *symstr)
242 {
243 	Elf_Sym *symp, *symtab_start, *symtab_end;
244 	char *strtab;
245 
246 	stab = &db_symtabs;
247 
248 	symtab_start = STAB_TO_SYMSTART(stab);
249 	symtab_end = STAB_TO_SYMEND(stab);
250 
251 	strtab = db_elf_find_strtab(stab);
252 	if (strtab == NULL)
253 		return ((db_sym_t)0);
254 
255 	for (symp = symtab_start; symp < symtab_end; symp++) {
256 		if (symp->st_name != 0 &&
257 		    db_eqname(strtab + symp->st_name, symstr, 0))
258 			return ((db_sym_t)symp);
259 	}
260 
261 	return ((db_sym_t)0);
262 }
263 
264 /*
265  * Search for the symbol with the given address (matching within the
266  * provided threshold).
267  */
268 static db_sym_t
db_elf_search_symbol(db_symtab_t * symtab,db_addr_t off,db_strategy_t strategy,db_expr_t * diffp)269 db_elf_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strategy,
270     db_expr_t *diffp)
271 {
272 	Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end;
273 	db_addr_t diff = *diffp;
274 
275 	symtab = &db_symtabs;
276 
277 	symtab_start = STAB_TO_SYMSTART(symtab);
278 	symtab_end = STAB_TO_SYMEND(symtab);
279 
280 	rsymp = NULL;
281 
282 	for (symp = symtab_start; symp < symtab_end; symp++) {
283 		if (symp->st_name == 0)
284 			continue;
285 
286 #if 0
287 		/* This prevents me from seeing anythin in locore.s -- eeh */
288 		if (ELF_ST_TYPE(symp->st_info) != STT_OBJECT &&
289 		    ELF_ST_TYPE(symp->st_info) != STT_FUNC)
290 			continue;
291 #endif
292 
293 		if (off >= symp->st_value) {
294 			if (off - symp->st_value < diff) {
295 				diff = off - symp->st_value;
296 				rsymp = symp;
297 				if (diff == 0) {
298 					if (strategy == DB_STGY_PROC &&
299 					    ELFDEFNNAME(ST_TYPE)(symp->st_info)
300 					      == STT_FUNC &&
301 					    ELFDEFNNAME(ST_BIND)(symp->st_info)
302 					      != STB_LOCAL)
303 						break;
304 					if (strategy == DB_STGY_ANY &&
305 					    ELFDEFNNAME(ST_BIND)(symp->st_info)
306 					      != STB_LOCAL)
307 						break;
308 				}
309 			} else if (off - symp->st_value == diff) {
310 				if (rsymp == NULL)
311 					rsymp = symp;
312 				else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info)
313 				      == STB_LOCAL &&
314 				    ELFDEFNNAME(ST_BIND)(symp->st_info)
315 				      != STB_LOCAL) {
316 					/* pick the external symbol */
317 					rsymp = symp;
318 				}
319 			}
320 		}
321 	}
322 
323 	if (rsymp == NULL)
324 		*diffp = off;
325 	else
326 		*diffp = diff;
327 
328 	return ((db_sym_t)rsymp);
329 }
330 
331 /*
332  * Return the name and value for a symbol.
333  */
334 static void
db_elf_symbol_values(db_symtab_t * symtab,db_sym_t sym,const char ** namep,db_expr_t * valuep)335 db_elf_symbol_values(db_symtab_t *symtab, db_sym_t sym, const char **namep,
336     db_expr_t *valuep)
337 {
338 	Elf_Sym *symp = (Elf_Sym *)sym;
339 	char *strtab;
340 
341 	symtab = &db_symtabs;
342 
343 	if (namep) {
344 		strtab = db_elf_find_strtab(symtab);
345 		if (strtab == NULL)
346 			*namep = NULL;
347 		else
348 			*namep = strtab + symp->st_name;
349 	}
350 
351 	if (valuep)
352 		*valuep = symp->st_value;
353 }
354 
355 /*
356  * Return the file and line number of the current program counter
357  * if we can find the appropriate debugging symbol.
358  */
359 static bool
db_elf_line_at_pc(db_symtab_t * symtab,db_sym_t cursym,char ** filename,int * linenum,db_expr_t off)360 db_elf_line_at_pc(db_symtab_t *symtab, db_sym_t cursym, char **filename, 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 static bool
db_elf_sym_numargs(db_symtab_t * symtab,db_sym_t cursym,int * nargp,char ** argnamep)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 static void
db_elf_forall(db_symtab_t * stab,db_forall_func_t db_forall_func,void * arg)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 	stab = &db_symtabs;
392 
393 	symtab_start = STAB_TO_SYMSTART(stab);
394 	symtab_end = STAB_TO_SYMEND(stab);
395 
396 	strtab = db_elf_find_strtab(stab);
397 	if (strtab == NULL)
398 		return;
399 
400 	for (symp = symtab_start; symp < symtab_end; symp++)
401 		if (symp->st_name != 0) {
402 			suffix[1] = '\0';
403 			switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) {
404 			case STT_OBJECT:
405 				suffix[0] = '+';
406 				break;
407 			case STT_FUNC:
408 				suffix[0] = '*';
409 				break;
410 			case STT_SECTION:
411 				suffix[0] = '&';
412 				break;
413 			case STT_FILE:
414 				suffix[0] = '/';
415 				break;
416 			default:
417 				suffix[0] = '\0';
418 			}
419 			(*db_forall_func)(stab, (db_sym_t)symp,
420 			    strtab + symp->st_name, suffix, 0, arg);
421 		}
422 	return;
423 }
424 #endif /* DB_ELF_SYMBOLS */
425