On 14-11-18 14:25, Jakub Jelinek wrote: > On Wed, Nov 14, 2018 at 02:08:05PM +0100, Tom de Vries wrote: >>> +btest_dwz_CFLAGS = $(AM_CFLAGS) -g -O0 >> >> Hmm, I already discovered that specifying the -O0 doesn't work, since >> it's overridden by $(CFLAGS). >> >> With a hack like this: >> ... >> diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am >> index 2fec9bbb4b6..8bdf13b3546 100644 >> --- a/libbacktrace/Makefile.am >> +++ b/libbacktrace/Makefile.am >> @@ -99,11 +99,14 @@ check_PROGRAMS += btest >> if HAVE_DWZ >> >> btest_dwz_SOURCES = btest_dwz.c testlib.c >> -btest_dwz_CFLAGS = $(AM_CFLAGS) -g -O0 >> +btest_dwz_CFLAGS = $(AM_CFLAGS) -g >> btest_dwz_LDADD = libbacktrace.la >> >> check_PROGRAMS += btest_dwz >> >> +btest_dwz-btest_dwz.o: btest_dwz.c >> + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) >> $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_dwz_CFLAGS) $(CFLAGS) -O0 -c -o >> btest_dwz-btest_dwz.o `test -f 'btest_dwz.c' || echo >> '$(srcdir)/'`btest_dwz.c > > Can't you instead do something like: > btest_dwz.o: CFLAGS += -g -O0 > or something similar
Hi, yes, that works, thanks. > (whatever the corresponding goal is)? The goal is to run the testcase with a setting lower than -O2, such that we can successfully run a substantial portion of the test without needing support for DW_FORM_GNU_ref_alt. [ At O2 we get constprop versions of some functions, which have an abstract origin, which tends to be moved to the common debug file by dwz -m, after which we need support for DW_FORM_GNU_ref_alt to get to the name of the function. ] > Otherwise, the patch looks generally ok to me, Great. > but yes, I've been wondering > how you can get away with DW_FORM_GNU_ref_alt not implemented properly. > Indeed, DW_FORM_GNU_ref_alt support is required to make this work in general. But I observed that implementing just DW_FORM_GNU_strp_alt improves on the current situation, so I thought it was worthwhile submitting this as a separate patch. Updated patch attached (which also rewrites btest_dwz.c to an include of btest.c, while disabling the inline tests that require DW_FORM_GNU_ref_alt). Thanks, - Tom
[libbacktrace] Handle DW_FORM_GNU_strp_alt 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 to 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 includes btest.c but excludes the inline tests and is compiled with -O, such that it only requires FORM_GNU_strp_alt. Bootstrapped and reg-tested on x86_64. 2018-11-11 Tom de Vries <tdevr...@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.c (INLINE_TESTS): Define to 1 if not defined. (main): Only run test2 and test4 if INLINE_TESTS. * btest_dwz.c: New file. Define INLINE_TESTS to 0 and include btest.c. --- libbacktrace/Makefile.am | 22 +++++++++ libbacktrace/Makefile.in | 80 +++++++++++++++++++++++++------ libbacktrace/btest.c | 12 +++++ libbacktrace/btest_dwz.c | 33 +++++++++++++ libbacktrace/configure | 57 +++++++++++++++++++++- libbacktrace/configure.ac | 3 ++ libbacktrace/dwarf.c | 50 +++++++++++++------ libbacktrace/elf.c | 120 +++++++++++++++++++++++++++++++++++++++++++--- libbacktrace/internal.h | 4 +- 9 files changed, 341 insertions(+), 40 deletions(-) diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index 3c1bd49dd7b..08d1d402f6f 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.$(OBJEXT): CFLAGS += -g -O +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..72496697ca9 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,11 @@ 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.$(OBJEXT) \ +@HAVE_DWZ_TRUE@@NATIVE_TRUE@ testlib.$(OBJEXT) +btest_dwz_OBJECTS = $(am_btest_dwz_OBJECTS) +@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz_DEPENDENCIES = libbacktrace.la @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 +255,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 +511,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 +666,17 @@ 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_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 +794,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)$(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) @@ -1095,6 +1113,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 +1162,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'; \ @@ -1291,6 +1330,17 @@ uninstall-am: .PRECIOUS: Makefile +@HAVE_DWZ_TRUE@@NATIVE_TRUE@btest_dwz.$(OBJEXT): CFLAGS += -g -O + +@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 diff --git a/libbacktrace/btest.c b/libbacktrace/btest.c index 1348d54da50..70484eb318e 100644 --- a/libbacktrace/btest.c +++ b/libbacktrace/btest.c @@ -46,6 +46,10 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "testlib.h" +#ifndef INLINE_TESTS +#define INLINE_TESTS 1 +#endif + /* Test the backtrace function with non-inlined functions. */ static int test1 (void) __attribute__ ((noinline, unused)); @@ -108,6 +112,7 @@ f3 (int f1line, int f2line) return failures; } +#if INLINE_TESTS /* Test the backtrace function with inlined functions. */ static inline int test2 (void) __attribute__ ((always_inline, unused)); @@ -159,6 +164,7 @@ f13 (int f1line, int f2line) return failures; } +#endif /* Test the backtrace_simple function with non-inlined functions. */ @@ -310,6 +316,7 @@ f23 (int f1line, int f2line) return failures; } +#if INLINE_TESTS /* Test the backtrace_simple function with inlined functions. */ static inline int test4 (void) __attribute__ ((always_inline, unused)); @@ -386,6 +393,7 @@ f33 (int f1line, int f2line) return failures; } +#endif static int test5 (void) __attribute__ ((unused)); @@ -486,9 +494,13 @@ main (int argc ATTRIBUTE_UNUSED, char **argv) #if BACKTRACE_SUPPORTED test1 (); +#if INLINE_TESTS test2 (); +#endif test3 (); +#if INLINE_TESTS test4 (); +#endif #if BACKTRACE_SUPPORTS_DATA test5 (); #endif diff --git a/libbacktrace/btest_dwz.c b/libbacktrace/btest_dwz.c new file mode 100644 index 00000000000..ffa9dff8a0b --- /dev/null +++ b/libbacktrace/btest_dwz.c @@ -0,0 +1,33 @@ +/* btest_dwz.c -- Test for libbacktrace library + 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. */ + +#define INLINE_TESTS 0 +#include "btest.c" 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. */