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