aboutsummaryrefslogtreecommitdiff
path: root/libbacktrace
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2020-09-14 14:01:56 -0700
committerIan Lance Taylor <iant@golang.org>2020-09-14 14:11:17 -0700
commit05f40bc4c116ba48843728201bc7290a5e518598 (patch)
tree98fc1d2937d6781d3e3f8c45492a87cdf3adae01 /libbacktrace
parentcd6743e9c412b35e4ec7d8ebd7df8b0eeece3f01 (diff)
libbacktrace: support MiniDebugInfo
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.
Diffstat (limited to 'libbacktrace')
-rw-r--r--libbacktrace/Makefile.am55
-rw-r--r--libbacktrace/Makefile.in163
-rw-r--r--libbacktrace/config.h.in3
-rwxr-xr-xlibbacktrace/configure224
-rw-r--r--libbacktrace/configure.ac15
-rw-r--r--libbacktrace/elf.c1701
-rw-r--r--libbacktrace/internal.h9
-rw-r--r--libbacktrace/mtest.c401
-rw-r--r--libbacktrace/xztest.c508
9 files changed, 2913 insertions, 166 deletions
diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 6fc07498787..4d349386c9b 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -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
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index b244ca10a4a..201cee36d34 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -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
diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index 2303880b9b8..cdb416e6406 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -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
diff --git a/libbacktrace/configure b/libbacktrace/configure
index d4b3523e10e..031a15602c6 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -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
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index c4b19c4066f..0659ea60484 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -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;])],
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 80a00506bd6..dd004708246 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -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)
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index be99bb0c84c..09862337456 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -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
index 00000000000..d90fd1e33cc
--- /dev/null
+++ b/libbacktrace/mtest.c
@@ -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
index 00000000000..4fffe99fcf0
--- /dev/null
+++ b/libbacktrace/xztest.c
@@ -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);
+}