PR other/67165 54/181154/2
authorDenis Khalikov <d.khalikov@partner.samsung.com>
Thu, 7 Jun 2018 12:36:22 +0000 (15:36 +0300)
committerDongkyun Son <dongkyun.s@samsung.com>
Thu, 19 Jul 2018 09:06:41 +0000 (09:06 +0000)
* elf.c (__builtin_prefetch): Define if not __GNUC__.
(unlikely): Define.
(SHF_UNCOMPRESSED, ELFCOMPRESS_ZLIB): Define.
(b_elf_chdr): Define type.
(enum debug_section): Add ZDEBUG_xxx values.
(debug_section_names): Add names for new sections.
(struct debug_section_info): Add compressed field.
(elf_zlib_failed, elf_zlib_fetch): New static functions.
(HUFFMAN_TABLE_SIZE, HUFFMAN_VALUE_MASK): Define.
(HUFFMAN_BITS_SHIFT, HUFFMAN_BITS_MASK): Define.
(HUFFMAN_SECONDARY_SHIFT): Define.
(ZDEBUG_TABLE_SIZE): Define.
(ZDEBUG_TABLE_CODELEN_OFFSET, ZDEBUG_TABLE_WORK_OFFSET): Define.
(final_next_secondary): New static variable if
BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE.
(elf_zlib_inflate_table): New static function.
(BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE): If define, define main
function to produce fixed Huffman table.
(elf_zlib_default_table): New static variable.
(elf_zlib_inflate): New static function.
(elf_zlib_verify_checksum): Likewise.
(elf_zlib_inflate_and_verify): Likewise.
(elf_uncompress_zdebug): Likewise.
(elf_uncompress_chdr): Likewise.
(backtrace_uncompress_zdebug): New extern function.
(elf_add): Look for .zdebug sections and SHF_COMPRESSED debug
sections, and uncompress them.
* internal.h (backtrace_compress_zdebug): Declare.
* ztest.c: New file.
* configure.ac: Check for -lz and check whether the linker
supports --compress-debug-sections.
* Makefile.am (ztest_SOURCES): New variable.
(ztest_CFLAGS, ztest_LDADD): New variables.
(check_PROGRAMS): Add ztest.
(ctestg_SOURCES): New variable.
(ctestg_CFLAGS, ctestg_LDFLAGS, ctestg_LDADD): New variables.
(ctesta_SOURCES): New variable.
(ctesta_CFLAGS, ctesta_LDFLAGS, ctesta_LDADD): New variables.
(check_PROGRAMS): Add ctestg and ctesta.
* configure, config.h.in, Makefile.in: Rebuild.
* xcoff.c: Initial support for DWARF debug sections in XCOFF.
(STYP_DWARF, SSUBTYP_DW*): Define.
(enum dwarf_section): Define.
(struct dwsect_info): Define.
(xcoff_add): Look for DWARF sections, pass them to
backtrace_dwarf_add.
* configure.ac: Check for clock_gettime.
* config.h.in: Regenerate.
* configure: Likewise.
* ztest.c (average_time, test_large): Conditionalize test timing
on clock_gettime availability.
* Makefile.am: Append the content of clock_gettime_link to
ztest_LDADD.
* configure.ac: Test for the case that clock_gettime is in librt.
* Makefile.in: Regenerate.
* configure: Likewise.
* ztest.c: #include <errno.h>.
(TEST_TIMING): Don't define, don't test.
(xclock_gettime, xclockid_t): Define if !HAVE_CLOCK_GETTIME.
(clockid_t, clock_gettime, CLOCK_REALTIME): Likewise.
(ZLIB_CLOCK_GETTIME_ARG): Define.
* configure.ac: Change clock_gettime_link to CLOCK_GETTIME_LINK.
* Makefile.am: Likewise.
* configure, Makefile.in: Rebuild.
* elf.c (elf_zlib_fetch): Change pval argument to uint64_t *.
Read a four byte integer.
(elf_zlib_inflate): Change val to uint64_t.  Align pin to a 32-bit
boundary before ever calling elf_zlib_fetch.
* ztest.c (test_large): Simplify print statements a bit.
* ztest.c (test_large): Pass unsigned long *, not size_t *, to
zlib uncompress function.
* configure.ac: Add CET_FLAGS to EXTRA_FLAGS.
* aclocal.m4: Regenerate.
* Makefile.in: Likewise.
* configure: Likewise.
* elf.c (codes) [GENERATE_FIXED_HUFFMAN_TABLE]: Fix size to be
288.
(main) [GENERATE_FIXED_HUFFMAN_TABLE]: Pass 288 to
elf_zlib_inflate_table.  Generate elf_zlib_default_dist_table.
(elf_zlib_default_table): Update.
(elf_zlib_default_dist_table): New static array.
(elf_zlib_inflate): Use elf_zlib_default_dist_table for dist table
for block type 1.
* ztest.c (struct zlib_test): Add uncompressed_len.
(tests): Initialize uncompressed_len field.  Add new test case.
(test_samples): Use uncompressed_len field.

Change-Id: I1dd4780768695f66177983c50942001365ff75ed

libbacktrace/ChangeLog
libbacktrace/Makefile.am
libbacktrace/Makefile.in
libbacktrace/aclocal.m4
libbacktrace/config.h.in
libbacktrace/configure
libbacktrace/configure.ac
libbacktrace/elf.c
libbacktrace/internal.h
libbacktrace/xcoff.c
libbacktrace/ztest.c [new file with mode: 0644]

index 1c72eb0..ad0ab3c 100644 (file)
@@ -1,3 +1,117 @@
+2018-01-16  Ian Lance Taylor  <iant@golang.org>
+
+       * elf.c (codes) [GENERATE_FIXED_HUFFMAN_TABLE]: Fix size to be
+       288.
+       (main) [GENERATE_FIXED_HUFFMAN_TABLE]: Pass 288 to
+       elf_zlib_inflate_table.  Generate elf_zlib_default_dist_table.
+       (elf_zlib_default_table): Update.
+       (elf_zlib_default_dist_table): New static array.
+       (elf_zlib_inflate): Use elf_zlib_default_dist_table for dist table
+       for block type 1.
+       * ztest.c (struct zlib_test): Add uncompressed_len.
+       (tests): Initialize uncompressed_len field.  Add new test case.
+       (test_samples): Use uncompressed_len field.
+
+2017-11-17  Igor Tsimbalist  <igor.v.tsimbalist@intel.com>
+
+       * configure.ac: Add CET_FLAGS to EXTRA_FLAGS.
+       * aclocal.m4: Regenerate.
+       * Makefile.in: Likewise.
+       * configure: Likewise.
+
+2017-10-06  Ian Lance Taylor  <iant@golang.org>
+
+       * ztest.c (test_large): Pass unsigned long *, not size_t *, to
+       zlib uncompress function.
+
+2017-10-05  Ian Lance Taylor  <iant@golang.org>
+
+       * elf.c (elf_zlib_fetch): Change pval argument to uint64_t *.
+       Read a four byte integer.
+       (elf_zlib_inflate): Change val to uint64_t.  Align pin to a 32-bit
+       boundary before ever calling elf_zlib_fetch.
+       * ztest.c (test_large): Simplify print statements a bit.
+
+2017-10-02  Ian Lance Taylor  <iant@golang.org>
+
+       * ztest.c: #include <errno.h>.
+       (TEST_TIMING): Don't define, don't test.
+       (xclock_gettime, xclockid_t): Define if !HAVE_CLOCK_GETTIME.
+       (clockid_t, clock_gettime, CLOCK_REALTIME): Likewise.
+       (ZLIB_CLOCK_GETTIME_ARG): Define.
+       * configure.ac: Change clock_gettime_link to CLOCK_GETTIME_LINK.
+       * Makefile.am: Likewise.
+       * configure, Makefile.in: Rebuild.
+
+2017-10-02  Thomas Schwinge  <thomas@codesourcery.com>
+
+       PR other/67165
+       * Makefile.am: Append the content of clock_gettime_link to
+       ztest_LDADD.
+       * configure.ac: Test for the case that clock_gettime is in librt.
+       * Makefile.in: Regenerate.
+       * configure: Likewise.
+
+       PR other/67165
+       * configure.ac: Check for clock_gettime.
+       * config.h.in: Regenerate.
+       * configure: Likewise.
+       * ztest.c (average_time, test_large): Conditionalize test timing
+       on clock_gettime availability.
+
+2017-09-29  Tony Reix  <tony.reix@atos.net>
+
+       * xcoff.c: Initial support for DWARF debug sections in XCOFF.
+       (STYP_DWARF, SSUBTYP_DW*): Define.
+       (enum dwarf_section): Define.
+       (struct dwsect_info): Define.
+       (xcoff_add): Look for DWARF sections, pass them to
+       backtrace_dwarf_add.
+
+2017-09-28  Ian Lance Taylor  <iant@golang.org>
+
+       PR other/67165
+       * elf.c (__builtin_prefetch): Define if not __GNUC__.
+       (unlikely): Define.
+       (SHF_UNCOMPRESSED, ELFCOMPRESS_ZLIB): Define.
+       (b_elf_chdr): Define type.
+       (enum debug_section): Add ZDEBUG_xxx values.
+       (debug_section_names): Add names for new sections.
+       (struct debug_section_info): Add compressed field.
+       (elf_zlib_failed, elf_zlib_fetch): New static functions.
+       (HUFFMAN_TABLE_SIZE, HUFFMAN_VALUE_MASK): Define.
+       (HUFFMAN_BITS_SHIFT, HUFFMAN_BITS_MASK): Define.
+       (HUFFMAN_SECONDARY_SHIFT): Define.
+       (ZDEBUG_TABLE_SIZE): Define.
+       (ZDEBUG_TABLE_CODELEN_OFFSET, ZDEBUG_TABLE_WORK_OFFSET): Define.
+       (final_next_secondary): New static variable if
+       BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE.
+       (elf_zlib_inflate_table): New static function.
+       (BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE): If define, define main
+       function to produce fixed Huffman table.
+       (elf_zlib_default_table): New static variable.
+       (elf_zlib_inflate): New static function.
+       (elf_zlib_verify_checksum): Likewise.
+       (elf_zlib_inflate_and_verify): Likewise.
+       (elf_uncompress_zdebug): Likewise.
+       (elf_uncompress_chdr): Likewise.
+       (backtrace_uncompress_zdebug): New extern function.
+       (elf_add): Look for .zdebug sections and SHF_COMPRESSED debug
+       sections, and uncompress them.
+       * internal.h (backtrace_compress_zdebug): Declare.
+       * ztest.c: New file.
+       * configure.ac: Check for -lz and check whether the linker
+       supports --compress-debug-sections.
+       * Makefile.am (ztest_SOURCES): New variable.
+       (ztest_CFLAGS, ztest_LDADD): New variables.
+       (check_PROGRAMS): Add ztest.
+       (ctestg_SOURCES): New variable.
+       (ctestg_CFLAGS, ctestg_LDFLAGS, ctestg_LDADD): New variables.
+       (ctesta_SOURCES): New variable.
+       (ctesta_CFLAGS, ctesta_LDFLAGS, ctesta_LDADD): New variables.
+       (check_PROGRAMS): Add ctestg and ctesta.
+       * configure, config.h.in, Makefile.in: Rebuild.
+
 2017-09-22  Ian Lance Taylor  <iant@golang.org>
 
        PR sanitizer/77631
index 65635bf..7a26bdd 100644 (file)
@@ -101,6 +101,17 @@ stest_LDADD = libbacktrace.la
 
 check_PROGRAMS += stest
 
+ztest_SOURCES = ztest.c testlib.c
+ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
+ztest_LDADD = libbacktrace.la
+
+if HAVE_ZLIB
+ztest_LDADD += -lz
+endif
+ztest_LDADD += $(CLOCK_GETTIME_LINK)
+
+check_PROGRAMS += ztest
+
 edtest_SOURCES = edtest.c edtest2_build.c testlib.c
 edtest_LDADD = libbacktrace.la
 
@@ -132,6 +143,22 @@ dtest: btest
 
 endif HAVE_OBJCOPY_DEBUGLINK
 
+if HAVE_COMPRESSED_DEBUG
+
+ctestg_SOURCES = btest.c testlib.c
+ctestg_CFLAGS = $(AM_CFLAGS) -g
+ctestg_LDFLAGS = -Wl,--compress-debug-sections=zlib-gnu
+ctestg_LDADD = libbacktrace.la
+
+ctesta_SOURCES = btest.c testlib.c
+ctesta_CFLAGS = $(AM_CFLAGS) -g
+ctesta_LDFLAGS = -Wl,--compress-debug-sections=zlib-gabi
+ctesta_LDADD = libbacktrace.la
+
+check_PROGRAMS += ctestg ctesta
+
+endif
+
 endif NATIVE
 
 # We can't use automake's automatic dependency tracking, because it
index a659ec0..bd3f7b1 100644 (file)
@@ -83,17 +83,21 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
-@NATIVE_TRUE@am__append_1 = btest stest edtest
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_2 = ttest
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_3 = dtest
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+@NATIVE_TRUE@am__append_1 = btest stest ztest edtest
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_2 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_3 = ttest
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_4 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_5 = ctestg ctesta
 subdir = .
 DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \
        $(srcdir)/Makefile.am $(top_srcdir)/configure \
        $(am__configure_deps) $(srcdir)/config.h.in \
        $(srcdir)/../mkinstalldirs $(srcdir)/backtrace-supported.h.in
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/../config/lead-dot.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/../config/cet.m4 \
+       $(top_srcdir)/../config/enable.m4 \
+       $(top_srcdir)/../config/lead-dot.m4 \
        $(top_srcdir)/../config/multi.m4 \
        $(top_srcdir)/../config/override.m4 \
        $(top_srcdir)/../config/stdint.m4 \
@@ -116,8 +120,11 @@ am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \
        print.lo sort.lo state.lo
 libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS)
 @NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) \
-@NATIVE_TRUE@  edtest$(EXEEXT)
+@NATIVE_TRUE@  ztest$(EXEEXT) edtest$(EXEEXT)
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@      ctestg$(EXEEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@      ctesta$(EXEEXT)
 @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
 @NATIVE_TRUE@  btest-testlib.$(OBJEXT)
 btest_OBJECTS = $(am_btest_OBJECTS)
@@ -125,6 +132,22 @@ btest_OBJECTS = $(am_btest_OBJECTS)
 btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
        $(LDFLAGS) -o $@
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctesta_OBJECTS = ctesta-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@      ctesta-testlib.$(OBJEXT)
+ctesta_OBJECTS = $(am_ctesta_OBJECTS)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_DEPENDENCIES =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@      libbacktrace.la
+ctesta_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(ctesta_CFLAGS) $(CFLAGS) \
+       $(ctesta_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctestg_OBJECTS = ctestg-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@      ctestg-testlib.$(OBJEXT)
+ctestg_OBJECTS = $(am_ctestg_OBJECTS)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_DEPENDENCIES =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@      libbacktrace.la
+ctestg_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(ctestg_CFLAGS) $(CFLAGS) \
+       $(ctestg_LDFLAGS) $(LDFLAGS) -o $@
 @NATIVE_TRUE@am_edtest_OBJECTS = edtest.$(OBJEXT) \
 @NATIVE_TRUE@  edtest2_build.$(OBJEXT) testlib.$(OBJEXT)
 edtest_OBJECTS = $(am_edtest_OBJECTS)
@@ -140,6 +163,14 @@ ttest_OBJECTS = $(am_ttest_OBJECTS)
 ttest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
        $(LDFLAGS) -o $@
+@NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \
+@NATIVE_TRUE@  ztest-testlib.$(OBJEXT)
+ztest_OBJECTS = $(am_ztest_OBJECTS)
+@NATIVE_TRUE@ztest_DEPENDENCIES = libbacktrace.la \
+@NATIVE_TRUE@  $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ztest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+       --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+       $(LDFLAGS) -o $@
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp =
 am__depfiles_maybe =
@@ -153,8 +184,9 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
        --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
        $(LDFLAGS) -o $@
 SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
-       $(btest_SOURCES) $(edtest_SOURCES) $(stest_SOURCES) \
-       $(ttest_SOURCES)
+       $(btest_SOURCES) $(ctesta_SOURCES) $(ctestg_SOURCES) \
+       $(edtest_SOURCES) $(stest_SOURCES) $(ttest_SOURCES) \
+       $(ztest_SOURCES)
 MULTISRCTOP = 
 MULTIBUILDTOP = 
 MULTIDIRS = 
@@ -185,6 +217,7 @@ BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@
 BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@
 CC = @CC@
 CFLAGS = @CFLAGS@
+CLOCK_GETTIME_LINK = @CLOCK_GETTIME_LINK@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CYGPATH_W = @CYGPATH_W@
@@ -345,17 +378,29 @@ libbacktrace_la_LIBADD = \
        $(ALLOC_FILE)
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
-TESTS = $(check_PROGRAMS) $(am__append_3)
+TESTS = $(check_PROGRAMS) $(am__append_4)
 @NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
 @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
 @NATIVE_TRUE@btest_LDADD = libbacktrace.la
 @NATIVE_TRUE@stest_SOURCES = stest.c
 @NATIVE_TRUE@stest_LDADD = libbacktrace.la
+@NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
+@NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_2) \
+@NATIVE_TRUE@  $(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c
 @NATIVE_TRUE@edtest_LDADD = libbacktrace.la
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_SOURCES = ttest.c testlib.c
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_CFLAGS = $(AM_CFLAGS) -pthread
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_LDADD = libbacktrace.la
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_SOURCES = btest.c testlib.c
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_CFLAGS = $(AM_CFLAGS) -g
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_LDFLAGS = -Wl,--compress-debug-sections=zlib-gnu
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_LDADD = libbacktrace.la
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_SOURCES = btest.c testlib.c
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_CFLAGS = $(AM_CFLAGS) -g
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_LDFLAGS = -Wl,--compress-debug-sections=zlib-gabi
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_LDADD = libbacktrace.la
 
 # We can't use automake's automatic dependency tracking, because it
 # breaks when using bootstrap-lean.  Automatic dependency tracking
@@ -448,6 +493,12 @@ clean-checkPROGRAMS:
 btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) 
        @rm -f btest$(EXEEXT)
        $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
+ctesta$(EXEEXT): $(ctesta_OBJECTS) $(ctesta_DEPENDENCIES) $(EXTRA_ctesta_DEPENDENCIES) 
+       @rm -f ctesta$(EXEEXT)
+       $(ctesta_LINK) $(ctesta_OBJECTS) $(ctesta_LDADD) $(LIBS)
+ctestg$(EXEEXT): $(ctestg_OBJECTS) $(ctestg_DEPENDENCIES) $(EXTRA_ctestg_DEPENDENCIES) 
+       @rm -f ctestg$(EXEEXT)
+       $(ctestg_LINK) $(ctestg_OBJECTS) $(ctestg_LDADD) $(LIBS)
 edtest$(EXEEXT): $(edtest_OBJECTS) $(edtest_DEPENDENCIES) $(EXTRA_edtest_DEPENDENCIES) 
        @rm -f edtest$(EXEEXT)
        $(LINK) $(edtest_OBJECTS) $(edtest_LDADD) $(LIBS)
@@ -457,6 +508,9 @@ stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIE
 ttest$(EXEEXT): $(ttest_OBJECTS) $(ttest_DEPENDENCIES) $(EXTRA_ttest_DEPENDENCIES) 
        @rm -f ttest$(EXEEXT)
        $(ttest_LINK) $(ttest_OBJECTS) $(ttest_LDADD) $(LIBS)
+ztest$(EXEEXT): $(ztest_OBJECTS) $(ztest_DEPENDENCIES) $(EXTRA_ztest_DEPENDENCIES) 
+       @rm -f ztest$(EXEEXT)
+       $(ztest_LINK) $(ztest_OBJECTS) $(ztest_LDADD) $(LIBS)
 
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
@@ -485,6 +539,30 @@ btest-testlib.o: testlib.c
 btest-testlib.obj: testlib.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
 
+ctesta-btest.o: btest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+ctesta-btest.obj: btest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+ctesta-testlib.o: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+ctesta-testlib.obj: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
+ctestg-btest.o: btest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+ctestg-btest.obj: btest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+ctestg-testlib.o: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+ctestg-testlib.obj: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 ttest-ttest.o: ttest.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-ttest.o `test -f 'ttest.c' || echo '$(srcdir)/'`ttest.c
 
@@ -497,6 +575,18 @@ ttest-testlib.o: testlib.c
 ttest-testlib.obj: testlib.c
        $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
 
+ztest-ztest.o: ztest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-ztest.o `test -f 'ztest.c' || echo '$(srcdir)/'`ztest.c
+
+ztest-ztest.obj: ztest.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-ztest.obj `if test -f 'ztest.c'; then $(CYGPATH_W) 'ztest.c'; else $(CYGPATH_W) '$(srcdir)/ztest.c'; fi`
+
+ztest-testlib.o: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+ztest-testlib.obj: testlib.c
+       $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 mostlyclean-libtool:
        -rm -f *.lo
 
index 8e84ddd..7a6ea55 100644 (file)
@@ -670,6 +670,8 @@ AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
+m4_include([../config/cet.m4])
+m4_include([../config/enable.m4])
 m4_include([../config/lead-dot.m4])
 m4_include([../config/multi.m4])
 m4_include([../config/override.m4])
index 1c38e8e..c19b6e4 100644 (file)
@@ -9,6 +9,9 @@
 /* Define to 1 if you have the __atomic functions */
 #undef HAVE_ATOMIC_FUNCTIONS
 
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
 /* Define to 1 if you have the declaration of `strnlen', and to 0 if you
    don't. */
 #undef HAVE_DECL_STRNLEN
@@ -31,6 +34,9 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
 /* Define to 1 if you have the <link.h> header file. */
 #undef HAVE_LINK_H
 
@@ -76,6 +82,9 @@
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define if -lz is available. */
+#undef HAVE_ZLIB
+
 /* Define to the sub-directory in which libtool stores uninstalled libraries.
    */
 #undef LT_OBJDIR
index 785fcbe..a89550f 100755 (executable)
@@ -607,9 +607,14 @@ NATIVE_TRUE
 HAVE_OBJCOPY_DEBUGLINK_FALSE
 HAVE_OBJCOPY_DEBUGLINK_TRUE
 OBJCOPY
+HAVE_COMPRESSED_DEBUG_FALSE
+HAVE_COMPRESSED_DEBUG_TRUE
+HAVE_ZLIB_FALSE
+HAVE_ZLIB_TRUE
 HAVE_PTHREAD_FALSE
 HAVE_PTHREAD_TRUE
 PTHREAD_CFLAGS
+CLOCK_GETTIME_LINK
 BACKTRACE_USES_MALLOC
 ALLOC_FILE
 VIEW_FILE
@@ -738,6 +743,7 @@ enable_fast_install
 with_gnu_ld
 enable_libtool_lock
 enable_largefile
+enable_cet
 with_system_libunwind
 enable_host_shared
 '
@@ -1380,6 +1386,8 @@ Optional Features:
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --disable-largefile     omit support for large files
+  --enable-cet            enable Intel CET in target libraries
+                          [default=default]
   --enable-host-shared    build host code as shared libraries
 
 Optional Packages:
@@ -11141,7 +11149,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11144 "configure"
+#line 11152 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11247,7 +11255,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11250 "configure"
+#line 11258 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11779,6 +11787,77 @@ $as_echo "$libbacktrace_cv_c_random_seed_string" >&6; }
   fi
 fi
 
+if test -n "${with_target_subdir}"; then
+  # Add CET specific flags is Intel CET is enabled.
+   # Check whether --enable-cet was given.
+if test "${enable_cet+set}" = set; then :
+  enableval=$enable_cet;
+      case "$enableval" in
+       yes|no|default) ;;
+       *) as_fn_error "Unknown argument to enable/disable cet" "$LINENO" 5 ;;
+                          esac
+
+else
+  enable_cet=default
+fi
+
+
+case "$host" in
+  i[34567]86-*-linux* | x86_64-*-linux*)
+    case "$enable_cet" in
+      default)
+       # Check if assembler supports CET.
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+asm ("setssbsy");
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  enable_cet=yes
+else
+  enable_cet=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       ;;
+      yes)
+       # Check if assembler supports CET.
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+asm ("setssbsy");
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  as_fn_error "assembler with CET support is required for --enable-cet" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       ;;
+    esac
+    ;;
+  *)
+    enable_cet=no
+    ;;
+esac
+if test x$enable_cet = xyes; then
+  CET_FLAGS="-fcf-protection -mcet"
+fi
+
+  EXTRA_FLAGS="$EXTRA_FLAGS $CET_FLAGS"
+fi
+
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -12743,6 +12822,70 @@ $as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h
 
 fi
 
+# Check for the clock_gettime function.
+for ac_func in clock_gettime
+do :
+  ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
+if test "x$ac_cv_func_clock_gettime" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_CLOCK_GETTIME 1
+_ACEOF
+
+fi
+done
+
+clock_gettime_link=
+# At least for glibc, clock_gettime is in librt.  But don't
+# pull that in if it still doesn't give us the function we want.  This
+# test is copied from libgomp, and modified to not link in -lrt as
+# we're using this for test timing only.
+if test "$ac_cv_func_clock_gettime" = no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt  $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 clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_rt_clock_gettime=yes
+else
+  ac_cv_lib_rt_clock_gettime=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_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = x""yes; then :
+  CLOCK_GETTIME_LINK=-lrt
+
+$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+
+fi
+
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5
 $as_echo_n "checking whether -pthread is supported... " >&6; }
 if test "${libgo_cv_lib_pthread+set}" = set; then :
@@ -12779,6 +12922,103 @@ else
 fi
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress in -lz" >&5
+$as_echo_n "checking for compress in -lz... " >&6; }
+if test "${ac_cv_lib_z_compress+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz  $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 compress ();
+int
+main ()
+{
+return compress ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_z_compress=yes
+else
+  ac_cv_lib_z_compress=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_z_compress" >&5
+$as_echo "$ac_cv_lib_z_compress" >&6; }
+if test "x$ac_cv_lib_z_compress" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+  LIBS="-lz $LIBS"
+
+fi
+
+if test $ac_cv_lib_z_compress = "yes"; then
+
+$as_echo "#define HAVE_ZLIB 1" >>confdefs.h
+
+fi
+ if test "$ac_cv_lib_z_compress" = yes; then
+  HAVE_ZLIB_TRUE=
+  HAVE_ZLIB_FALSE='#'
+else
+  HAVE_ZLIB_TRUE='#'
+  HAVE_ZLIB_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether --compress-debug-sections is supported" >&5
+$as_echo_n "checking whether --compress-debug-sections is supported... " >&6; }
+if test "${libgo_cv_ld_compress+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  LDFLAGS_hold=$LDFLAGS
+LDFLAGS="$LDFLAGS -Wl,--compress-debug-sections=zlib-gnu"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  libgo_cv_ld_compress=yes
+else
+  libgo_cv_ld_compress=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LDFLAGS=$LDFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_ld_compress" >&5
+$as_echo "$libgo_cv_ld_compress" >&6; }
+ if test "$libgo_cv_ld_compress" = yes; then
+  HAVE_COMPRESSED_DEBUG_TRUE=
+  HAVE_COMPRESSED_DEBUG_FALSE='#'
+else
+  HAVE_COMPRESSED_DEBUG_TRUE='#'
+  HAVE_COMPRESSED_DEBUG_FALSE=
+fi
+
+
 
 # Extract the first word of "objcopy", so it can be a program name with args.
 set dummy objcopy; ac_word=$2
@@ -13008,6 +13248,14 @@ if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then
   as_fn_error "conditional \"HAVE_PTHREAD\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_ZLIB_TRUE}" && test -z "${HAVE_ZLIB_FALSE}"; then
+  as_fn_error "conditional \"HAVE_ZLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_COMPRESSED_DEBUG_TRUE}" && test -z "${HAVE_COMPRESSED_DEBUG_FALSE}"; then
+  as_fn_error "conditional \"HAVE_COMPRESSED_DEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${HAVE_OBJCOPY_DEBUGLINK_TRUE}" && test -z "${HAVE_OBJCOPY_DEBUGLINK_FALSE}"; then
   as_fn_error "conditional \"HAVE_OBJCOPY_DEBUGLINK\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
index 34d1591..c238cd6 100644 (file)
@@ -130,6 +130,12 @@ else
     EXTRA_FLAGS="$EXTRA_FLAGS -frandom-seed=\$@"
   fi
 fi
+
+if test -n "${with_target_subdir}"; then
+  # Add CET specific flags is Intel CET is enabled.
+  GCC_CET_FLAGS(CET_FLAGS)
+  EXTRA_FLAGS="$EXTRA_FLAGS $CET_FLAGS"
+fi
 AC_SUBST(EXTRA_FLAGS)
 
 ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wwrite-strings -Wstrict-prototypes \
@@ -388,6 +394,21 @@ if test "$have_getexecname" = "yes"; then
   AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.])
 fi
 
+# Check for the clock_gettime function.
+AC_CHECK_FUNCS(clock_gettime)
+clock_gettime_link=
+# At least for glibc, clock_gettime is in librt.  But don't
+# pull that in if it still doesn't give us the function we want.  This
+# test is copied from libgomp, and modified to not link in -lrt as
+# we're using this for test timing only.
+if test "$ac_cv_func_clock_gettime" = no; then
+  AC_CHECK_LIB(rt, clock_gettime,
+    [CLOCK_GETTIME_LINK=-lrt
+     AC_DEFINE(HAVE_CLOCK_GETTIME, 1,
+              [Define to 1 if you have the `clock_gettime' function.])])
+fi
+AC_SUBST(CLOCK_GETTIME_LINK)
+
 dnl Test whether the compiler supports the -pthread option.
 AC_CACHE_CHECK([whether -pthread is supported],
 [libgo_cv_lib_pthread],
@@ -405,6 +426,23 @@ AC_SUBST(PTHREAD_CFLAGS)
 
 AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes)
 
+AC_CHECK_LIB([z], [compress], [])
+if test $ac_cv_lib_z_compress = "yes"; then
+  AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.])
+fi
+AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes)
+
+dnl Test whether the linker supports the --compress_debug_sections option.
+AC_CACHE_CHECK([whether --compress-debug-sections is supported],
+[libgo_cv_ld_compress],
+[LDFLAGS_hold=$LDFLAGS
+LDFLAGS="$LDFLAGS -Wl,--compress-debug-sections=zlib-gnu"
+AC_LINK_IFELSE([AC_LANG_PROGRAM(,)],
+[libgo_cv_ld_compress=yes],
+[libgo_cv_ld_compress=no])
+LDFLAGS=$LDFLAGS_hold])
+AM_CONDITIONAL(HAVE_COMPRESSED_DEBUG, test "$libgo_cv_ld_compress" = yes)
+
 AC_ARG_VAR(OBJCOPY, [location of objcopy])
 AC_CHECK_PROG(OBJCOPY, objcopy, objcopy,)
 AC_CACHE_CHECK([whether objcopy supports debuglink],
index 9452681..f923bc2 100644 (file)
@@ -56,6 +56,13 @@ POSSIBILITY OF SUCH DAMAGE.  */
  #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
 #endif
 
+#ifndef __GNUC__
+#define __builtin_prefetch(p, r, l)
+#define unlikely(x) (x)
+#else
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+
 #if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
 
 /* If strnlen is not declared, provide our own version.  */
@@ -164,9 +171,11 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
 #undef SHT_SYMTAB
 #undef SHT_STRTAB
 #undef SHT_DYNSYM
+#undef SHF_COMPRESSED
 #undef STT_OBJECT
 #undef STT_FUNC
 #undef NT_GNU_BUILD_ID
+#undef ELFCOMPRESS_ZLIB
 
 /* Basic types.  */
 
@@ -257,6 +266,8 @@ typedef struct {
 #define SHT_STRTAB 3
 #define SHT_DYNSYM 11
 
+#define SHF_COMPRESSED 0x800
+
 #if BACKTRACE_ELF_SIZE == 32
 
 typedef struct
@@ -296,6 +307,29 @@ typedef struct
 
 #define NT_GNU_BUILD_ID 3
 
+#if BACKTRACE_ELF_SIZE == 32
+
+typedef struct
+{
+  b_elf_word   ch_type;                /* Compresstion algorithm */
+  b_elf_word   ch_size;                /* Uncompressed size */
+  b_elf_word   ch_addralign;           /* Alignment for uncompressed data */
+} b_elf_chdr;  /* Elf_Chdr */
+
+#else /* BACKTRACE_ELF_SIZE != 32 */
+
+typedef struct
+{
+  b_elf_word   ch_type;                /* Compression algorithm */
+  b_elf_word   ch_reserved;            /* Reserved */
+  b_elf_xword  ch_size;                /* Uncompressed size */
+  b_elf_xword  ch_addralign;           /* Alignment for uncompressed data */
+} b_elf_chdr;  /* Elf_Chdr */
+
+#endif /* BACKTRACE_ELF_SIZE != 32 */
+
+#define ELFCOMPRESS_ZLIB 1
+
 /* An index of ELF sections we care about.  */
 
 enum debug_section
@@ -305,6 +339,15 @@ enum debug_section
   DEBUG_ABBREV,
   DEBUG_RANGES,
   DEBUG_STR,
+
+  /* The old style compressed sections.  This list must correspond to
+     the list of normal debug sections.  */
+  ZDEBUG_INFO,
+  ZDEBUG_LINE,
+  ZDEBUG_ABBREV,
+  ZDEBUG_RANGES,
+  ZDEBUG_STR,
+
   DEBUG_MAX
 };
 
@@ -316,7 +359,12 @@ static const char * const debug_section_names[DEBUG_MAX] =
   ".debug_line",
   ".debug_abbrev",
   ".debug_ranges",
-  ".debug_str"
+  ".debug_str",
+  ".zdebug_info",
+  ".zdebug_line",
+  ".zdebug_abbrev",
+  ".zdebug_ranges",
+  ".zdebug_str"
 };
 
 /* Information we gather for the sections we care about.  */
@@ -329,6 +377,8 @@ struct debug_section_info
   size_t size;
   /* Section contents, after read from file.  */
   const unsigned char *data;
+  /* Whether the SHF_COMPRESSED flag is set for the section.  */
+  int compressed;
 };
 
 /* Information we keep for an ELF symbol.  */
@@ -965,6 +1015,1576 @@ elf_open_debugfile_by_debuglink (struct backtrace_state *state,
   return ddescriptor;
 }
 
+/* A function useful for setting a breakpoint for an inflation failure
+   when this code is compiled with -g.  */
+
+static void
+elf_zlib_failed(void)
+{
+}
+
+/* *PVAL is the current value being read from the stream, and *PBITS
+   is the number of valid bits.  Ensure that *PVAL holds at least 15
+   bits by reading additional bits from *PPIN, up to PINEND, as
+   needed.  Updates *PPIN, *PVAL and *PBITS.  Returns 1 on success, 0
+   on error.  */
+
+static int
+elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend,
+               uint64_t *pval, unsigned int *pbits)
+{
+  unsigned int bits;
+  const unsigned char *pin;
+  uint64_t val;
+  uint32_t next;
+
+  bits = *pbits;
+  if (bits >= 15)
+    return 1;
+  pin = *ppin;
+  val = *pval;
+
+  if (unlikely (pinend - pin < 4))
+    {
+      elf_zlib_failed ();
+      return 0;
+    }
+
+  /* We've ensured that PIN is aligned.  */
+  next = *(const uint32_t *)pin;
+
+#if __BYTE_ORDER == __ORDER_BIG_ENDIAN
+  next = __builtin_bswap32 (next);
+#endif
+
+  val |= (uint64_t)next << bits;
+  bits += 32;
+  pin += 4;
+
+  /* We will need the next four bytes soon.  */
+  __builtin_prefetch (pin, 0, 0);
+
+  *ppin = pin;
+  *pval = val;
+  *pbits = bits;
+  return 1;
+}
+
+/* Huffman code tables, like the rest of the zlib format, are defined
+   by RFC 1951.  We store a Huffman code table as a series of tables
+   stored sequentially in memory.  Each entry in a table is 16 bits.
+   The first, main, table has 256 entries.  It is followed by a set of
+   secondary tables of length 2 to 128 entries.  The maximum length of
+   a code sequence in the deflate format is 15 bits, so that is all we
+   need.  Each secondary table has an index, which is the offset of
+   the table in the overall memory storage.
+
+   The deflate format says that all codes of a given bit length are
+   lexicographically consecutive.  Perhaps we could have 130 values
+   that require a 15-bit code, perhaps requiring three secondary
+   tables of size 128.  I don't know if this is actually possible, but
+   it suggests that the maximum size required for secondary tables is
+   3 * 128 + 3 * 64 ... == 768.  The zlib enough program reports 660
+   as the maximum.  We permit 768, since in addition to the 256 for
+   the primary table, with two bytes per entry, and with the two
+   tables we need, that gives us a page.
+
+   A single table entry needs to store a value or (for the main table
+   only) the index and size of a secondary table.  Values range from 0
+   to 285, inclusive.  Secondary table indexes, per above, range from
+   0 to 510.  For a value we need to store the number of bits we need
+   to determine that value (one value may appear multiple times in the
+   table), which is 1 to 8.  For a secondary table we need to store
+   the number of bits used to index into the table, which is 1 to 7.
+   And of course we need 1 bit to decide whether we have a value or a
+   secondary table index.  So each entry needs 9 bits for value/table
+   index, 3 bits for size, 1 bit what it is.  For simplicity we use 16
+   bits per entry.  */
+
+/* Number of entries we allocate to for one code table.  We get a page
+   for the two code tables we need.  */
+
+#define HUFFMAN_TABLE_SIZE (1024)
+
+/* Bit masks and shifts for the values in the table.  */
+
+#define HUFFMAN_VALUE_MASK 0x01ff
+#define HUFFMAN_BITS_SHIFT 9
+#define HUFFMAN_BITS_MASK 0x7
+#define HUFFMAN_SECONDARY_SHIFT 12
+
+/* For working memory while inflating we need two code tables, we need
+   an array of code lengths (max value 15, so we use unsigned char),
+   and an array of unsigned shorts used while building a table.  The
+   latter two arrays must be large enough to hold the maximum number
+   of code lengths, which RFC 1951 defines as 286 + 30.  */
+
+#define ZDEBUG_TABLE_SIZE \
+  (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \
+   + (286 + 30) * sizeof (uint16_t)          \
+   + (286 + 30) * sizeof (unsigned char))
+
+#define ZDEBUG_TABLE_CODELEN_OFFSET \
+  (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \
+   + (286 + 30) * sizeof (uint16_t))
+
+#define ZDEBUG_TABLE_WORK_OFFSET \
+  (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t))
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+
+/* Used by the main function that generates the fixed table to learn
+   the table size.  */
+static size_t final_next_secondary;
+
+#endif
+
+/* Build a Huffman code table from an array of lengths in CODES of
+   length CODES_LEN.  The table is stored into *TABLE.  ZDEBUG_TABLE
+   is the same as for elf_zlib_inflate, used to find some work space.
+   Returns 1 on success, 0 on error.  */
+
+static int
+elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
+                       uint16_t *zdebug_table, uint16_t *table)
+{
+  uint16_t count[16];
+  uint16_t start[16];
+  uint16_t prev[16];
+  uint16_t firstcode[7];
+  uint16_t *next;
+  size_t i;
+  size_t j;
+  unsigned int code;
+  size_t next_secondary;
+
+  /* Count the number of code of each length.  Set NEXT[val] to be the
+     next value after VAL with the same bit length.  */
+
+  next = (uint16_t *) (((unsigned char *) zdebug_table)
+                      + ZDEBUG_TABLE_WORK_OFFSET);
+
+  memset (&count[0], 0, 16 * sizeof (uint16_t));
+  for (i = 0; i < codes_len; ++i)
+    {
+      if (unlikely (codes[i] >= 16))
+       {
+         elf_zlib_failed ();
+         return 0;
+       }
+
+      if (count[codes[i]] == 0)
+       {
+         start[codes[i]] = i;
+         prev[codes[i]] = i;
+       }
+      else
+       {
+         next[prev[codes[i]]] = i;
+         prev[codes[i]] = i;
+       }
+
+      ++count[codes[i]];
+    }
+
+  /* For each length, fill in the table for the codes of that
+     length.  */
+
+  memset (table, 0, HUFFMAN_TABLE_SIZE * sizeof (uint16_t));
+
+  /* Handle the values that do not require a secondary table.  */
+
+  code = 0;
+  for (j = 1; j <= 8; ++j)
+    {
+      unsigned int jcnt;
+      unsigned int val;
+
+      jcnt = count[j];
+      if (jcnt == 0)
+       continue;
+
+      if (unlikely (jcnt > (1U << j)))
+       {
+         elf_zlib_failed ();
+         return 0;
+       }
+
+      /* There are JCNT values that have this length, the values
+        starting from START[j] continuing through NEXT[VAL].  Those
+        values are assigned consecutive values starting at CODE.  */
+
+      val = start[j];
+      for (i = 0; i < jcnt; ++i)
+       {
+         uint16_t tval;
+         size_t ind;
+         unsigned int incr;
+
+         /* In the compressed bit stream, the value VAL is encoded as
+            J bits with the value C.  */
+
+         if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0))
+           {
+             elf_zlib_failed ();
+             return 0;
+           }
+
+         tval = val | ((j - 1) << HUFFMAN_BITS_SHIFT);
+
+         /* The table lookup uses 8 bits.  If J is less than 8, we
+            don't know what the other bits will be.  We need to fill
+            in all possibilities in the table.  Since the Huffman
+            code is unambiguous, those entries can't be used for any
+            other code.  */
+
+         for (ind = code; ind < 0x100; ind += 1 << j)
+           {
+             if (unlikely (table[ind] != 0))
+               {
+                 elf_zlib_failed ();
+                 return 0;
+               }
+             table[ind] = tval;
+           }
+
+         /* Advance to the next value with this length.  */
+         if (i + 1 < jcnt)
+           val = next[val];
+
+         /* The Huffman codes are stored in the bitstream with the
+            most significant bit first, as is required to make them
+            unambiguous.  The effect is that when we read them from
+            the bitstream we see the bit sequence in reverse order:
+            the most significant bit of the Huffman code is the least
+            significant bit of the value we read from the bitstream.
+            That means that to make our table lookups work, we need
+            to reverse the bits of CODE.  Since reversing bits is
+            tedious and in general requires using a table, we instead
+            increment CODE in reverse order.  That is, if the number
+            of bits we are currently using, here named J, is 3, we
+            count as 000, 100, 010, 110, 001, 101, 011, 111, which is
+            to say the numbers from 0 to 7 but with the bits
+            reversed.  Going to more bits, aka incrementing J,
+            effectively just adds more zero bits as the beginning,
+            and as such does not change the numeric value of CODE.
+
+            To increment CODE of length J in reverse order, find the
+            most significant zero bit and set it to one while
+            clearing all higher bits.  In other words, add 1 modulo
+            2^J, only reversed.  */
+
+         incr = 1U << (j - 1);
+         while ((code & incr) != 0)
+           incr >>= 1;
+         if (incr == 0)
+           code = 0;
+         else
+           {
+             code &= incr - 1;
+             code += incr;
+           }
+       }
+    }
+
+  /* Handle the values that require a secondary table.  */
+
+  /* Set FIRSTCODE, the number at which the codes start, for each
+     length.  */
+
+  for (j = 9; j < 16; j++)
+    {
+      unsigned int jcnt;
+      unsigned int k;
+
+      jcnt = count[j];
+      if (jcnt == 0)
+       continue;
+
+      /* There are JCNT values that have this length, the values
+        starting from START[j].  Those values are assigned
+        consecutive values starting at CODE.  */
+
+      firstcode[j - 9] = code;
+
+      /* Reverse add JCNT to CODE modulo 2^J.  */
+      for (k = 0; k < j; ++k)
+       {
+         if ((jcnt & (1U << k)) != 0)
+           {
+             unsigned int m;
+             unsigned int bit;
+
+             bit = 1U << (j - k - 1);
+             for (m = 0; m < j - k; ++m, bit >>= 1)
+               {
+                 if ((code & bit) == 0)
+                   {
+                     code += bit;
+                     break;
+                   }
+                 code &= ~bit;
+               }
+             jcnt &= ~(1U << k);
+           }
+       }
+      if (unlikely (jcnt != 0))
+       {
+         elf_zlib_failed ();
+         return 0;
+       }
+    }
+
+  /* For J from 9 to 15, inclusive, we store COUNT[J] consecutive
+     values starting at START[J] with consecutive codes starting at
+     FIRSTCODE[J - 9].  In the primary table we need to point to the
+     secondary table, and the secondary table will be indexed by J - 9
+     bits.  We count down from 15 so that we install the larger
+     secondary tables first, as the smaller ones may be embedded in
+     the larger ones.  */
+
+  next_secondary = 0; /* Index of next secondary table (after primary).  */
+  for (j = 15; j >= 9; j--)
+    {
+      unsigned int jcnt;
+      unsigned int val;
+      size_t primary; /* Current primary index.  */
+      size_t secondary; /* Offset to current secondary table.  */
+      size_t secondary_bits; /* Bit size of current secondary table.  */
+
+      jcnt = count[j];
+      if (jcnt == 0)
+       continue;
+
+      val = start[j];
+      code = firstcode[j - 9];
+      primary = 0x100;
+      secondary = 0;
+      secondary_bits = 0;
+      for (i = 0; i < jcnt; ++i)
+       {
+         uint16_t tval;
+         size_t ind;
+         unsigned int incr;
+
+         if ((code & 0xff) != primary)
+           {
+             uint16_t tprimary;
+
+             /* Fill in a new primary table entry.  */
+
+             primary = code & 0xff;
+
+             tprimary = table[primary];
+             if (tprimary == 0)
+               {
+                 /* Start a new secondary table.  */
+
+                 if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK)
+                               != next_secondary))
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+
+                 secondary = next_secondary;
+                 secondary_bits = j - 8;
+                 next_secondary += 1 << secondary_bits;
+                 table[primary] = (secondary
+                                   + ((j - 8) << HUFFMAN_BITS_SHIFT)
+                                   + (1U << HUFFMAN_SECONDARY_SHIFT));
+               }
+             else
+               {
+                 /* There is an existing entry.  It had better be a
+                    secondary table with enough bits.  */
+                 if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT))
+                               == 0))
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+                 secondary = tprimary & HUFFMAN_VALUE_MASK;
+                 secondary_bits = ((tprimary >> HUFFMAN_BITS_SHIFT)
+                                   & HUFFMAN_BITS_MASK);
+                 if (unlikely (secondary_bits < j - 8))
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+               }
+           }
+
+         /* Fill in secondary table entries.  */
+
+         tval = val | ((j - 8) << HUFFMAN_BITS_SHIFT);
+
+         for (ind = code >> 8;
+              ind < (1U << secondary_bits);
+              ind += 1U << (j - 8))
+           {
+             if (unlikely (table[secondary + 0x100 + ind] != 0))
+               {
+                 elf_zlib_failed ();
+                 return 0;
+               }
+             table[secondary + 0x100 + ind] = tval;
+           }
+
+         if (i + 1 < jcnt)
+           val = next[val];
+
+         incr = 1U << (j - 1);
+         while ((code & incr) != 0)
+           incr >>= 1;
+         if (incr == 0)
+           code = 0;
+         else
+           {
+             code &= incr - 1;
+             code += incr;
+           }
+       }
+    }
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+  final_next_secondary = next_secondary;
+#endif
+
+  return 1;
+}
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+
+/* Used to generate the fixed Huffman table for block type 1.  */
+
+#include <stdio.h>
+
+static uint16_t table[ZDEBUG_TABLE_SIZE];
+static unsigned char codes[288];
+
+int
+main ()
+{
+  size_t i;
+
+  for (i = 0; i <= 143; ++i)
+    codes[i] = 8;
+  for (i = 144; i <= 255; ++i)
+    codes[i] = 9;
+  for (i = 256; i <= 279; ++i)
+    codes[i] = 7;
+  for (i = 280; i <= 287; ++i)
+    codes[i] = 8;
+  if (!elf_zlib_inflate_table (&codes[0], 288, &table[0], &table[0]))
+    {
+      fprintf (stderr, "elf_zlib_inflate_table failed\n");
+      exit (EXIT_FAILURE);
+    }
+
+  printf ("static const uint16_t elf_zlib_default_table[%#zx] =\n",
+         final_next_secondary + 0x100);
+  printf ("{\n");
+  for (i = 0; i < final_next_secondary + 0x100; i += 8)
+    {
+      size_t j;
+
+      printf (" ");
+      for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j)
+       printf (" %#x,", table[j]);
+      printf ("\n");
+    }
+  printf ("};\n");
+  printf ("\n");
+
+  for (i = 0; i < 32; ++i)
+    codes[i] = 5;
+  if (!elf_zlib_inflate_table (&codes[0], 32, &table[0], &table[0]))
+    {
+      fprintf (stderr, "elf_zlib_inflate_table failed\n");
+      exit (EXIT_FAILURE);
+    }
+
+  printf ("static const uint16_t elf_zlib_default_dist_table[%#zx] =\n",
+         final_next_secondary + 0x100);
+  printf ("{\n");
+  for (i = 0; i < final_next_secondary + 0x100; i += 8)
+    {
+      size_t j;
+
+      printf (" ");
+      for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j)
+       printf (" %#x,", table[j]);
+      printf ("\n");
+    }
+  printf ("};\n");
+
+  return 0;
+}
+
+#endif
+
+/* The fixed tables generated by the #ifdef'ed out main function
+   above.  */
+
+static const uint16_t elf_zlib_default_table[0x170] =
+{
+  0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1230,
+  0xd08, 0xe60, 0xe20, 0x1210, 0xe00, 0xe80, 0xe40, 0x1250,
+  0xd04, 0xe58, 0xe18, 0x1200, 0xd14, 0xe78, 0xe38, 0x1240,
+  0xd0c, 0xe68, 0xe28, 0x1220, 0xe08, 0xe88, 0xe48, 0x1260,
+  0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x1238,
+  0xd0a, 0xe64, 0xe24, 0x1218, 0xe04, 0xe84, 0xe44, 0x1258,
+  0xd06, 0xe5c, 0xe1c, 0x1208, 0xd16, 0xe7c, 0xe3c, 0x1248,
+  0xd0e, 0xe6c, 0xe2c, 0x1228, 0xe0c, 0xe8c, 0xe4c, 0x1268,
+  0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1234,
+  0xd09, 0xe62, 0xe22, 0x1214, 0xe02, 0xe82, 0xe42, 0x1254,
+  0xd05, 0xe5a, 0xe1a, 0x1204, 0xd15, 0xe7a, 0xe3a, 0x1244,
+  0xd0d, 0xe6a, 0xe2a, 0x1224, 0xe0a, 0xe8a, 0xe4a, 0x1264,
+  0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123c,
+  0xd0b, 0xe66, 0xe26, 0x121c, 0xe06, 0xe86, 0xe46, 0x125c,
+  0xd07, 0xe5e, 0xe1e, 0x120c, 0xd17, 0xe7e, 0xe3e, 0x124c,
+  0xd0f, 0xe6e, 0xe2e, 0x122c, 0xe0e, 0xe8e, 0xe4e, 0x126c,
+  0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1232,
+  0xd08, 0xe61, 0xe21, 0x1212, 0xe01, 0xe81, 0xe41, 0x1252,
+  0xd04, 0xe59, 0xe19, 0x1202, 0xd14, 0xe79, 0xe39, 0x1242,
+  0xd0c, 0xe69, 0xe29, 0x1222, 0xe09, 0xe89, 0xe49, 0x1262,
+  0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123a,
+  0xd0a, 0xe65, 0xe25, 0x121a, 0xe05, 0xe85, 0xe45, 0x125a,
+  0xd06, 0xe5d, 0xe1d, 0x120a, 0xd16, 0xe7d, 0xe3d, 0x124a,
+  0xd0e, 0xe6d, 0xe2d, 0x122a, 0xe0d, 0xe8d, 0xe4d, 0x126a,
+  0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1236,
+  0xd09, 0xe63, 0xe23, 0x1216, 0xe03, 0xe83, 0xe43, 0x1256,
+  0xd05, 0xe5b, 0xe1b, 0x1206, 0xd15, 0xe7b, 0xe3b, 0x1246,
+  0xd0d, 0xe6b, 0xe2b, 0x1226, 0xe0b, 0xe8b, 0xe4b, 0x1266,
+  0xd03, 0xe57, 0xe17, 0xf1f, 0xd13, 0xe77, 0xe37, 0x123e,
+  0xd0b, 0xe67, 0xe27, 0x121e, 0xe07, 0xe87, 0xe47, 0x125e,
+  0xd07, 0xe5f, 0xe1f, 0x120e, 0xd17, 0xe7f, 0xe3f, 0x124e,
+  0xd0f, 0xe6f, 0xe2f, 0x122e, 0xe0f, 0xe8f, 0xe4f, 0x126e,
+  0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297,
+  0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f,
+  0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7,
+  0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af,
+  0x2b0, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7,
+  0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf,
+  0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7,
+  0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf,
+  0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7,
+  0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df,
+  0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7,
+  0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef,
+  0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7,
+  0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff,
+};
+
+static const uint16_t elf_zlib_default_dist_table[0x100] =
+{
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+  0x800, 0x810, 0x808, 0x818, 0x804, 0x814, 0x80c, 0x81c,
+  0x802, 0x812, 0x80a, 0x81a, 0x806, 0x816, 0x80e, 0x81e,
+  0x801, 0x811, 0x809, 0x819, 0x805, 0x815, 0x80d, 0x81d,
+  0x803, 0x813, 0x80b, 0x81b, 0x807, 0x817, 0x80f, 0x81f,
+};
+
+/* Inflate a zlib stream from PIN/SIN to POUT/SOUT.  Return 1 on
+   success, 0 on some error parsing the stream.  */
+
+static int
+elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
+                 unsigned char *pout, size_t sout)
+{
+  unsigned char *porigout;
+  const unsigned char *pinend;
+  unsigned char *poutend;
+
+  /* We can apparently see multiple zlib streams concatenated
+     together, so keep going as long as there is something to read.
+     The last 4 bytes are the checksum.  */
+  porigout = pout;
+  pinend = pin + sin;
+  poutend = pout + sout;
+  while ((pinend - pin) > 4)
+    {
+      uint64_t val;
+      unsigned int bits;
+      int last;
+
+      /* Read the two byte zlib header.  */
+
+      if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding.  */
+       {
+         /* Unknown compression method.  */
+         elf_zlib_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 ();
+         return 0;
+       }
+      if (unlikely ((pin[1] & 0x20) != 0))
+       {
+         /* Stream expects a predefined dictionary, but we have no
+            dictionary.  */
+         elf_zlib_failed ();
+         return 0;
+       }
+      val = (pin[0] << 8) | pin[1];
+      if (unlikely (val % 31 != 0))
+       {
+         /* Header check failure.  */
+         elf_zlib_failed ();
+         return 0;
+       }
+      pin += 2;
+
+      /* Align PIN to a 32-bit boundary.  */
+
+      val = 0;
+      bits = 0;
+      while ((((uintptr_t) pin) & 3) != 0)
+       {
+         val |= (uint64_t)*pin << bits;
+         bits += 8;
+         ++pin;
+       }
+
+      /* Read blocks until one is marked last.  */
+
+      last = 0;
+
+      while (!last)
+       {
+         unsigned int type;
+         const uint16_t *tlit;
+         const uint16_t *tdist;
+
+         if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+           return 0;
+
+         last = val & 1;
+         type = (val >> 1) & 3;
+         val >>= 3;
+         bits -= 3;
+
+         if (unlikely (type == 3))
+           {
+             /* Invalid block type.  */
+             elf_zlib_failed ();
+             return 0;
+           }
+
+         if (type == 0)
+           {
+             uint16_t len;
+             uint16_t lenc;
+
+             /* An uncompressed block.  */
+
+             /* If we've read ahead more than a byte, back up.  */
+             while (bits > 8)
+               {
+                 --pin;
+                 bits -= 8;
+               }
+
+             val = 0;
+             bits = 0;
+             if (unlikely ((pinend - pin) < 4))
+               {
+                 /* Missing length.  */
+                 elf_zlib_failed ();
+                 return 0;
+               }
+             len = pin[0] | (pin[1] << 8);
+             lenc = pin[2] | (pin[3] << 8);
+             pin += 4;
+             lenc = ~lenc;
+             if (unlikely (len != lenc))
+               {
+                 /* Corrupt data.  */
+                 elf_zlib_failed ();
+                 return 0;
+               }
+             if (unlikely (len > (unsigned int) (pinend - pin)
+                           || len > (unsigned int) (poutend - pout)))
+               {
+                 /* Not enough space in buffers.  */
+                 elf_zlib_failed ();
+                 return 0;
+               }
+             memcpy (pout, pin, len);
+             pout += len;
+             pin += len;
+
+             /* Align PIN.  */
+             while ((((uintptr_t) pin) & 3) != 0)
+               {
+                 val |= (uint64_t)*pin << bits;
+                 bits += 8;
+                 ++pin;
+               }
+
+             /* Go around to read the next block.  */
+             continue;
+           }
+
+         if (type == 1)
+           {
+             tlit = elf_zlib_default_table;
+             tdist = elf_zlib_default_dist_table;
+           }
+         else
+           {
+             unsigned int nlit;
+             unsigned int ndist;
+             unsigned int nclen;
+             unsigned char codebits[19];
+             unsigned char *plenbase;
+             unsigned char *plen;
+             unsigned char *plenend;
+
+             /* Read a Huffman encoding table.  The various magic
+                numbers here are from RFC 1951.  */
+
+             if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+               return 0;
+
+             nlit = (val & 0x1f) + 257;
+             val >>= 5;
+             ndist = (val & 0x1f) + 1;
+             val >>= 5;
+             nclen = (val & 0xf) + 4;
+             val >>= 4;
+             bits -= 14;
+             if (unlikely (nlit > 286 || ndist > 30))
+               {
+                 /* Values out of range.  */
+                 elf_zlib_failed ();
+                 return 0;
+               }
+
+             /* Read and build the table used to compress the
+                literal, length, and distance codes.  */
+
+             memset(&codebits[0], 0, 19);
+
+             /* There are always at least 4 elements in the
+                table.  */
+
+             if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+               return 0;
+
+             codebits[16] = val & 7;
+             codebits[17] = (val >> 3) & 7;
+             codebits[18] = (val >> 6) & 7;
+             codebits[0] = (val >> 9) & 7;
+             val >>= 12;
+             bits -= 12;
+
+             if (nclen == 4)
+               goto codebitsdone;
+
+             codebits[8] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 5)
+               goto codebitsdone;
+
+             if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+               return 0;
+
+             codebits[7] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 6)
+               goto codebitsdone;
+
+             codebits[9] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 7)
+               goto codebitsdone;
+
+             codebits[6] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 8)
+               goto codebitsdone;
+
+             codebits[10] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 9)
+               goto codebitsdone;
+
+             codebits[5] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 10)
+               goto codebitsdone;
+
+             if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+               return 0;
+
+             codebits[11] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 11)
+               goto codebitsdone;
+
+             codebits[4] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 12)
+               goto codebitsdone;
+
+             codebits[12] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 13)
+               goto codebitsdone;
+
+             codebits[3] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 14)
+               goto codebitsdone;
+
+             codebits[13] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 15)
+               goto codebitsdone;
+
+             if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+               return 0;
+
+             codebits[2] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 16)
+               goto codebitsdone;
+
+             codebits[14] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 17)
+               goto codebitsdone;
+
+             codebits[1] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+             if (nclen == 18)
+               goto codebitsdone;
+
+             codebits[15] = val & 7;
+             val >>= 3;
+             bits -= 3;
+
+           codebitsdone:
+
+             if (!elf_zlib_inflate_table (codebits, 19, zdebug_table,
+                                          zdebug_table))
+               return 0;
+
+             /* Read the compressed bit lengths of the literal,
+                length, and distance codes.  We have allocated space
+                at the end of zdebug_table to hold them.  */
+
+             plenbase = (((unsigned char *) zdebug_table)
+                         + ZDEBUG_TABLE_CODELEN_OFFSET);
+             plen = plenbase;
+             plenend = plen + nlit + ndist;
+             while (plen < plenend)
+               {
+                 uint16_t t;
+                 unsigned int b;
+                 uint16_t v;
+
+                 if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+                   return 0;
+
+                 t = zdebug_table[val & 0xff];
+
+                 /* The compression here uses bit lengths up to 7, so
+                    a secondary table is never necessary.  */
+                 if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0))
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+
+                 b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+                 val >>= b + 1;
+                 bits -= b + 1;
+
+                 v = t & HUFFMAN_VALUE_MASK;
+                 if (v < 16)
+                   *plen++ = v;
+                 else if (v == 16)
+                   {
+                     unsigned int c;
+                     unsigned int prev;
+
+                     /* Copy previous entry 3 to 6 times.  */
+
+                     if (unlikely (plen == plenbase))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     /* We used up to 7 bits since the last
+                        elf_zlib_fetch, so we have at least 8 bits
+                        available here.  */
+
+                     c = 3 + (val & 0x3);
+                     val >>= 2;
+                     bits -= 2;
+                     if (unlikely ((unsigned int) (plenend - plen) < c))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     prev = plen[-1];
+                     switch (c)
+                       {
+                       case 6:
+                         *plen++ = prev;
+                         /* fallthrough */
+                       case 5:
+                         *plen++ = prev;
+                         /* fallthrough */
+                       case 4:
+                         *plen++ = prev;
+                       }
+                     *plen++ = prev;
+                     *plen++ = prev;
+                     *plen++ = prev;
+                   }
+                 else if (v == 17)
+                   {
+                     unsigned int c;
+
+                     /* Store zero 3 to 10 times.  */
+
+                     /* We used up to 7 bits since the last
+                        elf_zlib_fetch, so we have at least 8 bits
+                        available here.  */
+
+                     c = 3 + (val & 0x7);
+                     val >>= 3;
+                     bits -= 3;
+                     if (unlikely ((unsigned int) (plenend - plen) < c))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     switch (c)
+                       {
+                       case 10:
+                         *plen++ = 0;
+                         /* fallthrough */
+                       case 9:
+                         *plen++ = 0;
+                         /* fallthrough */
+                       case 8:
+                         *plen++ = 0;
+                         /* fallthrough */
+                       case 7:
+                         *plen++ = 0;
+                         /* fallthrough */
+                       case 6:
+                         *plen++ = 0;
+                         /* fallthrough */
+                       case 5:
+                         *plen++ = 0;
+                         /* fallthrough */
+                       case 4:
+                         *plen++ = 0;
+                       }
+                     *plen++ = 0;
+                     *plen++ = 0;
+                     *plen++ = 0;
+                   }
+                 else if (v == 18)
+                   {
+                     unsigned int c;
+
+                     /* Store zero 11 to 138 times.  */
+
+                     /* We used up to 7 bits since the last
+                        elf_zlib_fetch, so we have at least 8 bits
+                        available here.  */
+
+                     c = 11 + (val & 0x7f);
+                     val >>= 7;
+                     bits -= 7;
+                     if (unlikely ((unsigned int) (plenend - plen) < c))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     memset (plen, 0, c);
+                     plen += c;
+                   }
+                 else
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+               }
+
+             /* Make sure that the stop code can appear.  */
+
+             plen = plenbase;
+             if (unlikely (plen[256] == 0))
+               {
+                 elf_zlib_failed ();
+                 return 0;
+               }
+
+             /* Build the decompression tables.  */
+
+             if (!elf_zlib_inflate_table (plen, nlit, zdebug_table,
+                                          zdebug_table))
+               return 0;
+             if (!elf_zlib_inflate_table (plen + nlit, ndist, zdebug_table,
+                                          zdebug_table + HUFFMAN_TABLE_SIZE))
+               return 0;
+             tlit = zdebug_table;
+             tdist = zdebug_table + HUFFMAN_TABLE_SIZE;
+           }
+
+         /* Inflate values until the end of the block.  This is the
+            main loop of the inflation code.  */
+
+         while (1)
+           {
+             uint16_t t;
+             unsigned int b;
+             uint16_t v;
+             unsigned int lit;
+
+             if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+               return 0;
+
+             t = tlit[val & 0xff];
+             b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+             v = t & HUFFMAN_VALUE_MASK;
+
+             if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0)
+               {
+                 lit = v;
+                 val >>= b + 1;
+                 bits -= b + 1;
+               }
+             else
+               {
+                 t = tlit[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];
+                 b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+                 lit = t & HUFFMAN_VALUE_MASK;
+                 val >>= b + 8;
+                 bits -= b + 8;
+               }
+
+             if (lit < 256)
+               {
+                 if (unlikely (pout == poutend))
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+
+                 *pout++ = lit;
+
+                 /* We will need to write the next byte soon.  We ask
+                    for high temporal locality because we will write
+                    to the whole cache line soon.  */
+                 __builtin_prefetch (pout, 1, 3);
+               }
+             else if (lit == 256)
+               {
+                 /* The end of the block.  */
+                 break;
+               }
+             else
+               {
+                 unsigned int dist;
+                 unsigned int len;
+
+                 /* Convert lit into a length.  */
+
+                 if (lit < 265)
+                   len = lit - 257 + 3;
+                 else if (lit == 285)
+                   len = 258;
+                 else if (unlikely (lit > 285))
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+                 else
+                   {
+                     unsigned int extra;
+
+                     if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+                       return 0;
+
+                     /* This is an expression for the table of length
+                        codes in RFC 1951 3.2.5.  */
+                     lit -= 265;
+                     extra = (lit >> 2) + 1;
+                     len = (lit & 3) << extra;
+                     len += 11;
+                     len += ((1U << (extra - 1)) - 1) << 3;
+                     len += val & ((1U << extra) - 1);
+                     val >>= extra;
+                     bits -= extra;
+                   }
+
+                 if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+                   return 0;
+
+                 t = tdist[val & 0xff];
+                 b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+                 v = t & HUFFMAN_VALUE_MASK;
+
+                 if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0)
+                   {
+                     dist = v;
+                     val >>= b + 1;
+                     bits -= b + 1;
+                   }
+                 else
+                   {
+                     t = tdist[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];
+                     b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+                     dist = t & HUFFMAN_VALUE_MASK;
+                     val >>= b + 8;
+                     bits -= b + 8;
+                   }
+
+                 /* Convert dist to a distance.  */
+
+                 if (dist == 0)
+                   {
+                     /* A distance of 1.  A common case, meaning
+                        repeat the last character LEN times.  */
+
+                     if (unlikely (pout == porigout))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     if (unlikely ((unsigned int) (poutend - pout) < len))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     memset (pout, pout[-1], len);
+                     pout += len;
+                   }
+                 else if (unlikely (dist > 29))
+                   {
+                     elf_zlib_failed ();
+                     return 0;
+                   }
+                 else
+                   {
+                     if (dist < 4)
+                       dist = dist + 1;
+                     else
+                       {
+                         unsigned int extra;
+
+                         if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+                           return 0;
+
+                         /* This is an expression for the table of
+                            distance codes in RFC 1951 3.2.5.  */
+                         dist -= 4;
+                         extra = (dist >> 1) + 1;
+                         dist = (dist & 1) << extra;
+                         dist += 5;
+                         dist += ((1U << (extra - 1)) - 1) << 2;
+                         dist += val & ((1U << extra) - 1);
+                         val >>= extra;
+                         bits -= extra;
+                       }
+
+                     /* Go back dist bytes, and copy len bytes from
+                        there.  */
+
+                     if (unlikely ((unsigned int) (pout - porigout) < dist))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     if (unlikely ((unsigned int) (poutend - pout) < len))
+                       {
+                         elf_zlib_failed ();
+                         return 0;
+                       }
+
+                     if (dist >= len)
+                       {
+                         memcpy (pout, pout - dist, len);
+                         pout += len;
+                       }
+                     else
+                       {
+                         while (len > 0)
+                           {
+                             unsigned int copy;
+
+                             copy = len < dist ? len : dist;
+                             memcpy (pout, pout - dist, copy);
+                             len -= copy;
+                             pout += copy;
+                           }
+                       }
+                   }
+               }
+           }
+       }
+    }
+
+  /* We should have filled the output buffer.  */
+  if (unlikely (pout != poutend))
+    {
+      elf_zlib_failed ();
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Verify the zlib checksum.  The checksum is in the 4 bytes at
+   CHECKBYTES, and the uncompressed data is at UNCOMPRESSED /
+   UNCOMPRESSED_SIZE.  Returns 1 on success, 0 on failure.  */
+
+static int
+elf_zlib_verify_checksum (const unsigned char *checkbytes,
+                         const unsigned char *uncompressed,
+                         size_t uncompressed_size)
+{
+  unsigned int i;
+  unsigned int cksum;
+  const unsigned char *p;
+  uint32_t s1;
+  uint32_t s2;
+  size_t hsz;
+
+  cksum = 0;
+  for (i = 0; i < 4; i++)
+    cksum = (cksum << 8) | checkbytes[i];
+
+  s1 = 1;
+  s2 = 0;
+
+  /* Minimize modulo operations.  */
+
+  p = uncompressed;
+  hsz = uncompressed_size;
+  while (hsz >= 5552)
+    {
+      for (i = 0; i < 5552; i += 16)
+       {
+         /* Manually unroll loop 16 times.  */
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+         s1 = s1 + *p++;
+         s2 = s2 + s1;
+       }
+      hsz -= 5552;
+      s1 %= 65521;
+      s2 %= 65521;
+    }
+
+  while (hsz >= 16)
+    {
+      /* Manually unroll loop 16 times.  */
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+
+      hsz -= 16;
+    }
+
+  for (i = 0; i < hsz; ++i)
+    {
+      s1 = s1 + *p++;
+      s2 = s2 + s1;
+    }
+
+  s1 %= 65521;
+  s2 %= 65521;
+
+  if (unlikely ((s2 << 16) + s1 != cksum))
+    {
+      elf_zlib_failed ();
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Inflate a zlib stream from PIN/SIN to POUT/SOUT, and verify the
+   checksum.  Return 1 on success, 0 on error.  */
+
+static int
+elf_zlib_inflate_and_verify (const unsigned char *pin, size_t sin,
+                            uint16_t *zdebug_table, unsigned char *pout,
+                            size_t sout)
+{
+  if (!elf_zlib_inflate (pin, sin, zdebug_table, pout, sout))
+    return 0;
+  if (!elf_zlib_verify_checksum (pin + sin - 4, pout, sout))
+    return 0;
+  return 1;
+}
+
+/* Uncompress the old compressed debug format, the one emitted by
+   --compress-debug-sections=zlib-gnu.  The compressed data is in
+   COMPRESSED / COMPRESSED_SIZE, and the function writes to
+   *UNCOMPRESSED / *UNCOMPRESSED_SIZE.  ZDEBUG_TABLE is work space to
+   hold Huffman tables.  Returns 0 on error, 1 on successful
+   decompression or if something goes wrong.  In general we try to
+   carry on, by returning 1, even if we can't decompress.  */
+
+static int
+elf_uncompress_zdebug (struct backtrace_state *state,
+                      const unsigned char *compressed, size_t compressed_size,
+                      uint16_t *zdebug_table,
+                      backtrace_error_callback error_callback, void *data,
+                      unsigned char **uncompressed, size_t *uncompressed_size)
+{
+  size_t sz;
+  size_t i;
+  unsigned char *po;
+
+  *uncompressed = NULL;
+  *uncompressed_size = 0;
+
+  /* The format starts with the four bytes ZLIB, followed by the 8
+     byte length of the uncompressed data in big-endian order,
+     followed by a zlib stream.  */
+
+  if (compressed_size < 12 || memcmp (compressed, "ZLIB", 4) != 0)
+    return 1;
+
+  sz = 0;
+  for (i = 0; i < 8; i++)
+    sz = (sz << 8) | compressed[i + 4];
+
+  if (*uncompressed != NULL && *uncompressed_size >= sz)
+    po = *uncompressed;
+  else
+    {
+      po = (unsigned char *) backtrace_alloc (state, sz, error_callback, data);
+      if (po == NULL)
+       return 0;
+    }
+
+  if (!elf_zlib_inflate_and_verify (compressed + 12, compressed_size - 12,
+                                   zdebug_table, po, sz))
+    return 1;
+
+  *uncompressed = po;
+  *uncompressed_size = sz;
+
+  return 1;
+}
+
+/* Uncompress the new compressed debug format, the official standard
+   ELF approach emitted by --compress-debug-sections=zlib-gabi.  The
+   compressed data is in COMPRESSED / COMPRESSED_SIZE, and the
+   function writes to *UNCOMPRESSED / *UNCOMPRESSED_SIZE.
+   ZDEBUG_TABLE is work space as for elf_uncompress_zdebug.  Returns 0
+   on error, 1 on successful decompression or if something goes wrong.
+   In general we try to carry on, by returning 1, even if we can't
+   decompress.  */
+
+static int
+elf_uncompress_chdr (struct backtrace_state *state,
+                    const unsigned char *compressed, size_t compressed_size,
+                    uint16_t *zdebug_table,
+                    backtrace_error_callback error_callback, void *data,
+                    unsigned char **uncompressed, size_t *uncompressed_size)
+{
+  const b_elf_chdr *chdr;
+  unsigned char *po;
+
+  *uncompressed = NULL;
+  *uncompressed_size = 0;
+
+  /* The format starts with an ELF compression header.  */
+  if (compressed_size < sizeof (b_elf_chdr))
+    return 1;
+
+  chdr = (const b_elf_chdr *) compressed;
+
+  if (chdr->ch_type != ELFCOMPRESS_ZLIB)
+    {
+      /* Unsupported compression algorithm.  */
+      return 1;
+    }
+
+  if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size)
+    po = *uncompressed;
+  else
+    {
+      po = (unsigned char *) backtrace_alloc (state, chdr->ch_size,
+                                             error_callback, data);
+      if (po == NULL)
+       return 0;
+    }
+
+  if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr),
+                                   compressed_size - sizeof (b_elf_chdr),
+                                   zdebug_table, po, chdr->ch_size))
+    return 1;
+
+  *uncompressed = po;
+  *uncompressed_size = chdr->ch_size;
+
+  return 1;
+}
+
+/* This function is a hook for testing the zlib support.  It is only
+   used by tests.  */
+
+int
+backtrace_uncompress_zdebug (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)
+{
+  uint16_t *zdebug_table;
+  int ret;
+
+  zdebug_table = ((uint16_t *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+                                               error_callback, data));
+  if (zdebug_table == NULL)
+    return 0;
+  ret = elf_uncompress_zdebug (state, compressed, compressed_size,
+                              zdebug_table, error_callback, data,
+                              uncompressed, uncompressed_size);
+  backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,
+                 error_callback, data);
+  return ret;
+}
+
 /* 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
@@ -1011,6 +2631,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
   off_t max_offset;
   struct backtrace_view debug_view;
   int debug_view_valid;
+  unsigned int using_debug_view;
+  uint16_t *zdebug_table;
 
   *found_sym = 0;
   *found_dwarf = 0;
@@ -1174,6 +2796,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
            {
              sections[j].offset = shdr->sh_offset;
              sections[j].size = shdr->sh_size;
+             sections[j].compressed = (shdr->sh_flags & SHF_COMPRESSED) != 0;
              break;
            }
        }
@@ -1284,8 +2907,6 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
       elf_add_syminfo_data (state, sdata);
     }
 
-  /* FIXME: Need to handle compressed debug sections.  */
-
   backtrace_release_view (state, &shdrs_view, error_callback, data);
   shdrs_view_valid = 0;
   backtrace_release_view (state, &names_view, error_callback, data);
@@ -1373,13 +2994,94 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
     goto fail;
   descriptor = -1;
 
+  using_debug_view = 0;
   for (i = 0; i < (int) DEBUG_MAX; ++i)
     {
       if (sections[i].size == 0)
        sections[i].data = NULL;
       else
-       sections[i].data = ((const unsigned char *) debug_view.data
-                           + (sections[i].offset - min_offset));
+       {
+         sections[i].data = ((const unsigned char *) debug_view.data
+                             + (sections[i].offset - min_offset));
+         if (i < ZDEBUG_INFO)
+           ++using_debug_view;
+       }
+    }
+
+  /* Uncompress the old format (--compress-debug-sections=zlib-gnu).  */
+
+  zdebug_table = NULL;
+  for (i = 0; i < ZDEBUG_INFO; ++i)
+    {
+      struct debug_section_info *pz;
+
+      pz = &sections[i + ZDEBUG_INFO - DEBUG_INFO];
+      if (sections[i].size == 0 && pz->size > 0)
+       {
+         unsigned char *uncompressed_data;
+         size_t uncompressed_size;
+
+         if (zdebug_table == NULL)
+           {
+             zdebug_table = ((uint16_t *)
+                             backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+                                              error_callback, data));
+             if (zdebug_table == NULL)
+               goto fail;
+           }
+
+         uncompressed_data = NULL;
+         uncompressed_size = 0;
+         if (!elf_uncompress_zdebug (state, pz->data, pz->size, zdebug_table,
+                                     error_callback, data,
+                                     &uncompressed_data, &uncompressed_size))
+           goto fail;
+         sections[i].data = uncompressed_data;
+         sections[i].size = uncompressed_size;
+         sections[i].compressed = 0;
+       }
+    }
+
+  /* Uncompress the official ELF format
+     (--compress-debug-sections=zlib-gabi).  */
+  for (i = 0; i < ZDEBUG_INFO; ++i)
+    {
+      unsigned char *uncompressed_data;
+      size_t uncompressed_size;
+
+      if (sections[i].size == 0 || !sections[i].compressed)
+       continue;
+
+      if (zdebug_table == NULL)
+       {
+         zdebug_table = ((uint16_t *)
+                         backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+                                          error_callback, data));
+         if (zdebug_table == NULL)
+           goto fail;
+       }
+
+      uncompressed_data = NULL;
+      uncompressed_size = 0;
+      if (!elf_uncompress_chdr (state, sections[i].data, sections[i].size,
+                               zdebug_table, error_callback, data,
+                               &uncompressed_data, &uncompressed_size))
+       goto fail;
+      sections[i].data = uncompressed_data;
+      sections[i].size = uncompressed_size;
+      sections[i].compressed = 0;
+
+      --using_debug_view;
+    }
+
+  if (zdebug_table != NULL)
+    backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,
+                   error_callback, data);
+
+  if (debug_view_valid && using_debug_view == 0)
+    {
+      backtrace_release_view (state, &debug_view, error_callback, data);
+      debug_view_valid = 0;
     }
 
   if (!backtrace_dwarf_add (state, base_address,
index 0a35921..8ae0be5 100644 (file)
@@ -292,4 +292,13 @@ extern int backtrace_dwarf_add (struct backtrace_state *state,
                                backtrace_error_callback error_callback,
                                void *data, fileline *fileline_fn);
 
+/* A test-only hook for elf_uncompress_zdebug.  */
+
+extern int backtrace_uncompress_zdebug (struct backtrace_state *,
+                                       const unsigned char *compressed,
+                                       size_t compressed_size,
+                                       backtrace_error_callback, void *data,
+                                       unsigned char **uncompressed,
+                                       size_t *uncompressed_size);
+
 #endif
index f752391..f84bf26 100644 (file)
@@ -124,9 +124,16 @@ typedef struct {
 
 #endif /* BACKTRACE_XCOFF_SIZE != 32 */
 
+#define STYP_DWARF     0x10    /* DWARF debugging section.  */
 #define STYP_TEXT      0x20    /* Executable text (code) section.  */
 #define STYP_OVRFLO    0x8000  /* Line-number field overflow section.  */
 
+#define SSUBTYP_DWINFO 0x10000 /* DWARF info section.  */
+#define SSUBTYP_DWLINE 0x20000 /* DWARF line-number section.  */
+#define SSUBTYP_DWARNGE        0x50000 /* DWARF aranges section.  */
+#define SSUBTYP_DWABREV        0x60000 /* DWARF abbreviation section.  */
+#define SSUBTYP_DWSTR  0x70000 /* DWARF strings section.  */
+
 /* XCOFF symbol.  */
 
 #define SYMNMLEN       8
@@ -367,6 +374,29 @@ struct xcoff_fileline_data
   struct xcoff_line_vector vec;
 };
 
+/* An index of DWARF sections we care about.  */
+
+enum dwarf_section
+{
+  DWSECT_INFO,
+  DWSECT_LINE,
+  DWSECT_ABBREV,
+  DWSECT_RANGES,
+  DWSECT_STR,
+  DWSECT_MAX
+};
+
+/* Information we gather for the DWARF sections we care about.  */
+
+struct dwsect_info
+{
+  /* Section file offset.  */
+  off_t offset;
+  /* Section size.  */
+  size_t size;
+  /* Section contents, after read from file.  */
+  const unsigned char *data;
+};
 
 /* A dummy callback function used when we can't find any debug info.  */
 
@@ -1056,12 +1086,16 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
   struct backtrace_view linenos_view;
   struct backtrace_view syms_view;
   struct backtrace_view str_view;
+  struct backtrace_view dwarf_view;
   b_xcoff_filhdr fhdr;
   const b_xcoff_scnhdr *sects;
   const b_xcoff_scnhdr *stext;
   uint64_t lnnoptr;
   uint32_t nlnno;
   off_t str_off;
+  off_t min_offset;
+  off_t max_offset;
+  struct dwsect_info dwsect[DWSECT_MAX];
   size_t sects_size;
   size_t syms_size;
   int32_t str_size;
@@ -1069,6 +1103,7 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
   int linenos_view_valid;
   int syms_view_valid;
   int str_view_valid;
+  int dwarf_view_valid;
   int magic_ok;
   int i;
 
@@ -1078,6 +1113,9 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
   linenos_view_valid = 0;
   syms_view_valid = 0;
   str_view_valid = 0;
+  dwarf_view_valid = 0;
+
+  str_size = 0;
 
   /* Map the XCOFF file header.  */
   if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr),
@@ -1092,7 +1130,7 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
   if (!magic_ok)
     {
       if (exe)
-        error_callback (data, "executable file is not XCOFF", 0);
+       error_callback (data, "executable file is not XCOFF", 0);
       goto fail;
     }
 
@@ -1114,8 +1152,8 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
 
   /* FIXME: assumes only one .text section.  */
   for (i = 0; i < fhdr.f_nscns; ++i)
-      if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
-         break;
+    if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
+      break;
   if (i == fhdr.f_nscns)
     goto fail;
 
@@ -1134,12 +1172,12 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
       /* Find the matching .ovrflo section.  */
       for (i = 0; i < fhdr.f_nscns; ++i)
        {
-           if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
-               && sects[i].s_nlnno == sntext)
-             {
-               nlnno = sects[i].s_vaddr;
-               break;
-             }
+         if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
+             && sects[i].s_nlnno == sntext)
+           {
+             nlnno = sects[i].s_vaddr;
+             break;
+           }
        }
     }
 #endif
@@ -1194,9 +1232,91 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
       xcoff_add_syminfo_data (state, sdata);
     }
 
-  /* Read the line number entries.  */
+  /* Read all the DWARF sections in a single view, since they are
+     probably adjacent in the file.  We never release this view.  */
+
+  min_offset = 0;
+  max_offset = 0;
+  memset (dwsect, 0, sizeof dwsect);
+  for (i = 0; i < fhdr.f_nscns; ++i)
+    {
+      off_t end;
+      int idx;
+
+      if ((sects[i].s_flags & 0xffff) != STYP_DWARF
+         || sects[i].s_size == 0)
+       continue;
+      /* Map DWARF section to array index.  */
+      switch (sects[i].s_flags & 0xffff0000)
+       {
+         case SSUBTYP_DWINFO:
+           idx = DWSECT_INFO;
+           break;
+         case SSUBTYP_DWLINE:
+           idx = DWSECT_LINE;
+           break;
+         case SSUBTYP_DWABREV:
+           idx = DWSECT_ABBREV;
+           break;
+         case SSUBTYP_DWARNGE:
+           idx = DWSECT_RANGES;
+           break;
+         case SSUBTYP_DWSTR:
+           idx = DWSECT_STR;
+           break;
+         default:
+           continue;
+       }
+      if (min_offset == 0 || (off_t) sects[i].s_scnptr < min_offset)
+       min_offset = sects[i].s_scnptr;
+      end = sects[i].s_scnptr + sects[i].s_size;
+      if (end > max_offset)
+       max_offset = end;
+      dwsect[idx].offset = sects[i].s_scnptr;
+      dwsect[idx].size = sects[i].s_size;
+    }
+  if (min_offset != 0 && max_offset != 0)
+    {
+      if (!backtrace_get_view (state, descriptor, offset + min_offset,
+                              max_offset - min_offset,
+                              error_callback, data, &dwarf_view))
+       goto fail;
+      dwarf_view_valid = 1;
+
+      for (i = 0; i < (int) DWSECT_MAX; ++i)
+       {
+         if (dwsect[i].offset == 0)
+           dwsect[i].data = NULL;
+         else
+           dwsect[i].data = ((const unsigned char *) dwarf_view.data
+                             + (dwsect[i].offset - min_offset));
+       }
+
+      if (!backtrace_dwarf_add (state, 0,
+                               dwsect[DWSECT_INFO].data,
+                               dwsect[DWSECT_INFO].size,
+#if BACKTRACE_XCOFF_SIZE == 32
+                               /* XXX workaround for broken lineoff */
+                               dwsect[DWSECT_LINE].data - 4,
+#else
+                               /* XXX workaround for broken lineoff */
+                               dwsect[DWSECT_LINE].data - 12,
+#endif
+                               dwsect[DWSECT_LINE].size,
+                               dwsect[DWSECT_ABBREV].data,
+                               dwsect[DWSECT_ABBREV].size,
+                               dwsect[DWSECT_RANGES].data,
+                               dwsect[DWSECT_RANGES].size,
+                               dwsect[DWSECT_STR].data,
+                               dwsect[DWSECT_STR].size,
+                               1, /* big endian */
+                               error_callback, data, fileline_fn))
+       goto fail;
+    }
+
+  /* Read the XCOFF line number entries if DWARF sections not found.  */
 
-  if (fhdr.f_symptr != 0 && lnnoptr != 0)
+  if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0)
     {
       size_t linenos_size = (size_t) nlnno * LINESZ;
 
@@ -1239,6 +1359,8 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
     backtrace_release_view (state, &syms_view, error_callback, data);
   if (linenos_view_valid)
     backtrace_release_view (state, &linenos_view, error_callback, data);
+  if (dwarf_view_valid)
+    backtrace_release_view (state, &dwarf_view, error_callback, data);
   if (descriptor != -1 && offset == 0)
     backtrace_close (descriptor, error_callback, data);
   return 0;
diff --git a/libbacktrace/ztest.c b/libbacktrace/ztest.c
new file mode 100644 (file)
index 0000000..a3d105d
--- /dev/null
@@ -0,0 +1,537 @@
+/* ztest.c -- Test for libbacktrace inflate code.
+   Copyright (C) 2017 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.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 ZLIB_CLOCK_GETTIME_ARG CLOCK_PROCESS_CPUTIME_ID
+#else
+#define ZLIB_CLOCK_GETTIME_ARG CLOCK_REALTIME
+#endif
+
+/* Some tests for the local zlib inflation code.  */
+
+struct zlib_test
+{
+  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, 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 zlib_test tests[] =
+{
+  {
+    "empty",
+    "",
+    0,
+    "\x78\x9c\x03\x00\x00\x00\x00\x01",
+    8,
+  },
+  {
+    "hello",
+    "hello, world\n",
+    0,
+    ("\x78\x9c\xca\x48\xcd\xc9\xc9\xd7\x51\x28\xcf"
+     "\x2f\xca\x49\xe1\x02\x04\x00\x00\xff\xff\x21\xe7\x04\x93"),
+    25,
+  },
+  {
+    "goodbye",
+    "goodbye, world",
+    0,
+    ("\x78\x9c\x4b\xcf\xcf\x4f\x49\xaa"
+     "\x4c\xd5\x51\x28\xcf\x2f\xca\x49"
+     "\x01\x00\x28\xa5\x05\x5e"),
+    22,
+  },
+  {
+    "ranges",
+    ("\xcc\x11\x00\x00\x00\x00\x00\x00\xd5\x13\x00\x00\x00\x00\x00\x00"
+     "\x1c\x14\x00\x00\x00\x00\x00\x00\x72\x14\x00\x00\x00\x00\x00\x00"
+     "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00"
+     "\x0c\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00"
+     "\x29\x14\x00\x00\x00\x00\x00\x00\x4e\x14\x00\x00\x00\x00\x00\x00"
+     "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\xfb\x12\x00\x00\x00\x00\x00\x00\x09\x13\x00\x00\x00\x00\x00\x00"
+     "\x67\x13\x00\x00\x00\x00\x00\x00\xcb\x13\x00\x00\x00\x00\x00\x00"
+     "\x9d\x14\x00\x00\x00\x00\x00\x00\xd5\x14\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\x5f\x0b\x00\x00\x00\x00\x00\x00\x6c\x0b\x00\x00\x00\x00\x00\x00"
+     "\x7d\x0b\x00\x00\x00\x00\x00\x00\x7e\x0c\x00\x00\x00\x00\x00\x00"
+     "\x38\x0f\x00\x00\x00\x00\x00\x00\x5c\x0f\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\x83\x0c\x00\x00\x00\x00\x00\x00\xfa\x0c\x00\x00\x00\x00\x00\x00"
+     "\xfd\x0d\x00\x00\x00\x00\x00\x00\xef\x0e\x00\x00\x00\x00\x00\x00"
+     "\x14\x0f\x00\x00\x00\x00\x00\x00\x38\x0f\x00\x00\x00\x00\x00\x00"
+     "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00"
+     "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\xfd\x0d\x00\x00\x00\x00\x00\x00\xd8\x0e\x00\x00\x00\x00\x00\x00"
+     "\x9f\x0f\x00\x00\x00\x00\x00\x00\xac\x0f\x00\x00\x00\x00\x00\x00"
+     "\xdb\x0f\x00\x00\x00\x00\x00\x00\xff\x0f\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\xfa\x0c\x00\x00\x00\x00\x00\x00\xea\x0d\x00\x00\x00\x00\x00\x00"
+     "\xef\x0e\x00\x00\x00\x00\x00\x00\x14\x0f\x00\x00\x00\x00\x00\x00"
+     "\x5c\x0f\x00\x00\x00\x00\x00\x00\x9f\x0f\x00\x00\x00\x00\x00\x00"
+     "\xac\x0f\x00\x00\x00\x00\x00\x00\xdb\x0f\x00\x00\x00\x00\x00\x00"
+     "\xff\x0f\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\x60\x11\x00\x00\x00\x00\x00\x00\xd1\x16\x00\x00\x00\x00\x00\x00"
+     "\x40\x0b\x00\x00\x00\x00\x00\x00\x2c\x10\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\x7a\x00\x00\x00\x00\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x00\x00"
+     "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+     "\x7a\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00"
+     "\x9f\x01\x00\x00\x00\x00\x00\x00\xa7\x01\x00\x00\x00\x00\x00\x00"
+     "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
+    672,
+    ("\x78\x9c\x3b\x23\xc8\x00\x06\x57\x85\x21\xb4\x8c\x08\x84\x2e\x82"
+     "\xd2\x73\xa1\xf4\x55\x28\x8d\x0e\x7e\x0b\x41\x68\x4e\xa8\x7e\x1e"
+     "\x28\x7d\x1a\x4a\x6b\x42\xf5\xf9\x91\x69\x5e\x3a\x9a\x79\x84\xf4"
+     "\xc7\x73\x43\xe8\x1c\x28\x5d\x0b\xa5\xeb\x78\x20\xb4\x05\x3f\x84"
+     "\x8e\xe1\xc7\xae\xbf\x19\xaa\xee\x17\x94\xfe\xcb\x0b\xa1\xdf\xf3"
+     "\x41\x68\x11\x7e\x54\x73\xe6\x43\xe9\x35\x50\xfa\x36\x94\xfe\x8f"
+     "\xc3\x7c\x98\x79\x37\xf8\xc8\xd3\x0f\x73\xd7\x2b\x1c\xee\x8a\x21"
+     "\xd2\x5d\x3a\x02\xd8\xcd\x4f\x80\xa6\x87\x8b\x62\x10\xda\x81\x1b"
+     "\xbf\xfa\x2a\x28\xbd\x0d\x4a\xcf\x67\x84\xd0\xcb\x19\xf1\xab\x5f"
+     "\x49\xa4\x7a\x00\x48\x97\x29\xd4"),
+    152,
+  }
+};
+
+/* 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)
+    {
+      char *p;
+      size_t v;
+      size_t j;
+      unsigned char *uncompressed;
+      size_t uncompressed_len;
+
+      p = malloc (12 + tests[i].compressed_len);
+      memcpy (p, "ZLIB", 4);
+      v = tests[i].uncompressed_len;
+      if (v == 0)
+       v = strlen (tests[i].uncompressed);
+      for (j = 0; j < 8; ++j)
+       p[j + 4] = (v >> ((7 - j) * 8)) & 0xff;
+      memcpy (p + 12, tests[i].compressed, tests[i].compressed_len);
+      uncompressed = NULL;
+      uncompressed_len = 0;
+      if (!backtrace_uncompress_zdebug (state, (unsigned char *) p,
+                                       tests[i].compressed_len + 12,
+                                       error_callback_compress, NULL,
+                                       &uncompressed, &uncompressed_len))
+       {
+         fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
+         ++failures;
+       }
+      else
+       {
+         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: inflate %s\n", tests[i].name);
+
+         backtrace_free (state, uncompressed, uncompressed_len,
+                         error_callback_compress, NULL);
+       }
+    }
+}
+
+#ifdef HAVE_ZLIB
+
+/* 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)
+{
+#ifdef HAVE_ZLIB
+  unsigned char *orig_buf;
+  size_t orig_bufsize;
+  size_t i;
+  char *compressed_buf;
+  size_t compressed_bufsize;
+  unsigned long compress_sizearg;
+  unsigned char *uncompressed_buf;
+  size_t uncompressed_bufsize;
+  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[] = {
+    "Mark.Twain-Tom.Sawyer.txt",
+    "../libgo/go/compress/testdata/Mark.Twain-Tom.Sawyer.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 = rbuf;
+         orig_bufsize = got;
+         break;
+       }
+      free (rbuf);
+    }
+
+  if (orig_buf == NULL)
+    {
+      /* We couldn't find an input file.  */
+      printf ("UNSUPPORTED: inflate large\n");
+      return;
+    }
+
+  compressed_bufsize = compressBound (orig_bufsize) + 12;
+  compressed_buf = malloc (compressed_bufsize);
+  if (compressed_buf == NULL)
+    {
+      perror ("malloc");
+      goto fail;
+    }
+
+  compress_sizearg = compressed_bufsize - 12;
+  r = compress (compressed_buf + 12, &compress_sizearg,
+               orig_buf, orig_bufsize);
+  if (r != Z_OK)
+    {
+      fprintf (stderr, "zlib compress failed: %d\n", r);
+      goto fail;
+    }
+
+  compressed_bufsize = compress_sizearg + 12;
+
+  /* Prepare the header that our library expects.  */
+  memcpy (compressed_buf, "ZLIB", 4);
+  for (i = 0; i < 8; ++i)
+    compressed_buf[i + 4] = (orig_bufsize >> ((7 - i) * 8)) & 0xff;
+
+  uncompressed_buf = malloc (orig_bufsize);
+  if (uncompressed_buf == NULL)
+    {
+      perror ("malloc");
+      goto fail;
+    }
+  uncompressed_bufsize = orig_bufsize;
+
+  if (!backtrace_uncompress_zdebug (state, compressed_buf, compressed_bufsize,
+                                   error_callback_compress, NULL,
+                                   &uncompressed_buf, &uncompressed_bufsize))
+    {
+      fprintf (stderr, "inflate large: backtrace_uncompress_zdebug failed\n");
+      goto fail;
+    }
+
+  if (uncompressed_bufsize != orig_bufsize)
+    {
+      fprintf (stderr,
+              "inflate 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, "inflate large: uncompressed data mismatch\n");
+      goto fail;
+    }
+
+  printf ("PASS: inflate large\n");
+
+  for (i = 0; i < trials; ++i)
+    {
+      unsigned long uncompress_sizearg;
+
+      cid = ZLIB_CLOCK_GETTIME_ARG;
+      if (clock_gettime (cid, &ts1) < 0)
+       {
+         if (errno == EINVAL)
+           return;
+         perror ("clock_gettime");
+         return;
+       }
+
+      if (!backtrace_uncompress_zdebug (state, compressed_buf,
+                                       compressed_bufsize,
+                                       error_callback_compress, NULL,
+                                       &uncompressed_buf,
+                                       &uncompressed_bufsize))
+       {
+         fprintf (stderr,
+                  ("inflate large: "
+                   "benchmark backtrace_uncompress_zdebug 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;
+
+      if (clock_gettime (cid, &ts1) < 0)
+       {
+         perror("clock_gettime");
+         return;
+       }
+
+      uncompress_sizearg = uncompressed_bufsize;
+      r = uncompress (uncompressed_buf, &uncompress_sizearg,
+                     compressed_buf + 12, compressed_bufsize - 12);
+
+      if (clock_gettime (cid, &ts2) < 0)
+       {
+         perror ("clock_gettime");
+         return;
+       }
+
+      if (r != Z_OK)
+       {
+         fprintf (stderr,
+                  "inflate large: benchmark zlib uncompress failed: %d\n",
+                  r);
+         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 ("zlib     : %zu ns\n", ztime);
+  printf ("ratio    : %g\n", (double) ztime / (double) ctime);
+
+  return;
+
+ fail:
+  printf ("FAIL: inflate 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_ZLIB */
+
+ printf ("UNSUPPORTED: inflate large\n");
+
+#endif /* !HAVE_ZLIB */
+}
+
+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);
+}