Update libbacktrace to dedbe13fda.

This commit is contained in:
Bartosz Taudul 2021-01-31 15:15:59 +01:00 committed by Bartosz Taudul
parent a3bfbab6bd
commit 8bacc7a91c
11 changed files with 1975 additions and 313 deletions

View File

@ -1,5 +1,5 @@
/* alloc.c -- Memory allocation without mmap. /* alloc.c -- Memory allocation without mmap.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,5 +1,5 @@
/* backtrace.h -- Public header file for stack backtrace library. /* backtrace.h -- Public header file for stack backtrace library.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,5 +1,5 @@
/* dwarf.c -- Get file/line information from DWARF for backtraces. /* dwarf.c -- Get file/line information from DWARF for backtraces.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -1389,7 +1389,7 @@ resolve_string (const struct dwarf_sections *dwarf_sections, int is_dwarf64,
offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base; offset = val->u.uint * (is_dwarf64 ? 8 : 4) + str_offsets_base;
if (offset + (is_dwarf64 ? 8 : 4) if (offset + (is_dwarf64 ? 8 : 4)
>= dwarf_sections->size[DEBUG_STR_OFFSETS]) > dwarf_sections->size[DEBUG_STR_OFFSETS])
{ {
error_callback (data, "DW_FORM_strx value out of range", 0); error_callback (data, "DW_FORM_strx value out of range", 0);
return 0; return 0;
@ -1433,7 +1433,7 @@ resolve_addr_index (const struct dwarf_sections *dwarf_sections,
struct dwarf_buf addr_buf; struct dwarf_buf addr_buf;
offset = addr_index * addrsize + addr_base; offset = addr_index * addrsize + addr_base;
if (offset + addrsize >= dwarf_sections->size[DEBUG_ADDR]) if (offset + addrsize > dwarf_sections->size[DEBUG_ADDR])
{ {
error_callback (data, "DW_FORM_addrx value out of range", 0); error_callback (data, "DW_FORM_addrx value out of range", 0);
return 0; return 0;
@ -1500,9 +1500,11 @@ function_addrs_compare (const void *v1, const void *v2)
return strcmp (a1->function->name, a2->function->name); return strcmp (a1->function->name, a2->function->name);
} }
/* Compare a PC against a function_addrs for bsearch. Note that if /* Compare a PC against a function_addrs for bsearch. We always
there are multiple ranges containing PC, which one will be returned allocate an entra entry at the end of the vector, so that this
is unpredictable. We compensate for that in dwarf_fileline. */ routine can safely look at the next entry. Note that if there are
multiple ranges containing PC, which one will be returned is
unpredictable. We compensate for that in dwarf_fileline. */
static int static int
function_addrs_search (const void *vkey, const void *ventry) function_addrs_search (const void *vkey, const void *ventry)
@ -1514,7 +1516,7 @@ function_addrs_search (const void *vkey, const void *ventry)
pc = *key; pc = *key;
if (pc < entry->low) if (pc < entry->low)
return -1; return -1;
else if (pc >= entry->high) else if (pc > (entry + 1)->low)
return 1; return 1;
else else
return 0; return 0;
@ -1585,9 +1587,11 @@ unit_addrs_compare (const void *v1, const void *v2)
return 0; return 0;
} }
/* Compare a PC against a unit_addrs for bsearch. Note that if there /* Compare a PC against a unit_addrs for bsearch. We always allocate
are multiple ranges containing PC, which one will be returned is an entry entry at the end of the vector, so that this routine can
unpredictable. We compensate for that in dwarf_fileline. */ safely look at the next entry. Note that if there are multiple
ranges containing PC, which one will be returned is unpredictable.
We compensate for that in dwarf_fileline. */
static int static int
unit_addrs_search (const void *vkey, const void *ventry) unit_addrs_search (const void *vkey, const void *ventry)
@ -1599,7 +1603,7 @@ unit_addrs_search (const void *vkey, const void *ventry)
pc = *key; pc = *key;
if (pc < entry->low) if (pc < entry->low)
return -1; return -1;
else if (pc >= entry->high) else if (pc > (entry + 1)->low)
return 1; return 1;
else else
return 0; return 0;
@ -2427,6 +2431,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
size_t i; size_t i;
struct unit **pu; struct unit **pu;
size_t unit_offset = 0; size_t unit_offset = 0;
struct unit_addrs *pa;
memset (&addrs->vec, 0, sizeof addrs->vec); memset (&addrs->vec, 0, sizeof addrs->vec);
memset (&unit_vec->vec, 0, sizeof unit_vec->vec); memset (&unit_vec->vec, 0, sizeof unit_vec->vec);
@ -2567,6 +2572,17 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
if (info.reported_underflow) if (info.reported_underflow)
goto fail; goto fail;
/* Add a trailing addrs entry, but don't include it in addrs->count. */
pa = ((struct unit_addrs *)
backtrace_vector_grow (state, sizeof (struct unit_addrs),
error_callback, data, &addrs->vec));
if (pa == NULL)
goto fail;
pa->low = 0;
--pa->low;
pa->high = pa->low;
pa->u = NULL;
unit_vec->vec = units; unit_vec->vec = units;
unit_vec->count = units_count; unit_vec->count = units_count;
return 1; return 1;
@ -2664,9 +2680,10 @@ read_v2_paths (struct backtrace_state *state, struct unit *u,
++hdr->dirs_count; ++hdr->dirs_count;
} }
hdr->dirs = NULL; /* The index of the first entry in the list of directories is 1. Index 0 is
if (hdr->dirs_count != 0) used for the current directory of the compilation. To simplify index
{ handling, we set entry 0 to the compilation unit directory. */
++hdr->dirs_count;
hdr->dirs = ((const char **) hdr->dirs = ((const char **)
backtrace_alloc (state, backtrace_alloc (state,
hdr->dirs_count * sizeof (const char *), hdr->dirs_count * sizeof (const char *),
@ -2674,9 +2691,9 @@ read_v2_paths (struct backtrace_state *state, struct unit *u,
hdr_buf->data)); hdr_buf->data));
if (hdr->dirs == NULL) if (hdr->dirs == NULL)
return 0; return 0;
}
i = 0; hdr->dirs[0] = u->comp_dir;
i = 1;
while (*hdr_buf->buf != '\0') while (*hdr_buf->buf != '\0')
{ {
if (hdr_buf->reported_underflow) if (hdr_buf->reported_underflow)
@ -2703,6 +2720,10 @@ read_v2_paths (struct backtrace_state *state, struct unit *u,
++hdr->filenames_count; ++hdr->filenames_count;
} }
/* The index of the first entry in the list of file names is 1. Index 0 is
used for the DW_AT_name of the compilation unit. To simplify index
handling, we set entry 0 to the compilation unit file name. */
++hdr->filenames_count;
hdr->filenames = ((const char **) hdr->filenames = ((const char **)
backtrace_alloc (state, backtrace_alloc (state,
hdr->filenames_count * sizeof (char *), hdr->filenames_count * sizeof (char *),
@ -2710,7 +2731,8 @@ read_v2_paths (struct backtrace_state *state, struct unit *u,
hdr_buf->data)); hdr_buf->data));
if (hdr->filenames == NULL) if (hdr->filenames == NULL)
return 0; return 0;
i = 0; hdr->filenames[0] = u->filename;
i = 1;
while (*hdr_buf->buf != '\0') while (*hdr_buf->buf != '\0')
{ {
const char *filename; const char *filename;
@ -2724,7 +2746,7 @@ read_v2_paths (struct backtrace_state *state, struct unit *u,
return 0; return 0;
dir_index = read_uleb128 (hdr_buf); dir_index = read_uleb128 (hdr_buf);
if (IS_ABSOLUTE_PATH (filename) if (IS_ABSOLUTE_PATH (filename)
|| (dir_index == 0 && u->comp_dir == NULL)) || (dir_index < hdr->dirs_count && hdr->dirs[dir_index] == NULL))
hdr->filenames[i] = filename; hdr->filenames[i] = filename;
else else
{ {
@ -2733,10 +2755,8 @@ read_v2_paths (struct backtrace_state *state, struct unit *u,
size_t filename_len; size_t filename_len;
char *s; char *s;
if (dir_index == 0) if (dir_index < hdr->dirs_count)
dir = u->comp_dir; dir = hdr->dirs[dir_index];
else if (dir_index - 1 < hdr->dirs_count)
dir = hdr->dirs[dir_index - 1];
else else
{ {
dwarf_buf_error (hdr_buf, dwarf_buf_error (hdr_buf,
@ -3024,8 +3044,8 @@ read_line_header (struct backtrace_state *state, struct dwarf_data *ddata,
static int static int
read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
struct unit *u, const struct line_header *hdr, const struct line_header *hdr, struct dwarf_buf *line_buf,
struct dwarf_buf *line_buf, struct line_vector *vec) struct line_vector *vec)
{ {
uint64_t address; uint64_t address;
unsigned int op_index; unsigned int op_index;
@ -3035,8 +3055,8 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
address = 0; address = 0;
op_index = 0; op_index = 0;
if (hdr->filenames_count > 0) if (hdr->filenames_count > 1)
reset_filename = hdr->filenames[0]; reset_filename = hdr->filenames[1];
else else
reset_filename = ""; reset_filename = "";
filename = reset_filename; filename = reset_filename;
@ -3101,10 +3121,8 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
size_t f_len; size_t f_len;
char *p; char *p;
if (dir_index == 0 && hdr->version < 5) if (dir_index < hdr->dirs_count)
dir = u->comp_dir; dir = hdr->dirs[dir_index];
else if (dir_index - 1 < hdr->dirs_count)
dir = hdr->dirs[dir_index - 1];
else else
{ {
dwarf_buf_error (line_buf, dwarf_buf_error (line_buf,
@ -3171,14 +3189,14 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
filename = ""; filename = "";
else else
{ {
if (fileno - 1 >= hdr->filenames_count) if (fileno >= hdr->filenames_count)
{ {
dwarf_buf_error (line_buf, dwarf_buf_error (line_buf,
("invalid file number in " ("invalid file number in "
"line number program")); "line number program"));
return 0; return 0;
} }
filename = hdr->filenames[fileno - 1]; filename = hdr->filenames[fileno];
} }
} }
break; break;
@ -3268,7 +3286,7 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr)) if (!read_line_header (state, ddata, u, is_dwarf64, &line_buf, hdr))
goto fail; goto fail;
if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec)) if (!read_line_program (state, ddata, hdr, &line_buf, &vec))
goto fail; goto fail;
if (line_buf.reported_underflow) if (line_buf.reported_underflow)
@ -3609,7 +3627,7 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
function->caller_filename = ""; function->caller_filename = "";
else else
{ {
if (val.u.uint - 1 >= lhdr->filenames_count) if (val.u.uint >= lhdr->filenames_count)
{ {
dwarf_buf_error (unit_buf, dwarf_buf_error (unit_buf,
("invalid file number in " ("invalid file number in "
@ -3617,7 +3635,7 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
return 0; return 0;
} }
function->caller_filename = function->caller_filename =
lhdr->filenames[val.u.uint - 1]; lhdr->filenames[val.u.uint];
} }
} }
break; break;
@ -3740,8 +3758,23 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
if (fvec.count > 0) if (fvec.count > 0)
{ {
struct function_addrs *p;
struct function_addrs *faddrs; struct function_addrs *faddrs;
/* Allocate a trailing entry, but don't include it
in fvec.count. */
p = ((struct function_addrs *)
backtrace_vector_grow (state,
sizeof (struct function_addrs),
error_callback, data,
&fvec.vec));
if (p == NULL)
return 0;
p->low = 0;
--p->low;
p->high = p->low;
p->function = NULL;
if (!backtrace_vector_release (state, &fvec.vec, if (!backtrace_vector_release (state, &fvec.vec,
error_callback, data)) error_callback, data))
return 0; return 0;
@ -3775,6 +3808,7 @@ read_function_info (struct backtrace_state *state, struct dwarf_data *ddata,
struct function_vector lvec; struct function_vector lvec;
struct function_vector *pfvec; struct function_vector *pfvec;
struct dwarf_buf unit_buf; struct dwarf_buf unit_buf;
struct function_addrs *p;
struct function_addrs *addrs; struct function_addrs *addrs;
size_t addrs_count; size_t addrs_count;
@ -3806,6 +3840,18 @@ read_function_info (struct backtrace_state *state, struct dwarf_data *ddata,
if (pfvec->count == 0) if (pfvec->count == 0)
return; return;
/* Allocate a trailing entry, but don't include it in
pfvec->count. */
p = ((struct function_addrs *)
backtrace_vector_grow (state, sizeof (struct function_addrs),
error_callback, data, &pfvec->vec));
if (p == NULL)
return;
p->low = 0;
--p->low;
p->high = p->low;
p->function = NULL;
addrs_count = pfvec->count; addrs_count = pfvec->count;
if (fvec == NULL) if (fvec == NULL)
@ -3842,30 +3888,54 @@ report_inlined_functions (uintptr_t pc, struct function *function,
backtrace_full_callback callback, void *data, backtrace_full_callback callback, void *data,
const char **filename, int *lineno) const char **filename, int *lineno)
{ {
struct function_addrs *function_addrs; struct function_addrs *p;
struct function_addrs *match;
struct function *inlined; struct function *inlined;
int ret; int ret;
if (function->function_addrs_count == 0) if (function->function_addrs_count == 0)
return 0; return 0;
function_addrs = ((struct function_addrs *) /* Our search isn't safe if pc == -1, as that is the sentinel
value. */
if (pc + 1 == 0)
return 0;
p = ((struct function_addrs *)
bsearch (&pc, function->function_addrs, bsearch (&pc, function->function_addrs,
function->function_addrs_count, function->function_addrs_count,
sizeof (struct function_addrs), sizeof (struct function_addrs),
function_addrs_search)); function_addrs_search));
if (function_addrs == NULL) if (p == NULL)
return 0; return 0;
while (((size_t) (function_addrs - function->function_addrs) + 1 /* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are
< function->function_addrs_count) sorted by low, so if pc > p->low we are at the end of a range of
&& pc >= (function_addrs + 1)->low function_addrs with the same low value. If pc == p->low walk
&& pc < (function_addrs + 1)->high) forward to the end of the range with that low value. Then walk
++function_addrs; backward and use the first range that includes pc. */
while (pc == (p + 1)->low)
++p;
match = NULL;
while (1)
{
if (pc < p->high)
{
match = p;
break;
}
if (p == function->function_addrs)
break;
if ((p - 1)->low < p->low)
break;
--p;
}
if (match == NULL)
return 0;
/* We found an inlined call. */ /* We found an inlined call. */
inlined = function_addrs->function; inlined = match->function;
/* Report any calls inlined into this one. */ /* Report any calls inlined into this one. */
ret = report_inlined_functions (pc, inlined, callback, data, ret = report_inlined_functions (pc, inlined, callback, data,
@ -3874,7 +3944,7 @@ report_inlined_functions (uintptr_t pc, struct function *function,
return ret; return ret;
/* Report this inlined call. */ /* Report this inlined call. */
ret = callback (data, pc, function_addrs->low, *filename, *lineno, inlined->name); ret = callback (data, pc, match->low, *filename, *lineno, inlined->name);
if (ret != 0) if (ret != 0)
return ret; return ret;
@ -3898,11 +3968,13 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
int *found) int *found)
{ {
struct unit_addrs *entry; struct unit_addrs *entry;
int found_entry;
struct unit *u; struct unit *u;
int new_data; int new_data;
struct line *lines; struct line *lines;
struct line *ln; struct line *ln;
struct function_addrs *function_addrs; struct function_addrs *p;
struct function_addrs *fmatch;
struct function *function; struct function *function;
const char *filename; const char *filename;
int lineno; int lineno;
@ -3910,8 +3982,10 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
*found = 1; *found = 1;
/* Find an address range that includes PC. */ /* Find an address range that includes PC. Our search isn't safe if
entry = (ddata->addrs_count == 0 PC == -1, as we use that as a sentinel value, so skip the search
in that case. */
entry = (ddata->addrs_count == 0 || pc + 1 == 0
? NULL ? NULL
: (struct unit_addrs*)bsearch (&pc, ddata->addrs, ddata->addrs_count, : (struct unit_addrs*)bsearch (&pc, ddata->addrs, ddata->addrs_count,
sizeof (struct unit_addrs), unit_addrs_search)); sizeof (struct unit_addrs), unit_addrs_search));
@ -3922,14 +3996,32 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
return 0; return 0;
} }
/* If there are multiple ranges that contain PC, use the last one, /* Here pc >= entry->low && pc < (entry + 1)->low. The unit_addrs
in order to produce predictable results. If we assume that all are sorted by low, so if pc > p->low we are at the end of a range
ranges are properly nested, then the last range will be the of unit_addrs with the same low value. If pc == p->low walk
smallest one. */ forward to the end of the range with that low value. Then walk
while ((size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count backward and use the first range that includes pc. */
&& pc >= (entry + 1)->low while (pc == (entry + 1)->low)
&& pc < (entry + 1)->high)
++entry; ++entry;
found_entry = 0;
while (1)
{
if (pc < entry->high)
{
found_entry = 1;
break;
}
if (entry == ddata->addrs)
break;
if ((entry - 1)->low < entry->low)
break;
--entry;
}
if (!found_entry)
{
*found = 0;
return 0;
}
/* We need the lines, lines_count, function_addrs, /* We need the lines, lines_count, function_addrs,
function_addrs_count fields of u. If they are not set, we need function_addrs_count fields of u. If they are not set, we need
@ -3965,6 +4057,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
new_data = 0; new_data = 0;
if (lines == NULL) if (lines == NULL)
{ {
struct function_addrs *function_addrs;
size_t function_addrs_count; size_t function_addrs_count;
struct line_header lhdr; struct line_header lhdr;
size_t count; size_t count;
@ -4081,24 +4174,39 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
if (entry->u->function_addrs_count == 0) if (entry->u->function_addrs_count == 0)
return callback (data, pc, 0, ln->filename, ln->lineno, NULL); return callback (data, pc, 0, ln->filename, ln->lineno, NULL);
function_addrs = ((struct function_addrs *) p = ((struct function_addrs *)
bsearch (&pc, entry->u->function_addrs, bsearch (&pc, entry->u->function_addrs,
entry->u->function_addrs_count, entry->u->function_addrs_count,
sizeof (struct function_addrs), sizeof (struct function_addrs),
function_addrs_search)); function_addrs_search));
if (function_addrs == NULL) if (p == NULL)
return callback (data, pc, 0, ln->filename, ln->lineno, NULL); return callback (data, pc, 0, ln->filename, ln->lineno, NULL);
/* If there are multiple function ranges that contain PC, use the /* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are
last one, in order to produce predictable results. */ sorted by low, so if pc > p->low we are at the end of a range of
function_addrs with the same low value. If pc == p->low walk
forward to the end of the range with that low value. Then walk
backward and use the first range that includes pc. */
while (pc == (p + 1)->low)
++p;
fmatch = NULL;
while (1)
{
if (pc < p->high)
{
fmatch = p;
break;
}
if (p == entry->u->function_addrs)
break;
if ((p - 1)->low < p->low)
break;
--p;
}
if (fmatch == NULL)
return callback (data, pc, 0, ln->filename, ln->lineno, NULL);
while (((size_t) (function_addrs - entry->u->function_addrs + 1) function = fmatch->function;
< entry->u->function_addrs_count)
&& pc >= (function_addrs + 1)->low
&& pc < (function_addrs + 1)->high)
++function_addrs;
function = function_addrs->function;
filename = ln->filename; filename = ln->filename;
lineno = ln->lineno; lineno = ln->lineno;
@ -4108,7 +4216,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
if (ret != 0) if (ret != 0)
return ret; return ret;
return callback (data, pc, function_addrs->low, filename, lineno, function->name); return callback (data, pc, fmatch->low, filename, lineno, function->name);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/* fileline.c -- Get file and line number information in a backtrace. /* fileline.c -- Get file and line number information in a backtrace.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -43,28 +43,15 @@ POSSIBILITY OF SUCH DAMAGE. */
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
#ifdef HAVE_MACH_O_DYLD_H
#include <mach-o/dyld.h>
#endif
#include "backtrace.hpp" #include "backtrace.hpp"
#include "internal.hpp" #include "internal.hpp"
#ifndef HAVE_GETEXECNAME #ifndef HAVE_GETEXECNAME
# ifdef __APPLE__
# include <mach-o/dyld.h>
static const char* getexecname()
{
static char execname[PATH_MAX+1];
uint32_t size = sizeof( execname );
if( _NSGetExecutablePath( execname, &size ) == 0 )
{
return execname;
}
else
{
return nullptr;
}
}
# else
#define getexecname() NULL #define getexecname() NULL
# endif
#endif #endif
namespace tracy namespace tracy
@ -142,6 +129,35 @@ sysctl_exec_name2 (struct backtrace_state *state,
#endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */ #endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
#ifdef HAVE_MACH_O_DYLD_H
static char *
macho_get_executable_path (struct backtrace_state *state,
backtrace_error_callback error_callback, void *data)
{
uint32_t len;
char *name;
len = 0;
if (_NSGetExecutablePath (NULL, &len) == 0)
return NULL;
name = (char *) backtrace_alloc (state, len, error_callback, data);
if (name == NULL)
return NULL;
if (_NSGetExecutablePath (name, &len) != 0)
{
backtrace_free (state, name, len, error_callback, data);
return NULL;
}
return name;
}
#else /* !defined (HAVE_MACH_O_DYLD_H) */
#define macho_get_executable_path(state, error_callback, data) NULL
#endif /* !defined (HAVE_MACH_O_DYLD_H) */
/* Initialize the fileline information from the executable. Returns 1 /* Initialize the fileline information from the executable. Returns 1
on success, 0 on failure. */ on success, 0 on failure. */
@ -179,7 +195,7 @@ fileline_initialize (struct backtrace_state *state,
descriptor = -1; descriptor = -1;
called_error_callback = 0; called_error_callback = 0;
for (pass = 0; pass < 7; ++pass) for (pass = 0; pass < 8; ++pass)
{ {
int does_not_exist; int does_not_exist;
@ -208,6 +224,9 @@ fileline_initialize (struct backtrace_state *state,
case 6: case 6:
filename = sysctl_exec_name2 (state, error_callback, data); filename = sysctl_exec_name2 (state, error_callback, data);
break; break;
case 7:
filename = macho_get_executable_path (state, error_callback, data);
break;
default: default:
abort (); abort ();
} }
@ -302,4 +321,31 @@ backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
return 1; return 1;
} }
/* A backtrace_syminfo_callback that can call into a
backtrace_full_callback, used when we have a symbol table but no
debug info. */
void
backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
const char *symname,
uintptr_t symval ATTRIBUTE_UNUSED,
uintptr_t symsize ATTRIBUTE_UNUSED)
{
struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
bdata->ret = bdata->full_callback (bdata->full_data, pc, 0, NULL, 0, symname);
}
/* An error callback that corresponds to
backtrace_syminfo_to_full_callback. */
void
backtrace_syminfo_to_full_error_callback (void *data, const char *msg,
int errnum)
{
struct backtrace_call_full *bdata = (struct backtrace_call_full *) data;
bdata->full_error_callback (bdata->full_data, msg, errnum);
}
} }

View File

@ -1,5 +1,5 @@
/* internal.h -- Internal header file for stack backtrace library. /* internal.h -- Internal header file for stack backtrace library.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -30,8 +30,8 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */ POSSIBILITY OF SUCH DAMAGE. */
#ifndef TRACY_BACKTRACE_INTERNAL_H #ifndef BACKTRACE_INTERNAL_H
#define TRACY_BACKTRACE_INTERNAL_H #define BACKTRACE_INTERNAL_H
/* We assume that <sys/types.h> and "backtrace.h" have already been /* We assume that <sys/types.h> and "backtrace.h" have already been
included. */ included. */
@ -56,6 +56,14 @@ POSSIBILITY OF SUCH DAMAGE. */
# endif # endif
#endif #endif
#ifndef ATTRIBUTE_FALLTHROUGH
# if (GCC_VERSION >= 7000)
# define ATTRIBUTE_FALLTHROUGH __attribute__ ((__fallthrough__))
# else
# define ATTRIBUTE_FALLTHROUGH
# endif
#endif
#ifndef HAVE_SYNC_FUNCTIONS #ifndef HAVE_SYNC_FUNCTIONS
/* Define out the sync functions. These should never be called if /* Define out the sync functions. These should never be called if
@ -329,6 +337,31 @@ extern int backtrace_dwarf_add (struct backtrace_state *state,
void *data, fileline *fileline_fn, void *data, fileline *fileline_fn,
struct dwarf_data **fileline_entry); struct dwarf_data **fileline_entry);
/* A data structure to pass to backtrace_syminfo_to_full. */
struct backtrace_call_full
{
backtrace_full_callback full_callback;
backtrace_error_callback full_error_callback;
void *full_data;
int ret;
};
/* A backtrace_syminfo_callback that can call into a
backtrace_full_callback, used when we have a symbol table but no
debug info. */
extern void backtrace_syminfo_to_full_callback (void *data, uintptr_t pc,
const char *symname,
uintptr_t symval,
uintptr_t symsize);
/* An error callback that corresponds to
backtrace_syminfo_to_full_callback. */
extern void backtrace_syminfo_to_full_error_callback (void *, const char *,
int);
/* A test-only hook for elf_uncompress_zdebug. */ /* A test-only hook for elf_uncompress_zdebug. */
extern int backtrace_uncompress_zdebug (struct backtrace_state *, extern int backtrace_uncompress_zdebug (struct backtrace_state *,
@ -338,6 +371,15 @@ extern int backtrace_uncompress_zdebug (struct backtrace_state *,
unsigned char **uncompressed, unsigned char **uncompressed,
size_t *uncompressed_size); size_t *uncompressed_size);
/* A test-only hook for elf_uncompress_lzma. */
extern int backtrace_uncompress_lzma (struct backtrace_state *,
const unsigned char *compressed,
size_t compressed_size,
backtrace_error_callback, void *data,
unsigned char **uncompressed,
size_t *uncompressed_size);
} }
#endif #endif

View File

@ -1,5 +1,5 @@
/* elf.c -- Get debug data from a Mach-O file for backtraces. /* elf.c -- Get debug data from a Mach-O file for backtraces.
Copyright (C) 2020 Free Software Foundation, Inc. Copyright (C) 2020-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -78,7 +78,7 @@ struct macho_header_64
struct macho_header_fat struct macho_header_fat
{ {
uint32_t magic; /* Magic number (MACH_O_MH_MAGIC_FAT) */ uint32_t magic; /* Magic number (MACH_O_MH_(MAGIC|CIGAM)_FAT(_64)?) */
uint32_t nfat_arch; /* Number of components */ uint32_t nfat_arch; /* Number of components */
}; };
@ -88,6 +88,8 @@ struct macho_header_fat
#define MACH_O_MH_MAGIC_64 0xfeedfacf #define MACH_O_MH_MAGIC_64 0xfeedfacf
#define MACH_O_MH_MAGIC_FAT 0xcafebabe #define MACH_O_MH_MAGIC_FAT 0xcafebabe
#define MACH_O_MH_CIGAM_FAT 0xbebafeca #define MACH_O_MH_CIGAM_FAT 0xbebafeca
#define MACH_O_MH_MAGIC_FAT_64 0xcafebabf
#define MACH_O_MH_CIGAM_FAT_64 0xbfbafeca
/* Value for the header filetype field. */ /* Value for the header filetype field. */
@ -108,6 +110,20 @@ struct macho_fat_arch
uint32_t align; /* Alignment of this entry */ uint32_t align; /* Alignment of this entry */
}; };
/* A component of a 64-bit fat file. This is used if the magic field
is MAGIC_FAT_64. This is only used when some file size or file
offset is too large to represent in the 32-bit format. */
struct macho_fat_arch_64
{
uint32_t cputype; /* CPU type */
uint32_t cpusubtype; /* CPU subtype */
uint64_t offset; /* File offset of this entry */
uint64_t size; /* Size of this entry */
uint32_t align; /* Alignment of this entry */
uint32_t reserved; /* Reserved */
};
/* Values for the fat_arch cputype field (and the header cputype /* Values for the fat_arch cputype field (and the header cputype
field). */ field). */
@ -115,9 +131,11 @@ struct macho_fat_arch
#define MACH_O_CPU_TYPE_X86 7 #define MACH_O_CPU_TYPE_X86 7
#define MACH_O_CPU_TYPE_ARM 12 #define MACH_O_CPU_TYPE_ARM 12
#define MACH_O_CPU_TYPE_PPC 18
#define MACH_O_CPU_TYPE_X86_64 (MACH_O_CPU_TYPE_X86 | MACH_O_CPU_ARCH_ABI64) #define MACH_O_CPU_TYPE_X86_64 (MACH_O_CPU_TYPE_X86 | MACH_O_CPU_ARCH_ABI64)
#define MACH_O_CPU_TYPE_ARM64 (MACH_O_CPU_TYPE_ARM | MACH_O_CPU_ARCH_ABI64) #define MACH_O_CPU_TYPE_ARM64 (MACH_O_CPU_TYPE_ARM | MACH_O_CPU_ARCH_ABI64)
#define MACH_O_CPU_TYPE_PPC64 (MACH_O_CPU_TYPE_PPC | MACH_O_CPU_ARCH_ABI64)
/* The header of a load command. */ /* The header of a load command. */
@ -743,14 +761,14 @@ static int
macho_add_fat (struct backtrace_state *state, const char *filename, macho_add_fat (struct backtrace_state *state, const char *filename,
int descriptor, int swapped, off_t offset, int descriptor, int swapped, off_t offset,
const unsigned char *match_uuid, uintptr_t base_address, const unsigned char *match_uuid, uintptr_t base_address,
int skip_symtab, uint32_t nfat_arch, int skip_symtab, uint32_t nfat_arch, int is_64,
backtrace_error_callback error_callback, void *data, backtrace_error_callback error_callback, void *data,
fileline *fileline_fn, int *found_sym) fileline *fileline_fn, int *found_sym)
{ {
int arch_view_valid; int arch_view_valid;
unsigned int cputype; unsigned int cputype;
size_t arch_size;
struct backtrace_view arch_view; struct backtrace_view arch_view;
size_t archoffset;
unsigned int i; unsigned int i;
arch_view_valid = 0; arch_view_valid = 0;
@ -763,46 +781,69 @@ macho_add_fat (struct backtrace_state *state, const char *filename,
cputype = MACH_O_CPU_TYPE_ARM64; cputype = MACH_O_CPU_TYPE_ARM64;
#elif defined (__arm__) #elif defined (__arm__)
cputype = MACH_O_CPU_TYPE_ARM; cputype = MACH_O_CPU_TYPE_ARM;
#elif defined (__ppc__)
cputype = MACH_O_CPU_TYPE_PPC;
#elif defined (__ppc64__)
cputype = MACH_O_CPU_TYPE_PPC64;
#else #else
error_callback (data, "unknown Mach-O architecture", 0); error_callback (data, "unknown Mach-O architecture", 0);
goto fail; goto fail;
#endif #endif
if (is_64)
arch_size = sizeof (struct macho_fat_arch_64);
else
arch_size = sizeof (struct macho_fat_arch);
if (!backtrace_get_view (state, descriptor, offset, if (!backtrace_get_view (state, descriptor, offset,
nfat_arch * sizeof (struct macho_fat_arch), nfat_arch * arch_size,
error_callback, data, &arch_view)) error_callback, data, &arch_view))
goto fail; goto fail;
archoffset = 0;
for (i = 0; i < nfat_arch; ++i) for (i = 0; i < nfat_arch; ++i)
{ {
struct macho_fat_arch fat_arch;
uint32_t fcputype; uint32_t fcputype;
uint64_t foffset;
memcpy (&fat_arch, if (is_64)
((const char *) arch_view.data {
+ i * sizeof (struct macho_fat_arch)), struct macho_fat_arch_64 fat_arch_64;
sizeof fat_arch);
fcputype = fat_arch.cputype; memcpy (&fat_arch_64,
(const char *) arch_view.data + i * arch_size,
arch_size);
fcputype = fat_arch_64.cputype;
foffset = fat_arch_64.offset;
if (swapped) if (swapped)
{
fcputype = __builtin_bswap32 (fcputype); fcputype = __builtin_bswap32 (fcputype);
foffset = __builtin_bswap64 (foffset);
}
}
else
{
struct macho_fat_arch fat_arch_32;
memcpy (&fat_arch_32,
(const char *) arch_view.data + i * arch_size,
arch_size);
fcputype = fat_arch_32.cputype;
foffset = (uint64_t) fat_arch_32.offset;
if (swapped)
{
fcputype = __builtin_bswap32 (fcputype);
foffset = (uint64_t) __builtin_bswap32 ((uint32_t) foffset);
}
}
if (fcputype == cputype) if (fcputype == cputype)
{ {
uint32_t foffset;
/* FIXME: What about cpusubtype? */ /* FIXME: What about cpusubtype? */
foffset = fat_arch.offset;
if (swapped)
foffset = __builtin_bswap32 (foffset);
backtrace_release_view (state, &arch_view, error_callback, data); backtrace_release_view (state, &arch_view, error_callback, data);
return macho_add (state, filename, descriptor, foffset, match_uuid, return macho_add (state, filename, descriptor, foffset, match_uuid,
base_address, skip_symtab, error_callback, data, base_address, skip_symtab, error_callback, data,
fileline_fn, found_sym); fileline_fn, found_sym);
} }
archoffset += sizeof (struct macho_fat_arch);
} }
error_callback (data, "could not find executable in fat file", 0); error_callback (data, "could not find executable in fat file", 0);
@ -871,6 +912,7 @@ macho_add_dsym (struct backtrace_state *state, const char *filename,
dsymsuffixdirlen = strlen (dsymsuffixdir); dsymsuffixdirlen = strlen (dsymsuffixdir);
dsymlen = (dirnamelen dsymlen = (dirnamelen
+ 1
+ basenamelen + basenamelen
+ dsymsuffixdirlen + dsymsuffixdirlen
+ basenamelen + basenamelen
@ -893,7 +935,7 @@ macho_add_dsym (struct backtrace_state *state, const char *filename,
if (diralc != NULL) if (diralc != NULL)
{ {
backtrace_free (state, diralc, dirnamelen, error_callback, data); backtrace_free (state, diralc, dirnamelen + 1, error_callback, data);
diralc = NULL; diralc = NULL;
} }
@ -983,6 +1025,7 @@ macho_add (struct backtrace_state *state, const char *filename, int descriptor,
hdroffset = offset + sizeof (struct macho_header_64); hdroffset = offset + sizeof (struct macho_header_64);
break; break;
case MACH_O_MH_MAGIC_FAT: case MACH_O_MH_MAGIC_FAT:
case MACH_O_MH_MAGIC_FAT_64:
{ {
struct macho_header_fat fat_header; struct macho_header_fat fat_header;
@ -990,10 +1033,12 @@ macho_add (struct backtrace_state *state, const char *filename, int descriptor,
memcpy (&fat_header, &header, sizeof fat_header); memcpy (&fat_header, &header, sizeof fat_header);
return macho_add_fat (state, filename, descriptor, 0, hdroffset, return macho_add_fat (state, filename, descriptor, 0, hdroffset,
match_uuid, base_address, skip_symtab, match_uuid, base_address, skip_symtab,
fat_header.nfat_arch, error_callback, data, fat_header.nfat_arch,
fileline_fn, found_sym); header.magic == MACH_O_MH_MAGIC_FAT_64,
error_callback, data, fileline_fn, found_sym);
} }
case MACH_O_MH_CIGAM_FAT: case MACH_O_MH_CIGAM_FAT:
case MACH_O_MH_CIGAM_FAT_64:
{ {
struct macho_header_fat fat_header; struct macho_header_fat fat_header;
uint32_t nfat_arch; uint32_t nfat_arch;
@ -1003,8 +1048,9 @@ macho_add (struct backtrace_state *state, const char *filename, int descriptor,
nfat_arch = __builtin_bswap32 (fat_header.nfat_arch); nfat_arch = __builtin_bswap32 (fat_header.nfat_arch);
return macho_add_fat (state, filename, descriptor, 1, hdroffset, return macho_add_fat (state, filename, descriptor, 1, hdroffset,
match_uuid, base_address, skip_symtab, match_uuid, base_address, skip_symtab,
nfat_arch, error_callback, data, nfat_arch,
fileline_fn, found_sym); header.magic == MACH_O_MH_CIGAM_FAT_64,
error_callback, data, fileline_fn, found_sym);
} }
default: default:
error_callback (data, "executable file is not in Mach-O format", 0); error_callback (data, "executable file is not in Mach-O format", 0);

View File

@ -1,5 +1,5 @@
/* mmapio.c -- File views using mmap. /* mmapio.c -- File views using mmap.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -40,6 +40,10 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "backtrace.hpp" #include "backtrace.hpp"
#include "internal.hpp" #include "internal.hpp"
#ifndef HAVE_DECL_GETPAGESIZE
extern int getpagesize (void);
#endif
#ifndef MAP_FAILED #ifndef MAP_FAILED
#define MAP_FAILED ((void *)-1) #define MAP_FAILED ((void *)-1)
#endif #endif
@ -101,10 +105,10 @@ backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED,
union { union {
const void *cv; const void *cv;
void *v; void *v;
}; } cc;
cv = view->base; cc.cv = view->base;
if (munmap (v, view->len) < 0) if (munmap (cc.v, view->len) < 0)
error_callback (data, "munmap", errno); error_callback (data, "munmap", errno);
} }

View File

@ -1,5 +1,5 @@
/* posix.c -- POSIX file I/O routines for the backtrace library. /* posix.c -- POSIX file I/O routines for the backtrace library.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,5 +1,5 @@
/* sort.c -- Sort without allocating memory /* sort.c -- Sort without allocating memory
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -1,5 +1,5 @@
/* state.c -- Create the backtrace state. /* state.c -- Create the backtrace state.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Google. Written by Ian Lance Taylor, Google.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without