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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <assert.h> 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <gelf.h> 33 #include <libelf.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include <sys/fcntl.h> 39 #include <sys/stat.h> 40 41 #include "dis_target.h" 42 #include "dis_util.h" 43 44 /* 45 * Standard ELF disassembler target. 46 * 47 * We only support disassembly of ELF files, though this target interface could 48 * be extended in the future. Each basic type (target, func, section) contains 49 * enough information to uniquely identify the location within the file. The 50 * interfaces use libelf(3LIB) to do the actual processing of the file. 51 */ 52 53 /* 54 * Symbol table entry type. We maintain our own symbol table sorted by address, 55 * with the symbol name already resolved against the ELF symbol table. 56 */ 57 typedef struct sym_entry { 58 GElf_Sym se_sym; /* value of symbol */ 59 char *se_name; /* name of symbol */ 60 int se_shndx; /* section where symbol is located */ 61 } sym_entry_t; 62 63 /* 64 * Target data structure. This structure keeps track of the ELF file 65 * information, a few bits of pre-processed section index information, and 66 * sorted versions of the symbol table. We also keep track of the last symbol 67 * looked up, as the majority of lookups remain within the same symbol. 68 */ 69 struct dis_tgt { 70 Elf *dt_elf; /* libelf handle */ 71 Elf *dt_elf_root; /* main libelf handle (for archives) */ 72 const char *dt_filename; /* name of file */ 73 int dt_fd; /* underlying file descriptor */ 74 size_t dt_shstrndx; /* section index of .shstrtab */ 75 size_t dt_symidx; /* section index of symbol table */ 76 sym_entry_t *dt_symcache; /* last symbol looked up */ 77 sym_entry_t *dt_symtab; /* sorted symbol table */ 78 int dt_symcount; /* # of symbol table entries */ 79 struct dis_tgt *dt_next; /* next target (for archives) */ 80 Elf_Arhdr *dt_arhdr; /* archive header (for archives) */ 81 }; 82 83 /* 84 * Function data structure. We resolve the symbol and lookup the associated ELF 85 * data when building this structure. The offset is calculated based on the 86 * section's starting address. 87 */ 88 struct dis_func { 89 sym_entry_t *df_sym; /* symbol table reference */ 90 Elf_Data *df_data; /* associated ELF data */ 91 size_t df_offset; /* offset within data */ 92 }; 93 94 /* 95 * Section data structure. We store the entire section header so that we can 96 * determine some properties (such as whether or not it contains text) after 97 * building the structure. 98 */ 99 struct dis_scn { 100 GElf_Shdr ds_shdr; 101 const char *ds_name; 102 Elf_Data *ds_data; 103 }; 104 105 /* Lifted from Psymtab.c */ 106 #define DATA_TYPES \ 107 ((1 << STT_OBJECT) | (1 << STT_FUNC) | \ 108 (1 << STT_COMMON) | (1 << STT_TLS)) 109 #define IS_DATA_TYPE(tp) (((1 << (tp)) & DATA_TYPES) != 0) 110 111 /* 112 * Pick out the best symbol to used based on the sections available in the 113 * target. We prefer SHT_SYMTAB over SHT_DYNSYM. 114 */ 115 /* ARGSUSED */ 116 static void 117 get_symtab(dis_tgt_t *tgt, dis_scn_t *scn, void *data) 118 { 119 int *index = data; 120 121 *index += 1; 122 123 /* 124 * Prefer SHT_SYMTAB over SHT_DYNSYM 125 */ 126 if (scn->ds_shdr.sh_type == SHT_DYNSYM && tgt->dt_symidx == 0) 127 tgt->dt_symidx = *index; 128 else if (scn->ds_shdr.sh_type == SHT_SYMTAB) 129 tgt->dt_symidx = *index; 130 } 131 132 static int 133 sym_compare(const void *a, const void *b) 134 { 135 const sym_entry_t *syma = a; 136 const sym_entry_t *symb = b; 137 const char *aname = syma->se_name; 138 const char *bname = symb->se_name; 139 140 if (syma->se_sym.st_value < symb->se_sym.st_value) 141 return (-1); 142 143 if (syma->se_sym.st_value > symb->se_sym.st_value) 144 return (1); 145 146 /* 147 * Prefer functions over non-functions 148 */ 149 if (GELF_ST_TYPE(syma->se_sym.st_info) != 150 GELF_ST_TYPE(symb->se_sym.st_info)) { 151 if (GELF_ST_TYPE(syma->se_sym.st_info) == STT_FUNC) 152 return (-1); 153 if (GELF_ST_TYPE(symb->se_sym.st_info) == STT_FUNC) 154 return (1); 155 } 156 157 /* 158 * For symbols with the same address and type, we sort them according to 159 * a hierarchy: 160 * 161 * 1. weak symbols (common name) 162 * 2. global symbols (external name) 163 * 3. local symbols 164 */ 165 if (GELF_ST_BIND(syma->se_sym.st_info) != 166 GELF_ST_BIND(symb->se_sym.st_info)) { 167 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_WEAK) 168 return (-1); 169 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_WEAK) 170 return (1); 171 172 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_GLOBAL) 173 return (-1); 174 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_GLOBAL) 175 return (1); 176 } 177 178 /* 179 * As a last resort, if we have multiple symbols of the same type at the 180 * same address, prefer the version with the fewest leading underscores. 181 */ 182 if (aname == NULL) 183 return (-1); 184 if (bname == NULL) 185 return (1); 186 187 while (*aname == '_' && *bname == '_') { 188 aname++; 189 bname++; 190 } 191 192 if (*bname == '_') 193 return (-1); 194 if (*aname == '_') 195 return (1); 196 197 /* 198 * Prefer the symbol with the smaller size. 199 */ 200 if (syma->se_sym.st_size < symb->se_sym.st_size) 201 return (-1); 202 if (syma->se_sym.st_size > symb->se_sym.st_size) 203 return (1); 204 205 /* 206 * We really do have two identical symbols for some reason. Just report 207 * them as equal, and to the lucky one go the spoils. 208 */ 209 return (0); 210 } 211 212 /* 213 * Construct an optimized symbol table sorted by starting address. 214 */ 215 static void 216 construct_symtab(dis_tgt_t *tgt) 217 { 218 Elf_Scn *scn; 219 GElf_Shdr shdr; 220 Elf_Data *symdata; 221 int i; 222 GElf_Word *symshndx = NULL; 223 int symshndx_size; 224 sym_entry_t *sym; 225 sym_entry_t *p_symtab = NULL; 226 int nsym = 0; /* count of symbols we're not interested in */ 227 228 /* 229 * Find the symshndx section, if any 230 */ 231 for (scn = elf_nextscn(tgt->dt_elf, NULL); scn != NULL; 232 scn = elf_nextscn(tgt->dt_elf, scn)) { 233 if (gelf_getshdr(scn, &shdr) == NULL) 234 break; 235 if (shdr.sh_type == SHT_SYMTAB_SHNDX && 236 shdr.sh_link == tgt->dt_symidx) { 237 Elf_Data *data; 238 239 if ((data = elf_getdata(scn, NULL)) != NULL) { 240 symshndx = (GElf_Word *)data->d_buf; 241 symshndx_size = data->d_size / 242 sizeof (GElf_Word); 243 break; 244 } 245 } 246 } 247 248 if ((scn = elf_getscn(tgt->dt_elf, tgt->dt_symidx)) == NULL) 249 die("%s: failed to get section information", tgt->dt_filename); 250 if (gelf_getshdr(scn, &shdr) == NULL) 251 die("%s: failed to get section header", tgt->dt_filename); 252 if (shdr.sh_entsize == 0) 253 die("%s: symbol table has zero size", tgt->dt_filename); 254 255 if ((symdata = elf_getdata(scn, NULL)) == NULL) 256 die("%s: failed to get symbol table", tgt->dt_filename); 257 258 tgt->dt_symcount = symdata->d_size / gelf_fsize(tgt->dt_elf, ELF_T_SYM, 259 1, EV_CURRENT); 260 261 p_symtab = safe_malloc(tgt->dt_symcount * sizeof (sym_entry_t)); 262 263 for (i = 0, sym = p_symtab; i < tgt->dt_symcount; i++) { 264 (void) memset(sym, sizeof (sym_entry_t), 0); 265 if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) { 266 warn("%s: gelf_getsym returned NULL for %d", 267 tgt->dt_filename, i); 268 nsym++; 269 continue; 270 } 271 272 /* 273 * We're only interested in data symbols. 274 */ 275 if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) { 276 nsym++; 277 continue; 278 } 279 280 if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) { 281 if (i > symshndx_size) { 282 warn("%s: bad SHNX_XINDEX %d", 283 tgt->dt_filename, i); 284 sym->se_shndx = -1; 285 } else { 286 sym->se_shndx = symshndx[i]; 287 } 288 } else { 289 sym->se_shndx = sym->se_sym.st_shndx; 290 } 291 292 if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link, 293 (size_t)sym->se_sym.st_name)) == NULL) { 294 warn("%s: failed to lookup symbol %d name", 295 tgt->dt_filename, i); 296 nsym++; 297 continue; 298 } 299 300 sym++; 301 } 302 303 tgt->dt_symcount -= nsym; 304 tgt->dt_symtab = realloc(p_symtab, 305 tgt->dt_symcount * sizeof (sym_entry_t)); 306 307 qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t), 308 sym_compare); 309 } 310 311 /* 312 * Create a target backed by an ELF file. 313 */ 314 dis_tgt_t * 315 dis_tgt_create(const char *file) 316 { 317 dis_tgt_t *tgt, *current; 318 int idx; 319 Elf *elf; 320 GElf_Ehdr ehdr; 321 Elf_Arhdr *arhdr = NULL; 322 int cmd; 323 324 if (elf_version(EV_CURRENT) == EV_NONE) 325 die("libelf(3ELF) out of date"); 326 327 tgt = safe_malloc(sizeof (dis_tgt_t)); 328 329 if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) { 330 warn("%s: failed opening file, reason: %s", file, 331 strerror(errno)); 332 free(tgt); 333 return (NULL); 334 } 335 336 if ((tgt->dt_elf_root = 337 elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) { 338 warn("%s: invalid or corrupt ELF file", file); 339 dis_tgt_destroy(tgt); 340 return (NULL); 341 } 342 343 current = tgt; 344 cmd = ELF_C_READ; 345 while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) { 346 347 if (elf_kind(tgt->dt_elf_root) == ELF_K_AR && 348 (arhdr = elf_getarhdr(elf)) == NULL) { 349 warn("%s: malformed archive", file); 350 dis_tgt_destroy(tgt); 351 return (NULL); 352 } 353 354 /* 355 * Make sure that this Elf file is sane 356 */ 357 if (gelf_getehdr(elf, &ehdr) == NULL) { 358 if (arhdr != NULL) { 359 /* 360 * For archives, we drive on in the face of bad 361 * members. The "/" and "//" members are 362 * special, and should be silently ignored. 363 */ 364 if (strcmp(arhdr->ar_name, "/") != 0 && 365 strcmp(arhdr->ar_name, "//") != 0) 366 warn("%s[%s]: invalid file type", 367 file, arhdr->ar_name); 368 cmd = elf_next(elf); 369 (void) elf_end(elf); 370 continue; 371 } 372 373 warn("%s: invalid file type", file); 374 dis_tgt_destroy(tgt); 375 return (NULL); 376 } 377 378 /* 379 * If we're seeing a new Elf object, then we have an 380 * archive. In this case, we create a new target, and chain it 381 * off the master target. We can later iterate over these 382 * targets using dis_tgt_next(). 383 */ 384 if (current->dt_elf != NULL) { 385 dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t)); 386 next->dt_elf_root = tgt->dt_elf_root; 387 next->dt_fd = -1; 388 current->dt_next = next; 389 current = next; 390 } 391 current->dt_elf = elf; 392 current->dt_arhdr = arhdr; 393 394 if (elf_getshstrndx(elf, ¤t->dt_shstrndx) == -1) { 395 warn("%s: failed to get section string table for " 396 "file", file); 397 dis_tgt_destroy(tgt); 398 return (NULL); 399 } 400 401 idx = 0; 402 dis_tgt_section_iter(current, get_symtab, &idx); 403 404 if (current->dt_symidx != 0) 405 construct_symtab(current); 406 407 current->dt_filename = file; 408 409 cmd = elf_next(elf); 410 } 411 412 /* 413 * Final sanity check. If we had an archive with no members, then bail 414 * out with a nice message. 415 */ 416 if (tgt->dt_elf == NULL) { 417 warn("%s: empty archive\n", file); 418 dis_tgt_destroy(tgt); 419 return (NULL); 420 } 421 422 return (tgt); 423 } 424 425 /* 426 * Return the filename associated with the target. 427 */ 428 const char * 429 dis_tgt_name(dis_tgt_t *tgt) 430 { 431 return (tgt->dt_filename); 432 } 433 434 /* 435 * Return the archive member name, if any. 436 */ 437 const char * 438 dis_tgt_member(dis_tgt_t *tgt) 439 { 440 if (tgt->dt_arhdr) 441 return (tgt->dt_arhdr->ar_name); 442 else 443 return (NULL); 444 } 445 446 /* 447 * Return the Elf_Ehdr associated with this target. Needed to determine which 448 * disassembler to use. 449 */ 450 void 451 dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr) 452 { 453 (void) gelf_getehdr(tgt->dt_elf, ehdr); 454 } 455 456 /* 457 * Return the next target in the list, if this is an archive. 458 */ 459 dis_tgt_t * 460 dis_tgt_next(dis_tgt_t *tgt) 461 { 462 return (tgt->dt_next); 463 } 464 465 /* 466 * Destroy a target and free up any associated memory. 467 */ 468 void 469 dis_tgt_destroy(dis_tgt_t *tgt) 470 { 471 dis_tgt_t *current, *next; 472 473 current = tgt->dt_next; 474 while (current != NULL) { 475 next = current->dt_next; 476 if (current->dt_elf) 477 (void) elf_end(current->dt_elf); 478 if (current->dt_symtab) 479 free(current->dt_symtab); 480 free(current); 481 current = next; 482 } 483 484 if (tgt->dt_elf) 485 (void) elf_end(tgt->dt_elf); 486 if (tgt->dt_elf_root) 487 (void) elf_end(tgt->dt_elf_root); 488 489 if (tgt->dt_symtab) 490 free(tgt->dt_symtab); 491 492 free(tgt); 493 } 494 495 /* 496 * Given an address, returns the name of the corresponding symbol, as well as 497 * the offset within that symbol. If no matching symbol is found, then NULL is 498 * returned. 499 * 500 * If 'cache_result' is specified, then we keep track of the resulting symbol. 501 * This cached result is consulted first on subsequent lookups in order to avoid 502 * unecessary lookups. This flag should be used for resolving the current PC, 503 * as the majority of addresses stay within the current function. 504 */ 505 const char * 506 dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result, 507 size_t *size, int *isfunc) 508 { 509 int lo, hi, mid; 510 sym_entry_t *sym, *osym, *match; 511 int found; 512 513 if (tgt->dt_symcache != NULL && 514 addr >= tgt->dt_symcache->se_sym.st_value && 515 addr < tgt->dt_symcache->se_sym.st_value + 516 tgt->dt_symcache->se_sym.st_size) { 517 *offset = addr - tgt->dt_symcache->se_sym.st_value; 518 *size = tgt->dt_symcache->se_sym.st_size; 519 return (tgt->dt_symcache->se_name); 520 } 521 522 lo = 0; 523 hi = (tgt->dt_symcount - 1); 524 found = 0; 525 match = osym = NULL; 526 while (lo <= hi) { 527 mid = (lo + hi) / 2; 528 529 sym = &tgt->dt_symtab[mid]; 530 531 if (addr >= sym->se_sym.st_value && 532 addr < sym->se_sym.st_value + sym->se_sym.st_size && 533 (!found || sym->se_sym.st_value > osym->se_sym.st_value)) { 534 osym = sym; 535 found = 1; 536 } else if (addr == sym->se_sym.st_value) { 537 /* 538 * Particularly for .plt objects, it's possible to have 539 * a zero sized object. We want to return this, but we 540 * want it to be a last resort. 541 */ 542 match = sym; 543 } 544 545 if (addr < sym->se_sym.st_value) 546 hi = mid - 1; 547 else 548 lo = mid + 1; 549 } 550 551 if (!found) { 552 if (match) 553 osym = match; 554 else 555 return (NULL); 556 } 557 558 /* 559 * Walk backwards to find the best match. 560 */ 561 do { 562 sym = osym; 563 564 if (osym == tgt->dt_symtab) 565 break; 566 567 osym = osym - 1; 568 } while ((sym->se_sym.st_value == osym->se_sym.st_value) && 569 (addr >= osym->se_sym.st_value) && 570 (addr < osym->se_sym.st_value + osym->se_sym.st_size)); 571 572 if (cache_result) 573 tgt->dt_symcache = sym; 574 575 *offset = addr - sym->se_sym.st_value; 576 *size = sym->se_sym.st_size; 577 if (isfunc) 578 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC); 579 580 return (sym->se_name); 581 } 582 583 /* 584 * Given an address, return the starting offset of the next symbol in the file. 585 * Relies on the fact that this is only used when we encounter a bad instruction 586 * in the input stream, so we know that the last symbol looked up will be in the 587 * cache. 588 */ 589 off_t 590 dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr) 591 { 592 sym_entry_t *sym = tgt->dt_symcache; 593 uint64_t start; 594 595 /* make sure the cached symbol and address are valid */ 596 if (sym == NULL || addr < sym->se_sym.st_value || 597 addr >= sym->se_sym.st_value + sym->se_sym.st_size) 598 return (0); 599 600 start = sym->se_sym.st_value; 601 602 /* find the next symbol */ 603 while (sym != tgt->dt_symtab + tgt->dt_symcount && 604 sym->se_sym.st_value == start) 605 sym++; 606 607 return (sym->se_sym.st_value - addr); 608 } 609 610 /* 611 * Iterate over all sections in the target, executing the given callback for 612 * each. 613 */ 614 void 615 dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data) 616 { 617 dis_scn_t sdata; 618 Elf_Scn *scn; 619 int idx; 620 621 for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL; 622 scn = elf_nextscn(tgt->dt_elf, scn), idx++) { 623 624 if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) { 625 warn("%s: failed to get section %d header", 626 tgt->dt_filename, idx); 627 continue; 628 } 629 630 if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx, 631 sdata.ds_shdr.sh_name)) == NULL) { 632 warn("%s: failed to get section %d name", 633 tgt->dt_filename, idx); 634 continue; 635 } 636 637 if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) { 638 warn("%s: failed to get data for section '%s'", 639 tgt->dt_filename, sdata.ds_name); 640 continue; 641 } 642 643 func(tgt, &sdata, data); 644 } 645 } 646 647 /* 648 * Return 1 if the given section contains text, 0 otherwise. 649 */ 650 int 651 dis_section_istext(dis_scn_t *scn) 652 { 653 return ((scn->ds_shdr.sh_type == SHT_PROGBITS) && 654 (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR))); 655 } 656 657 /* 658 * Return a pointer to the section data. 659 */ 660 void * 661 dis_section_data(dis_scn_t *scn) 662 { 663 return (scn->ds_data->d_buf); 664 } 665 666 /* 667 * Return the size of the section data. 668 */ 669 size_t 670 dis_section_size(dis_scn_t *scn) 671 { 672 return (scn->ds_data->d_size); 673 } 674 675 /* 676 * Return the address for the given section. 677 */ 678 uint64_t 679 dis_section_addr(dis_scn_t *scn) 680 { 681 return (scn->ds_shdr.sh_addr); 682 } 683 684 /* 685 * Return the name of the current section. 686 */ 687 const char * 688 dis_section_name(dis_scn_t *scn) 689 { 690 return (scn->ds_name); 691 } 692 693 /* 694 * Create an allocated copy of the given section 695 */ 696 dis_scn_t * 697 dis_section_copy(dis_scn_t *scn) 698 { 699 dis_scn_t *new; 700 701 new = safe_malloc(sizeof (dis_scn_t)); 702 (void) memcpy(new, scn, sizeof (dis_scn_t)); 703 704 return (new); 705 } 706 707 /* 708 * Free section memory 709 */ 710 void 711 dis_section_free(dis_scn_t *scn) 712 { 713 free(scn); 714 } 715 716 /* 717 * Iterate over all functions in the target, executing the given callback for 718 * each one. 719 */ 720 void 721 dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data) 722 { 723 int i; 724 sym_entry_t *sym; 725 dis_func_t df; 726 Elf_Scn *scn; 727 GElf_Shdr shdr; 728 729 for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) { 730 731 /* ignore non-functions */ 732 if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) || 733 (sym->se_name == NULL) || 734 (sym->se_sym.st_size == 0) || 735 (sym->se_shndx >= SHN_LORESERVE)) 736 continue; 737 738 /* get the ELF data associated with this function */ 739 if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL || 740 gelf_getshdr(scn, &shdr) == NULL || 741 (df.df_data = elf_getdata(scn, NULL)) == NULL || 742 df.df_data->d_size == 0) { 743 warn("%s: failed to read section %d", 744 tgt->dt_filename, sym->se_shndx); 745 continue; 746 } 747 748 /* 749 * Verify that the address lies within the section that we think 750 * it does. 751 */ 752 if (sym->se_sym.st_value < shdr.sh_addr || 753 (sym->se_sym.st_value + sym->se_sym.st_size) > 754 (shdr.sh_addr + shdr.sh_size)) { 755 warn("%s: bad section %d for address %p", 756 tgt->dt_filename, sym->se_sym.st_shndx, 757 sym->se_sym.st_value); 758 continue; 759 } 760 761 df.df_sym = sym; 762 df.df_offset = sym->se_sym.st_value - shdr.sh_addr; 763 764 func(tgt, &df, data); 765 } 766 } 767 768 /* 769 * Return the data associated with a given function. 770 */ 771 void * 772 dis_function_data(dis_func_t *func) 773 { 774 return ((char *)func->df_data->d_buf + func->df_offset); 775 } 776 777 /* 778 * Return the size of a function. 779 */ 780 size_t 781 dis_function_size(dis_func_t *func) 782 { 783 return (func->df_sym->se_sym.st_size); 784 } 785 786 /* 787 * Return the address of a function. 788 */ 789 uint64_t 790 dis_function_addr(dis_func_t *func) 791 { 792 return (func->df_sym->se_sym.st_value); 793 } 794 795 /* 796 * Return the name of the function 797 */ 798 const char * 799 dis_function_name(dis_func_t *func) 800 { 801 return (func->df_sym->se_name); 802 } 803 804 /* 805 * Return a copy of a function. 806 */ 807 dis_func_t * 808 dis_function_copy(dis_func_t *func) 809 { 810 dis_func_t *new; 811 812 new = safe_malloc(sizeof (dis_func_t)); 813 (void) memcpy(new, func, sizeof (dis_func_t)); 814 815 return (new); 816 } 817 818 /* 819 * Free function memory 820 */ 821 void 822 dis_function_free(dis_func_t *func) 823 { 824 free(func); 825 } 826