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