summaryrefslogtreecommitdiff
path: root/addr2line.c
diff options
context:
space:
mode:
Diffstat (limited to 'addr2line.c')
-rw-r--r--addr2line.c65
1 files changed, 57 insertions, 8 deletions
diff --git a/addr2line.c b/addr2line.c
index fbe64758bc..eb15ef0bfc 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -101,8 +101,12 @@ void *alloca();
#define PATH_MAX 4096
#endif
-#ifndef SHF_COMPRESSED /* compatibility with glibc < 2.22 */
-#define SHF_COMPRESSED 0
+#ifdef SHF_COMPRESSED
+# ifdef HAVE_LIBZ
+# include <zlib.h>
+# endif
+#else /* compatibility with glibc < 2.22 */
+# define SHF_COMPRESSED 0
#endif
PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
@@ -478,6 +482,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 +683,22 @@ 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) {
+#ifdef HAVE_LIBZ
+ 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;
+#endif
+ }
+ 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: