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