1 1.29 christos /* $NetBSD: db_elf.c,v 1.29 2017/11/06 04:08:02 christos Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /*- 4 1.26 ad * Copyright (c) 1997, 2009 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.1 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.26 ad * NASA Ames Research Center, and by Andrew Doran. 10 1.1 thorpej * 11 1.1 thorpej * Redistribution and use in source and binary forms, with or without 12 1.1 thorpej * modification, are permitted provided that the following conditions 13 1.1 thorpej * are met: 14 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer. 16 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 18 1.1 thorpej * documentation and/or other materials provided with the distribution. 19 1.1 thorpej * 20 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE. 31 1.1 thorpej */ 32 1.18 lukem 33 1.18 lukem #include <sys/cdefs.h> 34 1.29 christos __KERNEL_RCSID(0, "$NetBSD: db_elf.c,v 1.29 2017/11/06 04:08:02 christos Exp $"); 35 1.1 thorpej 36 1.1 thorpej #include <sys/param.h> 37 1.20 simonb #include <sys/systm.h> 38 1.1 thorpej #include <sys/proc.h> 39 1.1 thorpej 40 1.28 christos #include <machine/db_machdep.h> 41 1.26 ad #include <machine/pmap.h> 42 1.26 ad #include <machine/vmparam.h> 43 1.1 thorpej 44 1.1 thorpej #ifdef DB_ELF_SYMBOLS 45 1.1 thorpej 46 1.28 christos #include <ddb/ddb.h> 47 1.1 thorpej #include <sys/exec_elf.h> 48 1.1 thorpej 49 1.20 simonb static char *db_elf_find_strtab(db_symtab_t *); 50 1.1 thorpej 51 1.1 thorpej #define STAB_TO_SYMSTART(stab) ((Elf_Sym *)((stab)->start)) 52 1.1 thorpej #define STAB_TO_SYMEND(stab) ((Elf_Sym *)((stab)->end)) 53 1.1 thorpej #define STAB_TO_EHDR(stab) ((Elf_Ehdr *)((stab)->private)) 54 1.1 thorpej #define STAB_TO_SHDR(stab, e) ((Elf_Shdr *)((stab)->private + (e)->e_shoff)) 55 1.1 thorpej 56 1.23 thorpej static bool db_elf_sym_init(int, void *, void *, const char *); 57 1.26 ad static db_sym_t db_elf_lookup(db_symtab_t *, const char *); 58 1.20 simonb static db_sym_t db_elf_search_symbol(db_symtab_t *, db_addr_t, db_strategy_t, 59 1.20 simonb db_expr_t *); 60 1.26 ad static void db_elf_symbol_values(db_symtab_t *, db_sym_t, const char **, 61 1.20 simonb db_expr_t *); 62 1.23 thorpej static bool db_elf_line_at_pc(db_symtab_t *, db_sym_t, char **, int *, 63 1.20 simonb db_expr_t); 64 1.23 thorpej static bool db_elf_sym_numargs(db_symtab_t *, db_sym_t, int *, char **); 65 1.20 simonb static void db_elf_forall(db_symtab_t *, db_forall_func_t db_forall_func, 66 1.20 simonb void *); 67 1.7 thorpej 68 1.14 jdolecek const db_symformat_t db_symformat_elf = { 69 1.7 thorpej "ELF", 70 1.7 thorpej db_elf_sym_init, 71 1.7 thorpej db_elf_lookup, 72 1.7 thorpej db_elf_search_symbol, 73 1.7 thorpej db_elf_symbol_values, 74 1.7 thorpej db_elf_line_at_pc, 75 1.7 thorpej db_elf_sym_numargs, 76 1.11 jhawk db_elf_forall 77 1.7 thorpej }; 78 1.7 thorpej 79 1.26 ad static db_symtab_t db_symtabs; 80 1.26 ad 81 1.26 ad /* 82 1.26 ad * Add symbol table, with given name, to symbol tables. 83 1.26 ad */ 84 1.26 ad static int 85 1.26 ad db_add_symbol_table(char *start, char *end, const char *name, char *ref) 86 1.26 ad { 87 1.26 ad 88 1.26 ad db_symtabs.start = start; 89 1.26 ad db_symtabs.end = end; 90 1.26 ad db_symtabs.name = name; 91 1.26 ad db_symtabs.private = ref; 92 1.26 ad 93 1.26 ad return(0); 94 1.26 ad } 95 1.26 ad 96 1.1 thorpej /* 97 1.1 thorpej * Find the symbol table and strings; tell ddb about them. 98 1.1 thorpej */ 99 1.23 thorpej static bool 100 1.20 simonb db_elf_sym_init( 101 1.20 simonb int symsize, /* size of symbol table */ 102 1.20 simonb void *symtab, /* pointer to start of symbol table */ 103 1.20 simonb void *esymtab, /* pointer to end of string table, 104 1.1 thorpej for checking - rounded up to integer 105 1.1 thorpej boundary */ 106 1.20 simonb const char *name 107 1.20 simonb ) 108 1.1 thorpej { 109 1.1 thorpej Elf_Ehdr *elf; 110 1.1 thorpej Elf_Shdr *shp; 111 1.1 thorpej Elf_Sym *symp, *symtab_start, *symtab_end; 112 1.15 bjh21 char *strtab_start, *strtab_end; 113 1.15 bjh21 int i, j; 114 1.1 thorpej 115 1.1 thorpej if (ALIGNED_POINTER(symtab, long) == 0) { 116 1.7 thorpej printf("[ %s symbol table has bad start address %p ]\n", 117 1.7 thorpej name, symtab); 118 1.24 thorpej return (false); 119 1.1 thorpej } 120 1.1 thorpej 121 1.1 thorpej symtab_start = symtab_end = NULL; 122 1.1 thorpej strtab_start = strtab_end = NULL; 123 1.1 thorpej 124 1.1 thorpej /* 125 1.1 thorpej * The format of the symbols loaded by the boot program is: 126 1.1 thorpej * 127 1.1 thorpej * Elf exec header 128 1.1 thorpej * first section header 129 1.1 thorpej * . . . 130 1.1 thorpej * . . . 131 1.1 thorpej * last section header 132 1.1 thorpej * first symbol or string table section 133 1.1 thorpej * . . . 134 1.1 thorpej * . . . 135 1.1 thorpej * last symbol or string table section 136 1.1 thorpej */ 137 1.1 thorpej 138 1.1 thorpej /* 139 1.1 thorpej * Validate the Elf header. 140 1.1 thorpej */ 141 1.1 thorpej elf = (Elf_Ehdr *)symtab; 142 1.10 kleink if (memcmp(elf->e_ident, ELFMAG, SELFMAG) != 0 || 143 1.10 kleink elf->e_ident[EI_CLASS] != ELFCLASS) 144 1.1 thorpej goto badheader; 145 1.1 thorpej 146 1.1 thorpej switch (elf->e_machine) { 147 1.1 thorpej 148 1.9 erh ELFDEFNNAME(MACHDEP_ID_CASES) 149 1.1 thorpej 150 1.1 thorpej default: 151 1.1 thorpej goto badheader; 152 1.1 thorpej } 153 1.1 thorpej 154 1.1 thorpej /* 155 1.15 bjh21 * Find the first (and, we hope, only) SHT_SYMTAB section in 156 1.15 bjh21 * the file, and the SHT_STRTAB section that goes with it. 157 1.1 thorpej */ 158 1.16 bjh21 if (elf->e_shoff == 0) 159 1.16 bjh21 goto badheader; 160 1.8 augustss shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff); 161 1.1 thorpej for (i = 0; i < elf->e_shnum; i++) { 162 1.15 bjh21 if (shp[i].sh_type == SHT_SYMTAB) { 163 1.16 bjh21 if (shp[i].sh_offset == 0) 164 1.16 bjh21 continue; 165 1.15 bjh21 /* Got the symbol table. */ 166 1.20 simonb symtab_start = (Elf_Sym *)((char *)symtab + 167 1.8 augustss shp[i].sh_offset); 168 1.20 simonb symtab_end = (Elf_Sym *)((char *)symtab + 169 1.8 augustss shp[i].sh_offset + shp[i].sh_size); 170 1.15 bjh21 /* Find the string table to go with it. */ 171 1.15 bjh21 j = shp[i].sh_link; 172 1.16 bjh21 if (shp[j].sh_offset == 0) 173 1.16 bjh21 continue; 174 1.15 bjh21 strtab_start = (char *)symtab + shp[j].sh_offset; 175 1.15 bjh21 strtab_end = (char *)symtab + shp[j].sh_offset + 176 1.15 bjh21 shp[j].sh_size; 177 1.15 bjh21 /* There should only be one symbol table. */ 178 1.15 bjh21 break; 179 1.1 thorpej } 180 1.1 thorpej } 181 1.1 thorpej 182 1.1 thorpej /* 183 1.1 thorpej * Now, sanity check the symbols against the string table. 184 1.1 thorpej */ 185 1.2 thorpej if (symtab_start == NULL || strtab_start == NULL || 186 1.2 thorpej ALIGNED_POINTER(symtab_start, long) == 0 || 187 1.2 thorpej ALIGNED_POINTER(strtab_start, long) == 0) 188 1.1 thorpej goto badheader; 189 1.1 thorpej for (symp = symtab_start; symp < symtab_end; symp++) 190 1.1 thorpej if (symp->st_name + strtab_start > strtab_end) 191 1.1 thorpej goto badheader; 192 1.1 thorpej 193 1.1 thorpej /* 194 1.1 thorpej * Link the symbol table into the debugger. 195 1.1 thorpej */ 196 1.1 thorpej if (db_add_symbol_table((char *)symtab_start, 197 1.7 thorpej (char *)symtab_end, name, (char *)symtab) != -1) { 198 1.24 thorpej return (true); 199 1.7 thorpej } 200 1.7 thorpej 201 1.24 thorpej return (false); 202 1.1 thorpej 203 1.1 thorpej badheader: 204 1.7 thorpej printf("[ %s ELF symbol table not valid ]\n", name); 205 1.24 thorpej return (false); 206 1.1 thorpej } 207 1.1 thorpej 208 1.1 thorpej /* 209 1.1 thorpej * Internal helper function - return a pointer to the string table 210 1.1 thorpej * for the current symbol table. 211 1.1 thorpej */ 212 1.1 thorpej static char * 213 1.20 simonb db_elf_find_strtab(db_symtab_t *stab) 214 1.1 thorpej { 215 1.1 thorpej Elf_Ehdr *elf = STAB_TO_EHDR(stab); 216 1.1 thorpej Elf_Shdr *shp = STAB_TO_SHDR(stab, elf); 217 1.1 thorpej int i; 218 1.1 thorpej 219 1.26 ad stab = &db_symtabs; 220 1.26 ad 221 1.17 christos /* 222 1.17 christos * We don't load ELF header for ELF modules. 223 1.17 christos * Find out if this is a loadable module. If so, 224 1.17 christos * string table comes right after symbol table. 225 1.17 christos */ 226 1.17 christos if ((Elf_Sym *)elf == STAB_TO_SYMSTART(stab)) { 227 1.17 christos return ((char *)STAB_TO_SYMEND(stab)); 228 1.17 christos } 229 1.1 thorpej for (i = 0; i < elf->e_shnum; i++) { 230 1.15 bjh21 if (shp[i].sh_type == SHT_SYMTAB) 231 1.15 bjh21 return ((char*)elf + shp[shp[i].sh_link].sh_offset); 232 1.1 thorpej } 233 1.1 thorpej 234 1.1 thorpej return (NULL); 235 1.1 thorpej } 236 1.1 thorpej 237 1.1 thorpej /* 238 1.1 thorpej * Lookup the symbol with the given name. 239 1.1 thorpej */ 240 1.20 simonb static db_sym_t 241 1.26 ad db_elf_lookup(db_symtab_t *stab, const char *symstr) 242 1.1 thorpej { 243 1.1 thorpej Elf_Sym *symp, *symtab_start, *symtab_end; 244 1.1 thorpej char *strtab; 245 1.1 thorpej 246 1.26 ad stab = &db_symtabs; 247 1.26 ad 248 1.1 thorpej symtab_start = STAB_TO_SYMSTART(stab); 249 1.1 thorpej symtab_end = STAB_TO_SYMEND(stab); 250 1.1 thorpej 251 1.1 thorpej strtab = db_elf_find_strtab(stab); 252 1.1 thorpej if (strtab == NULL) 253 1.1 thorpej return ((db_sym_t)0); 254 1.1 thorpej 255 1.1 thorpej for (symp = symtab_start; symp < symtab_end; symp++) { 256 1.1 thorpej if (symp->st_name != 0 && 257 1.1 thorpej db_eqname(strtab + symp->st_name, symstr, 0)) 258 1.1 thorpej return ((db_sym_t)symp); 259 1.1 thorpej } 260 1.1 thorpej 261 1.1 thorpej return ((db_sym_t)0); 262 1.1 thorpej } 263 1.1 thorpej 264 1.1 thorpej /* 265 1.1 thorpej * Search for the symbol with the given address (matching within the 266 1.1 thorpej * provided threshold). 267 1.1 thorpej */ 268 1.20 simonb static db_sym_t 269 1.20 simonb db_elf_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strategy, 270 1.20 simonb db_expr_t *diffp) 271 1.1 thorpej { 272 1.1 thorpej Elf_Sym *rsymp, *symp, *symtab_start, *symtab_end; 273 1.22 yamt db_addr_t diff = *diffp; 274 1.1 thorpej 275 1.26 ad symtab = &db_symtabs; 276 1.26 ad 277 1.1 thorpej symtab_start = STAB_TO_SYMSTART(symtab); 278 1.1 thorpej symtab_end = STAB_TO_SYMEND(symtab); 279 1.1 thorpej 280 1.1 thorpej rsymp = NULL; 281 1.1 thorpej 282 1.1 thorpej for (symp = symtab_start; symp < symtab_end; symp++) { 283 1.1 thorpej if (symp->st_name == 0) 284 1.1 thorpej continue; 285 1.26 ad 286 1.6 eeh #if 0 287 1.6 eeh /* This prevents me from seeing anythin in locore.s -- eeh */ 288 1.26 ad if (ELF_ST_TYPE(symp->st_info) != STT_OBJECT && 289 1.26 ad ELF_ST_TYPE(symp->st_info) != STT_FUNC) 290 1.1 thorpej continue; 291 1.6 eeh #endif 292 1.1 thorpej 293 1.1 thorpej if (off >= symp->st_value) { 294 1.22 yamt if (off - symp->st_value < diff) { 295 1.1 thorpej diff = off - symp->st_value; 296 1.1 thorpej rsymp = symp; 297 1.1 thorpej if (diff == 0) { 298 1.1 thorpej if (strategy == DB_STGY_PROC && 299 1.10 kleink ELFDEFNNAME(ST_TYPE)(symp->st_info) 300 1.10 kleink == STT_FUNC && 301 1.10 kleink ELFDEFNNAME(ST_BIND)(symp->st_info) 302 1.10 kleink != STB_LOCAL) 303 1.1 thorpej break; 304 1.1 thorpej if (strategy == DB_STGY_ANY && 305 1.10 kleink ELFDEFNNAME(ST_BIND)(symp->st_info) 306 1.10 kleink != STB_LOCAL) 307 1.1 thorpej break; 308 1.1 thorpej } 309 1.22 yamt } else if (off - symp->st_value == diff) { 310 1.1 thorpej if (rsymp == NULL) 311 1.1 thorpej rsymp = symp; 312 1.10 kleink else if (ELFDEFNNAME(ST_BIND)(rsymp->st_info) 313 1.10 kleink == STB_LOCAL && 314 1.10 kleink ELFDEFNNAME(ST_BIND)(symp->st_info) 315 1.10 kleink != STB_LOCAL) { 316 1.1 thorpej /* pick the external symbol */ 317 1.1 thorpej rsymp = symp; 318 1.1 thorpej } 319 1.1 thorpej } 320 1.1 thorpej } 321 1.1 thorpej } 322 1.1 thorpej 323 1.1 thorpej if (rsymp == NULL) 324 1.1 thorpej *diffp = off; 325 1.1 thorpej else 326 1.1 thorpej *diffp = diff; 327 1.1 thorpej 328 1.1 thorpej return ((db_sym_t)rsymp); 329 1.1 thorpej } 330 1.1 thorpej 331 1.1 thorpej /* 332 1.1 thorpej * Return the name and value for a symbol. 333 1.1 thorpej */ 334 1.20 simonb static void 335 1.26 ad db_elf_symbol_values(db_symtab_t *symtab, db_sym_t sym, const char **namep, 336 1.20 simonb db_expr_t *valuep) 337 1.1 thorpej { 338 1.1 thorpej Elf_Sym *symp = (Elf_Sym *)sym; 339 1.1 thorpej char *strtab; 340 1.1 thorpej 341 1.26 ad symtab = &db_symtabs; 342 1.26 ad 343 1.1 thorpej if (namep) { 344 1.1 thorpej strtab = db_elf_find_strtab(symtab); 345 1.1 thorpej if (strtab == NULL) 346 1.1 thorpej *namep = NULL; 347 1.1 thorpej else 348 1.1 thorpej *namep = strtab + symp->st_name; 349 1.1 thorpej } 350 1.1 thorpej 351 1.1 thorpej if (valuep) 352 1.1 thorpej *valuep = symp->st_value; 353 1.1 thorpej } 354 1.1 thorpej 355 1.1 thorpej /* 356 1.1 thorpej * Return the file and line number of the current program counter 357 1.1 thorpej * if we can find the appropriate debugging symbol. 358 1.1 thorpej */ 359 1.23 thorpej static bool 360 1.27 dsl db_elf_line_at_pc(db_symtab_t *symtab, db_sym_t cursym, char **filename, int *linenum, db_expr_t off) 361 1.1 thorpej { 362 1.1 thorpej 363 1.1 thorpej /* 364 1.1 thorpej * XXX We don't support this (yet). 365 1.1 thorpej */ 366 1.24 thorpej return (false); 367 1.1 thorpej } 368 1.1 thorpej 369 1.1 thorpej /* 370 1.1 thorpej * Returns the number of arguments to a function and their 371 1.1 thorpej * names if we can find the appropriate debugging symbol. 372 1.1 thorpej */ 373 1.23 thorpej static bool 374 1.20 simonb db_elf_sym_numargs(db_symtab_t *symtab, db_sym_t cursym, int *nargp, 375 1.20 simonb char **argnamep) 376 1.1 thorpej { 377 1.1 thorpej 378 1.1 thorpej /* 379 1.1 thorpej * XXX We don't support this (yet). 380 1.1 thorpej */ 381 1.24 thorpej return (false); 382 1.11 jhawk } 383 1.11 jhawk 384 1.20 simonb static void 385 1.20 simonb db_elf_forall(db_symtab_t *stab, db_forall_func_t db_forall_func, void *arg) 386 1.11 jhawk { 387 1.11 jhawk char *strtab; 388 1.11 jhawk static char suffix[2]; 389 1.11 jhawk Elf_Sym *symp, *symtab_start, *symtab_end; 390 1.11 jhawk 391 1.26 ad stab = &db_symtabs; 392 1.26 ad 393 1.11 jhawk symtab_start = STAB_TO_SYMSTART(stab); 394 1.11 jhawk symtab_end = STAB_TO_SYMEND(stab); 395 1.11 jhawk 396 1.11 jhawk strtab = db_elf_find_strtab(stab); 397 1.11 jhawk if (strtab == NULL) 398 1.11 jhawk return; 399 1.11 jhawk 400 1.11 jhawk for (symp = symtab_start; symp < symtab_end; symp++) 401 1.11 jhawk if (symp->st_name != 0) { 402 1.11 jhawk suffix[1] = '\0'; 403 1.11 jhawk switch (ELFDEFNNAME(ST_TYPE)(symp->st_info)) { 404 1.11 jhawk case STT_OBJECT: 405 1.11 jhawk suffix[0] = '+'; 406 1.11 jhawk break; 407 1.11 jhawk case STT_FUNC: 408 1.11 jhawk suffix[0] = '*'; 409 1.11 jhawk break; 410 1.11 jhawk case STT_SECTION: 411 1.11 jhawk suffix[0] = '&'; 412 1.11 jhawk break; 413 1.11 jhawk case STT_FILE: 414 1.11 jhawk suffix[0] = '/'; 415 1.11 jhawk break; 416 1.11 jhawk default: 417 1.11 jhawk suffix[0] = '\0'; 418 1.11 jhawk } 419 1.11 jhawk (*db_forall_func)(stab, (db_sym_t)symp, 420 1.11 jhawk strtab + symp->st_name, suffix, 0, arg); 421 1.11 jhawk } 422 1.11 jhawk return; 423 1.1 thorpej } 424 1.1 thorpej #endif /* DB_ELF_SYMBOLS */ 425