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 
 161         if (syma->se_sym.st_value < symb->se_sym.st_value)
 162                 return (-1);
 163 
 164         if (syma->se_sym.st_value > symb->se_sym.st_value)
 165                 return (1);
 166 
 167         /*
 168          * Prefer functions over non-functions
 169          */
 170         if (GELF_ST_TYPE(syma->se_sym.st_info) !=
 171             GELF_ST_TYPE(symb->se_sym.st_info)) {
 172                 if (GELF_ST_TYPE(syma->se_sym.st_info) == STT_FUNC)
 173                         return (-1);
 174                 if (GELF_ST_TYPE(symb->se_sym.st_info) == STT_FUNC)
 175                         return (1);
 176         }
 177 
 178         /*
 179          * For symbols with the same address and type, we sort them according to
 180          * a hierarchy:
 181          *
 182          *      1. weak symbols (common name)
 183          *      2. global symbols (external name)
 184          *      3. local symbols
 185          */
 186         if (GELF_ST_BIND(syma->se_sym.st_info) !=
 187             GELF_ST_BIND(symb->se_sym.st_info)) {
 188                 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_WEAK)
 189                         return (-1);
 190                 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_WEAK)
 191                         return (1);
 192 
 193                 if (GELF_ST_BIND(syma->se_sym.st_info) == STB_GLOBAL)
 194                         return (-1);
 195                 if (GELF_ST_BIND(symb->se_sym.st_info) == STB_GLOBAL)
 196                         return (1);
 197         }
 198 
 199         /*
 200          * As a last resort, if we have multiple symbols of the same type at the
 201          * same address, prefer the version with the fewest leading underscores.
 202          */
 203         if (aname == NULL)
 204                 return (-1);
 205         if (bname == NULL)
 206                 return (1);
 207 
 208         while (*aname == '_' && *bname == '_') {
 209                 aname++;
 210                 bname++;
 211         }
 212 
 213         if (*bname == '_')
 214                 return (-1);
 215         if (*aname == '_')
 216                 return (1);
 217 
 218         /*
 219          * Prefer the symbol with the smaller size.
 220          */
 221         if (syma->se_sym.st_size < symb->se_sym.st_size)
 222                 return (-1);
 223         if (syma->se_sym.st_size > symb->se_sym.st_size)
 224                 return (1);
 225 
 226         /*
 227          * We really do have two identical symbols for some reason.  Just report
 228          * them as equal, and to the lucky one go the spoils.
 229          */
 230         return (0);
 231 }
 232 
 233 /*
 234  * Construct an optimized symbol table sorted by starting address.
 235  */
 236 static void
 237 construct_symtab(dis_tgt_t *tgt)
 238 {
 239         Elf_Scn *scn;
 240         GElf_Shdr shdr;
 241         Elf_Data *symdata;
 242         int i;
 243         GElf_Word *symshndx = NULL;
 244         int symshndx_size;
 245         sym_entry_t *sym;
 246         sym_entry_t *p_symtab = NULL;
 247         int nsym = 0; /* count of symbols we're not interested in */
 248 
 249         /*
 250          * Find the symshndx section, if any
 251          */
 252         for (scn = elf_nextscn(tgt->dt_elf, NULL); scn != NULL;
 253             scn = elf_nextscn(tgt->dt_elf, scn)) {
 254                 if (gelf_getshdr(scn, &shdr) == NULL)
 255                         break;
 256                 if (shdr.sh_type == SHT_SYMTAB_SHNDX &&
 257                     shdr.sh_link == tgt->dt_symidx) {
 258                         Elf_Data        *data;
 259 
 260                         if ((data = elf_getdata(scn, NULL)) != NULL) {
 261                                 symshndx = (GElf_Word *)data->d_buf;
 262                                 symshndx_size = data->d_size /
 263                                     sizeof (GElf_Word);
 264                                 break;
 265                         }
 266                 }
 267         }
 268 
 269         if ((scn = elf_getscn(tgt->dt_elf, tgt->dt_symidx)) == NULL)
 270                 die("%s: failed to get section information", tgt->dt_filename);
 271         if (gelf_getshdr(scn, &shdr) == NULL)
 272                 die("%s: failed to get section header", tgt->dt_filename);
 273         if (shdr.sh_entsize == 0)
 274                 die("%s: symbol table has zero size", tgt->dt_filename);
 275 
 276         if ((symdata = elf_getdata(scn, NULL)) == NULL)
 277                 die("%s: failed to get symbol table", tgt->dt_filename);
 278 
 279         tgt->dt_symcount = symdata->d_size / gelf_fsize(tgt->dt_elf, ELF_T_SYM,
 280             1, EV_CURRENT);
 281 
 282         p_symtab = safe_malloc(tgt->dt_symcount * sizeof (sym_entry_t));
 283 
 284         for (i = 0, sym = p_symtab; i < tgt->dt_symcount; i++) {
 285                 if (gelf_getsym(symdata, i, &(sym->se_sym)) == NULL) {
 286                         warn("%s: gelf_getsym returned NULL for %d",
 287                             tgt->dt_filename, i);
 288                         nsym++;
 289                         continue;
 290                 }
 291 
 292                 /*
 293                  * We're only interested in data symbols.
 294                  */
 295                 if (!IS_DATA_TYPE(GELF_ST_TYPE(sym->se_sym.st_info))) {
 296                         nsym++;
 297                         continue;
 298                 }
 299 
 300                 if (sym->se_sym.st_shndx == SHN_XINDEX && symshndx != NULL) {
 301                         if (i > symshndx_size) {
 302                                 warn("%s: bad SHNX_XINDEX %d",
 303                                     tgt->dt_filename, i);
 304                                 sym->se_shndx = -1;
 305                         } else {
 306                                 sym->se_shndx = symshndx[i];
 307                         }
 308                 } else {
 309                         sym->se_shndx = sym->se_sym.st_shndx;
 310                 }
 311 
 312                 /* Deal with symbols with special section indicies */
 313                 if (sym->se_shndx == SHN_ABS) {
 314                         /*
 315                          * If st_value == 0, references to these
 316                          * symbols in code are modified in situ
 317                          * thus we will never attempt to look
 318                          * them up.
 319                          */
 320                         if (sym->se_sym.st_value == 0) {
 321                                 /*
 322                                  * References to these symbols in code
 323                                  * are modified in situ by the runtime
 324                                  * linker and no code on disk will ever
 325                                  * attempt to look them up.
 326                                  */
 327                                 nsym++;
 328                                 continue;
 329                         } else {
 330                                 /*
 331                                  * If st_value != 0, (such as examining
 332                                  * something in /system/object/.../object)
 333                                  * the values should resolve to a value
 334                                  * within an existing section (such as
 335                                  * .data).  This also means it never needs
 336                                  * to have st_value mapped.
 337                                  */
 338                                 sym++;
 339                                 continue;
 340                         }
 341                 }
 342 
 343                 /*
 344                  * Ignore the symbol if it has some other special
 345                  * section index
 346                  */
 347                 if (sym->se_shndx == SHN_UNDEF ||
 348                     sym->se_shndx >= SHN_LORESERVE) {
 349                         nsym++;
 350                         continue;
 351                 }
 352 
 353                 if ((sym->se_name = elf_strptr(tgt->dt_elf, shdr.sh_link,
 354                     (size_t)sym->se_sym.st_name)) == NULL) {
 355                         warn("%s: failed to lookup symbol %d name",
 356                             tgt->dt_filename, i);
 357                         nsym++;
 358                         continue;
 359                 }
 360 
 361                 /*
 362                  * If we had to map this section, its symbol value
 363                  * also needs to be mapped.
 364                  */
 365                 if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
 366                         sym->se_sym.st_value +=
 367                             tgt->dt_shnmap[sym->se_shndx].dm_start;
 368 
 369                 sym++;
 370         }
 371 
 372         tgt->dt_symcount -= nsym;
 373         tgt->dt_symtab = realloc(p_symtab, tgt->dt_symcount *
 374             sizeof (sym_entry_t));
 375 
 376         qsort(tgt->dt_symtab, tgt->dt_symcount, sizeof (sym_entry_t),
 377             sym_compare);
 378 }
 379 
 380 /*
 381  * Assign virtual address ranges for sections that need it
 382  */
 383 static void
 384 create_addrmap(dis_tgt_t *tgt)
 385 {
 386         uint64_t addr;
 387         int i;
 388 
 389         if (tgt->dt_shnmap == NULL)
 390                 return;
 391 
 392         /* find the greatest used address */
 393         for (addr = 0, i = 1; i < tgt->dt_shncount; i++)
 394                 if (tgt->dt_shnmap[i].dm_start > addr)
 395                         addr = tgt->dt_shnmap[i].dm_start +
 396                             tgt->dt_shnmap[i].dm_length;
 397 
 398         addr = P2ROUNDUP(addr, 0x1000);
 399 
 400         /*
 401          * Assign section a starting address beyond the largest mapped section
 402          * if no address was given.
 403          */
 404         for (i = 1; i < tgt->dt_shncount; i++) {
 405                 if (tgt->dt_shnmap[i].dm_start != 0)
 406                         continue;
 407 
 408                 tgt->dt_shnmap[i].dm_start = addr;
 409                 tgt->dt_shnmap[i].dm_mapped = B_TRUE;
 410                 addr = P2ROUNDUP(addr + tgt->dt_shnmap[i].dm_length, 0x1000);
 411         }
 412 }
 413 
 414 /*
 415  * Create a target backed by an ELF file.
 416  */
 417 dis_tgt_t *
 418 dis_tgt_create(const char *file)
 419 {
 420         dis_tgt_t *tgt, *current;
 421         int idx;
 422         Elf *elf;
 423         GElf_Ehdr ehdr;
 424         Elf_Arhdr *arhdr = NULL;
 425         int cmd;
 426 
 427         if (elf_version(EV_CURRENT) == EV_NONE)
 428                 die("libelf(3ELF) out of date");
 429 
 430         tgt = safe_malloc(sizeof (dis_tgt_t));
 431 
 432         if ((tgt->dt_fd = open(file, O_RDONLY)) < 0) {
 433                 warn("%s: failed opening file, reason: %s", file,
 434                     strerror(errno));
 435                 free(tgt);
 436                 return (NULL);
 437         }
 438 
 439         if ((tgt->dt_elf_root =
 440             elf_begin(tgt->dt_fd, ELF_C_READ, NULL)) == NULL) {
 441                 warn("%s: invalid or corrupt ELF file", file);
 442                 dis_tgt_destroy(tgt);
 443                 return (NULL);
 444         }
 445 
 446         current = tgt;
 447         cmd = ELF_C_READ;
 448         while ((elf = elf_begin(tgt->dt_fd, cmd, tgt->dt_elf_root)) != NULL) {
 449 
 450                 if (elf_kind(tgt->dt_elf_root) == ELF_K_AR &&
 451                     (arhdr = elf_getarhdr(elf)) == NULL) {
 452                         warn("%s: malformed archive", file);
 453                         dis_tgt_destroy(tgt);
 454                         return (NULL);
 455                 }
 456 
 457                 /*
 458                  * Make sure that this Elf file is sane
 459                  */
 460                 if (gelf_getehdr(elf, &ehdr) == NULL) {
 461                         if (arhdr != NULL) {
 462                                 /*
 463                                  * For archives, we drive on in the face of bad
 464                                  * members.  The "/" and "//" members are
 465                                  * special, and should be silently ignored.
 466                                  */
 467                                 if (strcmp(arhdr->ar_name, "/") != 0 &&
 468                                     strcmp(arhdr->ar_name, "//") != 0)
 469                                         warn("%s[%s]: invalid file type",
 470                                             file, arhdr->ar_name);
 471                                 cmd = elf_next(elf);
 472                                 (void) elf_end(elf);
 473                                 continue;
 474                         }
 475 
 476                         warn("%s: invalid file type", file);
 477                         dis_tgt_destroy(tgt);
 478                         return (NULL);
 479                 }
 480 
 481                 /*
 482                  * If we're seeing a new Elf object, then we have an
 483                  * archive. In this case, we create a new target, and chain it
 484                  * off the master target.  We can later iterate over these
 485                  * targets using dis_tgt_next().
 486                  */
 487                 if (current->dt_elf != NULL) {
 488                         dis_tgt_t *next = safe_malloc(sizeof (dis_tgt_t));
 489                         next->dt_elf_root = tgt->dt_elf_root;
 490                         next->dt_fd = -1;
 491                         current->dt_next = next;
 492                         current = next;
 493                 }
 494                 current->dt_elf = elf;
 495                 current->dt_arhdr = arhdr;
 496 
 497                 if (elf_getshdrstrndx(elf, &current->dt_shstrndx) == -1) {
 498                         warn("%s: failed to get section string table for "
 499                             "file", file);
 500                         dis_tgt_destroy(tgt);
 501                         return (NULL);
 502                 }
 503 
 504                 current->dt_shnmap = safe_malloc(sizeof (dis_shnmap_t) *
 505                     ehdr.e_shnum);
 506                 current->dt_shncount = ehdr.e_shnum;
 507 
 508                 idx = 0;
 509                 dis_tgt_section_iter(current, tgt_scn_init, &idx);
 510                 current->dt_filename = file;
 511 
 512                 create_addrmap(current);
 513                 if (current->dt_symidx != 0)
 514                         construct_symtab(current);
 515 
 516                 cmd = elf_next(elf);
 517         }
 518 
 519         /*
 520          * Final sanity check.  If we had an archive with no members, then bail
 521          * out with a nice message.
 522          */
 523         if (tgt->dt_elf == NULL) {
 524                 warn("%s: empty archive\n", file);
 525                 dis_tgt_destroy(tgt);
 526                 return (NULL);
 527         }
 528 
 529         return (tgt);
 530 }
 531 
 532 /*
 533  * Return the filename associated with the target.
 534  */
 535 const char *
 536 dis_tgt_name(dis_tgt_t *tgt)
 537 {
 538         return (tgt->dt_filename);
 539 }
 540 
 541 /*
 542  * Return the archive member name, if any.
 543  */
 544 const char *
 545 dis_tgt_member(dis_tgt_t *tgt)
 546 {
 547         if (tgt->dt_arhdr)
 548                 return (tgt->dt_arhdr->ar_name);
 549         else
 550                 return (NULL);
 551 }
 552 
 553 /*
 554  * Return the Elf_Ehdr associated with this target.  Needed to determine which
 555  * disassembler to use.
 556  */
 557 void
 558 dis_tgt_ehdr(dis_tgt_t *tgt, GElf_Ehdr *ehdr)
 559 {
 560         (void) gelf_getehdr(tgt->dt_elf, ehdr);
 561 }
 562 
 563 /*
 564  * Return the next target in the list, if this is an archive.
 565  */
 566 dis_tgt_t *
 567 dis_tgt_next(dis_tgt_t *tgt)
 568 {
 569         return (tgt->dt_next);
 570 }
 571 
 572 /*
 573  * Destroy a target and free up any associated memory.
 574  */
 575 void
 576 dis_tgt_destroy(dis_tgt_t *tgt)
 577 {
 578         dis_tgt_t *current, *next;
 579 
 580         current = tgt->dt_next;
 581         while (current != NULL) {
 582                 next = current->dt_next;
 583                 if (current->dt_elf)
 584                         (void) elf_end(current->dt_elf);
 585                 if (current->dt_symtab)
 586                         free(current->dt_symtab);
 587                 free(current);
 588                 current = next;
 589         }
 590 
 591         if (tgt->dt_elf)
 592                 (void) elf_end(tgt->dt_elf);
 593         if (tgt->dt_elf_root)
 594                 (void) elf_end(tgt->dt_elf_root);
 595 
 596         if (tgt->dt_symtab)
 597                 free(tgt->dt_symtab);
 598 
 599         free(tgt);
 600 }
 601 
 602 /*
 603  * Given an address, return the section it is in and set the offset within
 604  * the section.
 605  */
 606 const char *
 607 dis_find_section(dis_tgt_t *tgt, uint64_t addr, off_t *offset)
 608 {
 609         int i;
 610 
 611         for (i = 1; i < tgt->dt_shncount; i++) {
 612                 if ((addr >= tgt->dt_shnmap[i].dm_start) &&
 613                     (addr < tgt->dt_shnmap[i].dm_start +
 614                     tgt->dt_shnmap[i].dm_length)) {
 615                         *offset = addr - tgt->dt_shnmap[i].dm_start;
 616                         return (tgt->dt_shnmap[i].dm_name);
 617                 }
 618         }
 619 
 620         *offset = 0;
 621         return (NULL);
 622 }
 623 
 624 /*
 625  * Given an address, returns the name of the corresponding symbol, as well as
 626  * the offset within that symbol.  If no matching symbol is found, then NULL is
 627  * returned.
 628  *
 629  * If 'cache_result' is specified, then we keep track of the resulting symbol.
 630  * This cached result is consulted first on subsequent lookups in order to avoid
 631  * unecessary lookups.  This flag should be used for resolving the current PC,
 632  * as the majority of addresses stay within the current function.
 633  */
 634 const char *
 635 dis_tgt_lookup(dis_tgt_t *tgt, uint64_t addr, off_t *offset, int cache_result,
 636     size_t *size, int *isfunc)
 637 {
 638         int lo, hi, mid;
 639         sym_entry_t *sym, *osym, *match;
 640         int found;
 641 
 642         if (tgt->dt_symcache != NULL &&
 643             addr >= tgt->dt_symcache->se_sym.st_value &&
 644             addr < tgt->dt_symcache->se_sym.st_value +
 645             tgt->dt_symcache->se_sym.st_size) {
 646                 *offset = addr - tgt->dt_symcache->se_sym.st_value;
 647                 *size = tgt->dt_symcache->se_sym.st_size;
 648                 return (tgt->dt_symcache->se_name);
 649         }
 650 
 651         lo = 0;
 652         hi = (tgt->dt_symcount - 1);
 653         found = 0;
 654         match = osym = NULL;
 655         while (lo <= hi) {
 656                 mid = (lo + hi) / 2;
 657 
 658                 sym = &tgt->dt_symtab[mid];
 659 
 660                 if (addr >= sym->se_sym.st_value &&
 661                     addr < sym->se_sym.st_value + sym->se_sym.st_size &&
 662                     (!found || sym->se_sym.st_value > osym->se_sym.st_value)) {
 663                         osym = sym;
 664                         found = 1;
 665                 } else if (addr == sym->se_sym.st_value) {
 666                         /*
 667                          * Particularly for .plt objects, it's possible to have
 668                          * a zero sized object.  We want to return this, but we
 669                          * want it to be a last resort.
 670                          */
 671                         match = sym;
 672                 }
 673 
 674                 if (addr < sym->se_sym.st_value)
 675                         hi = mid - 1;
 676                 else
 677                         lo = mid + 1;
 678         }
 679 
 680         if (!found) {
 681                 if (match)
 682                         osym = match;
 683                 else
 684                         return (NULL);
 685         }
 686 
 687         /*
 688          * Walk backwards to find the best match.
 689          */
 690         do {
 691                 sym = osym;
 692 
 693                 if (osym == tgt->dt_symtab)
 694                         break;
 695 
 696                 osym = osym - 1;
 697         } while ((sym->se_sym.st_value == osym->se_sym.st_value) &&
 698             (addr >= osym->se_sym.st_value) &&
 699             (addr < osym->se_sym.st_value + osym->se_sym.st_size));
 700 
 701         if (cache_result)
 702                 tgt->dt_symcache = sym;
 703 
 704         *offset = addr - sym->se_sym.st_value;
 705         *size = sym->se_sym.st_size;
 706         if (isfunc)
 707                 *isfunc = (GELF_ST_TYPE(sym->se_sym.st_info) == STT_FUNC);
 708 
 709         return (sym->se_name);
 710 }
 711 
 712 /*
 713  * Given an address, return the starting offset of the next symbol in the file.
 714  * Only needed on variable length instruction architectures.
 715  */
 716 off_t
 717 dis_tgt_next_symbol(dis_tgt_t *tgt, uint64_t addr)
 718 {
 719         sym_entry_t *sym;
 720 
 721         for (sym = tgt->dt_symcache;
 722             sym != tgt->dt_symtab + tgt->dt_symcount;
 723             sym++) {
 724                 if (sym->se_sym.st_value >= addr)
 725                         return (sym->se_sym.st_value - addr);
 726         }
 727 
 728         return (0);
 729 }
 730 
 731 /*
 732  * Iterate over all sections in the target, executing the given callback for
 733  * each.
 734  */
 735 void
 736 dis_tgt_section_iter(dis_tgt_t *tgt, section_iter_f func, void *data)
 737 {
 738         dis_scn_t sdata;
 739         Elf_Scn *scn;
 740         int idx;
 741 
 742         for (scn = elf_nextscn(tgt->dt_elf, NULL), idx = 1; scn != NULL;
 743             scn = elf_nextscn(tgt->dt_elf, scn), idx++) {
 744 
 745                 if (gelf_getshdr(scn, &sdata.ds_shdr) == NULL) {
 746                         warn("%s: failed to get section %d header",
 747                             tgt->dt_filename, idx);
 748                         continue;
 749                 }
 750 
 751                 if ((sdata.ds_name = elf_strptr(tgt->dt_elf, tgt->dt_shstrndx,
 752                     sdata.ds_shdr.sh_name)) == NULL) {
 753                         warn("%s: failed to get section %d name",
 754                             tgt->dt_filename, idx);
 755                         continue;
 756                 }
 757 
 758                 if ((sdata.ds_data = elf_getdata(scn, NULL)) == NULL) {
 759                         warn("%s: failed to get data for section '%s'",
 760                             tgt->dt_filename, sdata.ds_name);
 761                         continue;
 762                 }
 763 
 764                 /*
 765                  * dis_tgt_section_iter is also used before the section map
 766                  * is initialized, so only check when we need to.  If the
 767                  * section map is uninitialized, it will return 0 and have
 768                  * no net effect.
 769                  */
 770                 if (sdata.ds_shdr.sh_addr == 0)
 771                         sdata.ds_shdr.sh_addr = tgt->dt_shnmap[idx].dm_start;
 772 
 773                 func(tgt, &sdata, data);
 774         }
 775 }
 776 
 777 /*
 778  * Return 1 if the given section contains text, 0 otherwise.
 779  */
 780 int
 781 dis_section_istext(dis_scn_t *scn)
 782 {
 783         return ((scn->ds_shdr.sh_type == SHT_PROGBITS) &&
 784             (scn->ds_shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR)));
 785 }
 786 
 787 /*
 788  * Return a pointer to the section data.
 789  */
 790 void *
 791 dis_section_data(dis_scn_t *scn)
 792 {
 793         return (scn->ds_data->d_buf);
 794 }
 795 
 796 /*
 797  * Return the size of the section data.
 798  */
 799 size_t
 800 dis_section_size(dis_scn_t *scn)
 801 {
 802         return (scn->ds_data->d_size);
 803 }
 804 
 805 /*
 806  * Return the address for the given section.
 807  */
 808 uint64_t
 809 dis_section_addr(dis_scn_t *scn)
 810 {
 811         return (scn->ds_shdr.sh_addr);
 812 }
 813 
 814 /*
 815  * Return the name of the current section.
 816  */
 817 const char *
 818 dis_section_name(dis_scn_t *scn)
 819 {
 820         return (scn->ds_name);
 821 }
 822 
 823 /*
 824  * Create an allocated copy of the given section
 825  */
 826 dis_scn_t *
 827 dis_section_copy(dis_scn_t *scn)
 828 {
 829         dis_scn_t *new;
 830 
 831         new = safe_malloc(sizeof (dis_scn_t));
 832         (void) memcpy(new, scn, sizeof (dis_scn_t));
 833 
 834         return (new);
 835 }
 836 
 837 /*
 838  * Free section memory
 839  */
 840 void
 841 dis_section_free(dis_scn_t *scn)
 842 {
 843         free(scn);
 844 }
 845 
 846 /*
 847  * Iterate over all functions in the target, executing the given callback for
 848  * each one.
 849  */
 850 void
 851 dis_tgt_function_iter(dis_tgt_t *tgt, function_iter_f func, void *data)
 852 {
 853         int i;
 854         sym_entry_t *sym;
 855         dis_func_t df;
 856         Elf_Scn *scn;
 857         GElf_Shdr       shdr;
 858 
 859         for (i = 0, sym = tgt->dt_symtab; i < tgt->dt_symcount; i++, sym++) {
 860 
 861                 /* ignore non-functions */
 862                 if ((GELF_ST_TYPE(sym->se_sym.st_info) != STT_FUNC) ||
 863                     (sym->se_name == NULL) ||
 864                     (sym->se_sym.st_size == 0) ||
 865                     (sym->se_shndx >= SHN_LORESERVE))
 866                         continue;
 867 
 868                 /* get the ELF data associated with this function */
 869                 if ((scn = elf_getscn(tgt->dt_elf, sym->se_shndx)) == NULL ||
 870                     gelf_getshdr(scn, &shdr) == NULL ||
 871                     (df.df_data = elf_getdata(scn, NULL)) == NULL ||
 872                     df.df_data->d_size == 0) {
 873                         warn("%s: failed to read section %d",
 874                             tgt->dt_filename, sym->se_shndx);
 875                         continue;
 876                 }
 877 
 878                 if (tgt->dt_shnmap[sym->se_shndx].dm_mapped)
 879                         shdr.sh_addr = tgt->dt_shnmap[sym->se_shndx].dm_start;
 880 
 881                 /*
 882                  * Verify that the address lies within the section that we think
 883                  * it does.
 884                  */
 885                 if (sym->se_sym.st_value < shdr.sh_addr ||
 886                     (sym->se_sym.st_value + sym->se_sym.st_size) >
 887                     (shdr.sh_addr + shdr.sh_size)) {
 888                         warn("%s: bad section %d for address %p",
 889                             tgt->dt_filename, sym->se_sym.st_shndx,
 890                             sym->se_sym.st_value);
 891                         continue;
 892                 }
 893 
 894                 df.df_sym = sym;
 895                 df.df_offset = sym->se_sym.st_value - shdr.sh_addr;
 896 
 897                 func(tgt, &df, data);
 898         }
 899 }
 900 
 901 /*
 902  * Return the data associated with a given function.
 903  */
 904 void *
 905 dis_function_data(dis_func_t *func)
 906 {
 907         return ((char *)func->df_data->d_buf + func->df_offset);
 908 }
 909 
 910 /*
 911  * Return the size of a function.
 912  */
 913 size_t
 914 dis_function_size(dis_func_t *func)
 915 {
 916         return (func->df_sym->se_sym.st_size);
 917 }
 918 
 919 /*
 920  * Return the address of a function.
 921  */
 922 uint64_t
 923 dis_function_addr(dis_func_t *func)
 924 {
 925         return (func->df_sym->se_sym.st_value);
 926 }
 927 
 928 /*
 929  * Return the name of the function
 930  */
 931 const char *
 932 dis_function_name(dis_func_t *func)
 933 {
 934         return (func->df_sym->se_name);
 935 }
 936 
 937 /*
 938  * Return a copy of a function.
 939  */
 940 dis_func_t *
 941 dis_function_copy(dis_func_t *func)
 942 {
 943         dis_func_t *new;
 944 
 945         new = safe_malloc(sizeof (dis_func_t));
 946         (void) memcpy(new, func, sizeof (dis_func_t));
 947 
 948         return (new);
 949 }
 950 
 951 /*
 952  * Free function memory
 953  */
 954 void
 955 dis_function_free(dis_func_t *func)
 956 {
 957         free(func);
 958 }