1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 24 * 25 * Copyright 2011 Jason King. All rights reserved. 26 */ 27 28 #include <assert.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <gelf.h> 32 #include <libelf.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 #include <sys/fcntl.h> 38 #include <sys/stat.h> 39 #include <sys/sysmacros.h> 40 #include <sys/types.h> 41 42 #include "dis_target.h" 43 #include "dis_util.h" 44 45 /* 46 * Standard ELF disassembler target. 47 * 48 * We only support disassembly of ELF files, though this target interface could 49 * be extended in the future. Each basic type (target, func, section) contains 50 * enough information to uniquely identify the location within the file. The 51 * interfaces use libelf(3LIB) to do the actual processing of the file. 52 */ 53 54 /* 55 * Symbol table entry type. We maintain our own symbol table sorted by address, 56 * with the symbol name already resolved against the ELF symbol table. 57 */ 58 typedef struct sym_entry { 59 GElf_Sym se_sym; /* value of symbol */ 60 char *se_name; /* name of symbol */ 61 int se_shndx; /* section where symbol is located */ 62 } sym_entry_t; 63 64 /* 65 * Create a map of the virtual address ranges of every section. This will 66 * allow us to create dummpy mappings for unassigned addresses. Otherwise 67 * multiple sections with unassigned addresses will appear to overlap and 68 * mess up symbol resolution (which uses the virtual address). 69 */ 70 typedef struct dis_shnmap { 71 const char *dm_name; /* name of section */ 72 uint64_t dm_start; /* virtual address of section */ 73 size_t dm_length; /* address length */ 74 boolean_t dm_mapped; /* did we assign the mapping */ 75 } dis_shnmap_t; 76 77 /* 78 * Target data structure. This structure keeps track of the ELF file 79 * information, a few bits of pre-processed section index information, and 80 * sorted versions of the symbol table. We also keep track of the last symbol 81 * looked up, as the majority of lookups remain within the same symbol. 82 */ 83 struct dis_tgt { 84 Elf *dt_elf; /* libelf handle */ 85 Elf *dt_elf_root; /* main libelf handle (for archives) */ 86 const char *dt_filename; /* name of file */ 87 int dt_fd; /* underlying file descriptor */ 88 size_t dt_shstrndx; /* section index of .shstrtab */ 89 size_t dt_symidx; /* section index of symbol table */ 90 sym_entry_t *dt_symcache; /* last symbol looked up */ 91 sym_entry_t *dt_symtab; /* sorted symbol table */ 92 int dt_symcount; /* # of symbol table entries */ 93 struct dis_tgt *dt_next; /* next target (for archives) */ 94 Elf_Arhdr *dt_arhdr; /* archive header (for archives) */ 95 dis_shnmap_t *dt_shnmap; /* section address map */ 96 size_t dt_shncount; /* # of sections in target */ 97 }; 98 99 /* 100 * Function data structure. We resolve the symbol and lookup the associated ELF 101 * data when building this structure. The offset is calculated based on the 102 * section's starting address. 103 */ 104 struct dis_func { 105 sym_entry_t *df_sym; /* symbol table reference */ 106 Elf_Data *df_data; /* associated ELF data */ 107 size_t df_offset; /* offset within data */ 108 }; 109 110 /* 111 * Section data structure. We store the entire section header so that we can 112 * determine some properties (such as whether or not it contains text) after 113 * building the structure. 114 */ 115 struct dis_scn { 116 GElf_Shdr ds_shdr; 117 const char *ds_name; 118 Elf_Data *ds_data; 119 }; 120 121 /* Lifted from Psymtab.c, omitting STT_TLS */ 122 #define DATA_TYPES \ 123 ((1 << STT_OBJECT) | (1 << STT_FUNC) | (1 << STT_COMMON)) 124 #define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0) 125 126 /* 127 * Save the virtual address range for this section and select the 128 * best section to use as the symbol table. We prefer SHT_SYMTAB 129 * over SHT_DYNSYM. 130 */ 131 /* ARGSUSED */ 132 static void 133 tgt_scn_init(dis_tgt_t *tgt, dis_scn_t *scn, void *data) 134 { 135 int *index = data; 136 137 *index += 1; 138 139 tgt->dt_shnmap[*index].dm_name = scn->ds_name; 140 tgt->dt_shnmap[*index].dm_start = scn->ds_shdr.sh_addr; 141 tgt->dt_shnmap[*index].dm_length = scn->ds_shdr.sh_size; 142 tgt->dt_shnmap[*index].dm_mapped = B_FALSE; 143 144 /* 145 * Prefer SHT_SYMTAB over SHT_DYNSYM 146 */ 147 if (scn->ds_shdr.sh_type == SHT_DYNSYM && tgt->dt_symidx == 0) 148 tgt->dt_symidx = *index; 149 else if (scn->ds_shdr.sh_type == SHT_SYMTAB) 150 tgt->dt_symidx = *index; 151 } 152 153 static int 154 sym_compare(const void *a, const void *b) 155 { 156 const sym_entry_t *syma = a; 157 const sym_entry_t *symb = b; 158 const char *aname = syma->se_name; 159 const char *bname = symb->se_name; 160 size_t alen; 161 size_t blen; 162 163 if (syma->se_sym.st_value < symb->se_sym.st_value) 164 return (-1); 165 166 if (syma->se_sym.st_value > symb->se_sym.st_value) 167 return (1); 168 169 /* 170 * Prefer functions over non-functions 171 */ 172 if (GELF_ST_TYPE(syma->se_sym.st_info) != 173 GELF_ST_TYPE(symb->se_sym.st_info)) { 174 if (GELF_ST_TYPE(syma->se_sym.st_info) == STT_FUNC) 175 return (-1); 176 if (GELF_ST_TYPE(symb->se_sym.st_info) == STT_FUNC) 177 return (1); 178 } 179 180 /* 181 * For symbols with the same address and type, we sort them according to 182 * a hierarchy: 183 * 184 * 1. weak symbols (common name) 185 * 2. global symbols (external name) 186 * 3. local symbols 187 */ 188 if (GELF_ST_BIND(syma->se_sym.st_info) != 189 GELF_ST_BIND(symb->se_sym.st_info)) { 190 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_WEAK) 191 return (-1); 192 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_WEAK) 193 return (1); 194 195 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_GLOBAL) 196 return (-1); 197 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_GLOBAL) 198 return (1); 199 } 200 201 /* 202 * As a last resort, if we have multiple symbols of the same type at the 203 * same address, prefer the version with the fewest leading underscores. 204 */ 205 if (aname == NULL) 206 return (-1); 207 if (bname == NULL) 208 return (1); 209 210 while (*aname == '_' && *bname == '_') { 211 aname++; 212 bname++; 213 } 214 215 if (*bname == '_') 216 return (-1); 217 if (*aname == '_') 218 return (1); 219 220 /* 221 * Prefer the symbol with the smaller size. 222 */ 223 if (syma->se_sym.st_size < symb->se_sym.st_size) 224 return (-1); 225 if (syma->se_sym.st_size > symb->se_sym.st_size) 226 return (1); 227 228 /* 229 * We really do have two identical symbols, choose the one with the 230 * shortest name if we can, heuristically taking it to be the most 231 * representative. 232 */ 233 alen = strlen(syma->se_name); 234 blen = strlen(symb->se_name); 235 236 if (alen < blen) 237 return (-1); 238 else if (alen > blen) 239 return (1); 240 241 /* 242 * If all else fails, compare the names, so that we give a stable 243 * sort 244 */ 245 return (strcmp(syma->se_name, symb->se_name)); 246 } 247 248 /* 249 * Construct an optimized symbol table sorted by starting address. 250 */ 251 static void 252 construct_symtab(dis_tgt_t *tgt) 253 { 254 Elf_Scn *scn; 255 GElf_Shdr shdr; 256 Elf_Data *symdata; 257 int i; 258 GElf_Word *symshndx = NULL; 259 int symshndx_size; 260 sym_entry_t *sym; 261 sym_entry_t *p_symtab = NULL; 262 int nsym = 0; /* count of symbols we're not interested in */ 263 264 /* 265 * Find the symshndx section, if any 266 */ 267 for (scn = elf_nextscn(tgt->dt_elf, NULL); scn != NULL; 268 scn = elf_nextscn(tgt->dt_elf, scn)) { 269 if (gelf_getshdr(scn, &shdr) == NULL) 270 break; 271 if (shdr.sh_type == SHT_SYMTAB_SHNDX && 272 shdr.sh_link == tgt->dt_symidx) { 273 Elf_Data *data; 274 275 if ((data = elf_getdata(scn, NULL)) != NULL) { 276 symshndx = (GElf_Word *)data->d_buf; 277 symshndx_size = data->d_size / 278 sizeof (GElf_Word); 279 break; 280 } 281 } 282 } 283 284 if ((scn = elf_getscn(tgt->dt_elf, tgt->dt_symidx)) == NULL) 285 die("%s: failed to get section information", tgt->dt_filename); 286 if (gelf_getshdr(scn, &shdr) == NULL) 287 die("%s: failed to get section header", tgt->dt_filename); 288 if (shdr.sh_entsize == 0) 289 die("%s: symbol table has zero size", tgt->dt_filename); 290 291 if ((symdata = elf_getdata(scn, NULL)) == NULL) 292 die("%s: failed to get symbol table", tgt->dt_filename); 293 294 tgt->dt_symcount = symdata->d_size / gelf_fsize(tgt->dt_elf, ELF_T_SYM, 295 1, EV_CURRENT); 296 297 p_symtab = safe_malloc(tgt->dt_symcount * sizeof (sym_entry_t)); 298 299 for (i = 0, sym = p_symtab; i < tgt->dt_symcount; i++) { 300 if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) { 301 warn("%s: gelf_getsym returned NULL for %d", 302 tgt->dt_filename, i); 303 nsym++; 304 continue; 305 } 306 307 /* 308 * We're only interested in data symbols. 309 */ 310 if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) { 311 nsym++; 312 continue; 313 } 314 315 if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) { 316 if (i > symshndx_size) { 317 warn("%s: bad SHNX_XINDEX %d", 318 tgt->dt_filename, i); 319 sym->se_shndx = -1; 320 } else { 321 sym->se_shndx = symshndx[i]; 322 } 323 } else { 324 sym->se_shndx = sym->se_sym.st_shndx; 325 } 326 327 /* Deal with symbols with special section indicies */ 328 if (sym->se_shndx == SHN_ABS) { 329 /* 330 * If st_value == 0, references to these 331 * symbols in code are modified in situ 332 * thus we will never attempt to look 333 * them up. 334 */ 335 if (sym->se_sym.st_value == 0) { 336 /* 337 * References to these symbols in code 338 * are modified in situ by the runtime 339 * linker and no code on disk will ever 340 * attempt to look them up. 341 */ 342 nsym++; 343 continue; 344 } else { 345 /* 346 * If st_value != 0, (such as examining 347 * something in /system/object/.../object) 348 * the values should resolve to a value 349 * within an existing section (such as 350 * .data). This also means it never needs 351 * to have st_value mapped. 352 */ 353 sym++; 354 continue; 355 } 356 } 357 358 /* 359 * Ignore the symbol if it has some other special 360 * section index 361 */ 362 if (sym->se_shndx == SHN_UNDEF || 363 sym->se_shndx >= SHN_LORESERVE) { 364 nsym++; 365 continue; 366 } 367 368 if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link, 369 (size_t)sym->se_sym.st_name)) == NULL) { 370 warn("%s: failed to lookup symbol %d name", 371 tgt->dt_filename, i); 372 nsym++; 373 continue; 374 } 375 376 /* 377 * If we had to map this section, its symbol value 378 * also needs to be mapped. 379 */ 380 if (tgt->dt_shnmap[sym->se_shndx].dm_mapped) 381 sym->se_sym.st_value += 382 tgt->dt_shnmap[sym->se_shndx].dm_start; 383 384 sym++; 385 } 386 387 tgt->dt_symcount -= nsym; 388 tgt->dt_symtab = realloc(p_symtab, tgt->dt_symcount * 389 sizeof (sym_entry_t)); 390 391 qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t), 392 sym_compare); 393 } 394 395 /* 396 * Assign virtual address ranges for sections that need it 397 */ 398 static void 399 create_addrmap(dis_tgt_t *tgt) 400 { 401 uint64_t addr; 402 int i; 403 404 if (tgt->dt_shnmap == NULL) 405 return; 406 407 /* find the greatest used address */ 408 for (addr = 0, i = 1; i < tgt->dt_shncount; i++) 409 if (tgt->dt_shnmap[i].dm_start > addr) 410 addr = tgt->dt_shnmap[i].dm_start + 411 tgt->dt_shnmap[i].dm_length; 412 413 addr = P2ROUNDUP(addr, 0x1000); 414 415 /* 416 * Assign section a starting address beyond the largest mapped section 417 * if no address was given. 418 */ 419 for (i = 1; i < tgt->dt_shncount; i++) { 420 if (tgt->dt_shnmap[i].dm_start != 0) 421 continue; 422 423 tgt->dt_shnmap[i].dm_start = addr; 424 tgt->dt_shnmap[i].dm_mapped = B_TRUE; 425 addr = P2ROUNDUP(addr + tgt->dt_shnmap[i].dm_length, 0x1000); 426 } 427 } 428 429 /* 430 * Create a target backed by an ELF file. 431 */ 432 dis_tgt_t * 433 dis_tgt_create(const char *file) 434 { 435 dis_tgt_t *tgt, *current; 436 int idx; 437 Elf *elf; 438 GElf_Ehdr ehdr; 439 Elf_Arhdr *arhdr = NULL; 440 int cmd; 441 442 if (elf_version(EV_CURRENT) == EV_NONE) 443 die("libelf(3ELF) out of date"); 444 445 tgt = safe_malloc(sizeof (dis_tgt_t)); 446 447 if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) { 448 warn("%s: failed opening file, reason: %s", file, 449 strerror(errno)); 450 free(tgt); 451 return (NULL); 452 } 453 454 if ((tgt->dt_elf_root = 455 elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) { 456 warn("%s: invalid or corrupt ELF file", file); 457 dis_tgt_destroy(tgt); 458 return (NULL); 459 } 460 461 current = tgt; 462 cmd = ELF_C_READ; 463 while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) { 464 size_t shnum = 0; 465 466 if (elf_kind(tgt->dt_elf_root) == ELF_K_AR && 467 (arhdr = elf_getarhdr(elf)) == NULL) { 468 warn("%s: malformed archive", file); 469 dis_tgt_destroy(tgt); 470 return (NULL); 471 } 472 473 /* 474 * Make sure that this Elf file is sane 475 */ 476 if (gelf_getehdr(elf, &ehdr) == NULL) { 477 if (arhdr != NULL) { 478 /* 479 * For archives, we drive on in the face of bad 480 * members. The "/" and "//" members are 481 * special, and should be silently ignored. 482 */ 483 if (strcmp(arhdr->ar_name, "/") != 0 && 484 strcmp(arhdr->ar_name, "//") != 0) 485 warn("%s[%s]: invalid file type", 486 file, arhdr->ar_name); 487 cmd = elf_next(elf); 488 (void) elf_end(elf); 489 continue; 490 } 491 492 warn("%s: invalid file type", file); 493 dis_tgt_destroy(tgt); 494 return (NULL); 495 } 496 497 /* 498 * If we're seeing a new Elf object, then we have an 499 * archive. In this case, we create a new target, and chain it 500 * off the master target. We can later iterate over these 501 * targets using dis_tgt_next(). 502 */ 503 if (current->dt_elf != NULL) { 504 dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t)); 505 next->dt_elf_root = tgt->dt_elf_root; 506 next->dt_fd = -1; 507 current->dt_next = next; 508 current = next; 509 } 510 current->dt_elf = elf; 511 current->dt_arhdr = arhdr; 512 513 if (elf_getshdrstrndx(elf, ¤t->dt_shstrndx) == -1) { 514 warn("%s: failed to get section string table for " 515 "file", file); 516 dis_tgt_destroy(tgt); 517 return (NULL); 518 } 519 520 if (elf_getshdrnum(elf, &shnum) == -1) { 521 warn("%s: failed to get number of sections in file", 522 file); 523 dis_tgt_destroy(tgt); 524 return (NULL); 525 } 526 527 current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) * 528 shnum); 529 current->dt_shncount = shnum; 530 531 idx = 0; 532 dis_tgt_section_iter(current, tgt_scn_init, &idx); 533 current->dt_filename = file; 534 535 create_addrmap(current); 536 if (current->dt_symidx != 0) 537 construct_symtab(current); 538 539 cmd = elf_next(elf); 540 } 541 542 /* 543 * Final sanity check. If we had an archive with no members, then bail 544 * out with a nice message. 545 */ 546 if (tgt->dt_elf == NULL) { 547 warn("%s: empty archive\n", file); 548 dis_tgt_destroy(tgt); 549 return (NULL); 550 } 551 552 return (tgt); 553 } 554 555 /* 556 * Return the filename associated with the target. 557 */ 558 const char * 559 dis_tgt_name(dis_tgt_t *tgt) 560 { 561 return (tgt->dt_filename); 562 } 563 564 /* 565 * Return the archive member name, if any. 566 */ 567 const char * 568 dis_tgt_member(dis_tgt_t *tgt) 569 { 570 if (tgt->dt_arhdr) 571 return (tgt->dt_arhdr->ar_name); 572 else 573 return (NULL); 574 } 575 576 /* 577 * Return the Elf_Ehdr associated with this target. Needed to determine which 578 * disassembler to use. 579 */ 580 void 581 dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr) 582 { 583 (void) gelf_getehdr(tgt->dt_elf, ehdr); 584 } 585 586 /* 587 * Return the next target in the list, if this is an archive. 588 */ 589 dis_tgt_t * 590 dis_tgt_next(dis_tgt_t *tgt) 591 { 592 return (tgt->dt_next); 593 } 594 595 /* 596 * Destroy a target and free up any associated memory. 597 */ 598 void 599 dis_tgt_destroy(dis_tgt_t *tgt) 600 { 601 dis_tgt_t *current, *next; 602 603 current = tgt->dt_next; 604 while (current != NULL) { 605 next = current->dt_next; 606 if (current->dt_elf) 607 (void) elf_end(current->dt_elf); 608 if (current->dt_symtab) 609 free(current->dt_symtab); 610 free(current); 611 current = next; 612 } 613 614 if (tgt->dt_elf) 615 (void) elf_end(tgt->dt_elf); 616 if (tgt->dt_elf_root) 617 (void) elf_end(tgt->dt_elf_root); 618 619 if (tgt->dt_symtab) 620 free(tgt->dt_symtab); 621 622 free(tgt); 623 } 624 625 /* 626 * Given an address, return the section it is in and set the offset within 627 * the section. 628 */ 629 const char * 630 dis_find_section(dis_tgt_t *tgt, uint64_t addr, off_t *offset) 631 { 632 int i; 633 634 for (i = 1; i < tgt->dt_shncount; i++) { 635 if ((addr >= tgt->dt_shnmap[i].dm_start) && 636 (addr < tgt->dt_shnmap[i].dm_start + 637 tgt->dt_shnmap[i].dm_length)) { 638 *offset = addr - tgt->dt_shnmap[i].dm_start; 639 return (tgt->dt_shnmap[i].dm_name); 640 } 641 } 642 643 *offset = 0; 644 return (NULL); 645 } 646 647 /* 648 * Given an address, returns the name of the corresponding symbol, as well as 649 * the offset within that symbol. If no matching symbol is found, then NULL is 650 * returned. 651 * 652 * If 'cache_result' is specified, then we keep track of the resulting symbol. 653 * This cached result is consulted first on subsequent lookups in order to avoid 654 * unecessary lookups. This flag should be used for resolving the current PC, 655 * as the majority of addresses stay within the current function. 656 */ 657 const char * 658 dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result, 659 size_t *size, int *isfunc) 660 { 661 int lo, hi, mid; 662 sym_entry_t *sym, *osym, *match; 663 int found; 664 665 *offset = 0; 666 *size = 0; 667 if (isfunc != NULL) 668 *isfunc = 0; 669 670 if (tgt->dt_symcache != NULL && 671 addr >= tgt->dt_symcache->se_sym.st_value && 672 addr < tgt->dt_symcache->se_sym.st_value + 673 tgt->dt_symcache->se_sym.st_size) { 674 sym = tgt->dt_symcache; 675 *offset = addr - sym->se_sym.st_value; 676 *size = sym->se_sym.st_size; 677 if (isfunc != NULL) 678 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == 679 STT_FUNC); 680 return (sym->se_name); 681 } 682 683 lo = 0; 684 hi = (tgt->dt_symcount - 1); 685 found = 0; 686 match = osym = NULL; 687 while (lo <= hi) { 688 mid = (lo + hi) / 2; 689 690 sym = &tgt->dt_symtab[mid]; 691 692 if (addr >= sym->se_sym.st_value && 693 addr < sym->se_sym.st_value + sym->se_sym.st_size && 694 (!found || sym->se_sym.st_value > osym->se_sym.st_value)) { 695 osym = sym; 696 found = 1; 697 } else if (addr == sym->se_sym.st_value) { 698 /* 699 * Particularly for .plt objects, it's possible to have 700 * a zero sized object. We want to return this, but we 701 * want it to be a last resort. 702 */ 703 match = sym; 704 } 705 706 if (addr < sym->se_sym.st_value) 707 hi = mid - 1; 708 else 709 lo = mid + 1; 710 } 711 712 if (!found) { 713 if (match) 714 osym = match; 715 else 716 return (NULL); 717 } 718 719 /* 720 * Walk backwards to find the best match. 721 */ 722 do { 723 sym = osym; 724 725 if (osym == tgt->dt_symtab) 726 break; 727 728 osym = osym - 1; 729 } while ((sym->se_sym.st_value == osym->se_sym.st_value) && 730 (addr >= osym->se_sym.st_value) && 731 (addr < osym->se_sym.st_value + osym->se_sym.st_size)); 732 733 if (cache_result) 734 tgt->dt_symcache = sym; 735 736 *offset = addr - sym->se_sym.st_value; 737 *size = sym->se_sym.st_size; 738 if (isfunc) 739 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC); 740 741 return (sym->se_name); 742 } 743 744 /* 745 * Given an address, return the starting offset of the next symbol in the file. 746 * Only needed on variable length instruction architectures. 747 */ 748 off_t 749 dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr) 750 { 751 sym_entry_t *sym; 752 753 sym = (tgt->dt_symcache != NULL) ? tgt->dt_symcache : tgt->dt_symtab; 754 755 while (sym != (tgt->dt_symtab + tgt->dt_symcount)) { 756 if (sym->se_sym.st_value >= addr) 757 return (sym->se_sym.st_value - addr); 758 sym++; 759 } 760 761 return (0); 762 } 763 764 /* 765 * Iterate over all sections in the target, executing the given callback for 766 * each. 767 */ 768 void 769 dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data) 770 { 771 dis_scn_t sdata; 772 Elf_Scn *scn; 773 int idx; 774 775 for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL; 776 scn = elf_nextscn(tgt->dt_elf, scn), idx++) { 777 778 if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) { 779 warn("%s: failed to get section %d header", 780 tgt->dt_filename, idx); 781 continue; 782 } 783 784 if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx, 785 sdata.ds_shdr.sh_name)) == NULL) { 786 warn("%s: failed to get section %d name", 787 tgt->dt_filename, idx); 788 continue; 789 } 790 791 if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) { 792 warn("%s: failed to get data for section '%s'", 793 tgt->dt_filename, sdata.ds_name); 794 continue; 795 } 796 797 /* 798 * dis_tgt_section_iter is also used before the section map 799 * is initialized, so only check when we need to. If the 800 * section map is uninitialized, it will return 0 and have 801 * no net effect. 802 */ 803 if (sdata.ds_shdr.sh_addr == 0) 804 sdata.ds_shdr.sh_addr = tgt->dt_shnmap[idx].dm_start; 805 806 func(tgt, &sdata, data); 807 } 808 } 809 810 /* 811 * Return 1 if the given section contains text, 0 otherwise. 812 */ 813 int 814 dis_section_istext(dis_scn_t *scn) 815 { 816 return ((scn->ds_shdr.sh_type == SHT_PROGBITS) && 817 (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR))); 818 } 819 820 /* 821 * Return a pointer to the section data. 822 */ 823 void * 824 dis_section_data(dis_scn_t *scn) 825 { 826 return (scn->ds_data->d_buf); 827 } 828 829 /* 830 * Return the size of the section data. 831 */ 832 size_t 833 dis_section_size(dis_scn_t *scn) 834 { 835 return (scn->ds_data->d_size); 836 } 837 838 /* 839 * Return the address for the given section. 840 */ 841 uint64_t 842 dis_section_addr(dis_scn_t *scn) 843 { 844 return (scn->ds_shdr.sh_addr); 845 } 846 847 /* 848 * Return the name of the current section. 849 */ 850 const char * 851 dis_section_name(dis_scn_t *scn) 852 { 853 return (scn->ds_name); 854 } 855 856 /* 857 * Create an allocated copy of the given section 858 */ 859 dis_scn_t * 860 dis_section_copy(dis_scn_t *scn) 861 { 862 dis_scn_t *new; 863 864 new = safe_malloc(sizeof (dis_scn_t)); 865 (void) memcpy(new, scn, sizeof (dis_scn_t)); 866 867 return (new); 868 } 869 870 /* 871 * Free section memory 872 */ 873 void 874 dis_section_free(dis_scn_t *scn) 875 { 876 free(scn); 877 } 878 879 /* 880 * Iterate over all functions in the target, executing the given callback for 881 * each one. 882 */ 883 void 884 dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data) 885 { 886 int i; 887 sym_entry_t *sym; 888 dis_func_t df; 889 Elf_Scn *scn; 890 GElf_Shdr shdr; 891 892 for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) { 893 894 /* ignore non-functions */ 895 if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) || 896 (sym->se_name == NULL) || 897 (sym->se_sym.st_size == 0) || 898 (sym->se_shndx >= SHN_LORESERVE)) 899 continue; 900 901 /* get the ELF data associated with this function */ 902 if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL || 903 gelf_getshdr(scn, &shdr) == NULL || 904 (df.df_data = elf_getdata(scn, NULL)) == NULL || 905 df.df_data->d_size == 0) { 906 warn("%s: failed to read section %d", 907 tgt->dt_filename, sym->se_shndx); 908 continue; 909 } 910 911 if (tgt->dt_shnmap[sym->se_shndx].dm_mapped) 912 shdr.sh_addr = tgt->dt_shnmap[sym->se_shndx].dm_start; 913 914 /* 915 * Verify that the address lies within the section that we think 916 * it does. 917 */ 918 if (sym->se_sym.st_value < shdr.sh_addr || 919 (sym->se_sym.st_value + sym->se_sym.st_size) > 920 (shdr.sh_addr + shdr.sh_size)) { 921 warn("%s: bad section %d for address %p", 922 tgt->dt_filename, sym->se_sym.st_shndx, 923 sym->se_sym.st_value); 924 continue; 925 } 926 927 df.df_sym = sym; 928 df.df_offset = sym->se_sym.st_value - shdr.sh_addr; 929 930 func(tgt, &df, data); 931 } 932 } 933 934 /* 935 * Return the data associated with a given function. 936 */ 937 void * 938 dis_function_data(dis_func_t *func) 939 { 940 return ((char *)func->df_data->d_buf + func->df_offset); 941 } 942 943 /* 944 * Return the size of a function. 945 */ 946 size_t 947 dis_function_size(dis_func_t *func) 948 { 949 return (func->df_sym->se_sym.st_size); 950 } 951 952 /* 953 * Return the address of a function. 954 */ 955 uint64_t 956 dis_function_addr(dis_func_t *func) 957 { 958 return (func->df_sym->se_sym.st_value); 959 } 960 961 /* 962 * Return the name of the function 963 */ 964 const char * 965 dis_function_name(dis_func_t *func) 966 { 967 return (func->df_sym->se_name); 968 } 969 970 /* 971 * Return a copy of a function. 972 */ 973 dis_func_t * 974 dis_function_copy(dis_func_t *func) 975 { 976 dis_func_t *new; 977 978 new = safe_malloc(sizeof (dis_func_t)); 979 (void) memcpy(new, func, sizeof (dis_func_t)); 980 981 return (new); 982 } 983 984 /* 985 * Free function memory 986 */ 987 void 988 dis_function_free(dis_func_t *func) 989 { 990 free(func); 991 } 992