From 05f40bc4c116ba48843728201bc7290a5e518598 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 14 Sep 2020 14:01:56 -0700 Subject: libbacktrace: support MiniDebugInfo libbacktrace/ChangeLog: PR libbacktrace/93608 Add support for MiniDebugInfo. * elf.c (struct elf_view): Define. Replace most uses of backtrace_view with elf_view. (elf_get_view): New static functions. Replace most calls of backtrace_get_view with elf_get_view. (elf_release_view): New static functions. Replace most calls of backtrace_release_view with elf_release_view. (elf_uncompress_failed): Rename from elf_zlib_failed. Change all callers. (LZMA_STATES, LZMA_POS_STATES, LZMA_DIST_STATES): Define. (LZMA_DIST_SLOTS, LZMA_DIST_MODEL_START): Define. (LZMA_DIST_MODEL_END, LZMA_FULL_DISTANCES): Define. (LZMA_ALIGN_SIZE, LZMA_LEN_LOW_SYMBOLS): Define. (LZMA_LEN_MID_SYMBOLS, LZMA_LEN_HIGH_SYMBOLS): Define. (LZMA_LITERAL_CODERS_MAX, LZMA_LITERAL_CODER_SIZE): Define. (LZMA_PROB_IS_MATCH_LEN, LZMA_PROB_IS_REP_LEN): Define. (LZMA_PROB_IS_REP0_LEN, LZMA_PROB_IS_REP1_LEN): Define. (LZMA_PROB_IS_REP2_LEN, LZMA_PROB_IS_REP0_LONG_LEN): Define. (LZMA_PROB_DIST_SLOT_LEN, LZMA_PROB_DIST_SPECIAL_LEN): Define. (LZMA_PROB_DIST_ALIGN_LEN): Define. (LZMA_PROB_MATCH_LEN_CHOICE_LEN): Define. (LZMA_PROB_MATCH_LEN_CHOICE2_LEN): Define. (LZMA_PROB_MATCH_LEN_LOW_LEN): Define. (LZMA_PROB_MATCH_LEN_MID_LEN): Define. (LZMA_PROB_MATCH_LEN_HIGH_LEN): Define. (LZMA_PROB_REP_LEN_CHOICE_LEN): Define. (LZMA_PROB_REP_LEN_CHOICE2_LEN): Define. (LZMA_PROB_REP_LEN_LOW_LEN): Define. (LZMA_PROB_REP_LEN_MID_LEN): Define. (LZMA_PROB_REP_LEN_HIGH_LEN): Define. (LZMA_PROB_LITERAL_LEN): Define. (LZMA_PROB_IS_MATCH_OFFSET, LZMA_PROB_IS_REP_OFFSET): Define. (LZMA_PROB_IS_REP0_OFFSET, LZMA_PROB_IS_REP1_OFFSET): Define. (LZMA_PROB_IS_REP2_OFFSET): Define. (LZMA_PROB_IS_REP0_LONG_OFFSET): Define. (LZMA_PROB_DIST_SLOT_OFFSET): Define. (LZMA_PROB_DIST_SPECIAL_OFFSET): Define. (LZMA_PROB_DIST_ALIGN_OFFSET): Define. (LZMA_PROB_MATCH_LEN_CHOICE_OFFSET): Define. (LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET): Define. (LZMA_PROB_MATCH_LEN_LOW_OFFSET): Define. (LZMA_PROB_MATCH_LEN_MID_OFFSET): Define. (LZMA_PROB_MATCH_LEN_HIGH_OFFSET): Define. (LZMA_PROB_REP_LEN_CHOICE_OFFSET): Define. (LZMA_PROB_REP_LEN_CHOICE2_OFFSET): Define. (LZMA_PROB_REP_LEN_LOW_OFFSET): Define. (LZMA_PROB_REP_LEN_MID_OFFSET): Define. (LZMA_PROB_REP_LEN_HIGH_OFFSET): Define. (LZMA_PROB_LITERAL_OFFSET): Define. (LZMA_PROB_TOTAL_COUNT): Define. (LZMA_IS_MATCH, LZMA_IS_REP, LZMA_IS_REP0): Define. (LZMA_IS_REP1, LZMA_IS_REP2, LZMA_IS_REP0_LONG): Define. (LZMA_DIST_SLOT, LZMA_DIST_SPECIAL, LZMA_DIST_ALIGN): Define. (LZMA_MATCH_LEN_CHOICE, LZMA_MATCH_LEN_CHOICE2): Define. (LZMA_MATCH_LEN_LOW, LZMA_MATCH_LEN_MID): Define. (LZMA_MATCH_LEN_HIGH, LZMA_REP_LEN_CHOICE): Define. (LZMA_REP_LEN_CHOICE2, LZMA_REP_LEN_LOW): Define. (LZMA_REP_LEN_MID, LZMA_REP_LEN_HIGH, LZMA_LITERAL): Define. (elf_lzma_varint): New static function. (elf_lzma_range_normalize): New static function. (elf_lzma_bit, elf_lzma_integer): New static functions. (elf_lzma_reverse_integer): New static function. (elf_lzma_len, elf_uncompress_lzma_block): New static functions. (elf_uncompress_lzma): New static function. (backtrace_uncompress_lzma): New function. (elf_add): Add memory and memory_size parameters. Change all callers. Look for .gnu_debugdata section, and, if found, decompress it and use it for symbols and debug info. Permit the descriptor parameter to be -1. * internal.h (backtrace_uncompress_lzma): Declare. * mtest.c: New file. * xztest.c: New file. * configure.ac: Check for nm, xz, and comm programs. Check for liblzma library. (HAVE_MINIDEBUG): Define. * Makefile.am (mtest_SOURCES): Define. (mtest_CFLAGS, mtest_LDADD): Define. (TESTS): Add mtest_minidebug if HAVE_MINIDEBUG. (%_minidebug): New pattern rule, if HAVE_MINIDEBUG. (xztest_SOURCES, xztest_CFLAGS, xztest_LDADD): Define. (xztest_alloc_SOURCES, xztest_alloc_CFLAGS): Define (xztest_alloc_LDADD): Define. (BUILDTESTS): Add mtest, xztest, xztest_alloc. (CLEANFILES): Add files created by minidebug pattern. (btest.lo): Correct INCDIR reference. (mtest.lo, xztest.lo, ztest.lo): New targets. * configure: Regenerate. * config.h.in: Regenerate. * Makefile.in: Regenerate. --- libbacktrace/elf.c | 1701 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 1551 insertions(+), 150 deletions(-) (limited to 'libbacktrace/elf.c') diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c index 80a0050..dd00470 100644 --- a/libbacktrace/elf.c +++ b/libbacktrace/elf.c @@ -390,6 +390,14 @@ struct elf_syminfo_data size_t count; }; +/* A view that works for either a file or memory. */ + +struct elf_view +{ + struct backtrace_view view; + int release; /* If non-zero, must call backtrace_release_view. */ +}; + /* Information about PowerPC64 ELFv1 .opd section. */ struct elf_ppc64_opd_data @@ -401,9 +409,48 @@ struct elf_ppc64_opd_data /* Size of the .opd section. */ size_t size; /* Corresponding section view. */ - struct backtrace_view view; + struct elf_view view; }; +/* Create a view of SIZE bytes from DESCRIPTOR/MEMORY at OFFSET. */ + +static int +elf_get_view (struct backtrace_state *state, int descriptor, + const unsigned char *memory, size_t memory_size, off_t offset, + uint64_t size, backtrace_error_callback error_callback, + void *data, struct elf_view *view) +{ + if (memory == NULL) + { + view->release = 1; + return backtrace_get_view (state, descriptor, offset, size, + error_callback, data, &view->view); + } + else + { + if ((uint64_t) offset + size > (uint64_t) memory_size) + { + error_callback (data, "out of range for in-memory file", 0); + return 0; + } + view->view.data = (const void *) (memory + offset); + view->view.base = NULL; + view->view.len = size; + view->release = 0; + return 1; + } +} + +/* Release a view read by elf_get_view. */ + +static void +elf_release_view (struct backtrace_state *state, struct elf_view *view, + backtrace_error_callback error_callback, void *data) +{ + if (view->release) + backtrace_release_view (state, &view->view, error_callback, data); +} + /* Compute the CRC-32 of BUF/LEN. This uses the CRC used for .gnu_debuglink files. */ @@ -1035,7 +1082,7 @@ elf_open_debugfile_by_debuglink (struct backtrace_state *state, when this code is compiled with -g. */ static void -elf_zlib_failed(void) +elf_uncompress_failed(void) { } @@ -1062,7 +1109,7 @@ elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend, if (unlikely (pinend - pin < 4)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1192,7 +1239,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, { if (unlikely (codes[i] >= 16)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1229,7 +1276,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, if (unlikely (jcnt > (1U << j))) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1249,7 +1296,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1265,7 +1312,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, { if (unlikely (table[ind] != 0)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } table[ind] = tval; @@ -1353,7 +1400,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, } if (unlikely (jcnt != 0)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } } @@ -1406,7 +1453,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK) != next_secondary)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1424,7 +1471,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } secondary = tprimary & HUFFMAN_VALUE_MASK; @@ -1432,7 +1479,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, & HUFFMAN_BITS_MASK); if (unlikely (secondary_bits < j - 8)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } } @@ -1448,7 +1495,7 @@ elf_zlib_inflate_table (unsigned char *codes, size_t codes_len, { if (unlikely (table[secondary + 0x100 + ind] != 0)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } table[secondary + 0x100 + ind] = tval; @@ -1664,28 +1711,28 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding. */ { /* Unknown compression method. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } if (unlikely ((pin[0] >> 4) > 7)) { /* Window size too large. Other than this check, we don't care about the window size. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } if (unlikely ((pin[1] & 0x20) != 0)) { /* Stream expects a predefined dictionary, but we have no dictionary. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } val = (pin[0] << 8) | pin[1]; if (unlikely (val % 31 != 0)) { /* Header check failure. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } pin += 2; @@ -1722,7 +1769,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely (type == 3)) { /* Invalid block type. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1745,7 +1792,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely ((pinend - pin) < 4)) { /* Missing length. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } len = pin[0] | (pin[1] << 8); @@ -1755,14 +1802,14 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely (len != lenc)) { /* Corrupt data. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } if (unlikely (len > (unsigned int) (pinend - pin) || len > (unsigned int) (poutend - pout))) { /* Not enough space in buffers. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } memcpy (pout, pin, len); @@ -1812,7 +1859,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely (nlit > 286 || ndist > 30)) { /* Values out of range. */ - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1977,7 +2024,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, a secondary table is never necessary. */ if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -1997,7 +2044,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely (plen == plenbase)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2010,7 +2057,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, bits -= 2; if (unlikely ((unsigned int) (plenend - plen) < c)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2045,7 +2092,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, bits -= 3; if (unlikely ((unsigned int) (plenend - plen) < c)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2091,7 +2138,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, bits -= 7; if (unlikely ((unsigned int) (plenend - plen) < c)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2100,7 +2147,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, } else { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } } @@ -2110,7 +2157,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, plen = plenbase; if (unlikely (plen[256] == 0)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2162,7 +2209,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, { if (unlikely (pout == poutend)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2191,7 +2238,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, len = 258; else if (unlikely (lit > 285)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } else @@ -2244,13 +2291,13 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely (pout == porigout)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } if (unlikely ((unsigned int) (poutend - pout) < len)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2259,7 +2306,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, } else if (unlikely (dist > 29)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } else @@ -2290,13 +2337,13 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, if (unlikely ((unsigned int) (pout - porigout) < dist)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } if (unlikely ((unsigned int) (poutend - pout) < len)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2326,7 +2373,7 @@ elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table, /* We should have filled the output buffer. */ if (unlikely (pout != poutend)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2453,7 +2500,7 @@ elf_zlib_verify_checksum (const unsigned char *checkbytes, if (unlikely ((s2 << 16) + s1 != cksum)) { - elf_zlib_failed (); + elf_uncompress_failed (); return 0; } @@ -2608,6 +2655,1311 @@ backtrace_uncompress_zdebug (struct backtrace_state *state, return ret; } +/* Number of LZMA states. */ +#define LZMA_STATES (12) + +/* Number of LZMA position states. The pb value of the property byte + is the number of bits to include in these states, and the maximum + value of pb is 4. */ +#define LZMA_POS_STATES (16) + +/* Number of LZMA distance states. These are used match distances + with a short match length: up to 4 bytes. */ +#define LZMA_DIST_STATES (4) + +/* Number of LZMA distance slots. LZMA uses six bits to encode larger + match lengths, so 1 << 6 possible probabilities. */ +#define LZMA_DIST_SLOTS (64) + +/* LZMA distances 0 to 3 are encoded directly, larger values use a + probability model. */ +#define LZMA_DIST_MODEL_START (4) + +/* The LZMA probability model ends at 14. */ +#define LZMA_DIST_MODEL_END (14) + +/* LZMA distance slots for distances less than 127. */ +#define LZMA_FULL_DISTANCES (128) + +/* LZMA uses four alignment bits. */ +#define LZMA_ALIGN_SIZE (16) + +/* LZMA match length is encoded with 4, 5, or 10 bits, some of which + are already known. */ +#define LZMA_LEN_LOW_SYMBOLS (8) +#define LZMA_LEN_MID_SYMBOLS (8) +#define LZMA_LEN_HIGH_SYMBOLS (256) + +/* LZMA literal encoding. */ +#define LZMA_LITERAL_CODERS_MAX (16) +#define LZMA_LITERAL_CODER_SIZE (0x300) + +/* LZMA is based on a large set of probabilities, each managed + independently. Each probability is an 11 bit number that we store + in a uint16_t. We use a single large array of probabilities. */ + +/* Lengths of entries in the LZMA probabilities array. The names used + here are copied from the Linux kernel implementation. */ + +#define LZMA_PROB_IS_MATCH_LEN (LZMA_STATES * LZMA_POS_STATES) +#define LZMA_PROB_IS_REP_LEN LZMA_STATES +#define LZMA_PROB_IS_REP0_LEN LZMA_STATES +#define LZMA_PROB_IS_REP1_LEN LZMA_STATES +#define LZMA_PROB_IS_REP2_LEN LZMA_STATES +#define LZMA_PROB_IS_REP0_LONG_LEN (LZMA_STATES * LZMA_POS_STATES) +#define LZMA_PROB_DIST_SLOT_LEN (LZMA_DIST_STATES * LZMA_DIST_SLOTS) +#define LZMA_PROB_DIST_SPECIAL_LEN (LZMA_FULL_DISTANCES - LZMA_DIST_MODEL_END) +#define LZMA_PROB_DIST_ALIGN_LEN LZMA_ALIGN_SIZE +#define LZMA_PROB_MATCH_LEN_CHOICE_LEN 1 +#define LZMA_PROB_MATCH_LEN_CHOICE2_LEN 1 +#define LZMA_PROB_MATCH_LEN_LOW_LEN (LZMA_POS_STATES * LZMA_LEN_LOW_SYMBOLS) +#define LZMA_PROB_MATCH_LEN_MID_LEN (LZMA_POS_STATES * LZMA_LEN_MID_SYMBOLS) +#define LZMA_PROB_MATCH_LEN_HIGH_LEN LZMA_LEN_HIGH_SYMBOLS +#define LZMA_PROB_REP_LEN_CHOICE_LEN 1 +#define LZMA_PROB_REP_LEN_CHOICE2_LEN 1 +#define LZMA_PROB_REP_LEN_LOW_LEN (LZMA_POS_STATES * LZMA_LEN_LOW_SYMBOLS) +#define LZMA_PROB_REP_LEN_MID_LEN (LZMA_POS_STATES * LZMA_LEN_MID_SYMBOLS) +#define LZMA_PROB_REP_LEN_HIGH_LEN LZMA_LEN_HIGH_SYMBOLS +#define LZMA_PROB_LITERAL_LEN \ + (LZMA_LITERAL_CODERS_MAX * LZMA_LITERAL_CODER_SIZE) + +/* Offsets into the LZMA probabilities array. This is mechanically + generated from the above lengths. */ + +#define LZMA_PROB_IS_MATCH_OFFSET 0 +#define LZMA_PROB_IS_REP_OFFSET \ + (LZMA_PROB_IS_MATCH_OFFSET + LZMA_PROB_IS_MATCH_LEN) +#define LZMA_PROB_IS_REP0_OFFSET \ + (LZMA_PROB_IS_REP_OFFSET + LZMA_PROB_IS_REP_LEN) +#define LZMA_PROB_IS_REP1_OFFSET \ + (LZMA_PROB_IS_REP0_OFFSET + LZMA_PROB_IS_REP0_LEN) +#define LZMA_PROB_IS_REP2_OFFSET \ + (LZMA_PROB_IS_REP1_OFFSET + LZMA_PROB_IS_REP1_LEN) +#define LZMA_PROB_IS_REP0_LONG_OFFSET \ + (LZMA_PROB_IS_REP2_OFFSET + LZMA_PROB_IS_REP2_LEN) +#define LZMA_PROB_DIST_SLOT_OFFSET \ + (LZMA_PROB_IS_REP0_LONG_OFFSET + LZMA_PROB_IS_REP0_LONG_LEN) +#define LZMA_PROB_DIST_SPECIAL_OFFSET \ + (LZMA_PROB_DIST_SLOT_OFFSET + LZMA_PROB_DIST_SLOT_LEN) +#define LZMA_PROB_DIST_ALIGN_OFFSET \ + (LZMA_PROB_DIST_SPECIAL_OFFSET + LZMA_PROB_DIST_SPECIAL_LEN) +#define LZMA_PROB_MATCH_LEN_CHOICE_OFFSET \ + (LZMA_PROB_DIST_ALIGN_OFFSET + LZMA_PROB_DIST_ALIGN_LEN) +#define LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET \ + (LZMA_PROB_MATCH_LEN_CHOICE_OFFSET + LZMA_PROB_MATCH_LEN_CHOICE_LEN) +#define LZMA_PROB_MATCH_LEN_LOW_OFFSET \ + (LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET + LZMA_PROB_MATCH_LEN_CHOICE2_LEN) +#define LZMA_PROB_MATCH_LEN_MID_OFFSET \ + (LZMA_PROB_MATCH_LEN_LOW_OFFSET + LZMA_PROB_MATCH_LEN_LOW_LEN) +#define LZMA_PROB_MATCH_LEN_HIGH_OFFSET \ + (LZMA_PROB_MATCH_LEN_MID_OFFSET + LZMA_PROB_MATCH_LEN_MID_LEN) +#define LZMA_PROB_REP_LEN_CHOICE_OFFSET \ + (LZMA_PROB_MATCH_LEN_HIGH_OFFSET + LZMA_PROB_MATCH_LEN_HIGH_LEN) +#define LZMA_PROB_REP_LEN_CHOICE2_OFFSET \ + (LZMA_PROB_REP_LEN_CHOICE_OFFSET + LZMA_PROB_REP_LEN_CHOICE_LEN) +#define LZMA_PROB_REP_LEN_LOW_OFFSET \ + (LZMA_PROB_REP_LEN_CHOICE2_OFFSET + LZMA_PROB_REP_LEN_CHOICE2_LEN) +#define LZMA_PROB_REP_LEN_MID_OFFSET \ + (LZMA_PROB_REP_LEN_LOW_OFFSET + LZMA_PROB_REP_LEN_LOW_LEN) +#define LZMA_PROB_REP_LEN_HIGH_OFFSET \ + (LZMA_PROB_REP_LEN_MID_OFFSET + LZMA_PROB_REP_LEN_MID_LEN) +#define LZMA_PROB_LITERAL_OFFSET \ + (LZMA_PROB_REP_LEN_HIGH_OFFSET + LZMA_PROB_REP_LEN_HIGH_LEN) + +#define LZMA_PROB_TOTAL_COUNT \ + (LZMA_PROB_LITERAL_OFFSET + LZMA_PROB_LITERAL_LEN) + +/* Check that the number of LZMA probabilities is the same as the + Linux kernel implementation. */ + +#if LZMA_PROB_TOTAL_COUNT != 1846 + (1 << 4) * 0x300 + #error Wrong number of LZMA probabilities +#endif + +/* Expressions for the offset in the LZMA probabilities array of a + specific probability. */ + +#define LZMA_IS_MATCH(state, pos) \ + (LZMA_PROB_IS_MATCH_OFFSET + (state) * LZMA_POS_STATES + (pos)) +#define LZMA_IS_REP(state) \ + (LZMA_PROB_IS_REP_OFFSET + (state)) +#define LZMA_IS_REP0(state) \ + (LZMA_PROB_IS_REP0_OFFSET + (state)) +#define LZMA_IS_REP1(state) \ + (LZMA_PROB_IS_REP1_OFFSET + (state)) +#define LZMA_IS_REP2(state) \ + (LZMA_PROB_IS_REP2_OFFSET + (state)) +#define LZMA_IS_REP0_LONG(state, pos) \ + (LZMA_PROB_IS_REP0_LONG_OFFSET + (state) * LZMA_POS_STATES + (pos)) +#define LZMA_DIST_SLOT(dist, slot) \ + (LZMA_PROB_DIST_SLOT_OFFSET + (dist) * LZMA_DIST_SLOTS + (slot)) +#define LZMA_DIST_SPECIAL(dist) \ + (LZMA_PROB_DIST_SPECIAL_OFFSET + (dist)) +#define LZMA_DIST_ALIGN(dist) \ + (LZMA_PROB_DIST_ALIGN_OFFSET + (dist)) +#define LZMA_MATCH_LEN_CHOICE \ + LZMA_PROB_MATCH_LEN_CHOICE_OFFSET +#define LZMA_MATCH_LEN_CHOICE2 \ + LZMA_PROB_MATCH_LEN_CHOICE2_OFFSET +#define LZMA_MATCH_LEN_LOW(pos, sym) \ + (LZMA_PROB_MATCH_LEN_LOW_OFFSET + (pos) * LZMA_LEN_LOW_SYMBOLS + (sym)) +#define LZMA_MATCH_LEN_MID(pos, sym) \ + (LZMA_PROB_MATCH_LEN_MID_OFFSET + (pos) * LZMA_LEN_MID_SYMBOLS + (sym)) +#define LZMA_MATCH_LEN_HIGH(sym) \ + (LZMA_PROB_MATCH_LEN_HIGH_OFFSET + (sym)) +#define LZMA_REP_LEN_CHOICE \ + LZMA_PROB_REP_LEN_CHOICE_OFFSET +#define LZMA_REP_LEN_CHOICE2 \ + LZMA_PROB_REP_LEN_CHOICE2_OFFSET +#define LZMA_REP_LEN_LOW(pos, sym) \ + (LZMA_PROB_REP_LEN_LOW_OFFSET + (pos) * LZMA_LEN_LOW_SYMBOLS + (sym)) +#define LZMA_REP_LEN_MID(pos, sym) \ + (LZMA_PROB_REP_LEN_MID_OFFSET + (pos) * LZMA_LEN_MID_SYMBOLS + (sym)) +#define LZMA_REP_LEN_HIGH(sym) \ + (LZMA_PROB_REP_LEN_HIGH_OFFSET + (sym)) +#define LZMA_LITERAL(code, size) \ + (LZMA_PROB_LITERAL_OFFSET + (code) * LZMA_LITERAL_CODER_SIZE + (size)) + +/* Read an LZMA varint from BUF, reading and updating *POFFSET, + setting *VAL. Returns 0 on error, 1 on success. */ + +static int +elf_lzma_varint (const unsigned char *compressed, size_t compressed_size, + size_t *poffset, uint64_t *val) +{ + size_t off; + int i; + uint64_t v; + unsigned char b; + + off = *poffset; + i = 0; + v = 0; + while (1) + { + if (unlikely (off >= compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + b = compressed[off]; + v |= (b & 0x7f) << (i * 7); + ++off; + if ((b & 0x80) == 0) + { + *poffset = off; + *val = v; + return 1; + } + ++i; + if (unlikely (i >= 9)) + { + elf_uncompress_failed (); + return 0; + } + } +} + +/* Normalize the LZMA range decoder, pulling in an extra input byte if + needed. */ + +static void +elf_lzma_range_normalize (const unsigned char *compressed, + size_t compressed_size, size_t *poffset, + uint32_t *prange, uint32_t *pcode) +{ + if (*prange < (1U << 24)) + { + if (unlikely (*poffset >= compressed_size)) + { + /* We assume this will be caught elsewhere. */ + elf_uncompress_failed (); + return; + } + *prange <<= 8; + *pcode <<= 8; + *pcode += compressed[*poffset]; + ++*poffset; + } +} + +/* Read and return a single bit from the LZMA stream, reading and + updating *PROB. Each bit comes from the range coder. */ + +static int +elf_lzma_bit (const unsigned char *compressed, size_t compressed_size, + uint16_t *prob, size_t *poffset, uint32_t *prange, + uint32_t *pcode) +{ + uint32_t bound; + + elf_lzma_range_normalize (compressed, compressed_size, poffset, + prange, pcode); + bound = (*prange >> 11) * (uint32_t) *prob; + if (*pcode < bound) + { + *prange = bound; + *prob += ((1U << 11) - *prob) >> 5; + return 0; + } + else + { + *prange -= bound; + *pcode -= bound; + *prob -= *prob >> 5; + return 1; + } +} + +/* Read an integer of size BITS from the LZMA stream, most significant + bit first. The bits are predicted using PROBS. */ + +static uint32_t +elf_lzma_integer (const unsigned char *compressed, size_t compressed_size, + uint16_t *probs, uint32_t bits, size_t *poffset, + uint32_t *prange, uint32_t *pcode) +{ + uint32_t sym; + uint32_t i; + + sym = 1; + for (i = 0; i < bits; i++) + { + int bit; + + bit = elf_lzma_bit (compressed, compressed_size, probs + sym, poffset, + prange, pcode); + sym <<= 1; + sym += bit; + } + return sym - (1 << bits); +} + +/* Read an integer of size BITS from the LZMA stream, least + significant bit first. The bits are predicted using PROBS. */ + +static uint32_t +elf_lzma_reverse_integer (const unsigned char *compressed, + size_t compressed_size, uint16_t *probs, + uint32_t bits, size_t *poffset, uint32_t *prange, + uint32_t *pcode) +{ + uint32_t sym; + uint32_t val; + uint32_t i; + + sym = 1; + val = 0; + for (i = 0; i < bits; i++) + { + int bit; + + bit = elf_lzma_bit (compressed, compressed_size, probs + sym, poffset, + prange, pcode); + sym <<= 1; + sym += bit; + val += bit << i; + } + return val; +} + +/* Read a length from the LZMA stream. IS_REP picks either LZMA_MATCH + or LZMA_REP probabilities. */ + +static uint32_t +elf_lzma_len (const unsigned char *compressed, size_t compressed_size, + uint16_t *probs, int is_rep, unsigned int pos_state, + size_t *poffset, uint32_t *prange, uint32_t *pcode) +{ + uint16_t *probs_choice; + uint16_t *probs_sym; + uint32_t bits; + uint32_t len; + + probs_choice = probs + (is_rep + ? LZMA_REP_LEN_CHOICE + : LZMA_MATCH_LEN_CHOICE); + if (elf_lzma_bit (compressed, compressed_size, probs_choice, poffset, + prange, pcode)) + { + probs_choice = probs + (is_rep + ? LZMA_REP_LEN_CHOICE2 + : LZMA_MATCH_LEN_CHOICE2); + if (elf_lzma_bit (compressed, compressed_size, probs_choice, + poffset, prange, pcode)) + { + probs_sym = probs + (is_rep + ? LZMA_REP_LEN_HIGH (0) + : LZMA_MATCH_LEN_HIGH (0)); + bits = 8; + len = 2 + 8 + 8; + } + else + { + probs_sym = probs + (is_rep + ? LZMA_REP_LEN_MID (pos_state, 0) + : LZMA_MATCH_LEN_MID (pos_state, 0)); + bits = 3; + len = 2 + 8; + } + } + else + { + probs_sym = probs + (is_rep + ? LZMA_REP_LEN_LOW (pos_state, 0) + : LZMA_MATCH_LEN_LOW (pos_state, 0)); + bits = 3; + len = 2; + } + + len += elf_lzma_integer (compressed, compressed_size, probs_sym, bits, + poffset, prange, pcode); + return len; +} + +/* Uncompress one LZMA block from a minidebug file. The compressed + data is at COMPRESSED + *POFFSET. Update *POFFSET. Store the data + into the memory at UNCOMPRESSED, size UNCOMPRESSED_SIZE. CHECK is + the stream flag from the xz header. Return 1 on successful + decompression. */ + +static int +elf_uncompress_lzma_block (const unsigned char *compressed, + size_t compressed_size, unsigned char check, + uint16_t *probs, unsigned char *uncompressed, + size_t uncompressed_size, size_t *poffset) +{ + size_t off; + size_t block_header_offset; + size_t block_header_size; + unsigned char block_flags; + uint64_t header_compressed_size; + uint64_t header_uncompressed_size; + unsigned char lzma2_properties; + uint32_t computed_crc; + uint32_t stream_crc; + size_t uncompressed_offset; + size_t dict_start_offset; + unsigned int lc; + unsigned int lp; + unsigned int pb; + uint32_t range; + uint32_t code; + uint32_t lstate; + uint32_t dist[4]; + + off = *poffset; + block_header_offset = off; + + /* Block header size is a single byte. */ + if (unlikely (off >= compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + block_header_size = (compressed[off] + 1) * 4; + if (unlikely (off + block_header_size > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + /* Block flags. */ + block_flags = compressed[off + 1]; + if (unlikely ((block_flags & 0x3c) != 0)) + { + elf_uncompress_failed (); + return 0; + } + + off += 2; + + /* Optional compressed size. */ + header_compressed_size = 0; + if ((block_flags & 0x40) != 0) + { + *poffset = off; + if (!elf_lzma_varint (compressed, compressed_size, poffset, + &header_compressed_size)) + return 0; + off = *poffset; + } + + /* Optional uncompressed size. */ + header_uncompressed_size = 0; + if ((block_flags & 0x80) != 0) + { + *poffset = off; + if (!elf_lzma_varint (compressed, compressed_size, poffset, + &header_uncompressed_size)) + return 0; + off = *poffset; + } + + /* The recipe for creating a minidebug file is to run the xz program + with no arguments, so we expect exactly one filter: lzma2. */ + + if (unlikely ((block_flags & 0x3) != 0)) + { + elf_uncompress_failed (); + return 0; + } + + if (unlikely (off + 2 >= block_header_offset + block_header_size)) + { + elf_uncompress_failed (); + return 0; + } + + /* The filter ID for LZMA2 is 0x21. */ + if (unlikely (compressed[off] != 0x21)) + { + elf_uncompress_failed (); + return 0; + } + ++off; + + /* The size of the filter properties for LZMA2 is 1. */ + if (unlikely (compressed[off] != 1)) + { + elf_uncompress_failed (); + return 0; + } + ++off; + + lzma2_properties = compressed[off]; + ++off; + + if (unlikely (lzma2_properties > 40)) + { + elf_uncompress_failed (); + return 0; + } + + /* The properties describe the dictionary size, but we don't care + what that is. */ + + /* Block header padding. */ + if (unlikely (off + 4 > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + off = (off + 3) &~ (size_t) 3; + + if (unlikely (off + 4 > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + /* Block header CRC. */ + computed_crc = elf_crc32 (0, compressed + block_header_offset, + block_header_size - 4); + stream_crc = (compressed[off] + | (compressed[off + 1] << 8) + | (compressed[off + 2] << 16) + | (compressed[off + 3] << 24)); + if (unlikely (computed_crc != stream_crc)) + { + elf_uncompress_failed (); + return 0; + } + off += 4; + + /* Read a sequence of LZMA2 packets. */ + + uncompressed_offset = 0; + dict_start_offset = 0; + lc = 0; + lp = 0; + pb = 0; + lstate = 0; + while (off < compressed_size) + { + unsigned char control; + + range = 0xffffffff; + code = 0; + + control = compressed[off]; + ++off; + if (unlikely (control == 0)) + { + /* End of packets. */ + break; + } + + if (control == 1 || control >= 0xe0) + { + /* Reset dictionary to empty. */ + dict_start_offset = uncompressed_offset; + } + + if (control < 0x80) + { + size_t chunk_size; + + /* The only valid values here are 1 or 2. A 1 means to + reset the dictionary (done above). Then we see an + uncompressed chunk. */ + + if (unlikely (control > 2)) + { + elf_uncompress_failed (); + return 0; + } + + /* An uncompressed chunk is a two byte size followed by + data. */ + + if (unlikely (off + 2 > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + chunk_size = compressed[off] << 8; + chunk_size += compressed[off + 1]; + ++chunk_size; + + off += 2; + + if (unlikely (off + chunk_size > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + if (unlikely (uncompressed_offset + chunk_size > uncompressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + memcpy (uncompressed + uncompressed_offset, compressed + off, + chunk_size); + uncompressed_offset += chunk_size; + off += chunk_size; + } + else + { + size_t uncompressed_chunk_start; + size_t uncompressed_chunk_size; + size_t compressed_chunk_size; + size_t limit; + + /* An LZMA chunk. This starts with an uncompressed size and + a compressed size. */ + + if (unlikely (off + 4 >= compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + uncompressed_chunk_start = uncompressed_offset; + + uncompressed_chunk_size = (control & 0x1f) << 16; + uncompressed_chunk_size += compressed[off] << 8; + uncompressed_chunk_size += compressed[off + 1]; + ++uncompressed_chunk_size; + + compressed_chunk_size = compressed[off + 2] << 8; + compressed_chunk_size += compressed[off + 3]; + ++compressed_chunk_size; + + off += 4; + + /* Bit 7 (0x80) is set. + Bits 6 and 5 (0x40 and 0x20) are as follows: + 0: don't reset anything + 1: reset state + 2: reset state, read properties + 3: reset state, read properties, reset dictionary (done above) */ + + if (control >= 0xc0) + { + unsigned char props; + + /* Bit 6 is set, read properties. */ + + if (unlikely (off >= compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + props = compressed[off]; + ++off; + if (unlikely (props > (4 * 5 + 4) * 9 + 8)) + { + elf_uncompress_failed (); + return 0; + } + pb = 0; + while (props >= 9 * 5) + { + props -= 9 * 5; + ++pb; + } + lp = 0; + while (props > 9) + { + props -= 9; + ++lp; + } + lc = props; + if (unlikely (lc + lp > 4)) + { + elf_uncompress_failed (); + return 0; + } + } + + if (control >= 0xa0) + { + size_t i; + + /* Bit 5 or 6 is set, reset LZMA state. */ + + lstate = 0; + memset (&dist, 0, sizeof dist); + for (i = 0; i < LZMA_PROB_TOTAL_COUNT; i++) + probs[i] = 1 << 10; + range = 0xffffffff; + code = 0; + } + + /* Read the range code. */ + + if (unlikely (off + 5 > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + /* The byte at compressed[off] is ignored for some + reason. */ + + code = ((compressed[off + 1] << 24) + + (compressed[off + 2] << 16) + + (compressed[off + 3] << 8) + + compressed[off + 4]); + off += 5; + + /* This is the main LZMA decode loop. */ + + limit = off + compressed_chunk_size; + *poffset = off; + while (*poffset < limit) + { + unsigned int pos_state; + + if (unlikely (uncompressed_offset + == (uncompressed_chunk_start + + uncompressed_chunk_size))) + { + /* We've decompressed all the expected bytes. */ + break; + } + + pos_state = ((uncompressed_offset - dict_start_offset) + & ((1 << pb) - 1)); + + if (elf_lzma_bit (compressed, compressed_size, + probs + LZMA_IS_MATCH (lstate, pos_state), + poffset, &range, &code)) + { + uint32_t len; + + if (elf_lzma_bit (compressed, compressed_size, + probs + LZMA_IS_REP (lstate), + poffset, &range, &code)) + { + int short_rep; + uint32_t next_dist; + + /* Repeated match. */ + + short_rep = 0; + if (elf_lzma_bit (compressed, compressed_size, + probs + LZMA_IS_REP0 (lstate), + poffset, &range, &code)) + { + if (elf_lzma_bit (compressed, compressed_size, + probs + LZMA_IS_REP1 (lstate), + poffset, &range, &code)) + { + if (elf_lzma_bit (compressed, compressed_size, + probs + LZMA_IS_REP2 (lstate), + poffset, &range, &code)) + { + next_dist = dist[3]; + dist[3] = dist[2]; + } + else + { + next_dist = dist[2]; + } + dist[2] = dist[1]; + } + else + { + next_dist = dist[1]; + } + + dist[1] = dist[0]; + dist[0] = next_dist; + } + else + { + if (!elf_lzma_bit (compressed, compressed_size, + (probs + + LZMA_IS_REP0_LONG (lstate, + pos_state)), + poffset, &range, &code)) + short_rep = 1; + } + + if (lstate < 7) + lstate = short_rep ? 9 : 8; + else + lstate = 11; + + if (short_rep) + len = 1; + else + len = elf_lzma_len (compressed, compressed_size, + probs, 1, pos_state, poffset, + &range, &code); + } + else + { + uint32_t dist_state; + uint32_t dist_slot; + uint16_t *probs_dist; + + /* Match. */ + + if (lstate < 7) + lstate = 7; + else + lstate = 10; + dist[3] = dist[2]; + dist[2] = dist[1]; + dist[1] = dist[0]; + len = elf_lzma_len (compressed, compressed_size, + probs, 0, pos_state, poffset, + &range, &code); + + if (len < 4 + 2) + dist_state = len - 2; + else + dist_state = 3; + probs_dist = probs + LZMA_DIST_SLOT (dist_state, 0); + dist_slot = elf_lzma_integer (compressed, + compressed_size, + probs_dist, 6, + poffset, &range, + &code); + if (dist_slot < LZMA_DIST_MODEL_START) + dist[0] = dist_slot; + else + { + uint32_t limit; + + limit = (dist_slot >> 1) - 1; + dist[0] = 2 + (dist_slot & 1); + if (dist_slot < LZMA_DIST_MODEL_END) + { + dist[0] <<= limit; + probs_dist = (probs + + LZMA_DIST_SPECIAL(dist[0] + - dist_slot + - 1)); + dist[0] += + elf_lzma_reverse_integer (compressed, + compressed_size, + probs_dist, + limit, poffset, + &range, &code); + } + else + { + uint32_t dist0; + uint32_t i; + + dist0 = dist[0]; + for (i = 0; i < limit - 4; i++) + { + uint32_t mask; + + elf_lzma_range_normalize (compressed, + compressed_size, + poffset, + &range, &code); + range >>= 1; + code -= range; + mask = -(code >> 31); + code += range & mask; + dist0 <<= 1; + dist0 += mask + 1; + } + dist0 <<= 4; + probs_dist = probs + LZMA_DIST_ALIGN (0); + dist0 += + elf_lzma_reverse_integer (compressed, + compressed_size, + probs_dist, 4, + poffset, + &range, &code); + dist[0] = dist0; + } + } + } + + if (unlikely (uncompressed_offset + - dict_start_offset < dist[0] + 1)) + { + elf_uncompress_failed (); + return 0; + } + if (unlikely (uncompressed_offset + len > uncompressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + if (dist[0] == 0) + { + /* A common case, meaning repeat the last + character LEN times. */ + memset (uncompressed + uncompressed_offset, + uncompressed[uncompressed_offset - 1], + len); + uncompressed_offset += len; + } + else if (dist[0] + 1 >= len) + { + memcpy (uncompressed + uncompressed_offset, + uncompressed + uncompressed_offset - dist[0] - 1, + len); + uncompressed_offset += len; + } + else + { + while (len > 0) + { + uint32_t copy; + + copy = len < dist[0] + 1 ? len : dist[0] + 1; + memcpy (uncompressed + uncompressed_offset, + (uncompressed + uncompressed_offset + - dist[0] - 1), + copy); + len -= copy; + uncompressed_offset += copy; + } + } + } + else + { + unsigned char prev; + unsigned char low; + size_t high; + uint16_t *lit_probs; + unsigned int sym; + + /* Literal value. */ + + if (uncompressed_offset > 0) + prev = uncompressed[uncompressed_offset - 1]; + else + prev = 0; + low = prev >> (8 - lc); + high = (((uncompressed_offset - dict_start_offset) + & ((1 << lp) - 1)) + << lc); + lit_probs = probs + LZMA_LITERAL (low + high, 0); + if (lstate < 7) + sym = elf_lzma_integer (compressed, compressed_size, + lit_probs, 8, poffset, &range, + &code); + else + { + unsigned int match; + unsigned int bit; + unsigned int match_bit; + unsigned int idx; + + sym = 1; + if (uncompressed_offset >= dist[0] + 1) + match = uncompressed[uncompressed_offset - dist[0] - 1]; + else + match = 0; + match <<= 1; + bit = 0x100; + do + { + match_bit = match & bit; + match <<= 1; + idx = bit + match_bit + sym; + sym <<= 1; + if (elf_lzma_bit (compressed, compressed_size, + lit_probs + idx, poffset, + &range, &code)) + { + ++sym; + bit &= match_bit; + } + else + { + bit &= ~ match_bit; + } + } + while (sym < 0x100); + } + + if (unlikely (uncompressed_offset >= uncompressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + uncompressed[uncompressed_offset] = (unsigned char) sym; + ++uncompressed_offset; + if (lstate <= 3) + lstate = 0; + else if (lstate <= 9) + lstate -= 3; + else + lstate -= 6; + } + } + + elf_lzma_range_normalize (compressed, compressed_size, poffset, + &range, &code); + + off = *poffset; + } + } + + /* We have reached the end of the block. Pad to four byte + boundary. */ + off = (off + 3) &~ (size_t) 3; + if (unlikely (off > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + + switch (check) + { + case 0: + /* No check. */ + break; + + case 1: + /* CRC32 */ + if (unlikely (off + 4 > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + computed_crc = elf_crc32 (0, uncompressed, uncompressed_offset); + stream_crc = (compressed[off] + | (compressed[off + 1] << 8) + | (compressed[off + 2] << 16) + | (compressed[off + 3] << 24)); + if (computed_crc != stream_crc) + { + elf_uncompress_failed (); + return 0; + } + off += 4; + break; + + case 4: + /* CRC64. We don't bother computing a CRC64 checksum. */ + if (unlikely (off + 8 > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + off += 8; + break; + + case 10: + /* SHA. We don't bother computing a SHA checksum. */ + if (unlikely (off + 32 > compressed_size)) + { + elf_uncompress_failed (); + return 0; + } + off += 32; + break; + + default: + elf_uncompress_failed (); + return 0; + } + + *poffset = off; + + return 1; +} + +/* Uncompress LZMA data found in a minidebug file. The minidebug + format is described at + https://sourceware.org/gdb/current/onlinedocs/gdb/MiniDebugInfo.html. + Returns 0 on error, 1 on successful decompression. For this + function we return 0 on failure to decompress, as the calling code + will carry on in that case. */ + +static int +elf_uncompress_lzma (struct backtrace_state *state, + const unsigned char *compressed, size_t compressed_size, + backtrace_error_callback error_callback, void *data, + unsigned char **uncompressed, size_t *uncompressed_size) +{ + size_t header_size; + size_t footer_size; + unsigned char check; + uint32_t computed_crc; + uint32_t stream_crc; + size_t offset; + size_t index_size; + size_t footer_offset; + size_t index_offset; + uint64_t index_compressed_size; + uint64_t index_uncompressed_size; + unsigned char *mem; + uint16_t *probs; + size_t compressed_block_size; + + /* The format starts with a stream header and ends with a stream + footer. */ + header_size = 12; + footer_size = 12; + if (unlikely (compressed_size < header_size + footer_size)) + { + elf_uncompress_failed (); + return 0; + } + + /* The stream header starts with a magic string. */ + if (unlikely (memcmp (compressed, "\375" "7zXZ\0", 6) != 0)) + { + elf_uncompress_failed (); + return 0; + } + + /* Next come stream flags. The first byte is zero, the second byte + is the check. */ + if (unlikely (compressed[6] != 0)) + { + elf_uncompress_failed (); + return 0; + } + check = compressed[7]; + if (unlikely ((check & 0xf8) != 0)) + { + elf_uncompress_failed (); + return 0; + } + + /* Next comes a CRC of the stream flags. */ + computed_crc = elf_crc32 (0, compressed + 6, 2); + stream_crc = (compressed[8] + | (compressed[9] << 8) + | (compressed[10] << 16) + | (compressed[11] << 24)); + if (unlikely (computed_crc != stream_crc)) + { + elf_uncompress_failed (); + return 0; + } + + /* Now that we've parsed the header, parse the footer, so that we + can get the uncompressed size. */ + + /* The footer ends with two magic bytes. */ + + offset = compressed_size; + if (unlikely (memcmp (compressed + offset - 2, "YZ", 2) != 0)) + { + elf_uncompress_failed (); + return 0; + } + offset -= 2; + + /* Before that are the stream flags, which should be the same as the + flags in the header. */ + if (unlikely (compressed[offset - 2] != 0 + || compressed[offset - 1] != check)) + { + elf_uncompress_failed (); + return 0; + } + offset -= 2; + + /* Before that is the size of the index field, which precedes the + footer. */ + index_size = (compressed[offset - 4] + | (compressed[offset - 3] << 8) + | (compressed[offset - 2] << 16) + | (compressed[offset - 1] << 24)); + index_size = (index_size + 1) * 4; + offset -= 4; + + /* Before that is a footer CRC. */ + computed_crc = elf_crc32 (0, compressed + offset, 6); + stream_crc = (compressed[offset - 4] + | (compressed[offset - 3] << 8) + | (compressed[offset - 2] << 16) + | (compressed[offset - 1] << 24)); + if (unlikely (computed_crc != stream_crc)) + { + elf_uncompress_failed (); + return 0; + } + offset -= 4; + + /* The index comes just before the footer. */ + if (unlikely (offset < index_size + header_size)) + { + elf_uncompress_failed (); + return 0; + } + + footer_offset = offset; + offset -= index_size; + index_offset = offset; + + /* The index starts with a zero byte. */ + if (unlikely (compressed[offset] != 0)) + { + elf_uncompress_failed (); + return 0; + } + ++offset; + + /* Next is the number of blocks. We expect zero blocks for an empty + stream, and otherwise a single block. */ + if (unlikely (compressed[offset] == 0)) + { + *uncompressed = NULL; + *uncompressed_size = 0; + return 1; + } + if (unlikely (compressed[offset] != 1)) + { + elf_uncompress_failed (); + return 0; + } + ++offset; + + /* Next is the compressed size and the uncompressed size. */ + if (!elf_lzma_varint (compressed, compressed_size, &offset, + &index_compressed_size)) + return 0; + if (!elf_lzma_varint (compressed, compressed_size, &offset, + &index_uncompressed_size)) + return 0; + + /* Pad to a four byte boundary. */ + offset = (offset + 3) &~ (size_t) 3; + + /* Next is a CRC of the index. */ + computed_crc = elf_crc32 (0, compressed + index_offset, + offset - index_offset); + stream_crc = (compressed[offset] + | (compressed[offset + 1] << 8) + | (compressed[offset + 2] << 16) + | (compressed[offset + 3] << 24)); + if (unlikely (computed_crc != stream_crc)) + { + elf_uncompress_failed (); + return 0; + } + offset += 4; + + /* We should now be back at the footer. */ + if (unlikely (offset != footer_offset)) + { + elf_uncompress_failed (); + return 0; + } + + /* Allocate space to hold the uncompressed data. If we succeed in + uncompressing the LZMA data, we never free this memory. */ + mem = (unsigned char *) backtrace_alloc (state, index_uncompressed_size, + error_callback, data); + if (unlikely (mem == NULL)) + return 0; + *uncompressed = mem; + *uncompressed_size = index_uncompressed_size; + + /* Allocate space for probabilities. */ + probs = ((uint16_t *) + backtrace_alloc (state, + LZMA_PROB_TOTAL_COUNT * sizeof (uint16_t), + error_callback, data)); + if (unlikely (probs == NULL)) + { + backtrace_free (state, mem, index_uncompressed_size, error_callback, + data); + return 0; + } + + /* Uncompress the block, which follows the header. */ + offset = 12; + if (!elf_uncompress_lzma_block (compressed, compressed_size, check, probs, + mem, index_uncompressed_size, &offset)) + { + backtrace_free (state, mem, index_uncompressed_size, error_callback, + data); + return 0; + } + + compressed_block_size = offset - 12; + if (unlikely (compressed_block_size + != ((index_compressed_size + 3) &~ (size_t) 3))) + { + elf_uncompress_failed (); + backtrace_free (state, mem, index_uncompressed_size, error_callback, + data); + return 0; + } + + offset = (offset + 3) &~ (size_t) 3; + if (unlikely (offset != index_offset)) + { + elf_uncompress_failed (); + backtrace_free (state, mem, index_uncompressed_size, error_callback, + data); + return 0; + } + + return 1; +} + +/* This function is a hook for testing the LZMA support. It is only + used by tests. */ + +int +backtrace_uncompress_lzma (struct backtrace_state *state, + const unsigned char *compressed, + size_t compressed_size, + backtrace_error_callback error_callback, + void *data, unsigned char **uncompressed, + size_t *uncompressed_size) +{ + return elf_uncompress_lzma (state, compressed, compressed_size, + error_callback, data, uncompressed, + uncompressed_size); +} + /* Add the backtrace data for one ELF file. Returns 1 on success, 0 on failure (in both cases descriptor is closed) or -1 if exe is non-zero and the ELF file is ET_DYN, which tells the caller that @@ -2616,23 +3968,24 @@ backtrace_uncompress_zdebug (struct backtrace_state *state, static int elf_add (struct backtrace_state *state, const char *filename, int descriptor, + const unsigned char *memory, size_t memory_size, uintptr_t base_address, backtrace_error_callback error_callback, void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf, struct dwarf_data **fileline_entry, int exe, int debuginfo, const char *with_buildid_data, uint32_t with_buildid_size) { - struct backtrace_view ehdr_view; + struct elf_view ehdr_view; b_elf_ehdr ehdr; off_t shoff; unsigned int shnum; unsigned int shstrndx; - struct backtrace_view shdrs_view; + struct elf_view shdrs_view; int shdrs_view_valid; const b_elf_shdr *shdrs; const b_elf_shdr *shstrhdr; size_t shstr_size; off_t shstr_off; - struct backtrace_view names_view; + struct elf_view names_view; int names_view_valid; const char *names; unsigned int symtab_shndx; @@ -2640,31 +3993,36 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, unsigned int i; struct debug_section_info sections[DEBUG_MAX]; struct debug_section_info zsections[DEBUG_MAX]; - struct backtrace_view symtab_view; + struct elf_view symtab_view; int symtab_view_valid; - struct backtrace_view strtab_view; + struct elf_view strtab_view; int strtab_view_valid; - struct backtrace_view buildid_view; + struct elf_view buildid_view; int buildid_view_valid; const char *buildid_data; uint32_t buildid_size; - struct backtrace_view debuglink_view; + struct elf_view debuglink_view; int debuglink_view_valid; const char *debuglink_name; uint32_t debuglink_crc; - struct backtrace_view debugaltlink_view; + struct elf_view debugaltlink_view; int debugaltlink_view_valid; const char *debugaltlink_name; const char *debugaltlink_buildid_data; uint32_t debugaltlink_buildid_size; + struct elf_view gnu_debugdata_view; + int gnu_debugdata_view_valid; + size_t gnu_debugdata_size; + unsigned char *gnu_debugdata_uncompressed; + size_t gnu_debugdata_uncompressed_size; off_t min_offset; off_t max_offset; off_t debug_size; - struct backtrace_view debug_view; + struct elf_view debug_view; int debug_view_valid; unsigned int using_debug_view; uint16_t *zdebug_table; - struct backtrace_view split_debug_view[DEBUG_MAX]; + struct elf_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; @@ -2689,17 +4047,19 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, debugaltlink_name = NULL; debugaltlink_buildid_data = NULL; debugaltlink_buildid_size = 0; + gnu_debugdata_view_valid = 0; + gnu_debugdata_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, - data, &ehdr_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, 0, sizeof ehdr, + error_callback, data, &ehdr_view)) goto fail; - memcpy (&ehdr, ehdr_view.data, sizeof ehdr); + memcpy (&ehdr, ehdr_view.view.data, sizeof ehdr); - backtrace_release_view (state, &ehdr_view, error_callback, data); + elf_release_view (state, &ehdr_view, error_callback, data); if (ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 @@ -2747,14 +4107,14 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if ((shnum == 0 || shstrndx == SHN_XINDEX) && shoff != 0) { - struct backtrace_view shdr_view; + struct elf_view shdr_view; const b_elf_shdr *shdr; - if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, - error_callback, data, &shdr_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, shoff, + sizeof shdr, error_callback, data, &shdr_view)) goto fail; - shdr = (const b_elf_shdr *) shdr_view.data; + shdr = (const b_elf_shdr *) shdr_view.view.data; if (shnum == 0) shnum = shdr->sh_size; @@ -2778,7 +4138,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, shstrndx -= 0x100; } - backtrace_release_view (state, &shdr_view, error_callback, data); + elf_release_view (state, &shdr_view, error_callback, data); } if (shnum == 0 || shstrndx == 0) @@ -2789,12 +4149,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, /* 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)) + if (!elf_get_view (state, descriptor, memory, memory_size, + 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; + shdrs = (const b_elf_shdr *) shdrs_view.view.data; /* Read the section names. */ @@ -2802,11 +4163,11 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, shstr_size = shstrhdr->sh_size; shstr_off = shstrhdr->sh_offset; - if (!backtrace_get_view (state, descriptor, shstr_off, shstrhdr->sh_size, - error_callback, data, &names_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, shstr_off, + shstrhdr->sh_size, error_callback, data, &names_view)) goto fail; names_view_valid = 1; - names = (const char *) names_view.data; + names = (const char *) names_view.view.data; symtab_shndx = 0; dynsym_shndx = 0; @@ -2871,13 +4232,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, { const b_elf_note *note; - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &buildid_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, + shdr->sh_offset, shdr->sh_size, error_callback, + data, &buildid_view)) goto fail; buildid_view_valid = 1; - note = (const b_elf_note *) buildid_view.data; + note = (const b_elf_note *) buildid_view.view.data; if (note->type == NT_GNU_BUILD_ID && note->namesz == 4 && strncmp (note->name, "GNU", 4) == 0 @@ -2905,13 +4266,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, const char *debuglink_data; size_t crc_offset; - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &debuglink_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, + shdr->sh_offset, shdr->sh_size, error_callback, + data, &debuglink_view)) goto fail; debuglink_view_valid = 1; - debuglink_data = (const char *) debuglink_view.data; + debuglink_data = (const char *) debuglink_view.view.data; crc_offset = strnlen (debuglink_data, shdr->sh_size); crc_offset = (crc_offset + 3) & ~3; if (crc_offset + 4 <= shdr->sh_size) @@ -2927,13 +4288,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, const char *debugaltlink_data; size_t debugaltlink_name_len; - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &debugaltlink_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, + shdr->sh_offset, shdr->sh_size, error_callback, + data, &debugaltlink_view)) goto fail; debugaltlink_view_valid = 1; - debugaltlink_data = (const char *) debugaltlink_view.data; + debugaltlink_data = (const char *) debugaltlink_view.view.data; debugaltlink_name = debugaltlink_data; debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size); if (debugaltlink_name_len < shdr->sh_size) @@ -2947,20 +4308,32 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, } } + if (!gnu_debugdata_view_valid + && strcmp (name, ".gnu_debugdata") == 0) + { + if (!elf_get_view (state, descriptor, memory, memory_size, + shdr->sh_offset, shdr->sh_size, error_callback, + data, &gnu_debugdata_view)) + goto fail; + + gnu_debugdata_size = shdr->sh_size; + gnu_debugdata_view_valid = 1; + } + /* Read the .opd section on PowerPC64 ELFv1. */ if (ehdr.e_machine == EM_PPC64 && (ehdr.e_flags & EF_PPC64_ABI) < 2 && shdr->sh_type == SHT_PROGBITS && strcmp (name, ".opd") == 0) { - if (!backtrace_get_view (state, descriptor, shdr->sh_offset, - shdr->sh_size, error_callback, data, - &opd_data.view)) + if (!elf_get_view (state, descriptor, memory, memory_size, + shdr->sh_offset, shdr->sh_size, error_callback, + data, &opd_data.view)) goto fail; opd = &opd_data; opd->addr = shdr->sh_addr; - opd->data = (const char *) opd_data.view.data; + opd->data = (const char *) opd_data.view.view.data; opd->size = shdr->sh_size; } } @@ -2984,15 +4357,15 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, } strtab_shdr = &shdrs[strtab_shndx - 1]; - if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset, - symtab_shdr->sh_size, error_callback, data, - &symtab_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, + symtab_shdr->sh_offset, symtab_shdr->sh_size, + error_callback, data, &symtab_view)) goto fail; symtab_view_valid = 1; - if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset, - strtab_shdr->sh_size, error_callback, data, - &strtab_view)) + if (!elf_get_view (state, descriptor, memory, memory_size, + strtab_shdr->sh_offset, strtab_shdr->sh_size, + error_callback, data, &strtab_view)) goto fail; strtab_view_valid = 1; @@ -3002,8 +4375,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, goto fail; if (!elf_initialize_syminfo (state, base_address, - symtab_view.data, symtab_shdr->sh_size, - strtab_view.data, strtab_shdr->sh_size, + symtab_view.view.data, symtab_shdr->sh_size, + strtab_view.view.data, strtab_shdr->sh_size, error_callback, data, sdata, opd)) { backtrace_free (state, sdata, sizeof *sdata, error_callback, data); @@ -3012,7 +4385,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, /* We no longer need the symbol table, but we hold on to the string table permanently. */ - backtrace_release_view (state, &symtab_view, error_callback, data); + elf_release_view (state, &symtab_view, error_callback, data); symtab_view_valid = 0; strtab_view_valid = 0; @@ -3021,9 +4394,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, elf_add_syminfo_data (state, sdata); } - backtrace_release_view (state, &shdrs_view, error_callback, data); + elf_release_view (state, &shdrs_view, error_callback, data); shdrs_view_valid = 0; - backtrace_release_view (state, &names_view, error_callback, data); + elf_release_view (state, &names_view, error_callback, data); names_view_valid = 0; /* If the debug info is in a separate file, read that one instead. */ @@ -3038,19 +4411,17 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, { int ret; - backtrace_release_view (state, &buildid_view, error_callback, data); + elf_release_view (state, &buildid_view, error_callback, data); if (debuglink_view_valid) - backtrace_release_view (state, &debuglink_view, error_callback, - data); + elf_release_view (state, &debuglink_view, error_callback, data); if (debugaltlink_view_valid) - backtrace_release_view (state, &debugaltlink_view, error_callback, - data); - ret = elf_add (state, "", d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL, - 0); + elf_release_view (state, &debugaltlink_view, error_callback, data); + ret = elf_add (state, "", d, NULL, 0, base_address, error_callback, + data, fileline_fn, found_sym, found_dwarf, NULL, 0, + 1, NULL, 0); if (ret < 0) backtrace_close (d, error_callback, data); - else + else if (descriptor >= 0) backtrace_close (descriptor, error_callback, data); return ret; } @@ -3058,13 +4429,13 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if (buildid_view_valid) { - backtrace_release_view (state, &buildid_view, error_callback, data); + elf_release_view (state, &buildid_view, error_callback, data); buildid_view_valid = 0; } if (opd) { - backtrace_release_view (state, &opd->view, error_callback, data); + elf_release_view (state, &opd->view, error_callback, data); opd = NULL; } @@ -3079,17 +4450,15 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, { int ret; - backtrace_release_view (state, &debuglink_view, error_callback, - data); + elf_release_view (state, &debuglink_view, error_callback, data); if (debugaltlink_view_valid) - backtrace_release_view (state, &debugaltlink_view, error_callback, - data); - ret = elf_add (state, "", d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL, - 0); + elf_release_view (state, &debugaltlink_view, error_callback, data); + ret = elf_add (state, "", d, NULL, 0, base_address, error_callback, + data, fileline_fn, found_sym, found_dwarf, NULL, 0, + 1, NULL, 0); if (ret < 0) backtrace_close (d, error_callback, data); - else + else if (descriptor >= 0) backtrace_close(descriptor, error_callback, data); return ret; } @@ -3097,7 +4466,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if (debuglink_view_valid) { - backtrace_release_view (state, &debuglink_view, error_callback, data); + elf_release_view (state, &debuglink_view, error_callback, data); debuglink_view_valid = 0; } @@ -3112,12 +4481,11 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, { int ret; - ret = elf_add (state, filename, d, base_address, error_callback, data, - fileline_fn, found_sym, found_dwarf, &fileline_altlink, - 0, 1, debugaltlink_buildid_data, - debugaltlink_buildid_size); - backtrace_release_view (state, &debugaltlink_view, error_callback, - data); + ret = elf_add (state, filename, d, NULL, 0, base_address, + error_callback, data, fileline_fn, found_sym, + found_dwarf, &fileline_altlink, 0, 1, + debugaltlink_buildid_data, debugaltlink_buildid_size); + elf_release_view (state, &debugaltlink_view, error_callback, data); debugaltlink_view_valid = 0; if (ret < 0) { @@ -3129,10 +4497,36 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if (debugaltlink_view_valid) { - backtrace_release_view (state, &debugaltlink_view, error_callback, data); + elf_release_view (state, &debugaltlink_view, error_callback, data); debugaltlink_view_valid = 0; } + if (gnu_debugdata_view_valid) + { + int ret; + + ret = elf_uncompress_lzma (state, + ((const unsigned char *) + gnu_debugdata_view.view.data), + gnu_debugdata_size, error_callback, data, + &gnu_debugdata_uncompressed, + &gnu_debugdata_uncompressed_size); + + elf_release_view (state, &gnu_debugdata_view, error_callback, data); + gnu_debugdata_view_valid = 0; + + if (ret) + { + ret = elf_add (state, filename, -1, gnu_debugdata_uncompressed, + gnu_debugdata_uncompressed_size, base_address, + error_callback, data, fileline_fn, found_sym, + found_dwarf, NULL, 0, 0, NULL, 0); + if (ret >= 0 && descriptor >= 0) + backtrace_close(descriptor, error_callback, data); + return ret; + } + } + /* Read all the debug sections in a single view, since they are probably adjacent in the file. If any of sections are uncompressed, we never release this view. */ @@ -3165,8 +4559,11 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, } if (min_offset == 0 || max_offset == 0) { - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; + if (descriptor >= 0) + { + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + } return 1; } @@ -3176,9 +4573,9 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, 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)) + if (!elf_get_view (state, descriptor, memory, memory_size, min_offset, + max_offset - min_offset, error_callback, data, + &debug_view)) goto fail; debug_view_valid = 1; } @@ -3196,24 +4593,28 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, else continue; - if (!backtrace_get_view (state, descriptor, dsec->offset, dsec->size, - error_callback, data, &split_debug_view[i])) + if (!elf_get_view (state, descriptor, memory, memory_size, + 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); + split_debug_view[i].view.data); else zsections[i].data = ((const unsigned char *) - split_debug_view[i].data); + split_debug_view[i].view.data); } } /* We've read all we need from the executable. */ - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - descriptor = -1; + if (descriptor >= 0) + { + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + descriptor = -1; + } using_debug_view = 0; if (debug_view_valid) @@ -3224,7 +4625,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, sections[i].data = NULL; else { - sections[i].data = ((const unsigned char *) debug_view.data + sections[i].data = ((const unsigned char *) debug_view.view.data + (sections[i].offset - min_offset)); ++using_debug_view; } @@ -3232,7 +4633,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if (zsections[i].size == 0) zsections[i].data = NULL; else - zsections[i].data = ((const unsigned char *) debug_view.data + zsections[i].data = ((const unsigned char *) debug_view.view.data + (zsections[i].offset - min_offset)); } } @@ -3269,8 +4670,8 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if (split_debug_view_valid[i]) { - backtrace_release_view (state, &split_debug_view[i], - error_callback, data); + elf_release_view (state, &split_debug_view[i], + error_callback, data); split_debug_view_valid[i] = 0; } } @@ -3309,8 +4710,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, --using_debug_view; else if (split_debug_view_valid[i]) { - backtrace_release_view (state, &split_debug_view[i], - error_callback, data); + elf_release_view (state, &split_debug_view[i], error_callback, data); split_debug_view_valid[i] = 0; } } @@ -3321,7 +4721,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, if (debug_view_valid && using_debug_view == 0) { - backtrace_release_view (state, &debug_view, error_callback, data); + elf_release_view (state, &debug_view, error_callback, data); debug_view_valid = 0; } @@ -3344,30 +4744,31 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor, fail: if (shdrs_view_valid) - backtrace_release_view (state, &shdrs_view, error_callback, data); + elf_release_view (state, &shdrs_view, error_callback, data); if (names_view_valid) - backtrace_release_view (state, &names_view, error_callback, data); + elf_release_view (state, &names_view, error_callback, data); if (symtab_view_valid) - backtrace_release_view (state, &symtab_view, error_callback, data); + elf_release_view (state, &symtab_view, error_callback, data); if (strtab_view_valid) - backtrace_release_view (state, &strtab_view, error_callback, data); + elf_release_view (state, &strtab_view, error_callback, data); if (debuglink_view_valid) - backtrace_release_view (state, &debuglink_view, error_callback, data); + elf_release_view (state, &debuglink_view, error_callback, data); if (debugaltlink_view_valid) - backtrace_release_view (state, &debugaltlink_view, error_callback, data); + elf_release_view (state, &debugaltlink_view, error_callback, data); + if (gnu_debugdata_view_valid) + elf_release_view (state, &gnu_debugdata_view, error_callback, data); if (buildid_view_valid) - backtrace_release_view (state, &buildid_view, error_callback, data); + elf_release_view (state, &buildid_view, error_callback, data); if (debug_view_valid) - backtrace_release_view (state, &debug_view, error_callback, data); + elf_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); + elf_release_view (state, &split_debug_view[i], error_callback, data); } if (opd) - backtrace_release_view (state, &opd->view, error_callback, data); - if (descriptor != -1) + elf_release_view (state, &opd->view, error_callback, data); + if (descriptor >= 0) backtrace_close (descriptor, error_callback, data); return 0; } @@ -3429,7 +4830,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, return 0; } - if (elf_add (pd->state, filename, descriptor, info->dlpi_addr, + if (elf_add (pd->state, filename, descriptor, NULL, 0, info->dlpi_addr, pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, NULL, 0, 0, NULL, 0)) { @@ -3458,7 +4859,7 @@ backtrace_initialize (struct backtrace_state *state, const char *filename, fileline elf_fileline_fn = elf_nodebug; struct phdr_data pd; - ret = elf_add (state, filename, descriptor, 0, error_callback, data, + ret = elf_add (state, filename, descriptor, NULL, 0, 0, error_callback, data, &elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL, 0); if (!ret) -- cgit v1.1