libbacktrace: Add support for MiniDebugInfo
This patch to libbacktrace adds support for MiniDebugInfo, as requested in PR 93608. MiniDebugInfo stores compressed symbol tables for an executable, where the executable is otherwise stripped. It is documented at https://fedoraproject.org/wiki/Features/MiniDebugInfo and https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html. Unfortunately, although debug info processors are already required to handle data compressed using zlib aka gzip in order to handle zdebug and SHT_COMPRESSED, the MiniDebugInfo implementation choose to instead compress the debug information with xz which uses LZMA2. This in effect forces all debug info processors to add a second decompression algorithm. Note to future developers: do not do this. This libbacktrace implementation includes a new small LZMA decompressor that just decompresses from one buffer to another. It is not heavily optimized, and on my laptop runs at about 78% of the speed of using liblzma directly. I think this is a decent tradeoff for keeping the code reasonably small. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian PR libbacktrace/93608 Add support for MiniDebugInfo. * elf.c (struct elf_view): Define. Replace most uses of backtrace_view with elf_view. (elf_get_view): New static functions. Replace most calls of backtrace_get_view with elf_get_view. (elf_release_view): New static functions. Replace most calls of backtrace_release_view with elf_release_view. (elf_uncompress_failed): Rename from elf_zlib_failed. Change all callers. (LZMA_STATES, LZMA_POS_STATES, LZMA_DIST_STATES): Define. (LZMA_DIST_SLOTS, LZMA_DIST_MODEL_START): Define. (LZMA_DIST_MODEL_END, LZMA_FULL_DISTANCES): Define. (LZMA_ALIGN_SIZE, LZMA_LEN_LOW_SYMBOLS): Define. (LZMA_LEN_MID_SYMBOLS, LZMA_LEN_HIGH_SYMBOLS): Define. (LZMA_LITERAL_CODERS_MAX, LZMA_LITERAL_CODER_SIZE): Define. (LZMA_PROB_IS_MATCH_LEN, LZMA_PROB_IS_REP_LEN): Define. (LZMA_PROB_IS_REP0_LEN, LZMA_PROB_IS_REP1_LEN): Define. (LZMA_PROB_IS_REP2_LEN, LZMA_PROB_IS_REP0_LONG_LEN): Define. (LZMA_PROB_DIST_SLOT_LEN, LZMA_PROB_DIST_SPECIAL_LEN): Define. (LZMA_PROB_DIST_ALIGN_LEN): Define. (LZMA_PROB_MATCH_LEN_CHOICE_LEN): Define. (LZMA_PROB_MATCH_LEN_CHOICE2_LEN): Define. (LZMA_PROB_MATCH_LEN_LOW_LEN): Define. (LZMA_PROB_MATCH_LEN_MID_LEN): Define. (LZMA_PROB_MATCH_LEN_HIGH_LEN): Define. (LZMA_PROB_REP_LEN_CHOICE_LEN): Define. (LZMA_PROB_REP_LEN_CHOICE2_LEN): Define. (LZMA_PROB_REP_LEN_LOW_LEN): Define. (LZMA_PROB_REP_LEN_MID_LEN): Define. (LZMA_PROB_REP_LEN_HIGH_LEN): Define. (LZMA_PROB_LITERAL_LEN): Define. (LZMA_PROB_IS_MATCH_OFFSET, LZMA_PROB_IS_REP_OFFSET): Define. (LZMA_PROB_IS_REP0_OFFSET, LZMA_PROB_IS_REP1_OFFSET): Define. (LZMA_PROB_IS_REP2_OFFSET): Define. (LZMA_PROB_IS_REP0_LONG_OFFSET): Define. (LZMA_PROB_DIST_SLOT_OFFSET): Define. (LZMA_PROB_DIST_SPECIAL_OFFSET): Define. (LZMA_PROB_DIST_ALIGN_OFFSET): Define. (LZMA_PROB_MATCH_LEN_CHOICE_OFFSET): Define. (LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET): Define. (LZMA_PROB_MATCH_LEN_LOW_OFFSET): Define. (LZMA_PROB_MATCH_LEN_MID_OFFSET): Define. (LZMA_PROB_MATCH_LEN_HIGH_OFFSET): Define. (LZMA_PROB_REP_LEN_CHOICE_OFFSET): Define. (LZMA_PROB_REP_LEN_CHOICE2_OFFSET): Define. (LZMA_PROB_REP_LEN_LOW_OFFSET): Define. (LZMA_PROB_REP_LEN_MID_OFFSET): Define. (LZMA_PROB_REP_LEN_HIGH_OFFSET): Define. (LZMA_PROB_LITERAL_OFFSET): Define. (LZMA_PROB_TOTAL_COUNT): Define. (LZMA_IS_MATCH, LZMA_IS_REP, LZMA_IS_REP0): Define. (LZMA_IS_REP1, LZMA_IS_REP2, LZMA_IS_REP0_LONG): Define. (LZMA_DIST_SLOT, LZMA_DIST_SPECIAL, LZMA_DIST_ALIGN): Define. (LZMA_MATCH_LEN_CHOICE, LZMA_MATCH_LEN_CHOICE2): Define. (LZMA_MATCH_LEN_LOW, LZMA_MATCH_LEN_MID): Define. (LZMA_MATCH_LEN_HIGH, LZMA_REP_LEN_CHOICE): Define. (LZMA_REP_LEN_CHOICE2, LZMA_REP_LEN_LOW): Define. (LZMA_REP_LEN_MID, LZMA_REP_LEN_HIGH, LZMA_LITERAL): Define. (elf_lzma_varint): New static function. (elf_lzma_range_normalize): New static function. (elf_lzma_bit, elf_lzma_integer): New static functions. (elf_lzma_reverse_integer): New static function. (elf_lzma_len, elf_uncompress_lzma_block): New static functions. (elf_uncompress_lzma): New static function. (backtrace_uncompress_lzma): New function. (elf_add): Add memory and memory_size parameters. Change all callers. Look for .gnu_debugdata section, and, if found, decompress it and use it for symbols and debug info. Permit the descriptor parameter to be -1. * internal.h (backtrace_uncompress_lzma): Declare. * mtest.c: New file. * xztest.c: New file. * configure.ac: Check for nm, xz, and comm programs. Check for liblzma library. (HAVE_MINIDEBUG): Define. * Makefile.am (mtest_SOURCES): Define. (mtest_CFLAGS, mtest_LDADD): Define. (TESTS): Add mtest_minidebug if HAVE_MINIDEBUG. (%_minidebug): New pattern rule, if HAVE_MINIDEBUG. (xztest_SOURCES, xztest_CFLAGS, xztest_LDADD): Define. (xztest_alloc_SOURCES, xztest_alloc_CFLAGS): Define (xztest_alloc_LDADD): Define. (BUILDTESTS): Add mtest, xztest, xztest_alloc. (CLEANFILES): Add files created b
Re: libbacktrace: Add support for MiniDebugInfo
Hi Ian, On 14/09/2020 14:12, Ian Lance Taylor via Gcc-patches wrote: > This patch to libbacktrace adds support for MiniDebugInfo, as > requested in PR 93608. This appears to introduce a failure in the libbacktrace testsuite (observed on both x86 and aarch64): ../gcc/libbacktrace/../test-driver: line 107: 7905 Segmentation fault (core dumped) "$@" > $log_file 2>&1 FAIL: mtest_minidebug > > MiniDebugInfo stores compressed symbol tables for an executable, where > the executable is otherwise stripped. It is documented at > https://fedoraproject.org/wiki/Features/MiniDebugInfo and > https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html. > > Unfortunately, although debug info processors are already required to > handle data compressed using zlib aka gzip in order to handle zdebug > and SHT_COMPRESSED, the MiniDebugInfo implementation choose to instead > compress the debug information with xz which uses LZMA2. This in > effect forces all debug info processors to add a second decompression > algorithm. Note to future developers: do not do this. > > This libbacktrace implementation includes a new small LZMA > decompressor that just decompresses from one buffer to another. It is > not heavily optimized, and on my laptop runs at about 78% of the speed > of using liblzma directly. I think this is a decent tradeoff for > keeping the code reasonably small. > > Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed > to mainline. > > Ian Thanks, Alex
Re: libbacktrace: Add support for MiniDebugInfo
On Wed, Sep 16, 2020, 4:03 AM Alex Coplan wrote: > Hi Ian, > > On 14/09/2020 14:12, Ian Lance Taylor via Gcc-patches wrote: > > This patch to libbacktrace adds support for MiniDebugInfo, as > > requested in PR 93608. > > This appears to introduce a failure in the libbacktrace testsuite > (observed on both x86 and aarch64): > > ../gcc/libbacktrace/../test-driver: line 107: 7905 Segmentation fault > (core dumped) "$@" > $log_file 2>&1 > FAIL: mtest_minidebug I tested on x86 without seeing anything like this. Can you give me any more details? Thanks. Ian > > MiniDebugInfo stores compressed symbol tables for an executable, where > > the executable is otherwise stripped. It is documented at > > https://fedoraproject.org/wiki/Features/MiniDebugInfo and > > https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html. > > > > Unfortunately, although debug info processors are already required to > > handle data compressed using zlib aka gzip in order to handle zdebug > > and SHT_COMPRESSED, the MiniDebugInfo implementation choose to instead > > compress the debug information with xz which uses LZMA2. This in > > effect forces all debug info processors to add a second decompression > > algorithm. Note to future developers: do not do this. > > > > This libbacktrace implementation includes a new small LZMA > > decompressor that just decompresses from one buffer to another. It is > > not heavily optimized, and on my laptop runs at about 78% of the speed > > of using liblzma directly. I think this is a decent tradeoff for > > keeping the code reasonably small. > > > > Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed > > to mainline. > > > > Ian > > Thanks, > Alex >
Re: libbacktrace: Add support for MiniDebugInfo
On 16/09/2020 07:26, Ian Lance Taylor wrote: > On Wed, Sep 16, 2020, 4:03 AM Alex Coplan wrote: > > > Hi Ian, > > > > On 14/09/2020 14:12, Ian Lance Taylor via Gcc-patches wrote: > > > This patch to libbacktrace adds support for MiniDebugInfo, as > > > requested in PR 93608. > > > > This appears to introduce a failure in the libbacktrace testsuite > > (observed on both x86 and aarch64): > > > > ../gcc/libbacktrace/../test-driver: line 107: 7905 Segmentation fault > > (core dumped) "$@" > $log_file 2>&1 > > FAIL: mtest_minidebug > > > > I tested on x86 without seeing anything like this. Can you give me any > more details? Thanks. Sure. On an Ubuntu 18.04 / x86-64 system with current trunk, configuring with: ~/toolchain/src/gcc/configure \ --prefix=`pwd` \ --enable-languages=c,c++ \ --disable-multilib \ --disable-bootstrap running `make && make check-libbacktrace` gives the failure described above. Here is the contents of libbacktrace/test-suite.log: = package-unused version-unused: ./test-suite.log = # TOTAL: 33 # PASS: 32 # SKIP: 0 # XFAIL: 0 # FAIL: 1 # XPASS: 0 # ERROR: 0 .. contents:: :depth: 2 FAIL: mtest_minidebug = no debug info in ELF executable no debug info in ELF executable no debug info in ELF executable no debug info in ELF executable no debug info in ELF executable no debug info in ELF executable no debug info in ELF executable test1: not enough frames; got 0, expected at least 3 test1: [0]: got expected f3 test1: [1]: got expected f2 FAIL mtest_minidebug (exit status: 139) --- Let me know if you need any more info. Thanks, Alex
Re: libbacktrace: Add support for MiniDebugInfo
On Wed, Sep 16, 2020 at 8:54 AM Alex Coplan wrote: > > On 16/09/2020 07:26, Ian Lance Taylor wrote: > > On Wed, Sep 16, 2020, 4:03 AM Alex Coplan wrote: > > > > > Hi Ian, > > > > > > On 14/09/2020 14:12, Ian Lance Taylor via Gcc-patches wrote: > > > > This patch to libbacktrace adds support for MiniDebugInfo, as > > > > requested in PR 93608. > > > > > > This appears to introduce a failure in the libbacktrace testsuite > > > (observed on both x86 and aarch64): > > > > > > ../gcc/libbacktrace/../test-driver: line 107: 7905 Segmentation fault > > > (core dumped) "$@" > $log_file 2>&1 > > > FAIL: mtest_minidebug > > > > > > > > I tested on x86 without seeing anything like this. Can you give me any > > more details? Thanks. > > Sure. On an Ubuntu 18.04 / x86-64 system with current trunk, configuring > with: > > ~/toolchain/src/gcc/configure \ > --prefix=`pwd` \ > --enable-languages=c,c++ \ > --disable-multilib \ > --disable-bootstrap > > running `make && make check-libbacktrace` gives the failure described > above. Here is the contents of libbacktrace/test-suite.log: > > = > package-unused version-unused: ./test-suite.log > = > > # TOTAL: 33 > # PASS: 32 > # SKIP: 0 > # XFAIL: 0 > # FAIL: 1 > # XPASS: 0 > # ERROR: 0 > > .. contents:: :depth: 2 > > FAIL: mtest_minidebug > = > > no debug info in ELF executable > no debug info in ELF executable > no debug info in ELF executable > no debug info in ELF executable > no debug info in ELF executable > no debug info in ELF executable > no debug info in ELF executable > test1: not enough frames; got 0, expected at least 3 > test1: [0]: got expected f3 > test1: [1]: got expected f2 > FAIL mtest_minidebug (exit status: 139) > > --- > > Let me know if you need any more info. Thanks. I think the problem arises when libbacktrace is unable to find debug info for any shared library involved in the link. This patch should fix it. Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu and aarch64-linux-gnu. Committed to mainline. Ian PR libbacktrace/97080 * fileline.c (backtrace_syminfo_to_full_callback): New function. (backtrace_syminfo_to_full_error_callback): New function. * elf.c (elf_nodebug): Call syminfo_fn if possible. * internal.h (struct backtrace_call_full): Define. (backtrace_syminfo_to_full_callback): Declare. (backtrace_syminfo_to_full_error_callback): Declare. * mtest.c (f3): Only check all[i] if data.index permits. diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index dd004708246..941f820d944 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -547,18 +547,6 @@ elf_crc32_file (struct backtrace_state *state, int descriptor, return ret; } -/* A dummy callback function used when we can't find any debug info. */ - -static int -elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, -uintptr_t pc ATTRIBUTE_UNUSED, -backtrace_full_callback callback ATTRIBUTE_UNUSED, -backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no debug info in ELF executable", -1); - return 0; -} - /* A dummy callback function used when we can't find a symbol table. */ @@ -571,6 +559,33 @@ elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, error_callback (data, "no symbol table in ELF executable", -1); } +/* A callback function used when we can't find any debug info. */ + +static int +elf_nodebug (struct backtrace_state *state, uintptr_t pc, +backtrace_full_callback callback, +backtrace_error_callback error_callback, void *data) +{ + if (state->syminfo_fn != NULL && state->syminfo_fn != elf_nosyms) +{ + struct backtrace_call_full bdata; + + /* Fetch symbol information so that we can least get the +function name. */ + + bdata.full_callback = callback; + bdata.full_error_callback = error_callback; + bdata.full_data = data; + bdata.ret = 0; + state->syminfo_fn (state, pc, backtrace_syminfo_to_full_callback, +backtrace_syminfo_to_full_error_callback, &bdata); + return bdata.ret; +} + + error_callback (data, "no debug info in ELF executable", -1); + return 0; +} + /* Compare struct elf_symbol for qsort. */ static int diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c index be62b9899c5..cd1e10dd58c 100644 --- a/libbacktrace/fileline.c +++ b/libbacktrace/fileline.c @@ -317,3 +317,30 @@ backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, state->syminfo_fn (state, pc, callback, error_callback, data); return 1; } + +/* A backtrace_syminfo_callback that can call into a + backtrace_full_callback, used when we have a symbol table but no + debug info. */ + +void +backtrace_syminfo_to_full_callback (void *data, uintptr_t pc, + const char *symname, +