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