Print this page
OS-4904 mdb can't print types from an object file with ctf
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
OS-4341 libproc should also check the GNU build id in addition to the debug link
Reviewed by: Patrick Mooney <patrick.f.mooney@gmail.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
OS-4050 libproc reads .gnu_debuglink padding incorrectly
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
OS-3780 libproc could know about .gnu_debuglink for remote symbol tables
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libproc/common/Psymtab.c
          +++ new/usr/src/lib/libproc/common/Psymtab.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
  24      - * Copyright (c) 2013, Joyent, Inc. All rights reserved.
       24 + * Copyright 2016 Joyent, Inc.
  25   25   * Copyright (c) 2013 by Delphix. All rights reserved.
  26   26   */
  27   27  
  28   28  #include <assert.h>
  29   29  #include <stdio.h>
  30   30  #include <stdlib.h>
  31   31  #include <stddef.h>
  32   32  #include <unistd.h>
  33   33  #include <ctype.h>
  34   34  #include <fcntl.h>
↓ open down ↓ 1 lines elided ↑ open up ↑
  36   36  #include <strings.h>
  37   37  #include <memory.h>
  38   38  #include <errno.h>
  39   39  #include <dirent.h>
  40   40  #include <signal.h>
  41   41  #include <limits.h>
  42   42  #include <libgen.h>
  43   43  #include <sys/types.h>
  44   44  #include <sys/stat.h>
  45   45  #include <sys/sysmacros.h>
       46 +#include <sys/crc32.h>
  46   47  
  47   48  #include "libproc.h"
  48   49  #include "Pcontrol.h"
  49   50  #include "Putil.h"
  50   51  #include "Psymtab_machelf.h"
  51   52  
  52   53  static file_info_t *build_map_symtab(struct ps_prochandle *, map_info_t *);
  53   54  static map_info_t *exec_map(struct ps_prochandle *);
  54   55  static map_info_t *object_to_map(struct ps_prochandle *, Lmid_t, const char *);
  55   56  static map_info_t *object_name_to_map(struct ps_prochandle *,
  56   57          Lmid_t, const char *);
  57   58  static GElf_Sym *sym_by_name(sym_tbl_t *, const char *, GElf_Sym *, uint_t *);
  58   59  static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uint_t *,
  59   60      uintptr_t);
  60   61  #ifdef _LP64
  61   62  static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uint_t *,
  62   63      uintptr_t);
  63   64  #endif
       65 +static uint32_t psym_crc32[] = { CRC32_TABLE };
  64   66  
  65   67  #define DATA_TYPES      \
  66   68          ((1 << STT_OBJECT) | (1 << STT_FUNC) | \
  67   69          (1 << STT_COMMON) | (1 << STT_TLS))
  68   70  #define IS_DATA_TYPE(tp)        (((1 << (tp)) & DATA_TYPES) != 0)
  69   71  
  70   72  #define MA_RWX  (MA_READ | MA_WRITE | MA_EXEC)
  71   73  
       74 +/*
       75 + * Minimum and maximum length of a build-id that we'll accept. Generally it's a
       76 + * 20 byte SHA1 and it's expected that the first byte (which is two ascii
       77 + * characters) indicates a directory and the remaining bytes become the file
       78 + * name. Therefore, our minimum length is at least 2 bytes (one for the
       79 + * directory and one for the name) and the max is a bit over the minimum -- 64,
       80 + * just in case folks do something odd. The string length is three times the max
       81 + * length. This accounts for the fact that each byte is two characters, a null
       82 + * terminator, and the directory '/' character.
       83 + */
       84 +#define MINBUILDID      2
       85 +#define MAXBUILDID      64
       86 +#define BUILDID_STRLEN  (3*MAXBUILDID)
       87 +#define BUILDID_NAME    ".note.gnu.build-id"
       88 +#define DBGLINK_NAME    ".gnu_debuglink"
       89 +
  72   90  typedef enum {
  73   91          PRO_NATURAL,
  74   92          PRO_BYADDR,
  75   93          PRO_BYNAME
  76   94  } pr_order_t;
  77   95  
  78   96  static int
  79   97  addr_cmp(const void *aa, const void *bb)
  80   98  {
  81   99          uintptr_t a = *((uintptr_t *)aa);
↓ open down ↓ 95 lines elided ↑ open up ↑
 177  195          uint_t i;
 178  196  
 179  197          if ((fptr = calloc(1, sizeof (file_info_t))) == NULL)
 180  198                  return (NULL);
 181  199  
 182  200          list_link(fptr, &P->file_head);
 183  201          (void) strcpy(fptr->file_pname, mptr->map_pmap.pr_mapname);
 184  202          mptr->map_file = fptr;
 185  203          fptr->file_ref = 1;
 186  204          fptr->file_fd = -1;
      205 +        fptr->file_dbgfile = -1;
 187  206          P->num_files++;
 188  207  
 189  208          /*
 190  209           * To figure out which map_info_t instances correspond to the mappings
 191  210           * for this load object we try to obtain the start and end address
 192  211           * for each section of our in-memory ELF image. If successful, we
 193  212           * walk down the list of addresses and the list of map_info_t
 194  213           * instances in lock step to correctly find the mappings that
 195  214           * correspond to this load object.
 196  215           */
↓ open down ↓ 70 lines elided ↑ open up ↑
 267  286                  if (fptr->file_lname)
 268  287                          free(fptr->file_lname);
 269  288                  if (fptr->file_rname)
 270  289                          free(fptr->file_rname);
 271  290                  if (fptr->file_elf)
 272  291                          (void) elf_end(fptr->file_elf);
 273  292                  if (fptr->file_elfmem != NULL)
 274  293                          free(fptr->file_elfmem);
 275  294                  if (fptr->file_fd >= 0)
 276  295                          (void) close(fptr->file_fd);
      296 +                if (fptr->file_dbgelf)
      297 +                        (void) elf_end(fptr->file_dbgelf);
      298 +                if (fptr->file_dbgfile >= 0)
      299 +                        (void) close(fptr->file_dbgfile);
 277  300                  if (fptr->file_ctfp) {
 278  301                          ctf_close(fptr->file_ctfp);
 279  302                          free(fptr->file_ctf_buf);
 280  303                  }
 281  304                  if (fptr->file_saddrs)
 282  305                          free(fptr->file_saddrs);
 283  306                  free(fptr);
 284  307                  P->num_files--;
 285  308          }
 286  309  }
↓ open down ↓ 525 lines elided ↑ open up ↑
 812  835              (fptr = mptr->map_file) == NULL)
 813  836                  return (NULL);
 814  837  
 815  838          return (Pbuild_file_ctf(P, fptr));
 816  839  }
 817  840  
 818  841  ctf_file_t *
 819  842  Plmid_to_ctf(struct ps_prochandle *P, Lmid_t lmid, const char *name)
 820  843  {
 821  844          map_info_t *mptr;
 822      -        file_info_t *fptr;
      845 +        file_info_t *fptr = NULL;
 823  846  
 824  847          if (name == PR_OBJ_EVERY)
 825  848                  return (NULL);
 826  849  
 827      -        if ((mptr = object_name_to_map(P, lmid, name)) == NULL ||
 828      -            (fptr = mptr->map_file) == NULL)
 829      -                return (NULL);
      850 +        /*
      851 +         * While most idle files are all ELF objects, not all of them have
      852 +         * mapping information available. There's nothing which would make
      853 +         * sense to fake up for ET_REL. Instead, if we're being asked for their
      854 +         * executable object and we know that the information is valid and they
      855 +         * only have a single file, we jump straight to that file pointer.
      856 +         */
      857 +        if (P->state == PS_IDLE && name == PR_OBJ_EXEC && P->info_valid == 1 &&
      858 +            P->num_files == 1 && P->mappings == NULL) {
      859 +                fptr = list_next(&P->file_head);
      860 +        }
 830  861  
      862 +        if (fptr == NULL) {
      863 +                if ((mptr = object_name_to_map(P, lmid, name)) == NULL ||
      864 +                    (fptr = mptr->map_file) == NULL)
      865 +                        return (NULL);
      866 +        }
      867 +
 831  868          return (Pbuild_file_ctf(P, fptr));
 832  869  }
 833  870  
 834  871  ctf_file_t *
 835  872  Pname_to_ctf(struct ps_prochandle *P, const char *name)
 836  873  {
 837  874          return (Plmid_to_ctf(P, PR_LMID_EVERY, name));
 838  875  }
 839  876  
 840  877  void
↓ open down ↓ 696 lines elided ↑ open up ↑
1537 1574                  sort_syms = NULL;
1538 1575                  (void) mutex_unlock(&sort_mtx);
1539 1576          }
1540 1577  
1541 1578          free(syms);
1542 1579  }
1543 1580  
1544 1581  
1545 1582  static Elf *
1546 1583  build_fake_elf(struct ps_prochandle *P, file_info_t *fptr, GElf_Ehdr *ehdr,
1547      -        size_t *nshdrs, Elf_Data **shdata)
     1584 +    size_t *nshdrs, Elf_Data **shdata)
1548 1585  {
1549 1586          size_t shstrndx;
1550 1587          Elf_Scn *scn;
1551 1588          Elf *elf;
1552 1589  
1553 1590          if ((elf = fake_elf(P, fptr)) == NULL ||
1554 1591              elf_kind(elf) != ELF_K_ELF ||
1555 1592              gelf_getehdr(elf, ehdr) == NULL ||
1556 1593              elf_getshdrnum(elf, nshdrs) == -1 ||
1557 1594              elf_getshdrstrndx(elf, &shstrndx) == -1 ||
↓ open down ↓ 2 lines elided ↑ open up ↑
1560 1597                  if (elf != NULL)
1561 1598                          (void) elf_end(elf);
1562 1599                  dprintf("failed to fake up ELF file\n");
1563 1600                  return (NULL);
1564 1601          }
1565 1602  
1566 1603          return (elf);
1567 1604  }
1568 1605  
1569 1606  /*
     1607 + * Try and find the file described by path in the file system and validate that
     1608 + * it matches our CRC before we try and process it for symbol information. If we
     1609 + * instead have an ELF data section, then that means we're checking a build-id
     1610 + * section instead. In that case we just need to find and bcmp the corresponding
     1611 + * section.
     1612 + *
     1613 + * Before we validate if it's a valid CRC or data section, we check to ensure
     1614 + * that it's a normal file and not anything else.
     1615 + */
     1616 +static boolean_t
     1617 +build_alt_debug(file_info_t *fptr, const char *path, uint32_t crc,
     1618 +    Elf_Data *data)
     1619 +{
     1620 +        int fd;
     1621 +        struct stat st;
     1622 +        Elf *elf;
     1623 +        Elf_Scn *scn;
     1624 +        GElf_Shdr symshdr, strshdr;
     1625 +        Elf_Data *symdata, *strdata;
     1626 +        boolean_t valid;
     1627 +        uint32_t c = -1U;
     1628 +
     1629 +        if ((fd = open(path, O_RDONLY)) < 0)
     1630 +                return (B_FALSE);
     1631 +
     1632 +        if (fstat(fd, &st) != 0) {
     1633 +                (void) close(fd);
     1634 +                return (B_FALSE);
     1635 +        }
     1636 +
     1637 +        if (S_ISREG(st.st_mode) == 0) {
     1638 +                (void) close(fd);
     1639 +                return (B_FALSE);
     1640 +        }
     1641 +
     1642 +        /*
     1643 +         * Only check the CRC if we've come here through a GNU debug link
     1644 +         * section as opposed to the build id. This is indicated by having the
     1645 +         * value of data be NULL.
     1646 +         */
     1647 +        if (data == NULL) {
     1648 +                for (;;) {
     1649 +                        char buf[4096];
     1650 +                        ssize_t ret = read(fd, buf, sizeof (buf));
     1651 +                        if (ret == -1) {
     1652 +                                if (ret == EINTR)
     1653 +                                        continue;
     1654 +                                (void) close(fd);
     1655 +                                return (B_FALSE);
     1656 +                        }
     1657 +                        if (ret == 0) {
     1658 +                                c = ~c;
     1659 +                                if (c != crc) {
     1660 +                                        dprintf("crc mismatch, found: 0x%x "
     1661 +                                            "expected 0x%x\n", c, crc);
     1662 +                                        (void) close(fd);
     1663 +                                        return (B_FALSE);
     1664 +                                }
     1665 +                                break;
     1666 +                        }
     1667 +                        CRC32(c, buf, ret, c, psym_crc32);
     1668 +                }
     1669 +        }
     1670 +
     1671 +        elf = elf_begin(fd, ELF_C_READ, NULL);
     1672 +        if (elf == NULL) {
     1673 +                (void) close(fd);
     1674 +                return (B_FALSE);
     1675 +        }
     1676 +
     1677 +        if (elf_kind(elf) != ELF_K_ELF) {
     1678 +                goto fail;
     1679 +        }
     1680 +
     1681 +        /*
     1682 +         * If we have a data section, that indicates we have a build-id which
     1683 +         * means we need to find the corresponding build-id section and compare
     1684 +         * it.
     1685 +         */
     1686 +        scn = NULL;
     1687 +        valid = B_FALSE;
     1688 +        for (scn = elf_nextscn(elf, scn); data != NULL && scn != NULL;
     1689 +            scn = elf_nextscn(elf, scn)) {
     1690 +                GElf_Shdr hdr;
     1691 +                Elf_Data *ntdata;
     1692 +
     1693 +                if (gelf_getshdr(scn, &hdr) == NULL)
     1694 +                        goto fail;
     1695 +
     1696 +                if (hdr.sh_type != SHT_NOTE)
     1697 +                        continue;
     1698 +
     1699 +                if ((ntdata = elf_getdata(scn, NULL)) == NULL)
     1700 +                        goto fail;
     1701 +
     1702 +                /*
     1703 +                 * First verify the data section sizes are equal, then the
     1704 +                 * section name. If that's all true, then we can just do a bcmp.
     1705 +                 */
     1706 +                if (data->d_size != ntdata->d_size)
     1707 +                        continue;
     1708 +
     1709 +                dprintf("found corresponding section in alternate file\n");
     1710 +                if (bcmp(ntdata->d_buf, data->d_buf, data->d_size) != 0)
     1711 +                        goto fail;
     1712 +
     1713 +                valid = B_TRUE;
     1714 +                break;
     1715 +        }
     1716 +        if (data != NULL && valid == B_FALSE) {
     1717 +                dprintf("failed to find a matching %s section in %s\n",
     1718 +                    BUILDID_NAME, path);
     1719 +                goto fail;
     1720 +        }
     1721 +
     1722 +
     1723 +        /*
     1724 +         * Do two passes, first see if we have a symbol header, then see if we
     1725 +         * can find the corresponding linked string table.
     1726 +         */
     1727 +        scn = NULL;
     1728 +        for (scn = elf_nextscn(elf, scn); scn != NULL;
     1729 +            scn = elf_nextscn(elf, scn)) {
     1730 +
     1731 +                if (gelf_getshdr(scn, &symshdr) == NULL)
     1732 +                        goto fail;
     1733 +
     1734 +                if (symshdr.sh_type != SHT_SYMTAB)
     1735 +                        continue;
     1736 +
     1737 +                if ((symdata = elf_getdata(scn, NULL)) == NULL)
     1738 +                        goto fail;
     1739 +
     1740 +                break;
     1741 +        }
     1742 +        if (scn == NULL)
     1743 +                goto fail;
     1744 +
     1745 +        if ((scn = elf_getscn(elf, symshdr.sh_link)) == NULL)
     1746 +                goto fail;
     1747 +
     1748 +        if (gelf_getshdr(scn, &strshdr) == NULL)
     1749 +                goto fail;
     1750 +
     1751 +        if ((strdata = elf_getdata(scn, NULL)) == NULL)
     1752 +                goto fail;
     1753 +
     1754 +        fptr->file_symtab.sym_data_pri = symdata;
     1755 +        fptr->file_symtab.sym_symn += symshdr.sh_size / symshdr.sh_entsize;
     1756 +        fptr->file_symtab.sym_strs = strdata->d_buf;
     1757 +        fptr->file_symtab.sym_strsz = strdata->d_size;
     1758 +        fptr->file_symtab.sym_hdr_pri = symshdr;
     1759 +        fptr->file_symtab.sym_strhdr = strshdr;
     1760 +
     1761 +        dprintf("successfully loaded additional debug symbols for %s from %s\n",
     1762 +            fptr->file_rname, path);
     1763 +
     1764 +        fptr->file_dbgfile = fd;
     1765 +        fptr->file_dbgelf = elf;
     1766 +        return (B_TRUE);
     1767 +fail:
     1768 +        (void) elf_end(elf);
     1769 +        (void) close(fd);
     1770 +        return (B_FALSE);
     1771 +}
     1772 +
     1773 +/*
     1774 + * We're here because the object in question has no symbol information, that's a
     1775 + * bit unfortunate. However, we've found that there's a .gnu_debuglink sitting
     1776 + * around. By convention that means that given the current location of the
     1777 + * object on disk, and the debug name that we found in the binary we need to
     1778 + * search the following locations for a matching file.
     1779 + *
     1780 + * <dirname>/.debug/<debug-name>
     1781 + * /usr/lib/debug/<dirname>/<debug-name>
     1782 + *
     1783 + * In the future, we should consider supporting looking in the prefix's
     1784 + * lib/debug directory for a matching object or supporting an arbitrary user
     1785 + * defined set of places to look.
     1786 + */
     1787 +static void
     1788 +find_alt_debuglink(file_info_t *fptr, const char *name, uint32_t crc)
     1789 +{
     1790 +        boolean_t r;
     1791 +        char *dup = NULL, *path = NULL, *dname;
     1792 +
     1793 +        dprintf("find_alt_debug: looking for %s, crc 0x%x\n", name, crc);
     1794 +        if (fptr->file_rname == NULL) {
     1795 +                dprintf("find_alt_debug: encountered null file_rname\n");
     1796 +                return;
     1797 +        }
     1798 +
     1799 +        dup = strdup(fptr->file_rname);
     1800 +        if (dup == NULL)
     1801 +                return;
     1802 +
     1803 +        dname = dirname(dup);
     1804 +        if (asprintf(&path, "%s/.debug/%s", dname, name) != -1) {
     1805 +                dprintf("attempting to load alternate debug information "
     1806 +                    "from %s\n", path);
     1807 +                r = build_alt_debug(fptr, path, crc, NULL);
     1808 +                free(path);
     1809 +                if (r == B_TRUE)
     1810 +                        goto out;
     1811 +        }
     1812 +
     1813 +        if (asprintf(&path, "/usr/lib/debug/%s/%s", dname, name) != -1) {
     1814 +                dprintf("attempting to load alternate debug information "
     1815 +                    "from %s\n", path);
     1816 +                r = build_alt_debug(fptr, path, crc, NULL);
     1817 +                free(path);
     1818 +                if (r == B_TRUE)
     1819 +                        goto out;
     1820 +        }
     1821 +out:
     1822 +        free(dup);
     1823 +}
     1824 +
     1825 +/*
1570 1826   * Build the symbol table for the given mapped file.
1571 1827   */
1572 1828  void
1573 1829  Pbuild_file_symtab(struct ps_prochandle *P, file_info_t *fptr)
1574 1830  {
1575 1831          char objectfile[PATH_MAX];
1576 1832          uint_t i;
1577 1833  
1578 1834          GElf_Ehdr ehdr;
1579 1835          GElf_Sym s;
1580 1836  
1581 1837          Elf_Data *shdata;
1582 1838          Elf_Scn *scn;
1583 1839          Elf *elf;
1584 1840          size_t nshdrs, shstrndx;
1585 1841  
1586 1842          struct {
1587 1843                  GElf_Shdr c_shdr;
1588 1844                  Elf_Data *c_data;
1589 1845                  const char *c_name;
1590      -        } *cp, *cache = NULL, *dyn = NULL, *plt = NULL, *ctf = NULL;
     1846 +        } *cp, *cache = NULL, *dyn = NULL, *plt = NULL, *ctf = NULL,
     1847 +        *dbglink = NULL, *buildid = NULL;
1591 1848  
1592 1849          if (fptr->file_init)
1593 1850                  return; /* We've already processed this file */
1594 1851  
1595 1852          /*
1596 1853           * Mark the file_info struct as having the symbol table initialized
1597 1854           * even if we fail below.  We tried once; we don't try again.
1598 1855           */
1599 1856          fptr->file_init = 1;
1600 1857  
↓ open down ↓ 205 lines elided ↑ open up ↑
1806 2063                           */
1807 2064                          if (shp->sh_link == 0 ||
1808 2065                              shp->sh_link >= nshdrs ||
1809 2066                              (cache[shp->sh_link].c_shdr.sh_type != SHT_DYNSYM &&
1810 2067                              cache[shp->sh_link].c_shdr.sh_type != SHT_SYMTAB)) {
1811 2068                                  dprintf("Bad sh_link %d for "
1812 2069                                      "CTF\n", shp->sh_link);
1813 2070                                  continue;
1814 2071                          }
1815 2072                          ctf = cp;
     2073 +                } else if (strcmp(cp->c_name, BUILDID_NAME) == 0) {
     2074 +                        dprintf("Found a %s section for %s\n", BUILDID_NAME,
     2075 +                            fptr->file_rname);
     2076 +                        /* The ElfXX_Nhdr is 32/64-bit neutral */
     2077 +                        if (cp->c_shdr.sh_type == SHT_NOTE &&
     2078 +                            cp->c_data->d_buf != NULL &&
     2079 +                            cp->c_data->d_size >= sizeof (Elf32_Nhdr)) {
     2080 +                                Elf32_Nhdr *hdr = cp->c_data->d_buf;
     2081 +                                if (hdr->n_type != 3)
     2082 +                                        continue;
     2083 +                                if (hdr->n_namesz != 4)
     2084 +                                        continue;
     2085 +                                if (hdr->n_descsz < MINBUILDID)
     2086 +                                        continue;
     2087 +                                /* Set a reasonable upper bound */
     2088 +                                if (hdr->n_descsz > MAXBUILDID) {
     2089 +                                        dprintf("Skipped %s as too large "
     2090 +                                            "(%ld)\n", BUILDID_NAME,
     2091 +                                            (unsigned long)hdr->n_descsz);
     2092 +                                        continue;
     2093 +                                }
     2094 +
     2095 +                                if (cp->c_data->d_size < sizeof (hdr) +
     2096 +                                    hdr->n_namesz + hdr->n_descsz)
     2097 +                                        continue;
     2098 +                                buildid = cp;
     2099 +                        }
     2100 +                } else if (strcmp(cp->c_name, DBGLINK_NAME) == 0) {
     2101 +                        dprintf("found %s section for %s\n", DBGLINK_NAME,
     2102 +                            fptr->file_rname);
     2103 +                        /*
     2104 +                         * Let's make sure of a few things before we do this.
     2105 +                         */
     2106 +                        if (cp->c_shdr.sh_type == SHT_PROGBITS &&
     2107 +                            cp->c_data->d_buf != NULL &&
     2108 +                            cp->c_data->d_size) {
     2109 +                                dbglink = cp;
     2110 +                        }
1816 2111                  }
1817 2112          }
1818 2113  
1819 2114          /*
     2115 +         * If we haven't found any symbol table information and we have found
     2116 +         * either a .note.gnu.build-id or a .gnu_debuglink, it's time to try and
     2117 +         * figure out where we might find this. Originally, GNU used the
     2118 +         * .gnu_debuglink solely, but then they added a .note.gnu.build-id. The
     2119 +         * build-id is some size, usually 16 or 20 bytes, often a SHA1 sum of
     2120 +         * the old, but not present file. All that you have to do to compare
     2121 +         * things is see if the sections are less, in theory saving you from
     2122 +         * doing lots of expensive I/O.
     2123 +         *
     2124 +         * For the .note.gnu.build-id, we're going to check a few things before
     2125 +         * using it, first that the name is 4 bytes, and is GNU and that the
     2126 +         * type is 3, which they say is the build-id identifier.
     2127 +         *
     2128 +         * To verify that the elf data for the .gnu_debuglink seems somewhat
     2129 +         * sane, eg. the elf data should be a string, so we want to verify we
     2130 +         * have a null-terminator.
     2131 +         */
     2132 +        if (fptr->file_symtab.sym_data_pri == NULL && buildid != NULL) {
     2133 +                int i, bo;
     2134 +                uint8_t *dp;
     2135 +                char buf[BUILDID_STRLEN], *path;
     2136 +                Elf32_Nhdr *hdr = buildid->c_data->d_buf;
     2137 +
     2138 +                /*
     2139 +                 * This was checked for validity when assigning the buildid
     2140 +                 * variable.
     2141 +                 */
     2142 +                bzero(buf, sizeof (buf));
     2143 +                dp = (uint8_t *)((uintptr_t)hdr + sizeof (*hdr) +
     2144 +                    hdr->n_namesz);
     2145 +                for (i = 0, bo = 0; i < hdr->n_descsz; i++, bo += 2, dp++) {
     2146 +                        assert(sizeof (buf) - bo > 0);
     2147 +
     2148 +                        /*
     2149 +                         * Recall that the build-id is structured as a series of
     2150 +                         * bytes. However, the first two characters are supposed
     2151 +                         * to represent a directory. Hence, once we reach offset
     2152 +                         * two, we insert a '/' character.
     2153 +                         */
     2154 +                        if (bo == 2) {
     2155 +                                buf[bo] = '/';
     2156 +                                bo++;
     2157 +                        }
     2158 +                        (void) snprintf(buf + bo, sizeof (buf) - bo, "%2x",
     2159 +                            *dp);
     2160 +                }
     2161 +
     2162 +                if (asprintf(&path, "/usr/lib/debug/.build-id/%s.debug",
     2163 +                    buf) != -1) {
     2164 +                        boolean_t r;
     2165 +                        dprintf("attempting to find build id alternate debug "
     2166 +                            "file at %s\n", path);
     2167 +                        r = build_alt_debug(fptr, path, 0, buildid->c_data);
     2168 +                        dprintf("attempt %s\n", r == B_TRUE ?
     2169 +                            "succeeded" : "failed");
     2170 +                        free(path);
     2171 +                } else {
     2172 +                        dprintf("failed to construct build id path: %s\n",
     2173 +                            strerror(errno));
     2174 +                }
     2175 +        }
     2176 +
     2177 +        if (fptr->file_symtab.sym_data_pri == NULL && dbglink != NULL) {
     2178 +                char *c = dbglink->c_data->d_buf;
     2179 +                size_t i;
     2180 +                boolean_t found = B_FALSE;
     2181 +                Elf_Data *ed = dbglink->c_data;
     2182 +                uint32_t crc;
     2183 +
     2184 +                for (i = 0; i < ed->d_size; i++) {
     2185 +                        if (c[i] == '\0') {
     2186 +                                uintptr_t off;
     2187 +                                dprintf("got .gnu_debuglink terminator at "
     2188 +                                    "offset %lu\n", (unsigned long)i);
     2189 +                                /*
     2190 +                                 * After the null terminator, there should be
     2191 +                                 * padding, followed by a 4 byte CRC of the
     2192 +                                 * file. If we don't see this, we're going to
     2193 +                                 * assume this is bogus.
     2194 +                                 */
     2195 +                                if ((i % sizeof (uint32_t)) == 0) {
     2196 +                                        i += 4;
     2197 +                                } else {
     2198 +                                        i += sizeof (uint32_t) -
     2199 +                                            (i % sizeof (uint32_t));
     2200 +                                }
     2201 +                                if (i + sizeof (uint32_t) ==
     2202 +                                    dbglink->c_data->d_size) {
     2203 +                                        found = B_TRUE;
     2204 +                                        off = (uintptr_t)ed->d_buf + i;
     2205 +                                        crc = *(uint32_t *)off;
     2206 +                                } else {
     2207 +                                        dprintf(".gnu_debuglink size mismatch, "
     2208 +                                            "expected: %lu, found: %lu\n",
     2209 +                                            (unsigned long)i,
     2210 +                                            (unsigned long)ed->d_size);
     2211 +                                }
     2212 +                                break;
     2213 +                        }
     2214 +                }
     2215 +
     2216 +                if (found == B_TRUE)
     2217 +                        find_alt_debuglink(fptr, dbglink->c_data->d_buf, crc);
     2218 +        }
     2219 +
     2220 +        /*
1820 2221           * At this point, we've found all the symbol tables we're ever going
1821 2222           * to find: the ones in the loop above and possibly the symtab that
1822 2223           * was included in the core file. Before we perform any lookups, we
1823 2224           * create sorted versions to optimize for lookups.
1824 2225           */
1825 2226          optimize_symtab(&fptr->file_symtab);
1826 2227          optimize_symtab(&fptr->file_dynsym);
1827 2228  
1828 2229          /*
1829 2230           * Fill in the base address of the text mapping for shared libraries.
↓ open down ↓ 106 lines elided ↑ open up ↑
1936 2337          if (cache != NULL)
1937 2338                  free(cache);
1938 2339  
1939 2340          (void) elf_end(elf);
1940 2341          fptr->file_elf = NULL;
1941 2342          if (fptr->file_elfmem != NULL) {
1942 2343                  free(fptr->file_elfmem);
1943 2344                  fptr->file_elfmem = NULL;
1944 2345          }
1945 2346          (void) close(fptr->file_fd);
     2347 +        if (fptr->file_dbgelf != NULL)
     2348 +                (void) elf_end(fptr->file_dbgelf);
     2349 +        fptr->file_dbgelf = NULL;
     2350 +        if (fptr->file_dbgfile >= 0)
     2351 +                (void) close(fptr->file_dbgfile);
1946 2352          fptr->file_fd = -1;
     2353 +        fptr->file_dbgfile = -1;
1947 2354  }
1948 2355  
1949 2356  /*
1950 2357   * Given a process virtual address, return the map_info_t containing it.
1951 2358   * If none found, return NULL.
1952 2359   */
1953 2360  map_info_t *
1954 2361  Paddr2mptr(struct ps_prochandle *P, uintptr_t addr)
1955 2362  {
1956 2363          int lo = 0;
↓ open down ↓ 615 lines elided ↑ open up ↑
2572 2979  
2573 2980          return (rv);
2574 2981  }
2575 2982  
2576 2983  /*
2577 2984   * Search the process symbol tables looking for a symbol whose name matches the
2578 2985   * specified name, but without any restriction on the link map id.
2579 2986   */
2580 2987  int
2581 2988  Plookup_by_name(struct ps_prochandle *P, const char *object,
2582      -        const char *symbol, GElf_Sym *symp)
     2989 +    const char *symbol, GElf_Sym *symp)
2583 2990  {
2584 2991          return (Pxlookup_by_name(P, PR_LMID_EVERY, object, symbol, symp, NULL));
2585 2992  }
2586 2993  
2587 2994  /*
2588 2995   * Iterate over the process's address space mappings.
2589 2996   */
2590 2997  static int
2591 2998  i_Pmapping_iter(struct ps_prochandle *P, boolean_t lmresolve,
2592 2999      proc_map_f *func, void *cd)
↓ open down ↓ 77 lines elided ↑ open up ↑
2670 3077  }
2671 3078  
2672 3079  int
2673 3080  Pobject_iter_resolved(struct ps_prochandle *P, proc_map_f *func, void *cd)
2674 3081  {
2675 3082          return (i_Pobject_iter(P, B_TRUE, func, cd));
2676 3083  }
2677 3084  
2678 3085  static char *
2679 3086  i_Pobjname(struct ps_prochandle *P, boolean_t lmresolve, uintptr_t addr,
2680      -        char *buffer, size_t bufsize)
     3087 +    char *buffer, size_t bufsize)
2681 3088  {
2682 3089          map_info_t *mptr;
2683 3090          file_info_t *fptr;
2684 3091  
2685 3092          /* create all the file_info_t's for all the mappings */
2686 3093          (void) Prd_agent(P);
2687 3094  
2688 3095          if ((mptr = Paddr2mptr(P, addr)) == NULL)
2689 3096                  return (NULL);
2690 3097  
↓ open down ↓ 12 lines elided ↑ open up ↑
2703 3110          return (NULL);
2704 3111  }
2705 3112  
2706 3113  /*
2707 3114   * Given a virtual address, return the name of the underlying
2708 3115   * mapped object (file) as provided by the dynamic linker.
2709 3116   * Return NULL if we can't find any name information for the object.
2710 3117   */
2711 3118  char *
2712 3119  Pobjname(struct ps_prochandle *P, uintptr_t addr,
2713      -        char *buffer, size_t bufsize)
     3120 +    char *buffer, size_t bufsize)
2714 3121  {
2715 3122          return (i_Pobjname(P, B_FALSE, addr, buffer, bufsize));
2716 3123  }
2717 3124  
2718 3125  /*
2719 3126   * Given a virtual address, try to return a filesystem path to the
2720 3127   * underlying mapped object (file).  If we're in the global zone,
2721 3128   * this path could resolve to an object in another zone.  If we're
2722 3129   * unable return a valid filesystem path, we'll fall back to providing
2723 3130   * the mapped object (file) name provided by the dynamic linker in
2724 3131   * the target process (ie, the object reported by Pobjname()).
2725 3132   */
2726 3133  char *
2727 3134  Pobjname_resolved(struct ps_prochandle *P, uintptr_t addr,
2728      -        char *buffer, size_t bufsize)
     3135 +    char *buffer, size_t bufsize)
2729 3136  {
2730 3137          return (i_Pobjname(P, B_TRUE, addr, buffer, bufsize));
2731 3138  }
2732 3139  
2733 3140  /*
2734 3141   * Given a virtual address, return the link map id of the underlying mapped
2735 3142   * object (file), as provided by the dynamic linker.  Return -1 on failure.
2736 3143   */
2737 3144  int
2738 3145  Plmid(struct ps_prochandle *P, uintptr_t addr, Lmid_t *lmidp)
↓ open down ↓ 413 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX