summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Nazar <nazard@nazar.ca>2019-09-04 23:36:06 -0400
committerDave Watson <dade.watson@gmail.com>2019-10-03 08:18:57 -0700
commita36ec8cfdb8764e4f8bf6b16a149a60ea6ad038d (patch)
treefbdf99561b77a53abef97428e6e60a842405b967
parentb316234d63c7ff6fcfac6d72e0f27394fe86af80 (diff)
downloadlibunwind-a36ec8cfdb8764e4f8bf6b16a149a60ea6ad038d.tar.gz
Add support for zlib compressed elf .debug_frame sections
In case zlib support is not available, fail to load instead of crashing while trying to read invalid data.
-rw-r--r--configure.ac17
-rw-r--r--src/Makefile.am10
-rw-r--r--src/dwarf/Gfind_proc_info-lsb.c50
-rw-r--r--src/unwind/libunwind.pc.in2
4 files changed, 67 insertions, 12 deletions
diff --git a/configure.ac b/configure.ac
index 8e62b8bd..11aeb2d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -302,6 +302,23 @@ fi
AC_SUBST([LIBLZMA])
AM_CONDITIONAL(HAVE_LZMA, test x$enable_minidebuginfo = xyes)
+LIBZ=
+AC_MSG_CHECKING([whether to support ZLIB-compressed symbol tables])
+AC_ARG_ENABLE(zlibdebuginfo,
+AS_HELP_STRING([--enable-zlibdebuginfo], [Enables support for ZLIB-compressed symbol tables]),, [enable_zlibdebuginfo=auto])
+AC_MSG_RESULT([$enable_zlibdebuginfo])
+if test x$enable_zlibdebuginfo != xno; then
+ AC_CHECK_LIB([z], [uncompress],
+ [LIBZ=-lz
+ AC_DEFINE([HAVE_ZLIB], [1], [Define if you have libz])
+ enable_zlibdebuginfo=yes],
+ [if test x$enable_zlibdebuginfo = xyes; then
+ AC_MSG_FAILURE([libz not found])
+ fi])
+fi
+AC_SUBST([LIBZ])
+AM_CONDITIONAL(HAVE_ZLIB, test x$enable_zlibdebuginfo = xyes)
+
AC_MSG_CHECKING([whether to support UNW_CACHE_PER_THREAD])
AC_ARG_ENABLE([per-thread-cache],
AS_HELP_STRING([--enable-per-thread-cache], [build with support for UNW_CACHE_PER_THREAD (which imposes a hight TLS memory usage) (default: disabled)]))
diff --git a/src/Makefile.am b/src/Makefile.am
index bc37b123..ff977446 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,7 +68,7 @@ libunwind_coredump_la_SOURCES = \
coredump/_UPT_resume.c
libunwind_coredump_la_LDFLAGS = $(COMMON_SO_LDFLAGS) \
-version-info $(COREDUMP_SO_VERSION)
-libunwind_coredump_la_LIBADD = $(LIBLZMA)
+libunwind_coredump_la_LIBADD = $(LIBLZMA) $(LIBZ)
noinst_HEADERS += coredump/_UCD_internal.h coredump/_UCD_lib.h
### libunwind-setjmp:
@@ -183,9 +183,9 @@ noinst_HEADERS += elf32.h elf64.h elfxx.h
libunwind_elf32_la_SOURCES = elf32.c
libunwind_elf64_la_SOURCES = elf64.c
libunwind_elfxx_la_SOURCES = elfxx.c
-libunwind_elf32_la_LIBADD = $(LIBLZMA)
-libunwind_elf64_la_LIBADD = $(LIBLZMA)
-libunwind_elfxx_la_LIBADD = $(LIBLZMA)
+libunwind_elf32_la_LIBADD = $(LIBLZMA) $(LIBZ)
+libunwind_elf64_la_LIBADD = $(LIBLZMA) $(LIBZ)
+libunwind_elfxx_la_LIBADD = $(LIBLZMA) $(LIBZ)
noinst_LTLIBRARIES += $(LIBUNWIND_ELF)
libunwind_la_LIBADD += $(LIBUNWIND_ELF)
@@ -732,7 +732,7 @@ endif
libunwind_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -XCClinker -nostdlib \
$(LDFLAGS_STATIC_LIBCXA) -version-info $(SOVERSION)
libunwind_la_LIBADD += -lc $(LIBCRTS)
-libunwind_la_LIBADD += $(LIBLZMA)
+libunwind_la_LIBADD += $(LIBLZMA) $(LIBZ)
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/tdep-$(arch) -I.
AM_CCASFLAGS = $(AM_CPPFLAGS)
diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
index 7d0c70f2..678c80bf 100644
--- a/src/dwarf/Gfind_proc_info-lsb.c
+++ b/src/dwarf/Gfind_proc_info-lsb.c
@@ -34,6 +34,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "dwarf-eh.h"
#include "libunwind_i.h"
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif /* HAVE_ZLIB */
+
struct table_entry
{
int32_t start_ip_offset;
@@ -123,14 +127,48 @@ load_debug_frame (const char *file, char **buf, size_t *bufsize, int is_local)
return 1;
}
- *bufsize = shdr->sh_size;
- GET_MEMORY(*buf, *bufsize);
-
- memcpy(*buf, shdr->sh_offset + ei.image, *bufsize);
+ if (shdr->sh_flags & SHF_COMPRESSED)
+ {
+ unsigned long destSize;
+ Elf_W (Chdr) *chdr = (shdr->sh_offset + ei.image);
+#ifdef HAVE_ZLIB
+ if (chdr->ch_type == ELFCOMPRESS_ZLIB)
+ {
+ *bufsize = destSize = chdr->ch_size;
+ GET_MEMORY(*buf, *bufsize);
+ ret = uncompress((unsigned char *)*buf, &destSize,
+ shdr->sh_offset + ei.image + sizeof(*chdr),
+ shdr->sh_size - sizeof(*chdr));
+ if (ret != Z_OK)
+ {
+ Debug (2, "failed to decompress zlib .debug_frame, skipping\n");
+ munmap(*buf, *bufsize);
+ munmap(ei.image, ei.size);
+ return 1;
+ }
+
+ Debug (4, "read %zd->%zd bytes of .debug_frame from offset %zd\n",
+ shdr->sh_size, *bufsize, shdr->sh_offset);
+ }
+ else
+#endif /* HAVE_ZLIB */
+ {
+ Debug (2, "unknown compression type %d, skipping\n",
+ chdr->ch_type);
+ munmap(ei.image, ei.size);
+ return 1;
+ }
+ }
+ else
+ {
+ *bufsize = shdr->sh_size;
+ GET_MEMORY(*buf, *bufsize);
- Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
- *bufsize, shdr->sh_offset);
+ memcpy(*buf, shdr->sh_offset + ei.image, *bufsize);
+ Debug (4, "read %zd bytes of .debug_frame from offset %zd\n",
+ *bufsize, shdr->sh_offset);
+ }
munmap(ei.image, ei.size);
return 0;
}
diff --git a/src/unwind/libunwind.pc.in b/src/unwind/libunwind.pc.in
index 1505c5d6..9a65faf3 100644
--- a/src/unwind/libunwind.pc.in
+++ b/src/unwind/libunwind.pc.in
@@ -7,5 +7,5 @@ Name: libunwind
Description: libunwind base library
Version: @VERSION@
Libs: -L${libdir} -lunwind
-Libs.private: @LIBLZMA@
+Libs.private: @LIBLZMA@ @LIBZ@
Cflags: -I${includedir}