This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: Handling dwz multi debuginfo files


Hi,

This patch adds support for dwz multi debuginfo files to libdw.
Fedora is planning to use these in the next release:
https://fedoraproject.org/wiki/Features/DwarfCompressor
The new DW_FORMs are proposed for DWARF5:
http://www.dwarfstd.org/ShowIssue.php?issue=120604.1
But are currently only a GNU extension written by the dwz tool:
http://sourceware.org/git/?p=dwz.git;a=summary

libdw was already setup anticipating such a scheme, so adding support
wasn't so hard. Basically a Dwarf descriptor can now have an alternative
Dwarf descriptor that is consulted whenever one of the new DW_FROM_*alts
is seen.

dwarf_begin_elf will find the right dwz alternative to use. But this is
currently tied somewhat to how fedora implemented this. There are also
two new functions dwarf_getalt () and dwarf_addalt () that can be used
to directly manipulate the alternative Dwarf descriptor. I anticipate
those will be used by some new libdwfl callbacks if we decide those are
necessary to support other ways to get/set alternative Dwarf
descriptors.

This is only lightly tested, but some quick stap queries on rawhide
packages that already had dwz files seemed to return the right results.
I did add some small test binary files and a readelf test to show the
results. I'll add some more tests once we decide whether this is the
proper way to support this.

Please take a look at the proposed implementation and let me know
whether it looks OK or some other approach might be better. I also
pushed this to the mjw/dwz branch.

Thanks,

Mark
From 90a10eb0825035a06a0088fcc52be26ca08c7a82 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mjw@redhat.com>
Date: Fri, 22 Jun 2012 12:02:45 +0200
Subject: [PATCH] libdw: Add support for DWZ multifile forms
 DW_FORM_GNU_ref_alt/strp_alt.

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.  This alternative Dwarf descriptor can be gotten by a new
function dwarf_getalt.  And if not automatically set by dwarf_begin_elf
it can be explicitly set through dwarf_addalt. There are no user visible
changes besides these two new functions.

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>
---
 libdw/ChangeLog                                |   34 +++++
 libdw/Makefile.am                              |    1 +
 libdw/dwarf.h                                  |    5 +-
 libdw/dwarf_addalt.c                           |  100 +++++++++++++++
 libdw/dwarf_begin.c                            |    1 +
 libdw/dwarf_begin_elf.c                        |  123 +++++++++++++++++++
 libdw/dwarf_end.c                              |    4 +
 libdw/dwarf_error.c                            |    1 +
 libdw/dwarf_formref.c                          |    2 +
 libdw/dwarf_formref_die.c                      |   15 ++-
 libdw/dwarf_formstring.c                       |   15 ++-
 libdw/dwarf_formudata.c                        |    6 +-
 libdw/{dwarf_lineop_index.c => dwarf_getalt.c} |   19 ++--
 libdw/dwarf_getpubnames.c                      |    3 +-
 libdw/libdw.h                                  |   10 ++
 libdw/libdw.map                                |    6 +
 libdw/libdwP.h                                 |   18 +++-
 libdw/libdw_form.c                             |    2 +
 src/ChangeLog                                  |    6 +
 src/readelf.c                                  |   18 +++-
 tests/ChangeLog                                |   11 ++
 tests/Makefile.am                              |    6 +-
 tests/libtestfile_multi_shared.so.bz2          |  Bin 0 -> 2547 bytes
 tests/run-readelf-dwz-multi.sh                 |  156 ++++++++++++++++++++++++
 tests/testfile_multi.dwz.bz2                   |  Bin 0 -> 512 bytes
 tests/testfile_multi_main.bz2                  |  Bin 0 -> 3086 bytes
 26 files changed, 538 insertions(+), 24 deletions(-)
 create mode 100644 libdw/dwarf_addalt.c
 copy libdw/{dwarf_lineop_index.c => dwarf_getalt.c} (82%)
 create mode 100755 tests/libtestfile_multi_shared.so.bz2
 create mode 100755 tests/run-readelf-dwz-multi.sh
 create mode 100644 tests/testfile_multi.dwz.bz2
 create mode 100755 tests/testfile_multi_main.bz2

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 5a07c46..986785c 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,39 @@
 2012-06-27  Mark Wielaard  <mjw@redhat.com>
 
+	* Makefile.am (libdw_a_SOURCES): Add dwarf_getalt.c and
+	dwarf_addalt.c.
+	* dwarf.h: Add DW_FORM_GNU_ref_alt and DW_FORM_GNU_strp_alt.
+	* dwarf_addalt.c: New file.
+	* 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_getalt.c: New file.
+	* dwarf_getpubnames.c (get_offsets): Adjust __libdw_read_offset call.
+	* libdw.h (dwarf_getalt): New define.
+	(dwarf_addalt): Likewise.
+	* libdw.map (ELFUTILS_0.155): New entry.
+	* 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-06-27  Mark Wielaard  <mjw@redhat.com>
+
 	* dwarf.h: Add DW_MACRO_GNU .debug_macro type encodings.
 
 2012-06-26  Mark Wielaard  <mjw@redhat.com>
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index e1fcef0..8275003 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -45,6 +45,7 @@ include_HEADERS = dwarf.h
 pkginclude_HEADERS = libdw.h
 
 libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
+		  dwarf_getalt.c dwarf_addalt.c \
 		  dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \
 		  dwarf_error.c dwarf_nextcu.c dwarf_diename.c dwarf_offdie.c \
 		  dwarf_attr.c dwarf_formstring.c \
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index 78a553a..11210a9 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -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. */
   };
 
 
diff --git a/libdw/dwarf_addalt.c b/libdw/dwarf_addalt.c
new file mode 100644
index 0000000..d1d0ffc
--- /dev/null
+++ b/libdw/dwarf_addalt.c
@@ -0,0 +1,100 @@
+/* Add alternative Dwarf descriptor
+   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 either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+#include <string.h>
+
+#include "libdwP.h"
+
+int
+dwarf_addalt (dwarf, alt)
+     Dwarf *dwarf;
+     Dwarf *alt;
+{
+  GElf_Ehdr *ehdr;
+  GElf_Ehdr ehdr_mem;
+  Elf_Scn *scn;
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr;
+  void *build_id;
+  int id_len;
+
+  if (dwarf == NULL || alt == NULL)
+    return -1;
+
+  ehdr = gelf_getehdr (dwarf->elf, &ehdr_mem);
+  if (ehdr == NULL)
+    return -1;
+
+  scn = NULL;
+  id_len = 0;
+  build_id = NULL;
+  while (build_id == NULL && (scn = elf_nextscn (dwarf->elf, scn)) != NULL)
+    {
+
+      shdr = gelf_getshdr (scn, &shdr_mem);
+      if (shdr == NULL)
+	return -1;
+
+      const char *scnname = elf_strptr (dwarf->elf, ehdr->e_shstrndx,
+					shdr->sh_name);
+      if (scnname == NULL)
+	return -1;
+
+      if (strcmp (scnname, ".gnu_debugaltlink") == 0)
+	{
+	  Elf_Data *data = elf_getdata (scn, NULL);
+	  if (data != NULL && data->d_size != 0)
+	    {
+	      build_id = memchr (data->d_buf, '\0', data->d_size);
+	      id_len = data->d_size - (build_id - data->d_buf + 1);
+	      break;
+	    }
+	  else
+	    return -1;
+	}
+    }
+
+  if (build_id == NULL || id_len <= 0)
+    return -1;
+
+  if (__check_build_id (alt, build_id, id_len) != 0)
+    return -1;
+
+  if (dwarf->free_alt)
+    INTUSE (dwarf_end) (dwarf->alt_dwarf);
+
+  dwarf->free_alt = 0;
+  dwarf->alt_dwarf = alt;
+
+  return 0;
+}
diff --git a/libdw/dwarf_begin.c b/libdw/dwarf_begin.c
index 1f3fc3b..9f3050f 100644
--- a/libdw/dwarf_begin.c
+++ b/libdw/dwarf_begin.c
@@ -98,3 +98,4 @@ dwarf_begin (fd, cmd)
 
   return result;
 }
+INTDEF(dwarf_begin)
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 3e01800..fd95770 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -31,12 +31,17 @@
 # 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;
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index b77988f..e65314a 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -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);
     }
diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c
index 89047dc..2292914 100644
--- a/libdw/dwarf_error.c
+++ b/libdw/dwarf_error.c
@@ -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]))
 
diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c
index a2554e9..86da7ea 100644
--- a/libdw/dwarf_formref.c
+++ b/libdw/dwarf_formref.c
@@ -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;
 
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 342f6b9..f070127 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -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;
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index fe2183a..c66454e 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -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)
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index f08e0d8..41b09e1 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -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))
diff --git a/libdw/dwarf_lineop_index.c b/libdw/dwarf_getalt.c
similarity index 82%
copy from libdw/dwarf_lineop_index.c
copy to libdw/dwarf_getalt.c
index 9ea4ef4..762b8a2 100644
--- a/libdw/dwarf_lineop_index.c
+++ b/libdw/dwarf_getalt.c
@@ -1,5 +1,5 @@
-/* Return line VLIW operation index.
-   Copyright (C) 2010 Red Hat, Inc.
+/* Retrieve alternative Dwarf descriptor used.
+   Copyright (C) 2012 Red Hat, Inc.
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -30,16 +30,17 @@
 # include <config.h>
 #endif
 
+#include <stddef.h>
+
 #include "libdwP.h"
 
 
-int
-dwarf_lineop_index (Dwarf_Line *line, unsigned int *idxp)
+Dwarf *
+dwarf_getalt (dwarf)
+     Dwarf *dwarf;
 {
-  if (line == NULL)
-    return -1;
-
-  *idxp = line->op_index;
+  if (dwarf == NULL)
+    return NULL;
 
-  return 0;
+  return dwarf->alt_dwarf;
 }
diff --git a/libdw/dwarf_getpubnames.c b/libdw/dwarf_getpubnames.c
index 4ea3889..12728a3 100644
--- a/libdw/dwarf_getpubnames.c
+++ b/libdw/dwarf_getpubnames.c
@@ -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;
diff --git a/libdw/libdw.h b/libdw/libdw.h
index f5fc4e2..049c808 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -263,6 +263,16 @@ extern Elf *dwarf_getelf (Dwarf *dwarf);
 /* Release debugging handling context.  */
 extern int dwarf_end (Dwarf *dwarf);
 
+/* Get the alternative Dwarf that is used for ref_alt and strp_alt
+   forms.  Return NULL if no such alternative Dwarf has been detected
+   or set yet.  */
+extern Dwarf *dwarf_getalt (Dwarf *dwarf);
+
+/* Adds the alternative Dwarf that will be used for ref_alt and strp_alt
+   forms.  Return zero on success.  Returns -1 when the alternative Dwarf
+   is not a valid Dwarf alternative.  */
+extern int dwarf_addalt (Dwarf *dwarf, Dwarf *alt);
+
 
 /* Get the data block for the .debug_info section.  */
 extern Elf_Data *dwarf_getscn_info (Dwarf *dwarf);
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 1f71d03..a6ebe52 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -254,3 +254,9 @@ ELFUTILS_0.149 {
 
     dwfl_dwarf_line;
 } ELFUTILS_0.148;
+
+ELFUTILS_0.155 {
+  global:
+    dwarf_getalt;
+    dwarf_addalt;
+} ELFUTILS_0.148;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 77e1b31..469773a 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -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 outselves.  */
+  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)
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index 2ff8868..c476a6e 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -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;
 
diff --git a/src/ChangeLog b/src/ChangeLog
index 2928ab1..4c05b80 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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-06-26  Mark Wielaard  <mjw@redhat.com>
 
 	* readelf.c (dwarf_attr_string): Add DW_AT_GNU_macros.
diff --git a/src/readelf.c b/src/readelf.c
index eb1d469..fe2707a 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -3647,6 +3647,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))
     {
@@ -5577,6 +5591,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);
@@ -5592,7 +5607,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;
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 9b64917..fa8109b 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -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-06-26  Mark Wielaard  <mjw@redhat.com>
 
 	* run-macro-test.sh: New test.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 39e58ae..16b2aae 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -80,7 +80,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
 	run-test-flag-nobits.sh run-prelink-addr-test.sh \
 	run-dwarf-getstring.sh run-rerequest_tag.sh run-typeiter.sh \
 	run-readelf-d.sh run-unstrip-n.sh run-low_high_pc.sh \
-	run-macro-test.sh
+	run-macro-test.sh run-readelf-dwz-multi.sh
 
 if !STANDALONE
 noinst_PROGRAMS += msg_tst md5-sha1-test
@@ -159,7 +159,9 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     run-readelf-d.sh testlib_dynseg.so.bz2 \
 	     run-unstrip-n.sh testcore-rtlib.bz2 \
 	     run-low_high_pc.sh testfile_low_high_pc.bz2 \
-	     run-macro-test.sh testfile-macinfo.bz2 testfile-macros.bz2
+	     run-macro-test.sh testfile-macinfo.bz2 testfile-macros.bz2 \
+	     run-readelf-dwz-multi.sh libtestfile_multi_shared.so.bz2 \
+	     testfile_multi.dwz.bz2 testfile_multi_main.bz2
 
 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
 			      bindir=$(DESTDIR)$(bindir) \
diff --git a/tests/libtestfile_multi_shared.so.bz2 b/tests/libtestfile_multi_shared.so.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..e9eb6a70f158fae329593180807df78be30a7621
GIT binary patch
literal 2547
zcmV<P2@Li^T4*^jL0KkKSr4l)SO5t?|NsC0|NZy>|NsB@|K|Vy|M%bi{OoW=!hQdC
z``mtf`)l9`cTcU(wy1Y?*&AgYoGKjbv>k54M4Ae1O(&BG)Y?rn!Z1xXlSWN688T#K
zWB}2iWN2xi2cl>i27#tP&<25~nq<%!Gy$N~O&SA9pb!lcKq`Kcd8&I<+K*F1BSwJG
z8UWA$$)nWMO${^}4Gl6h0MHEp000004FF_m>L3A-(8vQIX`?_514c~%Xv8!P00tlf
zMt}eYMuSE`#A%~Jh#CNB82|tYO%%w0rkhjJpQ>#ql=5mc(;y8R8V^X&&^<u)G|&b>
z(V!Xt4^RNnpc-faplCESXaEfW0st8e41h8Qnlu2=G-S{Qj6*=s0Ac_%XaE3YXf$LD
zMw&DjfuII~kN^OZB+!8}G-zrwN_vk;y;I5!r1WYuWB|};^oE#C9+N-~8UPsp4FCYp
zJwfUK^#ITSXaEMSR?fro$;d+V`H6g3Kq(MXpoeO>BoJE)dJWet0SR3jtBR|XvphKO
zI_76GS&~wkCj``;OBRZ)&LJj+VV9l+;bzlcu8G3N2&TyOczieVu~TwNC7x>79GPVD
zyGu6RjbZei>?{Kz6IaGI!Ub^2Q>Kx%g&N&`FM<?%qas5xQ2LFj@-br!7gDt%LFv2I
zjBUwIN3B{-J)tSd6pY0N>GFAujH7t975f-4SD_lC0j}I2%C#C{QkQ)I$RjnV5!nD`
zC|$bJh%7Yer3p1I``S)aVqsz3&ebaRR&u?l>QQI>aWQfKe+#F1?eJUI@Mdx{F#lL5
zHyxVHm#f~xukPuRqcL1yifqVb%!o_3P~srNh?FKfUDc4$>>7~(1%Z$u8qzv}1l9=V
zC>WkO^8kP?s?(EBy{crvE58KcQcctd-{iQgPpOx88Z45Xk~VCFi?#@@jEJqw5E6a9
z$AuuLY_$qk!l0;5e~{VF0Z~4nK}*Rn?dw&zoo0S9ELO{ya@EA=L5POR<z9rDFv$ZX
z19NBq#AJbJm;{T45Q9|0SqzYp*9?SCGcX8A3?w9kgu`AygflatwFnAS23^5D>#k-;
z4)KykeUMOOf>scO%mUT0fewZe21&4;*@TTlq~HkyR6wCX%)}7jlQCV~V0Utqz(hFO
z9S%07Oq{`;(soM35RnU5f!m@$a0#^Nx2k=2Bd+M;G<;PaE-gMKUPe6{HPcA1JULCx
zjPk|RpSv3RG4sKlfWAg66(VSY`&)56>t|s|*vFz+Zhf|{>)9I6<JNJrM>P6o%K@RC
zm4rVfwiLt?sI%#1$xzT3l#S|4Nv)n<1jtc|(D*t@Ge%CyU`dt+MFzSWZZdzT-45=a
zu~U4Qo!-uN9KxYObV$lZ3+wk42E1jW>0`EP#cQnWu6Oct))JBS_Ru6iI570kWI#VS
zz+x=I4yg0%AcRd5wn74hxz|aj8`PcDAbjJ=Ng69|2ZyzAX2?SeHHGNx94BN8D?qBK
z12CPC?b_)Q)-qV2U!pp;LR;%=7zMA>*n&GY1ndBI+$m&n-p$DxNQ|c`6LU)mGjFKI
z_g0B5d+al`Va81bn$shNdX+Rw9U4tq7S{D052iB7Hg4?pYpk^+O-2M1(}9CZ1lu)>
znyq2;5-B%FG19H?<!B@uMOBR1YJnw2dQi|i4@8*d+>&}QM5H2b0<Z?Yl*lNxI)%c&
zxcj7tE?}WN_b)AV`yS<u(X=9Q0)hin$p&K?gF7Qi$R()a!0LESJe&hxZZ<lI6}X8+
zWyVUENOaFkCx?fKj-sl6gur<#z1U=CDd1jb!1gt~K3Z&SbyxqT8hO*I`+qv9kd-Z2
zFx(-j`o1h#Uyr=N8qE}o)Dbt6ZVqT^>&9KnGb}@M`daZR(OG3j7Quk3ZCtNS@tS58
z$2hlkSv_nKfj1#sTWFwVprU1tB2+6}7R!y5bvv@?I$N@%8VgmPu{-qNcRcuwd0=GW
zLQFvnkXeUeA<jy~r6&ZFN!%U?s0fwZi%x`-xXDGleUY^9yS%Pvath*W9kRqWh!<xE
z?{Lsg>@nKa1mmQ2rQC^i!#joTMS-vS;wqT>eEb>fS1<!OI|?`<HRKFtf?0cqOK!r-
znZpVrnugw)M8(3hgv3rJ1TN%wIrwTq@HdkNTSt6KT05gUufIYdSY3z!wTfR?p=E*q
zigw}1pjuji^8wc^*p6is@8b@<?}4#)-2MlQP++pMk39sUO&}f8C}&%?&dxbr#)hZY
zy!hVkLlr0v1bj{9Kx!{{V8D=MO13Cx>J{}f4I$LgIbNy5SE)o@>Y_@PkUR@&Sd_4f
z{G<bg+HILLSIYq;g+gYGExx~JnEmL8vPL8bTROD>u1r;=fK>7L=wX9%6(XfB9(-#W
z*cx9$O>ah9D3gBi$jhTCkP-#XK9~lQ#N0@nG0fUFck-gPkd;(YDEkOhLOL=JLt|2H
zDIj3NB5e#v)m+gDkge?rHbZ)Z=4i(^jyl;GWgyHpW18r$US{YA8hW!79vt-|;Brh-
z)w&qf%A-~pRj?VQGoMu|1S`DOAe<-z(l&=eqD&e~<$N`k3b}I^;&LpSOT{$_iDW+f
z2@Ch3T)I@%%L<66RAqAMks>Y0cR7;F7R0DQCY8~*3}Ty&WP!%ACWCLR<V*^hzHFwv
zC4)OPJ{}Gl<uuQXw6xzB=t|ORmE>;GSZy@$K$uj`Qr1+O1~J%ha|y<IaTcP37H-<6
zn#pmQ2@D|#kXrymLIhs=t|1iW{9)i|0sQORi@GSdC<W;;bsTAnxCMsLl8~Z8X=y~W
zo|ayb!m$eFI8%s7#3W>k*+{C0w2L>MNh{XEE(O^sDMA8)JgX6l+S=}xBtD?}c5^~e
za~*&bhTU)wM1^HoY}OP+OfM7;77Iw-Z%K<Iu{g>l1WzF~f>14h6J<G0l}B**s3r1*
z4CXf?h)x{P(2_B7pd3tsKn|GX5ETT0K#b#?`OD42E67)9iSh*08xK>V6%Ly7+lwD{
zJYgIq6WSTngxeAU<jH_P%;mpm1tlEupMkW|0qv;EO>DsFGufS0q|6=zKn{;xI)P=Y
z5<!0NW6mQS9(?vn$oc5psGiZMr%Of!ubKz7Y0CJOA*E**F2;HYnF(W%C4exZJNQ@y
zQt(B*7y}IJMlA}#6IP<FePeXmy?DEv<un_dI3{UpcdU&oCC)p1oWj9`RuU+E7!$`g
zZ@%)EfY$T7bl;{Bj6fv8ig2F$`CE(|Z6way`<0syW!;f$Di}E8U+;}iIXc$q&P2%;
z^~NW!EJZzE^GCJa)0@>-><q(>QD8N!wmIR#10(+SAp~18)ODG;n533Xud)A&xgwk>
JNC(xJECB9{je`IH

literal 0
HcmV?d00001

diff --git a/tests/run-readelf-dwz-multi.sh b/tests/run-readelf-dwz-multi.sh
new file mode 100755
index 0000000..42e6aa4
--- /dev/null
+++ b/tests/run-readelf-dwz-multi.sh
@@ -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
index 0000000000000000000000000000000000000000..1f52fb69dbec5234c45d66cef98af3c7f8646bae
GIT binary patch
literal 512
zcmV+b0{{I&T4*^jL0KkKSxEywv;YBCfB*mQ-YZ5U!(Usaix9u>|M0+oBmh7FAOJuR
z0Ra#|0{}1qj5a7iG$hpVFq&vjQJPOv6F?dO0ibBadP6~ppww!fNMbUcnwTTh!J-BP
zWXQ?15s{_{G|_-1H71iyBh=BL(?AbX)M>Q<Xa+z400099uB9x7-cEyLye7G)+g-*j
z5Cg?LftI(dTjP;Zkr2+*K!z2bvu2v|>vw7?P{A$)wBMyw%*JvWx(L$*3IsDXl+k2$
zKwCo-rl5-wI1a?wC@Z0*G#tZDi97M>@=wPl8<l#QP<%*KxNO?3g&({Da1T$`RUj-(
z=tL!HQB{`wBZIXBC{&$M6<~1ni4&M-$0V;FNa4`9NlOZ;0LOfSdDtcoOa$r77<e2I
zI!G&);RVnP$>B6aMRW|x3o^u9goHG@HeX{L&4AdTj=7MWH_i5m8>bNi@Teb1K5!T(
z<9>3~3cYmk`Yp<r2m(A9lX#KqS?&W=Vi-8Dy1J7vIG<!fUt;%$2m}%*h2*A#(imD0
zZQ&r*pJZksUX22;Oa!vBVS}qAH~dNn#yJLInel=ePuk?<MVbl(2I}f_qnzOtWH#U^
zDFiJJ<tlE-p$#e`(+-N(=nHX&+N$fwa3|`kIe#yICOp|PoLRHy{}*yaI8cyD13$FD
C)Y{Yl

literal 0
HcmV?d00001

diff --git a/tests/testfile_multi_main.bz2 b/tests/testfile_multi_main.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..bc6ca5fd21a277cc6e1f87d96177b3bfcd57a0a3
GIT binary patch
literal 3086
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

literal 0
HcmV?d00001

-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]