crates/backtrace-sys2/src/libbacktrace/elf.c in pf2-0.6.0 vs crates/backtrace-sys2/src/libbacktrace/elf.c in pf2-0.7.0
- old
+ new
@@ -1,7 +1,7 @@
/* elf.c -- Get debug data from an ELF file for backtraces.
- Copyright (C) 2012-2021 Free Software Foundation, Inc.
+ Copyright (C) 2012-2024 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
@@ -587,11 +587,11 @@
state->syminfo_fn (state, pc, backtrace_syminfo_to_full_callback,
backtrace_syminfo_to_full_error_callback, &bdata);
return bdata.ret;
}
- error_callback (data, "no debug info in ELF executable", -1);
+ error_callback (data, "no debug info in ELF executable (make sure to compile with -g)", -1);
return 0;
}
/* Compare struct elf_symbol for qsort. */
@@ -631,11 +631,11 @@
/* Initialize the symbol table info for elf_syminfo. */
static int
elf_initialize_syminfo (struct backtrace_state *state,
- uintptr_t base_address,
+ struct libbacktrace_base_address base_address,
const unsigned char *symtab_data, size_t symtab_size,
const unsigned char *strtab, size_t strtab_size,
backtrace_error_callback error_callback,
void *data, struct elf_syminfo_data *sdata,
struct elf_ppc64_opd_data *opd)
@@ -697,11 +697,12 @@
&& sym->st_value < opd->addr + opd->size)
elf_symbols[j].address
= *(const b_elf_addr *) (opd->data + (sym->st_value - opd->addr));
else
elf_symbols[j].address = sym->st_value;
- elf_symbols[j].address += base_address;
+ elf_symbols[j].address =
+ libbacktrace_add_base (elf_symbols[j].address, base_address);
elf_symbols[j].size = sym->st_size;
++j;
}
backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol),
@@ -1180,18 +1181,11 @@
return 1;
pin = *ppin;
val = *pval;
if (unlikely (pin <= pinend))
- {
- if (bits == 0)
- {
- elf_uncompress_failed ();
- return 0;
- }
- return 1;
- }
+ return 1;
pin -= 4;
#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) \
&& defined(__ORDER_BIG_ENDIAN__) \
@@ -4852,29 +4846,29 @@
/* Often LITERAL is small, so handle small cases quickly. */
switch (literal)
{
case 8:
*pout++ = *plit++;
- /* FALLTHROUGH */
+ ATTRIBUTE_FALLTHROUGH;
case 7:
*pout++ = *plit++;
- /* FALLTHROUGH */
+ ATTRIBUTE_FALLTHROUGH;
case 6:
*pout++ = *plit++;
- /* FALLTHROUGH */
+ ATTRIBUTE_FALLTHROUGH;
case 5:
*pout++ = *plit++;
- /* FALLTHROUGH */
+ ATTRIBUTE_FALLTHROUGH;
case 4:
*pout++ = *plit++;
- /* FALLTHROUGH */
+ ATTRIBUTE_FALLTHROUGH;
case 3:
*pout++ = *plit++;
- /* FALLTHROUGH */
+ ATTRIBUTE_FALLTHROUGH;
case 2:
*pout++ = *plit++;
- /* FALLTHROUGH */
+ ATTRIBUTE_FALLTHROUGH;
case 1:
*pout++ = *plit++;
break;
case 0:
@@ -5074,11 +5068,11 @@
const unsigned char *compressed, size_t compressed_size,
uint16_t *zdebug_table,
backtrace_error_callback error_callback, void *data,
unsigned char **uncompressed, size_t *uncompressed_size)
{
- const b_elf_chdr *chdr;
+ b_elf_chdr chdr;
char *alc;
size_t alc_len;
unsigned char *po;
*uncompressed = NULL;
@@ -5086,49 +5080,52 @@
/* The format starts with an ELF compression header. */
if (compressed_size < sizeof (b_elf_chdr))
return 1;
- chdr = (const b_elf_chdr *) compressed;
+ /* The lld linker can misalign a compressed section, so we can't safely read
+ the fields directly as we can for other ELF sections. See
+ https://github.com/ianlancetaylor/libbacktrace/pull/120. */
+ memcpy (&chdr, compressed, sizeof (b_elf_chdr));
alc = NULL;
alc_len = 0;
- if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size)
+ if (*uncompressed != NULL && *uncompressed_size >= chdr.ch_size)
po = *uncompressed;
else
{
- alc_len = chdr->ch_size;
+ alc_len = chdr.ch_size;
alc = backtrace_alloc (state, alc_len, error_callback, data);
if (alc == NULL)
return 0;
po = (unsigned char *) alc;
}
- switch (chdr->ch_type)
+ switch (chdr.ch_type)
{
case ELFCOMPRESS_ZLIB:
if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr),
compressed_size - sizeof (b_elf_chdr),
- zdebug_table, po, chdr->ch_size))
+ zdebug_table, po, chdr.ch_size))
goto skip;
break;
case ELFCOMPRESS_ZSTD:
if (!elf_zstd_decompress (compressed + sizeof (b_elf_chdr),
compressed_size - sizeof (b_elf_chdr),
(unsigned char *)zdebug_table, po,
- chdr->ch_size))
+ chdr.ch_size))
goto skip;
break;
default:
/* Unsupported compression algorithm. */
goto skip;
}
*uncompressed = po;
- *uncompressed_size = chdr->ch_size;
+ *uncompressed_size = chdr.ch_size;
return 1;
skip:
if (alc != NULL && alc_len > 0)
@@ -5566,10 +5563,11 @@
size_t block_header_size;
unsigned char block_flags;
uint64_t header_compressed_size;
uint64_t header_uncompressed_size;
unsigned char lzma2_properties;
+ size_t crc_offset;
uint32_t computed_crc;
uint32_t stream_crc;
size_t uncompressed_offset;
size_t dict_start_offset;
unsigned int lc;
@@ -5669,32 +5667,33 @@
}
/* The properties describe the dictionary size, but we don't care
what that is. */
- /* Block header padding. */
- if (unlikely (off + 4 > compressed_size))
+ /* Skip to just before CRC, verifying zero bytes in between. */
+ crc_offset = block_header_offset + block_header_size - 4;
+ if (unlikely (crc_offset + 4 > compressed_size))
{
elf_uncompress_failed ();
return 0;
}
-
- off = (off + 3) &~ (size_t) 3;
-
- if (unlikely (off + 4 > compressed_size))
+ for (; off < crc_offset; off++)
{
- elf_uncompress_failed ();
- return 0;
+ if (compressed[off] != 0)
+ {
+ 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));
+ stream_crc = ((uint32_t)compressed[off]
+ | ((uint32_t)compressed[off + 1] << 8)
+ | ((uint32_t)compressed[off + 2] << 16)
+ | ((uint32_t)compressed[off + 3] << 24));
if (unlikely (computed_crc != stream_crc))
{
elf_uncompress_failed ();
return 0;
}
@@ -6300,14 +6299,14 @@
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));
+ stream_crc = ((uint32_t)compressed[8]
+ | ((uint32_t)compressed[9] << 8)
+ | ((uint32_t)compressed[10] << 16)
+ | ((uint32_t)compressed[11] << 24));
if (unlikely (computed_crc != stream_crc))
{
elf_uncompress_failed ();
return 0;
}
@@ -6344,14 +6343,14 @@
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));
+ stream_crc = ((uint32_t)compressed[offset - 4]
+ | ((uint32_t)compressed[offset - 3] << 8)
+ | ((uint32_t)compressed[offset - 2] << 16)
+ | ((uint32_t)compressed[offset - 1] << 24));
if (unlikely (computed_crc != stream_crc))
{
elf_uncompress_failed ();
return 0;
}
@@ -6403,14 +6402,14 @@
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));
+ stream_crc = ((uint32_t)compressed[offset]
+ | ((uint32_t)compressed[offset + 1] << 8)
+ | ((uint32_t)compressed[offset + 2] << 16)
+ | ((uint32_t)compressed[offset + 3] << 24));
if (unlikely (computed_crc != stream_crc))
{
elf_uncompress_failed ();
return 0;
}
@@ -6499,12 +6498,14 @@
base_address is determined. */
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 libbacktrace_base_address base_address,
+ struct elf_ppc64_opd_data *caller_opd,
+ 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 elf_view ehdr_view;
b_elf_ehdr ehdr;
@@ -6555,10 +6556,11 @@
unsigned int using_debug_view;
uint16_t *zdebug_table;
struct elf_view split_debug_view[DEBUG_MAX];
unsigned char split_debug_view_valid[DEBUG_MAX];
struct elf_ppc64_opd_data opd_data, *opd;
+ int opd_view_valid;
struct dwarf_sections dwarf_sections;
if (!debuginfo)
{
*found_sym = 0;
@@ -6582,10 +6584,11 @@
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;
+ opd_view_valid = 0;
if (!elf_get_view (state, descriptor, memory, memory_size, 0, sizeof ehdr,
error_callback, data, &ehdr_view))
goto fail;
@@ -6838,11 +6841,12 @@
= debugaltlink_data + debugaltlink_name_len;
debugaltlink_buildid_size = shdr->sh_size - debugaltlink_name_len;
}
}
- if (!gnu_debugdata_view_valid
+ if (!debuginfo
+ && !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))
@@ -6865,16 +6869,22 @@
opd = &opd_data;
opd->addr = shdr->sh_addr;
opd->data = (const char *) opd_data.view.view.data;
opd->size = shdr->sh_size;
+ opd_view_valid = 1;
}
}
+ /* A debuginfo file may not have a useful .opd section, but we can use the
+ one from the original executable. */
+ if (opd == NULL)
+ opd = caller_opd;
+
if (symtab_shndx == 0)
symtab_shndx = dynsym_shndx;
- if (symtab_shndx != 0 && !debuginfo)
+ if (symtab_shndx != 0)
{
const b_elf_shdr *symtab_shdr;
unsigned int strtab_shndx;
const b_elf_shdr *strtab_shdr;
struct elf_syminfo_data *sdata;
@@ -6946,13 +6956,13 @@
elf_release_view (state, &buildid_view, error_callback, data);
if (debuglink_view_valid)
elf_release_view (state, &debuglink_view, error_callback, data);
if (debugaltlink_view_valid)
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);
+ ret = elf_add (state, "", d, NULL, 0, base_address, opd,
+ error_callback, data, fileline_fn, found_sym,
+ found_dwarf, NULL, 0, 1, NULL, 0);
if (ret < 0)
backtrace_close (d, error_callback, data);
else if (descriptor >= 0)
backtrace_close (descriptor, error_callback, data);
return ret;
@@ -6963,16 +6973,10 @@
{
elf_release_view (state, &buildid_view, error_callback, data);
buildid_view_valid = 0;
}
- if (opd)
- {
- elf_release_view (state, &opd->view, error_callback, data);
- opd = NULL;
- }
-
if (debuglink_name != NULL)
{
int d;
d = elf_open_debugfile_by_debuglink (state, filename, debuglink_name,
@@ -6983,13 +6987,13 @@
int ret;
elf_release_view (state, &debuglink_view, error_callback, data);
if (debugaltlink_view_valid)
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);
+ ret = elf_add (state, "", d, NULL, 0, base_address, opd,
+ error_callback, data, fileline_fn, found_sym,
+ found_dwarf, NULL, 0, 1, NULL, 0);
if (ret < 0)
backtrace_close (d, error_callback, data);
else if (descriptor >= 0)
backtrace_close(descriptor, error_callback, data);
return ret;
@@ -7011,11 +7015,11 @@
0, error_callback, data);
if (d >= 0)
{
int ret;
- ret = elf_add (state, filename, d, NULL, 0, base_address,
+ ret = elf_add (state, filename, d, NULL, 0, base_address, opd,
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;
@@ -7048,19 +7052,26 @@
gnu_debugdata_view_valid = 0;
if (ret)
{
ret = elf_add (state, filename, -1, gnu_debugdata_uncompressed,
- gnu_debugdata_uncompressed_size, base_address,
+ gnu_debugdata_uncompressed_size, base_address, opd,
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;
}
}
+ if (opd_view_valid)
+ {
+ elf_release_view (state, &opd->view, error_callback, data);
+ opd_view_valid = 0;
+ opd = NULL;
+ }
+
/* 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. */
min_offset = 0;
@@ -7303,11 +7314,11 @@
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
if (split_debug_view_valid[i])
elf_release_view (state, &split_debug_view[i], error_callback, data);
}
- if (opd)
+ if (opd_view_valid)
elf_release_view (state, &opd->view, error_callback, data);
if (descriptor >= 0)
backtrace_close (descriptor, error_callback, data);
return 0;
}
@@ -7338,10 +7349,11 @@
{
struct phdr_data *pd = (struct phdr_data *) pdata;
const char *filename;
int descriptor;
int does_not_exist;
+ struct libbacktrace_base_address base_address;
fileline elf_fileline_fn;
int found_dwarf;
/* 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
@@ -7367,11 +7379,12 @@
pd->data, &does_not_exist);
if (descriptor < 0)
return 0;
}
- if (elf_add (pd->state, filename, descriptor, NULL, 0, info->dlpi_addr,
+ base_address.m = info->dlpi_addr;
+ if (elf_add (pd->state, filename, descriptor, NULL, 0, base_address, NULL,
pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
&found_dwarf, NULL, 0, 0, NULL, 0))
{
if (found_dwarf)
{
@@ -7396,14 +7409,23 @@
int found_sym;
int found_dwarf;
fileline elf_fileline_fn = elf_nodebug;
struct phdr_data pd;
- 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)
- return 0;
+ /* When using fdpic we must use dl_iterate_phdr for all modules, including
+ the main executable, so that we can get the right base address
+ mapping. */
+ if (!libbacktrace_using_fdpic ())
+ {
+ struct libbacktrace_base_address zero_base_address;
+
+ memset (&zero_base_address, 0, sizeof zero_base_address);
+ ret = elf_add (state, filename, descriptor, NULL, 0, zero_base_address,
+ NULL, error_callback, data, &elf_fileline_fn, &found_sym,
+ &found_dwarf, NULL, 1, 0, NULL, 0);
+ if (!ret)
+ return 0;
+ }
pd.state = state;
pd.error_callback = error_callback;
pd.data = data;
pd.fileline_fn = &elf_fileline_fn;