Hello everyone, following patches add support for XZ-compressed symbol tables, also known as MiniDebugInfo.
In short, MiniDebugInfo-containing binary is created by taking separate debuginfo ELF containing only the symbol table, compressing it with XZ and stuffing it into the .gnu_debugdata section of the binary. This feature will be used in next Fedora release and ABRT (among others), which is planned to be based on libunwind by then, would like to take advantage of it. Some more background can be found here [1].
Please review, I'll be happy to modify the patches according to your suggestions.
Thanks, Martin
[1] http://fedoraproject.org/wiki/Features/MiniDebugInfo [2] https://github.com/b42/libunwind/tree/minidebuginfo
* * *
Martin Milata (5): Make coredump test also test unw_get_proc_name Add liblzma detection to configure script MiniDebugInfo test: tests/run-coredump-unwind-mdi Refactor parts of elfxx.c to allow reusing code Search MiniDebugInfo for procedure names
configure.in | 16 +++ src/Makefile.am | 3 + src/elfxx.c | 279 ++++++++++++++++++++++++++++++++++------- tests/Makefile.am | 7 +- tests/run-coredump-unwind | 47 ++++++- tests/run-coredump-unwind-mdi | 8 ++ tests/test-coredump-unwind.c | 20 +++ 7 files changed, 326 insertions(+), 54 deletions(-) create mode 100755 tests/run-coredump-unwind-mdi
Signed-off-by: Martin Milata mmilata@redhat.com --- tests/run-coredump-unwind | 8 ++------ tests/test-coredump-unwind.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/tests/run-coredump-unwind b/tests/run-coredump-unwind index 18060c5..d6dd7e0 100755 --- a/tests/run-coredump-unwind +++ b/tests/run-coredump-unwind @@ -1,7 +1,8 @@ #!/bin/sh
TESTDIR=`pwd` -TEMPDIR=`mktemp -d` +TEMPDIR=`mktemp --tmpdir -d libunwind-test-XXXXXXXXXX` +trap "rm -r -- $TEMPDIR" EXIT
# create core dump ( @@ -11,10 +12,5 @@ TEMPDIR=`mktemp -d` ) 2>/dev/null COREFILE=$TEMPDIR/core*
-# fail if any command fails -set -e - # magic option -testcase enables checking for the specific contents of the stack ./test-coredump-unwind $COREFILE -testcase `cat $TEMPDIR/backing_files` - -rm -r -- $TEMPDIR diff --git a/tests/test-coredump-unwind.c b/tests/test-coredump-unwind.c index ab1ff03..2b2d4b9 100644 --- a/tests/test-coredump-unwind.c +++ b/tests/test-coredump-unwind.c @@ -269,9 +269,11 @@ main(int argc, char **argv) int ret;
#define TEST_FRAMES 4 +#define TEST_NAME_LEN 16 int testcase = 0; int test_cur = 0; long test_start_ips[TEST_FRAMES]; + char test_names[TEST_FRAMES][TEST_NAME_LEN];
install_sigsegv_handler();
@@ -338,7 +340,13 @@ main(int argc, char **argv)
if (testcase && test_cur < TEST_FRAMES) { + unw_word_t off; + test_start_ips[test_cur] = (long) pi.start_ip; + if (unw_get_proc_name(&c, test_names[test_cur], sizeof(test_names[0]), &off) != 0) + { + test_names[test_cur][0] = '\0'; + } test_cur++; }
@@ -366,6 +374,18 @@ main(int argc, char **argv) return -1; }
+ if (testcase && + ( strcmp(test_names[0], "a") + || strcmp(test_names[1], "b") + || strcmp(test_names[2], "b") + || strcmp(test_names[3], "main") + ) + ) + { + fprintf(stderr, "FAILURE: procedure names are missing/incorrect\n"); + return -1; + } + _UCD_destroy(ui);
return 0;
Signed-off-by: Martin Milata mmilata@redhat.com --- configure.in | 16 ++++++++++++++++ src/Makefile.am | 3 +++ 2 files changed, 19 insertions(+), 0 deletions(-)
diff --git a/configure.in b/configure.in index a1cf650..31bf4bd 100644 --- a/configure.in +++ b/configure.in @@ -236,6 +236,22 @@ if test x$enable_msabi_support = xyes; then fi AC_MSG_RESULT([$enable_msabi_support])
+AC_MSG_CHECKING([whether to support LZMA-compressed symbol tables]) +AC_ARG_ENABLE(minidebuginfo, +AS_HELP_STRING([--enable-minidebuginfo], [Enables support for LZMA-compressed symbol tables]), +[enable_minidebuginfo=$enableval], [enable_minidebuginfo=auto]) +AC_MSG_RESULT([$enable_minidebuginfo]) +if test x$enable_minidebuginfo != xno; then + AC_CHECK_LIB([lzma], [lzma_mf_is_supported], + [AC_SUBST([LIBLZMA], [-lzma]) + AC_DEFINE([HAVE_LZMA], [1], [Define if you have liblzma]) + enable_minidebuginfo=yes], + [if test x$enable_minidebuginfo = xyes; then + AC_MSG_FAILURE([liblzma not found]) + fi]) +fi +AM_CONDITIONAL(HAVE_LZMA, test x$enable_minidebuginfo = xyes) + LIBUNWIND___THREAD
AC_MSG_CHECKING([for Intel compiler]) diff --git a/src/Makefile.am b/src/Makefile.am index b3fd043..6209b23 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -515,6 +515,9 @@ endif libunwind_la_LDFLAGS = $(COMMON_SO_LDFLAGS) -XCClinker -nostdlib \ $(LDFLAGS_STATIC_LIBCXA) -version-info $(SOVERSION) libunwind_la_LIBADD += -lc $(LIBCRTS) +if HAVE_LZMA + libunwind_la_LIBADD += -llzma +endif
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/include/tdep-$(arch) -I. AM_CCASFLAGS = $(AM_CPPFLAGS)
Test that creates MiniDebugInfo-containing binary and then checks if it can recover the procedure names from its coredump.
Signed-off-by: Martin Milata mmilata@redhat.com --- tests/Makefile.am | 7 ++++++- tests/run-coredump-unwind | 39 ++++++++++++++++++++++++++++++++++++++- tests/run-coredump-unwind-mdi | 8 ++++++++ tests/test-coredump-unwind.c | 2 +- 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100755 tests/run-coredump-unwind-mdi
diff --git a/tests/Makefile.am b/tests/Makefile.am index 9dd9a76..40f3185 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2,7 +2,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
EXTRA_DIST = run-ia64-test-dyn1 run-ptrace-mapper run-ptrace-misc \ run-check-namespace run-coredump-unwind \ - check-namespace.sh.in Gtest-nomalloc.c Gtest-nocalloc.c + run-coredump-unwind-mdi check-namespace.sh.in \ + Gtest-nomalloc.c Gtest-nocalloc.c
MAINTAINERCLEANFILES = Makefile.in
@@ -60,6 +61,10 @@ endif if OS_LINUX check_SCRIPTS_cdep += run-coredump-unwind noinst_PROGRAMS_cdep += test-coredump-unwind + +if HAVE_LZMA + check_SCRIPTS_cdep += run-coredump-unwind-mdi +endif endif
perf: perf-startup Gperf-simple Lperf-simple Lperf-trace diff --git a/tests/run-coredump-unwind b/tests/run-coredump-unwind index d6dd7e0..8d07742 100755 --- a/tests/run-coredump-unwind +++ b/tests/run-coredump-unwind @@ -1,14 +1,51 @@ #!/bin/sh
+# this function is slight modification of the one used in RPM +# found at https://bugzilla.redhat.com/show_bug.cgi?id=834073 +# written by Alexander Larsson alexl@redhat.com +add_minidebug() +{ + debuginfo="$1" ## we don't have separate debuginfo file + binary="$1" + + dynsyms=`mktemp` + funcsyms=`mktemp` + keep_symbols=`mktemp` + mini_debuginfo=`mktemp` + + # Extract the dynamic symbols from the main binary, there is no need to also have these + # in the normal symbol table + nm -D "$binary" --format=posix --defined-only | awk '{ print $1 }' | sort > "$dynsyms" + # Extract all the text (i.e. function) symbols from the debuginfo + nm "$debuginfo" --format=posix --defined-only | awk '{ if ($2 == "T" || $2 == "t") print $1 }' | sort > "$funcsyms" + # Keep all the function symbols not already in the dynamic symbol table + comm -13 "$dynsyms" "$funcsyms" > "$keep_symbols" + # Copy the full debuginfo, keeping only a minumal set of symbols and removing some unnecessary sections + objcopy -S --remove-section .gdb_index --remove-section .comment --keep-symbols="$keep_symbols" "$debuginfo" "$mini_debuginfo" &> /dev/null + #Inject the compressed data into the .gnu_debugdata section of the original binary + xz "$mini_debuginfo" + mini_debuginfo="${mini_debuginfo}.xz" + objcopy --add-section .gnu_debugdata="$mini_debuginfo" "$binary" + rm -f "$dynsyms" "$funcsyms" "$keep_symbols" "$mini_debuginfo" + + strip "$binary" ## throw away the symbol table +} + + TESTDIR=`pwd` TEMPDIR=`mktemp --tmpdir -d libunwind-test-XXXXXXXXXX` trap "rm -r -- $TEMPDIR" EXIT
+cp crasher $TEMPDIR/crasher +if [ "$1" = "-minidebuginfo" ]; then + add_minidebug $TEMPDIR/crasher +fi + # create core dump ( cd $TEMPDIR ulimit -c 10000 - $TESTDIR/crasher $TEMPDIR/backing_files + ./crasher backing_files ) 2>/dev/null COREFILE=$TEMPDIR/core*
diff --git a/tests/run-coredump-unwind-mdi b/tests/run-coredump-unwind-mdi new file mode 100755 index 0000000..6b7f0c1 --- /dev/null +++ b/tests/run-coredump-unwind-mdi @@ -0,0 +1,8 @@ +#!/bin/sh + +# This test intends to test the unw_get_proc_name function on binaries without +# the symbol table but with so called MiniDebuginfo available. In particular, +# it is tested using the coredump accessors. For more info about MiniDebugInfo +# see e.g. http://fedoraproject.org/wiki/Features/MiniDebugInfo + +./run-coredump-unwind -minidebuginfo diff --git a/tests/test-coredump-unwind.c b/tests/test-coredump-unwind.c index 2b2d4b9..6e62b8d 100644 --- a/tests/test-coredump-unwind.c +++ b/tests/test-coredump-unwind.c @@ -269,7 +269,7 @@ main(int argc, char **argv) int ret;
#define TEST_FRAMES 4 -#define TEST_NAME_LEN 16 +#define TEST_NAME_LEN 32 int testcase = 0; int test_cur = 0; long test_start_ips[TEST_FRAMES];
Signed-off-by: Martin Milata mmilata@redhat.com --- src/elfxx.c | 123 ++++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 85 insertions(+), 38 deletions(-)
diff --git a/src/elfxx.c b/src/elfxx.c index 2d5aacc..514033d 100644 --- a/src/elfxx.c +++ b/src/elfxx.c @@ -29,6 +29,56 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include "libunwind_i.h"
+static Elf_W (Shdr)* +elf_w (section_table) (struct elf_image *ei) +{ + Elf_W (Ehdr) *ehdr = ei->image; + Elf_W (Off) soff; + + soff = ehdr->e_shoff; + if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size) + { + Debug (1, "section table outside of image? (%lu > %lu)\n", + (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize), + (unsigned long) ei->size); + return NULL; + } + + return (Elf_W (Shdr) *) ((char *) ei->image + soff); +} + +static char* +elf_w (string_table) (struct elf_image *ei, int section) +{ + Elf_W (Ehdr) *ehdr = ei->image; + Elf_W (Off) soff, str_soff; + Elf_W (Shdr) *str_shdr; + + /* this offset is assumed to be OK */ + soff = ehdr->e_shoff; + + str_soff = soff + (section * ehdr->e_shentsize); + if (str_soff + ehdr->e_shentsize > ei->size) + { + Debug (1, "string shdr table outside of image? (%lu > %lu)\n", + (unsigned long) (str_soff + ehdr->e_shentsize), + (unsigned long) ei->size); + return NULL; + } + str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff); + + if (str_shdr->sh_offset + str_shdr->sh_size > ei->size) + { + Debug (1, "string table outside of image? (%lu > %lu)\n", + (unsigned long) (str_shdr->sh_offset + str_shdr->sh_size), + (unsigned long) ei->size); + return NULL; + } + + Debug (16, "strtab=0x%lx\n", (long) str_shdr->sh_offset); + return ei->image + str_shdr->sh_offset; +} + static int elf_w (lookup_symbol) (unw_addr_space_t as, unw_word_t ip, struct elf_image *ei, @@ -38,8 +88,7 @@ elf_w (lookup_symbol) (unw_addr_space_t as, size_t syment_size; Elf_W (Ehdr) *ehdr = ei->image; Elf_W (Sym) *sym, *symtab, *symtab_end; - Elf_W (Off) soff, str_soff; - Elf_W (Shdr) *shdr, *str_shdr; + Elf_W (Shdr) *shdr; Elf_W (Addr) val, min_dist = ~(Elf_W (Addr))0; int i, ret = -UNW_ENOINFO; char *strtab; @@ -47,16 +96,9 @@ elf_w (lookup_symbol) (unw_addr_space_t as, if (!elf_w (valid_object) (ei)) return -UNW_ENOINFO;
- soff = ehdr->e_shoff; - if (soff + ehdr->e_shnum * ehdr->e_shentsize > ei->size) - { - Debug (1, "section table outside of image? (%lu > %lu)\n", - (unsigned long) (soff + ehdr->e_shnum * ehdr->e_shentsize), - (unsigned long) ei->size); - return -UNW_ENOINFO; - } - - shdr = (Elf_W (Shdr) *) ((char *) ei->image + soff); + shdr = elf_w (section_table) (ei); + if (!shdr) + return -UNW_ENOINFO;
for (i = 0; i < ehdr->e_shnum; ++i) { @@ -68,20 +110,12 @@ elf_w (lookup_symbol) (unw_addr_space_t as, symtab_end = (Elf_W (Sym) *) ((char *) symtab + shdr->sh_size); syment_size = shdr->sh_entsize;
- str_soff = soff + (shdr->sh_link * ehdr->e_shentsize); - if (str_soff + ehdr->e_shentsize >= ei->size) - { - Debug (1, "string table outside of image? (%lu >= %lu)\n", - (unsigned long) (str_soff + ehdr->e_shentsize), - (unsigned long) ei->size); - break; - } - str_shdr = (Elf_W (Shdr) *) ((char *) ei->image + str_soff); - strtab = (char *) ei->image + str_shdr->sh_offset; + strtab = elf_w (string_table) (ei, shdr->sh_link); + if (!strtab) + break;
- Debug (16, "symtab=0x%lx[%d], strtab=0x%lx\n", - (long) shdr->sh_offset, shdr->sh_type, - (long) str_shdr->sh_offset); + Debug (16, "symtab=0x%lx[%d]\n", + (long) shdr->sh_offset, shdr->sh_type);
for (sym = symtab; sym < symtab_end; @@ -121,6 +155,28 @@ elf_w (lookup_symbol) (unw_addr_space_t as, return ret; }
+static Elf_W (Addr) +elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase, + unsigned long mapoff) +{ + Elf_W (Addr) offset = 0; + Elf_W (Ehdr) *ehdr; + Elf_W (Phdr) *phdr; + int i; + + ehdr = ei->image; + phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff); + + for (i = 0; i < ehdr->e_phnum; ++i) + if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) + { + offset = segbase - phdr[i].p_vaddr; + break; + } + + return offset; +} + /* Find the ELF image that contains IP and return the "closest" procedure name, if there is one. With some caching, this could be sped up greatly, but until an application materializes that's @@ -133,22 +189,13 @@ elf_w (get_proc_name_in_image) (unw_addr_space_t as, struct elf_image *ei, unw_word_t ip, char *buf, size_t buf_len, unw_word_t *offp) { - Elf_W (Addr) load_offset = 0; - Elf_W (Ehdr) *ehdr; - Elf_W (Phdr) *phdr; - int i, ret; + Elf_W (Addr) load_offset; + int ret;
- ehdr = ei->image; - phdr = (Elf_W (Phdr) *) ((char *) ei->image + ehdr->e_phoff); + load_offset = elf_w (get_load_offset) (ei, segbase, mapoff); + ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp);
- for (i = 0; i < ehdr->e_phnum; ++i) - if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == mapoff) - { - load_offset = segbase - phdr[i].p_vaddr; - break; - }
- ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp);
return ret; }
After searching the normal symbol table, look if the binary contains .gnu_debugdata section. If it does, run LZMA decompression on it, load the resulting ELF image into memory and call lookup_symbol() on it again.
lookup_symbol() is modified so that it takes min_dist as a parameter and only returns a symbol when it finds one that is closer than indicated by the parameter.
Signed-off-by: Martin Milata mmilata@redhat.com --- src/elfxx.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 149 insertions(+), 9 deletions(-)
diff --git a/src/elfxx.c b/src/elfxx.c index 514033d..6060169 100644 --- a/src/elfxx.c +++ b/src/elfxx.c @@ -27,6 +27,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <stdio.h> #include <sys/param.h>
+#ifdef HAVE_LZMA +#include <lzma.h> +#endif /* HAVE_LZMA */ + #include "libunwind_i.h"
static Elf_W (Shdr)* @@ -83,13 +87,13 @@ static int elf_w (lookup_symbol) (unw_addr_space_t as, unw_word_t ip, struct elf_image *ei, Elf_W (Addr) load_offset, - char *buf, size_t buf_len, unw_word_t *offp) + char *buf, size_t buf_len, Elf_W (Addr) *min_dist) { size_t syment_size; Elf_W (Ehdr) *ehdr = ei->image; Elf_W (Sym) *sym, *symtab, *symtab_end; Elf_W (Shdr) *shdr; - Elf_W (Addr) val, min_dist = ~(Elf_W (Addr))0; + Elf_W (Addr) val; int i, ret = -UNW_ENOINFO; char *strtab;
@@ -131,9 +135,9 @@ elf_w (lookup_symbol) (unw_addr_space_t as, Debug (16, "0x%016lx info=0x%02x %s\n", (long) val, sym->st_info, strtab + sym->st_name);
- if ((Elf_W (Addr)) (ip - val) < min_dist) + if ((Elf_W (Addr)) (ip - val) < *min_dist) { - min_dist = (Elf_W (Addr)) (ip - val); + *min_dist = (Elf_W (Addr)) (ip - val); strncpy (buf, strtab + sym->st_name, buf_len); buf[buf_len - 1] = '\0'; ret = (strlen (strtab + sym->st_name) >= buf_len @@ -148,10 +152,6 @@ elf_w (lookup_symbol) (unw_addr_space_t as, } shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); } - if (min_dist >= ei->size) - return -UNW_ENOINFO; /* not found */ - if (offp) - *offp = min_dist; return ret; }
@@ -177,6 +177,123 @@ elf_w (get_load_offset) (struct elf_image *ei, unsigned long segbase, return offset; }
+#if HAVE_LZMA +static size_t +xz_uncompressed_size (uint8_t *compressed, size_t length) +{ + uint64_t memlimit = UINT64_MAX; + size_t ret = 0, pos = 0; + lzma_stream_flags options; + lzma_index *index; + + if (length < LZMA_STREAM_HEADER_SIZE) + return 0; + + uint8_t *footer = compressed + length - LZMA_STREAM_HEADER_SIZE; + if (lzma_stream_footer_decode (&options, footer) != LZMA_OK) + return 0; + + if (length < LZMA_STREAM_HEADER_SIZE + options.backward_size) + return 0; + + uint8_t *indexdata = footer - options.backward_size; + if (lzma_index_buffer_decode (&index, &memlimit, NULL, indexdata, + &pos, options.backward_size) != LZMA_OK) + return 0; + + if (lzma_index_size (index) == options.backward_size) + { + ret = lzma_index_uncompressed_size (index); + } + + lzma_index_end (index, NULL); + return ret; +} + +static int +elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi) +{ + Elf_W (Ehdr) *ehdr = ei->image; + Elf_W (Shdr) *shdr; + char *strtab; + int i; + uint8_t *compressed = NULL; + uint64_t memlimit = UINT64_MAX; /* no memory limit */ + size_t compressed_len, uncompressed_len; + + if (!elf_w (valid_object) (ei)) + return 0; + + shdr = elf_w (section_table) (ei); + if (!shdr) + return 0; + + strtab = elf_w (string_table) (ei, ehdr->e_shstrndx); + if (!strtab) + return 0; + + for (i = 0; i < ehdr->e_shnum; ++i) + { + if (strcmp (strtab + shdr->sh_name, ".gnu_debugdata") == 0) + { + if (shdr->sh_offset + shdr->sh_size > ei->size) + { + Debug (1, ".gnu_debugdata outside image? (0x%lu > 0x%lu)\n", + (unsigned long) shdr->sh_offset + shdr->sh_size, + (unsigned long) ei->size); + return 0; + } + + Debug (16, "found .gnu_debugdata at 0x%lx\n", + (unsigned long) shdr->sh_offset); + compressed = ((uint8_t *) ei->image) + shdr->sh_offset; + compressed_len = shdr->sh_size; + break; + } + + shdr = (Elf_W (Shdr) *) (((char *) shdr) + ehdr->e_shentsize); + } + + /* not found */ + if (!compressed) + return 0; + + uncompressed_len = xz_uncompressed_size (compressed, compressed_len); + if (uncompressed_len == 0) + { + Debug (1, "invalid .gnu_debugdata contents\n"); + return 0; + } + + mdi->size = uncompressed_len; + mdi->image = mmap (NULL, uncompressed_len, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + + if (mdi->image == MAP_FAILED) + return 0; + + size_t in_pos = 0, out_pos = 0; + lzma_ret lret; + lret = lzma_stream_buffer_decode (&memlimit, 0, NULL, + compressed, &in_pos, compressed_len, + mdi->image, &out_pos, mdi->size); + if (lret != LZMA_OK) + { + Debug (1, "LZMA decompression failed: %d\n", lret); + munmap (mdi->image, mdi->size); + return 0; + } + + return 1; +} +#else +static int +elf_w (extract_minidebuginfo) (struct elf_image *ei, struct elf_image *mdi) +{ + return 0; +} +#endif /* !HAVE_LZMA */ + /* Find the ELF image that contains IP and return the "closest" procedure name, if there is one. With some caching, this could be sped up greatly, but until an application materializes that's @@ -190,13 +307,36 @@ elf_w (get_proc_name_in_image) (unw_addr_space_t as, struct elf_image *ei, char *buf, size_t buf_len, unw_word_t *offp) { Elf_W (Addr) load_offset; + Elf_W (Addr) min_dist = ~(Elf_W (Addr))0; int ret;
load_offset = elf_w (get_load_offset) (ei, segbase, mapoff); - ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, offp); + ret = elf_w (lookup_symbol) (as, ip, ei, load_offset, buf, buf_len, &min_dist); + + /* If the ELF image has MiniDebugInfo embedded in it, look up the symbol in + there as well and replace the previously found if it is closer. */ + struct elf_image mdi; + if (elf_w (extract_minidebuginfo) (ei, &mdi)) + { + int ret_mdi;
+ load_offset = elf_w (get_load_offset) (&mdi, segbase, mapoff); + ret_mdi = elf_w (lookup_symbol) (as, ip, &mdi, load_offset, buf, + buf_len, &min_dist);
+ /* Closer symbol was found (possibly truncated). */ + if (ret_mdi == 0 || ret_mdi == -UNW_ENOMEM) + { + ret = ret_mdi; + } + + munmap (mdi.image, mdi.size); + }
+ if (min_dist >= ei->size) + return -UNW_ENOINFO; /* not found */ + if (offp) + *offp = min_dist; return ret; }
crash-catcher@lists.fedorahosted.org