Hello Ian,
thanks for review, I've fixed issues and updated the patch.
Can you please take a look.
Thanks.
On 06/29/2017 02:59 AM, Ian Lance Taylor wrote:
On Fri, Jun 16, 2017 at 8:39 AM, Denis Khalikov
<d.khali...@partner.samsung.com> wrote:
Hello everyone,
This is a patch for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77631
Can some one please review attached patch.
Sorry to take so long about this. It's a lot to look at.
diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog
index 096ceb6..4bd97f3 100644
--- a/libbacktrace/ChangeLog
+++ b/libbacktrace/ChangeLog
It's best if you don't include the ChangeLog as part of the patch.
The patch never applies cleanly anyhow. Just put the ChangeLog entry
in the e-mail or as a separate attachment. Actually I guess you did
that part, just leave ChangeLog out of the patch. Thanks.
+AC_CHECK_HEADERS(limits.h)
+
+AC_CHECK_HEADERS(sys/param.h)
May as well put these in a single AC_CHECK_HEADERS. But actually it
looks like you only want these to determine PATH_MAX, and I don't
think it's worth it. Just use 4096.
+ LINK = 1,
+ REGULAR = 2
These names, and also DYN, INVALID, and EXEC, are a little too short
and too likely to conflict with some sloppy system header file. The
enums in this code all use a prefix for each element; do that here
too.
+/* Cast from void pointer to uint32_t. */
+
+static uint32_t
+getl32 (void *p)
+{
+ char *addr = (char *) p;
+ uint32_t v = 0;
+ v = *((uint32_t *) addr);
+ return v;
+}
The comment here doesn't look right; this isn't a cast. And the
argument should really be char*. But more importantly, the name
suggests that you want a little-endian read, but this won't fetch a
little-endian value on a big-endian system. Either do a proper
little-endian fetch byte by byte, as the DWARF code already does, or
clarify the function name. I don't know what you actually need.
+/* Function that produce a crc32 value for input buffer. */
Let's move the CRC32 stuff into a different file. Add a comment
explaining how the table was generated.
+ static const unsigned long crc32_table[256]
Seems like this should be uint32_t. In any case not `unsigned long`,
which is 64 bits. In general the CRC code seems to use `unsigned
long` where I would expect `uint32_t`.
+ unsigned char buffer[8 * 1024];
This code is called from signal handlers and on threads; this array is
too long to put on the stack. Instead of looping and calling read
like this, use backtrace_get_view.
+/* Get length of the path. */
+
+static int
+pathlen (const char *buffer)
This function doesn't seem to get the length of the path, it seems to
get the length of the base name.
+ if (offset >= section_size)
+ return 0;
+ crc32_debug_link = getl32 (debug_link + offset);
Seems like you should compare offset + 4 to section_size to avoid
running off the end.
+ error_callback (data, "executable file is not ELF", 0);
This and other error messages no longer seem correct, as this function
is now used for files other than the executable file.
It doesn't seem like elf_get_section_by_name should call
process_elf_header, it seems like that will do unnecessary extra work.
For that matter elf_get_section_by_name shouldn't read the section
headers and names each time, we should only do that once.
+static int
+backtrace_readlink
This function should return type_of_file, and the enum should have an
error value.
+ if (buffer[0] == '/')
Use IS_ABSOLUTE_PATH.
+ debug_descriptor
+ = backtrace_open_debugfile (descriptor, filename, error_callback,
+ data, state);
If you're going to call this from fileline.c, then the function needs
to be defined in pecoff.c also. But calling it in fileline.c doesn't
seem right; why doesn't backtrace_initialize call it?
Ian
From 053f4fab56ed45dec17c1d4c66868678c817acf9 Mon Sep 17 00:00:00 2001
From: Denis Khalikov <d.khali...@partner.samsung.com>
Date: Sat, 1 Jul 2017 23:37:34 +0300
Subject: [PATCH] PR sanitizer/77631
* elf.c (enum type_of_file): New enum.
(enum type_of_elf): New enum.
(enum debug_path): New enum.
(get_uint32): New function.
(get_crc32): New function.
(base_name_len): New function.
(check_sum): New function. Verify sum.
(process_elf_header): New function. Process elf header.
(elf_get_section_by_name): New function. Get section by name.
(backtrace_readlink): New function. Get type of file from filename.
(resolve_realname): New function. Resolve real name if file is link.
(backtrace_resolve_realname): New function. Resolve real name for any
file type.
(search_for_debugfile): New function. Search for debug file in known
paths.
(open_debugfile_by_gnulink): New function. Open debug file with
gnulink.
(hex): New function. Convert to hex.
(get_build_id_name): New function. Generate build-id name.
(open_debugfile_by_build_id): New function. Open debug file with
build-id.
(backtrace_open_debugfile): New function. Open debug file.
(elf_add): Move code which reads elf header, headers section and names
section to process_elf_header.
Call backtrace_open_debugfile_file for executable.
(phdr_callback): Call backtrace_open_debugfile function for shared
library.
* crc32.c: New file.
(gnu_debuglink_crc32): New function. Generate crc32 sum.
---
libbacktrace/crc32.c | 107 ++++++
libbacktrace/elf.c | 995 +++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 1000 insertions(+), 102 deletions(-)
create mode 100644 libbacktrace/crc32.c
diff --git a/libbacktrace/crc32.c b/libbacktrace/crc32.c
new file mode 100644
index 0000000..18d8119
--- /dev/null
+++ b/libbacktrace/crc32.c
@@ -0,0 +1,107 @@
+/* crc32.c -- compute the CRC-32
+
+ The CRC-32 defined in IEEE 802.3 using the polynomial:
+
+ x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4
+ + x2 + x + 1
+
+ Hexademical representation of the polynomial over GF(2): 0xedb88320
+
+ The table was gerated by algorithm from zlib.(zlib/crc32.c)
+ The algorithm is described below.
+
+ * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ unsigned long crc_table[256];
+ void make_crc_table()
+ {
+ unsigned long c;
+ int n, k;
+ unsigned long poly;
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ poly = 0;
+ for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
+ poly |= (unsigned long)1 << (31 - p[n]);
+
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[n] = c;
+ }
+ }
+*/
+
+static const uint32_t crc32_table[256]
+ = {0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+
+static uint32_t
+gnu_debuglink_crc32 (uint32_t crc, const unsigned char *buf, size_t len)
+{
+ const unsigned char *end;
+ end = buf + len;
+ crc = ~crc;
+ while (buf < end)
+ {
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ ++buf;
+ }
+ return ~crc;
+}
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 89ed42b..c3c5586 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -35,6 +35,9 @@ POSSIBILITY OF SUCH DAMAGE. */
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
#ifdef HAVE_DL_ITERATE_PHDR
#include <link.h>
@@ -42,6 +45,16 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "backtrace.h"
#include "internal.h"
+#include "filenames.h"
+/* In case some other libraries build libbacktrace from source
+ (for example: libsanitizer do that way), we should manually update
+ each Makefile for each library to avoid situation with undefined
+ references after adding new file into libbacktrace sources.
+ Another way is to include crc32.c file into preproccessing stage. */
+#include "crc32.c"
+
+#undef PATH_MAX
+#define PATH_MAX 4096
#ifndef HAVE_DL_ITERATE_PHDR
@@ -283,6 +296,855 @@ struct elf_syminfo_data
size_t count;
};
+/* Information to read ELF note section. */
+
+typedef struct
+{
+ unsigned char namesz[4];
+ unsigned char descsz[4];
+ unsigned char type[4];
+ unsigned char name[1];
+} Elf_External_Note;
+
+/* Information about type of the file. */
+
+enum type_of_file
+{
+ FILE_TYPE_INVALID = -1,
+ FILE_TYPE_LINK = 1,
+ FILE_TYPE_REGULAR = 2
+};
+
+/* Information about debug paths. */
+
+enum debug_path
+{
+ DEBUG_PATH_CURRENT,
+ DEBUG_PATH_CURRENT_DEBUG,
+ DEBUG_PATH_USR_LIB_DEBUG,
+ DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE,
+ DEBUG_PATH_MAX
+};
+
+/* Type of the ELF file. */
+
+enum type_of_elf
+{
+ ELF_TYPE_DYN = -1,
+ ELF_TYPE_INVALID = 0,
+ ELF_TYPE_EXEC = 1
+};
+
+/* Paths to debug file. */
+
+static const char *const debug_file_path[DEBUG_PATH_MAX]
+ = {"", ".debug/", "/usr/lib/debug/", "/usr/lib/debug"};
+
+/* Get a uint32 from the buffer. */
+
+static uint32_t
+get_uint32 (const unsigned char *p, int is_bigendian)
+{
+ if (is_bigendian)
+ return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16)
+ | ((uint32_t) p[2] << 8) | (uint32_t) p[3]);
+ else
+ return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16)
+ | ((uint32_t) p[1] << 8) | (uint32_t) p[0]);
+}
+
+/* Generate crc32 sum from the file. */
+
+static uint32_t
+get_crc32 (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data)
+{
+ uint32_t file_crc;
+ off_t offset;
+ unsigned int buffer_count;
+ unsigned int buffer_len;
+ const unsigned char *buffer;
+ unsigned int pass;
+ unsigned int out_of_buffer_len;
+ struct stat file_stat;
+ struct backtrace_view file_view;
+
+ buffer_len = 8 * 1024;
+ offset = 0;
+ file_crc = 0;
+ out_of_buffer_len = 0;
+
+ memset (&file_stat, 0, sizeof (struct stat));
+
+ if (fstat (descriptor, &file_stat) == -1)
+ {
+ if (errno != ENOENT)
+ error_callback (data, "fstat", errno);
+ return 0;
+ }
+
+ if (!backtrace_get_view (state, descriptor, offset, file_stat.st_size,
+ error_callback, data, &file_view))
+ return 0;
+
+ buffer = (const unsigned char *) file_view.data;
+ buffer_count = file_stat.st_size / buffer_len;
+ out_of_buffer_len = file_stat.st_size % buffer_len;
+
+ for (pass = 0; pass < buffer_count; ++pass)
+ {
+ file_crc = gnu_debuglink_crc32 (file_crc, buffer + offset, buffer_len);
+ offset += buffer_len;
+ }
+
+ if (out_of_buffer_len > 0)
+ file_crc
+ = gnu_debuglink_crc32 (file_crc, buffer + offset, out_of_buffer_len);
+
+ backtrace_release_view (state, &file_view, error_callback, data);
+ return file_crc;
+}
+
+/* Get length of the base name. */
+
+static int
+base_name_len (const char *buffer)
+{
+ int len;
+
+ len = strlen (buffer);
+ while (len > 1 && !IS_DIR_SEPARATOR (buffer[len - 1]))
+ --len;
+ return len > 1 ? len : -1;
+}
+
+/* Verify crc32 sum. */
+
+static int
+check_sum (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data,
+ const unsigned char *debug_link, unsigned int offset,
+ unsigned int section_size, int is_bigendian)
+{
+ unsigned long crc32_debug_link;
+ unsigned long crc32_debug_file;
+ offset += 1;
+ offset = (offset + 3) & ~3;
+ if (offset + 4 > section_size)
+ return 0;
+ crc32_debug_link
+ = get_uint32 (debug_link + offset, is_bigendian);
+ crc32_debug_file = get_crc32 (state, descriptor, error_callback, data);
+ return crc32_debug_link == crc32_debug_file;
+}
+
+/* Process elf header. Verify magic number, version, etc, of the ELF
+ header. Populate ehdr_out, names_view_out and shdrs_view_out, caller
+ should realese view of the names_view_out and shdrs_view_out. Return
+ ELF_TYPE_EXEC if the file type is EXE, ELF_TYPE_DYN if type of the
+ file is DYN and ELF_TYPE_INVALID on the fail. */
+
+static enum type_of_elf
+process_elf_header (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data,
+ int exe, b_elf_ehdr *ehdr_out,
+ struct backtrace_view *shdrs_view_out,
+ struct backtrace_view *names_view_out)
+{
+ struct backtrace_view ehdr_view;
+ const b_elf_shdr *shstrhdr;
+ const b_elf_shdr *shdrs;
+ unsigned int shstrndx;
+ unsigned int shnum;
+ off_t shoff;
+ int shdrs_view_valid;
+
+ shdrs_view_valid = 0;
+
+ if (!backtrace_get_view (state, descriptor, 0, sizeof *ehdr_out,
+ error_callback, data, &ehdr_view))
+ goto fail;
+
+ memcpy (ehdr_out, ehdr_view.data, sizeof *ehdr_out);
+
+ backtrace_release_view (state, &ehdr_view, error_callback, data);
+
+ if (ehdr_out->e_ident[EI_MAG0] != ELFMAG0
+ || ehdr_out->e_ident[EI_MAG1] != ELFMAG1
+ || ehdr_out->e_ident[EI_MAG2] != ELFMAG2
+ || ehdr_out->e_ident[EI_MAG3] != ELFMAG3)
+ {
+ error_callback (data, "processed file is not ELF", 0);
+ goto fail;
+ }
+ if (ehdr_out->e_ident[EI_VERSION] != EV_CURRENT)
+ {
+ error_callback (data, "processed file is unrecognized ELF version", 0);
+ goto fail;
+ }
+
+#if BACKTRACE_ELF_SIZE == 32
+#define BACKTRACE_ELFCLASS ELFCLASS32
+#else
+#define BACKTRACE_ELFCLASS ELFCLASS64
+#endif
+
+ if (ehdr_out->e_ident[EI_CLASS] != BACKTRACE_ELFCLASS)
+ {
+ error_callback (data, "processed file is unexpected ELF class", 0);
+ goto fail;
+ }
+
+ if (ehdr_out->e_ident[EI_DATA] != ELFDATA2LSB
+ && ehdr_out->e_ident[EI_DATA] != ELFDATA2MSB)
+ {
+ error_callback (data, "processed file has unknown endianness", 0);
+ goto fail;
+ }
+
+ /* If the executable is ET_DYN, it is either a PIE, or we are running
+ directly a shared library with .interp. We need to wait for
+ dl_iterate_phdr in that case to determine the actual base_address. */
+ if (exe && ehdr_out->e_type == ET_DYN)
+ return ELF_TYPE_DYN;
+
+ shoff = ehdr_out->e_shoff;
+ shnum = ehdr_out->e_shnum;
+ shstrndx = ehdr_out->e_shstrndx;
+
+ if ((shnum == 0 || shstrndx == SHN_XINDEX) && shoff != 0)
+ {
+ struct backtrace_view shdr_view;
+ const b_elf_shdr *shdr;
+
+ if (!backtrace_get_view (state, descriptor, shoff, sizeof (b_elf_shdr),
+ error_callback, data, &shdr_view))
+ goto fail;
+
+ shdr = (const b_elf_shdr *) shdr_view.data;
+
+ if (shnum == 0)
+ shnum = shdr->sh_size;
+
+ if (shstrndx == SHN_XINDEX)
+ {
+ shstrndx = shdr->sh_link;
+
+ /* Versions of the GNU binutils between 2.12 and 2.18 did
+ not handle objects with more than SHN_LORESERVE sections
+ correctly. All large section indexes were offset by
+ 0x100. There is more information at
+ http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
+ Fortunately these object files are easy to detect, as the
+ GNU binutils always put the section header string table
+ near the end of the list of sections. Thus if the
+ section header string table index is larger than the
+ number of sections, then we know we have to subtract
+ 0x100 to get the real section index. */
+ if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100)
+ shstrndx -= 0x100;
+ }
+ backtrace_release_view (state, &shdr_view, error_callback, data);
+ }
+
+ /* Read the section headers, skipping the first one. */
+
+ if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr),
+ (shnum - 1) * sizeof (b_elf_shdr), error_callback,
+ data, shdrs_view_out))
+ goto fail;
+
+ shdrs_view_valid = 1;
+
+ shdrs = (const b_elf_shdr *) shdrs_view_out->data;
+ shstrhdr = &shdrs[shstrndx - 1];
+
+ /* Read the section names. */
+
+ if (!backtrace_get_view (state, descriptor, shstrhdr->sh_offset,
+ shstrhdr->sh_size, error_callback, data,
+ names_view_out))
+ goto fail;
+
+ ehdr_out->e_shoff = shoff;
+ ehdr_out->e_shnum = shnum;
+ ehdr_out->e_shstrndx = shstrndx;
+
+ return ELF_TYPE_EXEC;
+
+ fail:
+ /* In case fail happens with backtrace_get_view for names section. */
+ if (shdrs_view_valid)
+ backtrace_release_view (state, shdrs_view_out, error_callback, data);
+ return ELF_TYPE_INVALID;
+}
+
+/* Get content of the specifying section. */
+
+static unsigned char *
+elf_get_section_by_name (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data,
+ unsigned int *section_data_len_out, const char *section_name,
+ b_elf_ehdr *ehdr, struct backtrace_view *shdrs_view,
+ struct backtrace_view *names_view)
+{
+ const b_elf_shdr *shdrs;
+ const b_elf_shdr *shstrhdr;
+ size_t shstr_size;
+ struct backtrace_view section_view;
+ const char *names;
+ unsigned int i;
+ unsigned int shnum;
+ unsigned int shstrndx;
+ int section_view_valid;
+ unsigned char *section_data;
+
+ section_view_valid = 0;
+ section_data = NULL;
+
+ shnum = ehdr->e_shnum;
+ shstrndx = ehdr->e_shstrndx;
+ shdrs = (const b_elf_shdr *) shdrs_view->data;
+ shstrhdr = &shdrs[shstrndx - 1];
+ shstr_size = shstrhdr->sh_size;
+
+ names = (const char *) names_view->data;
+
+ for (i = 1; i < shnum; ++i)
+ {
+ const b_elf_shdr *shdr;
+ unsigned int sh_name;
+ const char *name;
+ shdr = &shdrs[i - 1];
+ sh_name = shdr->sh_name;
+ if (sh_name >= shstr_size)
+ {
+ error_callback (data, "ELF section name out of range", 0);
+ goto exit;
+ }
+
+ name = names + sh_name;
+
+ if (strcmp (name, section_name) == 0)
+ {
+ if (backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ §ion_view))
+ {
+ section_view_valid = 1;
+ section_data
+ = backtrace_alloc (state, shdr->sh_size, error_callback, data);
+ if (section_data == NULL)
+ goto exit;
+ memcpy (section_data, section_view.data, shdr->sh_size);
+ *section_data_len_out = shdr->sh_size;
+ }
+ break;
+ }
+ }
+
+ exit:
+ if (section_view_valid)
+ backtrace_release_view (state, §ion_view, error_callback, data);
+ return section_data;
+}
+
+/* Verify type of the file. */
+
+static enum type_of_file
+backtrace_readlink (const char *filename,
+ backtrace_error_callback error_callback, void *data)
+{
+ struct stat link_stat;
+ enum type_of_file file_type;
+ mode_t mode;
+
+ memset (&link_stat, 0, sizeof (struct stat));
+
+ if (lstat (filename, &link_stat) == -1)
+ {
+ if (errno != ENOENT)
+ error_callback (data, filename, errno);
+ file_type = FILE_TYPE_INVALID;
+ }
+
+ mode = link_stat.st_mode & S_IFMT;
+
+ switch (mode)
+ {
+ case S_IFLNK:
+ file_type = FILE_TYPE_LINK;
+ break;
+ case S_IFREG:
+ file_type = FILE_TYPE_REGULAR;
+ break;
+ default:
+ file_type = FILE_TYPE_INVALID;
+ }
+ return file_type;
+}
+
+/* Resolve full name of the link. In this case we can't use realpath function
+ because it could be undefined on some platfroms, also it allocates memory
+ by malloc, which we can't use. */
+
+static int
+resolve_realname (const char *filename, char *buffer,
+ struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+{
+ char *temp_buffer;
+ enum type_of_file file_type;
+ int filename_len;
+ int temp_filename_len;
+ int valid_temp_buffer;
+ int base_len;
+
+ valid_temp_buffer = 0;
+ filename_len = -1;
+ file_type = FILE_TYPE_LINK;
+
+ /* Allocate memory for sizeof(PATH_MAX) + 1 bytes because at this time
+ we don't know how long path could be. */
+ temp_buffer = backtrace_alloc (state, PATH_MAX + 1, error_callback, data);
+ if (temp_buffer == NULL)
+ return -1;
+
+ valid_temp_buffer = 1;
+
+ memset (temp_buffer, 0, PATH_MAX + 1);
+ memcpy (temp_buffer, filename, strlen (filename));
+
+ while (file_type == FILE_TYPE_LINK)
+ {
+ filename_len = readlink (temp_buffer, buffer, PATH_MAX);
+ if (filename_len < 1)
+ goto exit;
+
+ temp_filename_len = strlen (buffer);
+
+ /* Full path. */
+ if (IS_ABSOLUTE_PATH (buffer))
+ {
+ memset (temp_buffer, 0, PATH_MAX);
+ memcpy (temp_buffer, buffer, temp_filename_len);
+ }
+ else
+ {
+ /* Relative path. */
+ base_len = base_name_len (temp_buffer);
+ if (base_len < 1 || (base_len + filename_len > PATH_MAX))
+ {
+ filename_len = -1;
+ goto exit;
+ }
+ memcpy (temp_buffer + base_len, buffer, filename_len);
+ temp_buffer[base_len + filename_len] = '\0';
+ }
+
+ file_type = backtrace_readlink (temp_buffer, error_callback, data);
+ memset (buffer, 0, filename_len);
+ }
+
+ if (file_type != FILE_TYPE_REGULAR)
+ {
+ filename_len = -1;
+ goto exit;
+ }
+
+ filename_len = strlen (temp_buffer);
+ memcpy (buffer, temp_buffer, filename_len);
+
+ exit:
+ if (valid_temp_buffer)
+ backtrace_free (state, temp_buffer, PATH_MAX + 1, error_callback, data);
+ return filename_len;
+}
+
+/* Resolve realname of the filename. This function verifies filename.
+ If filename is name of the file it populates realname buffer.
+ If filename is link, it calls resolve_realname function. */
+
+static int
+backtrace_resolve_realname (const char *filename, char *realname,
+ struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+{
+ enum type_of_file file_type;
+ int filename_len;
+
+ filename_len = -1;
+
+ file_type = backtrace_readlink (filename, error_callback, data);
+
+ if (file_type == FILE_TYPE_LINK)
+ {
+ /* Read the actual filename. */
+ filename_len
+ = resolve_realname (filename, realname, state, error_callback, data);
+ if (filename_len <= 0)
+ return 0;
+ }
+ else if (file_type == FILE_TYPE_REGULAR)
+ {
+ filename_len = strlen (filename);
+ if (filename_len > PATH_MAX)
+ return 0;
+ memcpy (realname, filename, filename_len);
+ }
+ /* FILE_TYPE_INVALID. */
+ else
+ return 0;
+
+ return 1;
+}
+
+/* Search for debug file into specifying directorires. */
+
+static int
+search_for_debugfile (char *realname, char *debug_filename,
+ backtrace_error_callback error_callback, void *data,
+ struct backtrace_state *state)
+{
+ int debug_filename_len;
+ int pass;
+ int debug_path_len;
+ int debug_does_not_exist;
+ int debug_descriptor;
+ int base_len;
+ char *buffer;
+ int buffer_len;
+ int valid_buffer;
+
+ debug_descriptor = -1;
+ valid_buffer = 0;
+
+ base_len = base_name_len (realname);
+ if (base_len < 1)
+ goto exit;
+
+ debug_filename_len = strlen ((const char *) debug_filename);
+
+ if (debug_filename_len < 1)
+ goto exit;
+
+ buffer_len = base_len + strlen (debug_file_path[DEBUG_PATH_USR_LIB_DEBUG])
+ + debug_filename_len + 1;
+
+ buffer = backtrace_alloc (state, buffer_len, error_callback, data);
+
+ if (buffer == NULL)
+ goto exit;
+ memset (buffer, 0, buffer_len);
+ memcpy (buffer, realname, base_len);
+
+ valid_buffer = 1;
+ for (pass = 0; pass < DEBUG_PATH_MAX; ++pass)
+ {
+ switch (pass)
+ {
+ case DEBUG_PATH_CURRENT:
+ {
+ memcpy (buffer + base_len, debug_filename, debug_filename_len);
+ break;
+ }
+ case DEBUG_PATH_CURRENT_DEBUG:
+ {
+ debug_path_len = strlen (debug_file_path[DEBUG_PATH_CURRENT_DEBUG]);
+ memcpy (buffer + base_len,
+ debug_file_path[DEBUG_PATH_CURRENT_DEBUG], debug_path_len);
+ memcpy (buffer + base_len + debug_path_len, debug_filename,
+ debug_filename_len);
+ break;
+ }
+ case DEBUG_PATH_USR_LIB_DEBUG:
+ {
+ debug_path_len = strlen (debug_file_path[DEBUG_PATH_USR_LIB_DEBUG]);
+ memset (buffer, 0, buffer_len);
+ memcpy (buffer, debug_file_path[DEBUG_PATH_USR_LIB_DEBUG],
+ debug_path_len);
+ memcpy (buffer + debug_path_len, debug_filename,
+ debug_filename_len);
+ break;
+ }
+ case DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE:
+ {
+ debug_path_len
+ = strlen (debug_file_path[DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE]);
+ memset (buffer, 0, buffer_len);
+ memcpy (buffer,
+ debug_file_path[DEBUG_PATH_USR_LIB_DEBUG_PATH_TO_EXE],
+ debug_path_len);
+ memcpy (buffer + debug_path_len, realname, base_len);
+ memcpy (buffer + debug_path_len + base_len, debug_filename,
+ debug_filename_len);
+ break;
+ }
+ default:
+ goto exit;
+ }
+
+ debug_descriptor
+ = backtrace_open (buffer, error_callback, data, &debug_does_not_exist);
+
+ if (debug_descriptor > 0)
+ break;
+ }
+ exit:
+ if (valid_buffer)
+ backtrace_free (state, buffer, buffer_len, error_callback, data);
+ return debug_descriptor;
+}
+
+/* Open debug file by gnulink. */
+
+static int
+open_debugfile_by_gnulink (char *realname, unsigned char *section_data,
+ unsigned int section_data_len, int is_bigendian,
+ struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+{
+ int debug_descriptor;
+
+ debug_descriptor = search_for_debugfile (realname, (char *) section_data,
+ error_callback, data, state);
+ if (debug_descriptor < 0)
+ goto exit;
+
+ /* Check the crc32 checksum if it not the same return -1. */
+
+ if (!check_sum (state, debug_descriptor, error_callback, data,
+ (const unsigned char *) section_data,
+ strlen ((char *) section_data), section_data_len,
+ is_bigendian))
+ {
+ /* If crc32 sums are different, just close the descriptor
+ associated with debuginfo file. */
+ backtrace_close (debug_descriptor, error_callback, data);
+ debug_descriptor = -1;
+ }
+
+ exit:
+ return debug_descriptor;
+}
+
+/* Convert char to hex */
+
+static char
+hex (char ch)
+{
+ return ch > 9 ? ('a' + (ch - 10)) : ('0' + ch);
+}
+
+/* Get build-id name. */
+
+static char *
+get_build_id_name (unsigned char *section_data, unsigned int *len,
+ int is_bigendian, struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+{
+ Elf_External_Note *build_id_section;
+ char *build_id_name;
+ char *temp;
+ const char *debug_postfix;
+ const char *debug_prefix;
+ size_t debug_postfix_len;
+ size_t debug_prefix_len;
+ size_t name_size;
+ size_t offset;
+ unsigned char *hash_start;
+ uint32_t hash_size;
+ uint32_t identifier;
+
+ debug_postfix_len = 6;
+ debug_prefix_len = 10;
+ debug_postfix = ".debug";
+ debug_prefix = ".build-id/";
+ *len = 0;
+
+ build_id_section = (Elf_External_Note *) section_data;
+ hash_size = get_uint32 (build_id_section->descsz, is_bigendian);
+ identifier = get_uint32 (build_id_section->type, is_bigendian);
+ name_size = get_uint32 (build_id_section->namesz, is_bigendian);
+
+ if (identifier != NT_GNU_BUILD_ID || hash_size == 0 || name_size != 4
+ || strncmp ((char *) build_id_section->name, "GNU", 3) != 0)
+ return NULL;
+
+ offset = 16;
+ hash_start = section_data + offset;
+ *len = hash_size * 2 + debug_postfix_len + debug_prefix_len + 1;
+ build_id_name = backtrace_alloc (state, *len, error_callback, data);
+
+ if (build_id_name == NULL)
+ {
+ *len = 0;
+ return NULL;
+ }
+
+ memset (build_id_name, 0, *len);
+ memcpy (build_id_name, debug_prefix, debug_prefix_len);
+ temp = build_id_name + debug_prefix_len;
+
+ *temp++ = hex ((*hash_start & 0xF0) >> 4);
+ *temp++ = hex (*hash_start & 0x0F);
+ ++hash_start;
+ --hash_size;
+
+ memcpy (temp, "/", 1);
+ ++temp;
+
+ while (hash_size--)
+ {
+ *temp++ = hex ((*hash_start & 0xF0) >> 4);
+ *temp++ = hex (*hash_start & 0x0F);
+ ++hash_start;
+ }
+
+ memcpy (temp, debug_postfix, debug_postfix_len);
+ return build_id_name;
+}
+
+/* Open file by build-id. */
+
+static int
+open_debugfile_by_build_id (char *realname, unsigned char *section_data,
+ int is_bigendian, struct backtrace_state *state,
+ backtrace_error_callback error_callback, void *data)
+
+{
+ char *build_id_name;
+ int debug_descriptor;
+ unsigned int build_id_name_len;
+ size_t valid_build_id_name;
+
+ debug_descriptor = -1;
+ valid_build_id_name = 0;
+
+ build_id_name = get_build_id_name (section_data, &build_id_name_len,
+ is_bigendian, state, error_callback, data);
+
+ if (build_id_name == NULL || build_id_name_len == 0)
+ goto exit;
+
+ valid_build_id_name = 1;
+
+ debug_descriptor = search_for_debugfile (realname, build_id_name,
+ error_callback, data, state);
+
+ exit:
+ if (valid_build_id_name)
+ backtrace_free (state, build_id_name, build_id_name_len, error_callback,
+ data);
+ return debug_descriptor;
+}
+
+/* Open debug file. */
+
+static int
+backtrace_open_debugfile (int descriptor, const char *filename,
+ backtrace_error_callback error_callback, void *data,
+ struct backtrace_state *state)
+{
+ int debug_descriptor;
+ unsigned char *gnulink_section_data;
+ unsigned char *build_id_section_data;
+ size_t valid_descriptor;
+ size_t valid_gnulink_section_data;
+ size_t valid_build_id_section_data;
+ size_t valid_realname;
+ unsigned int build_id_section_data_len;
+ unsigned int gnu_link_section_data_len;
+ char *realname;
+ b_elf_ehdr ehdr;
+ struct backtrace_view shdrs_view;
+ struct backtrace_view names_view;
+ size_t valid_elf_header;
+
+ valid_elf_header = 0;
+ valid_realname = 0;
+ valid_descriptor = 0;
+ valid_gnulink_section_data = 0;
+ valid_build_id_section_data = 0;
+ build_id_section_data_len = 0;
+ gnu_link_section_data_len = 0;
+ debug_descriptor = -1;
+
+ if (!process_elf_header (state, descriptor, error_callback, data, 0, &ehdr,
+ &shdrs_view, &names_view))
+ goto exit;
+
+ valid_elf_header = 1;
+
+ realname = backtrace_alloc (state, PATH_MAX + 1, error_callback, data);
+
+ if (realname == NULL)
+ goto exit;
+
+ /* Indicates that we successfully allocated memory. */
+ valid_realname = 1;
+ memset (realname, 0, PATH_MAX + 1);
+
+ /* Populate the buffer with realname. */
+ if (!backtrace_resolve_realname (filename, realname, state, error_callback,
+ data))
+ goto exit;
+
+ /* Check if build-id section does exist. */
+ build_id_section_data
+ = elf_get_section_by_name (state, descriptor, error_callback, data,
+ &build_id_section_data_len, ".note.gnu.build-id",
+ &ehdr, &shdrs_view, &names_view);
+
+ if (build_id_section_data != NULL && build_id_section_data_len > 0)
+ {
+ valid_build_id_section_data = 1;
+ debug_descriptor
+ = open_debugfile_by_build_id (realname, build_id_section_data,
+ ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
+ state, error_callback, data);
+ }
+
+ if (debug_descriptor < 0)
+ {
+ gnulink_section_data
+ = elf_get_section_by_name (state, descriptor, error_callback, data,
+ &gnu_link_section_data_len, ".gnu_debuglink",
+ &ehdr, &shdrs_view, &names_view);
+
+ if (gnulink_section_data != NULL && gnu_link_section_data_len > 0)
+ {
+ valid_gnulink_section_data = 1;
+ debug_descriptor
+ = open_debugfile_by_gnulink (realname, gnulink_section_data,
+ gnu_link_section_data_len,
+ ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
+ state, error_callback, data);
+ }
+ }
+
+ if (debug_descriptor >= 0)
+ valid_descriptor = 1;
+
+ exit:
+ if (valid_descriptor)
+ backtrace_close (descriptor, error_callback, data);
+ if (valid_gnulink_section_data)
+ backtrace_free (state, gnulink_section_data, gnu_link_section_data_len,
+ error_callback, data);
+ if (valid_build_id_section_data)
+ backtrace_free (state, build_id_section_data, build_id_section_data_len,
+ error_callback, data);
+ if (valid_realname)
+ backtrace_free (state, realname, PATH_MAX + 1, error_callback, data);
+ if (valid_elf_header)
+ {
+ backtrace_release_view (state, &names_view, error_callback, data);
+ backtrace_release_view (state, &shdrs_view, error_callback, data);
+ }
+ return debug_descriptor;
+}
+
/* A dummy callback function used when we can't find any debug info. */
static int
@@ -521,9 +1383,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
backtrace_error_callback error_callback, void *data,
fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe)
{
- struct backtrace_view ehdr_view;
b_elf_ehdr ehdr;
- off_t shoff;
unsigned int shnum;
unsigned int shstrndx;
struct backtrace_view shdrs_view;
@@ -531,7 +1391,6 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
const b_elf_shdr *shdrs;
const b_elf_shdr *shstrhdr;
size_t shstr_size;
- off_t shstr_off;
struct backtrace_view names_view;
int names_view_valid;
const char *names;
@@ -547,6 +1406,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
off_t max_offset;
struct backtrace_view debug_view;
int debug_view_valid;
+ enum type_of_elf elf_type;
*found_sym = 0;
*found_dwarf = 0;
@@ -557,116 +1417,32 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
strtab_view_valid = 0;
debug_view_valid = 0;
- if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
- data, &ehdr_view))
- goto fail;
-
- memcpy (&ehdr, ehdr_view.data, sizeof ehdr);
-
- backtrace_release_view (state, &ehdr_view, error_callback, data);
-
- if (ehdr.e_ident[EI_MAG0] != ELFMAG0
- || ehdr.e_ident[EI_MAG1] != ELFMAG1
- || ehdr.e_ident[EI_MAG2] != ELFMAG2
- || ehdr.e_ident[EI_MAG3] != ELFMAG3)
- {
- error_callback (data, "executable file is not ELF", 0);
- goto fail;
- }
- if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
- {
- error_callback (data, "executable file is unrecognized ELF version", 0);
- goto fail;
- }
-
-#if BACKTRACE_ELF_SIZE == 32
-#define BACKTRACE_ELFCLASS ELFCLASS32
-#else
-#define BACKTRACE_ELFCLASS ELFCLASS64
-#endif
-
- if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS)
+ elf_type = process_elf_header (state, descriptor, error_callback, data, exe,
+ &ehdr, &shdrs_view, &names_view);
+ switch (elf_type)
{
- error_callback (data, "executable file is unexpected ELF class", 0);
+ /* Binary compiled with PIE option. */
+ case ELF_TYPE_DYN:
+ return -1;
+ case ELF_TYPE_EXEC:
+ break;
+ /* Header is invalid. */
+ case ELF_TYPE_INVALID:
goto fail;
}
- if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB
- && ehdr.e_ident[EI_DATA] != ELFDATA2MSB)
- {
- error_callback (data, "executable file has unknown endianness", 0);
- goto fail;
- }
-
- /* If the executable is ET_DYN, it is either a PIE, or we are running
- directly a shared library with .interp. We need to wait for
- dl_iterate_phdr in that case to determine the actual base_address. */
- if (exe && ehdr.e_type == ET_DYN)
- return -1;
-
- shoff = ehdr.e_shoff;
- shnum = ehdr.e_shnum;
- shstrndx = ehdr.e_shstrndx;
-
- if ((shnum == 0 || shstrndx == SHN_XINDEX)
- && shoff != 0)
- {
- struct backtrace_view shdr_view;
- const b_elf_shdr *shdr;
-
- if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr,
- error_callback, data, &shdr_view))
- goto fail;
-
- shdr = (const b_elf_shdr *) shdr_view.data;
-
- if (shnum == 0)
- shnum = shdr->sh_size;
-
- if (shstrndx == SHN_XINDEX)
- {
- shstrndx = shdr->sh_link;
-
- /* Versions of the GNU binutils between 2.12 and 2.18 did
- not handle objects with more than SHN_LORESERVE sections
- correctly. All large section indexes were offset by
- 0x100. There is more information at
- http://sourceware.org/bugzilla/show_bug.cgi?id-5900 .
- Fortunately these object files are easy to detect, as the
- GNU binutils always put the section header string table
- near the end of the list of sections. Thus if the
- section header string table index is larger than the
- number of sections, then we know we have to subtract
- 0x100 to get the real section index. */
- if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100)
- shstrndx -= 0x100;
- }
-
- backtrace_release_view (state, &shdr_view, error_callback, data);
- }
+ shdrs_view_valid = 1;
+ names_view_valid = 1;
/* To translate PC to file/line when using DWARF, we need to find
the .debug_info and .debug_line sections. */
- /* Read the section headers, skipping the first one. */
-
- if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr),
- (shnum - 1) * sizeof (b_elf_shdr),
- error_callback, data, &shdrs_view))
- goto fail;
- shdrs_view_valid = 1;
shdrs = (const b_elf_shdr *) shdrs_view.data;
- /* Read the section names. */
-
+ shnum = ehdr.e_shnum;
+ shstrndx = ehdr.e_shstrndx;
shstrhdr = &shdrs[shstrndx - 1];
shstr_size = shstrhdr->sh_size;
- shstr_off = shstrhdr->sh_offset;
-
- if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size,
- error_callback, data, &names_view))
- goto fail;
- names_view_valid = 1;
names = (const char *) names_view.data;
symtab_shndx = 0;
@@ -846,7 +1622,7 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
backtrace_release_view (state, &debug_view, error_callback, data);
if (descriptor != -1)
backtrace_close (descriptor, error_callback, data);
- return 0;
+ return 0;
}
/* Data passed to phdr_callback. */
@@ -877,6 +1653,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
int does_not_exist;
fileline elf_fileline_fn;
int found_dwarf;
+ int debug_descriptor;
/* There is not much we can do if we don't have the module name,
unless executable is ET_DYN, where we expect the very first
@@ -895,11 +1672,19 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data);
pd->exe_descriptor = -1;
}
+ debug_descriptor = -1;
descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
pd->data, &does_not_exist);
+
if (descriptor < 0)
return 0;
+
+ debug_descriptor
+ = backtrace_open_debugfile (descriptor, info->dlpi_name,
+ pd->error_callback, pd->data, pd->state);
+ if (debug_descriptor >= 0)
+ descriptor = debug_descriptor;
}
if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
@@ -929,6 +1714,12 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
int found_dwarf;
fileline elf_fileline_fn = elf_nodebug;
struct phdr_data pd;
+ int debug_descriptor;
+
+ debug_descriptor = backtrace_open_debugfile (descriptor, state->filename,
+ error_callback, data, state);
+ if (debug_descriptor >= 0)
+ descriptor = debug_descriptor;
ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
&found_sym, &found_dwarf, 1);
--
1.9.1