From 31ae7b863a8c9566cc6bd718c590195b30b20042 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 15 Feb 2020 17:56:35 -0800 Subject: [PATCH] libbacktrace: sometimes read debug sections individually libbacktrace/ * elf.c (elf_add): If debug sections are very large or far apart, read them individually rather than as a single view. --- libbacktrace/ChangeLog | 5 ++ libbacktrace/elf.c | 102 +++++++++++++++++++++++++++++++++-------- 2 files changed, 88 insertions(+), 19 deletions(-) diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog index 1739be9eedd..277d7c01ff3 100644 --- a/libbacktrace/ChangeLog +++ b/libbacktrace/ChangeLog @@ -1,3 +1,8 @@ +2020-05-09 Ian Lance Taylor + + * elf.c (elf_add): If debug sections are very large or far apart, + read them individually rather than as a single view. + 2020-05-08 Ian Lance Taylor * fileline.c (sysctl_exec_name): New static function. diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 9a866eb5048..eb481c588e7 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -2659,10 +2659,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, uint32_t debugaltlink_buildid_size; off_t min_offset; off_t max_offset; + off_t debug_size; struct backtrace_view debug_view; int debug_view_valid; unsigned int using_debug_view; uint16_t *zdebug_table; + struct backtrace_view split_debug_view[DEBUG_MAX]; + unsigned char split_debug_view_valid[DEBUG_MAX]; struct elf_ppc64_opd_data opd_data, *opd; struct dwarf_sections dwarf_sections; @@ -2687,6 +2690,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, debugaltlink_buildid_data = NULL; debugaltlink_buildid_size = 0; debug_view_valid = 0; + memset (&split_debug_view_valid[0], 0, sizeof split_debug_view_valid); opd = NULL; if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, @@ -3131,6 +3135,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, min_offset = 0; max_offset = 0; + debug_size = 0; for (i = 0; i < (int) DEBUG_MAX; ++i) { off_t end; @@ -3142,6 +3147,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, end = sections[i].offset + sections[i].size; if (end > max_offset) max_offset = end; + debug_size += sections[i].size; } if (zsections[i].size != 0) { @@ -3150,6 +3156,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, end = zsections[i].offset + zsections[i].size; if (end > max_offset) max_offset = end; + debug_size += zsections[i].size; } } if (min_offset == 0 || max_offset == 0) @@ -3159,11 +3166,45 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, return 1; } - if (!backtrace_get_view (state, descriptor, min_offset, - max_offset - min_offset, - error_callback, data, &debug_view)) - goto fail; - debug_view_valid = 1; + /* If the total debug section size is large, assume that there are + gaps between the sections, and read them individually. */ + + if (max_offset - min_offset < 0x20000000 + || max_offset - min_offset < debug_size + 0x10000) + { + if (!backtrace_get_view (state, descriptor, min_offset, + max_offset - min_offset, + error_callback, data, &debug_view)) + goto fail; + debug_view_valid = 1; + } + else + { + memset (&split_debug_view[0], 0, sizeof split_debug_view); + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + struct debug_section_info *dsec; + + if (sections[i].size != 0) + dsec = §ions[i]; + else if (zsections[i].size != 0) + dsec = &zsections[i]; + else + continue; + + if (!backtrace_get_view (state, descriptor, dsec->offset, dsec->size, + error_callback, data, &split_debug_view[i])) + goto fail; + split_debug_view_valid[i] = 1; + + if (sections[i].size != 0) + sections[i].data = ((const unsigned char *) + split_debug_view[i].data); + else + zsections[i].data = ((const unsigned char *) + split_debug_view[i].data); + } + } /* We've read all we need from the executable. */ if (!backtrace_close (descriptor, error_callback, data)) @@ -3171,22 +3212,25 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, descriptor = -1; using_debug_view = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) + if (debug_view_valid) { - if (sections[i].size == 0) - sections[i].data = NULL; - else + for (i = 0; i < (int) DEBUG_MAX; ++i) { - sections[i].data = ((const unsigned char *) debug_view.data - + (sections[i].offset - min_offset)); - ++using_debug_view; - } + if (sections[i].size == 0) + sections[i].data = NULL; + else + { + sections[i].data = ((const unsigned char *) debug_view.data + + (sections[i].offset - min_offset)); + ++using_debug_view; + } - if (zsections[i].size == 0) - zsections[i].data = NULL; - else - zsections[i].data = ((const unsigned char *) debug_view.data - + (zsections[i].offset - min_offset)); + if (zsections[i].size == 0) + zsections[i].data = NULL; + else + zsections[i].data = ((const unsigned char *) debug_view.data + + (zsections[i].offset - min_offset)); + } } /* Uncompress the old format (--compress-debug-sections=zlib-gnu). */ @@ -3218,6 +3262,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, sections[i].data = uncompressed_data; sections[i].size = uncompressed_size; sections[i].compressed = 0; + + if (split_debug_view_valid[i]) + { + backtrace_release_view (state, &split_debug_view[i], + error_callback, data); + split_debug_view_valid[i] = 0; + } } } @@ -3250,7 +3301,14 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, sections[i].size = uncompressed_size; sections[i].compressed = 0; - --using_debug_view; + if (debug_view_valid) + --using_debug_view; + else if (split_debug_view_valid[i]) + { + backtrace_release_view (state, &split_debug_view[i], + error_callback, data); + split_debug_view_valid[i] = 0; + } } if (zdebug_table != NULL) @@ -3297,6 +3355,12 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, backtrace_release_view (state, &buildid_view, error_callback, data); if (debug_view_valid) backtrace_release_view (state, &debug_view, error_callback, data); + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + if (split_debug_view_valid[i]) + backtrace_release_view (state, &split_debug_view[i], + error_callback, data); + } if (opd) backtrace_release_view (state, &opd->view, error_callback, data); if (descriptor != -1)