From: Andi Kleen <[email protected]>
Reworked patch based on a more compatible interface from Ian Lance
Taylor.
This allows tools to access discriminator and decl_line to resolve
inline stacks for autofdo.
libbacktrace/ChangeLog:
Andi Kleen <[email protected]>
Ian Lance Taylor <[email protected]>
* backtrace-supported.h.in (BACKTRACE_SUPPORTS_MOREDATA): New.
* backtrace.c (unwind): Handle moredata callback.
* backtrace.h (backtrace_pcinfo): Dito.
(struct backtrace_moredata): New interface.
* dwarf.c (struct line): Add disc field.
(struct function): Add caller_disc and decl_line.
(add_line): Handle discriminator.
(read_line_program): Dito.
(read_line_info): Dito.
(read_referenced_name): Handle decl_line.
(read_referenced_name_from_attr): Handle discriminator and
decl_line.
(read_function_entry): Dito.
(report_inlined_functions): Handle moredata callback.
(dwarf_lookup_pc): Dito.
(dwarf_fileline): Dito.
* fileline.c (backtrace_pcinfo): Add moredata.
(backtrace_syminfo): Dito.
* internal.h (struct backtrace_state): Add moredata flag.
* state.c (backtrace_create_state): Handle threaded flag.
---
libbacktrace/backtrace-supported.h.in | 8 +-
libbacktrace/backtrace.c | 14 ++-
libbacktrace/backtrace.h | 104 ++++++++++++++----
libbacktrace/dwarf.c | 151 +++++++++++++++++++++-----
libbacktrace/fileline.c | 21 +++-
libbacktrace/internal.h | 2 +
libbacktrace/state.c | 5 +-
7 files changed, 249 insertions(+), 56 deletions(-)
diff --git a/libbacktrace/backtrace-supported.h.in
b/libbacktrace/backtrace-supported.h.in
index 456c329f85d..e5ecf87f46a 100644
--- a/libbacktrace/backtrace-supported.h.in
+++ b/libbacktrace/backtrace-supported.h.in
@@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. */
be #include'd to see whether the backtrace library will be able to
get a backtrace and produce symbolic information. */
-
/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library
should work, 0 if it will not. Libraries may #include this to make
other arrangements. */
@@ -60,7 +59,12 @@ POSSIBILITY OF SUCH DAMAGE. */
#define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@
-/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo
+/* BACKTRACE_SUPPORTS_DATA will be #define'd as 1 if the backtrace_syminfo
will work for variables. It will always work for functions. */
#define BACKTRACE_SUPPORTS_DATA @BACKTRACE_SUPPORTS_DATA@
+
+/* BACKTRACE_SUPPORTS_MOREDATA will be #define'd as 1 if
+ backtrace_create_state supports setting the MOREDATA flag. */
+
+#define BACKTRACE_SUPPORTS_MOREDATA 1
diff --git a/libbacktrace/backtrace.c b/libbacktrace/backtrace.c
index 3935a3ed968..74ab932c1ec 100644
--- a/libbacktrace/backtrace.c
+++ b/libbacktrace/backtrace.c
@@ -31,6 +31,7 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
+#include <string.h>
#include <sys/types.h>
@@ -86,7 +87,18 @@ unwind (struct _Unwind_Context *context, void *vdata)
--pc;
if (!bdata->can_alloc)
- bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
+ {
+ if (bdata->state->moredata)
+ {
+ struct backtrace_moredata md;
+ memset (&md, 0, sizeof md);
+ md.version = 4;
+ md.data = bdata->data;
+ bdata->ret = bdata->callback (&md, pc, NULL, 0, NULL);
+ }
+ else
+ bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL);
+ }
else
bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback,
bdata->error_callback, bdata->data);
diff --git a/libbacktrace/backtrace.h b/libbacktrace/backtrace.h
index fd0c659decc..b94c410fe11 100644
--- a/libbacktrace/backtrace.h
+++ b/libbacktrace/backtrace.h
@@ -85,15 +85,44 @@ typedef void (*backtrace_error_callback) (void *data, const
char *msg,
/* Create state information for the backtrace routines. This must be
called before any of the other routines, and its return value must
- be passed to all of the other routines. FILENAME is the path name
- of the executable file; if it is NULL the library will try
- system-specific path names. If not NULL, FILENAME must point to a
- permanent buffer. If THREADED is non-zero the state may be
- accessed by multiple threads simultaneously, and the library will
- use appropriate atomic operations. If THREADED is zero the state
- may only be accessed by one thread at a time. This returns a state
- pointer on success, NULL on error. If an error occurs, this will
- call the ERROR_CALLBACK routine.
+ be passed to all of the other routines.
+
+ FILENAME is the path name of the executable file; if it is NULL the
+ library will try system-specific path names. If not NULL, FILENAME
+ must point to a permanent buffer.
+
+ FLAGS passes flags as bits in an int value:
+ 1: THREADED
+ 2: MOREDATA
+
+ If (FLAGS & 1) != 0 the THREADED flag is set. If this flag is set,
+ the state may be accessed by multiple threads simultaneously, and the
+ library will use appropriate atomic operations. If THREADED is not
+ set the state may only be accessed by one thread at a time.
+
+ If (FLAGS & 2) != 0 the MOREDATA flag is set. If this flag is set,
+ then backtrace_full_callback and backtrace_syminfo_callback will not
+ pass the DATA argument as the user-specified DATA value, but will
+ instead pass it as a pointer to a backtrace_moredata struct. This is
+ a backward compatible approach to getting more data from the various
+ backtrace functions. When the MOREDATA flag is set, the
+ backtrace_error_callback will also receive a pointer to
+ backtrace_moredata as its DATA argument; the callback can extract the
+ original data from the data field of the backtrace_moredata struct.
+
+ Historical note: in previous versions (before June, 2026) the FLAGS
+ argument was named THREADED, and passing non-zero for THREADED was
+ documented as doing what setting the THREADED flag does today. In
+ practice all callers passed either 0 or 1, so the new semantics of
+ the flag do not affect users of old versions of the library.
+ However, code that passes the MOREDATA flag must ensure that it is
+ using a new version of the library. The backtrace-supported.h file
+ will #define BACKTRACE_SUPPORTS_MOREDATA as 1 for versions of
+ libbacktrace that support the MOREDATA flag.
+
+ The backtrace_create_state function returns a state pointer on
+ success, NULL on error. If an error occurs, it will call the
+ ERROR_CALLBACK routine before returning.
Calling this function allocates resources that cannot be freed.
There is no backtrace_free_state function. The state is used to
@@ -106,13 +135,15 @@ extern struct backtrace_state *backtrace_create_state (
backtrace_error_callback error_callback, void *data);
/* The type of the callback argument to the backtrace_full function.
- DATA is the argument passed to backtrace_full. PC is the program
- counter. FILENAME is the name of the file containing PC, or NULL
- if not available. LINENO is the line number in FILENAME containing
- PC, or 0 if not available. FUNCTION is the name of the function
- containing PC, or NULL if not available. This should return 0 to
- continuing tracing. The FILENAME and FUNCTION buffers may become
- invalid after this function returns. */
+ DATA is either the argument passed to backtrace_full (if the MOREDATA
+ flag was not set when calling backtrace_create_state) or a pointer to
+ a backtrace_moredata struct. PC is the program counter. FILENAME is
+ the name of the file containing PC, or NULL if not available. LINENO
+ is the line number in FILENAME containing PC, or 0 if not available.
+ FUNCTION is the name of the function containing PC, or NULL if not
+ available. This should return 0 to continuing tracing. The FILENAME
+ and FUNCTION buffers may become invalid after this function
+ returns. */
typedef int (*backtrace_full_callback) (void *data, uintptr_t pc,
const char *filename, int lineno,
@@ -173,11 +204,14 @@ extern int backtrace_pcinfo (struct backtrace_state
*state, uintptr_t pc,
backtrace_error_callback error_callback,
void *data);
-/* The type of the callback argument to backtrace_syminfo. DATA and
- PC are the arguments passed to backtrace_syminfo. SYMNAME is the
- name of the symbol for the corresponding code. SYMVAL is the
- value and SYMSIZE is the size of the symbol. SYMNAME will be NULL
- if no error occurred but the symbol could not be found. */
+/* The type of the callback argument to backtrace_syminfo. DATA is
+ either the argument passed to backtrace_syminfo (if the MOREDATA flag
+ was not set when calling backtrace_create_state) or a pointer to a
+ backtrace_moredata struct. PC is the argument passed to
+ backtrace_syminfo. SYMNAME is the name of the symbol for the
+ corresponding code. SYMVAL is the value and SYMSIZE is the size of
+ the symbol. SYMNAME will be NULL if no error occurred but the symbol
+ could not be found. */
typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc,
const char *symname,
@@ -199,6 +233,34 @@ extern int backtrace_syminfo (struct backtrace_state
*state, uintptr_t addr,
backtrace_error_callback error_callback,
void *data);
+/* The type of the value that the DATA argument passed to
+ backtrace_full_callback or backtrace_syminfo_callback points to if
+ the MOREDATA flag is set in the call to backtrace_create_state.
+
+ The backtrace_moredata value will only be valid for the lifetime of
+ the callback; the callback may copy the data out but must not save
+ the pointer it receives. */
+
+struct backtrace_moredata
+{
+ /* The version of this struct. The current expectation is that the
+ version number will be the number of fields in the struct. It's
+ possible that future versions of libbacktrace will add new fields
+ and increment the version number accordingly. There is no plan to
+ remove fields from this struct. Thus the current value of the
+ version field will be 4. */
+ int version;
+ /* The DATA value passed to whatever function is calling the callback
+ (backtrace_full, backtrace_pcinfo, or backtrace_syminfo). */
+ void *data;
+ /* The DWARF discriminator. This is zero if there is none. See
+ https://wiki.dwarfstd.org/Path_Discriminators.md. */
+ unsigned int discriminator;
+ /* The line of the original declaration of the symbol the PC is
+ in. */
+ unsigned int decl_line;
+};
+
#ifdef __cplusplus
} /* End extern "C". */
#endif
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index ecf32f7688b..7dfff1293ba 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -234,6 +234,8 @@ struct line
const char *filename;
/* Line number. */
int lineno;
+ /* Discriminator. */
+ int disc;
/* Index of the object in the original array read from the DWARF
section, before it has been sorted. The index makes it possible
to use Quicksort and maintain stability. */
@@ -263,6 +265,10 @@ struct function
/* If this is an inlined function, the line number of the call
site. */
int caller_lineno;
+ /* Dito for the discriminator. */
+ int caller_disc;
+ /* Dito for the line of the declaration. */
+ int decl_line;
/* Map PC ranges to inlined functions. */
struct function_addrs *function_addrs;
size_t function_addrs_count;
@@ -2484,7 +2490,7 @@ build_address_map (struct backtrace_state *state,
static int
add_line (struct backtrace_state *state, struct dwarf_data *ddata,
- uintptr_t pc, const char *filename, int lineno,
+ uintptr_t pc, const char *filename, int lineno, int disc,
backtrace_error_callback error_callback, void *data,
struct line_vector *vec)
{
@@ -2495,7 +2501,8 @@ add_line (struct backtrace_state *state, struct
dwarf_data *ddata,
if (vec->count > 0)
{
ln = (struct line *) vec->vec.base + (vec->count - 1);
- if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno)
+ if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno
+ && ln->disc == disc)
return 1;
}
@@ -2511,6 +2518,7 @@ add_line (struct backtrace_state *state, struct
dwarf_data *ddata,
ln->filename = filename;
ln->lineno = lineno;
+ ln->disc = disc;
ln->idx = vec->count;
++vec->count;
@@ -2929,6 +2937,7 @@ read_line_program (struct backtrace_state *state, struct
dwarf_data *ddata,
const char *reset_filename;
const char *filename;
int lineno;
+ int disc = 0;
address = 0;
op_index = 0;
@@ -2954,8 +2963,9 @@ read_line_program (struct backtrace_state *state, struct
dwarf_data *ddata,
/ hdr->max_ops_per_insn);
op_index = (op_index + advance) % hdr->max_ops_per_insn;
lineno += hdr->line_base + (int) (op % hdr->line_range);
- add_line (state, ddata, address, filename, lineno,
+ add_line (state, ddata, address, filename, lineno, disc,
line_buf->error_callback, line_buf->data, vec);
+ disc = 0;
}
else if (op == DW_LNS_extended_op)
{
@@ -2973,6 +2983,7 @@ read_line_program (struct backtrace_state *state, struct
dwarf_data *ddata,
op_index = 0;
filename = reset_filename;
lineno = 1;
+ disc = 0;
break;
case DW_LNE_set_address:
address = read_address (line_buf, hdr->addrsize);
@@ -3025,11 +3036,10 @@ read_line_program (struct backtrace_state *state,
struct dwarf_data *ddata,
memcpy (p + dir_len + 1, f, f_len + 1);
filename = p;
}
- }
+ }
break;
case DW_LNE_set_discriminator:
- /* We don't care about discriminators. */
- read_uleb128 (line_buf);
+ disc = read_uleb128 (line_buf);
break;
default:
if (!advance (line_buf, len - 1))
@@ -3042,8 +3052,9 @@ read_line_program (struct backtrace_state *state, struct
dwarf_data *ddata,
switch (op)
{
case DW_LNS_copy:
- add_line (state, ddata, address, filename, lineno,
+ add_line (state, ddata, address, filename, lineno, disc,
line_buf->error_callback, line_buf->data, vec);
+ disc = 0;
break;
case DW_LNS_advance_pc:
{
@@ -3183,6 +3194,7 @@ read_line_info (struct backtrace_state *state, struct
dwarf_data *ddata,
ln->pc = (uintptr_t) -1;
ln->filename = NULL;
ln->lineno = 0;
+ ln->disc = 0;
ln->idx = 0;
if (!backtrace_vector_release (state, &vec.vec, error_callback, data))
@@ -3206,15 +3218,17 @@ read_line_info (struct backtrace_state *state, struct
dwarf_data *ddata,
static const char *read_referenced_name (struct dwarf_data *, struct unit *,
uint64_t, backtrace_error_callback,
- void *);
+ void *, int *);
-/* Read the name of a function from a DIE referenced by ATTR with VAL. */
+/* Read the name of a function from a DIE referenced by ATTR with VAL.
+ If DECL_LINE is not NULL, and the referenced DIE has a
+ DW_AT_decl_line attribute, store its value in *DECL_LINE. */
static const char *
read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
struct attr *attr, struct attr_val *val,
backtrace_error_callback error_callback,
- void *data)
+ void *data, int *decl_line)
{
switch (attr->name)
{
@@ -3237,12 +3251,14 @@ read_referenced_name_from_attr (struct dwarf_data
*ddata, struct unit *u,
return NULL;
uint64_t offset = val->u.uint - unit->low_offset;
- return read_referenced_name (ddata, unit, offset, error_callback, data);
+ return read_referenced_name (ddata, unit, offset, error_callback, data,
+ decl_line);
}
if (val->encoding == ATTR_VAL_UINT
|| val->encoding == ATTR_VAL_REF_UNIT)
- return read_referenced_name (ddata, u, val->u.uint, error_callback, data);
+ return read_referenced_name (ddata, u, val->u.uint, error_callback, data,
+ decl_line);
if (val->encoding == ATTR_VAL_REF_ALT_INFO)
{
@@ -3254,7 +3270,7 @@ read_referenced_name_from_attr (struct dwarf_data *ddata,
struct unit *u,
uint64_t offset = val->u.uint - alt_unit->low_offset;
return read_referenced_name (ddata->altlink, alt_unit, offset,
- error_callback, data);
+ error_callback, data, decl_line);
}
return NULL;
@@ -3262,12 +3278,14 @@ read_referenced_name_from_attr (struct dwarf_data
*ddata, struct unit *u,
/* Read the name of a function from a DIE referenced by a
DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within
- the same compilation unit. */
+ the same compilation unit. If DECL_LINE is not NULL, and the
+ referenced DIE has a DW_AT_decl_line attribute, store its value in
+ *DECL_LINE. */
static const char *
read_referenced_name (struct dwarf_data *ddata, struct unit *u,
uint64_t offset, backtrace_error_callback error_callback,
- void *data)
+ void *data, int *decl_line)
{
struct dwarf_buf unit_buf;
uint64_t code;
@@ -3359,12 +3377,18 @@ read_referenced_name (struct dwarf_data *ddata, struct
unit *u,
const char *name;
name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i],
- &val, error_callback, data);
+ &val, error_callback, data,
+ decl_line);
if (name != NULL)
ret = name;
}
break;
+ case DW_AT_decl_line:
+ if (decl_line != NULL && val.encoding == ATTR_VAL_UINT)
+ *decl_line = val.u.uint;
+ break;
+
default:
break;
}
@@ -3517,6 +3541,16 @@ read_function_entry (struct backtrace_state *state,
struct dwarf_data *ddata,
function->caller_lineno = val.u.uint;
break;
+ case DW_AT_GNU_discriminator:
+ if (val.encoding == ATTR_VAL_UINT)
+ function->caller_disc = val.u.uint;
+ break;
+
+ case DW_AT_decl_line:
+ if (val.encoding == ATTR_VAL_UINT)
+ function->decl_line = val.u.uint;
+ break;
+
case DW_AT_abstract_origin:
case DW_AT_specification:
/* Second name preference: override DW_AT_name, don't override
@@ -3529,7 +3563,8 @@ read_function_entry (struct backtrace_state *state,
struct dwarf_data *ddata,
name
= read_referenced_name_from_attr (ddata, u,
&abbrev->attrs[i], &val,
- error_callback, data);
+ error_callback, data,
+ &function->decl_line);
if (name != NULL)
function->name = name;
}
@@ -3752,13 +3787,16 @@ read_function_info (struct backtrace_state *state,
struct dwarf_data *ddata,
}
/* See if PC is inlined in FUNCTION. If it is, print out the inlined
- information, and update FILENAME and LINENO for the caller.
+ information, and update FILENAME and LINENO and DISC and DECL_LINE
+ for the caller.
Returns whatever CALLBACK returns, or 0 to keep going. */
static int
-report_inlined_functions (uintptr_t pc, struct function *function,
+report_inlined_functions (struct backtrace_state *state,
+ uintptr_t pc, struct function *function,
backtrace_full_callback callback, void *data,
- const char **filename, int *lineno)
+ const char **filename, int *lineno,
+ int *disc)
{
struct function_addrs *p;
struct function_addrs *match;
@@ -3810,12 +3848,18 @@ report_inlined_functions (uintptr_t pc, struct function
*function,
inlined = match->function;
/* Report any calls inlined into this one. */
- ret = report_inlined_functions (pc, inlined, callback, data,
- filename, lineno);
+ ret = report_inlined_functions (state, pc, inlined, callback, data,
+ filename, lineno, disc);
if (ret != 0)
return ret;
/* Report this inlined call. */
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = *disc;
+ md->decl_line = inlined->decl_line;
+ }
ret = callback (data, pc, *filename, *lineno, inlined->name);
if (ret != 0)
return ret;
@@ -3824,6 +3868,7 @@ report_inlined_functions (uintptr_t pc, struct function
*function,
it the appropriate filename and line number. */
*filename = inlined->caller_filename;
*lineno = inlined->caller_lineno;
+ *disc = inlined->caller_disc;
return 0;
}
@@ -3850,6 +3895,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct
dwarf_data *ddata,
struct function *function;
const char *filename;
int lineno;
+ int disc = 0;
int ret;
*found = 1;
@@ -3991,6 +4037,12 @@ dwarf_lookup_pc (struct backtrace_state *state, struct
dwarf_data *ddata,
if (new_data)
return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
data, found);
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = 0;
+ md->decl_line = 0;
+ }
return callback (data, pc, NULL, 0, NULL);
}
@@ -4038,13 +4090,27 @@ dwarf_lookup_pc (struct backtrace_state *state, struct
dwarf_data *ddata,
entry->u->abs_filename = filename;
}
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = 0;
+ md->decl_line = 0;
+ }
return callback (data, pc, entry->u->abs_filename, 0, NULL);
}
/* Search for function name within this unit. */
if (entry->u->function_addrs_count == 0)
- return callback (data, pc, ln->filename, ln->lineno, NULL);
+ {
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = ln->disc;
+ md->decl_line = 0;
+ }
+ return callback (data, pc, ln->filename, ln->lineno, NULL);
+ }
p = ((struct function_addrs *)
bsearch (&pc, entry->u->function_addrs,
@@ -4052,7 +4118,15 @@ dwarf_lookup_pc (struct backtrace_state *state, struct
dwarf_data *ddata,
sizeof (struct function_addrs),
function_addrs_search));
if (p == NULL)
- return callback (data, pc, ln->filename, ln->lineno, NULL);
+ {
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = ln->disc;
+ md->decl_line = 0;
+ }
+ return callback (data, pc, ln->filename, ln->lineno, NULL);
+ }
/* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are
sorted by low, so if pc > p->low we are at the end of a range of
@@ -4076,18 +4150,32 @@ dwarf_lookup_pc (struct backtrace_state *state, struct
dwarf_data *ddata,
--p;
}
if (fmatch == NULL)
- return callback (data, pc, ln->filename, ln->lineno, NULL);
+ {
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = ln->disc;
+ md->decl_line = 0;
+ }
+ return callback (data, pc, ln->filename, ln->lineno, NULL);
+ }
function = fmatch->function;
filename = ln->filename;
lineno = ln->lineno;
+ disc = ln->disc;
- ret = report_inlined_functions (pc, function, callback, data,
- &filename, &lineno);
+ ret = report_inlined_functions (state, pc, function, callback, data,
+ &filename, &lineno, &disc);
if (ret != 0)
return ret;
-
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = disc;
+ md->decl_line = function->decl_line;
+ }
return callback (data, pc, filename, lineno, function->name);
}
@@ -4137,7 +4225,12 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t
pc,
}
/* FIXME: See if any libraries have been dlopen'ed. */
-
+ if (state->moredata)
+ {
+ struct backtrace_moredata *md = (struct backtrace_moredata *) data;
+ md->discriminator = 0;
+ md->decl_line = 0;
+ }
return callback (data, pc, NULL, 0, NULL);
}
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 82535e3f6cf..617133ee032 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -31,6 +31,7 @@ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE
POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -393,6 +394,15 @@ backtrace_pcinfo (struct backtrace_state *state, uintptr_t
pc,
if (state->fileline_initialization_failed)
return 0;
+ if (state->moredata)
+ {
+ struct backtrace_moredata md;
+ memset (&md, 0, sizeof md);
+ md.version = 4;
+ md.data = data;
+ return state->fileline_fn (state, pc, callback, error_callback, &md);
+ }
+
return state->fileline_fn (state, pc, callback, error_callback, data);
}
@@ -409,7 +419,16 @@ backtrace_syminfo (struct backtrace_state *state,
uintptr_t pc,
if (state->fileline_initialization_failed)
return 0;
- state->syminfo_fn (state, pc, callback, error_callback, data);
+ if (state->moredata)
+ {
+ struct backtrace_moredata md;
+ memset (&md, 0, sizeof md);
+ md.version = 4;
+ md.data = data;
+ state->syminfo_fn (state, pc, callback, error_callback, &md);
+ }
+ else
+ state->syminfo_fn (state, pc, callback, error_callback, data);
return 1;
}
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 09a2147fdef..a5521e7ee38 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -143,6 +143,8 @@ struct backtrace_state
const char *filename;
/* Non-zero if threaded. */
int threaded;
+ /* Non-zero if MOREDATA flag was set. */
+ int moredata;
/* The master lock for fileline_fn, fileline_data, syminfo_fn,
syminfo_data, fileline_initialization_failed and everything the
data pointers point to. */
diff --git a/libbacktrace/state.c b/libbacktrace/state.c
index 8c201624006..602e6d23b7b 100644
--- a/libbacktrace/state.c
+++ b/libbacktrace/state.c
@@ -51,7 +51,7 @@ backtrace_create_state (const char *filename, int threaded,
struct backtrace_state *state;
#ifndef HAVE_SYNC_FUNCTIONS
- if (threaded)
+ if (threaded & 1)
{
error_callback (data, "backtrace library does not support threads", 0);
return NULL;
@@ -60,7 +60,8 @@ backtrace_create_state (const char *filename, int threaded,
memset (&init_state, 0, sizeof init_state);
init_state.filename = filename;
- init_state.threaded = threaded;
+ init_state.threaded = threaded & 1;
+ init_state.moredata = (threaded & 2) != 0;
state = ((struct backtrace_state *)
backtrace_alloc (&init_state, sizeof *state, error_callback, data));
--
2.54.0