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