1 /* $NetBSD: db_elf.c,v 1.13 2000/07/07 21:55:18 jhawk 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 void db_elf_forall __P((db_symtab_t *, 79 db_forall_func_t db_forall_func, void *)); 80 81 db_symformat_t db_symformat_elf = { 82 "ELF", 83 db_elf_sym_init, 84 db_elf_lookup, 85 db_elf_search_symbol, 86 db_elf_symbol_values, 87 db_elf_line_at_pc, 88 db_elf_sym_numargs, 89 db_elf_forall 90 }; 91 92 /* 93 * Find the symbol table and strings; tell ddb about them. 94 */ 95 boolean_t 96 db_elf_sym_init(symsize, symtab, esymtab, name) 97 int symsize; /* size of symbol table */ 98 void *symtab; /* pointer to start of symbol table */ 99 void *esymtab; /* pointer to end of string table, 100 for checking - rounded up to integer 101 boundary */ 102 const char *name; 103 { 104 Elf_Ehdr *elf; 105 Elf_Shdr *shp; 106 Elf_Sym *symp, *symtab_start, *symtab_end; 107 char *shstrtab, *strtab_start, *strtab_end; 108 int i; 109 110 if (ALIGNED_POINTER(symtab, long) == 0) { 111 printf("[ %s symbol table has bad start address %p ]\n", 112 name, symtab); 113 return (FALSE); 114 } 115 116 symtab_start = symtab_end = NULL; 117 strtab_start = strtab_end = NULL; 118 119 /* 120 * The format of the symbols loaded by the boot program is: 121 * 122 * Elf exec header 123 * first section header 124 * . . . 125 * . . . 126 * last section header 127 * first symbol or string table section 128 * . . . 129 * . . . 130 * last symbol or string table section 131 */ 132 133 /* 134 * Validate the Elf header. 135 */ 136 elf = (Elf_Ehdr *)symtab; 137 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || 138 elf->e_ident[EI_CLASS] != ELFCLASS) 139 goto badheader; 140 141 switch (elf->e_machine) { 142 143 ELFDEFNNAME(MACHDEP_ID_CASES) 144 145 default: 146 goto badheader; 147 } 148 149 /* 150 * Find the section header string table (.shstrtab), and look up 151 * the symbol table (.symtab) and string table (.strtab) via their 152 * names in shstrtab, rather than by table type. 153 * This works in the presence of multiple string tables, such as 154 * stabs data found when booting netbsd.gdb. 155 */ 156 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff); 157 shstrtab = (char*)symtab + shp[elf->e_shstrndx].sh_offset; 158 for (i = 0; i < elf->e_shnum; i++) { 159 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) { 160 strtab_start = (char *)symtab + shp[i].sh_offset; 161 strtab_end = (char *)symtab + shp[i].sh_offset + 162 shp[i].sh_size; 163 } else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) { 164 symtab_start = (Elf_Sym *)((char *)symtab + 165 shp[i].sh_offset); 166 symtab_end = (Elf_Sym *)((char *)symtab + 167 shp[i].sh_offset + shp[i].sh_size); 168 } 169 } 170 171 /* 172 * Now, sanity check the symbols against the string table. 173 */ 174 if (symtab_start == NULL || strtab_start == NULL || 175 ALIGNED_POINTER(symtab_start, long) == 0 || 176 ALIGNED_POINTER(strtab_start, long) == 0) 177 goto badheader; 178 for (symp = symtab_start; symp < symtab_end; symp++) 179 if (symp->st_name + strtab_start > strtab_end) 180 goto badheader; 181 182 /* 183 * Link the symbol table into the debugger. 184 */ 185 if (db_add_symbol_table((char *)symtab_start, 186 (char *)symtab_end, name, (char *)symtab) != -1) { 187 printf("[ using %lu bytes of %s ELF symbol table ]\n", 188 (u_long)roundup(((char *)esymtab - (char *)symtab), 189 sizeof(u_long)), name); 190 return (TRUE); 191 } 192 193 return (FALSE); 194 195 badheader: 196 printf("[ %s ELF symbol table not valid ]\n", name); 197 return (FALSE); 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(stab) 206 db_symtab_t *stab; 207 { 208 Elf_Ehdr *elf = STAB_TO_EHDR(stab); 209 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf); 210 char *shstrtab; 211 int i; 212 213 shstrtab = (char*)elf + shp[elf->e_shstrndx].sh_offset; 214 for (i = 0; i < elf->e_shnum; i++) { 215 if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) 216 return ((char*)elf + shp[i].sh_offset); 217 } 218 219 return (NULL); 220 } 221 222 /* 223 * Lookup the symbol with the given name. 224 */ 225 db_sym_t 226 db_elf_lookup(stab, symstr) 227 db_symtab_t *stab; 228 char *symstr; 229 { 230 Elf_Sym *symp, *symtab_start, *symtab_end; 231 char *strtab; 232 233 symtab_start = STAB_TO_SYMSTART(stab); 234 symtab_end = STAB_TO_SYMEND(stab); 235 236 strtab = db_elf_find_strtab(stab); 237 if (strtab == NULL) 238 return ((db_sym_t)0); 239 240 for (symp = symtab_start; symp < symtab_end; symp++) { 241 if (symp->st_name != 0 && 242 db_eqname(strtab + symp->st_name, symstr, 0)) 243 return ((db_sym_t)symp); 244 } 245 246 return ((db_sym_t)0); 247 } 248 249 /* 250 * Search for the symbol with the given address (matching within the 251 * provided threshold). 252 */ 253 db_sym_t 254 db_elf_search_symbol(symtab, off, strategy, diffp) 255 db_symtab_t *symtab; 256 db_addr_t off; 257 db_strategy_t strategy; 258 db_expr_t *diffp; /* in/out */ 259 { 260 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end; 261 db_expr_t diff = *diffp; 262 263 symtab_start = STAB_TO_SYMSTART(symtab); 264 symtab_end = STAB_TO_SYMEND(symtab); 265 266 rsymp = NULL; 267 268 for (symp = symtab_start; symp < symtab_end; symp++) { 269 if (symp->st_name == 0) 270 continue; 271 #if 0 272 /* This prevents me from seeing anythin in locore.s -- eeh */ 273 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object && 274 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func) 275 continue; 276 #endif 277 278 if (off >= symp->st_value) { 279 if ((off - symp->st_value) < diff) { 280 diff = off - symp->st_value; 281 rsymp = symp; 282 if (diff == 0) { 283 if (strategy == DB_STGY_PROC && 284 ELFDEFNNAME(ST_TYPE)(symp->st_info) 285 == STT_FUNC && 286 ELFDEFNNAME(ST_BIND)(symp->st_info) 287 != STB_LOCAL) 288 break; 289 if (strategy == DB_STGY_ANY && 290 ELFDEFNNAME(ST_BIND)(symp->st_info) 291 != STB_LOCAL) 292 break; 293 } 294 } else if ((off - symp->st_value) == diff) { 295 if (rsymp == NULL) 296 rsymp = symp; 297 else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info) 298 == STB_LOCAL && 299 ELFDEFNNAME(ST_BIND)(symp->st_info) 300 != STB_LOCAL) { 301 /* pick the external symbol */ 302 rsymp = symp; 303 } 304 } 305 } 306 } 307 308 if (rsymp == NULL) 309 *diffp = off; 310 else 311 *diffp = diff; 312 313 return ((db_sym_t)rsymp); 314 } 315 316 /* 317 * Return the name and value for a symbol. 318 */ 319 void 320 db_elf_symbol_values(symtab, sym, namep, valuep) 321 db_symtab_t *symtab; 322 db_sym_t sym; 323 char **namep; 324 db_expr_t *valuep; 325 { 326 Elf_Sym *symp = (Elf_Sym *)sym; 327 char *strtab; 328 329 if (namep) { 330 strtab = db_elf_find_strtab(symtab); 331 if (strtab == NULL) 332 *namep = NULL; 333 else 334 *namep = strtab + symp->st_name; 335 } 336 337 if (valuep) 338 *valuep = symp->st_value; 339 } 340 341 /* 342 * Return the file and line number of the current program counter 343 * if we can find the appropriate debugging symbol. 344 */ 345 boolean_t 346 db_elf_line_at_pc(symtab, cursym, filename, linenum, off) 347 db_symtab_t *symtab; 348 db_sym_t cursym; 349 char **filename; 350 int *linenum; 351 db_expr_t off; 352 { 353 354 /* 355 * XXX We don't support this (yet). 356 */ 357 return (FALSE); 358 } 359 360 /* 361 * Returns the number of arguments to a function and their 362 * names if we can find the appropriate debugging symbol. 363 */ 364 boolean_t 365 db_elf_sym_numargs(symtab, cursym, nargp, argnamep) 366 db_symtab_t *symtab; 367 db_sym_t cursym; 368 int *nargp; 369 char **argnamep; 370 { 371 372 /* 373 * XXX We don't support this (yet). 374 */ 375 return (FALSE); 376 } 377 378 void 379 db_elf_forall(stab, db_forall_func, arg) 380 db_symtab_t *stab; 381 db_forall_func_t db_forall_func; 382 void *arg; 383 { 384 char *strtab; 385 static char suffix[2]; 386 Elf_Sym *symp, *symtab_start, *symtab_end; 387 388 symtab_start = STAB_TO_SYMSTART(stab); 389 symtab_end = STAB_TO_SYMEND(stab); 390 391 strtab = db_elf_find_strtab(stab); 392 if (strtab == NULL) 393 return; 394 395 for (symp = symtab_start; symp < symtab_end; symp++) 396 if (symp->st_name != 0) { 397 suffix[1] = '\0'; 398 switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) { 399 case STT_OBJECT: 400 suffix[0] = '+'; 401 break; 402 case STT_FUNC: 403 suffix[0] = '*'; 404 break; 405 case STT_SECTION: 406 suffix[0] = '&'; 407 break; 408 case STT_FILE: 409 suffix[0] = '/'; 410 break; 411 default: 412 suffix[0] = '\0'; 413 } 414 (*db_forall_func)(stab, (db_sym_t)symp, 415 strtab + symp->st_name, suffix, 0, arg); 416 } 417 return; 418 } 419 #endif /* DB_ELF_SYMBOLS */ 420