This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][libbacktrace] Handle DW_FORM_GNU_strp_alt
- From: Tom de Vries <tdevries at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Cc: Ian Lance Taylor <ian at airs dot com>, Jakub Jelinek <jakub at redhat dot com>, Richard Biener <rguenther at suse dot de>
- Date: Tue, 13 Nov 2018 14:42:47 +0100
- Subject: [PATCH][libbacktrace] Handle DW_FORM_GNU_strp_alt
Hi,
The dwz tool attempts to optimize DWARF debugging information contained in ELF
shared libraries and ELF executables for size.
With the dwz -m option, it attempts to optimize by moving DWARF debugging
information entries (DIEs), strings and macro descriptions duplicated in
more than one object into a newly created ELF ET_REL object whose filename is
given as -m option argument. The debug sections in the executables and
shared libraries specified on the command line are then modified again,
referring to the entities in the newly created object.
After a dwz invocation:
...
$ dwz -m c.debug a.out b.out
...
both a.out and b.out contain a .gnu_debugaltlink section referring to c.debug,
and use "DWZ DWARF multifile extensions" such as DW_FORM_GNU_strp_alt and
DW_FORM_GNU_ref_alt refer to the content of c.debug.
The .gnu_debugaltlink consists of a filename and the expected buildid.
This patch adds to libbacktrace:
- finding a file matching the .gnu_debugaltlink filename
- verifying the .gnu_debugaltlink buildid
- reading the dwarf of the .gnu_debugaltlink
- support for FORM_GNU_strp_alt
- a testcase btest_dwz.c, which is btest.c minimized to the point that it only
requires FORM_GNU_strp_alt.
Bootstrapped and reg-tested on x86_64.
OK for trunk?
Thanks,
- Tom
[libbacktrace] Handle DW_FORM_GNU_strp_alt
2018-11-11 Tom de Vries <tdevries@suse.de>
* dwarf.c (struct dwarf_data): Add altlink field.
(read_attribute): Add altlink parameter. Handle DW_FORM_GNU_strp_alt
using altlink.
(find_address_ranges, build_address_map, build_dwarf_data): Add and
handle altlink parameter.
(read_referenced_name, read_function_entry): Add argument to
read_attribute call.
(backtrace_dwarf_add): Add and handle fileline_entry and
fileline_altlink parameters.
* elf.c (elf_open_debugfile_by_debugaltlink): New function.
(elf_add): Add and handle fileline_entry, with_buildid_data and
with_buildid_size parameters. Handle .gnu_debugaltlink section.
(phdr_callback, backtrace_initialize): Add arguments to elf_add calls.
* internal.h (backtrace_dwarf_add): Add fileline_entry and
fileline_altlink parameters.
* configure.ac (DWZ): Set with AC_CHECK_PROG.
(HAVE_DWZ): Set with AM_CONDITIONAL.
* configure: Regenerate.
* Makefile.am (check_PROGRAMS): Add btest_dwz.
(TESTS): Add btest_dwz_2 and btest_dwz_3.
* Makefile.in: Regenerate.
* btest_dwz.c: New file.
---
libbacktrace/Makefile.am | 22 +++++
libbacktrace/Makefile.in | 95 ++++++++++++++++---
libbacktrace/btest_dwz.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++
libbacktrace/configure | 57 ++++++++++-
libbacktrace/configure.ac | 3 +
libbacktrace/dwarf.c | 50 +++++++---
libbacktrace/elf.c | 120 +++++++++++++++++++++--
libbacktrace/internal.h | 4 +-
8 files changed, 548 insertions(+), 40 deletions(-)
diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 3c1bd49dd7b..2fec9bbb4b6 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -96,6 +96,28 @@ btest_LDADD = libbacktrace.la
check_PROGRAMS += btest
+if HAVE_DWZ
+
+btest_dwz_SOURCES = btest_dwz.c testlib.c
+btest_dwz_CFLAGS = $(AM_CFLAGS) -g -O0
+btest_dwz_LDADD = libbacktrace.la
+
+check_PROGRAMS += btest_dwz
+
+TESTS += btest_dwz_2 btest_dwz_3
+
+btest_dwz_2 btest_dwz_3: btest_dwz_23
+
+.PHONY: btest_dwz_23
+
+btest_dwz_23: btest_dwz
+ rm -f btest_dwz.debug
+ cp btest_dwz btest_dwz_2
+ cp btest_dwz btest_dwz_3
+ $(DWZ) -m btest_dwz.debug btest_dwz_2 btest_dwz_3
+
+endif HAVE_DWZ
+
stest_SOURCES = stest.c
stest_LDADD = libbacktrace.la
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 60a9d887dba..b3e9b9a4eec 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -120,12 +120,16 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
-@NATIVE_TRUE@am__append_1 = btest stest ztest edtest
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_2 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_3 = ttest
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_4 = dtest
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_5 = ctestg ctesta
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ $(am__EXEEXT_4) $(am__EXEEXT_5)
+@NATIVE_TRUE@am__append_1 = btest
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_2 = btest_dwz
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = btest_dwz_2 btest_dwz_3
+@NATIVE_TRUE@am__append_4 = stest ztest edtest
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_5 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_6 = ttest
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_7 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_8 = ctestg ctesta
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/cet.m4 \
@@ -158,10 +162,12 @@ AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
-@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) \
-@NATIVE_TRUE@ ztest$(EXEEXT) edtest$(EXEEXT)
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT)
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 = \
+@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = btest_dwz$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_3 = stest$(EXEEXT) ztest$(EXEEXT) \
+@NATIVE_TRUE@ edtest$(EXEEXT)
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_4 = ttest$(EXEEXT)
+@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)
@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
@@ -171,6 +177,14 @@ btest_OBJECTS = $(am_btest_OBJECTS)
btest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am_btest_dwz_OBJECTS = \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@ btest_dwz-btest_dwz.$(OBJEXT) \
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@ btest_dwz-testlib.$(OBJEXT)
+btest_dwz_OBJECTS = $(am_btest_dwz_OBJECTS)
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz_DEPENDENCIES = libbacktrace.la
+btest_dwz_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(btest_dwz_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctesta_OBJECTS = ctesta-btest.$(OBJEXT) \
@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta-testlib.$(OBJEXT)
ctesta_OBJECTS = $(am_ctesta_OBJECTS)
@@ -244,9 +258,9 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
- $(btest_SOURCES) $(ctesta_SOURCES) $(ctestg_SOURCES) \
- $(edtest_SOURCES) $(stest_SOURCES) $(ttest_SOURCES) \
- $(ztest_SOURCES)
+ $(btest_SOURCES) $(btest_dwz_SOURCES) $(ctesta_SOURCES) \
+ $(ctestg_SOURCES) $(edtest_SOURCES) $(stest_SOURCES) \
+ $(ttest_SOURCES) $(ztest_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -500,6 +514,7 @@ CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
+DWZ = @DWZ@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
@@ -654,15 +669,18 @@ libbacktrace_la_LIBADD = \
$(ALLOC_FILE)
libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
-TESTS = $(check_PROGRAMS) $(am__append_4)
+TESTS = $(check_PROGRAMS) $(am__append_3) $(am__append_7)
@NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
@NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
@NATIVE_TRUE@btest_LDADD = libbacktrace.la
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz_SOURCES = btest_dwz.c testlib.c
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz_CFLAGS = $(AM_CFLAGS) -g -O0
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz_LDADD = libbacktrace.la
@NATIVE_TRUE@stest_SOURCES = stest.c
@NATIVE_TRUE@stest_LDADD = libbacktrace.la
@NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
@NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_2) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_5) \
@NATIVE_TRUE@ $(CLOCK_GETTIME_LINK)
@NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c
@NATIVE_TRUE@edtest_LDADD = libbacktrace.la
@@ -780,6 +798,10 @@ btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIE
@rm -f btest$(EXEEXT)
$(AM_V_CCLD)$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
+btest_dwz$(EXEEXT): $(btest_dwz_OBJECTS) $(btest_dwz_DEPENDENCIES) $(EXTRA_btest_dwz_DEPENDENCIES)
+ @rm -f btest_dwz$(EXEEXT)
+ $(AM_V_CCLD)$(btest_dwz_LINK) $(btest_dwz_OBJECTS) $(btest_dwz_LDADD) $(LIBS)
+
ctesta$(EXEEXT): $(ctesta_OBJECTS) $(ctesta_DEPENDENCIES) $(EXTRA_ctesta_DEPENDENCIES)
@rm -f ctesta$(EXEEXT)
$(AM_V_CCLD)$(ctesta_LINK) $(ctesta_OBJECTS) $(ctesta_LDADD) $(LIBS)
@@ -831,6 +853,18 @@ btest-testlib.o: testlib.c
btest-testlib.obj: testlib.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+btest_dwz-btest_dwz.o: btest_dwz.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_dwz_CFLAGS) $(CFLAGS) -c -o btest_dwz-btest_dwz.o `test -f 'btest_dwz.c' || echo '$(srcdir)/'`btest_dwz.c
+
+btest_dwz-btest_dwz.obj: btest_dwz.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_dwz_CFLAGS) $(CFLAGS) -c -o btest_dwz-btest_dwz.obj `if test -f 'btest_dwz.c'; then $(CYGPATH_W) 'btest_dwz.c'; else $(CYGPATH_W) '$(srcdir)/btest_dwz.c'; fi`
+
+btest_dwz-testlib.o: testlib.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_dwz_CFLAGS) $(CFLAGS) -c -o btest_dwz-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+btest_dwz-testlib.obj: testlib.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_dwz_CFLAGS) $(CFLAGS) -c -o btest_dwz-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
ctesta-btest.o: btest.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
@@ -1095,6 +1129,13 @@ btest.log: btest$(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)
+btest_dwz.log: btest_dwz$(EXEEXT)
+ @p='btest_dwz$(EXEEXT)'; \
+ b='btest_dwz'; \
+ $(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'; \
@@ -1137,6 +1178,20 @@ ctesta.log: ctesta$(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)
+btest_dwz_2.log: btest_dwz_2
+ @p='btest_dwz_2'; \
+ b='btest_dwz_2'; \
+ $(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)
+btest_dwz_3.log: btest_dwz_3
+ @p='btest_dwz_3'; \
+ b='btest_dwz_3'; \
+ $(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'; \
@@ -1292,6 +1347,16 @@ uninstall-am:
.PRECIOUS: Makefile
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz_2 btest_dwz_3: btest_dwz_23
+
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@.PHONY: btest_dwz_23
+
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz_23: btest_dwz
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@ rm -f btest_dwz.debug
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@ cp btest_dwz btest_dwz_2
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@ cp btest_dwz btest_dwz_3
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@ $(DWZ) -m btest_dwz.debug btest_dwz_2 btest_dwz_3
+
@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/btest_dwz.c b/libbacktrace/btest_dwz.c
new file mode 100644
index 00000000000..bda6c75cb98
--- /dev/null
+++ b/libbacktrace/btest_dwz.c
@@ -0,0 +1,237 @@
+/* btest.c -- Test for libbacktrace library
+ Copyright (C) 2012-2018 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Google.
+
+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. */
+
+/* This program tests the externally visible interfaces of the
+ libbacktrace library. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "filenames.h"
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+
+#include "testlib.h"
+
+#define FILE "btest_dwz.c"
+
+/* Test the backtrace_simple function with non-inlined functions. */
+
+static int test3 (void) __attribute__ ((noinline, unused));
+static int f22 (int) __attribute__ ((noinline));
+static int f23 (int, int) __attribute__ ((noinline));
+
+static int
+test3 (void)
+{
+ return f22 (__LINE__) + 1;
+}
+
+static int
+f22 (int f1line)
+{
+ return f23 (f1line, __LINE__) + 2;
+}
+
+static int
+f23 (int f1line, int f2line)
+{
+ uintptr_t addrs[20];
+ struct sdata data;
+ int f3line;
+ int i;
+
+ data.addrs = &addrs[0];
+ data.index = 0;
+ data.max = 20;
+ data.failed = 0;
+
+ f3line = __LINE__ + 1;
+ i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
+
+ if (i != 0)
+ {
+ fprintf (stderr, "test3: unexpected return value %d\n", i);
+ data.failed = 1;
+ }
+
+ if (!data.failed)
+ {
+ struct info all[20];
+ struct bdata bdata;
+ int j;
+
+ bdata.all = &all[0];
+ bdata.index = 0;
+ bdata.max = 20;
+ bdata.failed = 0;
+
+ for (j = 0; j < 3; ++j)
+ {
+ i = backtrace_pcinfo (state, addrs[j], callback_one,
+ error_callback_one, &bdata);
+ if (i != 0)
+ {
+ fprintf (stderr,
+ ("test3: unexpected return value "
+ "from backtrace_pcinfo %d\n"),
+ i);
+ bdata.failed = 1;
+ }
+ if (!bdata.failed && bdata.index != (size_t) (j + 1))
+ {
+ fprintf (stderr,
+ ("wrong number of calls from backtrace_pcinfo "
+ "got %u expected %d\n"),
+ (unsigned int) bdata.index, j + 1);
+ bdata.failed = 1;
+ }
+ }
+
+ //check ("test3", 0, all, f3line, "f23", FILE, &bdata.failed);
+ (void)f3line;
+ //check ("test3", 1, all, f2line, "f22", FILE, &bdata.failed);
+ (void)f2line;
+ check ("test3", 2, all, f1line, "test3", FILE, &bdata.failed);
+
+ if (bdata.failed)
+ data.failed = 1;
+
+ for (j = 0; j < 3; ++j)
+ {
+ struct symdata symdata;
+
+ symdata.name = NULL;
+ symdata.val = 0;
+ symdata.size = 0;
+ symdata.failed = 0;
+
+ i = backtrace_syminfo (state, addrs[j], callback_three,
+ error_callback_three, &symdata);
+ if (i == 0)
+ {
+ fprintf (stderr,
+ ("test3: [%d]: unexpected return value "
+ "from backtrace_syminfo %d\n"),
+ j, i);
+ symdata.failed = 1;
+ }
+
+ if (!symdata.failed)
+ {
+ const char *expected;
+
+ switch (j)
+ {
+ case 0:
+ expected = "f23";
+ break;
+ case 1:
+ expected = "f22";
+ break;
+ case 2:
+ expected = "test3";
+ break;
+ default:
+ assert (0);
+ }
+
+ if (symdata.name == NULL)
+ {
+ fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
+ symdata.failed = 1;
+ }
+ /* Use strncmp, not strcmp, because GCC might create a
+ clone. */
+ else if (strncmp (symdata.name, expected, strlen (expected))
+ != 0)
+ {
+ fprintf (stderr,
+ ("test3: [%d]: unexpected syminfo name "
+ "got %s expected %s\n"),
+ j, symdata.name, expected);
+ symdata.failed = 1;
+ }
+ }
+
+ if (symdata.failed)
+ data.failed = 1;
+ }
+ }
+
+ printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
+
+ if (data.failed)
+ ++failures;
+
+ return failures;
+}
+
+/* Check that are no files left open. */
+
+static void
+check_open_files (void)
+{
+ int i;
+
+ for (i = 3; i < 10; i++)
+ {
+ if (close (i) == 0)
+ {
+ fprintf (stderr,
+ "ERROR: descriptor %d still open after tests complete\n",
+ i);
+ ++failures;
+ }
+ }
+}
+
+/* Run all the tests. */
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+ error_callback_create, NULL);
+
+#if BACKTRACE_SUPPORTED
+ test3 ();
+#endif
+
+ check_open_files ();
+
+ exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libbacktrace/configure b/libbacktrace/configure
index c316dde1ad2..2ea112bde68 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -672,6 +672,9 @@ LD
FGREP
SED
LIBTOOL
+HAVE_DWZ_FALSE
+HAVE_DWZ_TRUE
+DWZ
RANLIB
MAINT
MAINTAINER_MODE_FALSE
@@ -5366,6 +5369,52 @@ case "$AWK" in
"") as_fn_error $? "can't build without awk" "$LINENO" 5 ;;
esac
+# Extract the first word of "dwz", so it can be a program name with args.
+set dummy dwz; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DWZ+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DWZ"; then
+ ac_cv_prog_DWZ="$DWZ" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DWZ="dwz"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DWZ=$ac_cv_prog_DWZ
+if test -n "$DWZ"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DWZ" >&5
+$as_echo "$DWZ" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "$DWZ" != ""; then
+ HAVE_DWZ_TRUE=
+ HAVE_DWZ_FALSE='#'
+else
+ HAVE_DWZ_TRUE='#'
+ HAVE_DWZ_FALSE=
+fi
+
+
case `pwd` in
*\ * | *\ *)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
@@ -11440,7 +11489,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11443 "configure"
+#line 11492 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11546,7 +11595,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11549 "configure"
+#line 11598 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -13558,6 +13607,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_DWZ_TRUE}" && test -z "${HAVE_DWZ_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_DWZ\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then
as_fn_error $? "conditional \"HAVE_PTHREAD\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index c75fc9d7ebc..9f0fac80719 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -78,6 +78,9 @@ case "$AWK" in
"") AC_MSG_ERROR([can't build without awk]) ;;
esac
+AC_CHECK_PROG(DWZ, dwz, dwz)
+AM_CONDITIONAL(HAVE_DWZ, test "$DWZ" != "")
+
LT_INIT
AM_PROG_LIBTOOL
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index 4566d37cf2f..c14b571bcb9 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -343,6 +343,8 @@ 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. */
@@ -660,7 +662,7 @@ static int
read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
int is_dwarf64, int version, int addrsize,
const unsigned char *dwarf_str, size_t dwarf_str_size,
- struct attr_val *val)
+ struct attr_val *val, struct dwarf_data *altlink)
{
/* Avoid warnings about val.u.FIELD may be used uninitialized if
this function is inlined. The warnings aren't valid but can
@@ -766,7 +768,7 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
form = read_uleb128 (buf);
return read_attribute ((enum dwarf_form) form, buf, is_dwarf64,
version, addrsize, dwarf_str, dwarf_str_size,
- val);
+ val, altlink);
}
case DW_FORM_sec_offset:
val->encoding = ATTR_VAL_REF_SECTION;
@@ -796,8 +798,18 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
val->u.uint = read_offset (buf, is_dwarf64);
return 1;
case DW_FORM_GNU_strp_alt:
- val->encoding = ATTR_VAL_REF_SECTION;
- val->u.uint = read_offset (buf, is_dwarf64);
+ {
+ uint64_t offset;
+
+ offset = read_offset (buf, is_dwarf64);
+ if (offset >= altlink->dwarf_str_size)
+ {
+ dwarf_buf_error (buf, "DW_FORM_GNU_strp_alt out of range");
+ return 0;
+ }
+ val->encoding = ATTR_VAL_STRING;
+ val->u.string = (const char *) altlink->dwarf_str + offset;
+ }
return 1;
default:
dwarf_buf_error (buf, "unrecognized DWARF form");
@@ -1252,7 +1264,8 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
size_t dwarf_ranges_size,
int is_bigendian, backtrace_error_callback error_callback,
void *data, struct unit *u,
- struct unit_addrs_vector *addrs)
+ struct unit_addrs_vector *addrs,
+ struct dwarf_data *altlink)
{
while (unit_buf->left > 0)
{
@@ -1288,7 +1301,7 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
if (!read_attribute (abbrev->attrs[i].form, unit_buf,
u->is_dwarf64, u->version, u->addrsize,
- dwarf_str, dwarf_str_size, &val))
+ dwarf_str, dwarf_str_size, &val, altlink))
return 0;
switch (abbrev->attrs[i].name)
@@ -1387,7 +1400,7 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
dwarf_str, dwarf_str_size,
dwarf_ranges, dwarf_ranges_size,
is_bigendian, error_callback, data,
- u, addrs))
+ u, addrs, altlink))
return 0;
}
}
@@ -1406,7 +1419,8 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
const unsigned char *dwarf_str, size_t dwarf_str_size,
int is_bigendian, backtrace_error_callback error_callback,
- void *data, struct unit_addrs_vector *addrs)
+ void *data, struct unit_addrs_vector *addrs,
+ struct dwarf_data *altlink)
{
struct dwarf_buf info;
struct abbrevs abbrevs;
@@ -1499,7 +1513,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
dwarf_str, dwarf_str_size,
dwarf_ranges, dwarf_ranges_size,
is_bigendian, error_callback, data,
- u, addrs))
+ u, addrs, altlink))
{
free_abbrevs (state, &u->abbrevs, error_callback, data);
backtrace_free (state, u, sizeof *u, error_callback, data);
@@ -2101,7 +2115,7 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
if (!read_attribute (abbrev->attrs[i].form, &unit_buf,
u->is_dwarf64, u->version, u->addrsize,
ddata->dwarf_str, ddata->dwarf_str_size,
- &val))
+ &val, ddata->altlink))
return NULL;
switch (abbrev->attrs[i].name)
@@ -2314,7 +2328,7 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
if (!read_attribute (abbrev->attrs[i].form, unit_buf,
u->is_dwarf64, u->version, u->addrsize,
ddata->dwarf_str, ddata->dwarf_str_size,
- &val))
+ &val, ddata->altlink))
return 0;
/* The compile unit sets the base address for any address
@@ -2925,7 +2939,7 @@ build_dwarf_data (struct backtrace_state *state,
size_t dwarf_str_size,
int is_bigendian,
backtrace_error_callback error_callback,
- void *data)
+ void *data, struct dwarf_data *altlink)
{
struct unit_addrs_vector addrs_vec;
struct unit_addrs *addrs;
@@ -2935,7 +2949,8 @@ build_dwarf_data (struct backtrace_state *state,
if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size,
dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges,
dwarf_ranges_size, dwarf_str, dwarf_str_size,
- is_bigendian, error_callback, data, &addrs_vec))
+ is_bigendian, error_callback, data, &addrs_vec,
+ altlink))
return NULL;
if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))
@@ -2952,6 +2967,7 @@ build_dwarf_data (struct backtrace_state *state,
return NULL;
fdata->next = NULL;
+ fdata->altlink = altlink;
fdata->base_address = base_address;
fdata->addrs = addrs;
fdata->addrs_count = addrs_count;
@@ -2988,7 +3004,8 @@ backtrace_dwarf_add (struct backtrace_state *state,
size_t dwarf_str_size,
int is_bigendian,
backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn)
+ void *data, fileline *fileline_fn, void **fileline_entry,
+ void *fileline_altlink)
{
struct dwarf_data *fdata;
@@ -2996,10 +3013,13 @@ backtrace_dwarf_add (struct backtrace_state *state,
dwarf_line, dwarf_line_size, dwarf_abbrev,
dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size,
dwarf_str, dwarf_str_size, is_bigendian,
- error_callback, data);
+ error_callback, data, fileline_altlink);
if (fdata == NULL)
return 0;
+ if (fileline_entry != NULL)
+ *fileline_entry = fdata;
+
if (!state->threaded)
{
struct dwarf_data **pp;
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index f4863f0bea5..f63f9c8bcec 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -1051,6 +1051,27 @@ elf_open_debugfile_by_debuglink (struct backtrace_state *state,
return ddescriptor;
}
+/* Open a separate debug info file, using the debugaltlink section data
+ to find it. Returns an open file descriptor, or -1. */
+
+static int
+elf_open_debugfile_by_debugaltlink (struct backtrace_state *state,
+ const char *filename,
+ const char *debugaltlink_name,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ int ddescriptor;
+
+ ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
+ debugaltlink_name,
+ error_callback, data);
+ if (ddescriptor < 0)
+ return -1;
+
+ return ddescriptor;
+}
+
/* A function useful for setting a breakpoint for an inflation failure
when this code is compiled with -g. */
@@ -2638,7 +2659,8 @@ static int
elf_add (struct backtrace_state *state, const char *filename, int descriptor,
uintptr_t base_address, backtrace_error_callback error_callback,
void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf,
- int exe, int debuginfo)
+ void **fileline_entry, int exe, int debuginfo,
+ const char *with_buildid_data, uint32_t with_buildid_size)
{
struct backtrace_view ehdr_view;
b_elf_ehdr ehdr;
@@ -2670,6 +2692,11 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
int debuglink_view_valid;
const char *debuglink_name;
uint32_t debuglink_crc;
+ struct backtrace_view debugaltlink_view;
+ int debugaltlink_view_valid;
+ const char *debugaltlink_name;
+ const char *debugaltlink_buildid_data;
+ uint32_t debugaltlink_buildid_size;
off_t min_offset;
off_t max_offset;
struct backtrace_view debug_view;
@@ -2694,6 +2721,10 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
debuglink_view_valid = 0;
debuglink_name = NULL;
debuglink_crc = 0;
+ debugaltlink_view_valid = 0;
+ debugaltlink_name = NULL;
+ debugaltlink_buildid_data = NULL;
+ debugaltlink_buildid_size = 0;
debug_view_valid = 0;
opd = NULL;
@@ -2873,6 +2904,15 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
buildid_data = ¬e->name[0] + ((note->namesz + 3) & ~ 3);
buildid_size = note->descsz;
}
+
+ if (with_buildid_size != 0)
+ {
+ if (buildid_size != with_buildid_size)
+ goto fail;
+
+ if (memcmp (buildid_data, with_buildid_data, buildid_size) != 0)
+ goto fail;
+ }
}
/* Read the debuglink file if present. */
@@ -2899,6 +2939,27 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
}
}
+ if (!debugaltlink_view_valid
+ && strcmp (name, ".gnu_debugaltlink") == 0)
+ {
+ const char *debugaltlink_data;
+ size_t debugaltlink_name_len;
+
+ if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ &debugaltlink_view))
+ goto fail;
+
+ debugaltlink_view_valid = 1;
+ debugaltlink_data = (const char *) debugaltlink_view.data;
+ debugaltlink_name = debugaltlink_data;
+ debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size);
+ debugaltlink_buildid_data = (debugaltlink_data
+ + debugaltlink_name_len
+ + 1);
+ debugaltlink_buildid_size = shdr->sh_size - debugaltlink_name_len - 1;
+ }
+
/* Read the .opd section on PowerPC64 ELFv1. */
if (ehdr.e_machine == EM_PPC64
&& (ehdr.e_flags & EF_PPC64_ABI) < 2
@@ -2993,8 +3054,12 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
if (debuglink_view_valid)
backtrace_release_view (state, &debuglink_view, error_callback,
data);
+ if (debugaltlink_view_valid)
+ backtrace_release_view (state, &debugaltlink_view, error_callback,
+ data);
ret = elf_add (state, NULL, d, base_address, error_callback, data,
- fileline_fn, found_sym, found_dwarf, 0, 1);
+ fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
+ 0);
if (ret < 0)
backtrace_close (d, error_callback, data);
else
@@ -3028,8 +3093,12 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
backtrace_release_view (state, &debuglink_view, error_callback,
data);
- ret = elf_add (state, NULL, d, base_address, error_callback, data,
- fileline_fn, found_sym, found_dwarf, 0, 1);
+ if (debugaltlink_view_valid)
+ backtrace_release_view (state, &debugaltlink_view, error_callback,
+ data);
+ ret = elf_add (state, filename, d, base_address, error_callback, data,
+ fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
+ 0);
if (ret < 0)
backtrace_close (d, error_callback, data);
else
@@ -3044,6 +3113,39 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
debuglink_view_valid = 0;
}
+ void *fileline_altlink = NULL;
+ if (debugaltlink_name != NULL)
+ {
+ int d;
+
+ d = elf_open_debugfile_by_debugaltlink (state, filename,
+ debugaltlink_name,
+ error_callback, data);
+ if (d >= 0)
+ {
+ int ret;
+
+ ret = elf_add (state, filename, d, base_address, error_callback, data,
+ fileline_fn, found_sym, found_dwarf, &fileline_altlink,
+ 0, 1, debugaltlink_buildid_data,
+ debugaltlink_buildid_size);
+ backtrace_release_view (state, &debugaltlink_view, error_callback,
+ data);
+ debugaltlink_view_valid = 0;
+ if (ret < 0)
+ {
+ backtrace_close (d, error_callback, data);
+ return ret;
+ }
+ }
+ }
+
+ if (debugaltlink_view_valid)
+ {
+ backtrace_release_view (state, &debugaltlink_view, error_callback, data);
+ debugaltlink_view_valid = 0;
+ }
+
/* Read all the debug sections in a single view, since they are
probably adjacent in the file. We never release this view. */
@@ -3181,7 +3283,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
sections[DEBUG_STR].data,
sections[DEBUG_STR].size,
ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
- error_callback, data, fileline_fn))
+ error_callback, data, fileline_fn, fileline_entry,
+ fileline_altlink))
goto fail;
*found_dwarf = 1;
@@ -3199,6 +3302,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
backtrace_release_view (state, &strtab_view, error_callback, data);
if (debuglink_view_valid)
backtrace_release_view (state, &debuglink_view, error_callback, data);
+ if (debugaltlink_view_valid)
+ backtrace_release_view (state, &debugaltlink_view, error_callback, data);
if (buildid_view_valid)
backtrace_release_view (state, &buildid_view, error_callback, data);
if (debug_view_valid)
@@ -3269,7 +3374,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
if (elf_add (pd->state, filename, descriptor, info->dlpi_addr,
pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
- &found_dwarf, 0, 0))
+ &found_dwarf, NULL, 0, 0, NULL, 0))
{
if (found_dwarf)
{
@@ -3297,7 +3402,8 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
struct phdr_data pd;
ret = elf_add (state, filename, descriptor, 0, error_callback, data,
- &elf_fileline_fn, &found_sym, &found_dwarf, 1, 0);
+ &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL,
+ 0);
if (!ret)
return 0;
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index bff8ed470e4..9c91f673d49 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -290,7 +290,9 @@ extern int backtrace_dwarf_add (struct backtrace_state *state,
size_t dwarf_str_size,
int is_bigendian,
backtrace_error_callback error_callback,
- void *data, fileline *fileline_fn);
+ void *data, fileline *fileline_fn,
+ void **fileline_entry,
+ void *fileline_altlink);
/* A test-only hook for elf_uncompress_zdebug. */