]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Add support for DWZ multifile forms DW_FORM_GNU_ref_alt/strp_alt.
authorMark Wielaard <mjw@redhat.com>
Fri, 22 Jun 2012 10:02:45 +0000 (12:02 +0200)
committerMark Wielaard <mjw@redhat.com>
Thu, 9 Aug 2012 14:32:43 +0000 (16:32 +0200)
DWZ multifile forms http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt reference an alternative
debuginfo file.  dwarf_begin and dwarf_begin_elf will try to use this
automatically.  There are no user visible changes to the libdw interface.

dwarf_formref_die, dwarf_formstring and dwarf_formudata can now return
a Dwarf_Die which comes from a CU in the alternative Dwarf descriptor.

__libdw_read_offset was adjusted to take an alternative Dwarf descriptor
into account.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
21 files changed:
libdw/ChangeLog
libdw/dwarf.h
libdw/dwarf_begin.c
libdw/dwarf_begin_elf.c
libdw/dwarf_end.c
libdw/dwarf_error.c
libdw/dwarf_formref.c
libdw/dwarf_formref_die.c
libdw/dwarf_formstring.c
libdw/dwarf_formudata.c
libdw/dwarf_getpubnames.c
libdw/libdwP.h
libdw/libdw_form.c
src/ChangeLog
src/readelf.c
tests/ChangeLog
tests/Makefile.am
tests/libtestfile_multi_shared.so.bz2 [new file with mode: 0755]
tests/run-readelf-dwz-multi.sh [new file with mode: 0755]
tests/testfile_multi.dwz.bz2 [new file with mode: 0644]
tests/testfile_multi_main.bz2 [new file with mode: 0755]

index 2bafdc22dbf3e47e28e0443ef4b54e854da43d1e..572252da01bc225ef29825cbb9be22a884cbed01 100644 (file)
@@ -1,3 +1,30 @@
+2012-06-27  Mark Wielaard  <mjw@redhat.com>
+
+       * dwarf.h: Add DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt.
+       * dwarf_begin.c (dwarf_begin): Add INTDEF.
+       * dwarf_begin_elf.c (__check_build_id): New internal_function.
+       (try_debugaltlink): New function.
+       (open_debugaltlink): Likewise.
+       (check_section): Try open_debugaltlink for .gnu_debugaltlink.
+       * dwarf_end.c (dwarf_end): Free the alternative Dwarf descriptor if
+       necessary.
+       * dwarf_error.c (errmsgs): Add DWARF_E_NO_ALT_DEBUGLINK.
+       * dwarf_formref.c (__libdw_formref): Using DW_FORM_GNU_ref_alt
+       is an error here.
+       * dwarf_formref_die.c (dwarf_formref_die): Handle DW_FORM_GNU_ref_alt.
+       * dwarf_formstring.c (dwarf_formstring): Handle DW_FORM_GNU_strp_alt.
+       * dwarf_formudata.c (__libdw_formptr): Adjust __libdw_read_offset
+       calls.
+       * dwarf_getpubnames.c (get_offsets): Adjust __libdw_read_offset call.
+       * libdwP.h: Add DWARF_E_NO_ALT_DEBUGLINK.
+       (struct Dwarf): Add alt_dwarf and free_alt fields.
+       (__libdw_read_offset): Add dbg_ret argument, use to check with
+       __libdw_offset_in_section.
+       (__check_build_id): New function declaration.
+       (dwarf_begin): Define as INTDECL.
+       * libdw_form.c (__libdw_form_val_len): Handle DW_FORM_GNU_ref_alt
+       and DW_FORM_GNU_strp_alt.
+
 2012-07-19  Mark Wielaard  <mjw@redhat.com>
 
        * dwarf.h: Add DW_OP_GNU_parameter_ref.
index f41d296021a5c3723350f80cf5ef1163686c71a6..81bc7fe58898820c6f6ad7efe8b2af9f81088376 100644 (file)
@@ -299,7 +299,10 @@ enum
     DW_FORM_sec_offset = 0x17,
     DW_FORM_exprloc = 0x18,
     DW_FORM_flag_present = 0x19,
-    DW_FORM_ref_sig8 = 0x20
+    DW_FORM_ref_sig8 = 0x20,
+
+    DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo.  */
+    DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */
   };
 
 
index 1f3fc3b90f7a0f5bde9b35dfb4e9fbb8998d935f..9f3050fdaf30024d3b2f09ea1a5fe3a38d2e4a12 100644 (file)
@@ -98,3 +98,4 @@ dwarf_begin (fd, cmd)
 
   return result;
 }
+INTDEF(dwarf_begin)
index 3e01800a545baa8ac37bbd6c38f73f739159cf47..fd957701dcad443c93aa2588578d858c340da453 100644 (file)
 # include <config.h>
 #endif
 
+#include <assert.h>
+#include <inttypes.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 
 #include "libdwP.h"
 
@@ -66,6 +71,110 @@ static const char dwarf_scnnames[IDX_last][17] =
 };
 #define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0]))
 
+internal_function int
+__check_build_id (Dwarf *dw, const uint8_t *build_id, const size_t id_len)
+{
+  if (dw == NULL)
+    return -1;
+
+  Elf *elf = dw->elf;
+  Elf_Scn *scn = elf_nextscn (elf, NULL);
+  if (scn == NULL)
+    return -1;
+
+  do
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+      if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
+       {
+         size_t pos = 0;
+         GElf_Nhdr nhdr;
+         size_t name_pos;
+         size_t desc_pos;
+         Elf_Data *data = elf_getdata (scn, NULL);
+         while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos,
+                                     &desc_pos)) > 0)
+           if (nhdr.n_type == NT_GNU_BUILD_ID
+               && nhdr.n_namesz == sizeof "GNU"
+               && ! memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU"))
+             return (nhdr.n_descsz == id_len
+                     && ! memcmp (data->d_buf + desc_pos,
+                                  build_id, id_len)) ? 0 : 1;
+        }
+      }
+    while ((scn = elf_nextscn (elf, scn)) != NULL);
+
+  return -1;
+}
+
+/* Try to open an debug alt link by name, checking build_id.
+   Marks free_alt on success, return NULL on failure.  */
+static Dwarf *
+try_debugaltlink (Dwarf *result, const char *try_name,
+                  const uint8_t *build_id, const size_t id_len)
+{
+  int fd = open (try_name, O_RDONLY);
+  if (fd > 0)
+    {
+      result->alt_dwarf = INTUSE (dwarf_begin) (fd, DWARF_C_READ);
+      if (result->alt_dwarf != NULL)
+       {
+         Elf *elf = result->alt_dwarf->elf;
+         if (__check_build_id (result->alt_dwarf, build_id, id_len) == 0
+             && elf_cntl (elf, ELF_C_FDREAD) == 0)
+           {
+             close (fd);
+             result->free_alt = 1;
+             return result;
+           }
+         INTUSE (dwarf_end) (result->alt_dwarf);
+       }
+      close (fd);
+    }
+  return NULL;
+}
+
+/* For dwz multifile support, ignore if it looks wrong.  */
+static Dwarf *
+open_debugaltlink (Dwarf *result, const char *alt_name,
+                  const uint8_t *build_id, const size_t id_len)
+{
+  /* First try the name itself, it is either an absolute path or
+     a relative one.  Sadly we don't know relative from where at
+     this point.  */
+  if (try_debugaltlink (result, alt_name, build_id, id_len) != NULL)
+    return result;
+
+  /* Lets try based on the build-id.  This is somewhat distro specific,
+     we are following the Fedora implementation described at
+  https://fedoraproject.org/wiki/Releases/FeatureBuildId#Find_files_by_build_ID
+   */
+#define DEBUG_PREFIX "/usr/lib/debug/.build-id/"
+#define PREFIX_LEN sizeof (DEBUG_PREFIX)
+  char id_name[PREFIX_LEN + 1 + id_len * 2 + sizeof ".debug" - 1];
+  strcpy (id_name, DEBUG_PREFIX);
+  int n = snprintf (&id_name[PREFIX_LEN  - 1],
+                   4, "%02" PRIx8 "/", (uint8_t) build_id[0]);
+  assert (n == 3);
+  for (size_t i = 1; i < id_len; ++i)
+    {
+      n = snprintf (&id_name[PREFIX_LEN - 1 + 3 + (i - 1) * 2],
+                   3, "%02" PRIx8, (uint8_t) build_id[i]);
+      assert (n == 2);
+    }
+  strcpy (&id_name[PREFIX_LEN - 1 + 3 + (id_len - 1) * 2],
+         ".debug");
+
+  if (try_debugaltlink (result, id_name, build_id, id_len))
+    return result;
+
+  /* Everything failed, mark this Dwarf as not having an alternate,
+     but don't fail the load.  The user may want to set it by hand
+     before usage.  */
+  result->alt_dwarf = NULL;
+  return result;
+}
 
 static Dwarf *
 check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
@@ -110,6 +219,20 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
       return NULL;
     }
 
+  /* For dwz multifile support, ignore if it looks wrong.  */
+  if (strcmp (scnname, ".gnu_debugaltlink") == 0)
+    {
+      Elf_Data *data = elf_getdata (scn, NULL);
+      if (data != NULL && data->d_size != 0)
+       {
+         const char *alt_name = data->d_buf;
+         const void *build_id = memchr (data->d_buf, '\0', data->d_size);
+         const int id_len = data->d_size - (build_id - data->d_buf + 1);
+         if (alt_name && build_id && id_len > 0)
+           return open_debugaltlink (result, alt_name, build_id + 1, id_len);
+       }
+    }
+
 
   /* Recognize the various sections.  Most names start with .debug_.  */
   size_t cnt;
index b77988f77511e5a6fdf68a618432c2c4f2f44c56..e65314ab029141f95481e07a3d77b7f3b64c5d9a 100644 (file)
@@ -111,6 +111,10 @@ dwarf_end (dwarf)
       if (dwarf->free_elf)
        elf_end (dwarf->elf);
 
+      /* Free the alternative Dwarf descriptor if necessary.  */
+      if (dwarf->free_alt)
+       INTUSE (dwarf_end) (dwarf->alt_dwarf);
+
       /* Free the context descriptor.  */
       free (dwarf);
     }
index 89047dcdeffb0d11bc99e724696064801c095f33..229291414666276ea77937428445f432f1159d65 100644 (file)
@@ -91,6 +91,7 @@ static const char *errmsgs[] =
     [DWARF_E_INVALID_OFFSET] = N_("invalid offset"),
     [DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"),
     [DWARF_E_INVALID_CFI] = N_("invalid CFI section"),
+    [DWARF_E_NO_ALT_DEBUGLINK] = N_("no alternative debug link found"),
   };
 #define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0]))
 
index a2554e914c96b646d9ed6b8efc3139e8b704c6ba..86da7eae351e7b73c37bd481588e95599f44c639 100644 (file)
@@ -72,6 +72,8 @@ __libdw_formref (attr, return_offset)
 
     case DW_FORM_ref_addr:
     case DW_FORM_ref_sig8:
+    case DW_FORM_GNU_ref_alt:
+      /* These aren't handled by dwarf_formref, only by dwarf_formref_die.  */
       __libdw_seterrno (DWARF_E_INVALID_REFERENCE);
       return -1;
 
index 342f6b9e256f658ce84e32e39549d6fc418375e8..f0701270fdc0abfc9884b293aa8251a4b51809f4 100644 (file)
@@ -46,7 +46,7 @@ dwarf_formref_die (attr, result)
   struct Dwarf_CU *cu = attr->cu;
 
   Dwarf_Off offset;
-  if (attr->form == DW_FORM_ref_addr)
+  if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt)
     {
       /* This has an absolute offset.  */
 
@@ -54,11 +54,20 @@ dwarf_formref_die (attr, result)
                          ? cu->address_size
                          : cu->offset_size);
 
-      if (__libdw_read_offset (cu->dbg, IDX_debug_info, attr->valp,
+      Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt
+                       ? cu->dbg->alt_dwarf : cu->dbg);
+
+      if (dbg_ret == NULL)
+       {
+         __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK);
+         return NULL;
+       }
+
+      if (__libdw_read_offset (cu->dbg, dbg_ret, IDX_debug_info, attr->valp,
                               ref_size, &offset, IDX_debug_info, 0))
        return NULL;
 
-      return INTUSE(dwarf_offdie) (cu->dbg, offset, result);
+      return INTUSE(dwarf_offdie) (dbg_ret, offset, result);
     }
 
   Elf_Data *data;
index fe2183a295d897f2895d3b9171d1205327d88a28..c66454e17d20807beb5a011a8cd6fc9342958f0d 100644 (file)
@@ -49,8 +49,17 @@ dwarf_formstring (attrp)
     return (const char *) attrp->valp;
 
   Dwarf *dbg = attrp->cu->dbg;
+  Dwarf *dbg_ret = attrp->form == DW_FORM_GNU_strp_alt ? dbg->alt_dwarf : dbg;
 
-  if (unlikely (attrp->form != DW_FORM_strp)
+  if (unlikely (dbg_ret == NULL))
+    {
+      __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK);
+      return NULL;
+    }
+
+
+  if (unlikely (attrp->form != DW_FORM_strp
+                  && attrp->form != DW_FORM_GNU_strp_alt)
       || dbg->sectiondata[IDX_debug_str] == NULL)
     {
       __libdw_seterrno (DWARF_E_NO_STRING);
@@ -58,10 +67,10 @@ dwarf_formstring (attrp)
     }
 
   uint64_t off;
-  if (__libdw_read_offset (dbg, cu_sec_idx (attrp->cu), attrp->valp,
+  if (__libdw_read_offset (dbg, dbg_ret, cu_sec_idx (attrp->cu), attrp->valp,
                           attrp->cu->offset_size, &off, IDX_debug_str, 1))
     return NULL;
 
-  return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off;
+  return (const char *) dbg_ret->sectiondata[IDX_debug_str]->d_buf + off;
 }
 INTDEF(dwarf_formstring)
index f08e0d8f57c3ea023c186428992818023a058a56..41b09e1ab6b51161a9c4ec44b4a011f03e070982 100644 (file)
@@ -52,7 +52,8 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
   Dwarf_Word offset;
   if (attr->form == DW_FORM_sec_offset)
     {
-      if (__libdw_read_offset (attr->cu->dbg, cu_sec_idx (attr->cu), attr->valp,
+      if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
+                              cu_sec_idx (attr->cu), attr->valp,
                               attr->cu->offset_size, &offset, sec_index, 0))
        return NULL;
     }
@@ -63,7 +64,8 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
       {
       case DW_FORM_data4:
       case DW_FORM_data8:
-       if (__libdw_read_offset (attr->cu->dbg, cu_sec_idx (attr->cu),
+       if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
+                                cu_sec_idx (attr->cu),
                                 attr->valp,
                                 attr->form == DW_FORM_data4 ? 4 : 8,
                                 &offset, sec_index, 0))
index 4ea3889658295382e9dde4c74d8821bc017bd7fc..12728a34385921acf9e5bd95d7d928780ce64957 100644 (file)
@@ -102,7 +102,8 @@ get_offsets (Dwarf *dbg)
        }
 
       /* Get the CU offset.  */
-      if (__libdw_read_offset (dbg, IDX_debug_pubnames, readp + 2, len_bytes,
+      if (__libdw_read_offset (dbg, dbg, IDX_debug_pubnames,
+                              readp + 2, len_bytes,
                               &mem[cnt].cu_offset, IDX_debug_info, 3))
        /* Error has been already set in reader.  */
        goto err_return;
index 77e1b31f849704876cd71ff7d837204c93605ded..da82e5d2f9989859bde671a1942b4b442f81e3e6 100644 (file)
@@ -116,6 +116,7 @@ enum
   DWARF_E_INVALID_OFFSET,
   DWARF_E_NO_DEBUG_RANGES,
   DWARF_E_INVALID_CFI,
+  DWARF_E_NO_ALT_DEBUGLINK
 };
 
 
@@ -127,6 +128,9 @@ struct Dwarf
   /* The underlying ELF file.  */
   Elf *elf;
 
+  /* dwz alternate DWARF file.  */
+  Dwarf *alt_dwarf;
+
   /* The section data.  */
   Elf_Data *sectiondata[IDX_last];
 
@@ -141,6 +145,9 @@ struct Dwarf
   /* If true, we allocated the ELF descriptor ourselves.  */
   bool free_elf;
 
+  /* If true, we allocated the Dwarf descriptor for alt_dwarf ourselves.  */
+  bool free_alt;
+
   /* Information for traversing the .debug_pubnames section.  This is
      an array and separately allocated with malloc.  */
   struct pubnames_s
@@ -580,13 +587,13 @@ __libdw_read_offset_inc (Dwarf *dbg,
 }
 
 static inline int
-__libdw_read_offset (Dwarf *dbg,
+__libdw_read_offset (Dwarf *dbg, Dwarf *dbg_ret,
                     int sec_index, const unsigned char *addr,
                     int width, Dwarf_Off *ret, int sec_ret,
                     size_t size)
 {
   READ_AND_RELOCATE (__libdw_relocate_offset, (*ret));
-  return __libdw_offset_in_section (dbg, sec_ret, *ret, size);
+  return __libdw_offset_in_section (dbg_ret, sec_ret, *ret, size);
 }
 
 static inline size_t
@@ -617,12 +624,19 @@ unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
                                 Dwarf_Off *offsetp)
   internal_function;
 
+/* Checks that the build_id of the underlying Elf matches the expected.
+   Returns zero on match, -1 on error or no build_id found or 1 when
+   build_id doesn't match.  */
+int __check_build_id (Dwarf *dw, const uint8_t *build_id, const size_t id_len)
+  internal_function;
+
 
 
 /* Aliases to avoid PLTs.  */
 INTDECL (dwarf_aggregate_size)
 INTDECL (dwarf_attr)
 INTDECL (dwarf_attr_integrate)
+INTDECL (dwarf_begin)
 INTDECL (dwarf_begin_elf)
 INTDECL (dwarf_child)
 INTDECL (dwarf_dieoffset)
index 2ff8868b1e31c39940f868b6d88c2bf7dd6402aa..c476a6e31f3225c022cc51d499ff807638673a79 100644 (file)
@@ -58,6 +58,8 @@ __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
 
     case DW_FORM_strp:
     case DW_FORM_sec_offset:
+    case DW_FORM_GNU_ref_alt:
+    case DW_FORM_GNU_strp_alt:
       result = cu->offset_size;
       break;
 
index d05bb2e36a87c6b399b8acacd0e9565a7ffd58cf..294e31b6633a3f8db3dfedb029e8bade6258a9b6 100644 (file)
@@ -1,3 +1,9 @@
+2012-06-27  Mark Wielaard  <mjw@redhat.com>
+
+       * readelf.c (dwarf_form_string): Handle DW_FORM_GNU_ref_alt and
+       DW_FORM_GNU_strp_alt.
+       (attr_callback): Likewise.
+
 2012-07-30  Petr Machata  <pmachata@redhat.com>
 
        * nm.c (show_symbols_bsd): Reorder arguments in {S,}FMTSTRS (and
index 9aaf4ece66e84da9943c6973dbafe223b150dc5e..36724a713df6151039994b6fa4bed271cc8716bd 100644 (file)
@@ -3651,6 +3651,20 @@ dwarf_form_string (unsigned int form)
 
   if (likely (form < nknown_forms))
     result = known_forms[form];
+  else
+    {
+      /* GNU extensions use vendor numbers.  */
+      switch (form)
+       {
+       case DW_FORM_GNU_ref_alt:
+         result = "GNU_ref_alt";
+         break;
+
+       case DW_FORM_GNU_strp_alt:
+         result = "GNU_strp_alt";
+         break;
+       }
+    }
 
   if (unlikely (result == NULL))
     {
@@ -5593,6 +5607,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
     case DW_FORM_indirect:
     case DW_FORM_strp:
     case DW_FORM_string:
+    case DW_FORM_GNU_strp_alt:
       if (cbargs->silent)
        break;
       const char *str = dwarf_formstring (attrp);
@@ -5608,7 +5623,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
     case DW_FORM_ref8:
     case DW_FORM_ref4:
     case DW_FORM_ref2:
-    case DW_FORM_ref1:;
+    case DW_FORM_ref1:
+    case DW_FORM_GNU_ref_alt:
       if (cbargs->silent)
        break;
       Dwarf_Die ref;
index 2291b62b8893dff175f26753a23f5dbf71041c6f..1cdd464695151be6d1b0b03ed0c8861d6db4f902 100644 (file)
@@ -1,3 +1,14 @@
+2012-06-27  Mark Wielaard  <mjw@redhat.com>
+
+       * Makefile.am (TESTS): Add run-readelf-dwz-multi.sh.
+       (EXTRA_DIST): Add run-readelf-dwz-multi.sh,
+       libtestfile_multi_shared.so.bz2, testfile_multi.dwz.bz2 and
+       testfile_multi_main.bz2.
+       * run-readelf-dwz-multi.sh: New test.
+       * libtestfile_multi_shared.so.bz2: New testfile.
+       * testfile_multi.dwz.bz2: New testifle.
+       * testfile_multi_main.bz2: New testifle.
+
 2012-08-01  Petr Machata  <pmachata@redhat.com>
 
        * run-test-archive64.sh: New test.
index d0f4e80a07d3c89339e8eac2866645cb2ca7c127..df66db6ee9f0d2c9ae94895b96f5f9af1a516561 100644 (file)
@@ -73,7 +73,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-nm-self.sh run-readelf-self.sh \
        run-readelf-test1.sh run-readelf-test2.sh run-readelf-test3.sh \
        run-readelf-test4.sh run-readelf-twofiles.sh \
-       run-readelf-macro.sh \
+       run-readelf-macro.sh run-readelf-dwz-multi.sh \
        run-native-test.sh run-bug1-test.sh \
        dwfl-bug-addr-overflow run-addrname-test.sh \
        dwfl-bug-fd-leak dwfl-bug-report \
@@ -145,6 +145,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile46.bz2 testfile47.bz2 testfile48.bz2 testfile48.debug.bz2 \
             testfile49.bz2 testfile50.bz2 testfile51.bz2 \
             run-readelf-macro.sh testfilemacro.bz2 \
+            run-readelf-dwz-multi.sh libtestfile_multi_shared.so.bz2 \
+            testfile_multi.dwz.bz2 testfile_multi_main.bz2 \
             run-prelink-addr-test.sh \
             testfile52-32.so.bz2 testfile52-32.so.debug.bz2 \
             testfile52-32.prelink.so.bz2 testfile52-32.noshdrs.so.bz2 \
diff --git a/tests/libtestfile_multi_shared.so.bz2 b/tests/libtestfile_multi_shared.so.bz2
new file mode 100755 (executable)
index 0000000..e9eb6a7
Binary files /dev/null and b/tests/libtestfile_multi_shared.so.bz2 differ
diff --git a/tests/run-readelf-dwz-multi.sh b/tests/run-readelf-dwz-multi.sh
new file mode 100755 (executable)
index 0000000..42e6aa4
--- /dev/null
@@ -0,0 +1,156 @@
+#! /bin/sh
+# Copyright (C) 2012 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# common.h
+#
+# #include <stdio.h>
+#
+# struct foobar
+# {
+#   int foo;
+#   struct foobar *bar;
+# };
+#
+# extern int call_foo(struct foobar *foobar_struct_ptr);
+
+# main.c
+#
+# #include "common.h"
+#
+# int main(int argc, char ** argv)
+# {
+#   struct foobar b;
+#   b.foo = 42;
+#   b.bar = &b;
+#
+#   return call_foo(b.bar);
+# }
+
+# shared.c
+#
+# #include "common.h"
+#
+# int call_foo(struct foobar *fb)
+# {
+#   return fb->bar->foo - 42;
+# }
+
+# gcc -fPIC -g -c -Wall shared.c
+# gcc -shared -o libtestfile_multi_shared.so shared.o
+# gcc -g -o testfile_multi_main -L. -ltestfile_multi_shared main.c -Wl,-rpath,.
+# dwz -m testfile_multi.dwz testfile_multi_main libtestfile_multi_shared.so
+
+testfiles libtestfile_multi_shared.so testfile_multi_main testfile_multi.dwz
+
+testrun_compare ../src/readelf --debug-dump=info testfile_multi_main <<\EOF
+
+DWARF section [28] '.debug_info' at offset 0x1078:
+ [Offset]
+ Compilation unit at offset 0:
+ Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
+ [     b]  compile_unit
+           producer             (strp) "GNU C 4.7.0 20120507 (Red Hat 4.7.0-5) -mtune=generic -march=x86-64 -g"
+           language             (data1) ISO C89 (1)
+           name                 (strp) "main.c"
+           comp_dir             (GNU_strp_alt) "/home/mark/src/tests/dwz"
+           low_pc               (addr) 0x00000000004006ac <main>
+           high_pc              (udata) 44
+           stmt_list            (sec_offset) 0
+ [    26]    imported_unit
+             import               (GNU_ref_alt) [     b]
+ [    2b]    pointer_type
+             byte_size            (data1) 8
+             type                 (GNU_ref_alt) [    53]
+ [    31]    subprogram
+             external             (flag_present) 
+             name                 (strp) "main"
+             decl_file            (data1) 1
+             decl_line            (data1) 3
+             prototyped           (flag_present) 
+             type                 (GNU_ref_alt) [    3e]
+             low_pc               (addr) 0x00000000004006ac <main>
+             high_pc              (udata) 44
+             frame_base           (exprloc) 
+              [   0] call_frame_cfa
+             GNU_all_tail_call_sites (flag_present) 
+             sibling              (ref_udata) [    6e]
+ [    48]      formal_parameter
+               name                 (strp) "argc"
+               decl_file            (data1) 1
+               decl_line            (data1) 3
+               type                 (GNU_ref_alt) [    3e]
+               location             (exprloc) 
+                [   0] fbreg -36
+ [    56]      formal_parameter
+               name                 (strp) "argv"
+               decl_file            (data1) 1
+               decl_line            (data1) 3
+               type                 (ref_udata) [    6e]
+               location             (exprloc) 
+                [   0] fbreg -48
+ [    61]      variable
+               name                 (string) "b"
+               decl_file            (data1) 1
+               decl_line            (data1) 5
+               type                 (GNU_ref_alt) [    5a]
+               location             (exprloc) 
+                [   0] fbreg -32
+ [    6e]    pointer_type
+             byte_size            (data1) 8
+             type                 (ref_udata) [    2b]
+EOF
+
+testrun_compare ../src/readelf --debug-dump=info libtestfile_multi_shared.so <<\EOF
+
+DWARF section [25] '.debug_info' at offset 0x106c:
+ [Offset]
+ Compilation unit at offset 0:
+ Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
+ [     b]  compile_unit
+           producer             (strp) "GNU C 4.7.0 20120507 (Red Hat 4.7.0-5) -fpreprocessed -mtune=generic -march=x86-64 -g -fPIC"
+           language             (data1) ISO C89 (1)
+           name                 (strp) "shared.c"
+           comp_dir             (GNU_strp_alt) "/home/mark/src/tests/dwz"
+           low_pc               (addr) +0x0000000000000670 <call_foo>
+           high_pc              (udata) 23
+           stmt_list            (sec_offset) 0
+ [    26]    imported_unit
+             import               (GNU_ref_alt) [     b]
+ [    2b]    subprogram
+             external             (flag_present) 
+             name                 (strp) "call_foo"
+             decl_file            (data1) 1
+             decl_line            (data1) 3
+             prototyped           (flag_present) 
+             type                 (GNU_ref_alt) [    3e]
+             low_pc               (addr) +0x0000000000000670 <call_foo>
+             high_pc              (udata) 23
+             frame_base           (exprloc) 
+              [   0] call_frame_cfa
+             GNU_all_call_sites   (flag_present) 
+ [    41]      formal_parameter
+               name                 (string) "fb"
+               decl_file            (data1) 1
+               decl_line            (data1) 3
+               type                 (GNU_ref_alt) [    76]
+               location             (exprloc) 
+                [   0] fbreg -24
+EOF
+
+exit 0
diff --git a/tests/testfile_multi.dwz.bz2 b/tests/testfile_multi.dwz.bz2
new file mode 100644 (file)
index 0000000..1f52fb6
Binary files /dev/null and b/tests/testfile_multi.dwz.bz2 differ
diff --git a/tests/testfile_multi_main.bz2 b/tests/testfile_multi_main.bz2
new file mode 100755 (executable)
index 0000000..bc6ca5f
Binary files /dev/null and b/tests/testfile_multi_main.bz2 differ