From a20a2b00446d52f86b94e86bc43a1aee3da9f92f Mon Sep 17 00:00:00 2001 From: naruse Date: Mon, 13 Aug 2018 02:56:06 +0000 Subject: [PATCH] support compressed debug_line https://blogs.oracle.com/solaris/elf_section_compression-v2 https://gnu.wildebeest.org/blog/mjw/2016/01/13/elf-libelf-compressed-sections-and-elfutils/ git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64328 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- addr2line.c | 59 +++++++++++++++++++++++++++++++++++++++++++++------- configure.ac | 3 +++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/addr2line.c b/addr2line.c index fbe64758bc..a5b3e22074 100644 --- a/addr2line.c +++ b/addr2line.c @@ -101,7 +101,9 @@ void *alloca(); #define PATH_MAX 4096 #endif -#ifndef SHF_COMPRESSED /* compatibility with glibc < 2.22 */ +#ifdef SHF_COMPRESSED +#include +#else /* compatibility with glibc < 2.22 */ #define SHF_COMPRESSED 0 #endif @@ -478,6 +480,41 @@ follow_debuglink(const char *debuglink, int num_traces, void **traces, fill_lines(num_traces, traces, 0, objp, lines, offset); } +static int +parse_compressed_debug_line(int num_traces, void **traces, + char *debug_line, unsigned long size, + obj_info_t *obj, line_info_t *lines, int offset) +{ + void *uncompressed_debug_line; + ElfW(Chdr) *chdr = (ElfW(Chdr) *)debug_line; + unsigned long destsize = chdr->ch_size; + int ret = 0; + + if (chdr->ch_type != ELFCOMPRESS_ZLIB) { + /* unsupported compression type */ + return -1; + } + + uncompressed_debug_line = malloc(destsize); + if (!uncompressed_debug_line) return -1; + ret = uncompress(uncompressed_debug_line, &destsize, + (const Bytef *)debug_line + sizeof(ElfW(Chdr)), size-sizeof(ElfW(Chdr))); + if (ret != Z_OK) { /* Z_OK = 0 */ + goto finish; + } + ret = parse_debug_line(num_traces, traces, + uncompressed_debug_line, + destsize, + obj, lines, offset); + if (ret) { + goto finish; + } + +finish: + free(uncompressed_debug_line); + return ret ? -1 : 0; +} + /* read file and fill lines */ static uintptr_t fill_lines(int num_traces, void **traces, int check_debuglink, @@ -644,12 +681,20 @@ fill_lines(int num_traces, void **traces, int check_debuglink, goto finish; } - if (!compressed_p && - parse_debug_line(num_traces, traces, - file + debug_line_shdr->sh_offset, - debug_line_shdr->sh_size, - obj, lines, offset)) - goto fail; + if (compressed_p) { + int r = parse_compressed_debug_line(num_traces, traces, + file + debug_line_shdr->sh_offset, + debug_line_shdr->sh_size, + obj, lines, offset); + if (r) goto fail; + } + else { + int r = parse_debug_line(num_traces, traces, + file + debug_line_shdr->sh_offset, + debug_line_shdr->sh_size, + obj, lines, offset); + if (r) goto fail; + } finish: return dladdr_fbase; fail: diff --git a/configure.ac b/configure.ac index 358acbe261..30d6afa9ce 100644 --- a/configure.ac +++ b/configure.ac @@ -2451,6 +2451,9 @@ AS_IF([test "$rb_cv_binary_elf" = yes], [ AC_CHECK_HEADERS([elf.h elf_abi.h]) AS_IF([test $ac_cv_header_elf_h = yes -o $ac_cv_header_elf_abi_h = yes], [ AC_LIBOBJ([addr2line]) + AS_IF([test "x$compress_debug_sections" = xzlib], [ + AC_CHECK_LIB([z], [uncompress]) + ]) ]) ])