1 /* $NetBSD: db_elf.c,v 1.19 2001/11/15 09:48:02 lukem 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/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: db_elf.c,v 1.19 2001/11/15 09:48:02 lukem Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/proc.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 __P((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 __P((int, void *, void *, const char *)); 71 db_sym_t db_elf_lookup __P((db_symtab_t *, char *)); 72 db_sym_t db_elf_search_symbol __P((db_symtab_t *, db_addr_t, 73 db_strategy_t, db_expr_t *)); 74 void db_elf_symbol_values __P((db_symtab_t *, db_sym_t, 75 char **, db_expr_t *)); 76 boolean_t db_elf_line_at_pc __P((db_symtab_t *, db_sym_t, 77 char **, int *, db_expr_t)); 78 boolean_t db_elf_sym_numargs __P((db_symtab_t *, db_sym_t, int *, 79 char **)); 80 void db_elf_forall __P((db_symtab_t *, 81 db_forall_func_t db_forall_func, void *)); 82 83 const 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 *strtab_start, *strtab_end; 110 int i, j; 111 112 if (ALIGNED_POINTER(symtab, long) == 0) { 113 printf("[ %s symbol table has bad start address %p ]\n", 114 name, symtab); 115 return (FALSE); 116 } 117 118 symtab_start = symtab_end = NULL; 119 strtab_start = strtab_end = NULL; 120 121 /* 122 * The format of the symbols loaded by the boot program is: 123 * 124 * Elf exec header 125 * first section header 126 * . . . 127 * . . . 128 * last section header 129 * first symbol or string table section 130 * . . . 131 * . . . 132 * last symbol or string table section 133 */ 134 135 /* 136 * Validate the Elf header. 137 */ 138 elf = (Elf_Ehdr *)symtab; 139 if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || 140 elf->e_ident[EI_CLASS] != ELFCLASS) 141 goto badheader; 142 143 switch (elf->e_machine) { 144 145 ELFDEFNNAME(MACHDEP_ID_CASES) 146 147 default: 148 goto badheader; 149 } 150 151 /* 152 * Find the first (and, we hope, only) SHT_SYMTAB section in 153 * the file, and the SHT_STRTAB section that goes with it. 154 */ 155 if (elf->e_shoff == 0) 156 goto badheader; 157 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff); 158 for (i = 0; i < elf->e_shnum; i++) { 159 if (shp[i].sh_type == SHT_SYMTAB) { 160 if (shp[i].sh_offset == 0) 161 continue; 162 /* Got the symbol table. */ 163 symtab_start = (Elf_Sym *)((char *)symtab + 164 shp[i].sh_offset); 165 symtab_end = (Elf_Sym *)((char *)symtab + 166 shp[i].sh_offset + shp[i].sh_size); 167 /* Find the string table to go with it. */ 168 j = shp[i].sh_link; 169 if (shp[j].sh_offset == 0) 170 continue; 171 strtab_start = (char *)symtab + shp[j].sh_offset; 172 strtab_end = (char *)symtab + shp[j].sh_offset + 173 shp[j].sh_size; 174 /* There should only be one symbol table. */ 175 break; 176 } 177 } 178 179 /* 180 * Now, sanity check the symbols against the string table. 181 */ 182 if (symtab_start == NULL || strtab_start == NULL || 183 ALIGNED_POINTER(symtab_start, long) == 0 || 184 ALIGNED_POINTER(strtab_start, long) == 0) 185 goto badheader; 186 for (symp = symtab_start; symp < symtab_end; symp++) 187 if (symp->st_name + strtab_start > strtab_end) 188 goto badheader; 189 190 /* 191 * Link the symbol table into the debugger. 192 */ 193 if (db_add_symbol_table((char *)symtab_start, 194 (char *)symtab_end, name, (char *)symtab) != -1) { 195 printf("[ using %lu bytes of %s ELF symbol table ]\n", 196 (u_long)roundup(((char *)esymtab - (char *)symtab), 197 sizeof(u_long)), name); 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 * 213 db_elf_find_strtab(stab) 214 db_symtab_t *stab; 215 { 216 Elf_Ehdr *elf = STAB_TO_EHDR(stab); 217 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf); 218 int i; 219 220 /* 221 * We don't load ELF header for ELF modules. 222 * Find out if this is a loadable module. If so, 223 * string table comes right after symbol table. 224 */ 225 if ((Elf_Sym *)elf == STAB_TO_SYMSTART(stab)) { 226 return ((char *)STAB_TO_SYMEND(stab)); 227 } 228 for (i = 0; i < elf->e_shnum; i++) { 229 if (shp[i].sh_type == SHT_SYMTAB) 230 return ((char*)elf + shp[shp[i].sh_link].sh_offset); 231 } 232 233 return (NULL); 234 } 235 236 /* 237 * Lookup the symbol with the given name. 238 */ 239 db_sym_t 240 db_elf_lookup(stab, symstr) 241 db_symtab_t *stab; 242 char *symstr; 243 { 244 Elf_Sym *symp, *symtab_start, *symtab_end; 245 char *strtab; 246 247 symtab_start = STAB_TO_SYMSTART(stab); 248 symtab_end = STAB_TO_SYMEND(stab); 249 250 strtab = db_elf_find_strtab(stab); 251 if (strtab == NULL) 252 return ((db_sym_t)0); 253 254 for (symp = symtab_start; symp < symtab_end; symp++) { 255 if (symp->st_name != 0 && 256 db_eqname(strtab + symp->st_name, symstr, 0)) 257 return ((db_sym_t)symp); 258 } 259 260 return ((db_sym_t)0); 261 } 262 263 /* 264 * Search for the symbol with the given address (matching within the 265 * provided threshold). 266 */ 267 db_sym_t 268 db_elf_search_symbol(symtab, off, strategy, diffp) 269 db_symtab_t *symtab; 270 db_addr_t off; 271 db_strategy_t strategy; 272 db_expr_t *diffp; /* in/out */ 273 { 274 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end; 275 db_expr_t diff = *diffp; 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 #if 0 286 /* This prevents me from seeing anythin in locore.s -- eeh */ 287 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object && 288 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func) 289 continue; 290 #endif 291 292 if (off >= symp->st_value) { 293 if ((off - symp->st_value) < diff) { 294 diff = off - symp->st_value; 295 rsymp = symp; 296 if (diff == 0) { 297 if (strategy == DB_STGY_PROC && 298 ELFDEFNNAME(ST_TYPE)(symp->st_info) 299 == STT_FUNC && 300 ELFDEFNNAME(ST_BIND)(symp->st_info) 301 != STB_LOCAL) 302 break; 303 if (strategy == DB_STGY_ANY && 304 ELFDEFNNAME(ST_BIND)(symp->st_info) 305 != STB_LOCAL) 306 break; 307 } 308 } else if ((off - symp->st_value) == diff) { 309 if (rsymp == NULL) 310 rsymp = symp; 311 else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info) 312 == STB_LOCAL && 313 ELFDEFNNAME(ST_BIND)(symp->st_info) 314 != STB_LOCAL) { 315 /* pick the external symbol */ 316 rsymp = symp; 317 } 318 } 319 } 320 } 321 322 if (rsymp == NULL) 323 *diffp = off; 324 else 325 *diffp = diff; 326 327 return ((db_sym_t)rsymp); 328 } 329 330 /* 331 * Return the name and value for a symbol. 332 */ 333 void 334 db_elf_symbol_values(symtab, sym, namep, valuep) 335 db_symtab_t *symtab; 336 db_sym_t sym; 337 char **namep; 338 db_expr_t *valuep; 339 { 340 Elf_Sym *symp = (Elf_Sym *)sym; 341 char *strtab; 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 boolean_t 360 db_elf_line_at_pc(symtab, cursym, filename, linenum, off) 361 db_symtab_t *symtab; 362 db_sym_t cursym; 363 char **filename; 364 int *linenum; 365 db_expr_t off; 366 { 367 368 /* 369 * XXX We don't support this (yet). 370 */ 371 return (FALSE); 372 } 373 374 /* 375 * Returns the number of arguments to a function and their 376 * names if we can find the appropriate debugging symbol. 377 */ 378 boolean_t 379 db_elf_sym_numargs(symtab, cursym, nargp, argnamep) 380 db_symtab_t *symtab; 381 db_sym_t cursym; 382 int *nargp; 383 char **argnamep; 384 { 385 386 /* 387 * XXX We don't support this (yet). 388 */ 389 return (FALSE); 390 } 391 392 void 393 db_elf_forall(stab, db_forall_func, arg) 394 db_symtab_t *stab; 395 db_forall_func_t db_forall_func; 396 void *arg; 397 { 398 char *strtab; 399 static char suffix[2]; 400 Elf_Sym *symp, *symtab_start, *symtab_end; 401 402 symtab_start = STAB_TO_SYMSTART(stab); 403 symtab_end = STAB_TO_SYMEND(stab); 404 405 strtab = db_elf_find_strtab(stab); 406 if (strtab == NULL) 407 return; 408 409 for (symp = symtab_start; symp < symtab_end; symp++) 410 if (symp->st_name != 0) { 411 suffix[1] = '\0'; 412 switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) { 413 case STT_OBJECT: 414 suffix[0] = '+'; 415 break; 416 case STT_FUNC: 417 suffix[0] = '*'; 418 break; 419 case STT_SECTION: 420 suffix[0] = '&'; 421 break; 422 case STT_FILE: 423 suffix[0] = '/'; 424 break; 425 default: 426 suffix[0] = '\0'; 427 } 428 (*db_forall_func)(stab, (db_sym_t)symp, 429 strtab + symp->st_name, suffix, 0, arg); 430 } 431 return; 432 } 433 #endif /* DB_ELF_SYMBOLS */ 434