libbacktrace: support MiniDebugInfo
authorIan Lance Taylor <iant@golang.org>
Mon, 14 Sep 2020 21:01:56 +0000 (14:01 -0700)
committerIan Lance Taylor <iant@golang.org>
Mon, 14 Sep 2020 21:11:17 +0000 (14:11 -0700)
libbacktrace/ChangeLog:
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 by minidebug pattern.
(btest.lo): Correct INCDIR reference.
(mtest.lo, xztest.lo, ztest.lo): New targets.
* configure: Regenerate.
* config.h.in: Regenerate.
* Makefile.in: Regenerate.

libbacktrace/Makefile.am
libbacktrace/Makefile.in
libbacktrace/config.h.in
libbacktrace/configure
libbacktrace/configure.ac
libbacktrace/elf.c
libbacktrace/internal.h
libbacktrace/mtest.c [new file with mode: 0644]
libbacktrace/xztest.c [new file with mode: 0644]

index 6fc0749878761beea8521ccd637c522d21867541..4d349386c9b9452a21accbda134a43096239f9d3 100644 (file)
@@ -478,13 +478,61 @@ endif HAVE_DSYMUTIL
 
 endif
 
+mtest_SOURCES = mtest.c testlib.c
+mtest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O
+mtest_LDADD = libbacktrace.la
+
+BUILDTESTS += mtest
+
+if HAVE_MINIDEBUG
+
+TESTS += mtest_minidebug
+
+%_minidebug: %
+       $(NM) -D $< -P --defined-only | $(AWK) '{ print $$1 }' | sort > $<.dsyms
+       $(NM) $< -P --defined-only | $(AWK) '{ if ($$2 == "T" || $$2 == "t" || $$2 == "D") print $$1 }' | sort > $<.fsyms
+       $(COMM) -13 $<.dsyms $<.fsyms > $<.keepsyms
+       $(OBJCOPY) --only-keep-debug $< $<.dbg
+       $(OBJCOPY) -S --remove-section .gdb_index --remove-section .comment --keep-symbols=$<.keepsyms $<.dbg $<.mdbg
+       $(OBJCOPY) --strip-all --remove-section ..comment $< $<.strip
+       rm -f $<.mdbg.xz
+       $(XZ) $<.mdbg
+       $(OBJCOPY) --add-section .gnu_debugdata=$<.mdbg.xz $<.strip
+       mv $<.strip $@
+
+endif HAVE_MINIDEBUG
+
 endif NATIVE
 
+if HAVE_ELF
+
+xztest_SOURCES = xztest.c testlib.c
+xztest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+xztest_LDADD = libbacktrace.la
+
+xztest_alloc_SOURCES = $(xztest_SOURCES)
+xztest_alloc_CFLAGS = $(xztest_CFLAGS)
+xztest_alloc_LDADD = libbacktrace_alloc.la
+
+if HAVE_LIBLZMA
+xztest_LDADD += -llzma
+xztest_alloc_LDADD += -llzma
+endif
+
+xztest_LDADD += $(CLOCK_GETTIME_LINK)
+xztest_alloc_LDADD += $(CLOCK_GETTIME_LINK)
+
+BUILDTESTS += xztest xztest_alloc
+
+endif HAVE_ELF
+
 check_PROGRAMS += $(BUILDTESTS)
 
 TESTS += $(BUILDTESTS)
 
-CLEANFILES = $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build
+CLEANFILES = \
+       $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build \
+       *.dsyms *.fsyms *.keepsyms *.dbg *.mdbg *.mdbg.xz *.strip
 
 clean-local:
        -rm -rf usr
@@ -504,7 +552,7 @@ clean-local:
 INCDIR = $(top_srcdir)/../include
 alloc.lo: config.h backtrace.h internal.h
 backtrace.lo: config.h backtrace.h internal.h
-btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.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
 elf.lo: config.h backtrace.h internal.h
@@ -512,6 +560,7 @@ fileline.lo: config.h backtrace.h internal.h
 macho.lo: config.h backtrace.h internal.h
 mmap.lo: config.h backtrace.h internal.h
 mmapio.lo: config.h backtrace.h internal.h
+mtest.lo: backtrace.h backtrace-supported.h
 nounwind.lo: config.h internal.h
 pecoff.lo: config.h backtrace.h internal.h
 posix.lo: config.h backtrace.h internal.h
@@ -523,5 +572,7 @@ 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
 xcoff.lo: config.h backtrace.h internal.h
+xztest.lo: config.h backtrace.h backtrace-supported.h internal.h testlib.h
+ztest.lo: config.h backtrace.h backtrace-supported.h internal.h testlib.h
 
 include $(top_srcdir)/../multilib.am
index b244ca10a4a359632c79c9f3951568027587b640..201cee36d349369516dfbdf773797d9149f75a14 100644 (file)
@@ -121,10 +121,10 @@ build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
 check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
-       $(am__EXEEXT_12)
+       $(am__EXEEXT_14)
 TESTS = $(am__append_4) $(am__append_7) $(am__append_9) \
        $(am__append_12) $(am__append_13) $(am__append_20) \
-       $(am__EXEEXT_12)
+       $(am__append_25) $(am__EXEEXT_14)
 @HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_1 = libbacktrace_elf_for_test.la
 @NATIVE_TRUE@am__append_2 = test_elf_32 test_elf_64 test_macho \
 @NATIVE_TRUE@  test_xcoff_32 test_xcoff_64 test_pecoff \
@@ -157,6 +157,11 @@ TESTS = $(am__append_4) $(am__append_7) $(am__append_9) \
 @HAVE_DWARF5_TRUE@@NATIVE_TRUE@am__append_22 = dwarf5 dwarf5_alloc
 @HAVE_DSYMUTIL_TRUE@@HAVE_DWARF5_TRUE@@NATIVE_TRUE@am__append_23 = dwarf5.dSYM \
 @HAVE_DSYMUTIL_TRUE@@HAVE_DWARF5_TRUE@@NATIVE_TRUE@    dwarf5_alloc.dSYM
+@NATIVE_TRUE@am__append_24 = mtest
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@am__append_25 = mtest_minidebug
+@HAVE_ELF_TRUE@@HAVE_LIBLZMA_TRUE@am__append_26 = -llzma
+@HAVE_ELF_TRUE@@HAVE_LIBLZMA_TRUE@am__append_27 = -llzma
+@HAVE_ELF_TRUE@am__append_28 = xztest xztest_alloc
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../config/cet.m4 \
@@ -235,9 +240,12 @@ libbacktrace_noformat_la_OBJECTS =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@      ctesta_alloc$(EXEEXT)
 @HAVE_DWARF5_TRUE@@NATIVE_TRUE@am__EXEEXT_11 = dwarf5$(EXEEXT) \
 @HAVE_DWARF5_TRUE@@NATIVE_TRUE@        dwarf5_alloc$(EXEEXT)
-am__EXEEXT_12 = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
+@NATIVE_TRUE@am__EXEEXT_12 = mtest$(EXEEXT)
+@HAVE_ELF_TRUE@am__EXEEXT_13 = xztest$(EXEEXT) xztest_alloc$(EXEEXT)
+am__EXEEXT_14 = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
        $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
-       $(am__EXEEXT_10) $(am__EXEEXT_11)
+       $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \
+       $(am__EXEEXT_13)
 @NATIVE_TRUE@am_allocfail_OBJECTS = allocfail-allocfail.$(OBJEXT) \
 @NATIVE_TRUE@  allocfail-testlib.$(OBJEXT)
 allocfail_OBJECTS = $(am_allocfail_OBJECTS)
@@ -355,6 +363,13 @@ edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
 edtest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(edtest_alloc_CFLAGS) \
        $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+@NATIVE_TRUE@am_mtest_OBJECTS = mtest-mtest.$(OBJEXT) \
+@NATIVE_TRUE@  mtest-testlib.$(OBJEXT)
+mtest_OBJECTS = $(am_mtest_OBJECTS)
+@NATIVE_TRUE@mtest_DEPENDENCIES = libbacktrace.la
+mtest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mtest_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
 @NATIVE_TRUE@am_stest_OBJECTS = stest-stest.$(OBJEXT)
 stest_OBJECTS = $(am_stest_OBJECTS)
 @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
@@ -465,6 +480,23 @@ unittest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
        $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
        $(unittest_alloc_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o \
        $@
+@HAVE_ELF_TRUE@am_xztest_OBJECTS = xztest-xztest.$(OBJEXT) \
+@HAVE_ELF_TRUE@        xztest-testlib.$(OBJEXT)
+xztest_OBJECTS = $(am_xztest_OBJECTS)
+@HAVE_ELF_TRUE@xztest_DEPENDENCIES = libbacktrace.la \
+@HAVE_ELF_TRUE@        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+xztest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(xztest_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_ELF_TRUE@am__objects_12 = xztest_alloc-xztest.$(OBJEXT) \
+@HAVE_ELF_TRUE@        xztest_alloc-testlib.$(OBJEXT)
+@HAVE_ELF_TRUE@am_xztest_alloc_OBJECTS = $(am__objects_12)
+xztest_alloc_OBJECTS = $(am_xztest_alloc_OBJECTS)
+@HAVE_ELF_TRUE@xztest_alloc_DEPENDENCIES = libbacktrace_alloc.la \
+@HAVE_ELF_TRUE@        $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+xztest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(xztest_alloc_CFLAGS) \
+       $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
 @HAVE_ELF_TRUE@@NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \
 @HAVE_ELF_TRUE@@NATIVE_TRUE@   ztest-testlib.$(OBJEXT)
 ztest_OBJECTS = $(am_ztest_OBJECTS)
@@ -474,11 +506,11 @@ ztest_OBJECTS = $(am_ztest_OBJECTS)
 ztest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) \
        $(AM_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_ELF_TRUE@@NATIVE_TRUE@am__objects_12 =  \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am__objects_13 =  \
 @HAVE_ELF_TRUE@@NATIVE_TRUE@   ztest_alloc-ztest.$(OBJEXT) \
 @HAVE_ELF_TRUE@@NATIVE_TRUE@   ztest_alloc-testlib.$(OBJEXT)
 @HAVE_ELF_TRUE@@NATIVE_TRUE@am_ztest_alloc_OBJECTS =  \
-@HAVE_ELF_TRUE@@NATIVE_TRUE@   $(am__objects_12)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@   $(am__objects_13)
 ztest_alloc_OBJECTS = $(am_ztest_alloc_OBJECTS)
 @HAVE_ELF_TRUE@@NATIVE_TRUE@ztest_alloc_DEPENDENCIES =  \
 @HAVE_ELF_TRUE@@NATIVE_TRUE@   libbacktrace_alloc.la \
@@ -530,13 +562,14 @@ SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
        $(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
        $(ctestg_alloc_SOURCES) $(dwarf5_SOURCES) \
        $(dwarf5_alloc_SOURCES) $(edtest_SOURCES) \
-       $(edtest_alloc_SOURCES) $(stest_SOURCES) \
+       $(edtest_alloc_SOURCES) $(mtest_SOURCES) $(stest_SOURCES) \
        $(stest_alloc_SOURCES) $(test_elf_32_SOURCES) \
        $(test_elf_64_SOURCES) $(test_macho_SOURCES) \
        $(test_pecoff_SOURCES) $(test_unknown_SOURCES) \
        $(test_xcoff_32_SOURCES) $(test_xcoff_64_SOURCES) \
        $(ttest_SOURCES) $(ttest_alloc_SOURCES) $(unittest_SOURCES) \
-       $(unittest_alloc_SOURCES) $(ztest_SOURCES) \
+       $(unittest_alloc_SOURCES) $(xztest_SOURCES) \
+       $(xztest_alloc_SOURCES) $(ztest_SOURCES) \
        $(ztest_alloc_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
@@ -786,6 +819,7 @@ CC = @CC@
 CET_HOST_FLAGS = @CET_HOST_FLAGS@
 CFLAGS = @CFLAGS@
 CLOCK_GETTIME_LINK = @CLOCK_GETTIME_LINK@
+COMM = @COMM@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CYGPATH_W = @CYGPATH_W@
@@ -844,6 +878,7 @@ STRIP = @STRIP@
 VERSION = @VERSION@
 VIEW_FILE = @VIEW_FILE@
 WARN_FLAGS = @WARN_FLAGS@
+XZ = @XZ@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -953,7 +988,8 @@ libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
 # Add a test to this variable if you want it to be built and run.
 BUILDTESTS = $(am__append_2) $(am__append_10) $(am__append_11) \
        $(am__append_16) $(am__append_17) $(am__append_18) \
-       $(am__append_21) $(am__append_22)
+       $(am__append_21) $(am__append_22) $(am__append_24) \
+       $(am__append_28)
 
 # Add a file to this variable if you want it to be built for testing.
 check_DATA = $(am__append_5) $(am__append_19) $(am__append_23)
@@ -1078,7 +1114,21 @@ libbacktrace_TEST_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) -g
 @HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_alloc_SOURCES = $(dwarf5_SOURCES)
 @HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_alloc_CFLAGS = $(dwarf5_CFLAGS)
 @HAVE_DWARF5_TRUE@@NATIVE_TRUE@dwarf5_alloc_LDADD = libbacktrace_alloc.la
-CLEANFILES = $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build
+@NATIVE_TRUE@mtest_SOURCES = mtest.c testlib.c
+@NATIVE_TRUE@mtest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -O
+@NATIVE_TRUE@mtest_LDADD = libbacktrace.la
+@HAVE_ELF_TRUE@xztest_SOURCES = xztest.c testlib.c
+@HAVE_ELF_TRUE@xztest_CFLAGS = $(libbacktrace_TEST_CFLAGS) -DSRCDIR=\"$(srcdir)\"
+@HAVE_ELF_TRUE@xztest_LDADD = libbacktrace.la $(am__append_26) \
+@HAVE_ELF_TRUE@        $(CLOCK_GETTIME_LINK)
+@HAVE_ELF_TRUE@xztest_alloc_SOURCES = $(xztest_SOURCES)
+@HAVE_ELF_TRUE@xztest_alloc_CFLAGS = $(xztest_CFLAGS)
+@HAVE_ELF_TRUE@xztest_alloc_LDADD = libbacktrace_alloc.la \
+@HAVE_ELF_TRUE@        $(am__append_27) $(CLOCK_GETTIME_LINK)
+CLEANFILES = \
+       $(TESTS) *.debug elf_for_test.c edtest2_build.c gen_edtest2_build \
+       *.dsyms *.fsyms *.keepsyms *.dbg *.mdbg *.mdbg.xz *.strip
+
 
 # We can't use automake's automatic dependency tracking, because it
 # breaks when using bootstrap-lean.  Automatic dependency tracking
@@ -1259,6 +1309,10 @@ edtest_alloc$(EXEEXT): $(edtest_alloc_OBJECTS) $(edtest_alloc_DEPENDENCIES) $(EX
        @rm -f edtest_alloc$(EXEEXT)
        $(AM_V_CCLD)$(edtest_alloc_LINK) $(edtest_alloc_OBJECTS) $(edtest_alloc_LDADD) $(LIBS)
 
+mtest$(EXEEXT): $(mtest_OBJECTS) $(mtest_DEPENDENCIES) $(EXTRA_mtest_DEPENDENCIES) 
+       @rm -f mtest$(EXEEXT)
+       $(AM_V_CCLD)$(mtest_LINK) $(mtest_OBJECTS) $(mtest_LDADD) $(LIBS)
+
 stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) 
        @rm -f stest$(EXEEXT)
        $(AM_V_CCLD)$(stest_LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
@@ -1311,6 +1365,14 @@ unittest_alloc$(EXEEXT): $(unittest_alloc_OBJECTS) $(unittest_alloc_DEPENDENCIES
        @rm -f unittest_alloc$(EXEEXT)
        $(AM_V_CCLD)$(unittest_alloc_LINK) $(unittest_alloc_OBJECTS) $(unittest_alloc_LDADD) $(LIBS)
 
+xztest$(EXEEXT): $(xztest_OBJECTS) $(xztest_DEPENDENCIES) $(EXTRA_xztest_DEPENDENCIES) 
+       @rm -f xztest$(EXEEXT)
+       $(AM_V_CCLD)$(xztest_LINK) $(xztest_OBJECTS) $(xztest_LDADD) $(LIBS)
+
+xztest_alloc$(EXEEXT): $(xztest_alloc_OBJECTS) $(xztest_alloc_DEPENDENCIES) $(EXTRA_xztest_alloc_DEPENDENCIES) 
+       @rm -f xztest_alloc$(EXEEXT)
+       $(AM_V_CCLD)$(xztest_alloc_LINK) $(xztest_alloc_OBJECTS) $(xztest_alloc_LDADD) $(LIBS)
+
 ztest$(EXEEXT): $(ztest_OBJECTS) $(ztest_DEPENDENCIES) $(EXTRA_ztest_DEPENDENCIES) 
        @rm -f ztest$(EXEEXT)
        $(AM_V_CCLD)$(ztest_LINK) $(ztest_OBJECTS) $(ztest_LDADD) $(LIBS)
@@ -1514,6 +1576,18 @@ edtest_alloc-testlib.o: testlib.c
 edtest_alloc-testlib.obj: testlib.c
        $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(edtest_alloc_CFLAGS) $(CFLAGS) -c -o edtest_alloc-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
 
+mtest-mtest.o: mtest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mtest_CFLAGS) $(CFLAGS) -c -o mtest-mtest.o `test -f 'mtest.c' || echo '$(srcdir)/'`mtest.c
+
+mtest-mtest.obj: mtest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mtest_CFLAGS) $(CFLAGS) -c -o mtest-mtest.obj `if test -f 'mtest.c'; then $(CYGPATH_W) 'mtest.c'; else $(CYGPATH_W) '$(srcdir)/mtest.c'; fi`
+
+mtest-testlib.o: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mtest_CFLAGS) $(CFLAGS) -c -o mtest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+mtest-testlib.obj: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mtest_CFLAGS) $(CFLAGS) -c -o mtest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 stest-stest.o: stest.c
        $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stest_CFLAGS) $(CFLAGS) -c -o stest-stest.o `test -f 'stest.c' || echo '$(srcdir)/'`stest.c
 
@@ -1658,6 +1732,30 @@ unittest_alloc-testlib.o: testlib.c
 unittest_alloc-testlib.obj: testlib.c
        $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unittest_alloc_CFLAGS) $(CFLAGS) -c -o unittest_alloc-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
 
+xztest-xztest.o: xztest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_CFLAGS) $(CFLAGS) -c -o xztest-xztest.o `test -f 'xztest.c' || echo '$(srcdir)/'`xztest.c
+
+xztest-xztest.obj: xztest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_CFLAGS) $(CFLAGS) -c -o xztest-xztest.obj `if test -f 'xztest.c'; then $(CYGPATH_W) 'xztest.c'; else $(CYGPATH_W) '$(srcdir)/xztest.c'; fi`
+
+xztest-testlib.o: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_CFLAGS) $(CFLAGS) -c -o xztest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+xztest-testlib.obj: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_CFLAGS) $(CFLAGS) -c -o xztest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
+xztest_alloc-xztest.o: xztest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_alloc_CFLAGS) $(CFLAGS) -c -o xztest_alloc-xztest.o `test -f 'xztest.c' || echo '$(srcdir)/'`xztest.c
+
+xztest_alloc-xztest.obj: xztest.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_alloc_CFLAGS) $(CFLAGS) -c -o xztest_alloc-xztest.obj `if test -f 'xztest.c'; then $(CYGPATH_W) 'xztest.c'; else $(CYGPATH_W) '$(srcdir)/xztest.c'; fi`
+
+xztest_alloc-testlib.o: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_alloc_CFLAGS) $(CFLAGS) -c -o xztest_alloc-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+xztest_alloc-testlib.obj: testlib.c
+       $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xztest_alloc_CFLAGS) $(CFLAGS) -c -o xztest_alloc-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 ztest-ztest.o: ztest.c
        $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-ztest.o `test -f 'ztest.c' || echo '$(srcdir)/'`ztest.c
 
@@ -1933,6 +2031,13 @@ btest_gnudebuglink.log: btest_gnudebuglink
        --log-file $$b.log --trs-file $$b.trs \
        $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
        "$$tst" $(AM_TESTS_FD_REDIRECT)
+mtest_minidebug.log: mtest_minidebug
+       @p='mtest_minidebug'; \
+       b='mtest_minidebug'; \
+       $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+       --log-file $$b.log --trs-file $$b.trs \
+       $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+       "$$tst" $(AM_TESTS_FD_REDIRECT)
 test_elf_32.log: test_elf_32$(EXEEXT)
        @p='test_elf_32$(EXEEXT)'; \
        b='test_elf_32'; \
@@ -2115,6 +2220,27 @@ dwarf5_alloc.log: dwarf5_alloc$(EXEEXT)
        --log-file $$b.log --trs-file $$b.trs \
        $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
        "$$tst" $(AM_TESTS_FD_REDIRECT)
+mtest.log: mtest$(EXEEXT)
+       @p='mtest$(EXEEXT)'; \
+       b='mtest'; \
+       $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+       --log-file $$b.log --trs-file $$b.trs \
+       $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+       "$$tst" $(AM_TESTS_FD_REDIRECT)
+xztest.log: xztest$(EXEEXT)
+       @p='xztest$(EXEEXT)'; \
+       b='xztest'; \
+       $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+       --log-file $$b.log --trs-file $$b.trs \
+       $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+       "$$tst" $(AM_TESTS_FD_REDIRECT)
+xztest_alloc.log: xztest_alloc$(EXEEXT)
+       @p='xztest_alloc$(EXEEXT)'; \
+       b='xztest_alloc'; \
+       $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+       --log-file $$b.log --trs-file $$b.trs \
+       $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+       "$$tst" $(AM_TESTS_FD_REDIRECT)
 .test.log:
        @p='$<'; \
        $(am__set_b); \
@@ -2323,11 +2449,23 @@ uninstall-am:
 @NATIVE_TRUE@    $<
 @NATIVE_TRUE@  $(OBJCOPY) --strip-debug $< $@
 
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@%_minidebug: %
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(NM) -D $< -P --defined-only | $(AWK) '{ print $$1 }' | sort > $<.dsyms
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(NM) $< -P --defined-only | $(AWK) '{ if ($$2 == "T" || $$2 == "t" || $$2 == "D") print $$1 }' | sort > $<.fsyms
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(COMM) -13 $<.dsyms $<.fsyms > $<.keepsyms
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(OBJCOPY) --only-keep-debug $< $<.dbg
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(OBJCOPY) -S --remove-section .gdb_index --remove-section .comment --keep-symbols=$<.keepsyms $<.dbg $<.mdbg
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(OBJCOPY) --strip-all --remove-section ..comment $< $<.strip
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     rm -f $<.mdbg.xz
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(XZ) $<.mdbg
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     $(OBJCOPY) --add-section .gnu_debugdata=$<.mdbg.xz $<.strip
+@HAVE_MINIDEBUG_TRUE@@NATIVE_TRUE@     mv $<.strip $@
+
 clean-local:
        -rm -rf usr
 alloc.lo: config.h backtrace.h internal.h
 backtrace.lo: config.h backtrace.h internal.h
-btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.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
 elf.lo: config.h backtrace.h internal.h
@@ -2335,6 +2473,7 @@ fileline.lo: config.h backtrace.h internal.h
 macho.lo: config.h backtrace.h internal.h
 mmap.lo: config.h backtrace.h internal.h
 mmapio.lo: config.h backtrace.h internal.h
+mtest.lo: backtrace.h backtrace-supported.h
 nounwind.lo: config.h internal.h
 pecoff.lo: config.h backtrace.h internal.h
 posix.lo: config.h backtrace.h internal.h
@@ -2346,6 +2485,8 @@ 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
 xcoff.lo: config.h backtrace.h internal.h
+xztest.lo: config.h backtrace.h backtrace-supported.h internal.h testlib.h
+ztest.lo: config.h backtrace.h backtrace-supported.h internal.h testlib.h
 
 # GNU Make needs to see an explicit $(MAKE) variable in the command it
 # runs to enable its job server during parallel builds.  Hence the
index 2303880b9b871591811893e64ddb3137dda2376b..cdb416e6406129911d2a149d2f4339dd86ebc3dc 100644 (file)
@@ -46,6 +46,9 @@
    <sys/sysctl.h>. */
 #undef HAVE_KERN_PROC_ARGS
 
+/* Define if -llzma is available. */
+#undef HAVE_LIBLZMA
+
 /* Define to 1 if you have the <link.h> header file. */
 #undef HAVE_LINK_H
 
index d4b3523e10ee6658a0bbf48abb836b08c40073ea..031a15602c628784be3ccfd42e27d9d7491ad6bc 100755 (executable)
@@ -635,6 +635,16 @@ LTLIBOBJS
 LIBOBJS
 NATIVE_FALSE
 NATIVE_TRUE
+HAVE_LIBLZMA_FALSE
+HAVE_LIBLZMA_TRUE
+HAVE_MINIDEBUG_FALSE
+HAVE_MINIDEBUG_TRUE
+HAVE_COMM_FALSE
+HAVE_COMM_TRUE
+COMM
+HAVE_XZ_FALSE
+HAVE_XZ_TRUE
+XZ
 HAVE_DSYMUTIL_FALSE
 HAVE_DSYMUTIL_TRUE
 HAVE_OBJCOPY_DEBUGLINK_FALSE
@@ -804,7 +814,8 @@ LIBS
 CPPFLAGS
 CPP
 OBJCOPY
-DSYMUTIL'
+DSYMUTIL
+NM'
 
 
 # Initialize some variables set by options.
@@ -1460,6 +1471,7 @@ Some influential environment variables:
   CPP         C preprocessor
   OBJCOPY     location of objcopy
   DSYMUTIL    location of dsymutil
+  NM          location of nm
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -11505,7 +11517,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11508 "configure"
+#line 11520 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11611,7 +11623,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11614 "configure"
+#line 11626 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -13857,6 +13869,196 @@ else
 fi
 
 
+
+# Extract the first word of "nm", so it can be a program name with args.
+set dummy nm; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  ac_cv_prog_NM="$NM" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NM="nm"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NM=$ac_cv_prog_NM
+if test -n "$NM"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NM" >&5
+$as_echo "$NM" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+# Extract the first word of "xz", so it can be a program name with args.
+set dummy xz; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_XZ+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$XZ"; then
+  ac_cv_prog_XZ="$XZ" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_XZ="xz"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+XZ=$ac_cv_prog_XZ
+if test -n "$XZ"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XZ" >&5
+$as_echo "$XZ" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "$XZ" != ""; then
+  HAVE_XZ_TRUE=
+  HAVE_XZ_FALSE='#'
+else
+  HAVE_XZ_TRUE='#'
+  HAVE_XZ_FALSE=
+fi
+
+# Extract the first word of "comm", so it can be a program name with args.
+set dummy comm; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_COMM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$COMM"; then
+  ac_cv_prog_COMM="$COMM" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_COMM="comm"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+COMM=$ac_cv_prog_COMM
+if test -n "$COMM"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $COMM" >&5
+$as_echo "$COMM" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "$COMM" != ""; then
+  HAVE_COMM_TRUE=
+  HAVE_COMM_FALSE='#'
+else
+  HAVE_COMM_TRUE='#'
+  HAVE_COMM_FALSE=
+fi
+
+
+ if test "${with_target_subdir}" = "" -a "$FORMAT_FILE" = "elf.lo" -a "${OBJCOPY}" != "" -a "${NM}" != "" -a "${XZ}" != "" -a "${COMM}" != ""; then
+  HAVE_MINIDEBUG_TRUE=
+  HAVE_MINIDEBUG_FALSE='#'
+else
+  HAVE_MINIDEBUG_TRUE='#'
+  HAVE_MINIDEBUG_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzma_auto_decoder in -llzma" >&5
+$as_echo_n "checking for lzma_auto_decoder in -llzma... " >&6; }
+if ${ac_cv_lib_lzma_lzma_auto_decoder+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-llzma  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char lzma_auto_decoder ();
+int
+main ()
+{
+return lzma_auto_decoder ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_lzma_lzma_auto_decoder=yes
+else
+  ac_cv_lib_lzma_lzma_auto_decoder=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_auto_decoder" >&5
+$as_echo "$ac_cv_lib_lzma_lzma_auto_decoder" >&6; }
+if test "x$ac_cv_lib_lzma_lzma_auto_decoder" = xyes; then :
+
+$as_echo "#define HAVE_LIBLZMA 1" >>confdefs.h
+
+fi
+
+ if test "$ac_cv_lib_lzma_lzma_auto_decoder" = yes; then
+  HAVE_LIBLZMA_TRUE=
+  HAVE_LIBLZMA_FALSE='#'
+else
+  HAVE_LIBLZMA_TRUE='#'
+  HAVE_LIBLZMA_FALSE=
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tests can run" >&5
 $as_echo_n "checking whether tests can run... " >&6; }
 if ${libbacktrace_cv_sys_native+:} false; then :
@@ -14073,6 +14275,22 @@ if test -z "${HAVE_DSYMUTIL_TRUE}" && test -z "${HAVE_DSYMUTIL_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_DSYMUTIL\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_XZ_TRUE}" && test -z "${HAVE_XZ_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_XZ\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_COMM_TRUE}" && test -z "${HAVE_COMM_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_COMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_MINIDEBUG_TRUE}" && test -z "${HAVE_MINIDEBUG_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_MINIDEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_LIBLZMA_TRUE}" && test -z "${HAVE_LIBLZMA_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_LIBLZMA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${NATIVE_TRUE}" && test -z "${NATIVE_FALSE}"; then
   as_fn_error $? "conditional \"NATIVE\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
index c4b19c4066f0657528838abb3ce6140f9bcd7d86..0659ea604848e59893e19b2595521e1af3a64fcb 100644 (file)
@@ -512,6 +512,21 @@ AC_ARG_VAR(DSYMUTIL, [location of dsymutil])
 AC_CHECK_PROG(DSYMUTIL, dsymutil, dsymutil)
 AM_CONDITIONAL(HAVE_DSYMUTIL, test -n "${DSYMUTIL}")
 
+AC_ARG_VAR(NM, [location of nm])
+AC_CHECK_PROG(NM, nm, nm)
+
+AC_CHECK_PROG(XZ, xz, xz)
+AM_CONDITIONAL(HAVE_XZ, test "$XZ" != "")
+AC_CHECK_PROG(COMM, comm, comm)
+AM_CONDITIONAL(HAVE_COMM, test "$COMM" != "")
+
+AM_CONDITIONAL(HAVE_MINIDEBUG,
+  test "${with_target_subdir}" = "" -a "$FORMAT_FILE" = "elf.lo" -a "${OBJCOPY}" != "" -a "${NM}" != "" -a "${XZ}" != "" -a "${COMM}" != "")
+
+AC_CHECK_LIB([lzma], [lzma_auto_decoder],
+    [AC_DEFINE(HAVE_LIBLZMA, 1, [Define if -llzma is available.])])
+AM_CONDITIONAL(HAVE_LIBLZMA, test "$ac_cv_lib_lzma_lzma_auto_decoder" = yes)
+
 AC_CACHE_CHECK([whether tests can run],
   [libbacktrace_cv_sys_native],
   [AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
index 80a00506bd6186a758abc9a3327d5a0abf271a4b..dd00470824687774e4118e4c0d08e279682c7357 100644 (file)
@@ -390,6 +390,14 @@ struct elf_syminfo_data
   size_t count;
 };
 
+/* A view that works for either a file or memory.  */
+
+struct elf_view
+{
+  struct backtrace_view view;
+  int release; /* If non-zero, must call backtrace_release_view.  */
+};
+
 /* Information about PowerPC64 ELFv1 .opd section.  */
 
 struct elf_ppc64_opd_data
@@ -401,9 +409,48 @@ struct elf_ppc64_opd_data
   /* Size of the .opd section.  */
   size_t size;
   /* Corresponding section view.  */
-  struct backtrace_view view;
+  struct elf_view view;
 };
 
+/* Create a view of SIZE bytes from DESCRIPTOR/MEMORY at OFFSET.  */
+
+static int
+elf_get_view (struct backtrace_state *state, int descriptor,
+             const unsigned char *memory, size_t memory_size, off_t offset,
+             uint64_t size, backtrace_error_callback error_callback,
+             void *data, struct elf_view *view)
+{
+  if (memory == NULL)
+    {
+      view->release = 1;
+      return backtrace_get_view (state, descriptor, offset, size,
+                                error_callback, data, &view->view);
+    }
+  else
+    {
+      if ((uint64_t) offset + size > (uint64_t) memory_size)
+       {
+         error_callback (data, "out of range for in-memory file", 0);
+         return 0;
+       }
+      view->view.data = (const void *) (memory + offset);
+      view->view.base = NULL;
+      view->view.len = size;
+      view->release = 0;
+      return 1;
+    }
+}
+
+/* Release a view read by elf_get_view.  */
+
+static void
+elf_release_view (struct backtrace_state *state, struct elf_view *view,
+                 backtrace_error_callback error_callback, void *data)
+{
+  if (view->release)
+    backtrace_release_view (state, &view->view, error_callback, data);
+}
+
 /* Compute the CRC-32 of BUF/LEN.  This uses the CRC used for
    .gnu_debuglink files.  */
 
@@ -1035,7 +1082,7 @@ elf_open_debugfile_by_debuglink (struct backtrace_state *state,
    when this code is compiled with -g.  */
 
 static void
-elf_zlib_failed(void)
+elf_uncompress_failed(void)
 {
 }
 
@@ -1062,7 +1109,7 @@ elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend,
 
   if (unlikely (pinend - pin < 4))
     {
-      elf_zlib_failed ();
+      elf_uncompress_failed ();
       return 0;
     }
 
@@ -1192,7 +1239,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
     {
       if (unlikely (codes[i] >= 16))
        {
-         elf_zlib_failed ();
+         elf_uncompress_failed ();
          return 0;
        }
 
@@ -1229,7 +1276,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
 
       if (unlikely (jcnt > (1U << j)))
        {
-         elf_zlib_failed ();
+         elf_uncompress_failed ();
          return 0;
        }
 
@@ -1249,7 +1296,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
 
          if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0))
            {
-             elf_zlib_failed ();
+             elf_uncompress_failed ();
              return 0;
            }
 
@@ -1265,7 +1312,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
            {
              if (unlikely (table[ind] != 0))
                {
-                 elf_zlib_failed ();
+                 elf_uncompress_failed ();
                  return 0;
                }
              table[ind] = tval;
@@ -1353,7 +1400,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
        }
       if (unlikely (jcnt != 0))
        {
-         elf_zlib_failed ();
+         elf_uncompress_failed ();
          return 0;
        }
     }
@@ -1406,7 +1453,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
                  if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK)
                                != next_secondary))
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
 
@@ -1424,7 +1471,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
                  if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT))
                                == 0))
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
                  secondary = tprimary & HUFFMAN_VALUE_MASK;
@@ -1432,7 +1479,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
                                    & HUFFMAN_BITS_MASK);
                  if (unlikely (secondary_bits < j - 8))
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
                }
@@ -1448,7 +1495,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
            {
              if (unlikely (table[secondary + 0x100 + ind] != 0))
                {
-                 elf_zlib_failed ();
+                 elf_uncompress_failed ();
                  return 0;
                }
              table[secondary + 0x100 + ind] = tval;
@@ -1664,28 +1711,28 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
       if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding.  */
        {
          /* Unknown compression method.  */
-         elf_zlib_failed ();
+         elf_uncompress_failed ();
          return 0;
        }
       if (unlikely ((pin[0] >> 4) > 7))
        {
          /* Window size too large.  Other than this check, we don't
             care about the window size.  */
-         elf_zlib_failed ();
+         elf_uncompress_failed ();
          return 0;
        }
       if (unlikely ((pin[1] & 0x20) != 0))
        {
          /* Stream expects a predefined dictionary, but we have no
             dictionary.  */
-         elf_zlib_failed ();
+         elf_uncompress_failed ();
          return 0;
        }
       val = (pin[0] << 8) | pin[1];
       if (unlikely (val % 31 != 0))
        {
          /* Header check failure.  */
-         elf_zlib_failed ();
+         elf_uncompress_failed ();
          return 0;
        }
       pin += 2;
@@ -1722,7 +1769,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
          if (unlikely (type == 3))
            {
              /* Invalid block type.  */
-             elf_zlib_failed ();
+             elf_uncompress_failed ();
              return 0;
            }
 
@@ -1745,7 +1792,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
              if (unlikely ((pinend - pin) < 4))
                {
                  /* Missing length.  */
-                 elf_zlib_failed ();
+                 elf_uncompress_failed ();
                  return 0;
                }
              len = pin[0] | (pin[1] << 8);
@@ -1755,14 +1802,14 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
              if (unlikely (len != lenc))
                {
                  /* Corrupt data.  */
-                 elf_zlib_failed ();
+                 elf_uncompress_failed ();
                  return 0;
                }
              if (unlikely (len > (unsigned int) (pinend - pin)
                            || len > (unsigned int) (poutend - pout)))
                {
                  /* Not enough space in buffers.  */
-                 elf_zlib_failed ();
+                 elf_uncompress_failed ();
                  return 0;
                }
              memcpy (pout, pin, len);
@@ -1812,7 +1859,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
              if (unlikely (nlit > 286 || ndist > 30))
                {
                  /* Values out of range.  */
-                 elf_zlib_failed ();
+                 elf_uncompress_failed ();
                  return 0;
                }
 
@@ -1977,7 +2024,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                     a secondary table is never necessary.  */
                  if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0))
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
 
@@ -1997,7 +2044,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
 
                      if (unlikely (plen == plenbase))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
@@ -2010,7 +2057,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                      bits -= 2;
                      if (unlikely ((unsigned int) (plenend - plen) < c))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
@@ -2045,7 +2092,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                      bits -= 3;
                      if (unlikely ((unsigned int) (plenend - plen) < c))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
@@ -2091,7 +2138,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                      bits -= 7;
                      if (unlikely ((unsigned int) (plenend - plen) < c))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
@@ -2100,7 +2147,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                    }
                  else
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
                }
@@ -2110,7 +2157,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
              plen = plenbase;
              if (unlikely (plen[256] == 0))
                {
-                 elf_zlib_failed ();
+                 elf_uncompress_failed ();
                  return 0;
                }
 
@@ -2162,7 +2209,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                {
                  if (unlikely (pout == poutend))
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
 
@@ -2191,7 +2238,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                    len = 258;
                  else if (unlikely (lit > 285))
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
                  else
@@ -2244,13 +2291,13 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
 
                      if (unlikely (pout == porigout))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
                      if (unlikely ((unsigned int) (poutend - pout) < len))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
@@ -2259,7 +2306,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
                    }
                  else if (unlikely (dist > 29))
                    {
-                     elf_zlib_failed ();
+                     elf_uncompress_failed ();
                      return 0;
                    }
                  else
@@ -2290,13 +2337,13 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
 
                      if (unlikely ((unsigned int) (pout - porigout) < dist))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
                      if (unlikely ((unsigned int) (poutend - pout) < len))
                        {
-                         elf_zlib_failed ();
+                         elf_uncompress_failed ();
                          return 0;
                        }
 
@@ -2326,7 +2373,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
   /* We should have filled the output buffer.  */
   if (unlikely (pout != poutend))
     {
-      elf_zlib_failed ();
+      elf_uncompress_failed ();
       return 0;
     }
 
@@ -2453,7 +2500,7 @@ elf_zlib_verify_checksum (const unsigned char *checkbytes,
 
   if (unlikely ((s2 << 16) + s1 != cksum))
     {
-      elf_zlib_failed ();
+      elf_uncompress_failed ();
       return 0;
     }
 
@@ -2608,6 +2655,1311 @@ backtrace_uncompress_zdebug (struct backtrace_state *state,
   return ret;
 }
 
+/* Number of LZMA states.  */
+#define LZMA_STATES (12)
+
+/* Number of LZMA position states.  The pb value of the property byte
+   is the number of bits to include in these states, and the maximum
+   value of pb is 4.  */
+#define LZMA_POS_STATES (16)
+
+/* Number of LZMA distance states.  These are used match distances
+   with a short match length: up to 4 bytes.  */
+#define LZMA_DIST_STATES (4)
+
+/* Number of LZMA distance slots.  LZMA uses six bits to encode larger
+   match lengths, so 1 << 6 possible probabilities.  */
+#define LZMA_DIST_SLOTS (64)
+
+/* LZMA distances 0 to 3 are encoded directly, larger values use a
+   probability model.  */
+#define LZMA_DIST_MODEL_START (4)
+
+/* The LZMA probability model ends at 14.  */
+#define LZMA_DIST_MODEL_END (14)
+
+/* LZMA distance slots for distances less than 127.  */
+#define LZMA_FULL_DISTANCES (128)
+
+/* LZMA uses four alignment bits.  */
+#define LZMA_ALIGN_SIZE (16)
+
+/* LZMA match length is encoded with 4, 5, or 10 bits, some of which
+   are already known.  */
+#define LZMA_LEN_LOW_SYMBOLS (8)
+#define LZMA_LEN_MID_SYMBOLS (8)
+#define LZMA_LEN_HIGH_SYMBOLS (256)
+
+/* LZMA literal encoding.  */
+#define LZMA_LITERAL_CODERS_MAX (16)
+#define LZMA_LITERAL_CODER_SIZE (0x300)
+
+/* LZMA is based on a large set of probabilities, each managed
+   independently.  Each probability is an 11 bit number that we store
+   in a uint16_t.  We use a single large array of probabilities.  */
+
+/* Lengths of entries in the LZMA probabilities array.  The names used
+   here are copied from the Linux kernel implementation.  */
+
+#define LZMA_PROB_IS_MATCH_LEN (LZMA_STATES * LZMA_POS_STATES)
+#define LZMA_PROB_IS_REP_LEN LZMA_STATES
+#define LZMA_PROB_IS_REP0_LEN LZMA_STATES
+#define LZMA_PROB_IS_REP1_LEN LZMA_STATES
+#define LZMA_PROB_IS_REP2_LEN LZMA_STATES
+#define LZMA_PROB_IS_REP0_LONG_LEN (LZMA_STATES * LZMA_POS_STATES)
+#define LZMA_PROB_DIST_SLOT_LEN (LZMA_DIST_STATES * LZMA_DIST_SLOTS)
+#define LZMA_PROB_DIST_SPECIAL_LEN (LZMA_FULL_DISTANCES - LZMA_DIST_MODEL_END)
+#define LZMA_PROB_DIST_ALIGN_LEN LZMA_ALIGN_SIZE
+#define LZMA_PROB_MATCH_LEN_CHOICE_LEN 1
+#define LZMA_PROB_MATCH_LEN_CHOICE2_LEN 1
+#define LZMA_PROB_MATCH_LEN_LOW_LEN (LZMA_POS_STATES * LZMA_LEN_LOW_SYMBOLS)
+#define LZMA_PROB_MATCH_LEN_MID_LEN (LZMA_POS_STATES * LZMA_LEN_MID_SYMBOLS)
+#define LZMA_PROB_MATCH_LEN_HIGH_LEN LZMA_LEN_HIGH_SYMBOLS
+#define LZMA_PROB_REP_LEN_CHOICE_LEN 1
+#define LZMA_PROB_REP_LEN_CHOICE2_LEN 1
+#define LZMA_PROB_REP_LEN_LOW_LEN (LZMA_POS_STATES * LZMA_LEN_LOW_SYMBOLS)
+#define LZMA_PROB_REP_LEN_MID_LEN (LZMA_POS_STATES * LZMA_LEN_MID_SYMBOLS)
+#define LZMA_PROB_REP_LEN_HIGH_LEN LZMA_LEN_HIGH_SYMBOLS
+#define LZMA_PROB_LITERAL_LEN \
+  (LZMA_LITERAL_CODERS_MAX * LZMA_LITERAL_CODER_SIZE)
+
+/* Offsets into the LZMA probabilities array.  This is mechanically
+   generated from the above lengths.  */
+
+#define LZMA_PROB_IS_MATCH_OFFSET 0
+#define LZMA_PROB_IS_REP_OFFSET \
+  (LZMA_PROB_IS_MATCH_OFFSET + LZMA_PROB_IS_MATCH_LEN)
+#define LZMA_PROB_IS_REP0_OFFSET \
+  (LZMA_PROB_IS_REP_OFFSET + LZMA_PROB_IS_REP_LEN)
+#define LZMA_PROB_IS_REP1_OFFSET \
+  (LZMA_PROB_IS_REP0_OFFSET + LZMA_PROB_IS_REP0_LEN)
+#define LZMA_PROB_IS_REP2_OFFSET \
+  (LZMA_PROB_IS_REP1_OFFSET + LZMA_PROB_IS_REP1_LEN)
+#define LZMA_PROB_IS_REP0_LONG_OFFSET \
+  (LZMA_PROB_IS_REP2_OFFSET + LZMA_PROB_IS_REP2_LEN)
+#define LZMA_PROB_DIST_SLOT_OFFSET \
+  (LZMA_PROB_IS_REP0_LONG_OFFSET + LZMA_PROB_IS_REP0_LONG_LEN)
+#define LZMA_PROB_DIST_SPECIAL_OFFSET \
+  (LZMA_PROB_DIST_SLOT_OFFSET + LZMA_PROB_DIST_SLOT_LEN)
+#define LZMA_PROB_DIST_ALIGN_OFFSET \
+  (LZMA_PROB_DIST_SPECIAL_OFFSET + LZMA_PROB_DIST_SPECIAL_LEN)
+#define LZMA_PROB_MATCH_LEN_CHOICE_OFFSET \
+  (LZMA_PROB_DIST_ALIGN_OFFSET + LZMA_PROB_DIST_ALIGN_LEN)
+#define LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET \
+  (LZMA_PROB_MATCH_LEN_CHOICE_OFFSET + LZMA_PROB_MATCH_LEN_CHOICE_LEN)
+#define LZMA_PROB_MATCH_LEN_LOW_OFFSET \
+  (LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET + LZMA_PROB_MATCH_LEN_CHOICE2_LEN)
+#define LZMA_PROB_MATCH_LEN_MID_OFFSET \
+  (LZMA_PROB_MATCH_LEN_LOW_OFFSET + LZMA_PROB_MATCH_LEN_LOW_LEN)
+#define LZMA_PROB_MATCH_LEN_HIGH_OFFSET \
+  (LZMA_PROB_MATCH_LEN_MID_OFFSET + LZMA_PROB_MATCH_LEN_MID_LEN)
+#define LZMA_PROB_REP_LEN_CHOICE_OFFSET \
+  (LZMA_PROB_MATCH_LEN_HIGH_OFFSET + LZMA_PROB_MATCH_LEN_HIGH_LEN)
+#define LZMA_PROB_REP_LEN_CHOICE2_OFFSET \
+  (LZMA_PROB_REP_LEN_CHOICE_OFFSET + LZMA_PROB_REP_LEN_CHOICE_LEN)
+#define LZMA_PROB_REP_LEN_LOW_OFFSET \
+  (LZMA_PROB_REP_LEN_CHOICE2_OFFSET + LZMA_PROB_REP_LEN_CHOICE2_LEN)
+#define LZMA_PROB_REP_LEN_MID_OFFSET \
+  (LZMA_PROB_REP_LEN_LOW_OFFSET + LZMA_PROB_REP_LEN_LOW_LEN)
+#define LZMA_PROB_REP_LEN_HIGH_OFFSET \
+  (LZMA_PROB_REP_LEN_MID_OFFSET + LZMA_PROB_REP_LEN_MID_LEN)
+#define LZMA_PROB_LITERAL_OFFSET \
+  (LZMA_PROB_REP_LEN_HIGH_OFFSET + LZMA_PROB_REP_LEN_HIGH_LEN)
+
+#define LZMA_PROB_TOTAL_COUNT \
+  (LZMA_PROB_LITERAL_OFFSET + LZMA_PROB_LITERAL_LEN)
+
+/* Check that the number of LZMA probabilities is the same as the
+   Linux kernel implementation.  */
+
+#if LZMA_PROB_TOTAL_COUNT != 1846 + (1 << 4) * 0x300
+ #error Wrong number of LZMA probabilities
+#endif
+
+/* Expressions for the offset in the LZMA probabilities array of a
+   specific probability.  */
+
+#define LZMA_IS_MATCH(state, pos) \
+  (LZMA_PROB_IS_MATCH_OFFSET + (state) * LZMA_POS_STATES + (pos))
+#define LZMA_IS_REP(state) \
+  (LZMA_PROB_IS_REP_OFFSET + (state))
+#define LZMA_IS_REP0(state) \
+  (LZMA_PROB_IS_REP0_OFFSET + (state))
+#define LZMA_IS_REP1(state) \
+  (LZMA_PROB_IS_REP1_OFFSET + (state))
+#define LZMA_IS_REP2(state) \
+  (LZMA_PROB_IS_REP2_OFFSET + (state))
+#define LZMA_IS_REP0_LONG(state, pos) \
+  (LZMA_PROB_IS_REP0_LONG_OFFSET + (state) * LZMA_POS_STATES + (pos))
+#define LZMA_DIST_SLOT(dist, slot) \
+  (LZMA_PROB_DIST_SLOT_OFFSET + (dist) * LZMA_DIST_SLOTS + (slot))
+#define LZMA_DIST_SPECIAL(dist) \
+  (LZMA_PROB_DIST_SPECIAL_OFFSET + (dist))
+#define LZMA_DIST_ALIGN(dist) \
+  (LZMA_PROB_DIST_ALIGN_OFFSET + (dist))
+#define LZMA_MATCH_LEN_CHOICE \
+  LZMA_PROB_MATCH_LEN_CHOICE_OFFSET
+#define LZMA_MATCH_LEN_CHOICE2 \
+  LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET
+#define LZMA_MATCH_LEN_LOW(pos, sym) \
+  (LZMA_PROB_MATCH_LEN_LOW_OFFSET + (pos) * LZMA_LEN_LOW_SYMBOLS + (sym))
+#define LZMA_MATCH_LEN_MID(pos, sym) \
+  (LZMA_PROB_MATCH_LEN_MID_OFFSET + (pos) * LZMA_LEN_MID_SYMBOLS + (sym))
+#define LZMA_MATCH_LEN_HIGH(sym) \
+  (LZMA_PROB_MATCH_LEN_HIGH_OFFSET + (sym))
+#define LZMA_REP_LEN_CHOICE \
+  LZMA_PROB_REP_LEN_CHOICE_OFFSET
+#define LZMA_REP_LEN_CHOICE2 \
+  LZMA_PROB_REP_LEN_CHOICE2_OFFSET
+#define LZMA_REP_LEN_LOW(pos, sym) \
+  (LZMA_PROB_REP_LEN_LOW_OFFSET + (pos) * LZMA_LEN_LOW_SYMBOLS + (sym))
+#define LZMA_REP_LEN_MID(pos, sym) \
+  (LZMA_PROB_REP_LEN_MID_OFFSET + (pos) * LZMA_LEN_MID_SYMBOLS + (sym))
+#define LZMA_REP_LEN_HIGH(sym) \
+  (LZMA_PROB_REP_LEN_HIGH_OFFSET + (sym))
+#define LZMA_LITERAL(code, size) \
+  (LZMA_PROB_LITERAL_OFFSET + (code) * LZMA_LITERAL_CODER_SIZE + (size))
+
+/* Read an LZMA varint from BUF, reading and updating *POFFSET,
+   setting *VAL.  Returns 0 on error, 1 on success.  */
+
+static int
+elf_lzma_varint (const unsigned char *compressed, size_t compressed_size,
+                size_t *poffset, uint64_t *val)
+{
+  size_t off;
+  int i;
+  uint64_t v;
+  unsigned char b;
+
+  off = *poffset;
+  i = 0;
+  v = 0;
+  while (1)
+    {
+      if (unlikely (off >= compressed_size))
+       {
+         elf_uncompress_failed ();
+         return 0;
+       }
+      b = compressed[off];
+      v |= (b & 0x7f) << (i * 7);
+      ++off;
+      if ((b & 0x80) == 0)
+       {
+         *poffset = off;
+         *val = v;
+         return 1;
+       }
+      ++i;
+      if (unlikely (i >= 9))
+       {
+         elf_uncompress_failed ();
+         return 0;
+       }
+    }
+}
+
+/* Normalize the LZMA range decoder, pulling in an extra input byte if
+   needed.  */
+
+static void
+elf_lzma_range_normalize (const unsigned char *compressed,
+                         size_t compressed_size, size_t *poffset,
+                         uint32_t *prange, uint32_t *pcode)
+{
+  if (*prange < (1U << 24))
+    {
+      if (unlikely (*poffset >= compressed_size))
+       {
+         /* We assume this will be caught elsewhere.  */
+         elf_uncompress_failed ();
+         return;
+       }
+      *prange <<= 8;
+      *pcode <<= 8;
+      *pcode += compressed[*poffset];
+      ++*poffset;
+    }
+}
+
+/* Read and return a single bit from the LZMA stream, reading and
+   updating *PROB.  Each bit comes from the range coder.  */
+
+static int
+elf_lzma_bit (const unsigned char *compressed, size_t compressed_size,
+             uint16_t *prob, size_t *poffset, uint32_t *prange,
+             uint32_t *pcode)
+{
+  uint32_t bound;
+
+  elf_lzma_range_normalize (compressed, compressed_size, poffset,
+                           prange, pcode);
+  bound = (*prange >> 11) * (uint32_t) *prob;
+  if (*pcode < bound)
+    {
+      *prange = bound;
+      *prob += ((1U << 11) - *prob) >> 5;
+      return 0;
+    }
+  else
+    {
+      *prange -= bound;
+      *pcode -= bound;
+      *prob -= *prob >> 5;
+      return 1;
+    }
+}
+
+/* Read an integer of size BITS from the LZMA stream, most significant
+   bit first.  The bits are predicted using PROBS.  */
+
+static uint32_t
+elf_lzma_integer (const unsigned char *compressed, size_t compressed_size,
+                 uint16_t *probs, uint32_t bits, size_t *poffset,
+                 uint32_t *prange, uint32_t *pcode)
+{
+  uint32_t sym;
+  uint32_t i;
+
+  sym = 1;
+  for (i = 0; i < bits; i++)
+    {
+      int bit;
+
+      bit = elf_lzma_bit (compressed, compressed_size, probs + sym, poffset,
+                         prange, pcode);
+      sym <<= 1;
+      sym += bit;
+    }
+  return sym - (1 << bits);
+}
+
+/* Read an integer of size BITS from the LZMA stream, least
+   significant bit first.  The bits are predicted using PROBS.  */
+
+static uint32_t
+elf_lzma_reverse_integer (const unsigned char *compressed,
+                         size_t compressed_size, uint16_t *probs,
+                         uint32_t bits, size_t *poffset, uint32_t *prange,
+                         uint32_t *pcode)
+{
+  uint32_t sym;
+  uint32_t val;
+  uint32_t i;
+
+  sym = 1;
+  val = 0;
+  for (i = 0; i < bits; i++)
+    {
+      int bit;
+
+      bit = elf_lzma_bit (compressed, compressed_size, probs + sym, poffset,
+                         prange, pcode);
+      sym <<= 1;
+      sym += bit;
+      val += bit << i;
+    }
+  return val;
+}
+
+/* Read a length from the LZMA stream.  IS_REP picks either LZMA_MATCH
+   or LZMA_REP probabilities.  */
+
+static uint32_t
+elf_lzma_len (const unsigned char *compressed, size_t compressed_size,
+             uint16_t *probs, int is_rep, unsigned int pos_state,
+             size_t *poffset, uint32_t *prange, uint32_t *pcode)
+{
+  uint16_t *probs_choice;
+  uint16_t *probs_sym;
+  uint32_t bits;
+  uint32_t len;
+
+  probs_choice = probs + (is_rep
+                         ? LZMA_REP_LEN_CHOICE
+                         : LZMA_MATCH_LEN_CHOICE);
+  if (elf_lzma_bit (compressed, compressed_size, probs_choice, poffset,
+                   prange, pcode))
+    {
+      probs_choice = probs + (is_rep
+                             ? LZMA_REP_LEN_CHOICE2
+                             : LZMA_MATCH_LEN_CHOICE2);
+      if (elf_lzma_bit (compressed, compressed_size, probs_choice,
+                       poffset, prange, pcode))
+       {
+         probs_sym = probs + (is_rep
+                              ? LZMA_REP_LEN_HIGH (0)
+                              : LZMA_MATCH_LEN_HIGH (0));
+         bits = 8;
+         len = 2 + 8 + 8;
+       }
+      else
+       {
+         probs_sym = probs + (is_rep
+                              ? LZMA_REP_LEN_MID (pos_state, 0)
+                              : LZMA_MATCH_LEN_MID (pos_state, 0));
+         bits = 3;
+         len = 2 + 8;
+       }
+    }
+  else
+    {
+      probs_sym = probs + (is_rep
+                          ? LZMA_REP_LEN_LOW (pos_state, 0)
+                          : LZMA_MATCH_LEN_LOW (pos_state, 0));
+      bits = 3;
+      len = 2;
+    }
+
+  len += elf_lzma_integer (compressed, compressed_size, probs_sym, bits,
+                          poffset, prange, pcode);
+  return len;
+}
+
+/* Uncompress one LZMA block from a minidebug file.  The compressed
+   data is at COMPRESSED + *POFFSET.  Update *POFFSET.  Store the data
+   into the memory at UNCOMPRESSED, size UNCOMPRESSED_SIZE.  CHECK is
+   the stream flag from the xz header.  Return 1 on successful
+   decompression.  */
+
+static int
+elf_uncompress_lzma_block (const unsigned char *compressed,
+                          size_t compressed_size, unsigned char check,
+                          uint16_t *probs, unsigned char *uncompressed,
+                          size_t uncompressed_size, size_t *poffset)
+{
+  size_t off;
+  size_t block_header_offset;
+  size_t block_header_size;
+  unsigned char block_flags;
+  uint64_t header_compressed_size;
+  uint64_t header_uncompressed_size;
+  unsigned char lzma2_properties;
+  uint32_t computed_crc;
+  uint32_t stream_crc;
+  size_t uncompressed_offset;
+  size_t dict_start_offset;
+  unsigned int lc;
+  unsigned int lp;
+  unsigned int pb;
+  uint32_t range;
+  uint32_t code;
+  uint32_t lstate;
+  uint32_t dist[4];
+
+  off = *poffset;
+  block_header_offset = off;
+
+  /* Block header size is a single byte.  */
+  if (unlikely (off >= compressed_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  block_header_size = (compressed[off] + 1) * 4;
+  if (unlikely (off + block_header_size > compressed_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* Block flags.  */
+  block_flags = compressed[off + 1];
+  if (unlikely ((block_flags & 0x3c) != 0))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  off += 2;
+
+  /* Optional compressed size.  */
+  header_compressed_size = 0;
+  if ((block_flags & 0x40) != 0)
+    {
+      *poffset = off;
+      if (!elf_lzma_varint (compressed, compressed_size, poffset,
+                           &header_compressed_size))
+       return 0;
+      off = *poffset;
+    }
+
+  /* Optional uncompressed size.  */
+  header_uncompressed_size = 0;
+  if ((block_flags & 0x80) != 0)
+    {
+      *poffset = off;
+      if (!elf_lzma_varint (compressed, compressed_size, poffset,
+                           &header_uncompressed_size))
+       return 0;
+      off = *poffset;
+    }
+
+  /* The recipe for creating a minidebug file is to run the xz program
+     with no arguments, so we expect exactly one filter: lzma2.  */
+
+  if (unlikely ((block_flags & 0x3) != 0))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  if (unlikely (off + 2 >= block_header_offset + block_header_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* The filter ID for LZMA2 is 0x21.  */
+  if (unlikely (compressed[off] != 0x21))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  ++off;
+
+  /* The size of the filter properties for LZMA2 is 1.  */
+  if (unlikely (compressed[off] != 1))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  ++off;
+
+  lzma2_properties = compressed[off];
+  ++off;
+
+  if (unlikely (lzma2_properties > 40))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* The properties describe the dictionary size, but we don't care
+     what that is.  */
+
+  /* Block header padding.  */
+  if (unlikely (off + 4 > compressed_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  off = (off + 3) &~ (size_t) 3;
+
+  if (unlikely (off + 4 > compressed_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* Block header CRC.  */
+  computed_crc = elf_crc32 (0, compressed + block_header_offset,
+                           block_header_size - 4);
+  stream_crc = (compressed[off]
+               | (compressed[off + 1] << 8)
+               | (compressed[off + 2] << 16)
+               | (compressed[off + 3] << 24));
+  if (unlikely (computed_crc != stream_crc))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  off += 4;
+
+  /* Read a sequence of LZMA2 packets.  */
+
+  uncompressed_offset = 0;
+  dict_start_offset = 0;
+  lc = 0;
+  lp = 0;
+  pb = 0;
+  lstate = 0;
+  while (off < compressed_size)
+    {
+      unsigned char control;
+
+      range = 0xffffffff;
+      code = 0;
+
+      control = compressed[off];
+      ++off;
+      if (unlikely (control == 0))
+       {
+         /* End of packets.  */
+         break;
+       }
+
+      if (control == 1 || control >= 0xe0)
+       {
+         /* Reset dictionary to empty.  */
+         dict_start_offset = uncompressed_offset;
+       }
+
+      if (control < 0x80)
+       {
+         size_t chunk_size;
+
+         /* The only valid values here are 1 or 2.  A 1 means to
+            reset the dictionary (done above).  Then we see an
+            uncompressed chunk.  */
+
+         if (unlikely (control > 2))
+           {
+             elf_uncompress_failed ();
+             return 0;
+           }
+
+         /* An uncompressed chunk is a two byte size followed by
+            data.  */
+
+         if (unlikely (off + 2 > compressed_size))
+           {
+             elf_uncompress_failed ();
+             return 0;
+           }
+
+         chunk_size = compressed[off] << 8;
+         chunk_size += compressed[off + 1];
+         ++chunk_size;
+
+         off += 2;
+
+         if (unlikely (off + chunk_size > compressed_size))
+           {
+             elf_uncompress_failed ();
+             return 0;
+           }
+         if (unlikely (uncompressed_offset + chunk_size > uncompressed_size))
+           {
+             elf_uncompress_failed ();
+             return 0;
+           }
+
+         memcpy (uncompressed + uncompressed_offset, compressed + off,
+                 chunk_size);
+         uncompressed_offset += chunk_size;
+         off += chunk_size;
+       }
+      else
+       {
+         size_t uncompressed_chunk_start;
+         size_t uncompressed_chunk_size;
+         size_t compressed_chunk_size;
+         size_t limit;
+
+         /* An LZMA chunk.  This starts with an uncompressed size and
+            a compressed size.  */
+
+         if (unlikely (off + 4 >= compressed_size))
+           {
+             elf_uncompress_failed ();
+             return 0;
+           }
+
+         uncompressed_chunk_start = uncompressed_offset;
+
+         uncompressed_chunk_size = (control & 0x1f) << 16;
+         uncompressed_chunk_size += compressed[off] << 8;
+         uncompressed_chunk_size += compressed[off + 1];
+         ++uncompressed_chunk_size;
+
+         compressed_chunk_size = compressed[off + 2] << 8;
+         compressed_chunk_size += compressed[off + 3];
+         ++compressed_chunk_size;
+
+         off += 4;
+
+         /* Bit 7 (0x80) is set.
+            Bits 6 and 5 (0x40 and 0x20) are as follows:
+            0: don't reset anything
+            1: reset state
+            2: reset state, read properties
+            3: reset state, read properties, reset dictionary (done above) */
+
+         if (control >= 0xc0)
+           {
+             unsigned char props;
+
+             /* Bit 6 is set, read properties.  */
+
+             if (unlikely (off >= compressed_size))
+               {
+                 elf_uncompress_failed ();
+                 return 0;
+               }
+             props = compressed[off];
+             ++off;
+             if (unlikely (props > (4 * 5 + 4) * 9 + 8))
+               {
+                 elf_uncompress_failed ();
+                 return 0;
+               }
+             pb = 0;
+             while (props >= 9 * 5)
+               {
+                 props -= 9 * 5;
+                 ++pb;
+               }
+             lp = 0;
+             while (props > 9)
+               {
+                 props -= 9;
+                 ++lp;
+               }
+             lc = props;
+             if (unlikely (lc + lp > 4))
+               {
+                 elf_uncompress_failed ();
+                 return 0;
+               }
+           }
+
+         if (control >= 0xa0)
+           {
+             size_t i;
+
+             /* Bit 5 or 6 is set, reset LZMA state.  */
+
+             lstate = 0;
+             memset (&dist, 0, sizeof dist);
+             for (i = 0; i < LZMA_PROB_TOTAL_COUNT; i++)
+               probs[i] = 1 << 10;
+             range = 0xffffffff;
+             code = 0;
+           }
+
+         /* Read the range code.  */
+
+         if (unlikely (off + 5 > compressed_size))
+           {
+             elf_uncompress_failed ();
+             return 0;
+           }
+
+         /* The byte at compressed[off] is ignored for some
+            reason.  */
+
+         code = ((compressed[off + 1] << 24)
+                 + (compressed[off + 2] << 16)
+                 + (compressed[off + 3] << 8)
+                 + compressed[off + 4]);
+         off += 5;
+
+         /* This is the main LZMA decode loop.  */
+
+         limit = off + compressed_chunk_size;
+         *poffset = off;
+         while (*poffset < limit)
+           {
+             unsigned int pos_state;
+
+             if (unlikely (uncompressed_offset
+                           == (uncompressed_chunk_start
+                               + uncompressed_chunk_size)))
+               {
+                 /* We've decompressed all the expected bytes.  */
+                 break;
+               }
+
+             pos_state = ((uncompressed_offset - dict_start_offset)
+                          & ((1 << pb) - 1));
+
+             if (elf_lzma_bit (compressed, compressed_size,
+                               probs + LZMA_IS_MATCH (lstate, pos_state),
+                               poffset, &range, &code))
+               {
+                 uint32_t len;
+
+                 if (elf_lzma_bit (compressed, compressed_size,
+                                   probs + LZMA_IS_REP (lstate),
+                                   poffset, &range, &code))
+                   {
+                     int short_rep;
+                     uint32_t next_dist;
+
+                     /* Repeated match.  */
+
+                     short_rep = 0;
+                     if (elf_lzma_bit (compressed, compressed_size,
+                                       probs + LZMA_IS_REP0 (lstate),
+                                       poffset, &range, &code))
+                       {
+                         if (elf_lzma_bit (compressed, compressed_size,
+                                           probs + LZMA_IS_REP1 (lstate),
+                                           poffset, &range, &code))
+                           {
+                             if (elf_lzma_bit (compressed, compressed_size,
+                                               probs + LZMA_IS_REP2 (lstate),
+                                               poffset, &range, &code))
+                               {
+                                 next_dist = dist[3];
+                                 dist[3] = dist[2];
+                               }
+                             else
+                               {
+                                 next_dist = dist[2];
+                               }
+                             dist[2] = dist[1];
+                           }
+                         else
+                           {
+                             next_dist = dist[1];
+                           }
+
+                         dist[1] = dist[0];
+                         dist[0] = next_dist;
+                       }
+                     else
+                       {
+                         if (!elf_lzma_bit (compressed, compressed_size,
+                                           (probs
+                                            + LZMA_IS_REP0_LONG (lstate,
+                                                                 pos_state)),
+                                           poffset, &range, &code))
+                           short_rep = 1;
+                       }
+
+                     if (lstate < 7)
+                       lstate = short_rep ? 9 : 8;
+                     else
+                       lstate = 11;
+
+                     if (short_rep)
+                       len = 1;
+                     else
+                       len = elf_lzma_len (compressed, compressed_size,
+                                           probs, 1, pos_state, poffset,
+                                           &range, &code);
+                   }
+                 else
+                   {
+                     uint32_t dist_state;
+                     uint32_t dist_slot;
+                     uint16_t *probs_dist;
+
+                     /* Match.  */
+
+                     if (lstate < 7)
+                       lstate = 7;
+                     else
+                       lstate = 10;
+                     dist[3] = dist[2];
+                     dist[2] = dist[1];
+                     dist[1] = dist[0];
+                     len = elf_lzma_len (compressed, compressed_size,
+                                         probs, 0, pos_state, poffset,
+                                         &range, &code);
+
+                     if (len < 4 + 2)
+                       dist_state = len - 2;
+                     else
+                       dist_state = 3;
+                     probs_dist = probs + LZMA_DIST_SLOT (dist_state, 0);
+                     dist_slot = elf_lzma_integer (compressed,
+                                                   compressed_size,
+                                                   probs_dist, 6,
+                                                   poffset, &range,
+                                                   &code);
+                     if (dist_slot < LZMA_DIST_MODEL_START)
+                       dist[0] = dist_slot;
+                     else
+                       {
+                         uint32_t limit;
+
+                         limit = (dist_slot >> 1) - 1;
+                         dist[0] = 2 + (dist_slot & 1);
+                         if (dist_slot < LZMA_DIST_MODEL_END)
+                           {
+                             dist[0] <<= limit;
+                             probs_dist = (probs
+                                           + LZMA_DIST_SPECIAL(dist[0]
+                                                               - dist_slot
+                                                               - 1));
+                             dist[0] +=
+                               elf_lzma_reverse_integer (compressed,
+                                                         compressed_size,
+                                                         probs_dist,
+                                                         limit, poffset,
+                                                         &range, &code);
+                           }
+                         else
+                           {
+                             uint32_t dist0;
+                             uint32_t i;
+
+                             dist0 = dist[0];
+                             for (i = 0; i < limit - 4; i++)
+                               {
+                                 uint32_t mask;
+
+                                 elf_lzma_range_normalize (compressed,
+                                                           compressed_size,
+                                                           poffset,
+                                                           &range, &code);
+                                 range >>= 1;
+                                 code -= range;
+                                 mask = -(code >> 31);
+                                 code += range & mask;
+                                 dist0 <<= 1;
+                                 dist0 += mask + 1;
+                               }
+                             dist0 <<= 4;
+                             probs_dist = probs + LZMA_DIST_ALIGN (0);
+                             dist0 +=
+                               elf_lzma_reverse_integer (compressed,
+                                                         compressed_size,
+                                                         probs_dist, 4,
+                                                         poffset,
+                                                         &range, &code);
+                             dist[0] = dist0;
+                           }
+                       }
+                   }
+
+                 if (unlikely (uncompressed_offset
+                               - dict_start_offset < dist[0] + 1))
+                   {
+                     elf_uncompress_failed ();
+                     return 0;
+                   }
+                 if (unlikely (uncompressed_offset + len > uncompressed_size))
+                   {
+                     elf_uncompress_failed ();
+                     return 0;
+                   }
+
+                 if (dist[0] == 0)
+                   {
+                     /* A common case, meaning repeat the last
+                        character LEN times.  */
+                     memset (uncompressed + uncompressed_offset,
+                             uncompressed[uncompressed_offset - 1],
+                             len);
+                     uncompressed_offset += len;
+                   }
+                 else if (dist[0] + 1 >= len)
+                   {
+                     memcpy (uncompressed + uncompressed_offset,
+                             uncompressed + uncompressed_offset - dist[0] - 1,
+                             len);
+                     uncompressed_offset += len;
+                   }
+                 else
+                   {
+                     while (len > 0)
+                       {
+                         uint32_t copy;
+
+                         copy = len < dist[0] + 1 ? len : dist[0] + 1;
+                         memcpy (uncompressed + uncompressed_offset,
+                                 (uncompressed + uncompressed_offset
+                                  - dist[0] - 1),
+                                 copy);
+                         len -= copy;
+                         uncompressed_offset += copy;
+                       }
+                   }
+               }
+             else
+               {
+                 unsigned char prev;
+                 unsigned char low;
+                 size_t high;
+                 uint16_t *lit_probs;
+                 unsigned int sym;
+
+                 /* Literal value.  */
+
+                 if (uncompressed_offset > 0)
+                   prev = uncompressed[uncompressed_offset - 1];
+                 else
+                   prev = 0;
+                 low = prev >> (8 - lc);
+                 high = (((uncompressed_offset - dict_start_offset)
+                          & ((1 << lp) - 1))
+                         << lc);
+                 lit_probs = probs + LZMA_LITERAL (low + high, 0);
+                 if (lstate < 7)
+                   sym = elf_lzma_integer (compressed, compressed_size,
+                                           lit_probs, 8, poffset, &range,
+                                           &code);
+                 else
+                   {
+                     unsigned int match;
+                     unsigned int bit;
+                     unsigned int match_bit;
+                     unsigned int idx;
+
+                     sym = 1;
+                     if (uncompressed_offset >= dist[0] + 1)
+                       match = uncompressed[uncompressed_offset - dist[0] - 1];
+                     else
+                       match = 0;
+                     match <<= 1;
+                     bit = 0x100;
+                     do
+                       {
+                         match_bit = match & bit;
+                         match <<= 1;
+                         idx = bit + match_bit + sym;
+                         sym <<= 1;
+                         if (elf_lzma_bit (compressed, compressed_size,
+                                           lit_probs + idx, poffset,
+                                           &range, &code))
+                           {
+                             ++sym;
+                             bit &= match_bit;
+                           }
+                         else
+                           {
+                             bit &= ~ match_bit;
+                           }
+                       }
+                     while (sym < 0x100);
+                   }
+
+                 if (unlikely (uncompressed_offset >= uncompressed_size))
+                   {
+                     elf_uncompress_failed ();
+                     return 0;
+                   }
+
+                 uncompressed[uncompressed_offset] = (unsigned char) sym;
+                 ++uncompressed_offset;
+                 if (lstate <= 3)
+                   lstate = 0;
+                 else if (lstate <= 9)
+                   lstate -= 3;
+                 else
+                   lstate -= 6;
+               }
+           }
+
+         elf_lzma_range_normalize (compressed, compressed_size, poffset,
+                                   &range, &code);
+
+         off = *poffset;
+       }
+    }
+
+  /* We have reached the end of the block.  Pad to four byte
+     boundary.  */
+  off = (off + 3) &~ (size_t) 3;
+  if (unlikely (off > compressed_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  switch (check)
+    {
+    case 0:
+      /* No check.  */
+      break;
+
+    case 1:
+      /* CRC32 */
+      if (unlikely (off + 4 > compressed_size))
+       {
+         elf_uncompress_failed ();
+         return 0;
+       }
+      computed_crc = elf_crc32 (0, uncompressed, uncompressed_offset);
+      stream_crc = (compressed[off]
+                   | (compressed[off + 1] << 8)
+                   | (compressed[off + 2] << 16)
+                   | (compressed[off + 3] << 24));
+      if (computed_crc != stream_crc)
+       {
+         elf_uncompress_failed ();
+         return 0;
+       }
+      off += 4;
+      break;
+
+    case 4:
+      /* CRC64.  We don't bother computing a CRC64 checksum.  */
+      if (unlikely (off + 8 > compressed_size))
+       {
+         elf_uncompress_failed ();
+         return 0;
+       }
+      off += 8;
+      break;
+
+    case 10:
+      /* SHA.  We don't bother computing a SHA checksum.  */
+      if (unlikely (off + 32 > compressed_size))
+       {
+         elf_uncompress_failed ();
+         return 0;
+       }
+      off += 32;
+      break;
+
+    default:
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  *poffset = off;
+
+  return 1;
+}
+
+/* Uncompress LZMA data found in a minidebug file.  The minidebug
+   format is described at
+   https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html.
+   Returns 0 on error, 1 on successful decompression.  For this
+   function we return 0 on failure to decompress, as the calling code
+   will carry on in that case.  */
+
+static int
+elf_uncompress_lzma (struct backtrace_state *state,
+                    const unsigned char *compressed, size_t compressed_size,
+                    backtrace_error_callback error_callback, void *data,
+                    unsigned char **uncompressed, size_t *uncompressed_size)
+{
+  size_t header_size;
+  size_t footer_size;
+  unsigned char check;
+  uint32_t computed_crc;
+  uint32_t stream_crc;
+  size_t offset;
+  size_t index_size;
+  size_t footer_offset;
+  size_t index_offset;
+  uint64_t index_compressed_size;
+  uint64_t index_uncompressed_size;
+  unsigned char *mem;
+  uint16_t *probs;
+  size_t compressed_block_size;
+
+  /* The format starts with a stream header and ends with a stream
+     footer.  */
+  header_size = 12;
+  footer_size = 12;
+  if (unlikely (compressed_size < header_size + footer_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* The stream header starts with a magic string.  */
+  if (unlikely (memcmp (compressed, "\375" "7zXZ\0", 6) != 0))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* Next come stream flags.  The first byte is zero, the second byte
+     is the check.  */
+  if (unlikely (compressed[6] != 0))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  check = compressed[7];
+  if (unlikely ((check & 0xf8) != 0))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* Next comes a CRC of the stream flags.  */
+  computed_crc = elf_crc32 (0, compressed + 6, 2);
+  stream_crc = (compressed[8]
+               | (compressed[9] << 8)
+               | (compressed[10] << 16)
+               | (compressed[11] << 24));
+  if (unlikely (computed_crc != stream_crc))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* Now that we've parsed the header, parse the footer, so that we
+     can get the uncompressed size.  */
+
+  /* The footer ends with two magic bytes.  */
+
+  offset = compressed_size;
+  if (unlikely (memcmp (compressed + offset - 2, "YZ", 2) != 0))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  offset -= 2;
+
+  /* Before that are the stream flags, which should be the same as the
+     flags in the header.  */
+  if (unlikely (compressed[offset - 2] != 0
+               || compressed[offset - 1] != check))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  offset -= 2;
+
+  /* Before that is the size of the index field, which precedes the
+     footer.  */
+  index_size = (compressed[offset - 4]
+               | (compressed[offset - 3] << 8)
+               | (compressed[offset - 2] << 16)
+               | (compressed[offset - 1] << 24));
+  index_size = (index_size + 1) * 4;
+  offset -= 4;
+
+  /* Before that is a footer CRC.  */
+  computed_crc = elf_crc32 (0, compressed + offset, 6);
+  stream_crc = (compressed[offset - 4]
+               | (compressed[offset - 3] << 8)
+               | (compressed[offset - 2] << 16)
+               | (compressed[offset - 1] << 24));
+  if (unlikely (computed_crc != stream_crc))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  offset -= 4;
+
+  /* The index comes just before the footer.  */
+  if (unlikely (offset < index_size + header_size))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  footer_offset = offset;
+  offset -= index_size;
+  index_offset = offset;
+
+  /* The index starts with a zero byte.  */
+  if (unlikely (compressed[offset] != 0))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  ++offset;
+
+  /* Next is the number of blocks.  We expect zero blocks for an empty
+     stream, and otherwise a single block.  */
+  if (unlikely (compressed[offset] == 0))
+    {
+      *uncompressed = NULL;
+      *uncompressed_size = 0;
+      return 1;
+    }
+  if (unlikely (compressed[offset] != 1))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  ++offset;
+
+  /* Next is the compressed size and the uncompressed size.  */
+  if (!elf_lzma_varint (compressed, compressed_size, &offset,
+                       &index_compressed_size))
+    return 0;
+  if (!elf_lzma_varint (compressed, compressed_size, &offset,
+                       &index_uncompressed_size))
+    return 0;
+
+  /* Pad to a four byte boundary.  */
+  offset = (offset + 3) &~ (size_t) 3;
+
+  /* Next is a CRC of the index.  */
+  computed_crc = elf_crc32 (0, compressed + index_offset,
+                           offset - index_offset);
+  stream_crc = (compressed[offset]
+               | (compressed[offset + 1] << 8)
+               | (compressed[offset + 2] << 16)
+               | (compressed[offset + 3] << 24));
+  if (unlikely (computed_crc != stream_crc))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+  offset += 4;
+
+  /* We should now be back at the footer.  */
+  if (unlikely (offset != footer_offset))
+    {
+      elf_uncompress_failed ();
+      return 0;
+    }
+
+  /* Allocate space to hold the uncompressed data.  If we succeed in
+     uncompressing the LZMA data, we never free this memory.  */
+  mem = (unsigned char *) backtrace_alloc (state, index_uncompressed_size,
+                                          error_callback, data);
+  if (unlikely (mem == NULL))
+    return 0;
+  *uncompressed = mem;
+  *uncompressed_size = index_uncompressed_size;
+
+  /* Allocate space for probabilities.  */
+  probs = ((uint16_t *)
+          backtrace_alloc (state,
+                           LZMA_PROB_TOTAL_COUNT * sizeof (uint16_t),
+                           error_callback, data));
+  if (unlikely (probs == NULL))
+    {
+      backtrace_free (state, mem, index_uncompressed_size, error_callback,
+                     data);
+      return 0;
+    }
+
+  /* Uncompress the block, which follows the header.  */
+  offset = 12;
+  if (!elf_uncompress_lzma_block (compressed, compressed_size, check, probs,
+                                 mem, index_uncompressed_size, &offset))
+    {
+      backtrace_free (state, mem, index_uncompressed_size, error_callback,
+                     data);
+      return 0;
+    }
+
+  compressed_block_size = offset - 12;
+  if (unlikely (compressed_block_size
+               != ((index_compressed_size + 3) &~ (size_t) 3)))
+    {
+      elf_uncompress_failed ();
+      backtrace_free (state, mem, index_uncompressed_size, error_callback,
+                     data);
+      return 0;
+    }
+
+  offset = (offset + 3) &~ (size_t) 3;
+  if (unlikely (offset != index_offset))
+    {
+      elf_uncompress_failed ();
+      backtrace_free (state, mem, index_uncompressed_size, error_callback,
+                     data);
+      return 0;
+    }
+
+  return 1;
+}
+
+/* This function is a hook for testing the LZMA support.  It is only
+   used by tests.  */
+
+int
+backtrace_uncompress_lzma (struct backtrace_state *state,
+                          const unsigned char *compressed,
+                          size_t compressed_size,
+                          backtrace_error_callback error_callback,
+                          void *data, unsigned char **uncompressed,
+                          size_t *uncompressed_size)
+{
+  return elf_uncompress_lzma (state, compressed, compressed_size,
+                             error_callback, data, uncompressed,
+                             uncompressed_size);
+}
+
 /* Add the backtrace data for one ELF file.  Returns 1 on success,
    0 on failure (in both cases descriptor is closed) or -1 if exe
    is non-zero and the ELF file is ET_DYN, which tells the caller that
@@ -2616,23 +3968,24 @@ backtrace_uncompress_zdebug (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,
         struct dwarf_data **fileline_entry, int exe, int debuginfo,
         const char *with_buildid_data, uint32_t with_buildid_size)
 {
-  struct backtrace_view ehdr_view;
+  struct elf_view ehdr_view;
   b_elf_ehdr ehdr;
   off_t shoff;
   unsigned int shnum;
   unsigned int shstrndx;
-  struct backtrace_view shdrs_view;
+  struct elf_view shdrs_view;
   int shdrs_view_valid;
   const b_elf_shdr *shdrs;
   const b_elf_shdr *shstrhdr;
   size_t shstr_size;
   off_t shstr_off;
-  struct backtrace_view names_view;
+  struct elf_view names_view;
   int names_view_valid;
   const char *names;
   unsigned int symtab_shndx;
@@ -2640,31 +3993,36 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   unsigned int i;
   struct debug_section_info sections[DEBUG_MAX];
   struct debug_section_info zsections[DEBUG_MAX];
-  struct backtrace_view symtab_view;
+  struct elf_view symtab_view;
   int symtab_view_valid;
-  struct backtrace_view strtab_view;
+  struct elf_view strtab_view;
   int strtab_view_valid;
-  struct backtrace_view buildid_view;
+  struct elf_view buildid_view;
   int buildid_view_valid;
   const char *buildid_data;
   uint32_t buildid_size;
-  struct backtrace_view debuglink_view;
+  struct elf_view debuglink_view;
   int debuglink_view_valid;
   const char *debuglink_name;
   uint32_t debuglink_crc;
-  struct backtrace_view debugaltlink_view;
+  struct elf_view debugaltlink_view;
   int debugaltlink_view_valid;
   const char *debugaltlink_name;
   const char *debugaltlink_buildid_data;
   uint32_t debugaltlink_buildid_size;
+  struct elf_view gnu_debugdata_view;
+  int gnu_debugdata_view_valid;
+  size_t gnu_debugdata_size;
+  unsigned char *gnu_debugdata_uncompressed;
+  size_t gnu_debugdata_uncompressed_size;
   off_t min_offset;
   off_t max_offset;
   off_t debug_size;
-  struct backtrace_view debug_view;
+  struct elf_view debug_view;
   int debug_view_valid;
   unsigned int using_debug_view;
   uint16_t *zdebug_table;
-  struct backtrace_view split_debug_view[DEBUG_MAX];
+  struct elf_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;
@@ -2689,17 +4047,19 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   debugaltlink_name = NULL;
   debugaltlink_buildid_data = NULL;
   debugaltlink_buildid_size = 0;
+  gnu_debugdata_view_valid = 0;
+  gnu_debugdata_size = 0;
   debug_view_valid = 0;
   memset (&split_debug_view_valid[0], 0, sizeof split_debug_view_valid);
   opd = NULL;
 
-  if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
-                          data, &ehdr_view))
+  if (!elf_get_view (state, descriptor, memory, memory_size, 0, sizeof ehdr,
+                    error_callback, data, &ehdr_view))
     goto fail;
 
-  memcpy (&ehdr, ehdr_view.data, sizeof ehdr);
+  memcpy (&ehdr, ehdr_view.view.data, sizeof ehdr);
 
-  backtrace_release_view (state, &ehdr_view, error_callback, data);
+  elf_release_view (state, &ehdr_view, error_callback, data);
 
   if (ehdr.e_ident[EI_MAG0] != ELFMAG0
       || ehdr.e_ident[EI_MAG1] != ELFMAG1
@@ -2747,14 +4107,14 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   if ((shnum == 0 || shstrndx == SHN_XINDEX)
       && shoff != 0)
     {
-      struct backtrace_view shdr_view;
+      struct elf_view shdr_view;
       const b_elf_shdr *shdr;
 
-      if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr,
-                              error_callback, data, &shdr_view))
+      if (!elf_get_view (state, descriptor, memory, memory_size, shoff,
+                        sizeof shdr, error_callback, data, &shdr_view))
        goto fail;
 
-      shdr = (const b_elf_shdr *) shdr_view.data;
+      shdr = (const b_elf_shdr *) shdr_view.view.data;
 
       if (shnum == 0)
        shnum = shdr->sh_size;
@@ -2778,7 +4138,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
            shstrndx -= 0x100;
        }
 
-      backtrace_release_view (state, &shdr_view, error_callback, data);
+      elf_release_view (state, &shdr_view, error_callback, data);
     }
 
   if (shnum == 0 || shstrndx == 0)
@@ -2789,12 +4149,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
   /* Read the section headers, skipping the first one.  */
 
-  if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr),
-                          (shnum - 1) * sizeof (b_elf_shdr),
-                          error_callback, data, &shdrs_view))
+  if (!elf_get_view (state, descriptor, memory, memory_size,
+                    shoff + sizeof (b_elf_shdr),
+                    (shnum - 1) * sizeof (b_elf_shdr),
+                    error_callback, data, &shdrs_view))
     goto fail;
   shdrs_view_valid = 1;
-  shdrs = (const b_elf_shdr *) shdrs_view.data;
+  shdrs = (const b_elf_shdr *) shdrs_view.view.data;
 
   /* Read the section names.  */
 
@@ -2802,11 +4163,11 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   shstr_size = shstrhdr->sh_size;
   shstr_off = shstrhdr->sh_offset;
 
-  if (!backtrace_get_view (state, descriptor, shstr_off, shstrhdr->sh_size,
-                          error_callback, data, &names_view))
+  if (!elf_get_view (state, descriptor, memory, memory_size, shstr_off,
+                    shstrhdr->sh_size, error_callback, data, &names_view))
     goto fail;
   names_view_valid = 1;
-  names = (const char *) names_view.data;
+  names = (const char *) names_view.view.data;
 
   symtab_shndx = 0;
   dynsym_shndx = 0;
@@ -2871,13 +4232,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
        {
          const b_elf_note *note;
 
-         if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
-                                  shdr->sh_size, error_callback, data,
-                                  &buildid_view))
+         if (!elf_get_view (state, descriptor, memory, memory_size,
+                            shdr->sh_offset, shdr->sh_size, error_callback,
+                            data, &buildid_view))
            goto fail;
 
          buildid_view_valid = 1;
-         note = (const b_elf_note *) buildid_view.data;
+         note = (const b_elf_note *) buildid_view.view.data;
          if (note->type == NT_GNU_BUILD_ID
              && note->namesz == 4
              && strncmp (note->name, "GNU", 4) == 0
@@ -2905,13 +4266,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
          const char *debuglink_data;
          size_t crc_offset;
 
-         if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
-                                  shdr->sh_size, error_callback, data,
-                                  &debuglink_view))
+         if (!elf_get_view (state, descriptor, memory, memory_size,
+                            shdr->sh_offset, shdr->sh_size, error_callback,
+                            data, &debuglink_view))
            goto fail;
 
          debuglink_view_valid = 1;
-         debuglink_data = (const char *) debuglink_view.data;
+         debuglink_data = (const char *) debuglink_view.view.data;
          crc_offset = strnlen (debuglink_data, shdr->sh_size);
          crc_offset = (crc_offset + 3) & ~3;
          if (crc_offset + 4 <= shdr->sh_size)
@@ -2927,13 +4288,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
          const char *debugaltlink_data;
          size_t debugaltlink_name_len;
 
-         if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
-                                  shdr->sh_size, error_callback, data,
-                                  &debugaltlink_view))
+         if (!elf_get_view (state, descriptor, memory, memory_size,
+                            shdr->sh_offset, shdr->sh_size, error_callback,
+                            data, &debugaltlink_view))
            goto fail;
 
          debugaltlink_view_valid = 1;
-         debugaltlink_data = (const char *) debugaltlink_view.data;
+         debugaltlink_data = (const char *) debugaltlink_view.view.data;
          debugaltlink_name = debugaltlink_data;
          debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size);
          if (debugaltlink_name_len < shdr->sh_size)
@@ -2947,20 +4308,32 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
            }
        }
 
+      if (!gnu_debugdata_view_valid
+         && strcmp (name, ".gnu_debugdata") == 0)
+       {
+         if (!elf_get_view (state, descriptor, memory, memory_size,
+                            shdr->sh_offset, shdr->sh_size, error_callback,
+                            data, &gnu_debugdata_view))
+           goto fail;
+
+         gnu_debugdata_size = shdr->sh_size;
+         gnu_debugdata_view_valid = 1;
+       }
+
       /* Read the .opd section on PowerPC64 ELFv1.  */
       if (ehdr.e_machine == EM_PPC64
          && (ehdr.e_flags & EF_PPC64_ABI) < 2
          && shdr->sh_type == SHT_PROGBITS
          && strcmp (name, ".opd") == 0)
        {
-         if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
-                                  shdr->sh_size, error_callback, data,
-                                  &opd_data.view))
+         if (!elf_get_view (state, descriptor, memory, memory_size,
+                            shdr->sh_offset, shdr->sh_size, error_callback,
+                            data, &opd_data.view))
            goto fail;
 
          opd = &opd_data;
          opd->addr = shdr->sh_addr;
-         opd->data = (const char *) opd_data.view.data;
+         opd->data = (const char *) opd_data.view.view.data;
          opd->size = shdr->sh_size;
        }
     }
@@ -2984,15 +4357,15 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
        }
       strtab_shdr = &shdrs[strtab_shndx - 1];
 
-      if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset,
-                              symtab_shdr->sh_size, error_callback, data,
-                              &symtab_view))
+      if (!elf_get_view (state, descriptor, memory, memory_size,
+                        symtab_shdr->sh_offset, symtab_shdr->sh_size,
+                        error_callback, data, &symtab_view))
        goto fail;
       symtab_view_valid = 1;
 
-      if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset,
-                              strtab_shdr->sh_size, error_callback, data,
-                              &strtab_view))
+      if (!elf_get_view (state, descriptor, memory, memory_size,
+                        strtab_shdr->sh_offset, strtab_shdr->sh_size,
+                        error_callback, data, &strtab_view))
        goto fail;
       strtab_view_valid = 1;
 
@@ -3002,8 +4375,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
        goto fail;
 
       if (!elf_initialize_syminfo (state, base_address,
-                                  symtab_view.data, symtab_shdr->sh_size,
-                                  strtab_view.data, strtab_shdr->sh_size,
+                                  symtab_view.view.data, symtab_shdr->sh_size,
+                                  strtab_view.view.data, strtab_shdr->sh_size,
                                   error_callback, data, sdata, opd))
        {
          backtrace_free (state, sdata, sizeof *sdata, error_callback, data);
@@ -3012,7 +4385,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
       /* We no longer need the symbol table, but we hold on to the
         string table permanently.  */
-      backtrace_release_view (state, &symtab_view, error_callback, data);
+      elf_release_view (state, &symtab_view, error_callback, data);
       symtab_view_valid = 0;
       strtab_view_valid = 0;
 
@@ -3021,9 +4394,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
       elf_add_syminfo_data (state, sdata);
     }
 
-  backtrace_release_view (state, &shdrs_view, error_callback, data);
+  elf_release_view (state, &shdrs_view, error_callback, data);
   shdrs_view_valid = 0;
-  backtrace_release_view (state, &names_view, error_callback, data);
+  elf_release_view (state, &names_view, error_callback, data);
   names_view_valid = 0;
 
   /* If the debug info is in a separate file, read that one instead.  */
@@ -3038,19 +4411,17 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
        {
          int ret;
 
-         backtrace_release_view (state, &buildid_view, error_callback, data);
+         elf_release_view (state, &buildid_view, error_callback, data);
          if (debuglink_view_valid)
-           backtrace_release_view (state, &debuglink_view, error_callback,
-                                   data);
+           elf_release_view (state, &debuglink_view, error_callback, data);
          if (debugaltlink_view_valid)
-           backtrace_release_view (state, &debugaltlink_view, error_callback,
-                                   data);
-         ret = elf_add (state, "", d, base_address, error_callback, data,
-                        fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
-                        0);
+           elf_release_view (state, &debugaltlink_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);
          if (ret < 0)
            backtrace_close (d, error_callback, data);
-         else
+         else if (descriptor >= 0)
            backtrace_close (descriptor, error_callback, data);
          return ret;
        }
@@ -3058,13 +4429,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
   if (buildid_view_valid)
     {
-      backtrace_release_view (state, &buildid_view, error_callback, data);
+      elf_release_view (state, &buildid_view, error_callback, data);
       buildid_view_valid = 0;
     }
 
   if (opd)
     {
-      backtrace_release_view (state, &opd->view, error_callback, data);
+      elf_release_view (state, &opd->view, error_callback, data);
       opd = NULL;
     }
 
@@ -3079,17 +4450,15 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
        {
          int ret;
 
-         backtrace_release_view (state, &debuglink_view, error_callback,
-                                 data);
+         elf_release_view (state, &debuglink_view, error_callback, data);
          if (debugaltlink_view_valid)
-           backtrace_release_view (state, &debugaltlink_view, error_callback,
-                                   data);
-         ret = elf_add (state, "", d, base_address, error_callback, data,
-                        fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
-                        0);
+           elf_release_view (state, &debugaltlink_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);
          if (ret < 0)
            backtrace_close (d, error_callback, data);
-         else
+         else if (descriptor >= 0)
            backtrace_close(descriptor, error_callback, data);
          return ret;
        }
@@ -3097,7 +4466,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
   if (debuglink_view_valid)
     {
-      backtrace_release_view (state, &debuglink_view, error_callback, data);
+      elf_release_view (state, &debuglink_view, error_callback, data);
       debuglink_view_valid = 0;
     }
 
@@ -3112,12 +4481,11 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
        {
          int ret;
 
-         ret = elf_add (state, filename, d, base_address, error_callback, data,
-                        fileline_fn, found_sym, found_dwarf, &fileline_altlink,
-                        0, 1, debugaltlink_buildid_data,
-                        debugaltlink_buildid_size);
-         backtrace_release_view (state, &debugaltlink_view, error_callback,
-                                 data);
+         ret = elf_add (state, filename, d, NULL, 0, base_address,
+                        error_callback, data, fileline_fn, found_sym,
+                        found_dwarf, &fileline_altlink, 0, 1,
+                        debugaltlink_buildid_data, debugaltlink_buildid_size);
+         elf_release_view (state, &debugaltlink_view, error_callback, data);
          debugaltlink_view_valid = 0;
          if (ret < 0)
            {
@@ -3129,10 +4497,36 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
   if (debugaltlink_view_valid)
     {
-      backtrace_release_view (state, &debugaltlink_view, error_callback, data);
+      elf_release_view (state, &debugaltlink_view, error_callback, data);
       debugaltlink_view_valid = 0;
     }
 
+  if (gnu_debugdata_view_valid)
+    {
+      int ret;
+
+      ret = elf_uncompress_lzma (state,
+                                ((const unsigned char *)
+                                 gnu_debugdata_view.view.data),
+                                gnu_debugdata_size, error_callback, data,
+                                &gnu_debugdata_uncompressed,
+                                &gnu_debugdata_uncompressed_size);
+
+      elf_release_view (state, &gnu_debugdata_view, error_callback, data);
+      gnu_debugdata_view_valid = 0;
+
+      if (ret)
+       {
+         ret = elf_add (state, filename, -1, gnu_debugdata_uncompressed,
+                        gnu_debugdata_uncompressed_size, base_address,
+                        error_callback, data, fileline_fn, found_sym,
+                        found_dwarf, NULL, 0, 0, NULL, 0);
+         if (ret >= 0 && descriptor >= 0)
+           backtrace_close(descriptor, error_callback, data);
+         return ret;
+       }
+    }
+
   /* Read all the debug sections in a single view, since they are
      probably adjacent in the file.  If any of sections are
      uncompressed, we never release this view.  */
@@ -3165,8 +4559,11 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
     }
   if (min_offset == 0 || max_offset == 0)
     {
-      if (!backtrace_close (descriptor, error_callback, data))
-       goto fail;
+      if (descriptor >= 0)
+       {
+         if (!backtrace_close (descriptor, error_callback, data))
+           goto fail;
+       }
       return 1;
     }
 
@@ -3176,9 +4573,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   if (max_offset - min_offset < 0x20000000
       || max_offset - min_offset < debug_size + 0x10000)
     {
-      if (!backtrace_get_view (state, descriptor, min_offset,
-                              max_offset - min_offset,
-                              error_callback, data, &debug_view))
+      if (!elf_get_view (state, descriptor, memory, memory_size, min_offset,
+                        max_offset - min_offset, error_callback, data,
+                        &debug_view))
        goto fail;
       debug_view_valid = 1;
     }
@@ -3196,24 +4593,28 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
          else
            continue;
 
-         if (!backtrace_get_view (state, descriptor, dsec->offset, dsec->size,
-                                  error_callback, data, &split_debug_view[i]))
+         if (!elf_get_view (state, descriptor, memory, memory_size,
+                            dsec->offset, dsec->size, error_callback, data,
+                            &split_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);
+                               split_debug_view[i].view.data);
          else
            zsections[i].data = ((const unsigned char *)
-                                split_debug_view[i].data);
+                                split_debug_view[i].view.data);
        }
     }
 
   /* We've read all we need from the executable.  */
-  if (!backtrace_close (descriptor, error_callback, data))
-    goto fail;
-  descriptor = -1;
+  if (descriptor >= 0)
+    {
+      if (!backtrace_close (descriptor, error_callback, data))
+       goto fail;
+      descriptor = -1;
+    }
 
   using_debug_view = 0;
   if (debug_view_valid)
@@ -3224,7 +4625,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
            sections[i].data = NULL;
          else
            {
-             sections[i].data = ((const unsigned char *) debug_view.data
+             sections[i].data = ((const unsigned char *) debug_view.view.data
                                  + (sections[i].offset - min_offset));
              ++using_debug_view;
            }
@@ -3232,7 +4633,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
          if (zsections[i].size == 0)
            zsections[i].data = NULL;
          else
-           zsections[i].data = ((const unsigned char *) debug_view.data
+           zsections[i].data = ((const unsigned char *) debug_view.view.data
                                 + (zsections[i].offset - min_offset));
        }
     }
@@ -3269,8 +4670,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
          if (split_debug_view_valid[i])
            {
-             backtrace_release_view (state, &split_debug_view[i],
-                                     error_callback, data);
+             elf_release_view (state, &split_debug_view[i],
+                               error_callback, data);
              split_debug_view_valid[i] = 0;
            }
        }
@@ -3309,8 +4710,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
        --using_debug_view;
       else if (split_debug_view_valid[i])
        {
-         backtrace_release_view (state, &split_debug_view[i],
-                                 error_callback, data);
+         elf_release_view (state, &split_debug_view[i], error_callback, data);
          split_debug_view_valid[i] = 0;
        }
     }
@@ -3321,7 +4721,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
   if (debug_view_valid && using_debug_view == 0)
     {
-      backtrace_release_view (state, &debug_view, error_callback, data);
+      elf_release_view (state, &debug_view, error_callback, data);
       debug_view_valid = 0;
     }
 
@@ -3344,30 +4744,31 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 
  fail:
   if (shdrs_view_valid)
-    backtrace_release_view (state, &shdrs_view, error_callback, data);
+    elf_release_view (state, &shdrs_view, error_callback, data);
   if (names_view_valid)
-    backtrace_release_view (state, &names_view, error_callback, data);
+    elf_release_view (state, &names_view, error_callback, data);
   if (symtab_view_valid)
-    backtrace_release_view (state, &symtab_view, error_callback, data);
+    elf_release_view (state, &symtab_view, error_callback, data);
   if (strtab_view_valid)
-    backtrace_release_view (state, &strtab_view, error_callback, data);
+    elf_release_view (state, &strtab_view, error_callback, data);
   if (debuglink_view_valid)
-    backtrace_release_view (state, &debuglink_view, error_callback, data);
+    elf_release_view (state, &debuglink_view, error_callback, data);
   if (debugaltlink_view_valid)
-    backtrace_release_view (state, &debugaltlink_view, error_callback, data);
+    elf_release_view (state, &debugaltlink_view, error_callback, data);
+  if (gnu_debugdata_view_valid)
+    elf_release_view (state, &gnu_debugdata_view, error_callback, data);
   if (buildid_view_valid)
-    backtrace_release_view (state, &buildid_view, error_callback, data);
+    elf_release_view (state, &buildid_view, error_callback, data);
   if (debug_view_valid)
-    backtrace_release_view (state, &debug_view, error_callback, data);
+    elf_release_view (state, &debug_view, error_callback, data);
   for (i = 0; i < (int) DEBUG_MAX; ++i)
     {
       if (split_debug_view_valid[i])
-       backtrace_release_view (state, &split_debug_view[i],
-                               error_callback, data);
+       elf_release_view (state, &split_debug_view[i], error_callback, data);
     }
   if (opd)
-    backtrace_release_view (state, &opd->view, error_callback, data);
-  if (descriptor != -1)
+    elf_release_view (state, &opd->view, error_callback, data);
+  if (descriptor >= 0)
     backtrace_close (descriptor, error_callback, data);
   return 0;
 }
@@ -3429,7 +4830,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
        return 0;
     }
 
-  if (elf_add (pd->state, filename, descriptor, info->dlpi_addr,
+  if (elf_add (pd->state, filename, descriptor, NULL, 0, info->dlpi_addr,
               pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
               &found_dwarf, NULL, 0, 0, NULL, 0))
     {
@@ -3458,7 +4859,7 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
   fileline elf_fileline_fn = elf_nodebug;
   struct phdr_data pd;
 
-  ret = elf_add (state, filename, descriptor, 0, error_callback, data,
+  ret = elf_add (state, filename, descriptor, NULL, 0, 0, error_callback, data,
                 &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL,
                 0);
   if (!ret)
index be99bb0c84c6f0ee67015b2215707e40eba32e80..098623374560458475c57efe00799ebdf0d85508 100644 (file)
@@ -335,4 +335,13 @@ extern int backtrace_uncompress_zdebug (struct backtrace_state *,
                                        unsigned char **uncompressed,
                                        size_t *uncompressed_size);
 
+/* A test-only hook for elf_uncompress_lzma.  */
+
+extern int backtrace_uncompress_lzma (struct backtrace_state *,
+                                     const unsigned char *compressed,
+                                     size_t compressed_size,
+                                     backtrace_error_callback, void *data,
+                                     unsigned char **uncompressed,
+                                     size_t *uncompressed_size);
+
 #endif
diff --git a/libbacktrace/mtest.c b/libbacktrace/mtest.c
new file mode 100644 (file)
index 0000000..d90fd1e
--- /dev/null
@@ -0,0 +1,401 @@
+/* mtest.c -- Minidebug test for libbacktrace library
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+/* This program tests using libbacktrace with a program that uses the
+   minidebuginfo format in a .gnu_debugdata section.  See
+   https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html
+   for a bit more information about minidebuginfo.  What is relevant
+   for libbacktrace is that we have just a symbol table, with no debug
+   info, so we should be able to do a function backtrace, but we can't
+   do a file/line backtrace.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+
+#include "testlib.h"
+
+static int test1 (void) __attribute__ ((noinline, noclone, unused));
+static int f2 (int) __attribute__ ((noinline, noclone));
+static int f3 (int, int) __attribute__ ((noinline, noclone));
+
+/* Collected PC values.  */
+
+static uintptr_t addrs[20];
+
+/* The backtrace callback function.  This is like callback_one in
+   testlib.c, but it saves the PC also.  */
+
+static int
+callback_mtest (void *vdata, uintptr_t pc, const char *filename, int lineno,
+               const char *function)
+{
+  struct bdata *data = (struct bdata *) vdata;
+
+  if (data->index >= sizeof addrs / sizeof addrs[0])
+    {
+      fprintf (stderr, "callback_mtest: callback called too many times\n");
+      data->failed = 1;
+      return 1;
+    }
+
+  addrs[data->index] = pc;
+
+  return callback_one (vdata, pc, filename, lineno, function);
+}
+
+/* Test the backtrace function with non-inlined functions.  (We don't
+   test with inlined functions because they won't work with minidebug
+   anyhow.)  */
+
+static int
+test1 (void)
+{
+  /* Returning a value here and elsewhere avoids a tailcall which
+     would mess up the backtrace.  */
+  return f2 (__LINE__) + 1;
+}
+
+static int
+f2 (int f1line)
+{
+  return f3 (f1line, __LINE__) + 2;
+}
+
+static int
+f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
+{
+  struct info all[20];
+  struct bdata data;
+  int i;
+  size_t j;
+
+  data.all = &all[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  i = backtrace_full (state, 0, callback_mtest, error_callback_one, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test1: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  if (data.index < 3)
+    {
+      fprintf (stderr,
+              "test1: not enough frames; got %zu, expected at least 3\n",
+              data.index);
+      data.failed = 1;
+    }
+
+  /* When using minidebug we don't expect the function name here.  */
+
+  for (j = 0; j < 3 && j < data.index; j++)
+    {
+      if (all[j].function == NULL)
+       {
+         struct symdata symdata;
+
+         symdata.name = NULL;
+         symdata.val = 0;
+         symdata.size = 0;
+         symdata.failed = 0;
+
+         i = backtrace_syminfo (state, addrs[j], callback_three,
+                                error_callback_three, &symdata);
+         if (i == 0)
+           {
+             fprintf (stderr,
+                      ("test1: [%zu], unexpected return value from "
+                       "backtrace_syminfo %d\n"),
+                      j, i);
+             data.failed = 1;
+           }
+         else if (symdata.name == NULL)
+           {
+             fprintf (stderr, "test1: [%zu]: syminfo did not find name\n", j);
+             data.failed = 1;
+           }
+         else
+           all[j].function = strdup (symdata.name);
+       }
+    }
+
+  if (all[0].function == NULL)
+    {
+      fprintf (stderr, "test1: [0]: missing function name\n");
+      data.failed = 1;
+    }
+  else if (strcmp (all[0].function, "f3") != 0)
+    {
+      fprintf (stderr, "test1: [0]: got %s expected %s\n",
+              all[0].function, "f3");
+      data.failed = 1;
+    }
+
+  if (all[1].function == NULL)
+    {
+      fprintf (stderr, "test1: [1]: missing function name\n");
+      data.failed = 1;
+    }
+  else if (strcmp (all[1].function, "f2") != 0)
+    {
+      fprintf (stderr, "test1: [1]: got %s expected %s\n",
+              all[0].function, "f2");
+      data.failed = 1;
+    }
+
+  if (all[2].function == NULL)
+    {
+      fprintf (stderr, "test1: [2]: missing function name\n");
+      data.failed = 1;
+    }
+  else if (strcmp (all[2].function, "test1") != 0)
+    {
+      fprintf (stderr, "test1: [2]: got %s expected %s\n",
+              all[0].function, "test1");
+      data.failed = 1;
+    }
+
+  printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+/* Test the backtrace_simple function with non-inlined functions.  */
+
+static int test3 (void) __attribute__ ((noinline, noclone, unused));
+static int f22 (int) __attribute__ ((noinline, noclone));
+static int f23 (int, int) __attribute__ ((noinline, noclone));
+
+static int
+test3 (void)
+{
+  return f22 (__LINE__) + 1;
+}
+
+static int
+f22 (int f1line)
+{
+  return f23 (f1line, __LINE__) + 2;
+}
+
+static int
+f23 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
+{
+  uintptr_t addrs[20];
+  struct sdata data;
+  int i;
+
+  data.addrs = &addrs[0];
+  data.index = 0;
+  data.max = 20;
+  data.failed = 0;
+
+  i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
+
+  if (i != 0)
+    {
+      fprintf (stderr, "test3: unexpected return value %d\n", i);
+      data.failed = 1;
+    }
+
+  if (!data.failed)
+    {
+      int j;
+
+      for (j = 0; j < 3; ++j)
+       {
+         struct symdata symdata;
+
+         symdata.name = NULL;
+         symdata.val = 0;
+         symdata.size = 0;
+         symdata.failed = 0;
+
+         i = backtrace_syminfo (state, addrs[j], callback_three,
+                                error_callback_three, &symdata);
+         if (i == 0)
+           {
+             fprintf (stderr,
+                      ("test3: [%d]: unexpected return value "
+                       "from backtrace_syminfo %d\n"),
+                      j, i);
+             symdata.failed = 1;
+           }
+
+         if (!symdata.failed)
+           {
+             const char *expected;
+
+             switch (j)
+               {
+               case 0:
+                 expected = "f23";
+                 break;
+               case 1:
+                 expected = "f22";
+                 break;
+               case 2:
+                 expected = "test3";
+                 break;
+               default:
+                 assert (0);
+               }
+
+             if (symdata.name == NULL)
+               {
+                 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
+                 symdata.failed = 1;
+               }
+             /* Use strncmp, not strcmp, because GCC might create a
+                clone.  */
+             else if (strncmp (symdata.name, expected, strlen (expected))
+                      != 0)
+               {
+                 fprintf (stderr,
+                          ("test3: [%d]: unexpected syminfo name "
+                           "got %s expected %s\n"),
+                          j, symdata.name, expected);
+                 symdata.failed = 1;
+               }
+           }
+
+         if (symdata.failed)
+           data.failed = 1;
+       }
+    }
+
+  printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
+
+  if (data.failed)
+    ++failures;
+
+  return failures;
+}
+
+int test5 (void) __attribute__ ((unused));
+
+int global = 1;
+
+int
+test5 (void)
+{
+  struct symdata symdata;
+  int i;
+  uintptr_t addr = (uintptr_t) &global;
+
+  if (sizeof (global) > 1)
+    addr += 1;
+
+  symdata.name = NULL;
+  symdata.val = 0;
+  symdata.size = 0;
+  symdata.failed = 0;
+
+  i = backtrace_syminfo (state, addr, callback_three,
+                        error_callback_three, &symdata);
+  if (i == 0)
+    {
+      fprintf (stderr,
+              "test5: unexpected return value from backtrace_syminfo %d\n",
+              i);
+      symdata.failed = 1;
+    }
+
+  if (!symdata.failed)
+    {
+      if (symdata.name == NULL)
+       {
+         fprintf (stderr, "test5: NULL syminfo name\n");
+         symdata.failed = 1;
+       }
+      else if (!(strncmp (symdata.name, "global", 6) == 0
+                && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
+       {
+         fprintf (stderr,
+                  "test5: unexpected syminfo name got %s expected %s\n",
+                  symdata.name, "global");
+         symdata.failed = 1;
+       }
+      else if (symdata.val != (uintptr_t) &global)
+       {
+         fprintf (stderr,
+                  "test5: unexpected syminfo value got %lx expected %lx\n",
+                  (unsigned long) symdata.val,
+                  (unsigned long) (uintptr_t) &global);
+         symdata.failed = 1;
+       }
+      else if (symdata.size != sizeof (global))
+       {
+         fprintf (stderr,
+                  "test5: unexpected syminfo size got %lx expected %lx\n",
+                  (unsigned long) symdata.size,
+                  (unsigned long) sizeof (global));
+         symdata.failed = 1;
+       }
+    }
+
+  printf ("%s: backtrace_syminfo variable\n",
+         symdata.failed ? "FAIL" : "PASS");
+
+  if (symdata.failed)
+    ++failures;
+
+  return failures;
+}
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+                                 error_callback_create, NULL);
+
+#if BACKTRACE_SUPPORTED
+  test1 ();
+  test3 ();
+#if BACKTRACE_SUPPORTS_DATA
+  test5 ();
+#endif
+#endif
+
+  exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libbacktrace/xztest.c b/libbacktrace/xztest.c
new file mode 100644 (file)
index 0000000..4fffe99
--- /dev/null
@@ -0,0 +1,508 @@
+/* xztest.c -- Test for libbacktrace LZMA decoder.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_LIBLZMA
+#include <lzma.h>
+#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 LIBLZMA_CLOCK_GETTIME_ARG CLOCK_PROCESS_CPUTIME_ID
+#else
+#define LIBLZMA_CLOCK_GETTIME_ARG CLOCK_REALTIME
+#endif
+
+/* Some tests for the local lzma inflation code.  */
+
+struct lzma_test
+{
+  const char *name;
+  const char *uncompressed;
+  size_t uncompressed_len;
+  const char *compressed;
+  size_t compressed_len;
+};
+
+/* Error callback.  */
+
+static void
+error_callback_compress (void *vdata ATTRIBUTE_UNUSED, const char *msg,
+                        int errnum)
+{
+  fprintf (stderr, "%s", msg);
+  if (errnum > 0)
+    fprintf (stderr, ": %s", strerror (errnum));
+  fprintf (stderr, "\n");
+  exit (EXIT_FAILURE);
+}
+
+static const struct lzma_test tests[] =
+{
+  {
+    "empty",
+    "",
+    0,
+    ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x00\x00\x00\x00"
+     "\x1c\xdf\x44\x21\x1f\xb6\xf3\x7d\x01\x00\x00\x00\x00\x04\x59\x5a"),
+    32,
+  },
+  {
+    "hello",
+    "hello, world\n",
+    0,
+    ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21\x01"
+     "\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x0c\x68\x65\x6c\x6c\x6f"
+     "\x2c\x20\x77\x6f\x72\x6c\x64\x0a\x00\x00\x00\x00\x7b\x46\x5a\x81"
+     "\xc9\x12\xb8\xea\x00\x01\x25\x0d\x71\x19\xc4\xb6\x1f\xb6\xf3\x7d"
+     "\x01\x00\x00\x00\x00\x04\x59\x5a"),
+    72,
+  },
+  {
+    "goodbye",
+    "goodbye, world",
+    0,
+    ("\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21\x01"
+     "\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x0d\x67\x6f\x6f\x64\x62"
+     "\x79\x65\x2c\x20\x77\x6f\x72\x6c\x64\x00\x00\x00\xf6\xf8\xa3\x33"
+     "\x8c\x4e\xc9\x68\x00\x01\x26\x0e\x08\x1b\xe0\x04\x1f\xb6\xf3\x7d"
+     "\x01\x00\x00\x00\x00\x04\x59\x5a"),
+    72,
+  },
+};
+
+/* Test the hand coded samples.  */
+
+static void
+test_samples (struct backtrace_state *state)
+{
+  size_t i;
+
+  for (i = 0; i < sizeof tests / sizeof tests[0]; ++i)
+    {
+      unsigned char *uncompressed;
+      size_t uncompressed_len;
+
+      uncompressed = NULL;
+      uncompressed_len = 0;
+      if (!backtrace_uncompress_lzma (state,
+                                     ((const unsigned char *)
+                                      tests[i].compressed),
+                                     tests[i].compressed_len,
+                                     error_callback_compress, NULL,
+                                     &uncompressed, &uncompressed_len))
+       {
+         fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
+         ++failures;
+       }
+      else
+       {
+         size_t v;
+
+         v = tests[i].uncompressed_len;
+         if (v == 0)
+           v = strlen (tests[i].uncompressed);
+         if (uncompressed_len != v)
+           {
+             fprintf (stderr,
+                      "test %s: got uncompressed length %zu, want %zu\n",
+                      tests[i].name, uncompressed_len, v);
+             ++failures;
+           }
+         else if (memcmp (tests[i].uncompressed, uncompressed, v) != 0)
+           {
+             size_t j;
+
+             fprintf (stderr, "test %s: uncompressed data mismatch\n",
+                      tests[i].name);
+             for (j = 0; j < v; ++j)
+               if (tests[i].uncompressed[j] != uncompressed[j])
+                 fprintf (stderr, "  %zu: got %#x want %#x\n", j,
+                          uncompressed[j], tests[i].uncompressed[j]);
+             ++failures;
+           }
+         else
+           printf ("PASS: lzma %s\n", tests[i].name);
+
+         backtrace_free (state, uncompressed, uncompressed_len,
+                         error_callback_compress, NULL);
+       }
+    }
+}
+
+#if HAVE_LIBLZMA
+
+/* Given a set of TRIALS timings, discard the lowest and highest
+   values and return the mean average of the rest.  */
+
+static size_t
+average_time (const size_t *times, size_t trials)
+{
+  size_t imax;
+  size_t max;
+  size_t imin;
+  size_t min;
+  size_t i;
+  size_t sum;
+
+  imin = 0;
+  imax = 0;
+  min = times[0];
+  max = times[0];
+  for (i = 1; i < trials; ++i)
+    {
+      if (times[i] < min)
+       {
+         imin = i;
+         min = times[i];
+       }
+      if (times[i] > max)
+       {
+         imax = i;
+         max = times[i];
+       }
+    }
+
+  sum = 0;
+  for (i = 0; i < trials; ++i)
+    {
+      if (i != imax && i != imin)
+       sum += times[i];
+    }
+  return sum / (trials - 2);
+}
+
+#endif
+
+/* Test a larger text, if available.  */
+
+static void
+test_large (struct backtrace_state *state ATTRIBUTE_UNUSED)
+{
+#if HAVE_LIBLZMA
+  unsigned char *orig_buf;
+  size_t orig_bufsize;
+  size_t i;
+  lzma_stream initial_stream = LZMA_STREAM_INIT;
+  lzma_stream stream;
+  unsigned char *compressed_buf;
+  size_t compressed_bufsize;
+  unsigned char *uncompressed_buf;
+  size_t uncompressed_bufsize;
+  unsigned char *spare_buf;
+  int r;
+  clockid_t cid;
+  struct timespec ts1;
+  struct timespec ts2;
+  size_t ctime;
+  size_t ztime;
+  const size_t trials = 16;
+  size_t ctimes[16];
+  size_t ztimes[16];
+  static const char * const names[] = {
+    "Isaac.Newton-Opticks.txt",
+    "../libgo/go/testdata/Isaac.Newton-Opticks.txt",
+  };
+
+  orig_buf = NULL;
+  orig_bufsize = 0;
+  uncompressed_buf = NULL;
+  compressed_buf = NULL;
+
+  for (i = 0; i < sizeof names / sizeof names[0]; ++i)
+    {
+      size_t len;
+      char *namebuf;
+      FILE *e;
+      struct stat st;
+      char *rbuf;
+      size_t got;
+
+      len = strlen (SRCDIR) + strlen (names[i]) + 2;
+      namebuf = malloc (len);
+      if (namebuf == NULL)
+       {
+         perror ("malloc");
+         goto fail;
+       }
+      snprintf (namebuf, len, "%s/%s", SRCDIR, names[i]);
+      e = fopen (namebuf, "r");
+      free (namebuf);
+      if (e == NULL)
+       continue;
+      if (fstat (fileno (e), &st) < 0)
+       {
+         perror ("fstat");
+         fclose (e);
+         continue;
+       }
+      rbuf = malloc (st.st_size);
+      if (rbuf == NULL)
+       {
+         perror ("malloc");
+         goto fail;
+       }
+      got = fread (rbuf, 1, st.st_size, e);
+      fclose (e);
+      if (got > 0)
+       {
+         orig_buf = (unsigned char *) rbuf;
+         orig_bufsize = got;
+         break;
+       }
+      free (rbuf);
+    }
+
+  if (orig_buf == NULL)
+    {
+      /* We couldn't find an input file.  */
+      printf ("UNSUPPORTED: lzma large\n");
+      return;
+    }
+
+  stream = initial_stream;
+  r =  lzma_easy_encoder (&stream, 6, LZMA_CHECK_CRC32);
+  if (r != LZMA_OK)
+    {
+      fprintf (stderr, "lzma_easy_encoder failed: %d\n", r);
+      goto fail;
+    }
+
+  compressed_bufsize = orig_bufsize + 100;
+  compressed_buf = malloc (compressed_bufsize);
+  if (compressed_buf == NULL)
+    {
+      perror ("malloc");
+      goto fail;
+    }
+
+  stream.next_in = orig_buf;
+  stream.avail_in = orig_bufsize;
+  stream.next_out = compressed_buf;
+  stream.avail_out = compressed_bufsize;
+
+  do
+    {
+      r = lzma_code (&stream, LZMA_FINISH);
+      if (r != LZMA_OK && r != LZMA_STREAM_END)
+       {
+         fprintf (stderr, "lzma_code failed: %d\n", r);
+         goto fail;
+       }
+    }
+  while (r != LZMA_STREAM_END);
+
+  compressed_bufsize = stream.total_out;
+
+  if (!backtrace_uncompress_lzma (state, (unsigned char *) compressed_buf,
+                                 compressed_bufsize,
+                                 error_callback_compress, NULL,
+                                 &uncompressed_buf, &uncompressed_bufsize))
+    {
+      fprintf (stderr, "lzma large: backtrace_uncompress_lzma failed\n");
+      goto fail;
+    }
+
+  if (uncompressed_bufsize != orig_bufsize)
+    {
+      fprintf (stderr,
+              "lzma large: got uncompressed length %zu, want %zu\n",
+              uncompressed_bufsize, orig_bufsize);
+      goto fail;
+    }
+
+  if (memcmp (uncompressed_buf, orig_buf, uncompressed_bufsize) != 0)
+    {
+      fprintf (stderr, "lzma large: uncompressed data mismatch\n");
+      goto fail;
+    }
+
+  printf ("PASS: lzma large\n");
+
+  spare_buf = malloc (orig_bufsize);
+  if (spare_buf == NULL)
+    {
+      perror ("malloc");
+      goto fail;
+    }
+
+  for (i = 0; i < trials; ++i)
+    {
+      cid = LIBLZMA_CLOCK_GETTIME_ARG;
+      if (clock_gettime (cid, &ts1) < 0)
+       {
+         if (errno == EINVAL)
+           return;
+         perror ("clock_gettime");
+         return;
+       }
+
+      if (!backtrace_uncompress_lzma (state,
+                                     (unsigned char *) compressed_buf,
+                                     compressed_bufsize,
+                                     error_callback_compress, NULL,
+                                     &uncompressed_buf,
+                                     &uncompressed_bufsize))
+       {
+         fprintf (stderr,
+                  ("lzma large: "
+                   "benchmark backtrace_uncompress_lzma failed\n"));
+         return;
+       }
+
+      if (clock_gettime (cid, &ts2) < 0)
+       {
+         perror ("clock_gettime");
+         return;
+       }
+
+      ctime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
+      ctime += ts2.tv_nsec - ts1.tv_nsec;
+      ctimes[i] = ctime;
+
+      stream = initial_stream;
+
+      r = lzma_auto_decoder (&stream, UINT64_MAX, 0);
+      if (r != LZMA_OK)
+       {
+         fprintf (stderr, "lzma_stream_decoder failed: %d\n", r);
+         goto fail;
+       }
+
+      stream.next_in = compressed_buf;
+      stream.avail_in = compressed_bufsize;
+      stream.next_out = spare_buf;
+      stream.avail_out = orig_bufsize;
+
+      if (clock_gettime (cid, &ts1) < 0)
+       {
+         perror("clock_gettime");
+         return;
+       }
+
+      do
+       {
+         r = lzma_code (&stream, LZMA_FINISH);
+         if (r != LZMA_OK && r != LZMA_STREAM_END)
+           {
+             fprintf (stderr, "lzma_code failed: %d\n", r);
+             goto fail;
+           }
+       }
+      while (r != LZMA_STREAM_END);
+
+      if (clock_gettime (cid, &ts2) < 0)
+       {
+         perror ("clock_gettime");
+         return;
+       }
+
+      ztime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
+      ztime += ts2.tv_nsec - ts1.tv_nsec;
+      ztimes[i] = ztime;
+    }
+
+  /* Toss the highest and lowest times and average the rest.  */
+  ctime = average_time (ctimes, trials);
+  ztime = average_time (ztimes, trials);
+
+  printf ("backtrace: %zu ns\n", ctime);
+  printf ("liblzma  : %zu ns\n", ztime);
+  printf ("ratio    : %g\n", (double) ztime / (double) ctime);
+
+  return;
+
+ fail:
+  printf ("FAIL: lzma large\n");
+  ++failures;
+
+  if (orig_buf != NULL)
+    free (orig_buf);
+  if (compressed_buf != NULL)
+    free (compressed_buf);
+  if (uncompressed_buf != NULL)
+    free (uncompressed_buf);
+
+#else /* !HAVE_LIBLZMA */
+
+ printf ("UNSUPPORTED: lzma large\n");
+
+#endif /* !HAVE_LIBLZMA */
+}
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+  struct backtrace_state *state;
+
+  state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+                                 error_callback_create, NULL);
+
+  test_samples (state);
+  test_large (state);
+
+  exit (failures != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+}