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 2008 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 if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) { 265 warn("%s: gelf_getsym returned NULL for %d", 266 tgt->dt_filename, i); 267 nsym++; 268 continue; 269 } 270 271 /* 272 * We're only interested in data symbols. 273 */ 274 if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) { 275 nsym++; 276 continue; 277 } 278 279 if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) { 280 if (i > symshndx_size) { 281 warn("%s: bad SHNX_XINDEX %d", 282 tgt->dt_filename, i); 283 sym->se_shndx = -1; 284 } else { 285 sym->se_shndx = symshndx[i]; 286 } 287 } else { 288 sym->se_shndx = sym->se_sym.st_shndx; 289 } 290 291 if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link, 292 (size_t)sym->se_sym.st_name)) == NULL) { 293 warn("%s: failed to lookup symbol %d name", 294 tgt->dt_filename, i); 295 nsym++; 296 continue; 297 } 298 299 sym++; 300 } 301 302 tgt->dt_symcount -= nsym; 303 tgt->dt_symtab = realloc(p_symtab, tgt->dt_symcount * 304 sizeof (sym_entry_t)); 305 306 qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t), 307 sym_compare); 308 } 309 310 /* 311 * Create a target backed by an ELF file. 312 */ 313 dis_tgt_t * 314 dis_tgt_create(const char *file) 315 { 316 dis_tgt_t *tgt, *current; 317 int idx; 318 Elf *elf; 319 GElf_Ehdr ehdr; 320 Elf_Arhdr *arhdr = NULL; 321 int cmd; 322 323 if (elf_version(EV_CURRENT) == EV_NONE) 324 die("libelf(3ELF) out of date"); 325 326 tgt = safe_malloc(sizeof (dis_tgt_t)); 327 328 if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) { 329 warn("%s: failed opening file, reason: %s", file, 330 strerror(errno)); 331 free(tgt); 332 return (NULL); 333 } 334 335 if ((tgt->dt_elf_root = 336 elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) { 337 warn("%s: invalid or corrupt ELF file", file); 338 dis_tgt_destroy(tgt); 339 return (NULL); 340 } 341 342 current = tgt; 343 cmd = ELF_C_READ; 344 while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) { 345 346 if (elf_kind(tgt->dt_elf_root) == ELF_K_AR && 347 (arhdr = elf_getarhdr(elf)) == NULL) { 348 warn("%s: malformed archive", file); 349 dis_tgt_destroy(tgt); 350 return (NULL); 351 } 352 353 /* 354 * Make sure that this Elf file is sane 355 */ 356 if (gelf_getehdr(elf, &ehdr) == NULL) { 357 if (arhdr != NULL) { 358 /* 359 * For archives, we drive on in the face of bad 360 * members. The "/" and "//" members are 361 * special, and should be silently ignored. 362 */ 363 if (strcmp(arhdr->ar_name, "/") != 0 && 364 strcmp(arhdr->ar_name, "//") != 0) 365 warn("%s[%s]: invalid file type", 366 file, arhdr->ar_name); 367 cmd = elf_next(elf); 368 (void) elf_end(elf); 369 continue; 370 } 371 372 warn("%s: invalid file type", file); 373 dis_tgt_destroy(tgt); 374 return (NULL); 375 } 376 377 /* 378 * If we're seeing a new Elf object, then we have an 379 * archive. In this case, we create a new target, and chain it 380 * off the master target. We can later iterate over these 381 * targets using dis_tgt_next(). 382 */ 383 if (current->dt_elf != NULL) { 384 dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t)); 385 next->dt_elf_root = tgt->dt_elf_root; 386 next->dt_fd = -1; 387 current->dt_next = next; 388 current = next; 389 } 390 current->dt_elf = elf; 391 current->dt_arhdr = arhdr; 392 393 if (elf_getshstrndx(elf, ¤t->dt_shstrndx) == -1) { 394 warn("%s: failed to get section string table for " 395 "file", file); 396 dis_tgt_destroy(tgt); 397 return (NULL); 398 } 399 400 idx = 0; 401 dis_tgt_section_iter(current, get_symtab, &idx); 402 403 if (current->dt_symidx != 0) 404 construct_symtab(current); 405 406 current->dt_filename = file; 407 408 cmd = elf_next(elf); 409 } 410 411 /* 412 * Final sanity check. If we had an archive with no members, then bail 413 * out with a nice message. 414 */ 415 if (tgt->dt_elf == NULL) { 416 warn("%s: empty archive\n", file); 417 dis_tgt_destroy(tgt); 418 return (NULL); 419 } 420 421 return (tgt); 422 } 423 424 /* 425 * Return the filename associated with the target. 426 */ 427 const char * 428 dis_tgt_name(dis_tgt_t *tgt) 429 { 430 return (tgt->dt_filename); 431 } 432 433 /* 434 * Return the archive member name, if any. 435 */ 436 const char * 437 dis_tgt_member(dis_tgt_t *tgt) 438 { 439 if (tgt->dt_arhdr) 440 return (tgt->dt_arhdr->ar_name); 441 else 442 return (NULL); 443 } 444 445 /* 446 * Return the Elf_Ehdr associated with this target. Needed to determine which 447 * disassembler to use. 448 */ 449 void 450 dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr) 451 { 452 (void) gelf_getehdr(tgt->dt_elf, ehdr); 453 } 454 455 /* 456 * Return the next target in the list, if this is an archive. 457 */ 458 dis_tgt_t * 459 dis_tgt_next(dis_tgt_t *tgt) 460 { 461 return (tgt->dt_next); 462 } 463 464 /* 465 * Destroy a target and free up any associated memory. 466 */ 467 void 468 dis_tgt_destroy(dis_tgt_t *tgt) 469 { 470 dis_tgt_t *current, *next; 471 472 current = tgt->dt_next; 473 while (current != NULL) { 474 next = current->dt_next; 475 if (current->dt_elf) 476 (void) elf_end(current->dt_elf); 477 if (current->dt_symtab) 478 free(current->dt_symtab); 479 free(current); 480 current = next; 481 } 482 483 if (tgt->dt_elf) 484 (void) elf_end(tgt->dt_elf); 485 if (tgt->dt_elf_root) 486 (void) elf_end(tgt->dt_elf_root); 487 488 if (tgt->dt_symtab) 489 free(tgt->dt_symtab); 490 491 free(tgt); 492 } 493 494 /* 495 * Given an address, returns the name of the corresponding symbol, as well as 496 * the offset within that symbol. If no matching symbol is found, then NULL is 497 * returned. 498 * 499 * If 'cache_result' is specified, then we keep track of the resulting symbol. 500 * This cached result is consulted first on subsequent lookups in order to avoid 501 * unecessary lookups. This flag should be used for resolving the current PC, 502 * as the majority of addresses stay within the current function. 503 */ 504 const char * 505 dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result, 506 size_t *size, int *isfunc) 507 { 508 int lo, hi, mid; 509 sym_entry_t *sym, *osym, *match; 510 int found; 511 512 if (tgt->dt_symcache != NULL && 513 addr >= tgt->dt_symcache->se_sym.st_value && 514 addr < tgt->dt_symcache->se_sym.st_value + 515 tgt->dt_symcache->se_sym.st_size) { 516 *offset = addr - tgt->dt_symcache->se_sym.st_value; 517 *size = tgt->dt_symcache->se_sym.st_size; 518 return (tgt->dt_symcache->se_name); 519 } 520 521 lo = 0; 522 hi = (tgt->dt_symcount - 1); 523 found = 0; 524 match = osym = NULL; 525 while (lo <= hi) { 526 mid = (lo + hi) / 2; 527 528 sym = &tgt->dt_symtab[mid]; 529 530 if (addr >= sym->se_sym.st_value && 531 addr < sym->se_sym.st_value + sym->se_sym.st_size && 532 (!found || sym->se_sym.st_value > osym->se_sym.st_value)) { 533 osym = sym; 534 found = 1; 535 } else if (addr == sym->se_sym.st_value) { 536 /* 537 * Particularly for .plt objects, it's possible to have 538 * a zero sized object. We want to return this, but we 539 * want it to be a last resort. 540 */ 541 match = sym; 542 } 543 544 if (addr < sym->se_sym.st_value) 545 hi = mid - 1; 546 else 547 lo = mid + 1; 548 } 549 550 if (!found) { 551 if (match) 552 osym = match; 553 else 554 return (NULL); 555 } 556 557 /* 558 * Walk backwards to find the best match. 559 */ 560 do { 561 sym = osym; 562 563 if (osym == tgt->dt_symtab) 564 break; 565 566 osym = osym - 1; 567 } while ((sym->se_sym.st_value == osym->se_sym.st_value) && 568 (addr >= osym->se_sym.st_value) && 569 (addr < osym->se_sym.st_value + osym->se_sym.st_size)); 570 571 if (cache_result) 572 tgt->dt_symcache = sym; 573 574 *offset = addr - sym->se_sym.st_value; 575 *size = sym->se_sym.st_size; 576 if (isfunc) 577 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC); 578 579 return (sym->se_name); 580 } 581 582 /* 583 * Given an address, return the starting offset of the next symbol in the file. 584 * Relies on the fact that this is only used when we encounter a bad instruction 585 * in the input stream, so we know that the last symbol looked up will be in the 586 * cache. 587 */ 588 off_t 589 dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr) 590 { 591 sym_entry_t *sym = tgt->dt_symcache; 592 uint64_t start; 593 594 /* make sure the cached symbol and address are valid */ 595 if (sym == NULL || addr < sym->se_sym.st_value || 596 addr >= sym->se_sym.st_value + sym->se_sym.st_size) 597 return (0); 598 599 start = sym->se_sym.st_value; 600 601 /* find the next symbol */ 602 while (sym != tgt->dt_symtab + tgt->dt_symcount && 603 sym->se_sym.st_value == start) 604 sym++; 605 606 return (sym->se_sym.st_value - addr); 607 } 608 609 /* 610 * Iterate over all sections in the target, executing the given callback for 611 * each. 612 */ 613 void 614 dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data) 615 { 616 dis_scn_t sdata; 617 Elf_Scn *scn; 618 int idx; 619 620 for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL; 621 scn = elf_nextscn(tgt->dt_elf, scn), idx++) { 622 623 if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) { 624 warn("%s: failed to get section %d header", 625 tgt->dt_filename, idx); 626 continue; 627 } 628 629 if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx, 630 sdata.ds_shdr.sh_name)) == NULL) { 631 warn("%s: failed to get section %d name", 632 tgt->dt_filename, idx); 633 continue; 634 } 635 636 if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) { 637 warn("%s: failed to get data for section '%s'", 638 tgt->dt_filename, sdata.ds_name); 639 continue; 640 } 641 642 func(tgt, &sdata, data); 643 } 644 } 645 646 /* 647 * Return 1 if the given section contains text, 0 otherwise. 648 */ 649 int 650 dis_section_istext(dis_scn_t *scn) 651 { 652 return ((scn->ds_shdr.sh_type == SHT_PROGBITS) && 653 (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR))); 654 } 655 656 /* 657 * Return a pointer to the section data. 658 */ 659 void * 660 dis_section_data(dis_scn_t *scn) 661 { 662 return (scn->ds_data->d_buf); 663 } 664 665 /* 666 * Return the size of the section data. 667 */ 668 size_t 669 dis_section_size(dis_scn_t *scn) 670 { 671 return (scn->ds_data->d_size); 672 } 673 674 /* 675 * Return the address for the given section. 676 */ 677 uint64_t 678 dis_section_addr(dis_scn_t *scn) 679 { 680 return (scn->ds_shdr.sh_addr); 681 } 682 683 /* 684 * Return the name of the current section. 685 */ 686 const char * 687 dis_section_name(dis_scn_t *scn) 688 { 689 return (scn->ds_name); 690 } 691 692 /* 693 * Create an allocated copy of the given section 694 */ 695 dis_scn_t * 696 dis_section_copy(dis_scn_t *scn) 697 { 698 dis_scn_t *new; 699 700 new = safe_malloc(sizeof (dis_scn_t)); 701 (void) memcpy(new, scn, sizeof (dis_scn_t)); 702 703 return (new); 704 } 705 706 /* 707 * Free section memory 708 */ 709 void 710 dis_section_free(dis_scn_t *scn) 711 { 712 free(scn); 713 } 714 715 /* 716 * Iterate over all functions in the target, executing the given callback for 717 * each one. 718 */ 719 void 720 dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data) 721 { 722 int i; 723 sym_entry_t *sym; 724 dis_func_t df; 725 Elf_Scn *scn; 726 GElf_Shdr shdr; 727 728 for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) { 729 730 /* ignore non-functions */ 731 if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) || 732 (sym->se_name == NULL) || 733 (sym->se_sym.st_size == 0) || 734 (sym->se_shndx >= SHN_LORESERVE)) 735 continue; 736 737 /* get the ELF data associated with this function */ 738 if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL || 739 gelf_getshdr(scn, &shdr) == NULL || 740 (df.df_data = elf_getdata(scn, NULL)) == NULL || 741 df.df_data->d_size == 0) { 742 warn("%s: failed to read section %d", 743 tgt->dt_filename, sym->se_shndx); 744 continue; 745 } 746 747 /* 748 * Verify that the address lies within the section that we think 749 * it does. 750 */ 751 if (sym->se_sym.st_value < shdr.sh_addr || 752 (sym->se_sym.st_value + sym->se_sym.st_size) > 753 (shdr.sh_addr + shdr.sh_size)) { 754 warn("%s: bad section %d for address %p", 755 tgt->dt_filename, sym->se_sym.st_shndx, 756 sym->se_sym.st_value); 757 continue; 758 } 759 760 df.df_sym = sym; 761 df.df_offset = sym->se_sym.st_value - shdr.sh_addr; 762 763 func(tgt, &df, data); 764 } 765 } 766 767 /* 768 * Return the data associated with a given function. 769 */ 770 void * 771 dis_function_data(dis_func_t *func) 772 { 773 return ((char *)func->df_data->d_buf + func->df_offset); 774 } 775 776 /* 777 * Return the size of a function. 778 */ 779 size_t 780 dis_function_size(dis_func_t *func) 781 { 782 return (func->df_sym->se_sym.st_size); 783 } 784 785 /* 786 * Return the address of a function. 787 */ 788 uint64_t 789 dis_function_addr(dis_func_t *func) 790 { 791 return (func->df_sym->se_sym.st_value); 792 } 793 794 /* 795 * Return the name of the function 796 */ 797 const char * 798 dis_function_name(dis_func_t *func) 799 { 800 return (func->df_sym->se_name); 801 } 802 803 /* 804 * Return a copy of a function. 805 */ 806 dis_func_t * 807 dis_function_copy(dis_func_t *func) 808 { 809 dis_func_t *new; 810 811 new = safe_malloc(sizeof (dis_func_t)); 812 (void) memcpy(new, func, sizeof (dis_func_t)); 813 814 return (new); 815 } 816 817 /* 818 * Free function memory 819 */ 820 void 821 dis_function_free(dis_func_t *func) 822 { 823 free(func); 824 } 825