[9/9,libbacktrace] Add printdwarftest_dwz_cmp.sh test-case

Message ID 20181211101411.7067-10-tdevries@suse.de
State New
Headers show
Series
  • Handle .gnu_debugaltlink
Related show

Commit Message

Tom de Vries Dec. 11, 2018, 10:14 a.m.
2018-12-10  Tom de Vries  <tdevries@suse.de>

	* Makefile.am (TESTS): Add printdwarftest_dwz_cmp.sh.
	* Makefile.in: Regenerate.
	* printdwarftest.c: New file.
	* printdwarftest_dwz_cmp.sh: New file.
---
 libbacktrace/Makefile.am               |  11 ++
 libbacktrace/Makefile.in               |  75 +++++++---
 libbacktrace/printdwarftest.c          | 241 +++++++++++++++++++++++++++++++++
 libbacktrace/printdwarftest_dwz_cmp.sh |   8 ++
 4 files changed, 315 insertions(+), 20 deletions(-)
 create mode 100644 libbacktrace/printdwarftest.c
 create mode 100755 libbacktrace/printdwarftest_dwz_cmp.sh

-- 
2.16.4

Comments

Tom de Vries Jan. 17, 2019, 1:59 p.m. | #1
Hi,

now that the rest of the patch series has been committed, here's an
updated version of this patch that applies to trunk.

Thanks,
- Tom
[libbacktrace] Add printdwarftest_dwz_cmp.sh test-case

Add test-case that verifies that libbacktrace can find the same debug
information with and without dwz compression.

2018-12-10  Tom de Vries  <tdevries@suse.de>

	* Makefile.am (TESTS): Add printdwarftest_dwz_cmp.sh.
	* Makefile.in: Regenerate.
	* printdwarftest.c: New file.
	* printdwarftest_dwz_cmp.sh: New file.

---
 libbacktrace/Makefile.am               |  11 ++
 libbacktrace/Makefile.in               |  71 +++++++---
 libbacktrace/printdwarftest.c          | 241 +++++++++++++++++++++++++++++++++
 libbacktrace/printdwarftest_dwz_cmp.sh |   8 ++
 4 files changed, 313 insertions(+), 18 deletions(-)

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index bf90ebdb2d5..61dfca6256e 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -190,6 +190,17 @@ if HAVE_DWZ
 
 TESTS += btest_dwz
 
+printdwarftest.lo: dwarf.c
+
+printdwarftest_SOURCES = printdwarftest.c testlib.c
+printdwarftest_LDADD = libbacktrace.la
+
+check_PROGRAMS += printdwarftest
+
+printdwarftest_dwz_cmp.sh: printdwarftest_dwz
+
+TESTS += printdwarftest_dwz_cmp.sh
+
 endif HAVE_DWZ
 
 stest_SOURCES = stest.c
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index d55e0501171..06edf592f34 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -120,18 +120,22 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+	$(am__EXEEXT_4) $(am__EXEEXT_5)
 @NATIVE_TRUE@am__append_1 = test_elf test_xcoff_32 test_xcoff_64 \
 @NATIVE_TRUE@	test_pecoff test_unknown unittest unittest_alloc \
-@NATIVE_TRUE@	allocfail btest btest_alloc stest stest_alloc \
-@NATIVE_TRUE@	ztest ztest_alloc edtest edtest_alloc
+@NATIVE_TRUE@	allocfail btest btest_alloc
 @NATIVE_TRUE@am__append_2 = allocfail.sh
-@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = btest_dwz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_4 = -lz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_5 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_6 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_7 = dtest
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_8 = ctestg ctesta \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = btest_dwz \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	printdwarftest_dwz_cmp.sh
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_4 = printdwarftest
+@NATIVE_TRUE@am__append_5 = stest stest_alloc ztest ztest_alloc edtest \
+@NATIVE_TRUE@	edtest_alloc
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_6 = -lz
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_7 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_8 = ttest ttest_alloc
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_9 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_10 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
 subdir = .
@@ -184,13 +188,14 @@ libbacktrace_noformat_la_OBJECTS =  \
 @NATIVE_TRUE@	test_xcoff_64$(EXEEXT) test_pecoff$(EXEEXT) \
 @NATIVE_TRUE@	test_unknown$(EXEEXT) unittest$(EXEEXT) \
 @NATIVE_TRUE@	unittest_alloc$(EXEEXT) allocfail$(EXEEXT) \
-@NATIVE_TRUE@	btest$(EXEEXT) btest_alloc$(EXEEXT) \
-@NATIVE_TRUE@	stest$(EXEEXT) stest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	btest$(EXEEXT) btest_alloc$(EXEEXT)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = printdwarftest$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_3 = stest$(EXEEXT) stest_alloc$(EXEEXT) \
 @NATIVE_TRUE@	ztest$(EXEEXT) ztest_alloc$(EXEEXT) \
 @NATIVE_TRUE@	edtest$(EXEEXT) edtest_alloc$(EXEEXT)
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT) \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_4 = ttest$(EXEEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc$(EXEEXT)
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_5 =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc$(EXEEXT) \
@@ -258,6 +263,12 @@ edtest_OBJECTS = $(am_edtest_OBJECTS)
 @NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_5)
 edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
 @NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am_printdwarftest_OBJECTS =  \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	printdwarftest.$(OBJEXT) \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	testlib.$(OBJEXT)
+printdwarftest_OBJECTS = $(am_printdwarftest_OBJECTS)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_DEPENDENCIES =  \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	libbacktrace.la
 @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
 stest_OBJECTS = $(am_stest_OBJECTS)
 @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
@@ -373,8 +384,8 @@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
 	$(btest_SOURCES) $(btest_alloc_SOURCES) $(ctesta_SOURCES) \
 	$(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
 	$(ctestg_alloc_SOURCES) $(edtest_SOURCES) \
-	$(edtest_alloc_SOURCES) $(stest_SOURCES) \
-	$(stest_alloc_SOURCES) $(test_elf_SOURCES) \
+	$(edtest_alloc_SOURCES) $(printdwarftest_SOURCES) \
+	$(stest_SOURCES) $(stest_alloc_SOURCES) $(test_elf_SOURCES) \
 	$(test_pecoff_SOURCES) $(test_unknown_SOURCES) \
 	$(test_xcoff_32_SOURCES) $(test_xcoff_64_SOURCES) \
 	$(ttest_SOURCES) $(ttest_alloc_SOURCES) $(unittest_SOURCES) \
@@ -789,7 +800,7 @@ libbacktrace_la_LIBADD = \
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
 TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
-	$(am__append_7)
+	$(am__append_9)
 @NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
 @NATIVE_TRUE@	libbacktrace_noformat.la \
 @NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
@@ -828,15 +839,17 @@ TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
 @NATIVE_TRUE@btest_alloc_SOURCES = $(btest_SOURCES)
 @NATIVE_TRUE@btest_alloc_CFLAGS = $(btest_CFLAGS)
 @NATIVE_TRUE@btest_alloc_LDADD = libbacktrace_alloc.la
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_SOURCES = printdwarftest.c testlib.c
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_SOURCES = stest.c
 @NATIVE_TRUE@stest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_alloc_SOURCES = $(stest_SOURCES)
 @NATIVE_TRUE@stest_alloc_LDADD = libbacktrace_alloc.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_4) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_6) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
-@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_5) \
+@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_7) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@ztest_alloc_SOURCES = $(ztest_SOURCES)
 @NATIVE_TRUE@ztest_alloc_CFLAGS = $(ztest_CFLAGS)
@@ -1021,6 +1034,10 @@ edtest_alloc$(EXEEXT): $(edtest_alloc_OBJECTS) $(edtest_alloc_DEPENDENCIES) $(EX
 	@rm -f edtest_alloc$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(edtest_alloc_OBJECTS) $(edtest_alloc_LDADD) $(LIBS)
 
+printdwarftest$(EXEEXT): $(printdwarftest_OBJECTS) $(printdwarftest_DEPENDENCIES) $(EXTRA_printdwarftest_DEPENDENCIES) 
+	@rm -f printdwarftest$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(printdwarftest_OBJECTS) $(printdwarftest_LDADD) $(LIBS)
+
 stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) 
 	@rm -f stest$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
@@ -1487,6 +1504,13 @@ btest_alloc.log: btest_alloc$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+printdwarftest.log: printdwarftest$(EXEEXT)
+	@p='printdwarftest$(EXEEXT)'; \
+	b='printdwarftest'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 stest.log: stest$(EXEEXT)
 	@p='stest$(EXEEXT)'; \
 	b='stest'; \
@@ -1585,6 +1609,13 @@ btest_dwz.log: btest_dwz
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+printdwarftest_dwz_cmp.sh.log: printdwarftest_dwz_cmp.sh
+	@p='printdwarftest_dwz_cmp.sh'; \
+	b='printdwarftest_dwz_cmp.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 dtest.log: dtest
 	@p='dtest'; \
 	b='dtest'; \
@@ -1761,6 +1792,10 @@ uninstall-am:
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@	rm -f $@_2
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@	mv $@_1 $@
 
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest.lo: dwarf.c
+
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_dwz_cmp.sh: printdwarftest_dwz
+
 @NATIVE_TRUE@edtest2_build.c: gen_edtest2_build; @true
 @NATIVE_TRUE@gen_edtest2_build: $(srcdir)/edtest2.c
 @NATIVE_TRUE@	cat $(srcdir)/edtest2.c > tmp-edtest2_build.c
diff --git a/libbacktrace/printdwarftest.c b/libbacktrace/printdwarftest.c
new file mode 100644
index 00000000000..ba5473e4584
--- /dev/null
+++ b/libbacktrace/printdwarftest.c
@@ -0,0 +1,241 @@
+/* printdwarftest.c -- Print dwarf info cached by libbacktrace.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+/* Add all dwarf.c includes here, to make sure once-included headers are
+   included here (before defining backtrace_dwarf_add) rather than at the
+   #include "dwarf.c" below.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "dwarf2.h"
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "internal.h"
+
+#include "testlib.h"
+#include "backtrace-supported.h"
+
+/* Include dwarf.c, using dwarf.c as header file defining struct dwarf_data.
+   Rename the only external function to prevent conflict with dwarf.o.  */
+
+extern int dummy_backtrace_dwarf_add (struct backtrace_state *state,
+				      uintptr_t base_address,
+				      const unsigned char* dwarf_info,
+				      size_t dwarf_info_size,
+				      const unsigned char *dwarf_line,
+				      size_t dwarf_line_size,
+				      const unsigned char *dwarf_abbrev,
+				      size_t dwarf_abbrev_size,
+				      const unsigned char *dwarf_ranges,
+				      size_t dwarf_range_size,
+				      const unsigned char *dwarf_str,
+				      size_t dwarf_str_size,
+				      int is_bigendian,
+				      struct dwarf_data *fileline_altlink,
+				      backtrace_error_callback error_callback,
+				      void *data, fileline *fileline_fn,
+				      struct dwarf_data **fileline_entry);
+
+#define backtrace_dwarf_add dummy_backtrace_dwarf_add
+#include "dwarf.c"
+
+static void
+error_callback (void *vdata ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
+		int errnum ATTRIBUTE_UNUSED)
+{
+}
+
+static int
+dummmy_callback (void *data ATTRIBUTE_UNUSED, uintptr_t pc ATTRIBUTE_UNUSED,
+		 const char *filename ATTRIBUTE_UNUSED,
+		 int lineno ATTRIBUTE_UNUSED,
+		 const char *function ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+struct print_callback_data
+{
+  uintptr_t base_address;
+  uintptr_t pc;
+  const char *filename;
+  int lineno;
+  const char *function;
+  uintptr_t d1_pc;
+  const char *d1_filename;
+  int d1_lineno;
+  const char *d1_function;
+  int depth;
+  int stack_printed;
+  int skip;
+};
+
+static int
+print_callback (void *data, uintptr_t pc ATTRIBUTE_UNUSED,
+		const char *filename ATTRIBUTE_UNUSED,
+		int lineno ATTRIBUTE_UNUSED,
+		const char *function ATTRIBUTE_UNUSED)
+{
+  struct print_callback_data *prev = (struct print_callback_data *)data;
+
+  prev->depth++;
+  if (prev->depth == 1)
+    {
+      if (prev->stack_printed)
+	prev->skip = 1;
+    }
+  else
+    {
+      if (prev->skip)
+	return 0;
+
+      fprintf (stderr, " %s@%d", function, prev->depth);
+      fprintf (stderr, " %d", lineno);
+      prev->stack_printed = 1;
+
+      return 0;
+    }
+
+  if (function == NULL)
+    return 0;
+
+  if (prev->pc == 0)
+    {
+      fprintf (stderr, "%p", (void *)(pc - prev->base_address));
+      fprintf (stderr, " %s@%d", function, prev->depth);
+      fprintf (stderr, " %s", filename);
+      fprintf (stderr, "\n  %d", lineno);
+      fprintf (stderr, "@%p", (void *)(pc - prev->base_address));
+      goto update;
+    }
+
+  if (function != prev->function)
+    {
+      if (pc != prev->pc)
+	{
+	  fprintf (stderr, "\n");
+	  fprintf (stderr, "%p", (void *)(pc - prev->base_address));
+	  fprintf (stderr, " %s@%d", function, prev->depth);
+	}
+      else
+	fprintf (stderr, " %s@%d", function, prev->depth);
+    }
+
+  if (filename != prev->filename)
+    fprintf (stderr, " %s", filename);
+
+  if (lineno != prev->lineno)
+    {
+      prev->stack_printed = 0;
+      prev->skip = 0;
+      fprintf (stderr, "\n  %d", lineno);
+      fprintf (stderr, "@%p", (void *)(pc - prev->base_address));
+    }
+
+ update:
+  prev->pc = pc;
+  prev->filename = filename;
+  prev->lineno = lineno;
+  prev->function = function;
+  if (prev->depth == 1)
+    {
+      prev->d1_pc = pc;
+      prev->d1_filename = filename;
+      prev->d1_lineno = lineno;
+      prev->d1_function = function;
+    }
+  return 0;
+}
+
+static void
+print_dwarf_data (struct backtrace_state *state, void *data)
+{
+  struct dwarf_data *fdata;
+  unsigned int i;
+
+  fdata = (struct dwarf_data *)data;
+
+  for (i = 0; i < fdata->addrs_count; ++i)
+    {
+      struct unit_addrs *addr = &fdata->addrs[i];
+      uintptr_t pc;
+
+      struct print_callback_data tdata;
+      tdata.base_address = fdata->base_address;
+      tdata.pc = 0;
+      tdata.stack_printed = 0;
+      tdata.skip = 0;
+      for (pc = addr->low; pc < addr->high; ++pc)
+	{
+	  int found;
+	  tdata.depth = 0;
+	  dwarf_lookup_pc (state, fdata, pc, print_callback, error_callback,
+			   &tdata, &found);
+	  if (!found)
+	    fprintf (stderr, "not found: %p\n", (void *)pc);
+	}
+      if (tdata.pc != 0)
+	fprintf (stderr, "\n");
+    }
+}
+
+static void
+print_dwarf_cache (struct backtrace_state *state)
+{
+  struct dwarf_data **pp;
+
+  if (state->fileline_data == NULL)
+    backtrace_pcinfo (state, (uintptr_t)print_callback, dummmy_callback,
+		      NULL, NULL);
+
+  for (pp = (struct dwarf_data **) (void *) &state->fileline_data;
+       *pp != NULL;
+       pp = &(*pp)->next)
+    print_dwarf_data (state, *pp);
+}
+
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+				  error_callback_create, NULL);
+
+  print_dwarf_cache ((struct backtrace_state *)state);
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libbacktrace/printdwarftest_dwz_cmp.sh b/libbacktrace/printdwarftest_dwz_cmp.sh
new file mode 100755
index 00000000000..617de00ece8
--- /dev/null
+++ b/libbacktrace/printdwarftest_dwz_cmp.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+log1=printdwarftest_dwz.1.log
+log2=printdwarftest_dwz.2.log
+
+./printdwarftest 2> $log1
+./printdwarftest_dwz 2> $log2
+cmp $log1 $log2
Martin Sebor via Gcc-patches Jan. 18, 2019, 2:23 p.m. | #2
On Thu, Jan 17, 2019 at 5:59 AM Tom de Vries <tdevries@suse.de> wrote:
>

> now that the rest of the patch series has been committed, here's an

> updated version of this patch that applies to trunk.


I would much rather put dwarf_data into internal.h than to #include
"dwarf.c" from a different file.  Using #include with a .c file is
just a bad path to walk down.

Ian
Tom de Vries Jan. 19, 2019, 12:45 a.m. | #3
On 18-01-19 15:23, Ian Lance Taylor wrote:
> On Thu, Jan 17, 2019 at 5:59 AM Tom de Vries <tdevries@suse.de> wrote:

>>

>> now that the rest of the patch series has been committed, here's an

>> updated version of this patch that applies to trunk.

> 

> I would much rather put dwarf_data into internal.h than to #include

> "dwarf.c" from a different file.  Using #include with a .c file is

> just a bad path to walk down.


This version avoids the include of dwarf.c.

Does that look better?

Thanks,
- Tom
[libbacktrace] Add printdwarftest_dwz_cmp.sh test-case

Add test-case that verifies that libbacktrace can find the same debug
information with and without dwz compression.

2018-12-10  Tom de Vries  <tdevries@suse.de>

	* Makefile.am (TESTS): Add printdwarftest_dwz_cmp.sh.
	* Makefile.in: Regenerate.
	* printdwarftest.c: New file.
	* printdwarftest_dwz_cmp.sh: New file.
	* dwarf.c (struct function_vector, struct unit_addrs)
	(struct dwarf_info): Move ...
	* internal.h: ... here.

---
 libbacktrace/Makefile.am               |  11 ++
 libbacktrace/Makefile.in               |  70 ++++++++---
 libbacktrace/dwarf.c                   |  64 +---------
 libbacktrace/internal.h                |  68 +++++++++++
 libbacktrace/printdwarftest.c          | 208 +++++++++++++++++++++++++++++++++
 libbacktrace/printdwarftest_dwz_cmp.sh |   8 ++
 6 files changed, 348 insertions(+), 81 deletions(-)

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index bf90ebdb2d5..7843229304d 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -190,6 +190,15 @@ if HAVE_DWZ
 
 TESTS += btest_dwz
 
+printdwarftest_SOURCES =
+printdwarftest_LDADD = libbacktrace.la printdwarftest.lo testlib.lo
+
+check_PROGRAMS += printdwarftest
+
+printdwarftest_dwz_cmp.sh: printdwarftest_dwz
+
+TESTS += printdwarftest_dwz_cmp.sh
+
 endif HAVE_DWZ
 
 stest_SOURCES = stest.c
@@ -319,11 +328,13 @@ nounwind.lo: config.h internal.h
 pecoff.lo: config.h backtrace.h internal.h
 posix.lo: config.h backtrace.h internal.h
 print.lo: config.h backtrace.h internal.h
+printdwarftest.lo: config.h backtrace.h internal.h testlib.h
 read.lo: config.h backtrace.h internal.h
 simple.lo: config.h backtrace.h internal.h
 sort.lo: config.h backtrace.h internal.h
 stest.lo: config.h backtrace.h internal.h
 state.lo: config.h backtrace.h backtrace-supported.h internal.h
+testlib.lo: $(INCDIR)/filenames.h backtrace.h testlib.h
 unknown.lo: config.h backtrace.h internal.h
 xcoff.lo: config.h backtrace.h internal.h
 
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index d55e0501171..427a0c36161 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -120,18 +120,22 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+	$(am__EXEEXT_4) $(am__EXEEXT_5)
 @NATIVE_TRUE@am__append_1 = test_elf test_xcoff_32 test_xcoff_64 \
 @NATIVE_TRUE@	test_pecoff test_unknown unittest unittest_alloc \
-@NATIVE_TRUE@	allocfail btest btest_alloc stest stest_alloc \
-@NATIVE_TRUE@	ztest ztest_alloc edtest edtest_alloc
+@NATIVE_TRUE@	allocfail btest btest_alloc
 @NATIVE_TRUE@am__append_2 = allocfail.sh
-@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = btest_dwz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_4 = -lz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_5 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_6 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_7 = dtest
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_8 = ctestg ctesta \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = btest_dwz \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	printdwarftest_dwz_cmp.sh
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_4 = printdwarftest
+@NATIVE_TRUE@am__append_5 = stest stest_alloc ztest ztest_alloc edtest \
+@NATIVE_TRUE@	edtest_alloc
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_6 = -lz
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_7 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_8 = ttest ttest_alloc
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_9 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_10 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
 subdir = .
@@ -184,13 +188,14 @@ libbacktrace_noformat_la_OBJECTS =  \
 @NATIVE_TRUE@	test_xcoff_64$(EXEEXT) test_pecoff$(EXEEXT) \
 @NATIVE_TRUE@	test_unknown$(EXEEXT) unittest$(EXEEXT) \
 @NATIVE_TRUE@	unittest_alloc$(EXEEXT) allocfail$(EXEEXT) \
-@NATIVE_TRUE@	btest$(EXEEXT) btest_alloc$(EXEEXT) \
-@NATIVE_TRUE@	stest$(EXEEXT) stest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	btest$(EXEEXT) btest_alloc$(EXEEXT)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = printdwarftest$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_3 = stest$(EXEEXT) stest_alloc$(EXEEXT) \
 @NATIVE_TRUE@	ztest$(EXEEXT) ztest_alloc$(EXEEXT) \
 @NATIVE_TRUE@	edtest$(EXEEXT) edtest_alloc$(EXEEXT)
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT) \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_4 = ttest$(EXEEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc$(EXEEXT)
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_5 =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc$(EXEEXT) \
@@ -258,6 +263,11 @@ edtest_OBJECTS = $(am_edtest_OBJECTS)
 @NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_5)
 edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
 @NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la
+am_printdwarftest_OBJECTS =
+printdwarftest_OBJECTS = $(am_printdwarftest_OBJECTS)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_DEPENDENCIES =  \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	libbacktrace.la printdwarftest.lo \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	testlib.lo
 @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
 stest_OBJECTS = $(am_stest_OBJECTS)
 @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
@@ -373,8 +383,8 @@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
 	$(btest_SOURCES) $(btest_alloc_SOURCES) $(ctesta_SOURCES) \
 	$(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
 	$(ctestg_alloc_SOURCES) $(edtest_SOURCES) \
-	$(edtest_alloc_SOURCES) $(stest_SOURCES) \
-	$(stest_alloc_SOURCES) $(test_elf_SOURCES) \
+	$(edtest_alloc_SOURCES) $(printdwarftest_SOURCES) \
+	$(stest_SOURCES) $(stest_alloc_SOURCES) $(test_elf_SOURCES) \
 	$(test_pecoff_SOURCES) $(test_unknown_SOURCES) \
 	$(test_xcoff_32_SOURCES) $(test_xcoff_64_SOURCES) \
 	$(ttest_SOURCES) $(ttest_alloc_SOURCES) $(unittest_SOURCES) \
@@ -789,7 +799,7 @@ libbacktrace_la_LIBADD = \
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
 TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
-	$(am__append_7)
+	$(am__append_9)
 @NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
 @NATIVE_TRUE@	libbacktrace_noformat.la \
 @NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
@@ -828,15 +838,17 @@ TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
 @NATIVE_TRUE@btest_alloc_SOURCES = $(btest_SOURCES)
 @NATIVE_TRUE@btest_alloc_CFLAGS = $(btest_CFLAGS)
 @NATIVE_TRUE@btest_alloc_LDADD = libbacktrace_alloc.la
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_SOURCES = 
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_LDADD = libbacktrace.la printdwarftest.lo testlib.lo
 @NATIVE_TRUE@stest_SOURCES = stest.c
 @NATIVE_TRUE@stest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_alloc_SOURCES = $(stest_SOURCES)
 @NATIVE_TRUE@stest_alloc_LDADD = libbacktrace_alloc.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_4) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_6) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
-@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_5) \
+@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_7) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@ztest_alloc_SOURCES = $(ztest_SOURCES)
 @NATIVE_TRUE@ztest_alloc_CFLAGS = $(ztest_CFLAGS)
@@ -1021,6 +1033,10 @@ edtest_alloc$(EXEEXT): $(edtest_alloc_OBJECTS) $(edtest_alloc_DEPENDENCIES) $(EX
 	@rm -f edtest_alloc$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(edtest_alloc_OBJECTS) $(edtest_alloc_LDADD) $(LIBS)
 
+printdwarftest$(EXEEXT): $(printdwarftest_OBJECTS) $(printdwarftest_DEPENDENCIES) $(EXTRA_printdwarftest_DEPENDENCIES) 
+	@rm -f printdwarftest$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(printdwarftest_OBJECTS) $(printdwarftest_LDADD) $(LIBS)
+
 stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) 
 	@rm -f stest$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
@@ -1487,6 +1503,13 @@ btest_alloc.log: btest_alloc$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+printdwarftest.log: printdwarftest$(EXEEXT)
+	@p='printdwarftest$(EXEEXT)'; \
+	b='printdwarftest'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 stest.log: stest$(EXEEXT)
 	@p='stest$(EXEEXT)'; \
 	b='stest'; \
@@ -1585,6 +1608,13 @@ btest_dwz.log: btest_dwz
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+printdwarftest_dwz_cmp.sh.log: printdwarftest_dwz_cmp.sh
+	@p='printdwarftest_dwz_cmp.sh'; \
+	b='printdwarftest_dwz_cmp.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 dtest.log: dtest
 	@p='dtest'; \
 	b='dtest'; \
@@ -1761,6 +1791,8 @@ uninstall-am:
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@	rm -f $@_2
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@	mv $@_1 $@
 
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_dwz_cmp.sh: printdwarftest_dwz
+
 @NATIVE_TRUE@edtest2_build.c: gen_edtest2_build; @true
 @NATIVE_TRUE@gen_edtest2_build: $(srcdir)/edtest2.c
 @NATIVE_TRUE@	cat $(srcdir)/edtest2.c > tmp-edtest2_build.c
@@ -1783,11 +1815,13 @@ nounwind.lo: config.h internal.h
 pecoff.lo: config.h backtrace.h internal.h
 posix.lo: config.h backtrace.h internal.h
 print.lo: config.h backtrace.h internal.h
+printdwarftest.lo: config.h backtrace.h internal.h testlib.h
 read.lo: config.h backtrace.h internal.h
 simple.lo: config.h backtrace.h internal.h
 sort.lo: config.h backtrace.h internal.h
 stest.lo: config.h backtrace.h internal.h
 state.lo: config.h backtrace.h backtrace-supported.h internal.h
+testlib.lo: $(INCDIR)/filenames.h backtrace.h testlib.h
 unknown.lo: config.h backtrace.h internal.h
 xcoff.lo: config.h backtrace.h internal.h
 
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index aacbd3a453d..2d4d9a5ab69 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -261,16 +261,6 @@ struct function_addrs
   struct function *function;
 };
 
-/* A growable vector of function address ranges.  */
-
-struct function_vector
-{
-  /* Memory.  This is an array of struct function_addrs.  */
-  struct backtrace_vector vec;
-  /* Number of address ranges present.  */
-  size_t count;
-};
-
 /* A DWARF compilation unit.  This only holds the information we need
    to map a PC to a file and line.  */
 
@@ -322,21 +312,6 @@ struct unit
   size_t function_addrs_count;
 };
 
-/* An address range for a compilation unit.  This maps a PC value to a
-   specific compilation unit.  Note that we invert the representation
-   in DWARF: instead of listing the units and attaching a list of
-   ranges, we list the ranges and have each one point to the unit.
-   This lets us do a binary search to find the unit.  */
-
-struct unit_addrs
-{
-  /* Range is LOW <= PC < HIGH.  */
-  uint64_t low;
-  uint64_t high;
-  /* Compilation unit for this address range.  */
-  struct unit *u;
-};
-
 /* A growable vector of compilation unit address ranges.  */
 
 struct unit_addrs_vector
@@ -355,43 +330,6 @@ struct unit_vector
   size_t count;
 };
 
-/* The information we need to map a PC to a file and line.  */
-
-struct dwarf_data
-{
-  /* The data for the next file we know about.  */
-  struct dwarf_data *next;
-  /* The data for .gnu_debugaltlink.  */
-  struct dwarf_data *altlink;
-  /* The base address for this file.  */
-  uintptr_t base_address;
-  /* A sorted list of address ranges.  */
-  struct unit_addrs *addrs;
-  /* Number of address ranges in list.  */
-  size_t addrs_count;
-  /* A sorted list of units.  */
-  struct unit **units;
-  /* Number of units in the list.  */
-  size_t units_count;
-  /* The unparsed .debug_info section.  */
-  const unsigned char *dwarf_info;
-  size_t dwarf_info_size;
-  /* The unparsed .debug_line section.  */
-  const unsigned char *dwarf_line;
-  size_t dwarf_line_size;
-  /* The unparsed .debug_ranges section.  */
-  const unsigned char *dwarf_ranges;
-  size_t dwarf_ranges_size;
-  /* The unparsed .debug_str section.  */
-  const unsigned char *dwarf_str;
-  size_t dwarf_str_size;
-  /* Whether the data is big-endian or not.  */
-  int is_bigendian;
-  /* A vector used for function addresses.  We keep this here so that
-     we can grow the vector as we read more functions.  */
-  struct function_vector fvec;
-};
-
 /* Report an error for a DWARF buffer.  */
 
 static void
@@ -2809,7 +2747,7 @@ report_inlined_functions (uintptr_t pc, struct function *function,
    ERROR_CALLBACK and return 0.  Sets *FOUND to 1 if the PC is found,
    0 if not.  */
 
-static int
+int
 dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
 		 uintptr_t pc, backtrace_full_callback callback,
 		 backtrace_error_callback error_callback, void *data,
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index e8389779322..cfaf177647d 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -317,4 +317,72 @@ extern int backtrace_uncompress_zdebug (struct backtrace_state *,
 					unsigned char **uncompressed,
 					size_t *uncompressed_size);
 
+extern int dwarf_lookup_pc (struct backtrace_state *, struct dwarf_data *,
+			    uintptr_t, backtrace_full_callback,
+			    backtrace_error_callback, void *, int *);
+
+struct unit;
+
+/* An address range for a compilation unit.  This maps a PC value to a
+   specific compilation unit.  Note that we invert the representation
+   in DWARF: instead of listing the units and attaching a list of
+   ranges, we list the ranges and have each one point to the unit.
+   This lets us do a binary search to find the unit.  */
+
+struct unit_addrs
+{
+  /* Range is LOW <= PC < HIGH.  */
+  uint64_t low;
+  uint64_t high;
+  /* Compilation unit for this address range.  */
+  struct unit *u;
+};
+
+/* A growable vector of function address ranges.  */
+
+struct function_vector
+{
+  /* Memory.  This is an array of struct function_addrs.  */
+  struct backtrace_vector vec;
+  /* Number of address ranges present.  */
+  size_t count;
+};
+
+/* The information we need to map a PC to a file and line.  */
+
+struct dwarf_data
+{
+  /* The data for the next file we know about.  */
+  struct dwarf_data *next;
+  /* The data for .gnu_debugaltlink.  */
+  struct dwarf_data *altlink;
+  /* The base address for this file.  */
+  uintptr_t base_address;
+  /* A sorted list of address ranges.  */
+  struct unit_addrs *addrs;
+  /* Number of address ranges in list.  */
+  size_t addrs_count;
+  /* A sorted list of units.  */
+  struct unit **units;
+  /* Number of units in the list.  */
+  size_t units_count;
+  /* The unparsed .debug_info section.  */
+  const unsigned char *dwarf_info;
+  size_t dwarf_info_size;
+  /* The unparsed .debug_line section.  */
+  const unsigned char *dwarf_line;
+  size_t dwarf_line_size;
+  /* The unparsed .debug_ranges section.  */
+  const unsigned char *dwarf_ranges;
+  size_t dwarf_ranges_size;
+  /* The unparsed .debug_str section.  */
+  const unsigned char *dwarf_str;
+  size_t dwarf_str_size;
+  /* Whether the data is big-endian or not.  */
+  int is_bigendian;
+  /* A vector used for function addresses.  We keep this here so that
+     we can grow the vector as we read more functions.  */
+  struct function_vector fvec;
+};
+
 #endif
diff --git a/libbacktrace/printdwarftest.c b/libbacktrace/printdwarftest.c
new file mode 100644
index 00000000000..775e23d4ed3
--- /dev/null
+++ b/libbacktrace/printdwarftest.c
@@ -0,0 +1,208 @@
+/* printdwarftest.c -- Print dwarf info cached by libbacktrace.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+#include "testlib.h"
+
+static void
+error_callback (void *vdata ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
+		int errnum ATTRIBUTE_UNUSED)
+{
+}
+
+static int
+dummmy_callback (void *data ATTRIBUTE_UNUSED, uintptr_t pc ATTRIBUTE_UNUSED,
+		 const char *filename ATTRIBUTE_UNUSED,
+		 int lineno ATTRIBUTE_UNUSED,
+		 const char *function ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+struct print_callback_data
+{
+  uintptr_t base_address;
+  uintptr_t pc;
+  const char *filename;
+  int lineno;
+  const char *function;
+  uintptr_t d1_pc;
+  const char *d1_filename;
+  int d1_lineno;
+  const char *d1_function;
+  int depth;
+  int stack_printed;
+  int skip;
+};
+
+static int
+print_callback (void *data, uintptr_t pc ATTRIBUTE_UNUSED,
+		const char *filename ATTRIBUTE_UNUSED,
+		int lineno ATTRIBUTE_UNUSED,
+		const char *function ATTRIBUTE_UNUSED)
+{
+  struct print_callback_data *prev = (struct print_callback_data *)data;
+
+  prev->depth++;
+  if (prev->depth == 1)
+    {
+      if (prev->stack_printed)
+	prev->skip = 1;
+    }
+  else
+    {
+      if (prev->skip)
+	return 0;
+
+      fprintf (stderr, " %s@%d", function, prev->depth);
+      fprintf (stderr, " %d", lineno);
+      prev->stack_printed = 1;
+
+      return 0;
+    }
+
+  if (function == NULL)
+    return 0;
+
+  if (prev->pc == 0)
+    {
+      fprintf (stderr, "%p", (void *)(pc - prev->base_address));
+      fprintf (stderr, " %s@%d", function, prev->depth);
+      fprintf (stderr, " %s", filename);
+      fprintf (stderr, "\n  %d", lineno);
+      fprintf (stderr, "@%p", (void *)(pc - prev->base_address));
+      goto update;
+    }
+
+  if (function != prev->function)
+    {
+      if (pc != prev->pc)
+	{
+	  fprintf (stderr, "\n");
+	  fprintf (stderr, "%p", (void *)(pc - prev->base_address));
+	  fprintf (stderr, " %s@%d", function, prev->depth);
+	}
+      else
+	fprintf (stderr, " %s@%d", function, prev->depth);
+    }
+
+  if (filename != prev->filename)
+    fprintf (stderr, " %s", filename);
+
+  if (lineno != prev->lineno)
+    {
+      prev->stack_printed = 0;
+      prev->skip = 0;
+      fprintf (stderr, "\n  %d", lineno);
+      fprintf (stderr, "@%p", (void *)(pc - prev->base_address));
+    }
+
+ update:
+  prev->pc = pc;
+  prev->filename = filename;
+  prev->lineno = lineno;
+  prev->function = function;
+  if (prev->depth == 1)
+    {
+      prev->d1_pc = pc;
+      prev->d1_filename = filename;
+      prev->d1_lineno = lineno;
+      prev->d1_function = function;
+    }
+  return 0;
+}
+
+static void
+print_dwarf_data (struct backtrace_state *state, void *data)
+{
+  struct dwarf_data *fdata;
+  unsigned int i;
+
+  fdata = (struct dwarf_data *)data;
+
+  for (i = 0; i < fdata->addrs_count; ++i)
+    {
+      struct unit_addrs *addr = &fdata->addrs[i];
+      uintptr_t pc;
+
+      struct print_callback_data tdata;
+      tdata.base_address = fdata->base_address;
+      tdata.pc = 0;
+      tdata.stack_printed = 0;
+      tdata.skip = 0;
+      for (pc = addr->low; pc < addr->high; ++pc)
+	{
+	  int found;
+	  tdata.depth = 0;
+	  dwarf_lookup_pc (state, fdata, pc, print_callback, error_callback,
+			   &tdata, &found);
+	  if (!found)
+	    fprintf (stderr, "not found: %p\n", (void *)pc);
+	}
+      if (tdata.pc != 0)
+	fprintf (stderr, "\n");
+    }
+}
+
+static void
+print_dwarf_cache (struct backtrace_state *state)
+{
+  struct dwarf_data **pp;
+
+  if (state->fileline_data == NULL)
+    backtrace_pcinfo (state, (uintptr_t)print_callback, dummmy_callback,
+		      NULL, NULL);
+
+  for (pp = (struct dwarf_data **) (void *) &state->fileline_data;
+       *pp != NULL;
+       pp = &(*pp)->next)
+    print_dwarf_data (state, *pp);
+}
+
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  state = backtrace_create_state (argv[0], 0, error_callback_create, NULL);
+
+  print_dwarf_cache ((struct backtrace_state *)state);
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libbacktrace/printdwarftest_dwz_cmp.sh b/libbacktrace/printdwarftest_dwz_cmp.sh
new file mode 100755
index 00000000000..617de00ece8
--- /dev/null
+++ b/libbacktrace/printdwarftest_dwz_cmp.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+log1=printdwarftest_dwz.1.log
+log2=printdwarftest_dwz.2.log
+
+./printdwarftest 2> $log1
+./printdwarftest_dwz 2> $log2
+cmp $log1 $log2
Martin Sebor via Gcc-patches Jan. 19, 2019, 12:54 a.m. | #4
On Fri, Jan 18, 2019 at 4:45 PM Tom de Vries <tdevries@suse.de> wrote:
>

> On 18-01-19 15:23, Ian Lance Taylor wrote:

> > On Thu, Jan 17, 2019 at 5:59 AM Tom de Vries <tdevries@suse.de> wrote:

> >>

> >> now that the rest of the patch series has been committed, here's an

> >> updated version of this patch that applies to trunk.

> >

> > I would much rather put dwarf_data into internal.h than to #include

> > "dwarf.c" from a different file.  Using #include with a .c file is

> > just a bad path to walk down.

>

> This version avoids the include of dwarf.c.

>

> Does that look better?


> +printdwarftest_SOURCES =

> +printdwarftest_LDADD = libbacktrace.la printdwarftest.lo testlib.lo


Seems like you could write

printdwarftest_SOURCES = printdwarftest.c testlib.c
printdwarftest_LDADD = libbacktrace.la

> -static int

> +int

>  dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,


Ah, I didn't consider this.  We can't do this.  It will break code
like libsanitizer/libbacktrace/backtrace-rename.h.

Is there a way that we could run a similar test looking at the output
of readelf --debug?

Ian
Tom de Vries Jan. 22, 2019, 9:43 p.m. | #5
On 19-01-19 01:54, Ian Lance Taylor wrote:
> On Fri, Jan 18, 2019 at 4:45 PM Tom de Vries <tdevries@suse.de> wrote:

>>

>> On 18-01-19 15:23, Ian Lance Taylor wrote:

>>> On Thu, Jan 17, 2019 at 5:59 AM Tom de Vries <tdevries@suse.de> wrote:

>>>>

>>>> now that the rest of the patch series has been committed, here's an

>>>> updated version of this patch that applies to trunk.

>>>

>>> I would much rather put dwarf_data into internal.h than to #include

>>> "dwarf.c" from a different file.  Using #include with a .c file is

>>> just a bad path to walk down.

>>

>> This version avoids the include of dwarf.c.

>>

>> Does that look better?

> 

>> +printdwarftest_SOURCES =

>> +printdwarftest_LDADD = libbacktrace.la printdwarftest.lo testlib.lo

> 

> Seems like you could write

> 

> printdwarftest_SOURCES = printdwarftest.c testlib.c

> printdwarftest_LDADD = libbacktrace.la

> 


That's what I had initially, but I realized that that makes it harder to
keep dependencies correct.  That is, now I've added the dependencies:
...
+printdwarftest.lo: config.h backtrace.h internal.h testlib.h
+testlib.lo: $(INCDIR)/filenames.h backtrace.h testlib.h
...
and that works for "printdwarftest_LDADD = ... printdwarftest.lo
testlib.lo".

When doing this instead:
...
printdwarftest_SOURCES = printdwarftest.c testlib.c
printdwarftest_LDADD = libbacktrace.la
...
no printdwarftest.lo or testlib.lo is generated.

So, I could rewrite the dependencies to:
...
+printdwarftest.o: config.h backtrace.h internal.h testlib.h
+printdwarftest.obj: config.h backtrace.h internal.h testlib.h
+testlib.o: $(INCDIR)/filenames.h backtrace.h testlib.h
+testlib.obj: $(INCDIR)/filenames.h backtrace.h testlib.h
...
but that looks somewhat fragile, because when adding:
...
+printdwarftest_CFLAGS = -fno-tree-tail-merge
...
we need to rewrite the dependencies to:
...
+printdwarftest-printdwarftest.o: config.h backtrace.h internal.h testlib.h
+printdwarftest-printdwarftest.obj: config.h backtrace.h internal.h
testlib.h
+printdwarftest-testlib.o: $(INCDIR)/filenames.h backtrace.h testlib.h
+printdwarftest-testlib.obj: $(INCDIR)/filenames.h backtrace.h testlib.h
...

>> -static int

>> +int

>>  dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,

> 

> Ah, I didn't consider this.  We can't do this.  It will break code

> like libsanitizer/libbacktrace/backtrace-rename.h.

> 

> Is there a way that we could run a similar test looking at the output

> of readelf --debug?


No, not really. We're not interested in the contents of the debug
information as such. We're interested in the representation of that
information that libbacktrace builds from it, and the test compares that
representation with and without dwz, to make sure no information got
lost (which could indicate a dwz bug, or a lacking feature in libbacktrace).

With a normal backtrace test, you just ask for information about a
couple of locations.  With this test, you ask for all the information,
giving libbacktrace a probing you just can't get with a normal test, so
I think it's a good idea to have it.

What is an acceptable way to proceed here? I could add a
libbacktrace_nodwarf.la, and have the test-case add a -DFOR_TESTING or
some such when compiling dwarf.c, and add the necessary handling in
dwarf.c conditional on FOR_TESTING. WDYT?

Thanks,
- Tom
Ian Lance Taylor Jan. 29, 2019, 3:28 p.m. | #6
On Tue, Jan 22, 2019 at 1:43 PM Tom de Vries <tdevries@suse.de> wrote:
>

> What is an acceptable way to proceed here? I could add a

> libbacktrace_nodwarf.la, and have the test-case add a -DFOR_TESTING or

> some such when compiling dwarf.c, and add the necessary handling in

> dwarf.c conditional on FOR_TESTING. WDYT?


I guess we could try it.

I'm very seriously concerned with the additional complexity being
added to this package.  It has to live in a very constrained space and
it's already complex.  Sacrificing maintainability for testing is a
bad tradeoff in the long run.  But we can try it.

Ian

Patch

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 497cc2f5c97..f270cf16833 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -167,6 +167,17 @@  if HAVE_DWZ
 
 TESTS += btest_dwz
 
+printdwarftest.lo: dwarf.c
+
+printdwarftest_SOURCES = printdwarftest.c testlib.c
+printdwarftest_LDADD = libbacktrace.la
+
+check_PROGRAMS += printdwarftest
+
+printdwarftest_dwz_cmp.sh: printdwarftest_dwz
+
+TESTS += printdwarftest_dwz_cmp.sh
+
 endif HAVE_DWZ
 
 stest_SOURCES = stest.c
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 0abfcb42460..d5cc8e958c4 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -120,17 +120,21 @@  POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+	$(am__EXEEXT_4) $(am__EXEEXT_5)
 @NATIVE_TRUE@am__append_1 = test_elf test_xcoff_32 test_xcoff_64 \
 @NATIVE_TRUE@	test_pecoff test_unknown unittest unittest_alloc \
-@NATIVE_TRUE@	btest btest_alloc stest stest_alloc ztest \
-@NATIVE_TRUE@	ztest_alloc edtest edtest_alloc
-@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_2 = btest_dwz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_3 = -lz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_4 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_5 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_6 = dtest
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_7 = ctestg ctesta \
+@NATIVE_TRUE@	btest btest_alloc
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_2 = btest_dwz \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	printdwarftest_dwz_cmp.sh
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = printdwarftest
+@NATIVE_TRUE@am__append_4 = stest stest_alloc ztest ztest_alloc edtest \
+@NATIVE_TRUE@	edtest_alloc
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_5 = -lz
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_6 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_7 = ttest ttest_alloc
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_8 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_9 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
 subdir = .
@@ -178,13 +182,14 @@  libbacktrace_noformat_la_OBJECTS =  \
 @NATIVE_TRUE@	test_xcoff_64$(EXEEXT) test_pecoff$(EXEEXT) \
 @NATIVE_TRUE@	test_unknown$(EXEEXT) unittest$(EXEEXT) \
 @NATIVE_TRUE@	unittest_alloc$(EXEEXT) btest$(EXEEXT) \
-@NATIVE_TRUE@	btest_alloc$(EXEEXT) stest$(EXEEXT) \
-@NATIVE_TRUE@	stest_alloc$(EXEEXT) ztest$(EXEEXT) \
-@NATIVE_TRUE@	ztest_alloc$(EXEEXT) edtest$(EXEEXT) \
-@NATIVE_TRUE@	edtest_alloc$(EXEEXT)
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT) \
+@NATIVE_TRUE@	btest_alloc$(EXEEXT)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = printdwarftest$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_3 = stest$(EXEEXT) stest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	ztest$(EXEEXT) ztest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	edtest$(EXEEXT) edtest_alloc$(EXEEXT)
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_4 = ttest$(EXEEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc$(EXEEXT)
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_5 =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc$(EXEEXT) \
@@ -247,6 +252,12 @@  edtest_OBJECTS = $(am_edtest_OBJECTS)
 @NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_5)
 edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
 @NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am_printdwarftest_OBJECTS =  \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	printdwarftest.$(OBJEXT) \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	testlib.$(OBJEXT)
+printdwarftest_OBJECTS = $(am_printdwarftest_OBJECTS)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_DEPENDENCIES =  \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@	libbacktrace.la
 @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
 stest_OBJECTS = $(am_stest_OBJECTS)
 @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
@@ -361,8 +372,8 @@  SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
 	$(btest_alloc_SOURCES) $(ctesta_SOURCES) \
 	$(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
 	$(ctestg_alloc_SOURCES) $(edtest_SOURCES) \
-	$(edtest_alloc_SOURCES) $(stest_SOURCES) \
-	$(stest_alloc_SOURCES) $(test_elf_SOURCES) \
+	$(edtest_alloc_SOURCES) $(printdwarftest_SOURCES) \
+	$(stest_SOURCES) $(stest_alloc_SOURCES) $(test_elf_SOURCES) \
 	$(test_pecoff_SOURCES) $(test_unknown_SOURCES) \
 	$(test_xcoff_32_SOURCES) $(test_xcoff_64_SOURCES) \
 	$(ttest_SOURCES) $(ttest_alloc_SOURCES) $(unittest_SOURCES) \
@@ -776,7 +787,7 @@  libbacktrace_la_LIBADD = \
 	$(ALLOC_FILE)
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
-TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_6)
+TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_8)
 @NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
 @NATIVE_TRUE@	libbacktrace_noformat.la
 @NATIVE_TRUE@libbacktrace_alloc_la_SOURCES = $(libbacktrace_la_SOURCES)
@@ -805,15 +816,17 @@  TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_6)
 @NATIVE_TRUE@btest_alloc_SOURCES = $(btest_SOURCES)
 @NATIVE_TRUE@btest_alloc_CFLAGS = $(btest_CFLAGS)
 @NATIVE_TRUE@btest_alloc_LDADD = libbacktrace_alloc.la
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_SOURCES = printdwarftest.c testlib.c
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_SOURCES = stest.c
 @NATIVE_TRUE@stest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_alloc_SOURCES = $(stest_SOURCES)
 @NATIVE_TRUE@stest_alloc_LDADD = libbacktrace_alloc.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_3) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_5) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
-@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_4) \
+@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_6) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@ztest_alloc_SOURCES = $(ztest_SOURCES)
 @NATIVE_TRUE@ztest_alloc_CFLAGS = $(ztest_CFLAGS)
@@ -991,6 +1004,10 @@  edtest_alloc$(EXEEXT): $(edtest_alloc_OBJECTS) $(edtest_alloc_DEPENDENCIES) $(EX
 	@rm -f edtest_alloc$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(edtest_alloc_OBJECTS) $(edtest_alloc_LDADD) $(LIBS)
 
+printdwarftest$(EXEEXT): $(printdwarftest_OBJECTS) $(printdwarftest_DEPENDENCIES) $(EXTRA_printdwarftest_DEPENDENCIES) 
+	@rm -f printdwarftest$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(printdwarftest_OBJECTS) $(printdwarftest_LDADD) $(LIBS)
+
 stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) 
 	@rm -f stest$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
@@ -1450,6 +1467,13 @@  btest_alloc.log: btest_alloc$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+printdwarftest.log: printdwarftest$(EXEEXT)
+	@p='printdwarftest$(EXEEXT)'; \
+	b='printdwarftest'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 stest.log: stest$(EXEEXT)
 	@p='stest$(EXEEXT)'; \
 	b='stest'; \
@@ -1541,6 +1565,13 @@  btest_dwz.log: btest_dwz
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+printdwarftest_dwz_cmp.sh.log: printdwarftest_dwz_cmp.sh
+	@p='printdwarftest_dwz_cmp.sh'; \
+	b='printdwarftest_dwz_cmp.sh'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 dtest.log: dtest
 	@p='dtest'; \
 	b='dtest'; \
@@ -1710,6 +1741,10 @@  uninstall-am:
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@	cp $< $@_2
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@	$(DWZ) -m $@_common.debug $@ $@_2
 
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest.lo: dwarf.c
+
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@printdwarftest_dwz_cmp.sh: printdwarftest_dwz
+
 @NATIVE_TRUE@edtest2_build.c: gen_edtest2_build; @true
 @NATIVE_TRUE@gen_edtest2_build: $(srcdir)/edtest2.c
 @NATIVE_TRUE@	cat $(srcdir)/edtest2.c > tmp-edtest2_build.c
diff --git a/libbacktrace/printdwarftest.c b/libbacktrace/printdwarftest.c
new file mode 100644
index 00000000000..f4fea4c09d6
--- /dev/null
+++ b/libbacktrace/printdwarftest.c
@@ -0,0 +1,241 @@ 
+/* printdwarftest.c -- Print dwarf info cached by libbacktrace.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+/* Add all dwarf.c includes here, to make sure once-included headers are
+   included here (before defining backtrace_dwarf_add) rather than at the
+   #include "dwarf.c" below.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "dwarf2.h"
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "internal.h"
+
+#include "testlib.h"
+#include "backtrace-supported.h"
+
+/* Include dwarf.c, using dwarf.c as header file defining struct dwarf_data.
+   Rename the only external function to prevent conflict with dwarf.o.  */
+
+extern int dummy_backtrace_dwarf_add (struct backtrace_state *state,
+				      uintptr_t base_address,
+				      const unsigned char* dwarf_info,
+				      size_t dwarf_info_size,
+				      const unsigned char *dwarf_line,
+				      size_t dwarf_line_size,
+				      const unsigned char *dwarf_abbrev,
+				      size_t dwarf_abbrev_size,
+				      const unsigned char *dwarf_ranges,
+				      size_t dwarf_range_size,
+				      const unsigned char *dwarf_str,
+				      size_t dwarf_str_size,
+				      int is_bigendian,
+				      backtrace_error_callback error_callback,
+				      void *data, fileline *fileline_fn,
+				      void **fileline_entry,
+				      void *fileline_altlink);
+
+#define backtrace_dwarf_add dummy_backtrace_dwarf_add
+#include "dwarf.c"
+
+static void
+error_callback (void *vdata ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
+		int errnum ATTRIBUTE_UNUSED)
+{
+}
+
+static int
+dummmy_callback (void *data ATTRIBUTE_UNUSED, uintptr_t pc ATTRIBUTE_UNUSED,
+		 const char *filename ATTRIBUTE_UNUSED,
+		 int lineno ATTRIBUTE_UNUSED,
+		 const char *function ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+struct print_callback_data
+{
+  uintptr_t base_address;
+  uintptr_t pc;
+  const char *filename;
+  int lineno;
+  const char *function;
+  uintptr_t d1_pc;
+  const char *d1_filename;
+  int d1_lineno;
+  const char *d1_function;
+  int depth;
+  int stack_printed;
+  int skip;
+};
+
+static int
+print_callback (void *data, uintptr_t pc ATTRIBUTE_UNUSED,
+		const char *filename ATTRIBUTE_UNUSED,
+		int lineno ATTRIBUTE_UNUSED,
+		const char *function ATTRIBUTE_UNUSED)
+{
+  struct print_callback_data *prev = (struct print_callback_data *)data;
+
+  prev->depth++;
+  if (prev->depth == 1)
+    {
+      if (prev->stack_printed)
+	prev->skip = 1;
+    }
+  else
+    {
+      if (prev->skip)
+	return 0;
+
+      fprintf (stderr, " %s@%d", function, prev->depth);
+      fprintf (stderr, " %d", lineno);
+      prev->stack_printed = 1;
+
+      return 0;
+    }
+
+  if (function == NULL)
+    return 0;
+
+  if (prev->pc == 0)
+    {
+      fprintf (stderr, "%p", (void *)(pc - prev->base_address));
+      fprintf (stderr, " %s@%d", function, prev->depth);
+      fprintf (stderr, " %s", filename);
+      fprintf (stderr, "\n  %d", lineno);
+      fprintf (stderr, "@%p", (void *)(pc - prev->base_address));
+      goto update;
+    }
+
+  if (function != prev->function)
+    {
+      if (pc != prev->pc)
+	{
+	  fprintf (stderr, "\n");
+	  fprintf (stderr, "%p", (void *)(pc - prev->base_address));
+	  fprintf (stderr, " %s@%d", function, prev->depth);
+	}
+      else
+	fprintf (stderr, " %s@%d", function, prev->depth);
+    }
+
+  if (filename != prev->filename)
+    fprintf (stderr, " %s", filename);
+
+  if (lineno != prev->lineno)
+    {
+      prev->stack_printed = 0;
+      prev->skip = 0;
+      fprintf (stderr, "\n  %d", lineno);
+      fprintf (stderr, "@%p", (void *)(pc - prev->base_address));
+    }
+
+ update:
+  prev->pc = pc;
+  prev->filename = filename;
+  prev->lineno = lineno;
+  prev->function = function;
+  if (prev->depth == 1)
+    {
+      prev->d1_pc = pc;
+      prev->d1_filename = filename;
+      prev->d1_lineno = lineno;
+      prev->d1_function = function;
+    }
+  return 0;
+}
+
+static void
+print_dwarf_data (struct backtrace_state *state, void *data)
+{
+  struct dwarf_data *fdata;
+  unsigned int i;
+
+  fdata = (struct dwarf_data *)data;
+
+  for (i = 0; i < fdata->addrs_count; ++i)
+    {
+      struct unit_addrs *addr = &fdata->addrs[i];
+      uintptr_t pc;
+
+      struct print_callback_data tdata;
+      tdata.base_address = fdata->base_address;
+      tdata.pc = 0;
+      tdata.stack_printed = 0;
+      tdata.skip = 0;
+      for (pc = addr->low; pc < addr->high; ++pc)
+	{
+	  int found;
+	  tdata.depth = 0;
+	  dwarf_lookup_pc (state, fdata, pc, print_callback, error_callback,
+			   &tdata, &found);
+	  if (!found)
+	    fprintf (stderr, "not found: %p\n", (void *)pc);
+	}
+      if (tdata.pc != 0)
+	fprintf (stderr, "\n");
+    }
+}
+
+static void
+print_dwarf_cache (struct backtrace_state *state)
+{
+  struct dwarf_data **pp;
+
+  if (state->fileline_data == NULL)
+    backtrace_pcinfo (state, (uintptr_t)print_callback, dummmy_callback,
+		      NULL, NULL);
+
+  for (pp = (struct dwarf_data **) (void *) &state->fileline_data;
+       *pp != NULL;
+       pp = &(*pp)->next)
+    print_dwarf_data (state, *pp);
+}
+
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+				  error_callback_create, NULL);
+
+  print_dwarf_cache ((struct backtrace_state *)state);
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libbacktrace/printdwarftest_dwz_cmp.sh b/libbacktrace/printdwarftest_dwz_cmp.sh
new file mode 100755
index 00000000000..617de00ece8
--- /dev/null
+++ b/libbacktrace/printdwarftest_dwz_cmp.sh
@@ -0,0 +1,8 @@ 
+#!/bin/sh
+
+log1=printdwarftest_dwz.1.log
+log2=printdwarftest_dwz.2.log
+
+./printdwarftest 2> $log1
+./printdwarftest_dwz 2> $log2
+cmp $log1 $log2