libbacktrace patch committed: Use __has_attribute for fallthrough
This libbacktrace patch uses __has_attribute for fallthrough. It also fixes some FALLTHROUGH comments to use ATTRIBUTE_FALLTHROUGH. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian * internal.h: Use __has_attribute to check for fallthrough attribute. * elf.c (elf_zstd_decompress): Use ATTRIBUTE_FALLTHROUGH rather than a FALLTHROUGH comment. 58b219d3cf69a0464d3c74d43e4cc24117e64647 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index e8d67feab6d..0040479143d 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -4848,25 +4848,25 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin, { case 8: *pout++ = *plit++; - /* FALLTHROUGH */ + ATTRIBUTE_FALLTHROUGH; case 7: *pout++ = *plit++; - /* FALLTHROUGH */ + ATTRIBUTE_FALLTHROUGH; case 6: *pout++ = *plit++; - /* FALLTHROUGH */ + ATTRIBUTE_FALLTHROUGH; case 5: *pout++ = *plit++; - /* FALLTHROUGH */ + ATTRIBUTE_FALLTHROUGH; case 4: *pout++ = *plit++; - /* FALLTHROUGH */ + ATTRIBUTE_FALLTHROUGH; case 3: *pout++ = *plit++; - /* FALLTHROUGH */ + ATTRIBUTE_FALLTHROUGH; case 2: *pout++ = *plit++; - /* FALLTHROUGH */ + ATTRIBUTE_FALLTHROUGH; case 1: *pout++ = *plit++; break; diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h index a119cda692f..fe2abe50b0f 100644 --- a/libbacktrace/internal.h +++ b/libbacktrace/internal.h @@ -56,6 +56,11 @@ POSSIBILITY OF SUCH DAMAGE. */ # endif #endif +#ifdef __has_attribute +# if __has_attribute(fallthrough) +# define ATTRIBUTE_FALLTHROUGH __attribute__ ((fallthrough)) +# endif +#endif #ifndef ATTRIBUTE_FALLTHROUGH # if (GCC_VERSION >= 7000) # define ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__))
Re: libbacktrace patch committed: Better backtrace_print if no debug info
On Wed, Jul 17, 2024 at 5:40 PM Ian Lance Taylor wrote: > > This libbacktrace patch improves backtrace_print when there is no > debug info. It falls back to calling backtrace_syminfo, and uses that > to print an offset from a symbol if it can. This is a partial fix for > https://github.com/ianlancetaylor/libbacktrace/issues/59. > Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu. > Committed to mainline. And this patch corrects a bug in that patch. Ian c7c8bcdbb412c71c9522f7874d43a3bd9319b940 diff --git a/libbacktrace/print.c b/libbacktrace/print.c index 70f5a93c49d..d4637af9a4f 100644 --- a/libbacktrace/print.c +++ b/libbacktrace/print.c @@ -77,7 +77,7 @@ static void print_syminfo_callback (void *data, uintptr_t pc, fprintf (pdata->f, "0x%lx ???\n\t%s+0x%lx:0\n", (unsigned long) pc, symname, -pc - symval); +(unsigned long) (pc - symval)); } /* Print one level of a backtrace. */
libbacktrace patch committed: Better backtrace_print if no debug info
This libbacktrace patch improves backtrace_print when there is no debug info. It falls back to calling backtrace_syminfo, and uses that to print an offset from a symbol if it can. This is a partial fix for https://github.com/ianlancetaylor/libbacktrace/issues/59. Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian * print.c (print_syminfo_callback): New static function. (print_callback): Call backtrace_syminfo if there is no function or file name. 4dbb53eb10767d111228224ae3113aee0d4d6213 diff --git a/libbacktrace/print.c b/libbacktrace/print.c index 3e61f02ebbc..70f5a93c49d 100644 --- a/libbacktrace/print.c +++ b/libbacktrace/print.c @@ -47,6 +47,39 @@ struct print_data FILE *f; }; +/* Print errors to stderr. */ + +static void +error_callback (void *data, const char *msg, int errnum) +{ + struct print_data *pdata = (struct print_data *) data; + + if (pdata->state->filename != NULL) +fprintf (stderr, "%s: ", pdata->state->filename); + fprintf (stderr, "libbacktrace: %s", msg); + if (errnum > 0) +fprintf (stderr, ": %s", strerror (errnum)); + fputc ('\n', stderr); +} + +/* Print one level of a backtrace if we couldn't get a file or function name. + Use syminfo to try to get a symbol name. */ + +static void print_syminfo_callback (void *data, uintptr_t pc, + const char *symname, uintptr_t symval, + uintptr_t symsize ATTRIBUTE_UNUSED) +{ + struct print_data *pdata = (struct print_data *) data; + + if (symname == NULL) +fprintf (pdata->f, "0x%lx ???\n\t???:0\n", (unsigned long) pc); + else +fprintf (pdata->f, "0x%lx ???\n\t%s+0x%lx:0\n", +(unsigned long) pc, +symname, +pc - symval); +} + /* Print one level of a backtrace. */ static int @@ -55,6 +88,13 @@ print_callback (void *data, uintptr_t pc, const char *filename, int lineno, { struct print_data *pdata = (struct print_data *) data; + if (function == NULL && filename == NULL) +{ + backtrace_syminfo (pdata->state, pc, print_syminfo_callback, +error_callback, data); + return 0; +} + fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n", (unsigned long) pc, function == NULL ? "???" : function, @@ -63,21 +103,6 @@ print_callback (void *data, uintptr_t pc, const char *filename, int lineno, return 0; } -/* Print errors to stderr. */ - -static void -error_callback (void *data, const char *msg, int errnum) -{ - struct print_data *pdata = (struct print_data *) data; - - if (pdata->state->filename != NULL) -fprintf (stderr, "%s: ", pdata->state->filename); - fprintf (stderr, "libbacktrace: %s", msg); - if (errnum > 0) -fprintf (stderr, ": %s", strerror (errnum)); - fputc ('\n', stderr); -} - /* Print a backtrace. */ void __attribute__((noinline))
libbacktrace patch committed: Mention dl_iterate_phdr in README
This patch adds some notes about dl_iterate_phdr to the libbacktrace README file. In general dl_iterate_phdr is not async-signal-safe and does call malloc, so programs that want to use libbacktrace functions from a signal handler or within malloc must make an initiali libbacktrace call in order to call dl_iterate_phdr. Committed to mainline. Ian * README: Add notes about dl_iterate_phdr. 14667f4cc51b6c59cf9e6c05f3bcac17df94ef10 diff --git a/libbacktrace/README b/libbacktrace/README index 6225f92b855..6e6ec332fe2 100644 --- a/libbacktrace/README +++ b/libbacktrace/README @@ -5,8 +5,18 @@ The libbacktrace library may be linked into a program or library and used to produce symbolic backtraces. Sample uses would be to print a detailed backtrace when an error occurs or to gather detailed profiling information. + In general the functions provided by this library are async-signal-safe, meaning that they may be safely called from a signal handler. +That said, on systems that use dl_iterate_phdr, such as GNU/Linux, +the first call to a libbacktrace function will call dl_iterate_phdr, +which is not in general async-signal-safe. Therefore, programs +that call libbacktrace from a signal handler should ensure that they +make an initial call from outside of a signal handler. +Similar considerations apply when arranging to call libbacktrace +from within malloc; dl_iterate_phdr can also call malloc, +so make an initial call to a libbacktrace function outside of +malloc before trying to call libbacktrace functions within malloc. The libbacktrace library is provided under a BSD license. See the source files for the exact license text. @@ -20,7 +30,7 @@ will work. See the source file backtrace-supported.h.in for the macros that it defines. -As of October 2020, libbacktrace supports ELF, PE/COFF, Mach-O, and +As of July 2024, libbacktrace supports ELF, PE/COFF, Mach-O, and XCOFF executables with DWARF debugging information. In other words, it supports GNU/Linux, *BSD, macOS, Windows, and AIX. The library is written to make it straightforward to add support for
libbacktrace patch committed: Avoid infinite recursion
libbacktrace could get an infinite recursion in an odd case in which a .gnu_debugdata section was added to a debug file, and mini_debuginfo was put into the debug file, and the debug file was put into a /usr/lib/debug directory to be found by build ID. This combination doesn't really make sense but we shouldn't get an infinite recursion. This patch fixes the problem. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * elf.c (elf_add): Don't use .gnu_debugdata if we are already reading a debuginfo file. * Makefile.am (m2test_*): New test targets. (CHECK_PROGRAMS): Add m2test. (MAKETESTS): Add m2test_minidebug2. (%_minidebug2): New pattern. (CLEANFILES): Remove minidebug2 files. * Makefile.in: Regenerate. 8a3a34665210105a89b14f380c3bec780c209046 diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index bed42c29329..8215cfd9bd5 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -594,6 +594,39 @@ MAKETESTS += mtest_minidebug $(OBJCOPY) --add-section .gnu_debugdata=$<.mdbg.xz $<.strip mv $<.strip $@ +if HAVE_ELF +if HAVE_BUILDID +if HAVE_OBJCOPY_DEBUGLINK + +m2test_SOURCES = $(mtest_SOURCES) +m2test_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O +m2test_LDFLAGS = -Wl,--build-id $(libbacktrace_testing_ldflags) +m2test_LDADD = libbacktrace_elf_for_test.la + +check_PROGRAMS += m2test +MAKETESTS += m2test_minidebug2 + +# minidebug2 is like minidebug but also adds the gnu_debugdata section +# to the debug file, and uses a build ID file. There is no reason to do +# this but it was causing an infinite recursion. +%_minidebug2: % + $(NM) -D $< -P --defined-only | $(AWK) '{ print $$1 }' | sort > $<.dsyms2 + $(NM) $< -P --defined-only | $(AWK) '{ if ($$2 == "T" || $$2 == "t" || $$2 == "D") print $$1 }' | sort > $<.fsyms2 + $(COMM) -13 $<.dsyms2 $<.fsyms2 > $<.keepsyms2 + $(OBJCOPY) --only-keep-debug $< $<.dbg2 + $(OBJCOPY) -S --remove-section .gdb_index --remove-section .comment --keep-symbols=$<.keepsyms2 $<.dbg2 $<.mdbg2 + $(OBJCOPY) --strip-all --remove-section ..comment $< $<.strip2 + rm -f $<.mdbg2.xz + $(XZ) $<.mdbg2 + $(OBJCOPY) --add-section .gnu_debugdata=$<.mdbg2.xz $<.dbg2 + $(OBJCOPY) --add-section .gnu_debugdata=$<.mdbg2.xz $<.strip2 + $(SHELL) ./install-debuginfo-for-buildid.sh $(TEST_BUILD_ID_DIR) $<.dbg2 + mv $<.strip2 $@ + +endif HAVE_OBJCOPY_DEBUGLINK +endif HAVE_BUILDID +endif HAVE_ELF + endif HAVE_MINIDEBUG endif NATIVE @@ -629,7 +662,8 @@ TESTS += $(MAKETESTS) $(BUILDTESTS) CLEANFILES = \ $(MAKETESTS) $(BUILDTESTS) *.debug elf_for_test.c edtest2_build.c \ gen_edtest2_build \ - *.dsyms *.fsyms *.keepsyms *.dbg *.mdbg *.mdbg.xz *.strip + *.dsyms *.fsyms *.keepsyms *.dbg *.mdbg *.mdbg.xz *.strip \ + *.dsyms2 *.fsyms2 *.keepsyms2 *.dbg2 *.mdbg2 *.mdbg2.xz *.strip2 clean-local: -rm -rf usr diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index e6a66c0db90..107c96892a0 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -6841,7 +6841,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, } } - if (!gnu_debugdata_view_valid + if (!debuginfo + && !gnu_debugdata_view_valid && strcmp (name, ".gnu_debugdata") == 0) { if (!elf_get_view (state, descriptor, memory, memory_size,
libbacktrace patch committed: Don't fail if symbol size is unknown
Mach-O and PE/COFF don't record symbol sizes in the symbol table. Adjust the libbacktrace testsuite so that it doesn't fail if the symbol size is unknown, only if it is incorrect. Ran libbacktrace tests on macOS on the compile farm and on x86_64-pc-linux-gnu. Committed to mainline. Ian * btest.c (test5): Don't fail if symbol size is 0. * mtest.c (test5): Likewise. d7318f4cf89c2a934fcd1f87d711081285fad242 diff --git a/libbacktrace/btest.c b/libbacktrace/btest.c index c4b2db2cce2..3b603f643fa 100644 --- a/libbacktrace/btest.c +++ b/libbacktrace/btest.c @@ -440,7 +440,7 @@ test5 (void) (unsigned long) (uintptr_t) ); symdata.failed = 1; } - else if (symdata.size != sizeof (global)) + else if (symdata.size != sizeof (global) && symdata.size != 0) { fprintf (stderr, "test5: unexpected syminfo size got %lx expected %lx\n", diff --git a/libbacktrace/mtest.c b/libbacktrace/mtest.c index f793391653d..5ec43c7bbce 100644 --- a/libbacktrace/mtest.c +++ b/libbacktrace/mtest.c @@ -373,7 +373,7 @@ test5 (void) (unsigned long) (uintptr_t) ); symdata.failed = 1; } - else if (symdata.size != sizeof (global)) + else if (symdata.size != sizeof (global) && symdata.size != 0) { fprintf (stderr, "test5: unexpected syminfo size got %lx expected %lx\n",
libbacktrace patch committed: Correctly gather Mach-O symbols
The libbacktrace symbol table code was incorrectly discarding global Mach-O symbols. This patch fixes the problem. Tested on macOS on the compile farm, and also on x86_64-pc-linux-gnu. Committed to mainline. Ian For PR libbacktrace/97082 * macho.c (MACH_O_N_EXT): Don't define. (MACH_O_N_UNDF): Define. (macho_defined_symbol): Don't discard N_EXT symbols. Do discard N_UNDF symbols. af827b2ab90b9d726c7182c41fa2409005909db8 diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c index 5ceff05b29a..8f768f14a57 100644 --- a/libbacktrace/macho.c +++ b/libbacktrace/macho.c @@ -271,12 +271,14 @@ struct macho_nlist_64 /* Value found in nlist n_type field. */ -#define MACH_O_N_EXT 0x01/* Extern symbol */ +#define MACH_O_N_STAB 0xe0/* Stabs debugging symbol */ +#define MACH_O_N_TYPE 0x0e/* Mask for type bits */ + +/* Values found after masking with MACH_O_N_TYPE. */ +#define MACH_O_N_UNDF 0x00/* Undefined symbol */ #define MACH_O_N_ABS 0x02/* Absolute symbol */ -#define MACH_O_N_SECT 0x0e/* Defined in section */ +#define MACH_O_N_SECT 0x0e/* Defined in section from n_sect field */ -#define MACH_O_N_TYPE 0x0e/* Mask for type bits */ -#define MACH_O_N_STAB 0xe0/* Stabs debugging symbol */ /* Information we keep for a Mach-O symbol. */ @@ -492,10 +494,10 @@ macho_defined_symbol (uint8_t type) { if ((type & MACH_O_N_STAB) != 0) return 0; - if ((type & MACH_O_N_EXT) != 0) -return 0; switch (type & MACH_O_N_TYPE) { +case MACH_O_N_UNDF: + return 0; case MACH_O_N_ABS: return 1; case MACH_O_N_SECT:
Re: libbacktrace patch committed: Add clang optnone attribute
On Thu, Jul 11, 2024 at 7:19 PM Andrew Pinski wrote: > > On Thu, Jul 11, 2024 at 4:14 PM Ian Lance Taylor wrote: > > > > The libbacktrace testsuite was not passing when run with current > > versions of clang. Add the optnone attribute to make it pass. Add > > -Wno-attributes and -Wno-unknown-attributes to disable warnings about > > unrecognized function attributes. Bootstrapped and ran libbacktrace > > testsuite on x86_64-pc-linux-gnu. Committed to mainline. > > NoteI see they have `noclone` and `noinline`, maybe it should have > `noipa` on them too. noipa disables a few more things than > noclone/noinline that might make a difference too. > Yeah, I was thinking of that, too, perhaps wrapped in a macro like: #if __has_attribute(optnone) # define ATTR_NOOPTS __attribute__ ((noinline, noclone, optnone, unused)) #else # if __has_attribute(noipa) # define ATTR_NOOPTS __attribute__ ((noipa, unused)) # else # define ATTR_NOOPTS __attribute__ ((noinline, noclone, unused)) # endif /* noipa */ #endif /* optnone */ ...and then use that macro in the relevant places. That way it wouldn't be necessary to turn off the warnings from -Wno-attributes and -Wno-unknown-attributes. > Thanks, > Andrew Pinski > > > > > Ian > > > > * btest.c (test1, test3): Add optnone attribute. > > * edtest.c (test1): Likewise. > > * mtest.c (test1, test3): Likewise. > > * configure.ac: Use -Wno-attributes and -Wno-unknown-attributes. > > * configure: Regenerate.
Re: libbacktrace patch committed: Add clang optnone attribute
On Thu, Jul 11, 2024 at 4:18 PM Andrew Pinski wrote: > > On Thu, Jul 11, 2024 at 4:14 PM Ian Lance Taylor wrote: > > > > The libbacktrace testsuite was not passing when run with current > > versions of clang. Add the optnone attribute to make it pass. Add > > -Wno-attributes and -Wno-unknown-attributes to disable warnings about > > unrecognized function attributes. Bootstrapped and ran libbacktrace > > testsuite on x86_64-pc-linux-gnu. Committed to mainline. > > NoteI see they have `noclone` and `noinline`, maybe it should have > `noipa` on them too. noipa disables a few more things than > noclone/noinline that might make a difference too. Thanks, I looked into that, and as far as I can tell for purposes of the libbacktrace testsuite it doesn't matter. All that matters here is that the function isn't inlined, so that it shows up in the call stack. It's OK if the compiler makes other deductions about what the function does. And indeed the tests are passing. Of course we can change the testsuite again if I'm mistaken. Ian
Re: libbacktrace patch committed: Add clang optnone attribute
On Thu, Jul 11, 2024 at 4:14 PM Ian Lance Taylor wrote: > > The libbacktrace testsuite was not passing when run with current > versions of clang. Add the optnone attribute to make it pass. Add > -Wno-attributes and -Wno-unknown-attributes to disable warnings about > unrecognized function attributes. Bootstrapped and ran libbacktrace > testsuite on x86_64-pc-linux-gnu. Committed to mainline. NoteI see they have `noclone` and `noinline`, maybe it should have `noipa` on them too. noipa disables a few more things than noclone/noinline that might make a difference too. Thanks, Andrew Pinski > > Ian > > * btest.c (test1, test3): Add optnone attribute. > * edtest.c (test1): Likewise. > * mtest.c (test1, test3): Likewise. > * configure.ac: Use -Wno-attributes and -Wno-unknown-attributes. > * configure: Regenerate.
libbacktrace patch committed: Add clang optnone attribute
The libbacktrace testsuite was not passing when run with current versions of clang. Add the optnone attribute to make it pass. Add -Wno-attributes and -Wno-unknown-attributes to disable warnings about unrecognized function attributes. Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian * btest.c (test1, test3): Add optnone attribute. * edtest.c (test1): Likewise. * mtest.c (test1, test3): Likewise. * configure.ac: Use -Wno-attributes and -Wno-unknown-attributes. * configure: Regenerate. 67130485e51fb4391908dc8beb7259623a94fbd6 diff --git a/libbacktrace/btest.c b/libbacktrace/btest.c index d9fc372d33d..c4b2db2cce2 100644 --- a/libbacktrace/btest.c +++ b/libbacktrace/btest.c @@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. */ /* Test the backtrace function with non-inlined functions. */ -static int test1 (void) __attribute__ ((noinline, noclone, unused)); +static int test1 (void) __attribute__ ((noinline, noclone, optnone, unused)); static int f2 (int) __attribute__ ((noinline, noclone)); static int f3 (int, int) __attribute__ ((noinline, noclone)); @@ -163,7 +163,7 @@ f13 (int f1line, int f2line) /* Test the backtrace_simple function with non-inlined functions. */ -static int test3 (void) __attribute__ ((noinline, noclone, unused)); +static int test3 (void) __attribute__ ((noinline, noclone, optnone, unused)); static int f22 (int) __attribute__ ((noinline, noclone)); static int f23 (int, int) __attribute__ ((noinline, noclone)); diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 59e9c415db8..bfd7f35d2d2 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -144,7 +144,8 @@ AC_SUBST(EXTRA_FLAGS) ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wwrite-strings -Wstrict-prototypes \ -Wmissing-prototypes -Wold-style-definition \ - -Wmissing-format-attribute -Wcast-qual], + -Wmissing-format-attribute -Wcast-qual \ + -Wno-attributes -Wno-unknown-attributes], [WARN_FLAGS]) AC_ARG_ENABLE([werror], diff --git a/libbacktrace/edtest.c b/libbacktrace/edtest.c index d99b8a60295..b644d93788c 100644 --- a/libbacktrace/edtest.c +++ b/libbacktrace/edtest.c @@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "testlib.h" -static int test1 (void) __attribute__ ((noinline, noclone, unused)); +static int test1 (void) __attribute__ ((noinline, noclone, optnone, unused)); extern int f2 (int); extern int f3 (int, int); diff --git a/libbacktrace/mtest.c b/libbacktrace/mtest.c index 9afe7089514..f793391653d 100644 --- a/libbacktrace/mtest.c +++ b/libbacktrace/mtest.c @@ -47,7 +47,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "testlib.h" -static int test1 (void) __attribute__ ((noinline, noclone, unused)); +static int test1 (void) __attribute__ ((noinline, noclone, optnone, unused)); static int f2 (int) __attribute__ ((noinline, noclone)); static int f3 (int, int) __attribute__ ((noinline, noclone)); @@ -211,7 +211,7 @@ f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused))) /* Test the backtrace_simple function with non-inlined functions. */ -static int test3 (void) __attribute__ ((noinline, noclone, unused)); +static int test3 (void) __attribute__ ((noinline, noclone, optnone, unused)); static int f22 (int) __attribute__ ((noinline, noclone)); static int f23 (int, int) __attribute__ ((noinline, noclone));
libbacktrace patch committed: Suggest -g if no debug info
This small libbacktrace patch suggests compiling with -g (and, on macOS, running dsymutil), if there is no debug info. Ran libbacktrace testsuite. Committed to mainline. Ian * elf.c (elf_nodebug): Suggest -g. * macho.c (macho_nodebug): Suggest -g and dsymutil. * pecoff.c (coff_nodebug): Suggest -g. b96789abf8a51e8f70309799b5dfee36d4fb3da6 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 735f8752500..e6a66c0db90 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -589,7 +589,7 @@ elf_nodebug (struct backtrace_state *state, uintptr_t pc, return bdata.ret; } - error_callback (data, "no debug info in ELF executable", -1); + error_callback (data, "no debug info in ELF executable (make sure to compile with -g)", -1); return 0; } diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c index 42f24721e6a..5ceff05b29a 100644 --- a/libbacktrace/macho.c +++ b/libbacktrace/macho.c @@ -324,7 +324,7 @@ macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, backtrace_full_callback callback ATTRIBUTE_UNUSED, backtrace_error_callback error_callback, void *data) { - error_callback (data, "no debug info in Mach-O executable", -1); + error_callback (data, "no debug info in Mach-O executable (make sure to compile with -g; may need to run dsymutil)", -1); return 0; } diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index bbb59e26d7a..e88e4d2b038 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -240,7 +240,7 @@ coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, backtrace_full_callback callback ATTRIBUTE_UNUSED, backtrace_error_callback error_callback, void *data) { - error_callback (data, "no debug info in PE/COFF executable", -1); + error_callback (data, "no debug info in PE/COFF executable (make sure to compile with -g)", -1); return 0; }
libbacktrace patch committed: Remove trailing whitespace
This minor libbacktrace patch removes trailing whitespace. Ran libbacktrace tests. Committed to mainline. Ian * dwarf.c: Remove trailing whitespace. * macho.c: Likewise. 3f660179d6a0ebcd83d6a546f48a163d1a685f72 diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index ed0672964c2..cc36a0a2990 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -1705,7 +1705,7 @@ add_ranges_from_ranges ( base = (uintptr_t) high; else { - if (!add_range (state, rdata, + if (!add_range (state, rdata, (uintptr_t) low + base + base_address, (uintptr_t) high + base + base_address, error_callback, data, vec)) @@ -1904,7 +1904,7 @@ add_ranges (struct backtrace_state *state, const struct dwarf_sections *dwarf_sections, uintptr_t base_address, int is_bigendian, struct unit *u, uintptr_t base, const struct pcrange *pcrange, - int (*add_range) (struct backtrace_state *state, void *rdata, + int (*add_range) (struct backtrace_state *state, void *rdata, uintptr_t lowpc, uintptr_t highpc, backtrace_error_callback error_callback, void *data, void *vec), diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c index b4856346ccc..42f24721e6a 100644 --- a/libbacktrace/macho.c +++ b/libbacktrace/macho.c @@ -674,7 +674,6 @@ macho_add_symtab (struct backtrace_state *state, int descriptor, struct macho_syminfo_data *p; p = backtrace_atomic_load_pointer (pp); - if (p == NULL) break;
libbacktrace patch committed: OK if zero backward bits
I've committed this libbacktrace patch to not fail on the case where there are no bits available when looking backward. This can happen at the very end of the frame if no bits are actually required. The test case is long and may be proprietary, so not including it. Bootstrapped and ran libbacktrace and Go testsuite. Committed to mainline. Ian * elf.c (elf_fetch_bits_backward) Don't fail if no bits are available. dda0996e11dbc07f63d3456e36dc5eaec7361004 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 3cd87020b03..735f8752500 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -1182,14 +1182,7 @@ elf_fetch_bits_backward (const unsigned char **ppin, val = *pval; if (unlikely (pin <= pinend)) -{ - if (bits == 0) - { - elf_uncompress_failed (); - return 0; - } - return 1; -} +return 1; pin -= 4;
Re: libbacktrace patch committed: Don't assume compressed section aligned
On Fri, Mar 8, 2024 at 2:48 PM Fangrui Song wrote: > > On ELF64, it looks like BFD uses 8-byte alignment for compressed > `.debug_*` sections while gold/lld/mold use 1-byte alignment. I do not > know how the Solaris linker sets the alignment. > > The specification's wording makes me confused whether it really > requires 8-byte alignment, even if a non-packed `Elf64_Chdr` surely > requires 8. Since compressed sections begin with a compression header structure that identifies the compression algorithm, compressed sections must be aligned to the alignment of the compression header. I don't think there is any ambiguity here. > > The sh_size and sh_addralign fields of the section header for a compressed > > section reflect the requirements of the compressed section. > > There are many `.debug_*` sections. So avoiding some alignment padding > seems a very natural extension (a DWARF v5 -gsplit-dwarf relocatable > file has ~10 `.debug_*` sections), even if the specification doesn't > allow it with a very strict interpretation... > > (Off-topic: I wonder whether ELF control structures should use > unaligned LEB128 more. REL/RELA can naturally be replaced with a > LEB128 one similar to wasm.) > > On Fri, Mar 8, 2024 at 1:57 PM Ian Lance Taylor wrote: > > > > Reportedly when lld compresses debug sections, it fails to set the > > alignment of the compressed section such that the compressed header > > can be read directly. To me this seems like a bug in lld. However, > > libbacktrace needs to work around it. This patch, originally by the > > GitHub user ubyte, does that. Bootstrapped and tested on > > x86_64-pc-linux-gnu. Committed to mainline. > > > > Ian > > > > * elf.c (elf_uncompress_chdr): Don't assume compressed section is > > aligned. > > > > -- > 宋方睿 -- H.J.
Re: libbacktrace patch committed: Don't assume compressed section aligned
On ELF64, it looks like BFD uses 8-byte alignment for compressed `.debug_*` sections while gold/lld/mold use 1-byte alignment. I do not know how the Solaris linker sets the alignment. The specification's wording makes me confused whether it really requires 8-byte alignment, even if a non-packed `Elf64_Chdr` surely requires 8. > The sh_size and sh_addralign fields of the section header for a compressed > section reflect the requirements of the compressed section. There are many `.debug_*` sections. So avoiding some alignment padding seems a very natural extension (a DWARF v5 -gsplit-dwarf relocatable file has ~10 `.debug_*` sections), even if the specification doesn't allow it with a very strict interpretation... (Off-topic: I wonder whether ELF control structures should use unaligned LEB128 more. REL/RELA can naturally be replaced with a LEB128 one similar to wasm.) On Fri, Mar 8, 2024 at 1:57 PM Ian Lance Taylor wrote: > > Reportedly when lld compresses debug sections, it fails to set the > alignment of the compressed section such that the compressed header > can be read directly. To me this seems like a bug in lld. However, > libbacktrace needs to work around it. This patch, originally by the > GitHub user ubyte, does that. Bootstrapped and tested on > x86_64-pc-linux-gnu. Committed to mainline. > > Ian > > * elf.c (elf_uncompress_chdr): Don't assume compressed section is > aligned. -- 宋方睿
libbacktrace patch committed: Don't assume compressed section aligned
Reportedly when lld compresses debug sections, it fails to set the alignment of the compressed section such that the compressed header can be read directly. To me this seems like a bug in lld. However, libbacktrace needs to work around it. This patch, originally by the GitHub user ubyte, does that. Bootstrapped and tested on x86_64-pc-linux-gnu. Committed to mainline. Ian * elf.c (elf_uncompress_chdr): Don't assume compressed section is aligned. 5825bd0e0d0040126e78269e56c9b9f533e2a520 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 7841c86cd9c..3cd87020b03 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -5076,7 +5076,7 @@ elf_uncompress_chdr (struct backtrace_state *state, backtrace_error_callback error_callback, void *data, unsigned char **uncompressed, size_t *uncompressed_size) { - const b_elf_chdr *chdr; + b_elf_chdr chdr; char *alc; size_t alc_len; unsigned char *po; @@ -5088,27 +5088,30 @@ elf_uncompress_chdr (struct backtrace_state *state, if (compressed_size < sizeof (b_elf_chdr)) return 1; - chdr = (const b_elf_chdr *) compressed; + /* The lld linker can misalign a compressed section, so we can't safely read + the fields directly as we can for other ELF sections. See + https://github.com/ianlancetaylor/libbacktrace/pull/120. */ + memcpy (, compressed, sizeof (b_elf_chdr)); alc = NULL; alc_len = 0; - if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size) + if (*uncompressed != NULL && *uncompressed_size >= chdr.ch_size) po = *uncompressed; else { - alc_len = chdr->ch_size; + alc_len = chdr.ch_size; alc = backtrace_alloc (state, alc_len, error_callback, data); if (alc == NULL) return 0; po = (unsigned char *) alc; } - switch (chdr->ch_type) + switch (chdr.ch_type) { case ELFCOMPRESS_ZLIB: if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr), compressed_size - sizeof (b_elf_chdr), - zdebug_table, po, chdr->ch_size)) + zdebug_table, po, chdr.ch_size)) goto skip; break; @@ -5116,7 +5119,7 @@ elf_uncompress_chdr (struct backtrace_state *state, if (!elf_zstd_decompress (compressed + sizeof (b_elf_chdr), compressed_size - sizeof (b_elf_chdr), (unsigned char *)zdebug_table, po, - chdr->ch_size)) + chdr.ch_size)) goto skip; break; @@ -5126,7 +5129,7 @@ elf_uncompress_chdr (struct backtrace_state *state, } *uncompressed = po; - *uncompressed_size = chdr->ch_size; + *uncompressed_size = chdr.ch_size; return 1; @@ -6876,8 +6879,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, } } - // A debuginfo file may not have a useful .opd section, but we can use the - // one from the original executable. + /* A debuginfo file may not have a useful .opd section, but we can use the + one from the original executable. */ if (opd == NULL) opd = caller_opd;
libbacktrace patch committed: Link test programs with -no-install
Some of the libbacktrace tests link a program and then modify the debug info in some way. When configured with --enable-shared the linking, using libtool, generates a shell script. That causes the tests to fail because they can't modify the debug info of a shell script. This patch, originally by Jan Tojnar, pass the -no-install flag to libtool to avoid generating a shell script. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * Makefile.am (libbacktrace_testing_ldflags): Define. (*_LDFLAGS): Add $(libbacktrace_testing_ldflags) for test programs. * Makefile.in: Regenerate 9b0d218544cd1b12bf63792c70052d2970acc69b diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index 750ed80ed05..5677ecd8865 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -106,6 +106,10 @@ check_DATA = # Flags to use when compiling test programs. libbacktrace_TEST_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) -g +# Flags to use when linking test programs. +# This avoids generating a shell script when configured with --enable-shared. +libbacktrace_testing_ldflags = -no-install + if USE_DSYMUTIL %.dSYM: % @@ -170,54 +174,63 @@ xcoff_%.c: xcoff.c test_elf_32_SOURCES = test_format.c testlib.c test_elf_32_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_elf_32_LDFLAGS = $(libbacktrace_testing_ldflags) test_elf_32_LDADD = libbacktrace_noformat.la elf_32.lo BUILDTESTS += test_elf_32 test_elf_64_SOURCES = test_format.c testlib.c test_elf_64_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_elf_64_LDFLAGS = $(libbacktrace_testing_ldflags) test_elf_64_LDADD = libbacktrace_noformat.la elf_64.lo BUILDTESTS += test_elf_64 test_macho_SOURCES = test_format.c testlib.c test_macho_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_macho_LDFLAGS = $(libbacktrace_testing_ldflags) test_macho_LDADD = libbacktrace_noformat.la macho.lo BUILDTESTS += test_macho test_xcoff_32_SOURCES = test_format.c testlib.c test_xcoff_32_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_xcoff_32_LDFLAGS = $(libbacktrace_testing_ldflags) test_xcoff_32_LDADD = libbacktrace_noformat.la xcoff_32.lo BUILDTESTS += test_xcoff_32 test_xcoff_64_SOURCES = test_format.c testlib.c test_xcoff_64_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_xcoff_64_LDFLAGS = $(libbacktrace_testing_ldflags) test_xcoff_64_LDADD = libbacktrace_noformat.la xcoff_64.lo BUILDTESTS += test_xcoff_64 test_pecoff_SOURCES = test_format.c testlib.c test_pecoff_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_pecoff_LDFLAGS = $(libbacktrace_testing_ldflags) test_pecoff_LDADD = libbacktrace_noformat.la pecoff.lo BUILDTESTS += test_pecoff test_unknown_SOURCES = test_format.c testlib.c test_unknown_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_unknown_LDFLAGS = $(libbacktrace_testing_ldflags) test_unknown_LDADD = libbacktrace_noformat.la unknown.lo BUILDTESTS += test_unknown unittest_SOURCES = unittest.c testlib.c unittest_CFLAGS = $(libbacktrace_TEST_CFLAGS) +unittest_LDFLAGS = $(libbacktrace_testing_ldflags) unittest_LDADD = libbacktrace.la BUILDTESTS += unittest unittest_alloc_SOURCES = $(unittest_SOURCES) unittest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) +unittest_alloc_LDFLAGS = $(libbacktrace_testing_ldflags) unittest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += unittest_alloc @@ -253,7 +266,7 @@ if HAVE_OBJCOPY_DEBUGLINK b2test_SOURCES = $(btest_SOURCES) b2test_CFLAGS = $(libbacktrace_TEST_CFLAGS) -b2test_LDFLAGS = -Wl,--build-id +b2test_LDFLAGS = -Wl,--build-id $(libbacktrace_testing_ldflags) b2test_LDADD = libbacktrace_elf_for_test.la check_PROGRAMS += b2test @@ -263,7 +276,7 @@ if HAVE_DWZ b3test_SOURCES = $(btest_SOURCES) b3test_CFLAGS = $(libbacktrace_TEST_CFLAGS) -b3test_LDFLAGS = -Wl,--build-id +b3test_LDFLAGS = -Wl,--build-id $(libbacktrace_testing_ldflags) b3test_LDADD = libbacktrace_elf_for_test.la check_PROGRAMS += b3test @@ -277,6 +290,7 @@ endif HAVE_ELF btest_SOURCES = btest.c testlib.c btest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O +btest_LDFLAGS = $(libbacktrace_testing_ldflags) btest_LDADD = libbacktrace.la BUILDTESTS += btest @@ -289,6 +303,7 @@ if HAVE_ELF btest_lto_SOURCES = btest.c testlib.c btest_lto_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O -flto +btest_lto_LDFLAGS = $(libbacktrace_testing_ldflags) btest_lto_LDADD = libbacktrace.la BUILDTESTS += btest_lto @@ -297,6 +312,7 @@ endif HAVE_ELF btest_alloc_SOURCES = $(btest_SOURCES) btest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) +btest_alloc_LDFLAGS = $(libbacktrace_testing_ldflags) btest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += btest_alloc @@ -331,6 +347,7 @@ endif HAVE_DWZ stest_SOURCES = stest.c stest_CFLAGS = $(libbacktrace_TEST_CFLAGS) +stest_LDFLAGS = $(libbacktrace_testing_ldflags) stest_LDADD = libbacktrace.la BUILDTESTS += stest @@ -341,6 +358,7 @@ endif USE_DSYMUTIL stest_alloc_SOURCES = $(stest_SOURCES) stest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS)
libbacktrace patch committed: Skip all LZMA block header padding bytes
This patch to libbacktrace corrects the LZMA block header parsing to skip all the padding bytes, verifying that they are zero. This fixes https://github.com/ianlancetaylor/libbacktrace/issues/118. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. I was able to verify that the problem occurred when setting the environment variable XZ_OPT="--threads=2", and that this patch fixes the bug. Committed to mainline. Ian * elf.c (elf_uncompress_lzma_block): Skip all header padding bytes and verify that they are zero. 23f9fbed3c97ed70d2615d7d3fa7c249cc862553 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index f4527e2477d..7841c86cd9c 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -5568,6 +5568,7 @@ elf_uncompress_lzma_block (const unsigned char *compressed, uint64_t header_compressed_size; uint64_t header_uncompressed_size; unsigned char lzma2_properties; + size_t crc_offset; uint32_t computed_crc; uint32_t stream_crc; size_t uncompressed_offset; @@ -5671,19 +5672,20 @@ elf_uncompress_lzma_block (const unsigned char *compressed, /* The properties describe the dictionary size, but we don't care what that is. */ - /* Block header padding. */ - if (unlikely (off + 4 > compressed_size)) + /* Skip to just before CRC, verifying zero bytes in between. */ + crc_offset = block_header_offset + block_header_size - 4; + if (unlikely (crc_offset + 4 > compressed_size)) { elf_uncompress_failed (); return 0; } - - off = (off + 3) &~ (size_t) 3; - - if (unlikely (off + 4 > compressed_size)) + for (; off < crc_offset; off++) { - elf_uncompress_failed (); - return 0; + if (compressed[off] != 0) + { + elf_uncompress_failed (); + return 0; + } } /* Block header CRC. */
Re: libbacktrace patch committed: Read symbol table of debuginfo file
On Thu, Feb 29, 2024 at 7:47 PM Ian Lance Taylor wrote: > > This patch to libbacktrace reads symbol tables from debuginfo files. > These become another symbol table to search. This is needed if people > use --strip-all rather than --strip-debug when adding a debuglink > section. This fixes > https://github.com/ianlancetaylor/libbacktrace/issues/113. > Bootstrapped and ran libbacktrace and libgo tests on > x86_64-pc-linux-gnu. Committed to mainline. This introduced a bug on the PPC v1 ABI, where libbacktrace uses the .opd section to convert from a function descriptor address to a code address. The .opd section is missing from a debuginfo file. This patch changes the code to use the original .opd section if it is missing. Checked on powerpc64-linux-gnu and x86_64-pc-linux-gnu. Committed to mainline. Ian PR libbacktrace/114201 * elf.c (elf_add): Add caller_opd parameter. Change all callers. Release opd data after all recursive calls. f692b338cd27a4e0d38fcb5af3d416cd66fbf814 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 664937e1438..f4527e2477d 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -6501,8 +6501,9 @@ backtrace_uncompress_lzma (struct backtrace_state *state, static int elf_add (struct backtrace_state *state, const char *filename, int descriptor, const unsigned char *memory, size_t memory_size, -uintptr_t base_address, backtrace_error_callback error_callback, -void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf, +uintptr_t base_address, struct elf_ppc64_opd_data *caller_opd, +backtrace_error_callback error_callback, void *data, +fileline *fileline_fn, int *found_sym, int *found_dwarf, struct dwarf_data **fileline_entry, int exe, int debuginfo, const char *with_buildid_data, uint32_t with_buildid_size) { @@ -6557,6 +6558,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, struct elf_view split_debug_view[DEBUG_MAX]; unsigned char split_debug_view_valid[DEBUG_MAX]; struct elf_ppc64_opd_data opd_data, *opd; + int opd_view_valid; struct dwarf_sections dwarf_sections; if (!debuginfo) @@ -6584,6 +6586,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, debug_view_valid = 0; memset (_debug_view_valid[0], 0, sizeof split_debug_view_valid); opd = NULL; + opd_view_valid = 0; if (!elf_get_view (state, descriptor, memory, memory_size, 0, sizeof ehdr, error_callback, data, _view)) @@ -6867,9 +6870,15 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, opd->addr = shdr->sh_addr; opd->data = (const char *) opd_data.view.view.data; opd->size = shdr->sh_size; + opd_view_valid = 1; } } + // A debuginfo file may not have a useful .opd section, but we can use the + // one from the original executable. + if (opd == NULL) +opd = caller_opd; + if (symtab_shndx == 0) symtab_shndx = dynsym_shndx; if (symtab_shndx != 0) @@ -6948,9 +6957,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, elf_release_view (state, _view, error_callback, data); if (debugaltlink_view_valid) elf_release_view (state, _view, error_callback, data); - ret = elf_add (state, "", d, NULL, 0, base_address, error_callback, -data, fileline_fn, found_sym, found_dwarf, NULL, 0, -1, NULL, 0); + ret = elf_add (state, "", d, NULL, 0, base_address, opd, +error_callback, data, fileline_fn, found_sym, +found_dwarf, NULL, 0, 1, NULL, 0); if (ret < 0) backtrace_close (d, error_callback, data); else if (descriptor >= 0) @@ -6965,12 +6974,6 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, buildid_view_valid = 0; } - if (opd) -{ - elf_release_view (state, >view, error_callback, data); - opd = NULL; -} - if (debuglink_name != NULL) { int d; @@ -6985,9 +6988,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, elf_release_view (state, _view, error_callback, data); if (debugaltlink_view_valid) elf_release_view (state, _view, error_callback, data); - ret = elf_add (state, "", d, NULL, 0, base_address, error_callback, -data, fileline_fn, found_sym, found_dwarf, NULL, 0, -1, NULL, 0); + ret = elf_add (state, "", d, NULL, 0, base_address, opd, +error_callback, data, fileline_fn, found_sym, +found_dwarf, NULL, 0, 1, NULL, 0); if (ret < 0) backtrace_close (d, error_callback, data); else if (descriptor >= 0) @@ -7013,7 +7016,7 @@ elf_add (struct
libbacktrace patch committed: Read symbol table of debuginfo file
This patch to libbacktrace reads symbol tables from debuginfo files. These become another symbol table to search. This is needed if people use --strip-all rather than --strip-debug when adding a debuglink section. This fixes https://github.com/ianlancetaylor/libbacktrace/issues/113. Bootstrapped and ran libbacktrace and libgo tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * elf.c (elf_add): Add the symbol table from a debuginfo file. * Makefile.am (MAKETESTS): Add buildidfull and gnudebuglinkfull variants of buildid and gnudebuglink tests. (%_gnudebuglinkfull, %_buildidfull): New patterns. * Makefile.in: Regenerate. 24810fbf7b0ce274dfa46cc362305ac77ee5a72c diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index 16a72d2abf7..750ed80ed05 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -257,7 +257,7 @@ b2test_LDFLAGS = -Wl,--build-id b2test_LDADD = libbacktrace_elf_for_test.la check_PROGRAMS += b2test -MAKETESTS += b2test_buildid +MAKETESTS += b2test_buildid b2test_buildidfull if HAVE_DWZ @@ -267,7 +267,7 @@ b3test_LDFLAGS = -Wl,--build-id b3test_LDADD = libbacktrace_elf_for_test.la check_PROGRAMS += b3test -MAKETESTS += b3test_dwz_buildid +MAKETESTS += b3test_dwz_buildid b3test_dwz_buildidfull endif HAVE_DWZ @@ -443,12 +443,16 @@ endif HAVE_PTHREAD if HAVE_OBJCOPY_DEBUGLINK -MAKETESTS += btest_gnudebuglink +MAKETESTS += btest_gnudebuglink btest_gnudebuglinkfull %_gnudebuglink: % $(OBJCOPY) --only-keep-debug $< $@.debug $(OBJCOPY) --strip-debug --add-gnu-debuglink=$@.debug $< $@ +%_gnudebuglinkfull: % + $(OBJCOPY) --only-keep-debug $< $@.debug + $(OBJCOPY) --strip-all --add-gnu-debuglink=$@.debug $< $@ + endif HAVE_OBJCOPY_DEBUGLINK %_buildid: % @@ -457,6 +461,12 @@ endif HAVE_OBJCOPY_DEBUGLINK $< $(OBJCOPY) --strip-debug $< $@ +%_buildidfull: % + ./install-debuginfo-for-buildid.sh \ + "$(TEST_BUILD_ID_DIR)" \ + $< + $(OBJCOPY) --strip-all $< $@ + if HAVE_COMPRESSED_DEBUG ctestg_SOURCES = btest.c testlib.c diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index c506cc29fe1..664937e1438 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -6872,7 +6872,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if (symtab_shndx == 0) symtab_shndx = dynsym_shndx; - if (symtab_shndx != 0 && !debuginfo) + if (symtab_shndx != 0) { const b_elf_shdr *symtab_shdr; unsigned int strtab_shndx;
libbacktrace patch committed
This libbacktrace patch, based on one by Andres Freund, uses the _pgmptr variable declared on Windows to find the executable file name if none is specified. Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Patch from Andres Freund: * configure.ac: Check for _pgmptr declaration. * fileline.c (fileline_initialize): Check for _pgmfptr before /proc/self/exec. * configure, config.h.in: Regenerate. a349ba16f18b66b70c7a1bdb1ab5c5b6247676da diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 39e6bf41e35..72ff2b30053 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -407,6 +407,9 @@ if test "$have_getexecname" = "yes"; then AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.]) fi +# Check for _pgmptr variable, contains the executable filename on windows +AC_CHECK_DECLS([_pgmptr]) + # Check for sysctl definitions. AC_CACHE_CHECK([for KERN_PROC], diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index 674bf33cdcf..0e560b44e7a 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -155,6 +155,16 @@ macho_get_executable_path (struct backtrace_state *state, #endif /* !defined (HAVE_MACH_O_DYLD_H) */ +#if HAVE_DECL__PGMPTR + +#define windows_executable_filename() _pgmptr + +#else /* !HAVE_DECL__PGMPTR */ + +#define windows_executable_filename() NULL + +#endif /* !HAVE_DECL__PGMPTR */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -192,7 +202,7 @@ fileline_initialize (struct backtrace_state *state, descriptor = -1; called_error_callback = 0; - for (pass = 0; pass < 8; ++pass) + for (pass = 0; pass < 9; ++pass) { int does_not_exist; @@ -205,23 +215,28 @@ fileline_initialize (struct backtrace_state *state, filename = getexecname (); break; case 2: - filename = "/proc/self/exe"; + /* Test this before /proc/self/exe, as the latter exists but points +to the wine binary (and thus doesn't work). */ + filename = windows_executable_filename (); break; case 3: - filename = "/proc/curproc/file"; + filename = "/proc/self/exe"; break; case 4: + filename = "/proc/curproc/file"; + break; + case 5: snprintf (buf, sizeof (buf), "/proc/%ld/object/a.out", (long) getpid ()); filename = buf; break; - case 5: + case 6: filename = sysctl_exec_name1 (state, error_callback, data); break; - case 6: + case 7: filename = sysctl_exec_name2 (state, error_callback, data); break; - case 7: + case 8: filename = macho_get_executable_path (state, error_callback, data); break; default:
libbacktrace patch committed: Tweaks to zstd decompression
In looking over the recently committed support for zstd decompression in libbacktrace, I found a few minor cases that needed fixing. Bootstrapped and tested on x86_64-pc-linux-gnu. Committed to mainline. Ian * elf.c (elf_zstd_read_fse): Call elf_fetch_bits after reading bits, not before. Add unlikely for error case. (elf_zstd_offset_table): Regenerate. (elf_zstd_read_huff): Clear 13 entries in weight_mark, not 12. (elf_zstd_read_literals): For a single stream adjust by total_streams_size, not compressed_size. 2e71f05403c36d25216107a7ae43c7055a282d73 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index efd509bba6b..665b3dd1a53 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -2806,18 +2806,18 @@ elf_zstd_read_fse (const unsigned char **ppin, const unsigned char *pinend, while ((val & 0xfff) == 0xfff) { zidx += 3 * 6; - if (!elf_fetch_bits (, pinend, , )) - return 0; val >>= 12; bits -= 12; + if (!elf_fetch_bits (, pinend, , )) + return 0; } while ((val & 3) == 3) { zidx += 3; - if (!elf_fetch_bits (, pinend, , )) - return 0; val >>= 2; bits -= 2; + if (!elf_fetch_bits (, pinend, , )) + return 0; } /* We have at least 13 bits here, don't need to fetch. */ zidx += val & 3; @@ -2947,7 +2947,7 @@ elf_zstd_build_fse (const int16_t *norm, int idx, uint16_t *next, pos = (pos + step) & mask; } } - if (pos != 0) + if (unlikely (pos != 0)) { elf_uncompress_failed (); return 0; @@ -3423,17 +3423,17 @@ static const struct elf_zstd_fse_baseline_entry elf_zstd_match_table[64] = static const struct elf_zstd_fse_baseline_entry elf_zstd_offset_table[32] = { - { 1, 0, 5, 0 }, { 64, 6, 4, 0 }, { 512, 9, 5, 0 }, - { 32768, 15, 5, 0 }, { 2097152, 21, 5, 0 }, { 8, 3, 5, 0 }, - { 128, 7, 4, 0 }, { 4096, 12, 5, 0 }, { 262144, 18, 5, 0 }, - { 8388608, 23, 5, 0 }, { 32, 5, 5, 0 }, { 256, 8, 4, 0 }, - { 16384, 14, 5, 0 }, { 1048576, 20, 5, 0 }, { 4, 2, 5, 0 }, - { 128, 7, 4, 16 }, { 2048, 11, 5, 0 }, { 131072, 17, 5, 0 }, - { 4194304, 22, 5, 0 }, { 16, 4, 5, 0 }, { 256, 8, 4, 16 }, - { 8192, 13, 5, 0 }, { 524288, 19, 5, 0 }, { 2, 1, 5, 0 }, - { 64, 6, 4, 16 }, { 1024, 10, 5, 0 }, { 65536, 16, 5, 0 }, - { 268435456, 28, 5, 0 }, { 134217728, 27, 5, 0 }, { 67108864, 26, 5, 0 }, - { 33554432, 25, 5, 0 }, { 16777216, 24, 5, 0 }, + { 1, 0, 5, 0 }, { 61, 6, 4, 0 }, { 509, 9, 5, 0 }, + { 32765, 15, 5, 0 }, { 2097149, 21, 5, 0 }, { 5, 3, 5, 0 }, + { 125, 7, 4, 0 }, { 4093, 12, 5, 0 }, { 262141, 18, 5, 0 }, + { 8388605, 23, 5, 0 }, { 29, 5, 5, 0 }, { 253, 8, 4, 0 }, + { 16381, 14, 5, 0 }, { 1048573, 20, 5, 0 }, { 1, 2, 5, 0 }, + { 125, 7, 4, 16 }, { 2045, 11, 5, 0 }, { 131069, 17, 5, 0 }, + { 4194301, 22, 5, 0 }, { 13, 4, 5, 0 }, { 253, 8, 4, 16 }, + { 8189, 13, 5, 0 }, { 524285, 19, 5, 0 }, { 2, 1, 5, 0 }, + { 61, 6, 4, 16 }, { 1021, 10, 5, 0 }, { 65533, 16, 5, 0 }, + { 268435453, 28, 5, 0 }, { 134217725, 27, 5, 0 }, { 67108861, 26, 5, 0 }, + { 33554429, 25, 5, 0 }, { 16777213, 24, 5, 0 }, }; /* Read a zstd Huffman table and build the decoding table in *TABLE, reading @@ -3618,7 +3618,7 @@ elf_zstd_read_huff (const unsigned char **ppin, const unsigned char *pinend, } weight_mark = (uint32_t *) (weights + 256); - memset (weight_mark, 0, 12 * sizeof (uint32_t)); + memset (weight_mark, 0, 13 * sizeof (uint32_t)); weight_mask = 0; for (i = 0; i < count; ++i) { @@ -3685,7 +3685,7 @@ elf_zstd_read_huff (const unsigned char **ppin, const unsigned char *pinend, /* Change WEIGHT_MARK from a count of weights to the index of the first symbol for that weight. We shift the indexes to also store how many we - hae seen so far, below. */ + have seen so far, below. */ { uint32_t next; @@ -3766,7 +3766,7 @@ elf_zstd_read_literals (const unsigned char **ppin, { int raw; - /* Raw_literals_Block or RLE_Literals_Block */ + /* Raw_Literals_Block or RLE_Literals_Block */ raw = (hdr & 3) == 0; @@ -3948,7 +3948,7 @@ elf_zstd_read_literals (const unsigned char **ppin, unsigned int bits; uint32_t i; - pback = pin + compressed_size - 1; + pback = pin + total_streams_size - 1; pbackend = pin; if (!elf_fetch_backward_init (, pbackend, , )) return 0;
libbacktrace patch committed: Only test --build-id if supported
PR 108297 points out that there are systems that use ELF but for which the linker does not support the --build-id option. This libbacktrace patch skips --build-id tests when it doesn't work. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian PR libbacktrace/108297 * configure.ac: Test whether linker supports --build-id. * Makefile.am: Only run --build-id tests if supported. * configure, Makefile.in: Regenerate. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index 047b573c29a..1c4ac2baeb6 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -248,6 +248,7 @@ check_DATA += allocfail.dSYM endif USE_DSYMUTIL if HAVE_ELF +if HAVE_BUILDID if HAVE_OBJCOPY_DEBUGLINK b2test_SOURCES = $(btest_SOURCES) @@ -271,6 +272,7 @@ MAKETESTS += b3test_dwz_buildid endif HAVE_DWZ endif HAVE_OBJCOPY_DEBUGLINK +endif HAVE_BUILDID endif HAVE_ELF btest_SOURCES = btest.c testlib.c diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index d0a0475cfa8..28e3a688c24 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -484,7 +484,18 @@ AC_CHECK_LIB([z], [compress], [AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.])]) AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes) -dnl Test whether the linker supports the --compress_debug_sections option. +dnl Test whether the linker supports the --build-id option. +AC_CACHE_CHECK([whether --build-id is supported], +[libbacktrace_cv_ld_buildid], +[LDFLAGS_hold=$LDFLAGS +LDFLAGS="$LDFLAGS -Wl,--build-id" +AC_LINK_IFELSE([AC_LANG_PROGRAM(,)], +[libbacktrace_cv_ld_buildid=yes], +[libbacktrace_cv_ld_buildid=no]) +LDFLAGS=$LDFLAGS_hold]) +AM_CONDITIONAL(HAVE_BUILDID, test "$libbacktrace_cv_ld_buildid" = yes) + +dnl Test whether the linker supports the --compress-debug-sections option. AC_CACHE_CHECK([whether --compress-debug-sections is supported], [libgo_cv_ld_compress], [LDFLAGS_hold=$LDFLAGS
libbacktrace patch committed: Check for sys/link.h
Apparently QNX declares dl_iterate_phdr and friends in sys/link.h rather than link.h. This patch updates libbacktrace to check there. This fixes https://github.com/ianlancetaylor/libbacktrace/issues/86. Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian * configure.ac: Check for sys/link.h. Use either link.h or sys/link.h when checking for dl_iterate_phdr. * elf.c: Include sys/link.h if available. * configure, config.h.in: Regenerate. bab8b6e52fb0b48b5d9d1af5f93e5c8fb20d6240 diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 857987a2859..1daaa2f62d2 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -335,13 +335,17 @@ fi AC_SUBST(BACKTRACE_USES_MALLOC) # Check for dl_iterate_phdr. -AC_CHECK_HEADERS(link.h) -if test "$ac_cv_header_link_h" = "no"; then +AC_CHECK_HEADERS(link.h sys/link.h) +if test "$ac_cv_header_link_h" = "no" -a "$ac_cv_header_sys_link_h" = "no"; then have_dl_iterate_phdr=no else if test -n "${with_target_subdir}"; then +link_h=link.h +if test "$ac_cv_header_link_h" = "no"; then + link_h=sys/link.h +fi # When built as a GCC target library, we can't do a link test. -AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes], +AC_EGREP_HEADER([dl_iterate_phdr], [$link_h], [have_dl_iterate_phdr=yes], [have_dl_iterate_phdr=no]) else AC_CHECK_FUNC([dl_iterate_phdr], [have_dl_iterate_phdr=yes], diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 8b82dd45875..181d195fe35 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -40,7 +40,12 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef HAVE_DL_ITERATE_PHDR -#include + #ifdef HAVE_LINK_H + #include + #endif + #ifdef HAVE_SYS_LINK_H + #include + #endif #endif #include "backtrace.h"
libbacktrace patch committed: Don't exit Mach-O dyld loop on failure
This libbacktrace patch changes the loop over dynamic libraries on Mach-O to keep going if we fail to find the debug info for a particular library. We can still pick up debug info for other libraries even if one fails. Tested on x86_64-pc-linux-gnu which admittedly does little, but others have tested it on Mach-o. Committed to mainline. Ian * macho.c (backtrace_initialize) [HAVE_MACH_O_DYLD_H]: Don't exit loop if we can't find debug info for one shared library. d8ddf1fa098fa50929ea0a1569a8e38d80fadbaf diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c index 3f40811719e..16f406507d2 100644 --- a/libbacktrace/macho.c +++ b/libbacktrace/macho.c @@ -1268,7 +1268,7 @@ backtrace_initialize (struct backtrace_state *state, const char *filename, mff = macho_nodebug; if (!macho_add (state, name, d, 0, NULL, base_address, 0, error_callback, data, , )) - return 0; + continue; if (mff != macho_nodebug) macho_fileline_fn = mff;
libbacktrace patch committed: Don't let "make clean" remove allocfail.sh
The script allocfail.sh was being incorrectly removed by "make clean". This patch fixes the problem. This fixes https://github.com/ianlancetaylor/libbacktrace/issues/81. Ran libbacktrace "make check" and "make clean" on x86_64-pc-linux-gnu. Committed to mainline. Ian For https://github.com/ianlancetaylor/libbacktrace/issues/81 * Makefile.am (MAKETESTS): New variable split out of TESTS. (CLEANFILES): Replace TESTS with BUILDTESTS and MAKETESTS. * Makefile.in: Regenerate. 9ed57796235abcd24e06b1ce10fe72c3d0d07cc5 diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index bf507b73918..9f8516d00e2 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -85,13 +85,19 @@ libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) # Testsuite. -# Add a test to this variable if you want it to be built. +# Add a test to this variable if you want it to be built as a program, +# with SOURCES, etc. check_PROGRAMS = # Add a test to this variable if you want it to be run. TESTS = -# Add a test to this variable if you want it to be built and run. +# Add a test to this variable if you want it to be built as a Makefile +# target and run. +MAKETESTS = + +# Add a test to this variable if you want it to be built as a program, +# with SOURCES, etc., and run. BUILDTESTS = # Add a file to this variable if you want it to be built for testing. @@ -250,7 +256,7 @@ b2test_LDFLAGS = -Wl,--build-id b2test_LDADD = libbacktrace_elf_for_test.la check_PROGRAMS += b2test -TESTS += b2test_buildid +MAKETESTS += b2test_buildid if HAVE_DWZ @@ -260,7 +266,7 @@ b3test_LDFLAGS = -Wl,--build-id b3test_LDADD = libbacktrace_elf_for_test.la check_PROGRAMS += b3test -TESTS += b3test_dwz_buildid +MAKETESTS += b3test_dwz_buildid endif HAVE_DWZ @@ -311,11 +317,11 @@ if HAVE_DWZ cp $< $@; \ fi -TESTS += btest_dwz +MAKETESTS += btest_dwz if HAVE_OBJCOPY_DEBUGLINK -TESTS += btest_dwz_gnudebuglink +MAKETESTS += btest_dwz_gnudebuglink endif HAVE_OBJCOPY_DEBUGLINK @@ -416,7 +422,7 @@ endif HAVE_PTHREAD if HAVE_OBJCOPY_DEBUGLINK -TESTS += btest_gnudebuglink +MAKETESTS += btest_gnudebuglink %_gnudebuglink: % $(OBJCOPY) --only-keep-debug $< $@.debug @@ -494,7 +500,7 @@ endif USE_DSYMUTIL if HAVE_MINIDEBUG -TESTS += mtest_minidebug +MAKETESTS += mtest_minidebug %_minidebug: % $(NM) -D $< -P --defined-only | $(AWK) '{ print $$1 }' | sort > $<.dsyms @@ -536,10 +542,11 @@ endif HAVE_ELF check_PROGRAMS += $(BUILDTESTS) -TESTS += $(BUILDTESTS) +TESTS += $(MAKETESTS) $(BUILDTESTS) CLEANFILES = \ - $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build \ + $(MAKETESTS) $(BUILDTESTS) *.debug elf_for_test.c edtest2_build.c \ + gen_edtest2_build \ *.dsyms *.fsyms *.keepsyms *.dbg *.mdbg *.mdbg.xz *.strip clean-local:
libbacktrace patch committed: Update README
This patch updates the libbacktrace README to a near copy of the one from github.com/ianlancetaylor/libbacktrace. Committed to mainline. This fixes GCC PR 105721. Ian * README: Update. 6cf19361732bd7f8b41716ef9f4b5c205a3193b8 diff --git a/libbacktrace/README b/libbacktrace/README index e8b225745c9..6225f92b855 100644 --- a/libbacktrace/README +++ b/libbacktrace/README @@ -1,23 +1,31 @@ The libbacktrace library -Initially written by Ian Lance Taylor +Initially written by Ian Lance Taylor The libbacktrace library may be linked into a program or library and -used to produce symbolic backtraces. Sample uses would be to print a -detailed backtrace when an error occurs or to gather detailed -profiling information. +used to produce symbolic backtraces. +Sample uses would be to print a detailed backtrace when an error +occurs or to gather detailed profiling information. +In general the functions provided by this library are async-signal-safe, +meaning that they may be safely called from a signal handler. -The libbacktrace library is provided under a BSD license. See the -source files for the exact license text. +The libbacktrace library is provided under a BSD license. +See the source files for the exact license text. The public functions are declared and documented in the header file backtrace.h, which should be #include'd by a user of the library. Building libbacktrace will generate a file backtrace-supported.h, which a user of the library may use to determine whether backtraces -will work. See the source file backtrace-supported.h.in for the -macros that it defines. +will work. +See the source file backtrace-supported.h.in for the macros that it +defines. -As of September 2012, libbacktrace only supports ELF executables with -DWARF debugging information. The library is written to make it -straightforward to add support for other object file and debugging -formats. +As of October 2020, libbacktrace supports ELF, PE/COFF, Mach-O, and +XCOFF executables with DWARF debugging information. +In other words, it supports GNU/Linux, *BSD, macOS, Windows, and AIX. +The library is written to make it straightforward to add support for +other object file and debugging formats. + +The library relies on the C++ unwind API defined at +https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html +This API is provided by GCC and clang.
libbacktrace patch committed: don't skip aligned byte
This libbacktrace patch by Rui Ueyama fixes handling an uncompressed block that starts at an aligned byte. If the bits before the uncompressed block ended at a byte boundary, libbacktrace accidentally skipped the next byte, which is the first byte of the length of the block. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * elf.c (elf_zlib_inflate): Don't skip initial aligned byte in uncompressed block. 584ae0f0eea2a162dc02984c5976d5cbab5cd1e7 diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 5c7c21a8da7..8b82dd45875 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -1796,7 +1796,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, /* An uncompressed block. */ /* If we've read ahead more than a byte, back up. */ - while (bits > 8) + while (bits >= 8) { --pin; bits -= 8;
libbacktrace patch committed: Handle skeleton units
This libbacktrace patch handles DWARF 5 skeleton units, which are used when part of the DWARF information is stored in a separate file. This doesn't actually look in the separate file, as the line number information, which is all that we care about, is normally kept in the main executable because it needs relocations. For this patch bootstrapped and ran libbacktrace and Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian * dwarf.c (find_address_ranges): Handle skeleton units. (read_function_entry): Likewise. 3c16999f983331301384f51fc1cdc04f7d51ef6c diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 2158bc14065..45cc9e77e40 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -1989,14 +1989,16 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, break; case DW_AT_stmt_list: - if (abbrev->tag == DW_TAG_compile_unit + if ((abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) && (val.encoding == ATTR_VAL_UINT || val.encoding == ATTR_VAL_REF_SECTION)) u->lineoff = val.u.uint; break; case DW_AT_name: - if (abbrev->tag == DW_TAG_compile_unit) + if (abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) { name_val = val; have_name_val = 1; @@ -2004,7 +2006,8 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, break; case DW_AT_comp_dir: - if (abbrev->tag == DW_TAG_compile_unit) + if (abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) { comp_dir_val = val; have_comp_dir_val = 1; @@ -2012,19 +2015,22 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, break; case DW_AT_str_offsets_base: - if (abbrev->tag == DW_TAG_compile_unit + if ((abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) && val.encoding == ATTR_VAL_REF_SECTION) u->str_offsets_base = val.u.uint; break; case DW_AT_addr_base: - if (abbrev->tag == DW_TAG_compile_unit + if ((abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) && val.encoding == ATTR_VAL_REF_SECTION) u->addr_base = val.u.uint; break; case DW_AT_rnglists_base: - if (abbrev->tag == DW_TAG_compile_unit + if ((abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) && val.encoding == ATTR_VAL_REF_SECTION) u->rnglists_base = val.u.uint; break; @@ -2052,7 +2058,8 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, } if (abbrev->tag == DW_TAG_compile_unit - || abbrev->tag == DW_TAG_subprogram) + || abbrev->tag == DW_TAG_subprogram + || abbrev->tag == DW_TAG_skeleton_unit) { if (!add_ranges (state, dwarf_sections, base_address, is_bigendian, u, pcrange.lowpc, , @@ -2060,9 +2067,10 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, (void *) addrs)) return 0; - /* If we found the PC range in the DW_TAG_compile_unit, we -can stop now. */ - if (abbrev->tag == DW_TAG_compile_unit + /* If we found the PC range in the DW_TAG_compile_unit or +DW_TAG_skeleton_unit, we can stop now. */ + if ((abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) && (pcrange.have_ranges || (pcrange.have_lowpc && pcrange.have_highpc))) return 1; @@ -3274,7 +3282,8 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, /* The compile unit sets the base address for any address ranges in the function entries. */ - if (abbrev->tag == DW_TAG_compile_unit + if ((abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_skeleton_unit) && abbrev->attrs[i].name == DW_AT_low_pc) { if (val.encoding == ATTR_VAL_ADDRESS)
libbacktrace patch committed: Initialize DWARF 5 fields of unit
When I added the DWARF 5 support to libbacktrace in 2019-12-13 I forgot to initialize the new fields of the unit data structure. Whoops. Fixed with this patch. Bootstrapped and ran libbacktrace and Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian * dwarf.c (build_address_map): Initialize DWARF 5 fields of unit. ab59cb2055658a72fdccba0be76eeadd222ffef6 diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index c0bae0e501e..2158bc14065 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -2221,6 +2221,9 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, u->comp_dir = NULL; u->abs_filename = NULL; u->lineoff = 0; + u->str_offsets_base = 0; + u->addr_base = 0; + u->rnglists_base = 0; /* The actual line number mappings will be read as needed. */ u->lines = NULL;
libbacktrace patch committed: Don't special case file 0
This libbacktrace patch stops special casing file 0. It's no longer necessary as for DWARF 5 support we now set up filename 0 in all cases. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * dwarf.c (read_line_program): Don't special case file 0. (read_function_entry): Likewise. b3176ab8787a7f988a931e26bce9227edd2e6d1a diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 546b4b26a32..e6b1f238cd3 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -2857,20 +2857,15 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, uint64_t fileno; fileno = read_uleb128 (line_buf); - if (fileno == 0) - filename = ""; - else + if (fileno >= hdr->filenames_count) { - if (fileno >= hdr->filenames_count) - { - dwarf_buf_error (line_buf, -("invalid file number in " - "line number program"), -0); - return 0; - } - filename = hdr->filenames[fileno]; + dwarf_buf_error (line_buf, +("invalid file number in " + "line number program"), +0); + return 0; } + filename = hdr->filenames[fileno]; } break; case DW_LNS_set_column: @@ -3298,21 +3293,15 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, case DW_AT_call_file: if (val.encoding == ATTR_VAL_UINT) { - if (val.u.uint == 0) - function->caller_filename = ""; - else + if (val.u.uint >= lhdr->filenames_count) { - if (val.u.uint >= lhdr->filenames_count) - { - dwarf_buf_error (unit_buf, - ("invalid file number in " - "DW_AT_call_file attribute"), - 0); - return 0; - } - function->caller_filename = - lhdr->filenames[val.u.uint]; + dwarf_buf_error (unit_buf, + ("invalid file number in " + "DW_AT_call_file attribute"), + 0); + return 0; } + function->caller_filename = lhdr->filenames[val.u.uint]; } break;
libbacktrace patch committed: Pass -1 to error callback for unknown DWARF
This libbacktrace patch passes -1 to the error callback function for unknown DWARF versions. This makes users of libbacktrace treat DWARF versions that libbacktrace does not support as though no debug information were available. This fixes PR 98818. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * dwarf.c (dwarf_buf_error): Add errnum parameter. Change all callers. * backtrace.h: Update backtrace_error_callback comment. df003d1e0bf2d0a8e2ed45a323d4e974b15dc95f diff --git a/libbacktrace/backtrace.h b/libbacktrace/backtrace.h index 2814763f417..caaa66d3686 100644 --- a/libbacktrace/backtrace.h +++ b/libbacktrace/backtrace.h @@ -71,13 +71,14 @@ struct backtrace_state; invalid after this function returns. As a special case, the ERRNUM argument will be passed as -1 if no - debug info can be found for the executable, but the function - requires debug info (e.g., backtrace_full, backtrace_pcinfo). The - MSG in this case will be something along the lines of "no debug - info". Similarly, ERRNUM will be passed as -1 if there is no - symbol table, but the function requires a symbol table (e.g., - backtrace_syminfo). This may be used as a signal that some other - approach should be tried. */ + debug info can be found for the executable, or if the debug info + exists but has an unsupported version, but the function requires + debug info (e.g., backtrace_full, backtrace_pcinfo). The MSG in + this case will be something along the lines of "no debug info". + Similarly, ERRNUM will be passed as -1 if there is no symbol table, + but the function requires a symbol table (e.g., backtrace_syminfo). + This may be used as a signal that some other approach should be + tried. */ typedef void (*backtrace_error_callback) (void *data, const char *msg, int errnum); diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 9097df6cc76..546b4b26a32 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -410,13 +410,13 @@ struct dwarf_data /* Report an error for a DWARF buffer. */ static void -dwarf_buf_error (struct dwarf_buf *buf, const char *msg) +dwarf_buf_error (struct dwarf_buf *buf, const char *msg, int errnum) { char b[200]; snprintf (b, sizeof b, "%s in %s at %d", msg, buf->name, (int) (buf->buf - buf->start)); - buf->error_callback (buf->data, b, 0); + buf->error_callback (buf->data, b, errnum); } /* Require at least COUNT bytes in BUF. Return 1 if all is well, 0 on @@ -430,7 +430,7 @@ require (struct dwarf_buf *buf, size_t count) if (!buf->reported_underflow) { - dwarf_buf_error (buf, "DWARF underflow"); + dwarf_buf_error (buf, "DWARF underflow", 0); buf->reported_underflow = 1; } @@ -592,7 +592,7 @@ read_address (struct dwarf_buf *buf, int addrsize) case 8: return read_uint64 (buf); default: - dwarf_buf_error (buf, "unrecognized address size"); + dwarf_buf_error (buf, "unrecognized address size", 0); return 0; } } @@ -643,7 +643,7 @@ read_uleb128 (struct dwarf_buf *buf) ret |= ((uint64_t) (b & 0x7f)) << shift; else if (!overflow) { - dwarf_buf_error (buf, "LEB128 overflows uint64_t"); + dwarf_buf_error (buf, "LEB128 overflows uint64_t", 0); overflow = 1; } shift += 7; @@ -678,7 +678,7 @@ read_sleb128 (struct dwarf_buf *buf) val |= ((uint64_t) (b & 0x7f)) << shift; else if (!overflow) { - dwarf_buf_error (buf, "signed LEB128 overflows uint64_t"); + dwarf_buf_error (buf, "signed LEB128 overflows uint64_t", 0); overflow = 1; } shift += 7; @@ -818,7 +818,7 @@ read_attribute (enum dwarf_form form, uint64_t implicit_val, offset = read_offset (buf, is_dwarf64); if (offset >= dwarf_sections->size[DEBUG_STR]) { - dwarf_buf_error (buf, "DW_FORM_strp out of range"); + dwarf_buf_error (buf, "DW_FORM_strp out of range", 0); return 0; } val->encoding = ATTR_VAL_STRING; @@ -833,7 +833,7 @@ read_attribute (enum dwarf_form form, uint64_t implicit_val, offset = read_offset (buf, is_dwarf64); if (offset >= dwarf_sections->size[DEBUG_LINE_STR]) { - dwarf_buf_error (buf, "DW_FORM_line_strp out of range"); + dwarf_buf_error (buf, "DW_FORM_line_strp out of range", 0); return 0; } val->encoding = ATTR_VAL_STRING; @@ -880,7 +880,8 @@ read_attribute (enum dwarf_form form, uint64_t implicit_val, if (form == DW_FORM_implicit_const) { dwarf_buf_error (buf, -"DW_FORM_indirect to DW_FORM_implicit_const"); +"DW_FORM_indirect to DW_FORM_implicit_const", +0); return 0; } return
libbacktrace patch committed: Use objcopy --help to check for option
This patch changes the libbacktrace configure script to check for whether objcopy supports --add-gnu-debuglink (a test that only affects the libbacktrace testsuite) to look at the objcopy --help option rather than trying to apply --add-gnu-debuglink to /bin/ls. The latter can trigger a warning if /bin/ls already has a separate debug file. Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian * configure.ac: Check for objcopy --add-gnu-debuglink by using objcopy --help. * configure: Regenerate diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 83d4733509a..43a33a66b82 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -500,8 +500,7 @@ AC_CACHE_CHECK([whether objcopy supports debuglink], libbacktrace_cv_objcopy_debuglink=no elif ! test -n "${OBJCOPY}"; then libbacktrace_cv_objcopy_debuglink=no -elif ${OBJCOPY} --add-gnu-debuglink=x /bin/ls /tmp/ls$$; then - rm -f /tmp/ls$$ +elif ${OBJCOPY} --help | fgrep add-gnu-debuglink >/dev/null 2>&1; then libbacktrace_cv_objcopy_debuglink=yes else libbacktrace_cv_objcopy_debuglink=no
libbacktrace patch committed: Don't fail tests if dwz fails
On my system the current version of dwz fails on some DWARF 5 input. This is reportedly fixed by https://sourceware.org/pipermail/dwz/2021q1/000775.html, but in the meantime there is no reason for the libbacktrace testsuite to fail just because dwz fails. This patch changes the Makefile so that if dwz fails, we just use the uncompressed debug info. The test becomes meaningless, but at least it passes. And it will continue to test dwz information for cases where dwz works. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. (This commit also regenerates configure, which was not correct regenerated by an earlier commit. The only difference is some #line directives.) Ian * Makefile.am (%_dwz): If dwz fails, use uncompressed debug info. * Makefile.in: Regenerate. * configure: Regenerate. bfde774667fbce6d7d326c8a36a098138e224a95 diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index e1e55009f09..8874f41338a 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -303,9 +303,13 @@ if HAVE_DWZ rm -f $@ $@_common.debug cp $< $@_1 cp $< $@_2 - $(DWZ) -m $@_common.debug $@_1 $@_2 - rm -f $@_2 - mv $@_1 $@ + if $(DWZ) -m $@_common.debug $@_1 $@_2; then \ + rm -f $@_2; \ + mv $@_1 $@; \ + else \ + echo "Ignoring dwz errors, assuming that test passes"; \ + cp $< $@; \ + fi TESTS += btest_dwz
libbacktrace patch committed: Use correct DWARF-5 filename index
This libbacktrace patch uses the correct directory and filename index for DWARF 5. For DWARF 4 and before, the zero entry for the directory and filename information stored in the line program came from the compilation unit. Because of that, the old code used to handle zero specially, and otherwise subtract one from the index. For DWARF 5, the zero entry is actually present in the tables, so it is no longer appropriate to subtract one. To make this work in the simplest manner, just always store the zero entry in the tables, and stop treating zero specially, and stop subtracting one. For DWARF 4 and before, fetch the zero entry from the compilation unit. Bootstrapped on x86_64-pc-linux-gnu. The libbacktrace tests all pass. The libgo test all pass except for the ones that fail due to PR 98708. Committed to mainline. Ian * dwarf.c (read_v2_paths): Allocate zero entry for dirs and filenames. (read_line_program): Remove parameter u, change caller. Don't subtract one from dirs and filenames index. (read_function_entry): Don't subtract one from filenames index. 4817984f0f79656698e8b380e524f56a53881f15 diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 3d0cbedf770..9097df6cc76 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -2344,19 +2344,20 @@ read_v2_paths (struct backtrace_state *state, struct unit *u, ++hdr->dirs_count; } - hdr->dirs = NULL; - if (hdr->dirs_count != 0) -{ - hdr->dirs = ((const char **) - backtrace_alloc (state, - hdr->dirs_count * sizeof (const char *), - hdr_buf->error_callback, - hdr_buf->data)); - if (hdr->dirs == NULL) - return 0; -} + /* The index of the first entry in the list of directories is 1. Index 0 is + used for the current directory of the compilation. To simplify index + handling, we set entry 0 to the compilation unit directory. */ + ++hdr->dirs_count; + hdr->dirs = ((const char **) + backtrace_alloc (state, + hdr->dirs_count * sizeof (const char *), + hdr_buf->error_callback, + hdr_buf->data)); + if (hdr->dirs == NULL) +return 0; - i = 0; + hdr->dirs[0] = u->comp_dir; + i = 1; while (*hdr_buf->buf != '\0') { if (hdr_buf->reported_underflow) @@ -2383,6 +2384,10 @@ read_v2_paths (struct backtrace_state *state, struct unit *u, ++hdr->filenames_count; } + /* The index of the first entry in the list of file names is 1. Index 0 is + used for the DW_AT_name of the compilation unit. To simplify index + handling, we set entry 0 to the compilation unit file name. */ + ++hdr->filenames_count; hdr->filenames = ((const char **) backtrace_alloc (state, hdr->filenames_count * sizeof (char *), @@ -2390,7 +2395,8 @@ read_v2_paths (struct backtrace_state *state, struct unit *u, hdr_buf->data)); if (hdr->filenames == NULL) return 0; - i = 0; + hdr->filenames[0] = u->filename; + i = 1; while (*hdr_buf->buf != '\0') { const char *filename; @@ -2404,7 +2410,7 @@ read_v2_paths (struct backtrace_state *state, struct unit *u, return 0; dir_index = read_uleb128 (hdr_buf); if (IS_ABSOLUTE_PATH (filename) - || (dir_index == 0 && u->comp_dir == NULL)) + || (dir_index < hdr->dirs_count && hdr->dirs[dir_index] == NULL)) hdr->filenames[i] = filename; else { @@ -2413,10 +2419,8 @@ read_v2_paths (struct backtrace_state *state, struct unit *u, size_t filename_len; char *s; - if (dir_index == 0) - dir = u->comp_dir; - else if (dir_index - 1 < hdr->dirs_count) - dir = hdr->dirs[dir_index - 1]; + if (dir_index < hdr->dirs_count) + dir = hdr->dirs[dir_index]; else { dwarf_buf_error (hdr_buf, @@ -2704,8 +2708,8 @@ read_line_header (struct backtrace_state *state, struct dwarf_data *ddata, static int read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, const struct line_header *hdr, - struct dwarf_buf *line_buf, struct line_vector *vec) + const struct line_header *hdr, struct dwarf_buf *line_buf, + struct line_vector *vec) { uint64_t address; unsigned int op_index; @@ -2715,8 +2719,8 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, address = 0; op_index = 0; - if (hdr->filenames_count > 0) -reset_filename = hdr->filenames[0]; + if (hdr->filenames_count > 1) +reset_filename = hdr->filenames[1]; else reset_filename = ""; filename = reset_filename; @@ -2781,10 +2785,8 @@ read_line_program
libbacktrace patch committed: permit values at end of buffer
A couple of buffer overflow checks in libbacktrace incorrectly used >= when comparing the end of the value with the end of the buffer. It is of course OK if the value ends at the very end of the buffer. This patch corrects those cases to use > instead. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * dwarf.c (resolve_string): Use > rather than >= to check whether string index extends past buffer. (resolve_addr_index): Similarly for address index. 2e7ce16d5156bab9c217d21e7ff17a6a6eaf6fd3 diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 582f34bc816..0c913c95983 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -1053,7 +1053,7 @@ resolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64, offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base; if (offset + (is_dwarf64 ? 8 : 4) - >= dwarf_sections->size[DEBUG_STR_OFFSETS]) + > dwarf_sections->size[DEBUG_STR_OFFSETS]) { error_callback (data, "DW_FORM_strx value out of range", 0); return 0; @@ -1097,7 +1097,7 @@ resolve_addr_index (const struct dwarf_sections *dwarf_sections, struct dwarf_buf addr_buf; offset = addr_index * addrsize + addr_base; - if (offset + addrsize >= dwarf_sections->size[DEBUG_ADDR]) + if (offset + addrsize > dwarf_sections->size[DEBUG_ADDR]) { error_callback (data, "DW_FORM_addrx value out of range", 0); return 0;
libbacktrace patch committed: Use __attribute__((__fallthrough__))
This libbacktrace patch uses __attribute__((__fallthrough__)) rather than relying on a /*fallthrough*/ comment. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * internal.h (ATTRIBUTE_FALLTHROUGH): Define. * elf.c (elf_zlib_inflate): Use ATTRIBUTE_FALLTHROUGH. diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 941f820d944..d52b86cdeb5 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -2081,10 +2081,10 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, { case 6: *plen++ = prev; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 5: *plen++ = prev; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 4: *plen++ = prev; } @@ -2115,22 +2115,22 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, { case 10: *plen++ = 0; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 9: *plen++ = 0; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 8: *plen++ = 0; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 7: *plen++ = 0; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 6: *plen++ = 0; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 5: *plen++ = 0; - /* fallthrough */ + ATTRIBUTE_FALLTHROUGH; case 4: *plen++ = 0; } diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h index 047a700c0ce..659db9e21e2 100644 --- a/libbacktrace/internal.h +++ b/libbacktrace/internal.h @@ -56,6 +56,14 @@ POSSIBILITY OF SUCH DAMAGE. */ # endif #endif +#ifndef ATTRIBUTE_FALLTHROUGH +# if (GCC_VERSION >= 7000) +# define ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__)) +# else +# define ATTRIBUTE_FALLTHROUGH +# endif +#endif + #ifndef HAVE_SYNC_FUNCTIONS /* Define out the sync functions. These should never be called if
libbacktrace patch committed: Create mtest.dsym
This libbacktrace patch creates mtest.dsym when using dsymutil. This is for PR 97082, but it probably doesn't fix the PR. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian PR libbacktrace/97082 * Makefile.am (check_DATA): Add mtest.dSYM if USE_DSYMUTIL. * Makefile.in: Regenerate. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index f7e8ca2cf5c..5899a2157f4 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -484,6 +484,10 @@ mtest_LDADD = libbacktrace.la BUILDTESTS += mtest +if USE_DSYMUTIL +check_DATA += mtest.dSYM +endif USE_DSYMUTIL + if HAVE_MINIDEBUG TESTS += mtest_minidebug
libbacktrace patch committed: Only use dsymutil with Mach-O
This patch changes the libbacktrace tests to only run dsymutil when building for Mach-O. This should fix GCC PR 97227. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian PR libbacktrace/97227 * configure.ac (USE_DSYMUTIL): Define instead of HAVE_DSYMUTIL. * Makefile.am: Change all uses of HAVE_DSYMUTIL to USE_DSYMUTIL. * configure: Regenerate. * Makefile.in: Regenerate. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index 4d349386c9b..f7e8ca2cf5c 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -100,12 +100,12 @@ check_DATA = # Flags to use when compiling test programs. libbacktrace_TEST_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) -g -if HAVE_DSYMUTIL +if USE_DSYMUTIL %.dSYM: % $(DSYMUTIL) $< -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL if NATIVE check_LTLIBRARIES = libbacktrace_alloc.la @@ -237,9 +237,9 @@ allocfail.sh: allocfail TESTS += allocfail.sh -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += allocfail.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL if HAVE_ELF if HAVE_OBJCOPY_DEBUGLINK @@ -273,9 +273,9 @@ btest_LDADD = libbacktrace.la BUILDTESTS += btest -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += btest.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL if HAVE_ELF @@ -293,9 +293,9 @@ btest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += btest_alloc -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += btest_alloc.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL if HAVE_DWZ @@ -323,9 +323,9 @@ stest_LDADD = libbacktrace.la BUILDTESTS += stest -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += stest.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL stest_alloc_SOURCES = $(stest_SOURCES) stest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) @@ -333,9 +333,9 @@ stest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += stest_alloc -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += stest_alloc.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL if HAVE_ELF @@ -366,17 +366,17 @@ edtest_LDADD = libbacktrace.la BUILDTESTS += edtest -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += edtest.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL edtest_alloc_SOURCES = $(edtest_SOURCES) edtest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) edtest_alloc_LDADD = libbacktrace_alloc.la -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += edtest_alloc.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL BUILDTESTS += edtest_alloc @@ -394,9 +394,9 @@ ttest_SOURCES = ttest.c testlib.c ttest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -pthread ttest_LDADD = libbacktrace.la -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += ttest.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL BUILDTESTS += ttest_alloc @@ -404,9 +404,9 @@ ttest_alloc_SOURCES = $(ttest_SOURCES) ttest_alloc_CFLAGS = $(ttest_CFLAGS) ttest_alloc_LDADD = libbacktrace_alloc.la -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += ttest_alloc.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL endif HAVE_PTHREAD @@ -462,9 +462,9 @@ dwarf5_LDADD = libbacktrace.la BUILDTESTS += dwarf5 -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += dwarf5.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL dwarf5_alloc_SOURCES = $(dwarf5_SOURCES) dwarf5_alloc_CFLAGS = $(dwarf5_CFLAGS) @@ -472,9 +472,9 @@ dwarf5_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += dwarf5_alloc -if HAVE_DSYMUTIL +if USE_DSYMUTIL check_DATA += dwarf5_alloc.dSYM -endif HAVE_DSYMUTIL +endif USE_DSYMUTIL endif diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 0659ea60484..ec456bf4a1f 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -510,7 +510,7 @@ AM_CONDITIONAL(HAVE_OBJCOPY_DEBUGLINK, test "$libbacktrace_cv_objcopy_debuglink" AC_ARG_VAR(DSYMUTIL, [location of dsymutil]) AC_CHECK_PROG(DSYMUTIL, dsymutil, dsymutil) -AM_CONDITIONAL(HAVE_DSYMUTIL, test -n "${DSYMUTIL}") +AM_CONDITIONAL(USE_DSYMUTIL, test -n "${DSYMUTIL}" -a "$FORMAT_FILE" = "macho.lo") AC_ARG_VAR(NM, [location of nm]) AC_CHECK_PROG(NM, nm, nm)
Re: libbacktrace patch committed: Avoid ambiguous binary search
On Tue, Sep 8, 2020 at 6:22 PM Ian Lance Taylor wrote: > > This patch to libbacktrace avoids ambiguous binary searches. > Searching for a range match can cause the search order to not match > the sort order, which can cause libbacktrace to miss matching entries. > This patch allocates an extra entry at the end of function_addrs and > unit_addrs vectors, so that we can safely compare to the next entry > when searching. It adjusts the matching code accordingly. This fixes > https://github.com/ianlancetaylor/libbacktrace/issues/44. > Bootstrapped and ran libbacktrace and libgo tests on > x86_64-pc-linux-gnu. Committed to mainline. I realized that this isn't quite right for the case where the PC value we are looking up is equal to the low value in the array we are searching. In that case to ensure consistent results we have to step forward to the end of the sequence of identical low values, and only then step backward. This patch implements that. It also ensures that the right thing happens if someone decides to look up the PC value -1. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * dwarf.c (report_inlined_functions): Handle PC == -1 and PC == p->low. (dwarf_lookup_pc): Likewise. diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 386701bffea..582f34bc816 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -3558,6 +3558,11 @@ report_inlined_functions (uintptr_t pc, struct function *function, if (function->function_addrs_count == 0) return 0; + /* Our search isn't safe if pc == -1, as that is the sentinel + value. */ + if (pc + 1 == 0) +return 0; + p = ((struct function_addrs *) bsearch (, function->function_addrs, function->function_addrs_count, @@ -3567,9 +3572,12 @@ report_inlined_functions (uintptr_t pc, struct function *function, return 0; /* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are - sorted by low, so we are at the end of a range of function_addrs - with the same low alue. Walk backward and use the first range - that includes pc. */ + sorted by low, so if pc > p->low we are at the end of a range of + function_addrs with the same low value. If pc == p->low walk + forward to the end of the range with that low value. Then walk + backward and use the first range that includes pc. */ + while (pc == (p + 1)->low) +++p; match = NULL; while (1) { @@ -3636,8 +3644,10 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, *found = 1; - /* Find an address range that includes PC. */ - entry = (ddata->addrs_count == 0 + /* Find an address range that includes PC. Our search isn't safe if + PC == -1, as we use that as a sentinel value, so skip the search + in that case. */ + entry = (ddata->addrs_count == 0 || pc + 1 == 0 ? NULL : bsearch (, ddata->addrs, ddata->addrs_count, sizeof (struct unit_addrs), unit_addrs_search)); @@ -3649,9 +3659,12 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, } /* Here pc >= entry->low && pc < (entry + 1)->low. The unit_addrs - are sorted by low, so we are at the end of a range of unit_addrs - with the same low value. Walk backward and use the first range - that includes pc. */ + are sorted by low, so if pc > p->low we are at the end of a range + of unit_addrs with the same low value. If pc == p->low walk + forward to the end of the range with that low value. Then walk + backward and use the first range that includes pc. */ + while (pc == (entry + 1)->low) +++entry; found_entry = 0; while (1) { @@ -3832,9 +3845,12 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, return callback (data, pc, ln->filename, ln->lineno, NULL); /* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are - sorted by low, so we are at the end of a range of function_addrs - with the same low alue. Walk backward and use the first range - that includes pc. */ + sorted by low, so if pc > p->low we are at the end of a range of + function_addrs with the same low value. If pc == p->low walk + forward to the end of the range with that low value. Then walk + backward and use the first range that includes pc. */ + while (pc == (p + 1)->low) +++p; fmatch = NULL; while (1) {
libbacktrace patch committed: Don't strip underscore on 64-bit PE
This patch to libbacktrace avoids stripping a leading underscore from symbol names on 64-bit PE COFF. Bootstrapped and ran Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * pecoff.c (coff_initialize_syminfo): Add is_64 parameter. (coff_add): Determine and pass is_64. diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c index 221571c862e..49e5c3d868c 100644 --- a/libbacktrace/pecoff.c +++ b/libbacktrace/pecoff.c @@ -330,7 +330,7 @@ coff_is_function_symbol (const b_coff_internal_symbol *isym) static int coff_initialize_syminfo (struct backtrace_state *state, -uintptr_t base_address, +uintptr_t base_address, int is_64, const b_coff_section_header *sects, size_t sects_num, const b_coff_external_symbol *syms, size_t syms_size, const unsigned char *strtab, size_t strtab_size, @@ -426,9 +426,12 @@ coff_initialize_syminfo (struct backtrace_state *state, else name = isym.name; - /* Strip leading '_'. */ - if (name[0] == '_') - name++; + if (!is_64) + { + /* Strip leading '_'. */ + if (name[0] == '_') + name++; + } /* Symbol value is section relative, so we need to read the address of its section. */ @@ -605,6 +608,7 @@ coff_add (struct backtrace_state *state, int descriptor, off_t max_offset; struct backtrace_view debug_view; int debug_view_valid; + int is_64; uintptr_t image_base; struct dwarf_sections dwarf_sections; @@ -680,12 +684,16 @@ coff_add (struct backtrace_state *state, int descriptor, sects = (const b_coff_section_header *) (sects_view.data + fhdr.size_of_optional_header); + is_64 = 0; if (fhdr.size_of_optional_header > sizeof (*opt_hdr)) { if (opt_hdr->magic == PE_MAGIC) image_base = opt_hdr->u.pe.image_base; else if (opt_hdr->magic == PEP_MAGIC) - image_base = opt_hdr->u.pep.image_base; + { + image_base = opt_hdr->u.pep.image_base; + is_64 = 1; + } else { error_callback (data, "bad magic in PE optional header", 0); @@ -778,7 +786,7 @@ coff_add (struct backtrace_state *state, int descriptor, if (sdata == NULL) goto fail; - if (!coff_initialize_syminfo (state, image_base, + if (!coff_initialize_syminfo (state, image_base, is_64, sects, sects_num, syms_view.data, syms_size, str_view.data, str_size,
libbacktrace patch committed: Get executable name on macOS
This patch to libbacktrace gets the executable name on macOS using _NSGetExecutablePath. This is another aspect of PR 96973. Tested basic functionality on macOS. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * fileline.c (macho_get_executable_path): New static function. (fileline_initialize): Call macho_get_executable_path. diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index cc1011e8b5d..be62b9899c5 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -43,6 +43,10 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #endif +#ifdef HAVE_MACH_O_DYLD_H +#include +#endif + #include "backtrace.h" #include "internal.h" @@ -122,6 +126,35 @@ sysctl_exec_name2 (struct backtrace_state *state, #endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */ +#ifdef HAVE_MACH_O_DYLD_H + +static char * +macho_get_executable_path (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + uint32_t len; + char *name; + + len = 0; + if (_NSGetExecutablePath (NULL, ) == 0) +return NULL; + name = (char *) backtrace_alloc (state, len, error_callback, data); + if (name == NULL) +return NULL; + if (_NSGetExecutablePath (name, ) != 0) +{ + backtrace_free (state, name, len, error_callback, data); + return NULL; +} + return name; +} + +#else /* !defined (HAVE_MACH_O_DYLD_H) */ + +#define macho_get_executable_path(state, error_callback, data) NULL + +#endif /* !defined (HAVE_MACH_O_DYLD_H) */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -159,7 +192,7 @@ fileline_initialize (struct backtrace_state *state, descriptor = -1; called_error_callback = 0; - for (pass = 0; pass < 7; ++pass) + for (pass = 0; pass < 8; ++pass) { int does_not_exist; @@ -188,6 +221,9 @@ fileline_initialize (struct backtrace_state *state, case 6: filename = sysctl_exec_name2 (state, error_callback, data); break; + case 7: + filename = macho_get_executable_path (state, error_callback, data); + break; default: abort (); }
libbacktrace patch committed: Avoid ambiguous binary search
This patch to libbacktrace avoids ambiguous binary searches. Searching for a range match can cause the search order to not match the sort order, which can cause libbacktrace to miss matching entries. This patch allocates an extra entry at the end of function_addrs and unit_addrs vectors, so that we can safely compare to the next entry when searching. It adjusts the matching code accordingly. This fixes https://github.com/ianlancetaylor/libbacktrace/issues/44. Bootstrapped and ran libbacktrace and libgo tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * dwarf.c (function_addrs_search): Compare against the next entry low address, not the high address. (unit_addrs_search): Likewise. (build_address_map): Add a trailing unit_addrs. (read_function_entry): Add a trailing function_addrs. (read_function_info): Likewise. (report_inlined_functions): Search backward for function_addrs match. (dwarf_lookup_pc): Search backward for unit_addrs and function_addrs matches. diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c index 006c8181622..386701bffea 100644 --- a/libbacktrace/dwarf.c +++ b/libbacktrace/dwarf.c @@ -1164,9 +1164,11 @@ function_addrs_compare (const void *v1, const void *v2) return strcmp (a1->function->name, a2->function->name); } -/* Compare a PC against a function_addrs for bsearch. Note that if - there are multiple ranges containing PC, which one will be returned - is unpredictable. We compensate for that in dwarf_fileline. */ +/* Compare a PC against a function_addrs for bsearch. We always + allocate an entra entry at the end of the vector, so that this + routine can safely look at the next entry. Note that if there are + multiple ranges containing PC, which one will be returned is + unpredictable. We compensate for that in dwarf_fileline. */ static int function_addrs_search (const void *vkey, const void *ventry) @@ -1178,7 +1180,7 @@ function_addrs_search (const void *vkey, const void *ventry) pc = *key; if (pc < entry->low) return -1; - else if (pc >= entry->high) + else if (pc > (entry + 1)->low) return 1; else return 0; @@ -1249,9 +1251,11 @@ unit_addrs_compare (const void *v1, const void *v2) return 0; } -/* Compare a PC against a unit_addrs for bsearch. Note that if there - are multiple ranges containing PC, which one will be returned is - unpredictable. We compensate for that in dwarf_fileline. */ +/* Compare a PC against a unit_addrs for bsearch. We always allocate + an entry entry at the end of the vector, so that this routine can + safely look at the next entry. Note that if there are multiple + ranges containing PC, which one will be returned is unpredictable. + We compensate for that in dwarf_fileline. */ static int unit_addrs_search (const void *vkey, const void *ventry) @@ -1263,7 +1267,7 @@ unit_addrs_search (const void *vkey, const void *ventry) pc = *key; if (pc < entry->low) return -1; - else if (pc >= entry->high) + else if (pc > (entry + 1)->low) return 1; else return 0; @@ -2091,6 +2095,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, size_t i; struct unit **pu; size_t unit_offset = 0; + struct unit_addrs *pa; memset (>vec, 0, sizeof addrs->vec); memset (_vec->vec, 0, sizeof unit_vec->vec); @@ -2231,6 +2236,17 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, if (info.reported_underflow) goto fail; + /* Add a trailing addrs entry, but don't include it in addrs->count. */ + pa = ((struct unit_addrs *) + backtrace_vector_grow (state, sizeof (struct unit_addrs), + error_callback, data, >vec)); + if (pa == NULL) +goto fail; + pa->low = 0; + --pa->low; + pa->high = pa->low; + pa->u = NULL; + unit_vec->vec = units; unit_vec->count = units_count; return 1; @@ -3404,8 +3420,23 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, if (fvec.count > 0) { + struct function_addrs *p; struct function_addrs *faddrs; + /* Allocate a trailing entry, but don't include it +in fvec.count. */ + p = ((struct function_addrs *) + backtrace_vector_grow (state, + sizeof (struct function_addrs), + error_callback, data, + )); + if (p == NULL) + return 0; + p->low = 0; + --p->low; + p->high = p->low; + p->function = NULL; + if (!backtrace_vector_release (state, , error_callback, data)) return 0; @@ -3439,6 +3470,7 @@ read_function_info (struct backtrace_state
libbacktrace patch committed: Correct tipo in comment
This patch suggested by Ondřej Čertík fixes a typpo in a comment. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * simple.c (simple_unwind): Correct comment spelling. diff --git a/libbacktrace/simple.c b/libbacktrace/simple.c index b9b971af95e..9ba660c871c 100644 --- a/libbacktrace/simple.c +++ b/libbacktrace/simple.c @@ -55,7 +55,7 @@ struct backtrace_simple_data int ret; }; -/* Unwind library callback routine. This is passd to +/* Unwind library callback routine. This is passed to _Unwind_Backtrace. */ static _Unwind_Reason_Code
libbacktrace patch committed: Correct Mach-O memory allocation
This libbacktrace patch corrects the amount of memory allocated when looking for the Mach-O dsym file. We weren't allocating space for the backslash. Thanks to Alex Crichton for noticing this. This also fixes the amount of space released when freeing diralc in the same function. Thanks to Francois-Xavier Coudert for noticing that. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian * macho.c (macho_add_dsym): Make space for '/' in dsym. Use correct length when freeing diralc.
libbacktrace patch committed: Correctly swap Mach-O fat 32-bit file offset
This libbacktrace patch correctly swaps the 32-bit file offset in a Mach-O fat file. This is based on a patch by Francois-Xavier Coudert , who analyzed the problem. This is for PR 96973. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian PR libbacktrace/96973 * macho.c (macho_add_fat): Correctly swap 32-bit file offset. diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c index bd737226ca6..20dd3262d58 100644 --- a/libbacktrace/macho.c +++ b/libbacktrace/macho.c @@ -793,13 +793,24 @@ macho_add_fat (struct backtrace_state *state, const char *filename, for (i = 0; i < nfat_arch; ++i) { - struct macho_fat_arch_64 fat_arch; uint32_t fcputype; + uint64_t foffset; if (is_64) - memcpy (_arch, - (const char *) arch_view.data + i * arch_size, - arch_size); + { + struct macho_fat_arch_64 fat_arch_64; + + memcpy (_arch_64, + (const char *) arch_view.data + i * arch_size, + arch_size); + fcputype = fat_arch_64.cputype; + foffset = fat_arch_64.offset; + if (swapped) + { + fcputype = __builtin_bswap32 (fcputype); + foffset = __builtin_bswap64 (foffset); + } + } else { struct macho_fat_arch fat_arch_32; @@ -807,26 +818,18 @@ macho_add_fat (struct backtrace_state *state, const char *filename, memcpy (_arch_32, (const char *) arch_view.data + i * arch_size, arch_size); - fat_arch.cputype = fat_arch_32.cputype; - fat_arch.cpusubtype = fat_arch_32.cpusubtype; - fat_arch.offset = (uint64_t) fat_arch_32.offset; - fat_arch.size = (uint64_t) fat_arch_32.size; - fat_arch.align = fat_arch_32.align; - fat_arch.reserved = 0; + fcputype = fat_arch_32.cputype; + foffset = (uint64_t) fat_arch_32.offset; + if (swapped) + { + fcputype = __builtin_bswap32 (fcputype); + foffset = (uint64_t) __builtin_bswap32 ((uint32_t) foffset); + } } - fcputype = fat_arch.cputype; - if (swapped) - fcputype = __builtin_bswap32 (fcputype); - if (fcputype == cputype) { - uint64_t foffset; - /* FIXME: What about cpusubtype? */ - foffset = fat_arch.offset; - if (swapped) - foffset = __builtin_bswap64 (foffset); backtrace_release_view (state, _view, error_callback, data); return macho_add (state, filename, descriptor, foffset, match_uuid, base_address, skip_symtab, error_callback, data,
libbacktrace patch committed: Only match magic number at start of file
This patch fixes the libbacktrace file type detection, which is run at configure time, to only look for a magic number at the very start of the file. Otherwise we can get confused if the bytes happen to appear elsewhere on the first "line". This is for PR 96971. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian PR libbacktrace/96971 * filetype.awk: Only match magic number at start of line. diff --git a/libbacktrace/filetype.awk b/libbacktrace/filetype.awk index 14d91581f7e..1eefa7e72f0 100644 --- a/libbacktrace/filetype.awk +++ b/libbacktrace/filetype.awk @@ -1,13 +1,13 @@ # An awk script to determine the type of a file. -/\177ELF\001/ { if (NR == 1) { print "elf32"; exit } } -/\177ELF\002/ { if (NR == 1) { print "elf64"; exit } } -/\114\001/ { if (NR == 1) { print "pecoff"; exit } } -/\144\206/ { if (NR == 1) { print "pecoff"; exit } } -/\001\337/ { if (NR == 1) { print "xcoff32"; exit } } -/\001\367/ { if (NR == 1) { print "xcoff64"; exit } } -/\376\355\372\316/ { if (NR == 1) { print "macho"; exit } } -/\316\372\355\376/ { if (NR == 1) { print "macho"; exit } } -/\376\355\372\317/ { if (NR == 1) { print "macho"; exit } } -/\317\372\355\376/ { if (NR == 1) { print "macho"; exit } } -/\312\376\272\276/ { if (NR == 1) { print "macho"; exit } } -/\276\272\376\312/ { if (NR == 1) { print "macho"; exit } } +/^\177ELF\001/ { if (NR == 1) { print "elf32"; exit } } +/^\177ELF\002/ { if (NR == 1) { print "elf64"; exit } } +/^\114\001/ { if (NR == 1) { print "pecoff"; exit } } +/^\144\206/ { if (NR == 1) { print "pecoff"; exit } } +/^\001\337/ { if (NR == 1) { print "xcoff32"; exit } } +/^\001\367/ { if (NR == 1) { print "xcoff64"; exit } } +/^\376\355\372\316/ { if (NR == 1) { print "macho"; exit } } +/^\316\372\355\376/ { if (NR == 1) { print "macho"; exit } } +/^\376\355\372\317/ { if (NR == 1) { print "macho"; exit } } +/^\317\372\355\376/ { if (NR == 1) { print "macho"; exit } } +/^\312\376\272\276/ { if (NR == 1) { print "macho"; exit } } +/^\276\272\376\312/ { if (NR == 1) { print "macho"; exit } }
libbacktrace patch committed: Add support for Mach-O 64-bit FAT files
This libbacktrace patch adds support for Mach-O 64-bit FAT files. Bootstrapped and tested on x86_64-pc-linux-gnu. Committed to mainline. Ian libbacktrace/: * macho.c (MACH_O_MH_MAGIC_FAT_64): Define. (MACH_O_MH_CIGAM_FAT_64): Define. (struct macho_fat_arch_64): Define. (macho_add_fat): Add and use is_64 parameter. (macho_add): Recognize 64-bit fat files. diff --git a/libbacktrace/macho.c b/libbacktrace/macho.c index 3aea70cdbbe..bd737226ca6 100644 --- a/libbacktrace/macho.c +++ b/libbacktrace/macho.c @@ -75,7 +75,7 @@ struct macho_header_64 struct macho_header_fat { - uint32_t magic; /* Magic number (MACH_O_MH_MAGIC_FAT) */ + uint32_t magic; /* Magic number (MACH_O_MH_(MAGIC|CIGAM)_FAT(_64)?) */ uint32_t nfat_arch; /* Number of components */ }; @@ -85,6 +85,8 @@ struct macho_header_fat #define MACH_O_MH_MAGIC_64 0xfeedfacf #define MACH_O_MH_MAGIC_FAT0xcafebabe #define MACH_O_MH_CIGAM_FAT0xbebafeca +#define MACH_O_MH_MAGIC_FAT_64 0xcafebabf +#define MACH_O_MH_CIGAM_FAT_64 0xbfbafeca /* Value for the header filetype field. */ @@ -105,6 +107,20 @@ struct macho_fat_arch uint32_t align; /* Alignment of this entry */ }; +/* A component of a 64-bit fat file. This is used if the magic field + is MAGIC_FAT_64. This is only used when some file size or file + offset is too large to represent in the 32-bit format. */ + +struct macho_fat_arch_64 +{ + uint32_t cputype;/* CPU type */ + uint32_t cpusubtype; /* CPU subtype */ + uint64_t offset; /* File offset of this entry */ + uint64_t size; /* Size of this entry */ + uint32_t align; /* Alignment of this entry */ + uint32_t reserved; /* Reserved */ +}; + /* Values for the fat_arch cputype field (and the header cputype field). */ @@ -740,14 +756,14 @@ static int macho_add_fat (struct backtrace_state *state, const char *filename, int descriptor, int swapped, off_t offset, const unsigned char *match_uuid, uintptr_t base_address, - int skip_symtab, uint32_t nfat_arch, + int skip_symtab, uint32_t nfat_arch, int is_64, backtrace_error_callback error_callback, void *data, fileline *fileline_fn, int *found_sym) { int arch_view_valid; unsigned int cputype; + size_t arch_size; struct backtrace_view arch_view; - size_t archoffset; unsigned int i; arch_view_valid = 0; @@ -765,21 +781,39 @@ macho_add_fat (struct backtrace_state *state, const char *filename, goto fail; #endif + if (is_64) +arch_size = sizeof (struct macho_fat_arch_64); + else +arch_size = sizeof (struct macho_fat_arch); + if (!backtrace_get_view (state, descriptor, offset, - nfat_arch * sizeof (struct macho_fat_arch), + nfat_arch * arch_size, error_callback, data, _view)) goto fail; - archoffset = 0; for (i = 0; i < nfat_arch; ++i) { - struct macho_fat_arch fat_arch; + struct macho_fat_arch_64 fat_arch; uint32_t fcputype; - memcpy (_arch, - ((const char *) arch_view.data - + i * sizeof (struct macho_fat_arch)), - sizeof fat_arch); + if (is_64) + memcpy (_arch, + (const char *) arch_view.data + i * arch_size, + arch_size); + else + { + struct macho_fat_arch fat_arch_32; + + memcpy (_arch_32, + (const char *) arch_view.data + i * arch_size, + arch_size); + fat_arch.cputype = fat_arch_32.cputype; + fat_arch.cpusubtype = fat_arch_32.cpusubtype; + fat_arch.offset = (uint64_t) fat_arch_32.offset; + fat_arch.size = (uint64_t) fat_arch_32.size; + fat_arch.align = fat_arch_32.align; + fat_arch.reserved = 0; + } fcputype = fat_arch.cputype; if (swapped) @@ -787,19 +821,17 @@ macho_add_fat (struct backtrace_state *state, const char *filename, if (fcputype == cputype) { - uint32_t foffset; + uint64_t foffset; /* FIXME: What about cpusubtype? */ foffset = fat_arch.offset; if (swapped) - foffset = __builtin_bswap32 (foffset); + foffset = __builtin_bswap64 (foffset); backtrace_release_view (state, _view, error_callback, data); return macho_add (state, filename, descriptor, foffset, match_uuid, base_address, skip_symtab, error_callback, data, fileline_fn, found_sym); } - - archoffset += sizeof (struct macho_fat_arch); } error_callback (data, "could not find executable in fat file", 0); @@ -980,6 +1012,7 @@ macho_add (struct backtrace_state *state, const char *filename, int descriptor, hdroffset = offset + sizeof (struct macho_header_64);
libbacktrace patch committed: Mark state unused in ztest.c test_large
This libbacktrace patch marks the state parameter of test_large in ztest.c as ATTRIBUTE_UNUSED. The parameter is not used if HAVE_ZLIB is not defined. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2020-05-13 Ian Lance Taylor * ztest.c (test_large): Mark state ATTRIBUTE_UNUSED. diff --git a/libbacktrace/ztest.c b/libbacktrace/ztest.c index 2663c90061a..39476704972 100644 --- a/libbacktrace/ztest.c +++ b/libbacktrace/ztest.c @@ -294,7 +294,7 @@ average_time (const size_t *times, size_t trials) /* Test a larger text, if available. */ static void -test_large (struct backtrace_state *state) +test_large (struct backtrace_state *state ATTRIBUTE_UNUSED) { #ifdef HAVE_ZLIB unsigned char *orig_buf;
libbacktrace patch committed: Treat EACCES like ENOENT
This patch to libbacktrace treats an EACCES error when opening a file like an ENOENT error. This case happens when running the libgo syscall tests as root, when testing various ways of restricting a child process. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2020-05-13 Ian Lance Taylor PR go/95061 * posix.c (backtrace_open): Treat EACCESS like ENOENT. diff --git a/libbacktrace/posix.c b/libbacktrace/posix.c index 356e72b4a3b..a2c88dd8e4a 100644 --- a/libbacktrace/posix.c +++ b/libbacktrace/posix.c @@ -67,7 +67,11 @@ backtrace_open (const char *filename, backtrace_error_callback error_callback, descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC)); if (descriptor < 0) { - if (does_not_exist != NULL && errno == ENOENT) + /* If DOES_NOT_EXIST is not NULL, then don't call ERROR_CALLBACK +if the file does not exist. We treat lacking permission to +open the file as the file not existing; this case arises when +running the libgo syscall package tests as root. */ + if (does_not_exist != NULL && (errno == ENOENT || errno == EACCES)) *does_not_exist = 1; else error_callback (data, filename, errno);
libbacktrace patch committed: Declare getpagesize if necessary
Reportedly mingw-w64-gcc has mmap and getpagesize but does not provide a declaration of getpagesize in any header files. Check for a getpagesize declaration, and declare it if necessary. This is for PR 95012. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to master. Ian 2020-05-11 Ian Lance Taylor PR libbacktrace/95012 * configure.ac: Check for getpagesize declaration. * mmap.c: Declare getpagesize if necessary. * mmapio.c: Likewise. * configure: Regenerate. * config.h.in: Regenerate. * Makefile.in: Regenerate. diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 6f241c5bac0..de9cf628b47 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -376,7 +376,7 @@ if test "$have_fcntl" = "yes"; then [Define to 1 if you have the fcntl function]) fi -AC_CHECK_DECLS(strnlen) +AC_CHECK_DECLS(strnlen getpagesize) AC_CHECK_FUNCS(lstat readlink) # Check for getexecname function. diff --git a/libbacktrace/mmap.c b/libbacktrace/mmap.c index dd7d519cc56..6c8bd5d4a19 100644 --- a/libbacktrace/mmap.c +++ b/libbacktrace/mmap.c @@ -42,6 +42,10 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#ifndef HAVE_DECL_GETPAGESIZE +extern int getpagesize (void); +#endif + /* Memory allocation on systems that provide anonymous mmap. This permits the backtrace functions to be invoked from a signal handler, assuming that mmap is async-signal safe. */ diff --git a/libbacktrace/mmapio.c b/libbacktrace/mmapio.c index 5dd39525ba1..69cd8065a49 100644 --- a/libbacktrace/mmapio.c +++ b/libbacktrace/mmapio.c @@ -40,6 +40,10 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "internal.h" +#ifndef HAVE_DECL_GETPAGESIZE +extern int getpagesize (void); +#endif + #ifndef MAP_FAILED #define MAP_FAILED ((void *)-1) #endif
libbacktrace patch committed: Don't crash if no section headers
This patch to libbacktrace, by Roland McGrath, avoids crashing if an ELF file has no section headers. Bootstrapped and ran libbacktrace testsuite on x86_64-pc-linux-gnu. This fixes https://github.com/ianlancetaylor/libbacktrace/issues/41. Committed to master. Ian 2020-05-09 Roland McGrath * elf.c (elf_add): Bail early if there are no section headers at all. diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 1216af86fd9..80a00506bd6 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -2781,6 +2781,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, backtrace_release_view (state, _view, error_callback, data); } + if (shnum == 0 || shstrndx == 0) +goto fail; + /* To translate PC to file/line when using DWARF, we need to find the .debug_info and .debug_line sections. */
libbacktrace patch committed: Don't free strtab if error after reading symbols
This libbacktrace patch fixes the ELF support so that after reading symbol information we don't free the strtab, even if we encounter an error later while reading debug info. This fixes programs that try to get symbol information even if they can't get backtrace information. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2020-05-09 Ian Lance Taylor * elf.c (elf_add): Don't free strtab if an error occurs after recording symbol information. index eb481c588e7..1216af86fd9 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -3011,6 +3011,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, string table permanently. */ backtrace_release_view (state, _view, error_callback, data); symtab_view_valid = 0; + strtab_view_valid = 0; *found_sym = 1;
libbacktrace patch committed: Add Mach-O support
This patch to libbacktrace adds Mach-O support. Bootstrapped and tested on macOS. Most tests pass, but a couple still fail. This is for PR 88745. Committed to master. Ian 2020-05-09 Ian Lance Taylor PR libbacktrace/88745 * macho.c: New file. * filetype.awk: Recognize Mach-O files. * Makefile.am (FORMAT_FILES): Add macho.c. (check_DATA): New variable. Set to .dSYM if HAVE_DSYMUTIL. (%.dSYM): New pattern target. (test_macho_SOURCES, test_macho_CFLAGS): New targets. (test_macho_LDADD): New target. (BUILDTESTS): Add test_macho. (macho.lo): Add dependencies. * configure.ac: Recognize macho file type. Check for mach-o/dyld.h. Don't try to run objcopy if we don't find it. Look for dsymutil and define a HAVE_DSYMUTIL conditional. * Makefile.in: Regenerate. * configure: Regenerate. * config.h.in: Regenerate. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index c73f6633a76..d3a9ba8843a 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -56,6 +56,7 @@ BACKTRACE_FILES = \ FORMAT_FILES = \ elf.c \ + macho.c \ pecoff.c \ unknown.c \ xcoff.c @@ -84,18 +85,28 @@ libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) # Testsuite. -# Add test to this variable, if you want it to be build. +# Add a test to this variable if you want it to be built. check_PROGRAMS = -# Add test to this variable, if you want it to be run. +# Add a test to this variable if you want it to be run. TESTS = -# Add test to this variable, if you want it to be build and run. +# Add a test to this variable if you want it to be built and run. BUILDTESTS = +# Add a file to this variable if you want it to be built for testing. +check_DATA = + # Flags to use when compiling test programs. libbacktrace_TEST_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) -g +if HAVE_DSYMUTIL + +%.dSYM: % + $(DSYMUTIL) $< + +endif HAVE_DSYMUTIL + if NATIVE check_LTLIBRARIES = libbacktrace_alloc.la @@ -163,6 +174,12 @@ test_elf_64_LDADD = libbacktrace_noformat.la elf_64.lo BUILDTESTS += test_elf_64 +test_macho_SOURCES = test_format.c testlib.c +test_macho_CFLAGS = $(libbacktrace_TEST_CFLAGS) +test_macho_LDADD = libbacktrace_noformat.la macho.lo + +BUILDTESTS += test_macho + test_xcoff_32_SOURCES = test_format.c testlib.c test_xcoff_32_CFLAGS = $(libbacktrace_TEST_CFLAGS) test_xcoff_32_LDADD = libbacktrace_noformat.la xcoff_32.lo @@ -220,6 +237,10 @@ allocfail.sh: allocfail TESTS += allocfail.sh +if HAVE_DSYMUTIL +check_DATA += allocfail.dSYM +endif HAVE_DSYMUTIL + if HAVE_ELF if HAVE_OBJCOPY_DEBUGLINK @@ -252,6 +273,10 @@ btest_LDADD = libbacktrace.la BUILDTESTS += btest +if HAVE_DSYMUTIL +check_DATA += btest.dSYM +endif HAVE_DSYMUTIL + if HAVE_ELF btest_lto_SOURCES = btest.c testlib.c @@ -268,6 +293,10 @@ btest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += btest_alloc +if HAVE_DSYMUTIL +check_DATA += btest_alloc.dSYM +endif HAVE_DSYMUTIL + if HAVE_DWZ %_dwz: % @@ -294,12 +323,20 @@ stest_LDADD = libbacktrace.la BUILDTESTS += stest +if HAVE_DSYMUTIL +check_DATA += stest.dSYM +endif HAVE_DSYMUTIL + stest_alloc_SOURCES = $(stest_SOURCES) stest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) stest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += stest_alloc +if HAVE_DSYMUTIL +check_DATA += stest_alloc.dSYM +endif HAVE_DSYMUTIL + if HAVE_ELF ztest_SOURCES = ztest.c testlib.c @@ -329,10 +366,18 @@ edtest_LDADD = libbacktrace.la BUILDTESTS += edtest +if HAVE_DSYMUTIL +check_DATA += edtest.dSYM +endif HAVE_DSYMUTIL + edtest_alloc_SOURCES = $(edtest_SOURCES) edtest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) edtest_alloc_LDADD = libbacktrace_alloc.la +if HAVE_DSYMUTIL +check_DATA += edtest_alloc.dSYM +endif HAVE_DSYMUTIL + BUILDTESTS += edtest_alloc edtest2_build.c: gen_edtest2_build; @true @@ -349,12 +394,20 @@ ttest_SOURCES = ttest.c testlib.c ttest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -pthread ttest_LDADD = libbacktrace.la +if HAVE_DSYMUTIL +check_DATA += ttest.dSYM +endif HAVE_DSYMUTIL + BUILDTESTS += ttest_alloc ttest_alloc_SOURCES = $(ttest_SOURCES) ttest_alloc_CFLAGS = $(ttest_CFLAGS) ttest_alloc_LDADD = libbacktrace_alloc.la +if HAVE_DSYMUTIL +check_DATA += ttest_alloc.dSYM +endif HAVE_DSYMUTIL + endif HAVE_PTHREAD if HAVE_OBJCOPY_DEBUGLINK @@ -409,12 +462,20 @@ dwarf5_LDADD = libbacktrace.la BUILDTESTS += dwarf5 +if HAVE_DSYMUTIL +check_DATA += dwarf5.dSYM +endif HAVE_DSYMUTIL + dwarf5_alloc_SOURCES = $(dwarf5_SOURCES) dwarf5_alloc_CFLAGS = $(dwarf5_CFLAGS) dwarf5_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += dwarf5_alloc +if HAVE_DSYMUTIL +check_DATA += dwarf5_alloc.dSYM +endif HAVE_DSYMUTIL + endif endif NATIVE @@ -448,6 +509,7 @@ dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \ $(INCDIR)/filenames.h backtrace.h internal.h elf.lo: config.h backtrace.h internal.h fileline.lo: config.h backtrace.h internal.h +macho.lo: config.h backtrace.h
libbacktrace patch committed: Support short reads
This patch to libbacktrace handles short reads correctly. Short reads are unlikely, but they can reportedly happen when the debug sections are very large and we aren't using mmap. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2020-05-09 Ian Lance Taylor * read.c (backtrace_get_view): Support short read. diff --git a/libbacktrace/read.c b/libbacktrace/read.c index 57e4701bbeb..1a6052bf613 100644 --- a/libbacktrace/read.c +++ b/libbacktrace/read.c @@ -50,7 +50,8 @@ backtrace_get_view (struct backtrace_state *state, int descriptor, backtrace_error_callback error_callback, void *data, struct backtrace_view *view) { - ssize_t got; + uint64_t got; + ssize_t r; if ((uint64_t) (size_t) size != size) { @@ -70,15 +71,22 @@ backtrace_get_view (struct backtrace_state *state, int descriptor, view->data = view->base; view->len = size; - got = read (descriptor, view->base, size); - if (got < 0) + got = 0; + while (got < size) { - error_callback (data, "read", errno); - free (view->base); - return 0; + r = read (descriptor, view->base, size - got); + if (r < 0) + { + error_callback (data, "read", errno); + free (view->base); + return 0; + } + if (r == 0) + break; + got += (uint64_t) r; } - if ((size_t) got < size) + if (got < size) { error_callback (data, "file too short", 0); free (view->base);
libbacktrace patch committed: sometimes read debug sections individually
This patch to libbacktrace changes it to read the debug sections as individual sections if they are very large or are far apart. This uses less memory in some cases, and fixes some cases on 32-bit systems. In particular this fixes one of the problems in https://github.com/ianlancetaylor/libbacktrace/issues/29. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to master. Ian 2020-05-09 Ian Lance Taylor * elf.c (elf_add): If debug sections are very large or far apart, read them individually rather than as a single view. diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 9a866eb5048..eb481c588e7 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -2659,10 +2659,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, uint32_t debugaltlink_buildid_size; off_t min_offset; off_t max_offset; + off_t debug_size; struct backtrace_view debug_view; int debug_view_valid; unsigned int using_debug_view; uint16_t *zdebug_table; + struct backtrace_view split_debug_view[DEBUG_MAX]; + unsigned char split_debug_view_valid[DEBUG_MAX]; struct elf_ppc64_opd_data opd_data, *opd; struct dwarf_sections dwarf_sections; @@ -2687,6 +2690,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, debugaltlink_buildid_data = NULL; debugaltlink_buildid_size = 0; debug_view_valid = 0; + memset (_debug_view_valid[0], 0, sizeof split_debug_view_valid); opd = NULL; if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, @@ -3131,6 +3135,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, min_offset = 0; max_offset = 0; + debug_size = 0; for (i = 0; i < (int) DEBUG_MAX; ++i) { off_t end; @@ -3142,6 +3147,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, end = sections[i].offset + sections[i].size; if (end > max_offset) max_offset = end; + debug_size += sections[i].size; } if (zsections[i].size != 0) { @@ -3150,6 +3156,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, end = zsections[i].offset + zsections[i].size; if (end > max_offset) max_offset = end; + debug_size += zsections[i].size; } } if (min_offset == 0 || max_offset == 0) @@ -3159,11 +3166,45 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, return 1; } - if (!backtrace_get_view (state, descriptor, min_offset, - max_offset - min_offset, - error_callback, data, _view)) -goto fail; - debug_view_valid = 1; + /* If the total debug section size is large, assume that there are + gaps between the sections, and read them individually. */ + + if (max_offset - min_offset < 0x2000 + || max_offset - min_offset < debug_size + 0x1) +{ + if (!backtrace_get_view (state, descriptor, min_offset, + max_offset - min_offset, + error_callback, data, _view)) + goto fail; + debug_view_valid = 1; +} + else +{ + memset (_debug_view[0], 0, sizeof split_debug_view); + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + struct debug_section_info *dsec; + + if (sections[i].size != 0) + dsec = [i]; + else if (zsections[i].size != 0) + dsec = [i]; + else + continue; + + if (!backtrace_get_view (state, descriptor, dsec->offset, dsec->size, + error_callback, data, _debug_view[i])) + goto fail; + split_debug_view_valid[i] = 1; + + if (sections[i].size != 0) + sections[i].data = ((const unsigned char *) + split_debug_view[i].data); + else + zsections[i].data = ((const unsigned char *) +split_debug_view[i].data); + } +} /* We've read all we need from the executable. */ if (!backtrace_close (descriptor, error_callback, data)) @@ -3171,22 +3212,25 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, descriptor = -1; using_debug_view = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) + if (debug_view_valid) { - if (sections[i].size == 0) - sections[i].data = NULL; - else + for (i = 0; i < (int) DEBUG_MAX; ++i) { - sections[i].data = ((const unsigned char *) debug_view.data - + (sections[i].offset - min_offset)); - ++using_debug_view; - } + if (sections[i].size == 0) + sections[i].data = NULL; + else + { + sections[i].data = ((const unsigned char *) debug_view.data + +
libbacktrace patch committed: get executable name on FreeBSD and NetBSD
This libbacktrace patch adds the ability to fetch the executable name on FreeBSD and NetBSD using sysctl when /proc is not mounted. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2020-05-08 Ian Lance Taylor * fileline.c (sysctl_exec_name): New static function. (sysctl_exec_name1): New macro or static function. (sysctl_exec_name2): Likewise. (fileline_initialize): Try sysctl_exec_name[12]. * configure.ac: Check for sysctl args to fetch executable name. * configure: Regenerate. * config.h.in: Regenerate. diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac index 3730d7c4b06..5beed68ccf6 100644 --- a/libbacktrace/configure.ac +++ b/libbacktrace/configure.ac @@ -388,6 +388,36 @@ if test "$have_getexecname" = "yes"; then AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.]) fi +# Check for sysctl definitions. + +AC_CACHE_CHECK([for KERN_PROC], +[libbacktrace_cv_proc], +[AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([ +#include +#include +], [int mib0 = CTL_KERN; int mib1 = KERN_PROC; int mib2 = KERN_PROC_PATHNAME;])], + [libbacktrace_cv_proc=yes], + [libbacktrace_cv_proc=no])]) +if test "$libbacktrace_cv_proc" = "yes"; then + AC_DEFINE([HAVE_KERN_PROC], 1, +[Define to 1 if you have KERN_PROC and KERN_PROC_PATHNAME in .]) +fi + +AC_CACHE_CHECK([for KERN_PROG_ARGS], +[libbacktrace_cv_procargs], +[AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([ +#include +#include +], [int mib0 = CTL_KERN; int mib1 = KERN_PROC_ARGS; int mib2 = KERN_PROC_PATHNAME;])], + [libbacktrace_cv_procargs=yes], + [libbacktrace_cv_procargs=no])]) +if test "$libbacktrace_cv_procargs" = "yes"; then + AC_DEFINE([HAVE_KERN_PROC_ARGS], 1, +[Define to 1 if you have KERN_PROCARGS and KERN_PROC_PATHNAME in .]) +fi + # Check for the clock_gettime function. AC_CHECK_FUNCS(clock_gettime) clock_gettime_link= diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index fd5edbe5ddb..cc1011e8b5d 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -39,6 +39,10 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #include +#if defined (HAVE_KERN_PROC_ARGS) || defined (HAVE_KERN_PROC) +#include +#endif + #include "backtrace.h" #include "internal.h" @@ -46,6 +50,78 @@ POSSIBILITY OF SUCH DAMAGE. */ #define getexecname() NULL #endif +#if !defined (HAVE_KERN_PROC_ARGS) && !defined (HAVE_KERN_PROC) + +#define sysctl_exec_name1(state, error_callback, data) NULL +#define sysctl_exec_name2(state, error_callback, data) NULL + +#else /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */ + +static char * +sysctl_exec_name (struct backtrace_state *state, + int mib0, int mib1, int mib2, int mib3, + backtrace_error_callback error_callback, void *data) +{ + int mib[4]; + size_t len; + char *name; + size_t rlen; + + mib[0] = mib0; + mib[1] = mib1; + mib[2] = mib2; + mib[3] = mib3; + + if (sysctl (mib, 4, NULL, , NULL, 0) < 0) +return NULL; + name = (char *) backtrace_alloc (state, len, error_callback, data); + if (name == NULL) +return NULL; + rlen = len; + if (sysctl (mib, 4, name, , NULL, 0) < 0) +{ + backtrace_free (state, name, len, error_callback, data); + return NULL; +} + return name; +} + +#ifdef HAVE_KERN_PROC_ARGS + +static char * +sysctl_exec_name1 (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + /* This variant is used on NetBSD. */ + return sysctl_exec_name (state, CTL_KERN, KERN_PROC_ARGS, -1, + KERN_PROC_PATHNAME, error_callback, data); +} + +#else + +#define sysctl_exec_name1(state, error_callback, data) NULL + +#endif + +#ifdef HAVE_KERN_PROC + +static char * +sysctl_exec_name2 (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + /* This variant is used on FreeBSD. */ + return sysctl_exec_name (state, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1, + error_callback, data); +} + +#else + +#define sysctl_exec_name2(state, error_callback, data) NULL + +#endif + +#endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */ + /* Initialize the fileline information from the executable. Returns 1 on success, 0 on failure. */ @@ -83,7 +159,7 @@ fileline_initialize (struct backtrace_state *state, descriptor = -1; called_error_callback = 0; - for (pass = 0; pass < 5; ++pass) + for (pass = 0; pass < 7; ++pass) { int does_not_exist; @@ -106,6 +182,12 @@ fileline_initialize (struct backtrace_state *state, (long) getpid ()); filename = buf; break; + case 5: + filename = sysctl_exec_name1 (state, error_callback, data); + break; + case 6: + filename = sysctl_exec_name2 (state, error_callback, data); + break; default: abort (); }
libbacktrace patch committed: Update test file
This libbacktrace patch updates the test file used for comparisons with zlib. The file that the test was previously using, from libgo, no longer exists. Use its replacement file instead. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2020-02-15 Ian Lance Taylor * ztest.c (test_large): Update file to current libgo test file. diff --git a/libbacktrace/ztest.c b/libbacktrace/ztest.c index 40f9c389a2a..2663c90061a 100644 --- a/libbacktrace/ztest.c +++ b/libbacktrace/ztest.c @@ -315,8 +315,8 @@ test_large (struct backtrace_state *state) size_t ctimes[16]; size_t ztimes[16]; static const char * const names[] = { -"Mark.Twain-Tom.Sawyer.txt", -"../libgo/go/compress/testdata/Mark.Twain-Tom.Sawyer.txt" +"Isaac.Newton-Opticks.txt", +"../libgo/go/testdata/Isaac.Newton-Opticks.txt", }; orig_buf = NULL;
libbacktrace patch committed: Always build tests with -g
This patch ensures that the libbacktrace tests are always built with -g. It also builds them with the default warning flags, so I had to add a few casts to ztest.c to get it pass without warnings. This should fix PR 90636. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2020-02-03 Ian Lance Taylor * Makefile.am (libbacktrace_TEST_CFLAGS): Define. (test_elf32_CFLAGS): Use $(libbacktrace_test_CFLAGS). (test_elf_64_CFLAGS, test_xcoff_32_CFLAGS): Likewise. (test_xcoff_64_CFLAGS, test_pecoff_CFLAGS): Likewise. (test_unknown_CFLAGS, unittest_CFLAGS): Likewise. (unittest_alloc_CFLAGS, allocfail_CFLAGS): Likewise. (b2test_CFLAGS, b3test_CFLAGS, btest_CFLAGS): Likewise. (btest_lto_CFLAGS, btest_alloc_CFLAGS, stest_CFLAGS): Likewise. (stest_alloc_CFLAGS): Likewise. * Makefile.in: Regenerate. * ztest.c (error_callback_compress): Mark vdata unused. (test_large): Add casts to avoid warnings. diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am index b251b7bc34a..c73f6633a76 100644 --- a/libbacktrace/Makefile.am +++ b/libbacktrace/Makefile.am @@ -93,6 +93,9 @@ TESTS = # Add test to this variable, if you want it to be build and run. BUILDTESTS = +# Flags to use when compiling test programs. +libbacktrace_TEST_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) -g + if NATIVE check_LTLIBRARIES = libbacktrace_alloc.la @@ -149,41 +152,49 @@ xcoff_%.c: xcoff.c mv $@.tmp $@ test_elf_32_SOURCES = test_format.c testlib.c +test_elf_32_CFLAGS = $(libbacktrace_TEST_CFLAGS) test_elf_32_LDADD = libbacktrace_noformat.la elf_32.lo BUILDTESTS += test_elf_32 test_elf_64_SOURCES = test_format.c testlib.c +test_elf_64_CFLAGS = $(libbacktrace_TEST_CFLAGS) test_elf_64_LDADD = libbacktrace_noformat.la elf_64.lo BUILDTESTS += test_elf_64 test_xcoff_32_SOURCES = test_format.c testlib.c +test_xcoff_32_CFLAGS = $(libbacktrace_TEST_CFLAGS) test_xcoff_32_LDADD = libbacktrace_noformat.la xcoff_32.lo BUILDTESTS += test_xcoff_32 test_xcoff_64_SOURCES = test_format.c testlib.c +test_xcoff_64_CFLAGS = $(libbacktrace_TEST_CFLAGS) test_xcoff_64_LDADD = libbacktrace_noformat.la xcoff_64.lo BUILDTESTS += test_xcoff_64 test_pecoff_SOURCES = test_format.c testlib.c +test_pecoff_CFLAGS = $(libbacktrace_TEST_CFLAGS) test_pecoff_LDADD = libbacktrace_noformat.la pecoff.lo BUILDTESTS += test_pecoff test_unknown_SOURCES = test_format.c testlib.c +test_unknown_CFLAGS = $(libbacktrace_TEST_CFLAGS) test_unknown_LDADD = libbacktrace_noformat.la unknown.lo BUILDTESTS += test_unknown unittest_SOURCES = unittest.c testlib.c +unittest_CFLAGS = $(libbacktrace_TEST_CFLAGS) unittest_LDADD = libbacktrace.la BUILDTESTS += unittest unittest_alloc_SOURCES = $(unittest_SOURCES) +unittest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) unittest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += unittest_alloc @@ -200,6 +211,7 @@ libbacktrace_instrumented_alloc_la_DEPENDENCIES = \ instrumented_alloc.lo: alloc.c allocfail_SOURCES = allocfail.c testlib.c +allocfail_CFLAGS = $(libbacktrace_TEST_CFLAGS) allocfail_LDADD = libbacktrace_instrumented_alloc.la check_PROGRAMS += allocfail @@ -212,7 +224,7 @@ if HAVE_ELF if HAVE_OBJCOPY_DEBUGLINK b2test_SOURCES = $(btest_SOURCES) -b2test_CFLAGS = $(btest_CFLAGS) +b2test_CFLAGS = $(libbacktrace_TEST_CFLAGS) b2test_LDFLAGS = -Wl,--build-id b2test_LDADD = libbacktrace_elf_for_test.la @@ -222,7 +234,7 @@ TESTS += b2test_buildid if HAVE_DWZ b3test_SOURCES = $(btest_SOURCES) -b3test_CFLAGS = $(btest_CFLAGS) +b3test_CFLAGS = $(libbacktrace_TEST_CFLAGS) b3test_LDFLAGS = -Wl,--build-id b3test_LDADD = libbacktrace_elf_for_test.la @@ -235,7 +247,7 @@ endif HAVE_OBJCOPY_DEBUGLINK endif HAVE_ELF btest_SOURCES = btest.c testlib.c -btest_CFLAGS = $(AM_CFLAGS) -g -O +btest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O btest_LDADD = libbacktrace.la BUILDTESTS += btest @@ -243,7 +255,7 @@ BUILDTESTS += btest if HAVE_ELF btest_lto_SOURCES = btest.c testlib.c -btest_lto_CFLAGS = $(AM_CFLAGS) -g -O -flto +btest_lto_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O -flto btest_lto_LDADD = libbacktrace.la BUILDTESTS += btest_lto @@ -251,7 +263,7 @@ BUILDTESTS += btest_lto endif HAVE_ELF btest_alloc_SOURCES = $(btest_SOURCES) -btest_alloc_CFLAGS = $(btest_CFLAGS) +btest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) btest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += btest_alloc @@ -277,11 +289,13 @@ endif HAVE_OBJCOPY_DEBUGLINK endif HAVE_DWZ stest_SOURCES = stest.c +stest_CFLAGS = $(libbacktrace_TEST_CFLAGS) stest_LDADD = libbacktrace.la BUILDTESTS += stest stest_alloc_SOURCES = $(stest_SOURCES) +stest_alloc_CFLAGS = $(libbacktrace_TEST_CFLAGS) stest_alloc_LDADD = libbacktrace_alloc.la BUILDTESTS += stest_alloc @@ -289,7 +303,7 @@ BUILDTESTS += stest_alloc if HAVE_ELF ztest_SOURCES = ztest.c testlib.c -ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\" +ztest_CFLAGS = $(libbacktrace_TEST_CFLAGS)
libbacktrace patch committed: Add DWARF 5 support
This patch to libbacktrace adds DWARF 5 support. I tested this with GCC 8, GCC tip, and clang 8, using the -gdwarf-5 option. Bootstrapped and ran libbacktrace and libgo tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2019-12-13 Ian Lance Taylor Add DWARF 5 support. * dwarf.c (struct attr): Add val field. (enum attr_val_encoding): Add ATTR_VAL_ADDDRESS_INDEX, ATTR_VAL_STRING_INDEX, ATTR_VAL_RNGLISTS_INDEX. (struct line_header): Add addrsize field. (struct line_header_format): Define. (struct unit): Add str_offsets_base, addr_base, and rnglists_base fields. (read_uint24): New static function. (read_attribute): Add implicit_val parameter. Replace dwarf_str and dwarf_str_size parameters with dwarf_sections parameter. Add support for new DWARF 5 forms. Change all callers. (resolve_string): New static function. (resolve_addr_index): Likewise. (read_abbrevs): Support DW_FORM_implicit_const. (struct pcrange): Add lowpc_is_addr_index, highpc_is_addr_Index, and ranges_is_index fields. (update_pcrange): Support DWARF 5 encodings. (add_high_low_range): New static function, split out of add_ranges. (add_ranges_from_ranges): Likewise. (add_ranges_from_rnglists): New static function. (add_ranges): Just call new helper functions. (find_address_ranges): Use resolve_string for strings, after reading all attributes. Handle new DWARF 5 attributes. (build_address_map): Support DWARF 5 compilation units. (read_v2_paths): New static function, split out of read_line_header. (read_lnct): New static function. (read_line_header_format_entries): Likewise. (read_line_header): Add ddata parameter. Support DWARF 5 line headers. Call new helper functions. Change all callers. (read_line_program): Use addrsize from line program header. Don't special case directory index 0 for DWARF 5. (read_referenced_name): Use resolve_string. (read_function_entry): Handle DWARF 5 encodings. Use resolve_string. * internal.h (enum dwarf_section): Add DEBUG_ADDR, DEBUG_STR_OFFSETS, DEBUG_LINE_STR, DEBUG_RNGLISTS. * elf.c (dwarf_section_names): Add new section names. * pecoff.c (dwarf_section_names): Likewise. * xcoff.c (xcoff_add): Clear dwarf_sections before setting fields. * configure.ac: Define HAVE_DWARF5 automake conditional. * Makefile.am (dwarf5_SOURCES): New variable if HAVE_DWARF5. (dwarf5_CFLAGS, dwarf5_LDADD): Likewise. (dwarf5_alloc_SOURCES, dwarf5_alloc_CFLAGS): Likewise. (dwarf5_alloc_LDADD): Likewise. (BUILDTESTS): Add dwarf5 tests if HAVE_DWARF5. (CLEANFILES, clean-local): Define. Index: Makefile.am === --- Makefile.am (revision 279211) +++ Makefile.am (working copy) @@ -385,12 +385,33 @@ BUILDTESTS += ctestg_alloc ctesta_alloc endif +if HAVE_DWARF5 + +dwarf5_SOURCES = btest.c testlib.c +dwarf5_CFLAGS = $(AM_CFLAGS) -gdwarf-5 +dwarf5_LDADD = libbacktrace.la + +BUILDTESTS += dwarf5 + +dwarf5_alloc_SOURCES = $(dwarf5_SOURCES) +dwarf5_alloc_CFLAGS = $(dwarf5_CFLAGS) +dwarf5_alloc_LDADD = libbacktrace_alloc.la + +BUILDTESTS += dwarf5_alloc + +endif + endif NATIVE check_PROGRAMS += $(BUILDTESTS) TESTS += $(BUILDTESTS) +CLEANFILES = $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build + +clean-local: + -rm -rf usr + # We can't use automake's automatic dependency tracking, because it # breaks when using bootstrap-lean. Automatic dependency tracking # with GCC bootstrap will cause some of the objects to depend on Index: configure.ac === --- configure.ac(revision 279211) +++ configure.ac(working copy) @@ -420,6 +420,17 @@ AC_SUBST(PTHREAD_CFLAGS) AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes) +dnl Test whether the compiler supports the -gdwarf-5 option. +AC_CACHE_CHECK([whether -gdwarf-5 is supported], +[libbacktrace_cv_lib_dwarf5], +[CFLAGS_hold=$CFLAGS +CFLAGS="$CFLAGS -gdwarf-5" +AC_COMPILE_IFELSE([AC_LANG_SOURCE([int i;])], +[libbacktrace_cv_lib_dwarf5=yes], +[libbacktrace_cv_lib_dwarf5=no]) +CFLAGS=$CFLAGS_hold]) +AM_CONDITIONAL(HAVE_DWARF5, test "$libbacktrace_cv_lib_dwarf5" = yes) + AC_CHECK_LIB([z], [compress], [AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.])]) AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes) Index: dwarf.c === --- dwarf.c (revision 279211) +++ dwarf.c (working copy) @@ -92,6 +92,8 @@ struct attr enum dwarf_attribute name; /* The attribute form. */ enum dwarf_form form; + /* The attribute value, for DW_FORM_implicit_const. */ + int64_t val; }; /* A single DWARF abbreviation. */ @@ -133,22 +135,29 @@ enum attr_val_encoding ATTR_VAL_NONE, /* An address. */ ATTR_VAL_ADDRESS, + /* An index into the .debug_addr section, whose value is relative to + * the DW_AT_addr_base attribute of the compilation unit. */ + ATTR_VAL_ADDRESS_INDEX, /* A unsigned integer. */
libbacktrace patch committed: Remove duplication of address handling
Before this patch libbacktrace duplicated the handling of DW_AT_low_pc, DW_AT_high_pc, and DW_AT_ranges, once to build a mapping from addresses to compilation units, and then again to build a mapping from addresses to functions within a compilation unit. This patch removes the duplication into a pair of functions, one of which takes a function pointer to actually add the appropriate mapping. This is a step toward adding DWARF 5 support, as DWARF 5 requires handling more cases here, and it seemed painful to introduce further duplication. Bootstrapped and ran libbacktrace and Go testsuites on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: dwarf.c === --- dwarf.c (revision 279094) +++ dwarf.c (working copy) @@ -945,31 +945,28 @@ function_addrs_search (const void *vkey, return 0; } -/* Add a new compilation unit address range to a vector. Returns 1 on - success, 0 on failure. */ +/* Add a new compilation unit address range to a vector. This is + called via add_ranges. Returns 1 on success, 0 on failure. */ static int -add_unit_addr (struct backtrace_state *state, uintptr_t base_address, - struct unit_addrs addrs, +add_unit_addr (struct backtrace_state *state, void *rdata, + uint64_t lowpc, uint64_t highpc, backtrace_error_callback error_callback, void *data, - struct unit_addrs_vector *vec) + void *pvec) { + struct unit *u = (struct unit *) rdata; + struct unit_addrs_vector *vec = (struct unit_addrs_vector *) pvec; struct unit_addrs *p; - /* Add in the base address of the module here, so that we can look - up the PC directly. */ - addrs.low += base_address; - addrs.high += base_address; - /* Try to merge with the last entry. */ if (vec->count > 0) { p = (struct unit_addrs *) vec->vec.base + (vec->count - 1); - if ((addrs.low == p->high || addrs.low == p->high + 1) - && addrs.u == p->u) + if ((lowpc == p->high || lowpc == p->high + 1) + && u == p->u) { - if (addrs.high > p->high) - p->high = addrs.high; + if (highpc > p->high) + p->high = highpc; return 1; } } @@ -980,8 +977,12 @@ add_unit_addr (struct backtrace_state *s if (p == NULL) return 0; - *p = addrs; + p->low = lowpc; + p->high = highpc; + p->u = u; + ++vec->count; + return 1; } @@ -1262,29 +1263,122 @@ lookup_abbrev (struct abbrevs *abbrevs, return (const struct abbrev *) p; } -/* Add non-contiguous address ranges for a compilation unit. Returns - 1 on success, 0 on failure. */ +/* This struct is used to gather address range information while + reading attributes. We use this while building a mapping from + address ranges to compilation units and then again while mapping + from address ranges to function entries. Normally either + lowpc/highpc is set or ranges is set. */ + +struct pcrange { + uint64_t lowpc; /* The low PC value. */ + int have_lowpc; /* Whether a low PC value was found. */ + uint64_t highpc; /* The high PC value. */ + int have_highpc; /* Whether a high PC value was found. */ + int highpc_is_relative; /* Whether highpc is relative to lowpc. */ + uint64_t ranges; /* Offset in ranges section. */ + int have_ranges; /* Whether ranges is valid. */ +}; + +/* Update PCRANGE from an attribute value. */ + +static void +update_pcrange (const struct attr* attr, const struct attr_val* val, + struct pcrange *pcrange) +{ + switch (attr->name) +{ +case DW_AT_low_pc: + if (val->encoding == ATTR_VAL_ADDRESS) + { + pcrange->lowpc = val->u.uint; + pcrange->have_lowpc = 1; + } + break; + +case DW_AT_high_pc: + if (val->encoding == ATTR_VAL_ADDRESS) + { + pcrange->highpc = val->u.uint; + pcrange->have_highpc = 1; + } + else if (val->encoding == ATTR_VAL_UINT) + { + pcrange->highpc = val->u.uint; + pcrange->have_highpc = 1; + pcrange->highpc_is_relative = 1; + } + break; + +case DW_AT_ranges: + if (val->encoding == ATTR_VAL_UINT + || val->encoding == ATTR_VAL_REF_SECTION) + { + pcrange->ranges = val->u.uint; + pcrange->have_ranges = 1; + } + break; + +default: + break; +} +} + +/* Call ADD_RANGE for each lowpc/highpc pair in PCRANGE. RDATA is + passed to ADD_RANGE, and is either a struct unit * or a struct + function *. VEC is the vector we are adding ranges to, and is + either a struct unit_addrs_vector * or a struct function_vector *. + Returns 1 on success, 0 on error. */ static int -add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, -struct unit *u, uint64_t ranges,
libbacktrace patch committed: Declare test1 in edtest.c with noclone
This libbacktrace patch adds the noclone attribute to the version of test1 in edtest.c, to correspond to other versions of test1. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2019-12-04 Ian Lance Taylor * edtest.c (test1): Add noclone attribute. Index: edtest.c === --- edtest.c(revision 278944) +++ edtest.c(working copy) @@ -43,8 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "testlib.h" -static int test1 (void) __attribute__ ((noinline, unused)); -static int test1 (void) __attribute__ ((noinline, unused)); +static int test1 (void) __attribute__ ((noinline, noclone, unused)); extern int f2 (int); extern int f3 (int, int);
libbacktrace patch committed: Simplify DWARF section handling
This libbacktrace patch simplifies the DWARF section handling. This is in preparation for DWARF 5 support, as DWARF 5 requires us to read more sections. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2019-12-04 Ian Lance Taylor * internal.h (enum dwarf_section): Define. (struct dwarf_sections): Define. (backtrace_dwarf_add): Update declaration to replace specific section parameters with dwarf_sections parameter. * dwarf.c (struct dwarf_data): Replace specific section fields with dwarf_sections field. (read_attribute): Use dwarf_sections with altlink. (build_address_map): Replace specific section parameters with dwarf_sections parameter. Change all callers. (read_line_info): Use dwarf_sections with ddata. (read_referenced_name): Likewise. (add_function_ranges): Likewise. (read_function_entry): Likewise. (read_function_info): Likewise. (build_dwarf_data): Replace specific section parameters with dwarf_sections parameter. Change all callers. (backtrace_dwarf_add): Likewise. * elf.c (enum debug_section): Remove. (dwarf_section_names): Remove .zdebug names. (elf_add): Track zsections separately. Build dwarf_sections. * pecoff.c (enum debug_section): Remove. (struct debug_section_info): Remove data field. (coff_add): Build dwarf_sections. * xcoff.c (enum dwarf_section): Remove. Replace DWSECT_xxx references with DEBUG_xxx references. (xcoff_add): Build dwarf_sections. Index: dwarf.c === --- dwarf.c (revision 278944) +++ dwarf.c (working copy) @@ -373,18 +373,8 @@ struct dwarf_data 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; + /* The unparsed DWARF debug data. */ + struct dwarf_sections dwarf_sections; /* Whether the data is big-endian or not. */ int is_bigendian; /* A vector used for function addresses. We keep this here so that @@ -871,13 +861,14 @@ read_attribute (enum dwarf_form form, st val->encoding = ATTR_VAL_NONE; return 1; } - if (offset >= altlink->dwarf_str_size) + if (offset >= altlink->dwarf_sections.size[DEBUG_STR]) { 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; + val->u.string = + (const char *) altlink->dwarf_sections.data[DEBUG_STR] + offset; return 1; } default: @@ -1499,10 +1490,7 @@ find_address_ranges (struct backtrace_st static int build_address_map (struct backtrace_state *state, uintptr_t base_address, - const unsigned char *dwarf_info, size_t dwarf_info_size, - const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, - const unsigned char *dwarf_str, size_t dwarf_str_size, + const struct dwarf_sections *dwarf_sections, int is_bigendian, struct dwarf_data *altlink, backtrace_error_callback error_callback, void *data, struct unit_addrs_vector *addrs, @@ -1525,9 +1513,9 @@ build_address_map (struct backtrace_stat not sure why. */ info.name = ".debug_info"; - info.start = dwarf_info; - info.buf = dwarf_info; - info.left = dwarf_info_size; + info.start = dwarf_sections->data[DEBUG_INFO]; + info.buf = info.start; + info.left = dwarf_sections->size[DEBUG_INFO]; info.is_bigendian = is_bigendian; info.error_callback = error_callback; info.data = data; @@ -1583,7 +1571,9 @@ build_address_map (struct backtrace_stat memset (>abbrevs, 0, sizeof u->abbrevs); abbrev_offset = read_offset (_buf, is_dwarf64); - if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size, + if (!read_abbrevs (state, abbrev_offset, +dwarf_sections->data[DEBUG_ABBREV], +dwarf_sections->size[DEBUG_ABBREV], is_bigendian, error_callback, data, >abbrevs)) goto fail; @@ -1610,8 +1600,10 @@ build_address_map (struct backtrace_stat u->function_addrs_count = 0; if (!find_address_ranges (state, base_address, _buf, - dwarf_str, dwarf_str_size, - dwarf_ranges, dwarf_ranges_size, +
libbacktrace patch committed: Only run ztest if HAVE_ELF
This libbacktrace patch only runs the two ztest tests if HAVE_ELF is true, since we only do uncompression on ELF. This should fix PR 89699. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2019-03-11 Ian Lance Taylor PR libbacktrace/89669 * Makefile.am (BUILDTESTS): Only add ztest and ztest_alloc if HAVE_ELF. * Makefile.in: Regenerate. Index: Makefile.am === --- Makefile.am (revision 269593) +++ Makefile.am (working copy) @@ -272,6 +272,8 @@ stest_alloc_LDADD = libbacktrace_alloc.l BUILDTESTS += stest_alloc +if HAVE_ELF + ztest_SOURCES = ztest.c testlib.c ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\" ztest_LDADD = libbacktrace.la @@ -291,6 +293,8 @@ ztest_alloc_CFLAGS = $(ztest_CFLAGS) BUILDTESTS += ztest_alloc +endif HAVE_ELF + edtest_SOURCES = edtest.c edtest2_build.c testlib.c edtest_LDADD = libbacktrace.la
libbacktrace patch committed: backtrace_create_state should be called once
This patch to libbacktrace expands the comment for backtrace_create_state to make clear that it should be called only once. There is no backtrace_free_state function. While it would be nice to have such a function, it's hard to write completely accurately as libbacktrace doesn't currently track all memory allocations. Committed to mainline. Ian 2018-10-05 Ian Lance Taylor PR libbacktrace/87529 * backtrace.h: Document that backtrace_create_state should be called only once. Index: backtrace.h === --- backtrace.h (revision 264813) +++ backtrace.h (working copy) @@ -92,7 +92,13 @@ typedef void (*backtrace_error_callback) use appropriate atomic operations. If THREADED is zero the state may only be accessed by one thread at a time. This returns a state pointer on success, NULL on error. If an error occurs, this will - call the ERROR_CALLBACK routine. */ + call the ERROR_CALLBACK routine. + + Calling this function allocates resources that can not be freed. + There is no backtrace_free_state function. The state is used to + cache information that is expensive to recompute. Programs are + expected to call this function at most once and to save the return + value for all later calls to backtrace functions. */ extern struct backtrace_state *backtrace_create_state ( const char *filename, int threaded,
Re: libbacktrace patch committed: Call munmap after memory test
On Tue, Apr 17, 2018 at 10:29 AM, Ian Lance Taylorwrote: > On Tue, Apr 17, 2018 at 10:21 AM, Tom de Vries wrote: >> On 04/17/2018 03:59 PM, Ian Lance Taylor wrote: >>> >>> The bug report https://github.com/ianlancetaylor/libbacktrace/issues/13 >>> points out that when backtrace_full checks whether memory is >>> available, it doesn't necessarily release that memory. It will stay >>> on the free list, so libbacktrace will use more and more memory over >>> time. This patch fixes that problem by explicitly calling munmap. >>> Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. >>> Committed to mainline. >>> >>> Ian >>> >>> >>> 2018-04-17 Ian Lance Taylor >>> >>> * backtrace.c (backtrace_full): When testing whether we can >>> allocate memory, call mmap directly, and munmap the memory. >>> >>> >>> patch.txt >>> >>> >>> Index: backtrace.c >>> === >>> --- backtrace.c (revision 259359) >>> +++ backtrace.c (working copy) >>> @@ -32,12 +32,26 @@ POSSIBILITY OF SUCH DAMAGE. */ >>> #include "config.h" >>> +#include >>> #include >>> +#if !BACKTRACE_USES_MALLOC >>> +#include >>> +#endif >>> + >> >> >> Hi, >> >> this breaks the nvptx build: >> ... >> libbacktrace/backtrace.c:39:10: fatal error: sys/mman.h: No such file or >> directory >> #include >> ^~~~ >> compilation terminated. > > Sorry about that. Committed this patch, which should fix that problem. Actually, never mind. Looks like this didn't fix the problem. I'm just reverting back to the state as of earlier today. Ian 2018-04-17 Ian Lance Taylor * backtrace.c: Revert last two changes. Don't call mmap directly. Index: backtrace.c === --- backtrace.c (revision 259439) +++ backtrace.c (working copy) @@ -32,27 +32,12 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include #include -#include "backtrace-supported.h" - -#if !BACKTRACE_USES_MALLOC -#include -#endif - #include "unwind.h" #include "backtrace.h" #include "internal.h" -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - /* The main backtrace_full routine. */ /* Data passed through _Unwind_Backtrace. */ @@ -119,6 +104,7 @@ backtrace_full (struct backtrace_state * backtrace_error_callback error_callback, void *data) { struct backtrace_data bdata; + void *p; bdata.skip = skip + 1; bdata.state = state; @@ -127,25 +113,16 @@ backtrace_full (struct backtrace_state * bdata.data = data; bdata.ret = 0; -#if !BACKTRACE_USES_MALLOC - { -size_t pagesize; -void *page; - -/* If we can't allocate any memory at all, don't try to produce - file/line information. */ -pagesize = getpagesize (); -page = mmap (NULL, pagesize, PROT_READ | PROT_WRITE, -MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -if (page == MAP_FAILED) - bdata.can_alloc = 0; -else - { - munmap (page, pagesize); - bdata.can_alloc = 1; - } - } -#endif + /* If we can't allocate any memory at all, don't try to produce + file/line information. */ + p = backtrace_alloc (state, 4096, NULL, NULL); + if (p == NULL) +bdata.can_alloc = 0; + else +{ + backtrace_free (state, p, 4096, NULL, NULL); + bdata.can_alloc = 1; +} _Unwind_Backtrace (unwind, ); return bdata.ret;
Re: libbacktrace patch committed: Call munmap after memory test
On Tue, Apr 17, 2018 at 10:21 AM, Tom de Vrieswrote: > On 04/17/2018 03:59 PM, Ian Lance Taylor wrote: >> >> The bug report https://github.com/ianlancetaylor/libbacktrace/issues/13 >> points out that when backtrace_full checks whether memory is >> available, it doesn't necessarily release that memory. It will stay >> on the free list, so libbacktrace will use more and more memory over >> time. This patch fixes that problem by explicitly calling munmap. >> Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. >> Committed to mainline. >> >> Ian >> >> >> 2018-04-17 Ian Lance Taylor >> >> * backtrace.c (backtrace_full): When testing whether we can >> allocate memory, call mmap directly, and munmap the memory. >> >> >> patch.txt >> >> >> Index: backtrace.c >> === >> --- backtrace.c (revision 259359) >> +++ backtrace.c (working copy) >> @@ -32,12 +32,26 @@ POSSIBILITY OF SUCH DAMAGE. */ >> #include "config.h" >> +#include >> #include >> +#if !BACKTRACE_USES_MALLOC >> +#include >> +#endif >> + > > > Hi, > > this breaks the nvptx build: > ... > libbacktrace/backtrace.c:39:10: fatal error: sys/mman.h: No such file or > directory > #include > ^~~~ > compilation terminated. Sorry about that. Committed this patch, which should fix that problem. Ian 2018-04-17 Ian Lance Taylor * backtrace.c: Include backtrace-supported.h before checking BACKTRACE_USES_MALLOC. Index: backtrace.c === --- backtrace.c (revision 259434) +++ backtrace.c (working copy) @@ -35,13 +35,14 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #include +#include "backtrace-supported.h" + #if !BACKTRACE_USES_MALLOC #include #endif #include "unwind.h" #include "backtrace.h" -#include "backtrace-supported.h" #include "internal.h" #ifndef MAP_ANONYMOUS
Re: libbacktrace patch committed: Call munmap after memory test
On 04/17/2018 03:59 PM, Ian Lance Taylor wrote: The bug report https://github.com/ianlancetaylor/libbacktrace/issues/13 points out that when backtrace_full checks whether memory is available, it doesn't necessarily release that memory. It will stay on the free list, so libbacktrace will use more and more memory over time. This patch fixes that problem by explicitly calling munmap. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2018-04-17 Ian Lance Taylor* backtrace.c (backtrace_full): When testing whether we can allocate memory, call mmap directly, and munmap the memory. patch.txt Index: backtrace.c === --- backtrace.c (revision 259359) +++ backtrace.c (working copy) @@ -32,12 +32,26 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +#include #include +#if !BACKTRACE_USES_MALLOC +#include +#endif + Hi, this breaks the nvptx build: ... libbacktrace/backtrace.c:39:10: fatal error: sys/mman.h: No such file or directory #include ^~~~ compilation terminated. ... Thanks, - Tom #include "unwind.h" #include "backtrace.h" +#include "backtrace-supported.h" #include "internal.h" +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + /* The main backtrace_full routine. */ /* Data passed through _Unwind_Backtrace. */ @@ -104,7 +118,6 @@ backtrace_full (struct backtrace_state * backtrace_error_callback error_callback, void *data) { struct backtrace_data bdata; - void *p; bdata.skip = skip + 1; bdata.state = state; @@ -113,16 +126,25 @@ backtrace_full (struct backtrace_state * bdata.data = data; bdata.ret = 0; - /* If we can't allocate any memory at all, don't try to produce - file/line information. */ - p = backtrace_alloc (state, 4096, NULL, NULL); - if (p == NULL) -bdata.can_alloc = 0; - else -{ - backtrace_free (state, p, 4096, NULL, NULL); - bdata.can_alloc = 1; -} +#if !BACKTRACE_USES_MALLOC + { +size_t pagesize; +void *page; + +/* If we can't allocate any memory at all, don't try to produce + file/line information. */ +pagesize = getpagesize (); +page = mmap (NULL, pagesize, PROT_READ | PROT_WRITE, +MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +if (page == MAP_FAILED) + bdata.can_alloc = 0; +else + { + munmap (page, pagesize); + bdata.can_alloc = 1; + } + } +#endif _Unwind_Backtrace (unwind, ); return bdata.ret;
libbacktrace patch committed: Call munmap after memory test
The bug report https://github.com/ianlancetaylor/libbacktrace/issues/13 points out that when backtrace_full checks whether memory is available, it doesn't necessarily release that memory. It will stay on the free list, so libbacktrace will use more and more memory over time. This patch fixes that problem by explicitly calling munmap. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2018-04-17 Ian Lance Taylor* backtrace.c (backtrace_full): When testing whether we can allocate memory, call mmap directly, and munmap the memory. Index: backtrace.c === --- backtrace.c (revision 259359) +++ backtrace.c (working copy) @@ -32,12 +32,26 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +#include #include +#if !BACKTRACE_USES_MALLOC +#include +#endif + #include "unwind.h" #include "backtrace.h" +#include "backtrace-supported.h" #include "internal.h" +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + /* The main backtrace_full routine. */ /* Data passed through _Unwind_Backtrace. */ @@ -104,7 +118,6 @@ backtrace_full (struct backtrace_state * backtrace_error_callback error_callback, void *data) { struct backtrace_data bdata; - void *p; bdata.skip = skip + 1; bdata.state = state; @@ -113,16 +126,25 @@ backtrace_full (struct backtrace_state * bdata.data = data; bdata.ret = 0; - /* If we can't allocate any memory at all, don't try to produce - file/line information. */ - p = backtrace_alloc (state, 4096, NULL, NULL); - if (p == NULL) -bdata.can_alloc = 0; - else -{ - backtrace_free (state, p, 4096, NULL, NULL); - bdata.can_alloc = 1; -} +#if !BACKTRACE_USES_MALLOC + { +size_t pagesize; +void *page; + +/* If we can't allocate any memory at all, don't try to produce + file/line information. */ +pagesize = getpagesize (); +page = mmap (NULL, pagesize, PROT_READ | PROT_WRITE, +MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +if (page == MAP_FAILED) + bdata.can_alloc = 0; +else + { + munmap (page, pagesize); + bdata.can_alloc = 1; + } + } +#endif _Unwind_Backtrace (unwind, ); return bdata.ret;
libbacktrace patch committed: Close debuginfo files
This patch to libbacktrace closes any debuginfo files that we opened. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. This should fix https://golang.org/issue/23626. Committed to mainline. Ian 2018-01-31 Ian Lance Taylor* elf.c (elf_add): Close descriptor if we use a debugfile. * btest.c (check_open_files): New static function. (main): Call check_open_files. Index: btest.c === --- btest.c (revision 257217) +++ btest.c (working copy) @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #include #include +#include #include "filenames.h" @@ -456,6 +457,25 @@ test5 (void) 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 @@ -474,5 +494,7 @@ main (int argc ATTRIBUTE_UNUSED, char ** #endif #endif + check_open_files (); + exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); } Index: elf.c === --- elf.c (revision 257217) +++ elf.c (working copy) @@ -2929,12 +2929,19 @@ elf_add (struct backtrace_state *state, error_callback, data); if (d >= 0) { + int ret; + backtrace_release_view (state, _view, error_callback, data); if (debuglink_view_valid) backtrace_release_view (state, _view, error_callback, data); - return elf_add (state, NULL, d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, 0, 1); + ret = elf_add (state, NULL, d, base_address, error_callback, data, +fileline_fn, found_sym, found_dwarf, 0, 1); + if (ret < 0) + backtrace_close (d, error_callback, data); + else + backtrace_close (descriptor, error_callback, data); + return ret; } } @@ -2953,10 +2960,17 @@ elf_add (struct backtrace_state *state, data); if (d >= 0) { + int ret; + backtrace_release_view (state, _view, error_callback, data); - return elf_add (state, NULL, d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, 0, 1); + ret = elf_add (state, NULL, d, base_address, error_callback, data, +fileline_fn, found_sym, found_dwarf, 0, 1); + if (ret < 0) + backtrace_close (d, error_callback, data); + else + backtrace_close(descriptor, error_callback, data); + return ret; } }
libbacktrace patch committed: Only free sym_view if it is valid
Another libbacktrace patch to avoid use of uninitialized memory: only free sym_view if it is valid. Committed to mainline. Ian 2018-01-25 Ian Lance Taylor* pecoff.c (coff_add): Only release syms_view if it is valid. Index: pecoff.c === --- pecoff.c(revision 257052) +++ pecoff.c(working copy) @@ -804,8 +804,11 @@ coff_add (struct backtrace_state *state, backtrace_release_view (state, _view, error_callback, data); sects_view_valid = 0; - backtrace_release_view (state, _view, error_callback, data); - syms_view_valid = 0; + if (syms_view_valid) +{ + backtrace_release_view (state, _view, error_callback, data); + syms_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. */
libbacktrace patch committed: Another memcpy -> coff_read4 fix
This libbacktrace patch fixes another cases where memcpy was used in a way that would leave some bytes uninitialized on a 64-bit system. Committed to mainline. Ian 2018-01-25 Ian Lance Taylor* pecoff.c (coff_add): Another memcpy -> coff_read4 fix. Index: pecoff.c === --- pecoff.c(revision 257040) +++ pecoff.c(working copy) @@ -631,10 +631,10 @@ coff_add (struct backtrace_state *state, goto fail; { -const char *vptr = (const char *)fhdr_view.data; +const unsigned char *vptr = fhdr_view.data; if (vptr[0] == 'M' && vptr[1] == 'Z') - memcpy (_off, vptr + 0x3c, 4); + fhdr_off = coff_read4 (vptr + 0x3c); else fhdr_off = 0; }
libbacktrace patch committed: Fix setting str_size on PE/COFF
This libbacktrace patch fixes the setting of str_size on PE/COFF to not leave some bytes uninitialized on a 64-bit host. Committed to mainline. Ian 2018-01-24 Ian Lance Taylor* pecoff.c (coff_add): Use coff_read4, not memcpy. Index: pecoff.c === --- pecoff.c(revision 257038) +++ pecoff.c(working copy) @@ -727,7 +727,7 @@ coff_add (struct backtrace_state *state, goto fail; syms_view_valid = 1; - memcpy (_size, syms_view.data + syms_size, 4); + str_size = coff_read4 (syms_view.data + syms_size); str_off = syms_off + syms_size;
libbacktrace patch committed: Only keep 16 entries on free list
PR 68239 points out that libbacktrace can sometimes take a long time scanning the list of free memory blocks looking for one that is large enough. Since the libbacktrace memory allocator does not have to be perfect in practice, only keep the 16 largest entries on the free list. Bootstrapped and ran libbacktrace and libgo tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2018-01-24 Ian Lance TaylorPR other/68239 * mmap.c (backtrace_free_locked): Don't put more than 16 entries on the free list. Index: mmap.c === --- mmap.c (revision 257038) +++ mmap.c (working copy) @@ -69,11 +69,33 @@ struct backtrace_freelist_struct static void backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size) { - /* Just leak small blocks. We don't have to be perfect. */ + /* Just leak small blocks. We don't have to be perfect. Don't put + more than 16 entries on the free list, to avoid wasting time + searching when allocating a block. If we have more than 16 + entries, leak the smallest entry. */ + if (size >= sizeof (struct backtrace_freelist_struct)) { + size_t c; + struct backtrace_freelist_struct **ppsmall; + struct backtrace_freelist_struct **pp; struct backtrace_freelist_struct *p; + c = 0; + ppsmall = NULL; + for (pp = >freelist; *pp != NULL; pp = &(*pp)->next) + { + if (ppsmall == NULL || (*pp)->size < (*ppsmall)->size) + ppsmall = pp; + ++c; + } + if (c >= 16) + { + if (size <= (*ppsmall)->size) + return; + *ppsmall = (*ppsmall)->next; + } + p = (struct backtrace_freelist_struct *) addr; p->next = state->freelist; p->size = size;
libbacktrace patch committed: Fix handling of inflate default dist table
I misunderstood how the dist codes are handled in block type 1. I also think'od the length of the codes for the default table. This patch fixes these problems, along with a test case that exposes them. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2018-01-16 Ian Lance Taylor* elf.c (codes) [GENERATE_FIXED_HUFFMAN_TABLE]: Fix size to be 288. (main) [GENERATE_FIXED_HUFFMAN_TABLE]: Pass 288 to elf_zlib_inflate_table. Generate elf_zlib_default_dist_table. (elf_zlib_default_table): Update. (elf_zlib_default_dist_table): New static array. (elf_zlib_inflate): Use elf_zlib_default_dist_table for dist table for block type 1. * ztest.c (struct zlib_test): Add uncompressed_len. (tests): Initialize uncompressed_len field. Add new test case. (test_samples): Use uncompressed_len field. Index: elf.c === --- elf.c (revision 256593) +++ elf.c (working copy) @@ -1461,7 +1461,7 @@ elf_zlib_inflate_table (unsigned char *c #include static uint16_t table[ZDEBUG_TABLE_SIZE]; -static unsigned char codes[287]; +static unsigned char codes[288]; int main () @@ -1476,7 +1476,7 @@ main () codes[i] = 7; for (i = 280; i <= 287; ++i) codes[i] = 8; - if (!elf_zlib_inflate_table ([0], 287, [0], [0])) + if (!elf_zlib_inflate_table ([0], 288, [0], [0])) { fprintf (stderr, "elf_zlib_inflate_table failed\n"); exit (EXIT_FAILURE); @@ -1495,48 +1495,72 @@ main () printf ("\n"); } printf ("};\n"); + printf ("\n"); + + for (i = 0; i < 32; ++i) +codes[i] = 5; + if (!elf_zlib_inflate_table ([0], 32, [0], [0])) +{ + fprintf (stderr, "elf_zlib_inflate_table failed\n"); + exit (EXIT_FAILURE); +} + + printf ("static const uint16_t elf_zlib_default_dist_table[%#zx] =\n", + final_next_secondary + 0x100); + printf ("{\n"); + for (i = 0; i < final_next_secondary + 0x100; i += 8) +{ + size_t j; + + printf (" "); + for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j) + printf (" %#x,", table[j]); + printf ("\n"); +} + printf ("};\n"); + return 0; } #endif -/* The fixed table generated by the #ifdef'ed out main function +/* The fixed tables generated by the #ifdef'ed out main function above. */ static const uint16_t elf_zlib_default_table[0x170] = { - 0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1232, - 0xd08, 0xe60, 0xe20, 0x1212, 0xe00, 0xe80, 0xe40, 0x1252, - 0xd04, 0xe58, 0xe18, 0x1202, 0xd14, 0xe78, 0xe38, 0x1242, - 0xd0c, 0xe68, 0xe28, 0x1222, 0xe08, 0xe88, 0xe48, 0x1262, - 0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x123a, - 0xd0a, 0xe64, 0xe24, 0x121a, 0xe04, 0xe84, 0xe44, 0x125a, - 0xd06, 0xe5c, 0xe1c, 0x120a, 0xd16, 0xe7c, 0xe3c, 0x124a, - 0xd0e, 0xe6c, 0xe2c, 0x122a, 0xe0c, 0xe8c, 0xe4c, 0x126a, - 0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1236, - 0xd09, 0xe62, 0xe22, 0x1216, 0xe02, 0xe82, 0xe42, 0x1256, - 0xd05, 0xe5a, 0xe1a, 0x1206, 0xd15, 0xe7a, 0xe3a, 0x1246, - 0xd0d, 0xe6a, 0xe2a, 0x1226, 0xe0a, 0xe8a, 0xe4a, 0x1266, - 0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123e, - 0xd0b, 0xe66, 0xe26, 0x121e, 0xe06, 0xe86, 0xe46, 0x125e, - 0xd07, 0xe5e, 0xe1e, 0x120e, 0xd17, 0xe7e, 0xe3e, 0x124e, - 0xd0f, 0xe6e, 0xe2e, 0x122e, 0xe0e, 0xe8e, 0xe4e, 0x126e, - 0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1234, - 0xd08, 0xe61, 0xe21, 0x1214, 0xe01, 0xe81, 0xe41, 0x1254, - 0xd04, 0xe59, 0xe19, 0x1204, 0xd14, 0xe79, 0xe39, 0x1244, - 0xd0c, 0xe69, 0xe29, 0x1224, 0xe09, 0xe89, 0xe49, 0x1264, - 0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123c, - 0xd0a, 0xe65, 0xe25, 0x121c, 0xe05, 0xe85, 0xe45, 0x125c, - 0xd06, 0xe5d, 0xe1d, 0x120c, 0xd16, 0xe7d, 0xe3d, 0x124c, - 0xd0e, 0xe6d, 0xe2d, 0x122c, 0xe0d, 0xe8d, 0xe4d, 0x126c, - 0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1238, - 0xd09, 0xe63, 0xe23, 0x1218, 0xe03, 0xe83, 0xe43, 0x1258, - 0xd05, 0xe5b, 0xe1b, 0x1208, 0xd15, 0xe7b, 0xe3b, 0x1248, - 0xd0d, 0xe6b, 0xe2b, 0x1228, 0xe0b, 0xe8b, 0xe4b, 0x1268, - 0xd03, 0xe57, 0xe17, 0x1200, 0xd13, 0xe77, 0xe37, 0x1240, - 0xd0b, 0xe67, 0xe27, 0x1220, 0xe07, 0xe87, 0xe47, 0x1260, - 0xd07, 0xe5f, 0xe1f, 0x1210, 0xd17, 0xe7f, 0xe3f, 0x1250, - 0xd0f, 0xe6f, 0xe2f, 0x1230, 0xe0f, 0xe8f, 0xe4f, 0, + 0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1230, + 0xd08, 0xe60, 0xe20, 0x1210, 0xe00, 0xe80, 0xe40, 0x1250, + 0xd04, 0xe58, 0xe18, 0x1200, 0xd14, 0xe78, 0xe38, 0x1240, + 0xd0c, 0xe68, 0xe28, 0x1220, 0xe08, 0xe88, 0xe48, 0x1260, + 0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x1238, + 0xd0a, 0xe64, 0xe24, 0x1218, 0xe04, 0xe84, 0xe44, 0x1258, + 0xd06, 0xe5c, 0xe1c, 0x1208, 0xd16, 0xe7c, 0xe3c, 0x1248, + 0xd0e, 0xe6c, 0xe2c, 0x1228, 0xe0c, 0xe8c, 0xe4c, 0x1268, + 0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1234, + 0xd09, 0xe62, 0xe22, 0x1214, 0xe02, 0xe82, 0xe42, 0x1254, + 0xd05,
Re: libbacktrace patch committed: Support compressed debug sections
On Sat, Nov 4, 2017 at 3:07 AM, Gerald Pfeiferwrote: > On Fri, 6 Oct 2017, Ian Lance Taylor wrote: >> Thanks for the report. I committed this patch, which I hope will fix >> the problem. > >> * ztest.c (test_large): Pass unsigned long *, not size_t *, to >> zlib uncompress function. > > Thank you, yes it did. (Sorry, I thought I had responded back > then, but apparently only in my mind, not with my keyboard.) > > I'm seeing the following as part of my nightly builds, though: > >test hello: got uncompressed length 0, want 13 >test goodbye: got uncompressed length 0, want 14 >inflate large: got uncompressed length 0, want 387851 > > Any idea what this might be? No, no idea, sorry. That seems strange, as though the uncompressor is not doing anything for some reason. Can you debug a bit? Ian
Re: libbacktrace patch committed: Support compressed debug sections
On Fri, 6 Oct 2017, Ian Lance Taylor wrote: > Thanks for the report. I committed this patch, which I hope will fix > the problem. > * ztest.c (test_large): Pass unsigned long *, not size_t *, to > zlib uncompress function. Thank you, yes it did. (Sorry, I thought I had responded back then, but apparently only in my mind, not with my keyboard.) I'm seeing the following as part of my nightly builds, though: test hello: got uncompressed length 0, want 13 test goodbye: got uncompressed length 0, want 14 inflate large: got uncompressed length 0, want 387851 Any idea what this might be? Gerald
Re: GCC 7 libbacktrace patch committed: Ignore compressed debug sections
On Tue, Oct 10, 2017 at 12:47 PM, Paolo Carliniwrote: > > On 10/10/2017 18:55, Ian Lance Taylor wrote: >> >> Index: elf.c >> === >> --- elf.c (revision 253593) >> +++ elf.c (working copy) >> @@ -103,6 +103,7 @@ >> #undef SHT_SYMTAB >> #undef SHT_STRTAB >> #undef SHT_DYNSYM >> +#undef SFH_COMPRESSED >> #undef STT_OBJECT >> #undef STT_FUNC > > You appear to have a typo here: SFH_COMPRESSED instead of SHF_COMPRESSED. > That breaks the bootstrap for me: > > ../../../../gcc-7-branch/libsanitizer/libbacktrace/../../libbacktrace/elf.c:199:0: > error: "SHF_COMPRESSED" redefined [-Werror] > #define SHF_COMPRESSED 0x800 > > I'm going to test and commit the obvious fix, if nobody beats me to it. Argh. Sorry about that. Please do commit the obvious fix. Thanks. Ian
Re: GCC 7 libbacktrace patch committed: Ignore compressed debug sections
Hi, On 10/10/2017 18:55, Ian Lance Taylor wrote: Index: elf.c === --- elf.c (revision 253593) +++ elf.c (working copy) @@ -103,6 +103,7 @@ #undef SHT_SYMTAB #undef SHT_STRTAB #undef SHT_DYNSYM +#undef SFH_COMPRESSED #undef STT_OBJECT #undef STT_FUNC You appear to have a typo here: SFH_COMPRESSED instead of SHF_COMPRESSED. That breaks the bootstrap for me: ../../../../gcc-7-branch/libsanitizer/libbacktrace/../../libbacktrace/elf.c:199:0: error: "SHF_COMPRESSED" redefined [-Werror] #define SHF_COMPRESSED 0x800 I'm going to test and commit the obvious fix, if nobody beats me to it. Paolo.
GCC 7 libbacktrace patch committed: Ignore compressed debug sections
This patch to the GCC 7 libbacktrace ignores compressed debug sections. If we don't, the DWARF reader reports an error. Since the GCC 7 libbacktrace does not support uncompressing the debug sections, ignoring them is the best approach (on trunk, we uncompress). This is for PR 80914. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu. Committed to GCC 7 branch. Ian 2017-10-10 Ian Lance TaylorPR go/80914 * elf.c (SHF_COMPRESSED): Define. (elf_add): Ignore debug sections with SHF_COMPRESSED set. Index: elf.c === --- elf.c (revision 253593) +++ elf.c (working copy) @@ -103,6 +103,7 @@ #undef SHT_SYMTAB #undef SHT_STRTAB #undef SHT_DYNSYM +#undef SFH_COMPRESSED #undef STT_OBJECT #undef STT_FUNC @@ -195,6 +196,8 @@ #define SHT_STRTAB 3 #define SHT_DYNSYM 11 +#define SHF_COMPRESSED 0x800 + #if BACKTRACE_ELF_SIZE == 32 typedef struct @@ -700,7 +703,8 @@ for (j = 0; j < (int) DEBUG_MAX; ++j) { - if (strcmp (name, debug_section_names[j]) == 0) + if (strcmp (name, debug_section_names[j]) == 0 + && (shdr->sh_flags & SHF_COMPRESSED) == 0) { sections[j].offset = shdr->sh_offset; sections[j].size = shdr->sh_size;
Re: libbacktrace patch committed: Support compressed debug sections
On Fri, Oct 6, 2017 at 3:22 AM, Gerald Pfeiferwrote: > On Thu, 28 Sep 2017, Ian Lance Taylor wrote: >> This patch to libbacktrace adds support for compressed debug sections. >> 2017-09-28 Ian Lance Taylor >> >> PR other/67165 >> * elf.c (__builtin_prefetch): Define if not __GNUC__. >> (unlikely): Define. >> (SHF_UNCOMPRESSED, ELFCOMPRESS_ZLIB): Define. >> (b_elf_chdr): Define type. >> (enum debug_section): Add ZDEBUG_xxx values. > > Since this change I am seeing the following in my night GCC build > and test logs on FreeBSD systems: > > gmake[2]: autogen: Command not found > gmake[2]: *** [Makefile:176: check] Error 127 > gmake[1]: *** [Makefile:3759: check-fixincludes] Error 2 > /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c: In function 'test_large': > /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:384:41: warning: passing > argument 2 of 'uncompress' from incompatible pointer type > [-Wincompatible-pointer-types] >r = uncompress (uncompressed_buf, _bufsize, > ^ > In file included from /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:43:0: > /usr/include/zlib.h:1265:21: note: expected 'uLongf * {aka long unsigned int > *}' but argument is of type 'size_t * {aka unsigned int *}' > ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, > ^~ > /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c: In function 'test_large': > /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:384:41: warning: passing > argument 2 of 'uncompress' from incompatible pointer type > [-Wincompatible-pointer-types] >r = uncompress (uncompressed_buf, _bufsize, > ^ > In file included from /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:43:0: > /usr/include/zlib.h:1265:21: note: expected 'uLongf * {aka long unsigned int > *}' but argument is of type 'size_t * {aka unsigned int *}' > ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, > ^~ > gmake[4]: *** [Makefile:306: check-DEJAGNU] Error 1 > gmake[3]: *** [Makefile:350: check-am] Error 2 > gmake[2]: *** [Makefile:904: check-recursive] Error 1 > gmake[1]: *** [Makefile:22343: check-target-libgomp] Error 2 > Fatal error 'mutex is on list' at line 272 in file > /usr/src/lib/libthr/thread/thr_mutex.c (errno = 0) > Fatal error 'mutex is on list' at line 272 in file > /usr/src/lib/libthr/thread/thr_mutex.c (errno = 0) > gmake: *** [Makefile:2286: do-check] Error 2 Thanks for the report. I committed this patch, which I hope will fix the problem. Ian 2017-10-06 Ian Lance Taylor * ztest.c (test_large): Pass unsigned long *, not size_t *, to zlib uncompress function. Index: ztest.c === --- ztest.c (revision 253490) +++ ztest.c (working copy) @@ -369,6 +369,8 @@ test_large (struct backtrace_state *stat for (i = 0; i < trials; ++i) { + unsigned long uncompress_sizearg; + cid = ZLIB_CLOCK_GETTIME_ARG; if (clock_gettime (cid, ) < 0) { @@ -406,7 +408,8 @@ test_large (struct backtrace_state *stat return; } - r = uncompress (uncompressed_buf, _bufsize, + uncompress_sizearg = uncompressed_bufsize; + r = uncompress (uncompressed_buf, _sizearg, compressed_buf + 12, compressed_bufsize - 12); if (clock_gettime (cid, ) < 0)
Re: libbacktrace patch committed: Support compressed debug sections
On Thu, 28 Sep 2017, Ian Lance Taylor wrote: > This patch to libbacktrace adds support for compressed debug sections. > 2017-09-28 Ian Lance Taylor> > PR other/67165 > * elf.c (__builtin_prefetch): Define if not __GNUC__. > (unlikely): Define. > (SHF_UNCOMPRESSED, ELFCOMPRESS_ZLIB): Define. > (b_elf_chdr): Define type. > (enum debug_section): Add ZDEBUG_xxx values. Since this change I am seeing the following in my night GCC build and test logs on FreeBSD systems: gmake[2]: autogen: Command not found gmake[2]: *** [Makefile:176: check] Error 127 gmake[1]: *** [Makefile:3759: check-fixincludes] Error 2 /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c: In function 'test_large': /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:384:41: warning: passing argument 2 of 'uncompress' from incompatible pointer type [-Wincompatible-pointer-types] r = uncompress (uncompressed_buf, _bufsize, ^ In file included from /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:43:0: /usr/include/zlib.h:1265:21: note: expected 'uLongf * {aka long unsigned int *}' but argument is of type 'size_t * {aka unsigned int *}' ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, ^~ /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c: In function 'test_large': /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:384:41: warning: passing argument 2 of 'uncompress' from incompatible pointer type [-Wincompatible-pointer-types] r = uncompress (uncompressed_buf, _bufsize, ^ In file included from /scratch/tmp/gerald/GCC-HEAD/libbacktrace/ztest.c:43:0: /usr/include/zlib.h:1265:21: note: expected 'uLongf * {aka long unsigned int *}' but argument is of type 'size_t * {aka unsigned int *}' ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, ^~ gmake[4]: *** [Makefile:306: check-DEJAGNU] Error 1 gmake[3]: *** [Makefile:350: check-am] Error 2 gmake[2]: *** [Makefile:904: check-recursive] Error 1 gmake[1]: *** [Makefile:22343: check-target-libgomp] Error 2 Fatal error 'mutex is on list' at line 272 in file /usr/src/lib/libthr/thread/thr_mutex.c (errno = 0) Fatal error 'mutex is on list' at line 272 in file /usr/src/lib/libthr/thread/thr_mutex.c (errno = 0) gmake: *** [Makefile:2286: do-check] Error 2 Gerald
libbacktrace patch committed: Minor decompression improvement
I've committed a patch to libbacktrace to speed up decompression a few percent by loading 32-bit values rather than 8-bit bytes. Bootstrapped and ran libbacktrace and Go tests on x86_64-pc-linux-gnu. Committed to mainline. Ian 2017-10-05 Ian Lance Taylor* elf.c (elf_zlib_fetch): Change pval argument to uint64_t *. Read a four byte integer. (elf_zlib_inflate): Change val to uint64_t. Align pin to a 32-bit boundary before ever calling elf_zlib_fetch. * ztest.c (test_large): Simplify print statements a bit. Index: elf.c === --- elf.c (revision 253376) +++ elf.c (working copy) @@ -1031,11 +1031,12 @@ elf_zlib_failed(void) static int elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend, - uint32_t *pval, unsigned int *pbits) + uint64_t *pval, unsigned int *pbits) { unsigned int bits; const unsigned char *pin; - uint32_t val; + uint64_t val; + uint32_t next; bits = *pbits; if (bits >= 15) @@ -1043,20 +1044,25 @@ elf_zlib_fetch (const unsigned char **pp pin = *ppin; val = *pval; - if (unlikely (pinend - pin < 2)) + if (unlikely (pinend - pin < 4)) { elf_zlib_failed (); return 0; } - val |= pin[0] << bits; - val |= pin[1] << (bits + 8); - bits += 16; - pin += 2; - - /* We will need the next two bytes soon. We ask for high temporal - locality because we will need the whole cache line soon. */ - __builtin_prefetch (pin, 0, 3); - __builtin_prefetch (pin + 1, 0, 3); + + /* We've ensured that PIN is aligned. */ + next = *(const uint32_t *)pin; + +#if __BYTE_ORDER == __ORDER_BIG_ENDIAN + next = __builtin_bswap32 (next); +#endif + + val |= (uint64_t)next << bits; + bits += 32; + pin += 4; + + /* We will need the next four bytes soon. */ + __builtin_prefetch (pin, 0, 0); *ppin = pin; *pval = val; @@ -1566,7 +1572,7 @@ elf_zlib_inflate (const unsigned char *p poutend = pout + sout; while ((pinend - pin) > 4) { - uint32_t val; + uint64_t val; unsigned int bits; int last; @@ -1601,10 +1607,19 @@ elf_zlib_inflate (const unsigned char *p } pin += 2; - /* Read blocks until one is marked last. */ + /* Align PIN to a 32-bit boundary. */ val = 0; bits = 0; + while uintptr_t) pin) & 3) != 0) + { + val |= (uint64_t)*pin << bits; + bits += 8; + ++pin; + } + + /* Read blocks until one is marked last. */ + last = 0; while (!last) @@ -1671,6 +1686,14 @@ elf_zlib_inflate (const unsigned char *p pout += len; pin += len; + /* Align PIN. */ + while uintptr_t) pin) & 3) != 0) + { + val |= (uint64_t)*pin << bits; + bits += 8; + ++pin; + } + /* Go around to read the next block. */ continue; } Index: ztest.c === --- ztest.c (revision 253377) +++ ztest.c (working copy) @@ -432,9 +432,9 @@ test_large (struct backtrace_state *stat ctime = average_time (ctimes, trials); ztime = average_time (ztimes, trials); - printf ("backtrace time: %zu ns\n", ctime); - printf ("zlib time:: %zu ns\n", ztime); - printf ("percentage: %g\n", (double) ztime / (double) ctime); + printf ("backtrace: %zu ns\n", ctime); + printf ("zlib : %zu ns\n", ztime); + printf ("ratio: %g\n", (double) ztime / (double) ctime); return;
Re: libbacktrace patch committed: Support compressed debug sections
Thanks for the fixes. I made some style tweaks, committed as follows after bootstrap and testing. Ian 2017-10-02 Ian Lance Taylor* ztest.c: #include . (TEST_TIMING): Don't define, don't test. (xclock_gettime, xclockid_t): Define if !HAVE_CLOCK_GETTIME. (clockid_t, clock_gettime, CLOCK_REALTIME): Likewise. (ZLIB_CLOCK_GETTIME_ARG): Define. * configure.ac: Change clock_gettime_link to CLOCK_GETTIME_LINK. * Makefile.am: Likewise. * configure, Makefile.in: Rebuild. Index: Makefile.am === --- Makefile.am (revision 253376) +++ Makefile.am (working copy) @@ -108,7 +108,7 @@ ztest_LDADD = libbacktrace.la if HAVE_ZLIB ztest_LDADD += -lz endif -ztest_LDADD += $(clock_gettime_link) +ztest_LDADD += $(CLOCK_GETTIME_LINK) check_PROGRAMS += ztest Index: configure.ac === --- configure.ac(revision 253376) +++ configure.ac(working copy) @@ -397,11 +397,11 @@ clock_gettime_link= # we're using this for test timing only. if test "$ac_cv_func_clock_gettime" = no; then AC_CHECK_LIB(rt, clock_gettime, -[clock_gettime_link=-lrt +[CLOCK_GETTIME_LINK=-lrt AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define to 1 if you have the `clock_gettime' function.])]) fi -AC_SUBST(clock_gettime_link) +AC_SUBST(CLOCK_GETTIME_LINK) dnl Test whether the compiler supports the -pthread option. AC_CACHE_CHECK([whether -pthread is supported], Index: ztest.c === --- ztest.c (revision 253376) +++ ztest.c (working copy) @@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +#include #include #include #include @@ -43,16 +44,37 @@ POSSIBILITY OF SUCH DAMAGE. */ #include #endif -#ifdef HAVE_CLOCK_GETTIME -# define TEST_TIMING -#endif - #include "backtrace.h" #include "backtrace-supported.h" #include "internal.h" #include "testlib.h" +#ifndef HAVE_CLOCK_GETTIME + +typedef int xclockid_t; + +static int +xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED, + struct timespec *ts ATTRIBUTE_UNUSED) +{ + errno = EINVAL; + return -1; +} + +#define clockid_t xclockid_t +#define clock_gettime xclock_gettime +#undef CLOCK_REALTIME +#define CLOCK_REALTIME 0 + +#endif /* !defined(HAVE_CLOCK_GETTIME) */ + +#ifdef CLOCK_PROCESS_CPUTIME_ID +#define ZLIB_CLOCK_GETTIME_ARG CLOCK_PROCESS_CPUTIME_ID +#else +#define ZLIB_CLOCK_GETTIME_ARG CLOCK_REALTIME +#endif + /* Some tests for the local zlib inflation code. */ struct zlib_test @@ -161,7 +183,7 @@ test_samples (struct backtrace_state *st } } -#if defined HAVE_ZLIB && defined TEST_TIMING +#ifdef HAVE_ZLIB /* Given a set of TRIALS timings, discard the lowest and highest values and return the mean average of the rest. */ @@ -220,7 +242,6 @@ test_large (struct backtrace_state *stat unsigned char *uncompressed_buf; size_t uncompressed_bufsize; int r; -# ifdef TEST_TIMING clockid_t cid; struct timespec ts1; struct timespec ts2; @@ -229,7 +250,6 @@ test_large (struct backtrace_state *stat const size_t trials = 16; size_t ctimes[16]; size_t ztimes[16]; -# endif /* TEST_TIMING */ static const char * const names[] = { "Mark.Twain-Tom.Sawyer.txt", "../libgo/go/compress/testdata/Mark.Twain-Tom.Sawyer.txt" @@ -347,16 +367,13 @@ test_large (struct backtrace_state *stat printf ("PASS: inflate large\n"); -# ifdef TEST_TIMING - for (i = 0; i < trials; ++i) { - cid = CLOCK_REALTIME; -#ifdef CLOCK_PROCESS_CPUTIME_ID - cid = CLOCK_PROCESS_CPUTIME_ID; -#endif + cid = ZLIB_CLOCK_GETTIME_ARG; if (clock_gettime (cid, ) < 0) { + if (errno == EINVAL) + return; perror ("clock_gettime"); return; } @@ -419,8 +436,6 @@ test_large (struct backtrace_state *stat printf ("zlib time:: %zu ns\n", ztime); printf ("percentage: %g\n", (double) ztime / (double) ctime); -# endif /* TEST_TIMING */ - return; fail:
Re: libbacktrace patch committed: Support compressed debug sections
Hi! On Mon, 02 Oct 2017 14:00:36 +0200, I wrote: > On Thu, 28 Sep 2017 17:30:53 -0700, Ian Lance Taylorwrote: > > This patch to libbacktrace adds support for compressed debug sections. > > [...] > > > --- ztest.c (revision 0) > > +++ ztest.c (working copy) > > @@ -0,0 +1,446 @@ > > +/* ztest.c -- Test for libbacktrace inflate code. > > +[...] > > + cid = CLOCK_REALTIME; > > +#ifdef CLOCK_PROCESS_CPUTIME_ID > > + cid = CLOCK_PROCESS_CPUTIME_ID; > > +#endif > > + if (clock_gettime (cid, ) < 0) > > +[...] > > On an elderly system, I ran into that not linking [...] > {+ztest-ztest.o: In function `test_large':+} > {+[...]/source-gcc/libbacktrace/ztest.c:350: undefined reference to > `clock_gettime'+} That's because the version of glibc used still provided clock_gettime in librt only. Committed to trunk r253345, as obvious: commit 0b986d3d7a36d3b3f84a0221f8a48af55e9aa08a Author: tschwinge Date: Mon Oct 2 11:56:39 2017 + libbacktrace: Support the case that clock_gettime is in librt libbacktrace/ PR other/67165 * Makefile.am: Append the content of clock_gettime_link to ztest_LDADD. * configure.ac: Test for the case that clock_gettime is in librt. * Makefile.in: Regenerate. * configure: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@253345 138bc75d-0d04-0410-961f-82ee72b054a4 --- libbacktrace/ChangeLog| 7 ++ libbacktrace/Makefile.am | 1 + libbacktrace/Makefile.in | 6 +++-- libbacktrace/configure| 56 +-- libbacktrace/configure.ac | 12 ++ 5 files changed, 78 insertions(+), 4 deletions(-) diff --git libbacktrace/ChangeLog libbacktrace/ChangeLog index 0e4cfd2..fde5a1b 100644 --- libbacktrace/ChangeLog +++ libbacktrace/ChangeLog @@ -1,6 +1,13 @@ 2017-10-02 Thomas Schwinge PR other/67165 + * Makefile.am: Append the content of clock_gettime_link to + ztest_LDADD. + * configure.ac: Test for the case that clock_gettime is in librt. + * Makefile.in: Regenerate. + * configure: Likewise. + + PR other/67165 * configure.ac: Check for clock_gettime. * config.h.in: Regenerate. * configure: Likewise. diff --git libbacktrace/Makefile.am libbacktrace/Makefile.am index 11d94eb..b4f4df4 100644 --- libbacktrace/Makefile.am +++ libbacktrace/Makefile.am @@ -108,6 +108,7 @@ ztest_LDADD = libbacktrace.la if HAVE_ZLIB ztest_LDADD += -lz endif +ztest_LDADD += $(clock_gettime_link) check_PROGRAMS += ztest diff --git libbacktrace/Makefile.in libbacktrace/Makefile.in index ceb769d..30a1442 100644 --- libbacktrace/Makefile.in +++ libbacktrace/Makefile.in @@ -165,7 +165,7 @@ ttest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ @NATIVE_TRUE@ ztest-testlib.$(OBJEXT) ztest_OBJECTS = $(am_ztest_OBJECTS) @NATIVE_TRUE@ztest_DEPENDENCIES = libbacktrace.la \ -@NATIVE_TRUE@ $(am__DEPENDENCIES_1) +@NATIVE_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) ztest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ @@ -287,6 +287,7 @@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ +clock_gettime_link = @clock_gettime_link@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ @@ -383,7 +384,8 @@ TESTS = $(check_PROGRAMS) $(am__append_4) @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_2) \ +@NATIVE_TRUE@ $(clock_gettime_link) @NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c @NATIVE_TRUE@edtest_LDADD = libbacktrace.la @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_SOURCES = ttest.c testlib.c diff --git libbacktrace/configure libbacktrace/configure index 062dc77..57ca5eb 100755 --- libbacktrace/configure +++ libbacktrace/configure @@ -614,6 +614,7 @@ HAVE_ZLIB_TRUE HAVE_PTHREAD_FALSE HAVE_PTHREAD_TRUE PTHREAD_CFLAGS +clock_gettime_link BACKTRACE_USES_MALLOC ALLOC_FILE VIEW_FILE @@ -11145,7 +11146,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11148 "configure" +#line 11149 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11251,7 +11252,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11254 "configure" +#line 11255 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12759,6 +12760,57 @@ _ACEOF fi done +clock_gettime_link= +# At least for glibc,
Re: libbacktrace patch committed: Support compressed debug sections
Hi! On Thu, 28 Sep 2017 17:30:53 -0700, Ian Lance Taylorwrote: > This patch to libbacktrace adds support for compressed debug sections. > [...] > --- ztest.c (revision 0) > +++ ztest.c (working copy) > @@ -0,0 +1,446 @@ > +/* ztest.c -- Test for libbacktrace inflate code. > +[...] > + cid = CLOCK_REALTIME; > +#ifdef CLOCK_PROCESS_CPUTIME_ID > + cid = CLOCK_PROCESS_CPUTIME_ID; > +#endif > + if (clock_gettime (cid, ) < 0) > +[...] On an elderly system, I ran into that not linking, and thus *all* libbacktrace testing disappearing: [...] {+ztest-ztest.o: In function `test_large':+} {+[...]/source-gcc/libbacktrace/ztest.c:350: undefined reference to `clock_gettime'+} {+[...]/source-gcc/libbacktrace/ztest.c:368: undefined reference to `clock_gettime'+} {+[...]/source-gcc/libbacktrace/ztest.c:378: undefined reference to `clock_gettime'+} {+[...]/source-gcc/libbacktrace/ztest.c:387: undefined reference to `clock_gettime'+} {+collect2: error: ld returned 1 exit status+} {+make[3]: *** [ztest] Error 1+} [...] [-make[3]: Leaving directory `[...]/build-gcc/libbacktrace'-] [-make check-TESTS-] [-make[3]: Entering directory `[...]/build-gcc/libbacktrace'-] [-objcopy --only-keep-debug btest btest.debug-] [-objcopy --strip-debug --add-gnu-debuglink=btest.debug btest dtest-] [-PASS: backtrace_full noinline-] [-PASS: backtrace_full inline-] [-PASS: backtrace_simple noinline-] [-PASS: backtrace_simple inline-] [-PASS: backtrace_syminfo variable-] [-PASS: btest-] [-PASS: stest-] [-PASS: backtrace_full alloc stress-] [-PASS: edtest-] [-PASS: threaded backtrace_full noinline-] [-PASS: ttest-] [-PASS: backtrace_full noinline-] [-PASS: backtrace_full inline-] [-PASS: backtrace_simple noinline-] [-PASS: backtrace_simple inline-] [-PASS: backtrace_syminfo variable-] [-PASS: dtest-] [-==[PID][PID][PID][PID]-] [-All 5 tests passed-] [-==[PID][PID][PID][PID]-] make[3]: Leaving directory `[...]/build-gcc/libbacktrace' {+make[2]: *** [check-am] Error 2+} {+make[2]: Target `check' not remade because of errors.+} make[2]: Leaving directory `[...]/build-gcc/libbacktrace' {+make[1]: *** [check-libbacktrace] Error 2+} [...] Committed to trunk r253344, as obvious: commit c476d11ef7dbd508067067fbd0b8450d27f1f057 Author: tschwinge Date: Mon Oct 2 11:56:25 2017 + libbacktrace: Conditionalize test timing on clock_gettime availability libbacktrace/ PR other/67165 * configure.ac: Check for clock_gettime. * config.h.in: Regenerate. * configure: Likewise. * ztest.c (average_time, test_large): Conditionalize test timing on clock_gettime availability. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@253344 138bc75d-0d04-0410-961f-82ee72b054a4 --- libbacktrace/ChangeLog| 9 + libbacktrace/config.h.in | 3 +++ libbacktrace/configure| 13 + libbacktrace/configure.ac | 3 +++ libbacktrace/ztest.c | 12 +++- 5 files changed, 39 insertions(+), 1 deletion(-) diff --git libbacktrace/ChangeLog libbacktrace/ChangeLog index 9597a68..0e4cfd2 100644 --- libbacktrace/ChangeLog +++ libbacktrace/ChangeLog @@ -1,3 +1,12 @@ +2017-10-02 Thomas Schwinge + + PR other/67165 + * configure.ac: Check for clock_gettime. + * config.h.in: Regenerate. + * configure: Likewise. + * ztest.c (average_time, test_large): Conditionalize test timing + on clock_gettime availability. + 2017-09-29 Tony Reix * xcoff.c: Initial support for DWARF debug sections in XCOFF. diff --git libbacktrace/config.h.in libbacktrace/config.h.in index a9f70da..c19b6e4 100644 --- libbacktrace/config.h.in +++ libbacktrace/config.h.in @@ -9,6 +9,9 @@ /* Define to 1 if you have the __atomic functions */ #undef HAVE_ATOMIC_FUNCTIONS +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + /* Define to 1 if you have the declaration of `strnlen', and to 0 if you don't. */ #undef HAVE_DECL_STRNLEN diff --git libbacktrace/configure libbacktrace/configure index ece4151..062dc77 100755 --- libbacktrace/configure +++ libbacktrace/configure @@ -12747,6 +12747,19 @@ $as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h fi +# Check for the clock_gettime function. +for ac_func in clock_gettime +do : + ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" +if test "x$ac_cv_func_clock_gettime" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_CLOCK_GETTIME 1 +_ACEOF + +fi +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5 $as_echo_n "checking whether -pthread is
libbacktrace patch committed: Support compressed debug sections
This patch to libbacktrace adds support for compressed debug sections. Rather than require all users of libbacktrace to link against -lz, I wrote new code in libbacktrace to inflate a zlib stream. Because the code does not have to be as flexible as zlib, and because it is only used to uncompress from one memory buffer to another and therefore does not need to provide a streaming interface, and because I wasted a day speeding it up, it's a few percent faster than zlib (at least as measured by the simple benchmark in the new ztest.c file). This fixes PR 67165. Bootstrapped and ran libbacktrace and Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian 2017-09-28 Ian Lance TaylorPR other/67165 * elf.c (__builtin_prefetch): Define if not __GNUC__. (unlikely): Define. (SHF_UNCOMPRESSED, ELFCOMPRESS_ZLIB): Define. (b_elf_chdr): Define type. (enum debug_section): Add ZDEBUG_xxx values. (debug_section_names): Add names for new sections. (struct debug_section_info): Add compressed field. (elf_zlib_failed, elf_zlib_fetch): New static functions. (HUFFMAN_TABLE_SIZE, HUFFMAN_VALUE_MASK): Define. (HUFFMAN_BITS_SHIFT, HUFFMAN_BITS_MASK): Define. (HUFFMAN_SECONDARY_SHIFT): Define. (ZDEBUG_TABLE_SIZE): Define. (ZDEBUG_TABLE_CODELEN_OFFSET, ZDEBUG_TABLE_WORK_OFFSET): Define. (final_next_secondary): New static variable if BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE. (elf_zlib_inflate_table): New static function. (BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE): If define, define main function to produce fixed Huffman table. (elf_zlib_default_table): New static variable. (elf_zlib_inflate): New static function. (elf_zlib_verify_checksum): Likewise. (elf_zlib_inflate_and_verify): Likewise. (elf_uncompress_zdebug): Likewise. (elf_uncompress_chdr): Likewise. (backtrace_uncompress_zdebug): New extern function. (elf_add): Look for .zdebug sections and SHF_COMPRESSED debug sections, and uncompress them. * internal.h (backtrace_compress_zdebug): Declare. * ztest.c: New file. * configure.ac: Check for -lz and check whether the linker supports --compress-debug-sections. * Makefile.am (ztest_SOURCES): New variable. (ztest_CFLAGS, ztest_LDADD): New variables. (check_PROGRAMS): Add ztest. (ctestg_SOURCES): New variable. (ctestg_CFLAGS, ctestg_LDFLAGS, ctestg_LDADD): New variables. (ctesta_SOURCES): New variable. (ctesta_CFLAGS, ctesta_LDFLAGS, ctesta_LDADD): New variables. (check_PROGRAMS): Add ctestg and ctesta. * configure, config.h.in, Makefile.in: Rebuild. Index: Makefile.am === --- Makefile.am (revision 253270) +++ Makefile.am (working copy) @@ -101,6 +101,16 @@ stest_LDADD = libbacktrace.la check_PROGRAMS += stest +ztest_SOURCES = ztest.c testlib.c +ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\" +ztest_LDADD = libbacktrace.la + +if HAVE_ZLIB +ztest_LDADD += -lz +endif + +check_PROGRAMS += ztest + edtest_SOURCES = edtest.c edtest2_build.c testlib.c edtest_LDADD = libbacktrace.la @@ -132,6 +142,22 @@ dtest: btest endif HAVE_OBJCOPY_DEBUGLINK +if HAVE_COMPRESSED_DEBUG + +ctestg_SOURCES = btest.c testlib.c +ctestg_CFLAGS = $(AM_CFLAGS) -g +ctestg_LDFLAGS = -Wl,--compress-debug-sections=zlib-gnu +ctestg_LDADD = libbacktrace.la + +ctesta_SOURCES = btest.c testlib.c +ctesta_CFLAGS = $(AM_CFLAGS) -g +ctesta_LDFLAGS = -Wl,--compress-debug-sections=zlib-gabi +ctesta_LDADD = libbacktrace.la + +check_PROGRAMS += ctestg ctesta + +endif + endif NATIVE # We can't use automake's automatic dependency tracking, because it Index: configure.ac === --- configure.ac(revision 253270) +++ configure.ac(working copy) @@ -405,6 +405,23 @@ AC_SUBST(PTHREAD_CFLAGS) AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes) +AC_CHECK_LIB([z], [compress], []) +if test $ac_cv_lib_z_compress = "yes"; then + AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.]) +fi +AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes) + +dnl Test whether the linker supports the --compress_debug_sections option. +AC_CACHE_CHECK([whether --compress-debug-sections is supported], +[libgo_cv_ld_compress], +[LDFLAGS_hold=$LDFLAGS +LDFLAGS="$LDFLAGS -Wl,--compress-debug-sections=zlib-gnu" +AC_LINK_IFELSE([AC_LANG_PROGRAM(,)], +[libgo_cv_ld_compress=yes], +[libgo_cv_ld_compress=no]) +LDFLAGS=$LDFLAGS_hold]) +AM_CONDITIONAL(HAVE_COMPRESSED_DEBUG, test "$libgo_cv_ld_compress" = yes) + AC_ARG_VAR(OBJCOPY, [location of objcopy]) AC_CHECK_PROG(OBJCOPY, objcopy, objcopy,) AC_CACHE_CHECK([whether objcopy supports debuglink], Index: elf.c === --- elf.c (revision 253270) +++ elf.c (working copy) @@ -56,6 +56,13 @@ POSSIBILITY OF SUCH DAMAGE. */ #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) #endif +#ifndef __GNUC__ +#define __builtin_prefetch(p, r, l) +#define unlikely(x) (x) +#else +#define unlikely(x)
libbacktrace patch committed: Replace lstat and readlink if not available
This patch to libbacktrace provides dummy versions of lstat and readlink if they are not available on the system. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu both normally and with a hand-edited config.h. Committed to mainline. Ian 2017-09-22 Ian Lance TaylorPR sanitizer/77631 * configure.ac: Check for lstat and readlink. * elf.c (lstat, readlink): Provide dummy versions if real versions are not available. * configure, config.h.in: Rebuild. Index: configure.ac === --- configure.ac(revision 253093) +++ configure.ac(working copy) @@ -373,6 +373,7 @@ if test "$have_fcntl" = "yes"; then fi AC_CHECK_DECLS(strnlen) +AC_CHECK_FUNCS(lstat readlink) # Check for getexecname function. if test -n "${with_target_subdir}"; then Index: elf.c === --- elf.c (revision 253093) +++ elf.c (working copy) @@ -75,6 +75,35 @@ xstrnlen (const char *s, size_t maxlen) #endif +#ifndef HAVE_LSTAT + +/* Dummy version of lstat for systems that don't have it. */ + +static int +xlstat (const char *path ATTRIBUTE_UNUSED, struct stat *st ATTRIBUTE_UNUSED) +{ + return -1; +} + +#define lstat xlstat + +#endif + +#ifndef HAVE_READLINK + +/* Dummy version of readlink for systems that don't have it. */ + +static ssize_t +xreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED, + size_t bufsz ATTRIBUTE_UNUSED) +{ + return -1; +} + +#define readlink xreadlink + +#endif + #ifndef HAVE_DL_ITERATE_PHDR /* Dummy version of dl_iterate_phdr for systems that don't have it. */
libbacktrace patch committed: Fix uninitialized field
I somehow failed to initialize the exe_filename field of phdr_data, which most likely led to PR 82284. Bootstrapped and ran libbacktrace tests for this obvious fix. Committed to mainline. Ian 2017-09-21 Ian Lance TaylorPR go/82284 * elf.c (backtrace_initialize): Set pd.exe_filename. Index: elf.c === --- elf.c (revision 253076) +++ elf.c (working copy) @@ -1489,6 +1489,7 @@ pd.fileline_fn = _fileline_fn; pd.found_sym = _sym; pd.found_dwarf = _dwarf; + pd.exe_filename = filename; pd.exe_descriptor = ret < 0 ? descriptor : -1; dl_iterate_phdr (phdr_callback, (void *) );
libbacktrace patch committed: Fix race on parallel initialization
The code in libbacktrace had a race when doing parallel initialization: if two threads start to initialize at the same time, and one completes first, the other, while running in backtrace_initialize, may see that the structure is initialized and thus not change *fileline_fn. The caller will then set state->fileline_fn to *fileline_fn, but since backtrace_initialize has not changed it that will be NULL. The effect is that if the timing is right the code can then call a NULL function pointer. This patch fixes the problem by always initializing *fileline_fn in backtrace_initialize. It adds a test in ttest.c that does 10 backtraces in parallel with an new state. To make writing the test easier I copied the test support functions out of btest.c into testlib.c. While doing that I eliminated some of the duplication in edtest.c by making that use testlib.c as well. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: Makefile.am === --- Makefile.am (revision 249070) +++ Makefile.am (working copy) @@ -89,7 +89,7 @@ TESTS = $(check_PROGRAMS) if NATIVE -btest_SOURCES = btest.c +btest_SOURCES = btest.c testlib.c btest_CFLAGS = $(AM_CFLAGS) -g -O btest_LDADD = libbacktrace.la @@ -100,7 +100,7 @@ stest_LDADD = libbacktrace.la check_PROGRAMS += stest -edtest_SOURCES = edtest.c edtest2_build.c +edtest_SOURCES = edtest.c edtest2_build.c testlib.c edtest_LDADD = libbacktrace.la check_PROGRAMS += edtest @@ -111,6 +111,16 @@ gen_edtest2_build: $(srcdir)/edtest2.c $(SHELL) $(srcdir)/../move-if-change tmp-edtest2_build.c edtest2_build.c echo timestamp > $@ +if HAVE_PTHREAD + +check_PROGRAMS += ttest + +ttest_SOURCES = ttest.c testlib.c +ttest_CFLAGS = -pthread +ttest_LDADD = libbacktrace.la + +endif HAVE_PTHREAD + endif NATIVE # We can't use automake's automatic dependency tracking, because it Index: btest.c === --- btest.c (revision 249070) +++ btest.c (working copy) @@ -43,237 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "backtrace.h" #include "backtrace-supported.h" -/* Portable attribute syntax. Actually some of these tests probably - won't work if the attributes are not recognized. */ - -#ifndef GCC_VERSION -# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) -#endif - -#if (GCC_VERSION < 2007) -# define __attribute__(x) -#endif - -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - -/* Used to collect backtrace info. */ - -struct info -{ - char *filename; - int lineno; - char *function; -}; - -/* Passed to backtrace callback function. */ - -struct bdata -{ - struct info *all; - size_t index; - size_t max; - int failed; -}; - -/* Passed to backtrace_simple callback function. */ - -struct sdata -{ - uintptr_t *addrs; - size_t index; - size_t max; - int failed; -}; - -/* Passed to backtrace_syminfo callback function. */ - -struct symdata -{ - const char *name; - uintptr_t val, size; - int failed; -}; - -/* The backtrace state. */ - -static void *state; - -/* The number of failures. */ - -static int failures; - -/* Return the base name in a path. */ - -static const char * -base (const char *p) -{ - const char *last; - const char *s; - - last = NULL; - for (s = p; *s != '\0'; ++s) -{ - if (IS_DIR_SEPARATOR (*s)) - last = s + 1; -} - return last != NULL ? last : p; -} - -/* Check an entry in a struct info array. */ - -static void -check (const char *name, int index, const struct info *all, int want_lineno, - const char *want_function, int *failed) -{ - if (*failed) -return; - if (all[index].filename == NULL || all[index].function == NULL) -{ - fprintf (stderr, "%s: [%d]: missing file name or function name\n", - name, index); - *failed = 1; - return; -} - if (strcmp (base (all[index].filename), "btest.c") != 0) -{ - fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index, - all[index].filename); - *failed = 1; -} - if (all[index].lineno != want_lineno) -{ - fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index, - all[index].lineno, want_lineno); - *failed = 1; -} - if (strcmp (all[index].function, want_function) != 0) -{ - fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index, - all[index].function, want_function); - *failed = 1; -} -} - -/* The backtrace callback function. */ - -static int -callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, - const char *filename, int lineno, const char *function) -{ - struct bdata *data = (struct bdata *) vdata; - struct info *p; - - if (data->index >= data->max) -{ - fprintf (stderr, "callback_one: callback called too many times\n"); - data->failed = 1; -
libbacktrace patch committed: Update dependencies
Although libbacktrace uses automake, it can't use automatic dependency tracking, because it breaks when using bootstrap-lean (PR 54732). The dependencies for sort.lo and stest.lo were never added to the list. Also, the dependencies for backtrace.lo were not updated for my recent change to that file. This patch fixes the problem. Committed to mainline. Ian 2015-09-11 Ian Lance Taylor* Makefile.am (backtrace.lo): Depend on internal.h. (sort.lo, stest.lo): Add explicit dependencies. * Makefile.in: Rebuild. Index: Makefile.am === --- Makefile.am (revision 227673) +++ Makefile.am (working copy) @@ -116,7 +116,7 @@ endif NATIVE INCDIR = $(top_srcdir)/../include alloc.lo: config.h backtrace.h internal.h -backtrace.lo: config.h backtrace.h +backtrace.lo: config.h backtrace.h internal.h btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \ $(INCDIR)/filenames.h backtrace.h internal.h @@ -130,5 +130,7 @@ posix.lo: config.h backtrace.h internal. print.lo: config.h backtrace.h internal.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 unknown.lo: config.h backtrace.h internal.h
libbacktrace patch committed: fix test for mmap failure
PR 67457 points out a crash in libbacktrace when there is no memory available. This is because the code testing the mmap result for failure is broken. This patch fixes it. Bootstrapped and ran libbacktrace tests. Committed to mainline. Ian 2015-09-08 Ian Lance TaylorPR other/67457 * mmap.c (backtrace_alloc): Correct test for mmap failure. Index: mmap.c === --- mmap.c (revision 227528) +++ mmap.c (working copy) @@ -139,7 +139,7 @@ backtrace_alloc (struct backtrace_state asksize = (size + pagesize - 1) & ~ (pagesize - 1); page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (page == NULL) + if (page == MAP_FAILED) error_callback (data, "mmap", errno); else {
Re: libbacktrace patch committed: Graceful fallback if out of memory
> From: Ian Lance Taylor> Date: Tue, 8 Sep 2015 18:46:21 +0200 > PR other/67457 > * backtrace.c: #include "internal.h". > (struct backtrace_data): Add can_alloc field. > (unwind): If can_alloc is false, don't try to get file/line > information. > (backtrace_full): Set can_alloc field in bdata. > * alloc.c (backtrace_alloc): Don't call error_callback if it is > NULL. > * mmap.c (backtrace_alloc): Likewise. > * internal.h: Update comments for backtrace_alloc and > backtrace_free. > Index: backtrace.c > === > --- backtrace.c (revision 227528) > +++ backtrace.c (working copy) > @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. */ > > #include "unwind.h" > #include "backtrace.h" > +#include "internal.h" > > /* The main backtrace_full routine. */ > I don't know about your environment, but for me (cross from x86_64-linux to cris-elf) that causes a: /bin/sh ./libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I/tmp/hpautotest-gcc0/gcc/libbacktrace -I /tmp/hpautotest-gcc0/gcc/libbacktrace/../include -I /tmp/hpautotest-gcc0/gcc/libbacktrace/../libgcc -I ../libgcc -funwind-tables -frandom-seed=backtrace.lo -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wmissing-format-attribute -Wcast-qual -g -O2 -c -o backtrace.lo /tmp/hpautotest-gcc0/gcc/libbacktrace/backtrace.c libtool: compile: gcc -DHAVE_CONFIG_H -I. -I/tmp/hpautotest-gcc0/gcc/libbacktrace -I /tmp/hpautotest-gcc0/gcc/libbacktrace/../include -I /tmp/hpautotest-gcc0/gcc/libbacktrace/../libgcc -I ../libgcc -funwind-tables -frandom-seed=backtrace.lo -W -Wall -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wmissing-format-attribute -Wcast-qual -g -O2 -c /tmp/hpautotest-gcc0/gcc/libbacktrace/backtrace.c -fPIC -DPIC -o .libs/backtrace.o In file included from /tmp/hpautotest-gcc0/gcc/libbacktrace/backtrace.c:37: /tmp/hpautotest-gcc0/gcc/libbacktrace/internal.h:182: error: expected declaration specifiers or '...' before 'off_t' make[3]: *** [backtrace.lo] Error 1 make[3]: Leaving directory `/tmp/hpautotest-gcc0/cris-elf/gccobj/libbacktrace' make[2]: *** [all] Error 2 make[2]: Leaving directory `/tmp/hpautotest-gcc0/cris-elf/gccobj/libbacktrace' make[1]: *** [all-libbacktrace] Error 2 make[1]: Leaving directory `/tmp/hpautotest-gcc0/cris-elf/gccobj' make: *** [all] Error 2 I've committed the following as obvious, following the pattern of the other files including internal.h, after observing all-libbacktrace (i.e. built for the host) complete. libbacktrace: * backtrace.c: #include . Index: backtrace.c === --- backtrace.c (revision 227567) +++ backtrace.c (working copy) @@ -32,6 +32,8 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" +#include + #include "unwind.h" #include "backtrace.h" #include "internal.h" brgds, H-P
Re: libbacktrace patch committed: Graceful fallback if out of memory
On Tue, Sep 8, 2015 at 5:00 PM, Hans-Peter Nilssonwrote: > > I've committed the following as obvious, following the pattern > of the other files including internal.h, after observing > all-libbacktrace (i.e. built for the host) complete. > > libbacktrace: > * backtrace.c: #include . Thanks. Ian
libbacktrace patch committed: Graceful fallback if out of memory
I've committed this libbacktrace patch to mainline to do a graceful fallback if no memory can be allocated. In that case we print out the PC addresses without trying to resolve file/line information. This is imperfect but better than the earlier behaviour of producing a series of error messages. Tested with libbacktrace and Go testsuites. Committed to mainline. Ian 2015-09-08 Ian Lance TaylorPR other/67457 * backtrace.c: #include "internal.h". (struct backtrace_data): Add can_alloc field. (unwind): If can_alloc is false, don't try to get file/line information. (backtrace_full): Set can_alloc field in bdata. * alloc.c (backtrace_alloc): Don't call error_callback if it is NULL. * mmap.c (backtrace_alloc): Likewise. * internal.h: Update comments for backtrace_alloc and backtrace_free. Index: alloc.c === --- alloc.c (revision 227528) +++ alloc.c (working copy) @@ -44,7 +44,8 @@ POSSIBILITY OF SUCH DAMAGE. */ backtrace functions may not be safely invoked from a signal handler. */ -/* Allocate memory like malloc. */ +/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't + report an error. */ void * backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED, @@ -55,7 +56,10 @@ backtrace_alloc (struct backtrace_state ret = malloc (size); if (ret == NULL) -error_callback (data, "malloc", errno); +{ + if (error_callback) + error_callback (data, "malloc", errno); +} return ret; } Index: backtrace.c === --- backtrace.c (revision 227528) +++ backtrace.c (working copy) @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "unwind.h" #include "backtrace.h" +#include "internal.h" /* The main backtrace_full routine. */ @@ -53,6 +54,8 @@ struct backtrace_data void *data; /* Value to return from backtrace_full. */ int ret; + /* Whether there is any memory available. */ + int can_alloc; }; /* Unwind library callback routine. This is passed to @@ -80,8 +83,11 @@ unwind (struct _Unwind_Context *context, if (!ip_before_insn) --pc; - bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, -bdata->error_callback, bdata->data); + if (!bdata->can_alloc) +bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL); + else +bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, + bdata->error_callback, bdata->data); if (bdata->ret != 0) return _URC_END_OF_STACK; @@ -96,6 +102,7 @@ backtrace_full (struct backtrace_state * backtrace_error_callback error_callback, void *data) { struct backtrace_data bdata; + void *p; bdata.skip = skip + 1; bdata.state = state; @@ -103,6 +110,18 @@ backtrace_full (struct backtrace_state * bdata.error_callback = error_callback; bdata.data = data; bdata.ret = 0; + + /* If we can't allocate any memory at all, don't try to produce + file/line information. */ + p = backtrace_alloc (state, 4096, NULL, NULL); + if (p == NULL) +bdata.can_alloc = 0; + else +{ + backtrace_free (state, p, 4096, NULL, NULL); + bdata.can_alloc = 1; +} + _Unwind_Backtrace (unwind, ); return bdata.ret; } Index: internal.h === --- internal.h (revision 227528) +++ internal.h (working copy) @@ -201,13 +201,15 @@ extern int backtrace_close (int descript extern void backtrace_qsort (void *base, size_t count, size_t size, int (*compar) (const void *, const void *)); -/* Allocate memory. This is like malloc. */ +/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL, + this does not report an error, it just returns NULL. */ extern void *backtrace_alloc (struct backtrace_state *state, size_t size, backtrace_error_callback error_callback, void *data) ATTRIBUTE_MALLOC; -/* Free memory allocated by backtrace_alloc. */ +/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is + NULL, this does not report an error. */ extern void backtrace_free (struct backtrace_state *state, void *mem, size_t size, Index: mmap.c === --- mmap.c (revision 227529) +++ mmap.c (working copy) @@ -77,7 +77,8 @@ backtrace_free_locked (struct backtrace_ } } -/* Allocate memory like malloc. */ +/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't + report an error. */ void * backtrace_alloc (struct backtrace_state *state, @@ -140,7 +141,10 @@ backtrace_alloc (struct backtrace_state page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
libbacktrace patch committed: Fix load_pointer if no atomic or sync functions
This patch to libbacktrace fixes the type returned by the backup definition of backtrace_atomic_load_pointer for the case where libbacktrace is compiled with neither the atomic nor the sync functions available. This case does not arise in general but could arise from other uses of the library, or when building stage 1 with a very old host compiler. Bootstrapped and ran libbacktrace tests on x86_64-unknown-linux-gnu, which proves nothing, really. Ian 2014-10-23 Ian Lance Taylor i...@google.com * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: Fix to return void *. Index: internal.h === --- internal.h (revision 216522) +++ internal.h (working copy) @@ -99,7 +99,7 @@ extern void backtrace_atomic_store_int ( /* We have neither the sync nor the atomic functions. These will never be called. */ -#define backtrace_atomic_load_pointer(p) (abort(), 0) +#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) #define backtrace_atomic_load_int(p) (abort(), 0) #define backtrace_atomic_store_pointer(p, v) abort() #define backtrace_atomic_store_size_t(p, v) abort()
libbacktrace patch committed: Fixes for large binaries
While testing on a large Google binary, I noticed that libbacktrace is allocating an inordinate amount of memory. The binary winds up with 377,944 entries in the unit_addrs vector. Each entry is 24 bytes, so this is 9,070,656 bytes, which is not too terrible. Unfortunately, for some reason I thought that when a libbacktrace vector is larger than a page the code should only allocate one additional page at a time. This vector requires 2215 4096-byte pages. Growing the vector one page at a time allocates a total of something like (2215 * 2214) / 2 pages, which turns out to be nearly 1.5G. Allocating 1.5G to represent a vector of size 9M is not desirable. It's true that when the vector grows, the old memory can be reused. But there is nothing in libbacktrace that is going to reuse that much memory. And even worse, there was a bug in the vector_grow routine that caused it to fail to correctly report the size of the old vector, so the memory had no chance of being reused anyhow. This patch fixes vector growth to double the number of pages requested each time. It fixes vector growth to record the correct size of the old vector being freed. The patch also adds some code to simply munmap large blocks of allocated memory. It's unlikely in practice that libbacktrace will ever be able to reuse a large block, so it's probably better to hand the memory back rather than hold onto it for no purpose. Bootstrapped and tested on x86_64-unknown-linux-gnu. Committed to 4.9 branch and mainline. Ian 2014-05-08 Ian Lance Taylor i...@google.com * mmap.c (backtrace_free): If freeing a large aligned block of memory, call munmap rather than holding onto it. (backtrace_vector_grow): When growing a vector, double the number of pages requested. When releasing the old version of a grown vector, pass the correct size to backtrace_free. Index: ChangeLog === --- ChangeLog (revision 210248) +++ ChangeLog (working copy) @@ -1,3 +1,11 @@ +2014-05-08 Ian Lance Taylor i...@google.com + + * mmap.c (backtrace_free): If freeing a large aligned block of + memory, call munmap rather than holding onto it. + (backtrace_vector_grow): When growing a vector, double the number + of pages requested. When releasing the old version of a grown + vector, pass the correct size to backtrace_free. + 2014-03-07 Ian Lance Taylor i...@google.com * sort.c (backtrace_qsort): Use middle element as pivot. Index: mmap.c === --- mmap.c (revision 210248) +++ mmap.c (working copy) @@ -164,6 +164,26 @@ backtrace_free (struct backtrace_state * { int locked; + /* If we are freeing a large aligned block, just release it back to + the system. This case arises when growing a vector for a large + binary with lots of debug info. Calling munmap here may cause us + to call mmap again if there is also a large shared library; we + just live with that. */ + if (size = 16 * 4096) +{ + size_t pagesize; + + pagesize = getpagesize (); + if (((uintptr_t) addr (pagesize - 1)) == 0 + (size (pagesize - 1)) == 0) + { + /* If munmap fails for some reason, just add the block to + the freelist. */ + if (munmap (addr, size) == 0) + return; + } +} + /* If we can acquire the lock, add the new space to the free list. If we can't acquire the lock, just leak the memory. __sync_lock_test_and_set returns the old state of the lock, so we @@ -209,14 +229,18 @@ backtrace_vector_grow (struct backtrace_ alc = pagesize; } else - alc = (alc + pagesize - 1) ~ (pagesize - 1); + { + alc *= 2; + alc = (alc + pagesize - 1) ~ (pagesize - 1); + } base = backtrace_alloc (state, alc, error_callback, data); if (base == NULL) return NULL; if (vec-base != NULL) { memcpy (base, vec-base, vec-size); - backtrace_free (state, vec-base, vec-alc, error_callback, data); + backtrace_free (state, vec-base, vec-size + vec-alc, + error_callback, data); } vec-base = base; vec-alc = alc - vec-size;
libbacktrace patch committed: Speed up sort
The new libbacktrace sort routine has, no doubt, many flaws, but one is quite significant. The backtrace data tends to be roughly sorted in practice (though unfortunately not perfectly sorted). By pivoting on the first element in the array, the sort routine was tending to maximize the number of recursive steps. This patch uses the middle element array as the pivot. This reduced the backtrace time on a large executable by two orders of magnitude. Bootstrapped and ran Go and sanitizer testsuites on x86_64-unknown-linux-gnu. Committed to mainline. Ian 2014-03-07 Ian Lance Taylor i...@google.com * sort.c (backtrace_qsort): Use middle element as pivot. Index: sort.c === --- sort.c (revision 208402) +++ sort.c (working copy) @@ -69,6 +69,12 @@ backtrace_qsort (void *basearg, size_t c if (count 2) return; + /* The symbol table and DWARF tables, which is all we use this + routine for, tend to be roughly sorted. Pick the middle element + in the array as our pivot point, so that we are more likely to + cut the array in half for each recursion step. */ + swap (base, base + (count / 2) * size, size); + mid = 0; for (i = 1; i count; i++) {
Re: libbacktrace patch committed (Was: Re: [jit] Update TODO.rst)
On Thu, 2013-10-17 at 21:28 -0700, Ian Lance Taylor wrote: On Thu, Oct 17, 2013 at 8:54 PM, David Malcolm dmalc...@redhat.com wrote: +* segfault seen in libbacktrace, when an ICE occurs That reminded me to commit this libbacktrace patch I worked up a couple of weeks ago. Previously if some debug section was missing, the code could compute the wrong min_offset. The missing section would have a zero offset, so min_offset would be set to zero, and would then be set to the offset of the next section, even though that one might not be the minimum. That could lead to a segfault in some cases, though I don't know if that is the issue that David is seeing. Thanks - your patch has fixed the issue I was seeing, and I now reliably get backtraces when an ICE happens within libgccjit.so. Now to try to fix things so that ICEs can't happen... Dave