1 /* $NetBSD: db_elf.c,v 1.18 2001/11/12 22:54:04 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.18 2001/11/12 22:54:04 lukem Exp $"); 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/proc.h> 47 48 #include <machine/db_machdep.h> 49 50 #include <ddb/db_sym.h> 51 #include <ddb/db_output.h> 52 #include <ddb/db_extern.h> 53 54 #ifdef DB_ELF_SYMBOLS 55 56 #ifndef DB_ELFSIZE 57 #error Must define DB_ELFSIZE! 58 #endif 59 60 #define ELFSIZE DB_ELFSIZE 61 62 #include <sys/exec_elf.h> 63 64 static char *db_elf_find_strtab __P((db_symtab_t *)); 65 66 #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start)) 67 #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end)) 68 #define STAB_TO_EHDR(stab) ((Elf_Ehdr *)((stab)->private)) 69 #define STAB_TO_SHDR(stab, e) ((Elf_Shdr *)((stab)->private + (e)->e_shoff)) 70 71 boolean_t db_elf_sym_init __P((int, void *, void *, const char *)); 72 db_sym_t db_elf_lookup __P((db_symtab_t *, char *)); 73 db_sym_t db_elf_search_symbol __P((db_symtab_t *, db_addr_t, 74 db_strategy_t, db_expr_t *)); 75 void db_elf_symbol_values __P((db_symtab_t *, db_sym_t, 76 char **, db_expr_t *)); 77 boolean_t db_elf_line_at_pc __P((db_symtab_t *, db_sym_t, 78 char **, int *, db_expr_t)); 79 boolean_t db_elf_sym_numargs __P((db_symtab_t *, db_sym_t, int *, 80 char **)); 81 void db_elf_forall __P((db_symtab_t *, 82 db_forall_func_t db_forall_func, void *)); 83 84 const db_symformat_t db_symformat_elf = { 85 "ELF", 86 db_elf_sym_init, 87 db_elf_lookup, 88 db_elf_search_symbol, 89 db_elf_symbol_values, 90 db_elf_line_at_pc, 91 db_elf_sym_numargs, 92 db_elf_forall 93 }; 94 95 /* 96 * Find the symbol table and strings; tell ddb about them. 97 */ 98 boolean_t 99 db_elf_sym_init(symsize, symtab, esymtab, name) 100 int symsize; /* size of symbol table */ 101 void *symtab; /* pointer to start of symbol table */ 102 void *esymtab; /* pointer to end of string table, 103 for checking - rounded up to integer 104 boundary */ 105 const char *name; 106 { 107 Elf_Ehdr *elf; 108 Elf_Shdr *shp; 109 Elf_Sym *symp, *symtab_start, *symtab_end; 110 char *strtab_start, *strtab_end; 111 int i, j; 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 goto badheader; 143 144 switch (elf->e_machine) { 145 146 ELFDEFNNAME(MACHDEP_ID_CASES) 147 148 default: 149 goto badheader; 150 } 151 152 /* 153 * Find the first (and, we hope, only) SHT_SYMTAB section in 154 * the file, and the SHT_STRTAB section that goes with it. 155 */ 156 if (elf->e_shoff == 0) 157 goto badheader; 158 shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff); 159 for (i = 0; i < elf->e_shnum; i++) { 160 if (shp[i].sh_type == SHT_SYMTAB) { 161 if (shp[i].sh_offset == 0) 162 continue; 163 /* Got the symbol table. */ 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 /* Find the string table to go with it. */ 169 j = shp[i].sh_link; 170 if (shp[j].sh_offset == 0) 171 continue; 172 strtab_start = (char *)symtab + shp[j].sh_offset; 173 strtab_end = (char *)symtab + shp[j].sh_offset + 174 shp[j].sh_size; 175 /* There should only be one symbol table. */ 176 break; 177 } 178 } 179 180 /* 181 * Now, sanity check the symbols against the string table. 182 */ 183 if (symtab_start == NULL || strtab_start == NULL || 184 ALIGNED_POINTER(symtab_start, long) == 0 || 185 ALIGNED_POINTER(strtab_start, long) == 0) 186 goto badheader; 187 for (symp = symtab_start; symp < symtab_end; symp++) 188 if (symp->st_name + strtab_start > strtab_end) 189 goto badheader; 190 191 /* 192 * Link the symbol table into the debugger. 193 */ 194 if (db_add_symbol_table((char *)symtab_start, 195 (char *)symtab_end, name, (char *)symtab) != -1) { 196 printf("[ using %lu bytes of %s ELF symbol table ]\n", 197 (u_long)roundup(((char *)esymtab - (char *)symtab), 198 sizeof(u_long)), name); 199 return (TRUE); 200 } 201 202 return (FALSE); 203 204 badheader: 205 printf("[ %s ELF symbol table not valid ]\n", name); 206 return (FALSE); 207 } 208 209 /* 210 * Internal helper function - return a pointer to the string table 211 * for the current symbol table. 212 */ 213 static char * 214 db_elf_find_strtab(stab) 215 db_symtab_t *stab; 216 { 217 Elf_Ehdr *elf = STAB_TO_EHDR(stab); 218 Elf_Shdr *shp = STAB_TO_SHDR(stab, elf); 219 int i; 220 221 /* 222 * We don't load ELF header for ELF modules. 223 * Find out if this is a loadable module. If so, 224 * string table comes right after symbol table. 225 */ 226 if ((Elf_Sym *)elf == STAB_TO_SYMSTART(stab)) { 227 return ((char *)STAB_TO_SYMEND(stab)); 228 } 229 for (i = 0; i < elf->e_shnum; i++) { 230 if (shp[i].sh_type == SHT_SYMTAB) 231 return ((char*)elf + shp[shp[i].sh_link].sh_offset); 232 } 233 234 return (NULL); 235 } 236 237 /* 238 * Lookup the symbol with the given name. 239 */ 240 db_sym_t 241 db_elf_lookup(stab, symstr) 242 db_symtab_t *stab; 243 char *symstr; 244 { 245 Elf_Sym *symp, *symtab_start, *symtab_end; 246 char *strtab; 247 248 symtab_start = STAB_TO_SYMSTART(stab); 249 symtab_end = STAB_TO_SYMEND(stab); 250 251 strtab = db_elf_find_strtab(stab); 252 if (strtab == NULL) 253 return ((db_sym_t)0); 254 255 for (symp = symtab_start; symp < symtab_end; symp++) { 256 if (symp->st_name != 0 && 257 db_eqname(strtab + symp->st_name, symstr, 0)) 258 return ((db_sym_t)symp); 259 } 260 261 return ((db_sym_t)0); 262 } 263 264 /* 265 * Search for the symbol with the given address (matching within the 266 * provided threshold). 267 */ 268 db_sym_t 269 db_elf_search_symbol(symtab, off, strategy, diffp) 270 db_symtab_t *symtab; 271 db_addr_t off; 272 db_strategy_t strategy; 273 db_expr_t *diffp; /* in/out */ 274 { 275 Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end; 276 db_expr_t diff = *diffp; 277 278 symtab_start = STAB_TO_SYMSTART(symtab); 279 symtab_end = STAB_TO_SYMEND(symtab); 280 281 rsymp = NULL; 282 283 for (symp = symtab_start; symp < symtab_end; symp++) { 284 if (symp->st_name == 0) 285 continue; 286 #if 0 287 /* This prevents me from seeing anythin in locore.s -- eeh */ 288 if (ELF_SYM_TYPE(symp->st_info) != Elf_estt_object && 289 ELF_SYM_TYPE(symp->st_info) != Elf_estt_func) 290 continue; 291 #endif 292 293 if (off >= symp->st_value) { 294 if ((off - symp->st_value) < diff) { 295 diff = off - symp->st_value; 296 rsymp = symp; 297 if (diff == 0) { 298 if (strategy == DB_STGY_PROC && 299 ELFDEFNNAME(ST_TYPE)(symp->st_info) 300 == STT_FUNC && 301 ELFDEFNNAME(ST_BIND)(symp->st_info) 302 != STB_LOCAL) 303 break; 304 if (strategy == DB_STGY_ANY && 305 ELFDEFNNAME(ST_BIND)(symp->st_info) 306 != STB_LOCAL) 307 break; 308 } 309 } else if ((off - symp->st_value) == diff) { 310 if (rsymp == NULL) 311 rsymp = symp; 312 else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info) 313 == STB_LOCAL && 314 ELFDEFNNAME(ST_BIND)(symp->st_info) 315 != STB_LOCAL) { 316 /* pick the external symbol */ 317 rsymp = symp; 318 } 319 } 320 } 321 } 322 323 if (rsymp == NULL) 324 *diffp = off; 325 else 326 *diffp = diff; 327 328 return ((db_sym_t)rsymp); 329 } 330 331 /* 332 * Return the name and value for a symbol. 333 */ 334 void 335 db_elf_symbol_values(symtab, sym, namep, valuep) 336 db_symtab_t *symtab; 337 db_sym_t sym; 338 char **namep; 339 db_expr_t *valuep; 340 { 341 Elf_Sym *symp = (Elf_Sym *)sym; 342 char *strtab; 343 344 if (namep) { 345 strtab = db_elf_find_strtab(symtab); 346 if (strtab == NULL) 347 *namep = NULL; 348 else 349 *namep = strtab + symp->st_name; 350 } 351 352 if (valuep) 353 *valuep = symp->st_value; 354 } 355 356 /* 357 * Return the file and line number of the current program counter 358 * if we can find the appropriate debugging symbol. 359 */ 360 boolean_t 361 db_elf_line_at_pc(symtab, cursym, filename, linenum, off) 362 db_symtab_t *symtab; 363 db_sym_t cursym; 364 char **filename; 365 int *linenum; 366 db_expr_t off; 367 { 368 369 /* 370 * XXX We don't support this (yet). 371 */ 372 return (FALSE); 373 } 374 375 /* 376 * Returns the number of arguments to a function and their 377 * names if we can find the appropriate debugging symbol. 378 */ 379 boolean_t 380 db_elf_sym_numargs(symtab, cursym, nargp, argnamep) 381 db_symtab_t *symtab; 382 db_sym_t cursym; 383 int *nargp; 384 char **argnamep; 385 { 386 387 /* 388 * XXX We don't support this (yet). 389 */ 390 return (FALSE); 391 } 392 393 void 394 db_elf_forall(stab, db_forall_func, arg) 395 db_symtab_t *stab; 396 db_forall_func_t db_forall_func; 397 void *arg; 398 { 399 char *strtab; 400 static char suffix[2]; 401 Elf_Sym *symp, *symtab_start, *symtab_end; 402 403 symtab_start = STAB_TO_SYMSTART(stab); 404 symtab_end = STAB_TO_SYMEND(stab); 405 406 strtab = db_elf_find_strtab(stab); 407 if (strtab == NULL) 408 return; 409 410 for (symp = symtab_start; symp < symtab_end; symp++) 411 if (symp->st_name != 0) { 412 suffix[1] = '\0'; 413 switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) { 414 case STT_OBJECT: 415 suffix[0] = '+'; 416 break; 417 case STT_FUNC: 418 suffix[0] = '*'; 419 break; 420 case STT_SECTION: 421 suffix[0] = '&'; 422 break; 423 case STT_FILE: 424 suffix[0] = '/'; 425 break; 426 default: 427 suffix[0] = '\0'; 428 } 429 (*db_forall_func)(stab, (db_sym_t)symp, 430 strtab + symp->st_name, suffix, 0, arg); 431 } 432 return; 433 } 434 #endif /* DB_ELF_SYMBOLS */ 435