1
0
mirror of https://github.com/wolfpld/tracy.git synced 2025-03-20 07:40:02 +08:00

Update libbacktrace to ca0de0517.

This commit is contained in:
Bartosz Taudul
2020-03-01 12:55:32 +01:00
parent c36ed4b8b8
commit fdc3b01054
13 changed files with 3627 additions and 2057 deletions
+332 -87
View File
@@ -1,5 +1,5 @@
/* elf.c -- Get debug data from an ELF file for backtraces.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
Copyright (C) 2012-2020 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without
@@ -57,15 +57,13 @@ POSSIBILITY OF SUCH DAMAGE. */
#endif
#ifndef __GNUC__
#ifndef __builtin_prefetch
# define __builtin_prefetch(p, r, l)
#endif
#define __builtin_prefetch(p, r, l)
#ifndef unlikely
# define unlikely(x) (x)
#define unlikely(x) (x)
#endif
#else
#ifndef unlikely
# define unlikely(x) __builtin_expect(!!(x), 0)
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#endif
@@ -120,6 +118,29 @@ xreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED,
#endif
#ifndef HAVE_DL_ITERATE_PHDR
/* Dummy version of dl_iterate_phdr for systems that don't have it. */
#define dl_phdr_info x_dl_phdr_info
#define dl_iterate_phdr x_dl_iterate_phdr
struct dl_phdr_info
{
uintptr_t dlpi_addr;
const char *dlpi_name;
};
static int
dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
size_t, void *) ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
return 0;
}
#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */
/* The configure script must tell us whether we are 32-bit or 64-bit
ELF. We could make this code test and support either possibility,
but there is no point. This code only works for the currently
@@ -323,41 +344,19 @@ typedef struct
#define ELFCOMPRESS_ZLIB 1
/* An index of ELF sections we care about. */
/* Names of sections, indexed by enum dwarf_section in internal.h. */
enum debug_section
{
DEBUG_INFO,
DEBUG_LINE,
DEBUG_ABBREV,
DEBUG_RANGES,
DEBUG_STR,
/* The old style compressed sections. This list must correspond to
the list of normal debug sections. */
ZDEBUG_INFO,
ZDEBUG_LINE,
ZDEBUG_ABBREV,
ZDEBUG_RANGES,
ZDEBUG_STR,
DEBUG_MAX
};
/* Names of sections, indexed by enum elf_section. */
static const char * const debug_section_names[DEBUG_MAX] =
static const char * const dwarf_section_names[DEBUG_MAX] =
{
".debug_info",
".debug_line",
".debug_abbrev",
".debug_ranges",
".debug_str",
".zdebug_info",
".zdebug_line",
".zdebug_abbrev",
".zdebug_ranges",
".zdebug_str"
".debug_addr",
".debug_str_offsets",
".debug_line_str",
".debug_rnglists"
};
/* Information we gather for the sections we care about. */
@@ -659,6 +658,8 @@ static void
elf_add_syminfo_data (struct backtrace_state *state,
struct elf_syminfo_data *edata)
{
if (!state->threaded)
{
struct elf_syminfo_data **pp;
for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
@@ -666,6 +667,31 @@ elf_add_syminfo_data (struct backtrace_state *state,
pp = &(*pp)->next)
;
*pp = edata;
}
else
{
while (1)
{
struct elf_syminfo_data **pp;
pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
while (1)
{
struct elf_syminfo_data *p;
p = backtrace_atomic_load_pointer (pp);
if (p == NULL)
break;
pp = &p->next;
}
if (__sync_bool_compare_and_swap (pp, NULL, edata))
break;
}
}
}
/* Return the symbol name and value for an ADDR. */
@@ -679,6 +705,8 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
struct elf_syminfo_data *edata;
struct elf_symbol *sym = NULL;
if (!state->threaded)
{
for (edata = (struct elf_syminfo_data *) state->syminfo_data;
edata != NULL;
edata = edata->next)
@@ -689,6 +717,27 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
if (sym != NULL)
break;
}
}
else
{
struct elf_syminfo_data **pp;
pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data;
while (1)
{
edata = backtrace_atomic_load_pointer (pp);
if (edata == NULL)
break;
sym = ((struct elf_symbol *)
bsearch (&addr, edata->symbols, edata->count,
sizeof (struct elf_symbol), elf_symbol_search));
if (sym != NULL)
break;
pp = &edata->next;
}
}
if (sym == NULL)
callback (data, addr, NULL, 0, 0);
@@ -745,6 +794,8 @@ elf_readlink (struct backtrace_state *state, const char *filename,
}
}
#define SYSTEM_BUILD_ID_DIR "/usr/lib/debug/.build-id/"
/* Open a separate debug info file, using the build ID to find it.
Returns an open file descriptor, or -1.
@@ -757,7 +808,7 @@ elf_open_debugfile_by_buildid (struct backtrace_state *state,
backtrace_error_callback error_callback,
void *data)
{
const char * const prefix = "/usr/lib/debug/.build-id/";
const char * const prefix = SYSTEM_BUILD_ID_DIR;
const size_t prefix_len = strlen (prefix);
const char * const suffix = ".debug";
const size_t suffix_len = strlen (suffix);
@@ -2574,7 +2625,8 @@ static int
elf_add (struct backtrace_state *state, const char *filename, int descriptor,
uintptr_t base_address, backtrace_error_callback error_callback,
void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf,
int exe, int debuginfo)
struct dwarf_data **fileline_entry, int exe, int debuginfo,
const char *with_buildid_data, uint32_t with_buildid_size)
{
struct backtrace_view ehdr_view;
b_elf_ehdr ehdr;
@@ -2594,6 +2646,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
unsigned int dynsym_shndx;
unsigned int i;
struct debug_section_info sections[DEBUG_MAX];
struct debug_section_info zsections[DEBUG_MAX];
struct backtrace_view symtab_view;
int symtab_view_valid;
struct backtrace_view strtab_view;
@@ -2606,13 +2659,23 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
int debuglink_view_valid;
const char *debuglink_name;
uint32_t debuglink_crc;
struct backtrace_view debugaltlink_view;
int debugaltlink_view_valid;
const char *debugaltlink_name;
const char *debugaltlink_buildid_data;
uint32_t debugaltlink_buildid_size;
off_t min_offset;
off_t max_offset;
off_t debug_size;
struct backtrace_view debug_view;
int debug_view_valid;
unsigned int using_debug_view;
uint16_t *zdebug_table;
struct backtrace_view split_debug_view[DEBUG_MAX];
unsigned char split_debug_view_valid[DEBUG_MAX];
struct elf_ppc64_opd_data opd_data, *opd;
struct dwarf_sections dwarf_sections;
struct dwarf_data *fileline_altlink = NULL;
if (!debuginfo)
{
@@ -2630,7 +2693,12 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
debuglink_view_valid = 0;
debuglink_name = NULL;
debuglink_crc = 0;
debugaltlink_view_valid = 0;
debugaltlink_name = NULL;
debugaltlink_buildid_data = NULL;
debugaltlink_buildid_size = 0;
debug_view_valid = 0;
memset (&split_debug_view_valid[0], 0, sizeof split_debug_view_valid);
opd = NULL;
if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
@@ -2739,7 +2807,7 @@ 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, shstr_size,
if (!backtrace_get_view (state, descriptor, shstr_off, shstrhdr->sh_size,
error_callback, data, &names_view))
goto fail;
names_view_valid = 1;
@@ -2749,6 +2817,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
dynsym_shndx = 0;
memset (sections, 0, sizeof sections);
memset (zsections, 0, sizeof zsections);
/* Look for the symbol table. */
for (i = 1; i < shnum; ++i)
@@ -2776,7 +2845,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
for (j = 0; j < (int) DEBUG_MAX; ++j)
{
if (strcmp (name, debug_section_names[j]) == 0)
if (strcmp (name, dwarf_section_names[j]) == 0)
{
sections[j].offset = shdr->sh_offset;
sections[j].size = shdr->sh_size;
@@ -2785,10 +2854,23 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
}
}
if (name[0] == '.' && name[1] == 'z')
{
for (j = 0; j < (int) DEBUG_MAX; ++j)
{
if (strcmp (name + 2, dwarf_section_names[j] + 1) == 0)
{
zsections[j].offset = shdr->sh_offset;
zsections[j].size = shdr->sh_size;
break;
}
}
}
/* Read the build ID if present. This could check for any
SHT_NOTE section with the right note name and type, but gdb
looks for a specific section name. */
if (!debuginfo
if ((!debuginfo || with_buildid_data != NULL)
&& !buildid_view_valid
&& strcmp (name, ".note.gnu.build-id") == 0)
{
@@ -2804,11 +2886,20 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
if (note->type == NT_GNU_BUILD_ID
&& note->namesz == 4
&& strncmp (note->name, "GNU", 4) == 0
&& shdr->sh_size < 12 + ((note->namesz + 3) & ~ 3) + note->descsz)
&& shdr->sh_size <= 12 + ((note->namesz + 3) & ~ 3) + note->descsz)
{
buildid_data = &note->name[0] + ((note->namesz + 3) & ~ 3);
buildid_size = note->descsz;
}
if (with_buildid_size != 0)
{
if (buildid_size != with_buildid_size)
goto fail;
if (memcmp (buildid_data, with_buildid_data, buildid_size) != 0)
goto fail;
}
}
/* Read the debuglink file if present. */
@@ -2835,6 +2926,32 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
}
}
if (!debugaltlink_view_valid
&& strcmp (name, ".gnu_debugaltlink") == 0)
{
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))
goto fail;
debugaltlink_view_valid = 1;
debugaltlink_data = (const char *) debugaltlink_view.data;
debugaltlink_name = debugaltlink_data;
debugaltlink_name_len = strnlen (debugaltlink_data, shdr->sh_size);
if (debugaltlink_name_len < shdr->sh_size)
{
/* Include terminating zero. */
debugaltlink_name_len += 1;
debugaltlink_buildid_data
= debugaltlink_data + debugaltlink_name_len;
debugaltlink_buildid_size = shdr->sh_size - debugaltlink_name_len;
}
}
/* Read the .opd section on PowerPC64 ELFv1. */
if (ehdr.e_machine == EM_PPC64
&& (ehdr.e_flags & EF_PPC64_ABI) < 2
@@ -2902,6 +3019,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
string table permanently. */
backtrace_release_view (state, &symtab_view, error_callback, data);
symtab_view_valid = 0;
strtab_view_valid = 0;
*found_sym = 1;
@@ -2929,8 +3047,12 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
if (debuglink_view_valid)
backtrace_release_view (state, &debuglink_view, error_callback,
data);
ret = elf_add (state, NULL, d, base_address, error_callback, data,
fileline_fn, found_sym, found_dwarf, 0, 1);
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);
if (ret < 0)
backtrace_close (d, error_callback, data);
else
@@ -2964,8 +3086,12 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
backtrace_release_view (state, &debuglink_view, error_callback,
data);
ret = elf_add (state, NULL, d, base_address, error_callback, data,
fileline_fn, found_sym, found_dwarf, 0, 1);
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);
if (ret < 0)
backtrace_close (d, error_callback, data);
else
@@ -2980,22 +3106,66 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
debuglink_view_valid = 0;
}
if (debugaltlink_name != NULL)
{
int d;
d = elf_open_debugfile_by_debuglink (state, filename, debugaltlink_name,
0, error_callback, data);
if (d >= 0)
{
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);
debugaltlink_view_valid = 0;
if (ret < 0)
{
backtrace_close (d, error_callback, data);
return ret;
}
}
}
if (debugaltlink_view_valid)
{
backtrace_release_view (state, &debugaltlink_view, error_callback, data);
debugaltlink_view_valid = 0;
}
/* Read all the debug sections in a single view, since they are
probably adjacent in the file. We never release this view. */
probably adjacent in the file. If any of sections are
uncompressed, we never release this view. */
min_offset = 0;
max_offset = 0;
debug_size = 0;
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
off_t end;
if (sections[i].size == 0)
continue;
if (min_offset == 0 || sections[i].offset < min_offset)
min_offset = sections[i].offset;
end = sections[i].offset + sections[i].size;
if (end > max_offset)
max_offset = end;
if (sections[i].size != 0)
{
if (min_offset == 0 || sections[i].offset < min_offset)
min_offset = sections[i].offset;
end = sections[i].offset + sections[i].size;
if (end > max_offset)
max_offset = end;
debug_size += sections[i].size;
}
if (zsections[i].size != 0)
{
if (min_offset == 0 || zsections[i].offset < min_offset)
min_offset = zsections[i].offset;
end = zsections[i].offset + zsections[i].size;
if (end > max_offset)
max_offset = end;
debug_size += zsections[i].size;
}
}
if (min_offset == 0 || max_offset == 0)
{
@@ -3004,11 +3174,45 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
return 1;
}
if (!backtrace_get_view (state, descriptor, min_offset,
max_offset - min_offset,
error_callback, data, &debug_view))
goto fail;
debug_view_valid = 1;
/* If the total debug section size is large, assume that there are
gaps between the sections, and read them individually. */
if (max_offset - min_offset < 0x20000000
|| max_offset - min_offset < debug_size + 0x10000)
{
if (!backtrace_get_view (state, descriptor, min_offset,
max_offset - min_offset,
error_callback, data, &debug_view))
goto fail;
debug_view_valid = 1;
}
else
{
memset (&split_debug_view[0], 0, sizeof split_debug_view);
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
struct debug_section_info *dsec;
if (sections[i].size != 0)
dsec = &sections[i];
else if (zsections[i].size != 0)
dsec = &zsections[i];
else
continue;
if (!backtrace_get_view (state, descriptor, dsec->offset, dsec->size,
error_callback, data, &split_debug_view[i]))
goto fail;
split_debug_view_valid[i] = 1;
if (sections[i].size != 0)
sections[i].data = ((const unsigned char *)
split_debug_view[i].data);
else
zsections[i].data = ((const unsigned char *)
split_debug_view[i].data);
}
}
/* We've read all we need from the executable. */
if (!backtrace_close (descriptor, error_callback, data))
@@ -3016,28 +3220,33 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
descriptor = -1;
using_debug_view = 0;
for (i = 0; i < (int) DEBUG_MAX; ++i)
if (debug_view_valid)
{
if (sections[i].size == 0)
sections[i].data = NULL;
else
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
sections[i].data = ((const unsigned char *) debug_view.data
+ (sections[i].offset - min_offset));
if (i < ZDEBUG_INFO)
++using_debug_view;
if (sections[i].size == 0)
sections[i].data = NULL;
else
{
sections[i].data = ((const unsigned char *) debug_view.data
+ (sections[i].offset - min_offset));
++using_debug_view;
}
if (zsections[i].size == 0)
zsections[i].data = NULL;
else
zsections[i].data = ((const unsigned char *) debug_view.data
+ (zsections[i].offset - min_offset));
}
}
/* Uncompress the old format (--compress-debug-sections=zlib-gnu). */
zdebug_table = NULL;
for (i = 0; i < ZDEBUG_INFO; ++i)
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
struct debug_section_info *pz;
pz = &sections[i + ZDEBUG_INFO - DEBUG_INFO];
if (sections[i].size == 0 && pz->size > 0)
if (sections[i].size == 0 && zsections[i].size > 0)
{
unsigned char *uncompressed_data;
size_t uncompressed_size;
@@ -3053,19 +3262,27 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
uncompressed_data = NULL;
uncompressed_size = 0;
if (!elf_uncompress_zdebug (state, pz->data, pz->size, zdebug_table,
if (!elf_uncompress_zdebug (state, zsections[i].data,
zsections[i].size, zdebug_table,
error_callback, data,
&uncompressed_data, &uncompressed_size))
goto fail;
sections[i].data = uncompressed_data;
sections[i].size = uncompressed_size;
sections[i].compressed = 0;
if (split_debug_view_valid[i])
{
backtrace_release_view (state, &split_debug_view[i],
error_callback, data);
split_debug_view_valid[i] = 0;
}
}
}
/* Uncompress the official ELF format
(--compress-debug-sections=zlib-gabi). */
for (i = 0; i < ZDEBUG_INFO; ++i)
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
unsigned char *uncompressed_data;
size_t uncompressed_size;
@@ -3092,7 +3309,14 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
sections[i].size = uncompressed_size;
sections[i].compressed = 0;
--using_debug_view;
if (debug_view_valid)
--using_debug_view;
else if (split_debug_view_valid[i])
{
backtrace_release_view (state, &split_debug_view[i],
error_callback, data);
split_debug_view_valid[i] = 0;
}
}
if (zdebug_table != NULL)
@@ -3105,19 +3329,17 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
debug_view_valid = 0;
}
if (!backtrace_dwarf_add (state, base_address,
sections[DEBUG_INFO].data,
sections[DEBUG_INFO].size,
sections[DEBUG_LINE].data,
sections[DEBUG_LINE].size,
sections[DEBUG_ABBREV].data,
sections[DEBUG_ABBREV].size,
sections[DEBUG_RANGES].data,
sections[DEBUG_RANGES].size,
sections[DEBUG_STR].data,
sections[DEBUG_STR].size,
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
dwarf_sections.data[i] = sections[i].data;
dwarf_sections.size[i] = sections[i].size;
}
if (!backtrace_dwarf_add (state, base_address, &dwarf_sections,
ehdr.e_ident[EI_DATA] == ELFDATA2MSB,
error_callback, data, fileline_fn))
fileline_altlink,
error_callback, data, fileline_fn,
fileline_entry))
goto fail;
*found_dwarf = 1;
@@ -3135,10 +3357,18 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
backtrace_release_view (state, &strtab_view, error_callback, data);
if (debuglink_view_valid)
backtrace_release_view (state, &debuglink_view, error_callback, data);
if (debugaltlink_view_valid)
backtrace_release_view (state, &debugaltlink_view, error_callback, data);
if (buildid_view_valid)
backtrace_release_view (state, &buildid_view, error_callback, data);
if (debug_view_valid)
backtrace_release_view (state, &debug_view, error_callback, data);
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
if (split_debug_view_valid[i])
backtrace_release_view (state, &split_debug_view[i],
error_callback, data);
}
if (opd)
backtrace_release_view (state, &opd->view, error_callback, data);
if (descriptor != -1)
@@ -3205,7 +3435,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
if (elf_add (pd->state, filename, descriptor, info->dlpi_addr,
pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
&found_dwarf, 0, 0))
&found_dwarf, NULL, 0, 0, NULL, 0))
{
if (found_dwarf)
{
@@ -3233,7 +3463,8 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
struct phdr_data pd;
ret = elf_add (state, filename, descriptor, 0, error_callback, data,
&elf_fileline_fn, &found_sym, &found_dwarf, 1, 0);
&elf_fileline_fn, &found_sym, &found_dwarf, NULL, 1, 0, NULL,
0);
if (!ret)
return 0;
@@ -3248,12 +3479,26 @@ backtrace_initialize (struct backtrace_state *state, const char *filename,
dl_iterate_phdr (phdr_callback, (void *) &pd);
if (!state->threaded)
{
if (found_sym)
state->syminfo_fn = elf_syminfo;
else if (state->syminfo_fn == NULL)
state->syminfo_fn = elf_nosyms;
}
else
{
if (found_sym)
backtrace_atomic_store_pointer (&state->syminfo_fn, &elf_syminfo);
else
(void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
elf_nosyms);
}
if (!state->threaded)
*fileline_fn = state->fileline_fn;
else
*fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
if (*fileline_fn == NULL || *fileline_fn == elf_nodebug)
*fileline_fn = elf_fileline_fn;