mirror of
https://github.com/ianlancetaylor/libbacktrace.git
synced 2026-09-07 12:17:06 +08:00
libbacktrace: report decl_lineno with MOREDATA
Based on patch by Andi Kleen. * backtrace.h (struct backtrace_moredata): Add backtrace_decl_lineno field. * internal.h (BACKTRACE_MOREDATA_VERSION): Change to 4. * dwarf.c (struct function): Add decl_lineno field. (call_callback): Add decl_lineno parameter. Change all callers. (read_referenced_name_from_attr): Likewise. (read_referenced_name): Likewise. (report_inlined_functions): Likewise. (read_function_entry): Set decl_lineno field. (dwarf_lookup_pc): Handle decl_lineno across inlines. * mdtest.c (struct mdinfo): Define. (struct mddata): Define. (md_callback_one): Adjust for mddata. (md_callback_three): Likewise. (test1, f2): Reformat for simpler line number testing. (f3): Test that decl_lineno is correct. (f13): Adjust for mddata.
This commit is contained in:
+4
-1
@@ -228,7 +228,7 @@ struct backtrace_moredata
|
|||||||
possible that future versions of libbacktrace will add new fields
|
possible that future versions of libbacktrace will add new fields
|
||||||
and increment the version number accordingly. There is no plan to
|
and increment the version number accordingly. There is no plan to
|
||||||
remove fields from this struct. Thus the current value of the
|
remove fields from this struct. Thus the current value of the
|
||||||
version field will be 3. */
|
version field will be 4. */
|
||||||
int backtrace_version;
|
int backtrace_version;
|
||||||
/* The DATA value passed to whatever function is calling the callback
|
/* The DATA value passed to whatever function is calling the callback
|
||||||
(backtrace_full, backtrace_pcinfo, or backtrace_syminfo). */
|
(backtrace_full, backtrace_pcinfo, or backtrace_syminfo). */
|
||||||
@@ -236,6 +236,9 @@ struct backtrace_moredata
|
|||||||
/* The DWARF discriminator. This is zero if there is none. See
|
/* The DWARF discriminator. This is zero if there is none. See
|
||||||
https://wiki.dwarfstd.org/Path_Discriminators.md. */
|
https://wiki.dwarfstd.org/Path_Discriminators.md. */
|
||||||
unsigned int backtrace_discriminator;
|
unsigned int backtrace_discriminator;
|
||||||
|
/* The line number of the start of the function declaration or
|
||||||
|
definition. This is 0 if not available. */
|
||||||
|
int backtrace_decl_lineno;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -602,6 +602,8 @@ struct function
|
|||||||
/* If this is an inlined function, the discriminator of the call
|
/* If this is an inlined function, the discriminator of the call
|
||||||
site. */
|
site. */
|
||||||
unsigned int caller_disc;
|
unsigned int caller_disc;
|
||||||
|
/* The line number of the declaration. */
|
||||||
|
int decl_lineno;
|
||||||
/* Map PC ranges to inlined functions. */
|
/* Map PC ranges to inlined functions. */
|
||||||
struct function_addrs *function_addrs;
|
struct function_addrs *function_addrs;
|
||||||
size_t function_addrs_count;
|
size_t function_addrs_count;
|
||||||
@@ -1071,7 +1073,7 @@ read_initial_length (struct dwarf_buf *buf, int *is_dwarf64)
|
|||||||
static int
|
static int
|
||||||
call_callback (struct backtrace_state *state, backtrace_full_callback callback,
|
call_callback (struct backtrace_state *state, backtrace_full_callback callback,
|
||||||
void *data, uintptr_t pc, const char *filename, int lineno,
|
void *data, uintptr_t pc, const char *filename, int lineno,
|
||||||
const char *function, unsigned int disc)
|
const char *function, unsigned int disc, int decl_lineno)
|
||||||
{
|
{
|
||||||
if (!state->moredata)
|
if (!state->moredata)
|
||||||
return callback (data, pc, filename, lineno, function);
|
return callback (data, pc, filename, lineno, function);
|
||||||
@@ -1083,6 +1085,7 @@ call_callback (struct backtrace_state *state, backtrace_full_callback callback,
|
|||||||
md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
|
md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
|
||||||
md.backtrace_data = data;
|
md.backtrace_data = data;
|
||||||
md.backtrace_discriminator = disc;
|
md.backtrace_discriminator = disc;
|
||||||
|
md.backtrace_decl_lineno = decl_lineno;
|
||||||
return callback ((void *) &md, pc, filename, lineno, function);
|
return callback ((void *) &md, pc, filename, lineno, function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3579,15 +3582,17 @@ read_line_info (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
|
|
||||||
static const char *read_referenced_name (struct dwarf_data *, struct unit *,
|
static const char *read_referenced_name (struct dwarf_data *, struct unit *,
|
||||||
uint64_t, backtrace_error_callback,
|
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.
|
||||||
|
This sets *DECL_LINENO to the decl_line attribute of the DIE if
|
||||||
|
available. */
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
|
read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
|
||||||
struct attr *attr, struct attr_val *val,
|
struct attr *attr, struct attr_val *val,
|
||||||
backtrace_error_callback error_callback,
|
backtrace_error_callback error_callback,
|
||||||
void *data)
|
void *data, int *decl_lineno)
|
||||||
{
|
{
|
||||||
switch (attr->name)
|
switch (attr->name)
|
||||||
{
|
{
|
||||||
@@ -3610,12 +3615,14 @@ read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
uint64_t offset = val->u.uint - unit->low_offset;
|
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_lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val->encoding == ATTR_VAL_UINT
|
if (val->encoding == ATTR_VAL_UINT
|
||||||
|| val->encoding == ATTR_VAL_REF_UNIT)
|
|| 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_lineno);
|
||||||
|
|
||||||
if (val->encoding == ATTR_VAL_REF_ALT_INFO)
|
if (val->encoding == ATTR_VAL_REF_ALT_INFO)
|
||||||
{
|
{
|
||||||
@@ -3627,7 +3634,7 @@ read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
|
|||||||
|
|
||||||
uint64_t offset = val->u.uint - alt_unit->low_offset;
|
uint64_t offset = val->u.uint - alt_unit->low_offset;
|
||||||
return read_referenced_name (ddata->altlink, alt_unit, offset,
|
return read_referenced_name (ddata->altlink, alt_unit, offset,
|
||||||
error_callback, data);
|
error_callback, data, decl_lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -3635,12 +3642,13 @@ read_referenced_name_from_attr (struct dwarf_data *ddata, struct unit *u,
|
|||||||
|
|
||||||
/* Read the name of a function from a DIE referenced by a
|
/* Read the name of a function from a DIE referenced by a
|
||||||
DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within
|
DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within
|
||||||
the same compilation unit. */
|
the same compilation unit. This sets *DECL_LINENO to the function's
|
||||||
|
decl_line attribute if available. */
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
read_referenced_name (struct dwarf_data *ddata, struct unit *u,
|
read_referenced_name (struct dwarf_data *ddata, struct unit *u,
|
||||||
uint64_t offset, backtrace_error_callback error_callback,
|
uint64_t offset, backtrace_error_callback error_callback,
|
||||||
void *data)
|
void *data, int *decl_lineno)
|
||||||
{
|
{
|
||||||
struct dwarf_buf unit_buf;
|
struct dwarf_buf unit_buf;
|
||||||
uint64_t code;
|
uint64_t code;
|
||||||
@@ -3732,12 +3740,18 @@ read_referenced_name (struct dwarf_data *ddata, struct unit *u,
|
|||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i],
|
name = read_referenced_name_from_attr (ddata, u, &abbrev->attrs[i],
|
||||||
&val, error_callback, data);
|
&val, error_callback, data,
|
||||||
|
decl_lineno);
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
ret = name;
|
ret = name;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DW_AT_decl_line:
|
||||||
|
if (val.encoding == ATTR_VAL_UINT)
|
||||||
|
*decl_lineno = (int) val.u.uint;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3890,6 +3904,11 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
function->caller_disc = val.u.uint;
|
function->caller_disc = val.u.uint;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DW_AT_decl_line:
|
||||||
|
if (val.encoding == ATTR_VAL_UINT)
|
||||||
|
function->decl_lineno = (int) val.u.uint;
|
||||||
|
break;
|
||||||
|
|
||||||
case DW_AT_call_line:
|
case DW_AT_call_line:
|
||||||
if (val.encoding == ATTR_VAL_UINT)
|
if (val.encoding == ATTR_VAL_UINT)
|
||||||
function->caller_lineno = val.u.uint;
|
function->caller_lineno = val.u.uint;
|
||||||
@@ -3907,7 +3926,8 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
name
|
name
|
||||||
= read_referenced_name_from_attr (ddata, u,
|
= read_referenced_name_from_attr (ddata, u,
|
||||||
&abbrev->attrs[i], &val,
|
&abbrev->attrs[i], &val,
|
||||||
error_callback, data);
|
error_callback, data,
|
||||||
|
&function->decl_lineno);
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
function->name = name;
|
function->name = name;
|
||||||
}
|
}
|
||||||
@@ -4130,15 +4150,17 @@ 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
|
/* See if PC is inlined in FUNCTION. If it is, print out the inlined
|
||||||
information, and update FILENAME, LINENO, and DISC for the caller.
|
information, and update FILENAME, LINENO, DISC, and DECL_LINENO for
|
||||||
Returns whatever CALLBACK returns, or 0 to keep going. */
|
the caller. Returns whatever CALLBACK returns, or 0 to keep
|
||||||
|
going. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
report_inlined_functions (struct backtrace_state *state, uintptr_t pc,
|
report_inlined_functions (struct backtrace_state *state, uintptr_t pc,
|
||||||
struct function *function,
|
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,
|
||||||
unsigned int *disc)
|
unsigned int *disc,
|
||||||
|
int *decl_lineno)
|
||||||
{
|
{
|
||||||
struct function_addrs *p;
|
struct function_addrs *p;
|
||||||
struct function_addrs *match;
|
struct function_addrs *match;
|
||||||
@@ -4191,13 +4213,13 @@ report_inlined_functions (struct backtrace_state *state, uintptr_t pc,
|
|||||||
|
|
||||||
/* Report any calls inlined into this one. */
|
/* Report any calls inlined into this one. */
|
||||||
ret = report_inlined_functions (state, pc, inlined, callback, data,
|
ret = report_inlined_functions (state, pc, inlined, callback, data,
|
||||||
filename, lineno, disc);
|
filename, lineno, disc, decl_lineno);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Report this inlined call. */
|
/* Report this inlined call. */
|
||||||
ret = call_callback (state, callback, data, pc, *filename, *lineno,
|
ret = call_callback (state, callback, data, pc, *filename, *lineno,
|
||||||
inlined->name, *disc);
|
inlined->name, *disc, *decl_lineno);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -4206,6 +4228,7 @@ report_inlined_functions (struct backtrace_state *state, uintptr_t pc,
|
|||||||
*filename = inlined->caller_filename;
|
*filename = inlined->caller_filename;
|
||||||
*lineno = inlined->caller_lineno;
|
*lineno = inlined->caller_lineno;
|
||||||
*disc = inlined->caller_disc;
|
*disc = inlined->caller_disc;
|
||||||
|
*decl_lineno = inlined->decl_lineno;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -4233,6 +4256,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
const char *filename;
|
const char *filename;
|
||||||
int lineno;
|
int lineno;
|
||||||
unsigned int disc;
|
unsigned int disc;
|
||||||
|
int decl_lineno;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
*found = 1;
|
*found = 1;
|
||||||
@@ -4374,7 +4398,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
if (new_data)
|
if (new_data)
|
||||||
return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
|
return dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
|
||||||
data, found);
|
data, found);
|
||||||
return call_callback (state, callback, data, pc, NULL, 0, NULL, 0);
|
return call_callback (state, callback, data, pc, NULL, 0, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search for PC within this unit. */
|
/* Search for PC within this unit. */
|
||||||
@@ -4422,14 +4446,14 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return call_callback (state, callback, data, pc, entry->u->abs_filename,
|
return call_callback (state, callback, data, pc, entry->u->abs_filename,
|
||||||
0, NULL, 0);
|
0, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search for function name within this unit. */
|
/* Search for function name within this unit. */
|
||||||
|
|
||||||
if (entry->u->function_addrs_count == 0)
|
if (entry->u->function_addrs_count == 0)
|
||||||
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
||||||
NULL, ln->disc);
|
NULL, ln->disc, 0);
|
||||||
|
|
||||||
p = ((struct function_addrs *)
|
p = ((struct function_addrs *)
|
||||||
bsearch (&pc, entry->u->function_addrs,
|
bsearch (&pc, entry->u->function_addrs,
|
||||||
@@ -4438,7 +4462,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
function_addrs_search));
|
function_addrs_search));
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
||||||
NULL, ln->disc);
|
NULL, ln->disc, 0);
|
||||||
|
|
||||||
/* Here pc >= p->low && pc < (p + 1)->low. The function_addrs are
|
/* 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
|
sorted by low, so if pc > p->low we are at the end of a range of
|
||||||
@@ -4463,21 +4487,22 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
|||||||
}
|
}
|
||||||
if (fmatch == NULL)
|
if (fmatch == NULL)
|
||||||
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
||||||
NULL, ln->disc);
|
NULL, ln->disc, 0);
|
||||||
|
|
||||||
function = fmatch->function;
|
function = fmatch->function;
|
||||||
|
|
||||||
filename = ln->filename;
|
filename = ln->filename;
|
||||||
lineno = ln->lineno;
|
lineno = ln->lineno;
|
||||||
disc = ln->disc;
|
disc = ln->disc;
|
||||||
|
decl_lineno = function->decl_lineno;
|
||||||
|
|
||||||
ret = report_inlined_functions (state, pc, function, callback, data,
|
ret = report_inlined_functions (state, pc, function, callback, data,
|
||||||
&filename, &lineno, &disc);
|
&filename, &lineno, &disc, &decl_lineno);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return call_callback (state, callback, data, pc, filename, lineno,
|
return call_callback (state, callback, data, pc, filename, lineno,
|
||||||
function->name, disc);
|
function->name, disc, decl_lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4527,7 +4552,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
|||||||
|
|
||||||
/* FIXME: See if any libraries have been dlopen'ed. */
|
/* FIXME: See if any libraries have been dlopen'ed. */
|
||||||
|
|
||||||
return call_callback (state, callback, data, pc, NULL, 0, NULL, 0);
|
return call_callback (state, callback, data, pc, NULL, 0, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize our data structures from the DWARF debug info for a
|
/* Initialize our data structures from the DWARF debug info for a
|
||||||
|
|||||||
+1
-1
@@ -428,6 +428,6 @@ extern int backtrace_uncompress_lzma (struct backtrace_state *,
|
|||||||
size_t *uncompressed_size);
|
size_t *uncompressed_size);
|
||||||
|
|
||||||
/* Current expected backtrace_moredata version. */
|
/* Current expected backtrace_moredata version. */
|
||||||
#define BACKTRACE_MOREDATA_VERSION (3)
|
#define BACKTRACE_MOREDATA_VERSION (4)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -48,6 +48,22 @@ POSSIBILITY OF SUCH DAMAGE. */
|
|||||||
|
|
||||||
#include "testlib.h"
|
#include "testlib.h"
|
||||||
|
|
||||||
|
/* Used to collect moredata info from backtraces. */
|
||||||
|
|
||||||
|
struct mdinfo
|
||||||
|
{
|
||||||
|
int decl_lineno;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* We pass a pointer to this as the data field to the backtrace
|
||||||
|
functions. */
|
||||||
|
|
||||||
|
struct mddata
|
||||||
|
{
|
||||||
|
struct bdata bdata;
|
||||||
|
struct mdinfo *mdall;
|
||||||
|
};
|
||||||
|
|
||||||
/* backtrace_full_callback with moredata flag. */
|
/* backtrace_full_callback with moredata flag. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -55,15 +71,21 @@ md_callback_one (void *vdata, uintptr_t pc, const char *filename, int lineno,
|
|||||||
const char *function)
|
const char *function)
|
||||||
{
|
{
|
||||||
struct backtrace_moredata *md = (struct backtrace_moredata *) vdata;
|
struct backtrace_moredata *md = (struct backtrace_moredata *) vdata;
|
||||||
struct bdata *data = (struct bdata *) md->backtrace_data;
|
struct mddata *mddata = (struct mddata *) md->backtrace_data;
|
||||||
|
struct bdata *data = &mddata->bdata;
|
||||||
|
|
||||||
if (md->backtrace_version != BACKTRACE_MOREDATA_VERSION)
|
if (md->backtrace_version != BACKTRACE_MOREDATA_VERSION)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "md_callback_one: wrong moredata version: got %u, want %u\n", md->backtrace_version, BACKTRACE_MOREDATA_VERSION);
|
fprintf (stderr,
|
||||||
|
"md_callback_one: wrong moredata version: got %u, want %u\n",
|
||||||
|
md->backtrace_version, BACKTRACE_MOREDATA_VERSION);
|
||||||
data->failed = 1;
|
data->failed = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->index < data->max)
|
||||||
|
mddata->mdall[data->index].decl_lineno = md->backtrace_decl_lineno;
|
||||||
|
|
||||||
return callback_one ((void *) data, pc, filename, lineno, function);
|
return callback_one ((void *) data, pc, filename, lineno, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +100,19 @@ md_callback_three (void *vdata, uintptr_t pc, const char *symname,
|
|||||||
|
|
||||||
if (md->backtrace_version != BACKTRACE_MOREDATA_VERSION)
|
if (md->backtrace_version != BACKTRACE_MOREDATA_VERSION)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "md_callback_one: wrong moredata version: got %u, want %u\n", md->backtrace_version, BACKTRACE_MOREDATA_VERSION);
|
fprintf (stderr,
|
||||||
|
"md_callback_three: wrong moredata version: got %u, want %u\n",
|
||||||
|
md->backtrace_version, BACKTRACE_MOREDATA_VERSION);
|
||||||
|
data->failed = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (md->backtrace_decl_lineno != 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"md_callback_three: unexpected non-zero decl_lineno %d\n",
|
||||||
|
md->backtrace_decl_lineno);
|
||||||
|
data->failed = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,17 +125,11 @@ static int test1 (void) __attribute__ ((noinline, noclone, optnone, unused));
|
|||||||
static int f2 (int) __attribute__ ((noinline, noclone));
|
static int f2 (int) __attribute__ ((noinline, noclone));
|
||||||
static int f3 (int, int) __attribute__ ((noinline, noclone));
|
static int f3 (int, int) __attribute__ ((noinline, noclone));
|
||||||
|
|
||||||
static int
|
static int test1 (void) {
|
||||||
test1 (void)
|
|
||||||
{
|
|
||||||
/* Returning a value here and elsewhere avoids a tailcall which
|
|
||||||
would mess up the backtrace. */
|
|
||||||
return f2 (__LINE__) + 1;
|
return f2 (__LINE__) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int f2 (int f1line) {
|
||||||
f2 (int f1line)
|
|
||||||
{
|
|
||||||
return f3 (f1line, __LINE__) + 2;
|
return f3 (f1line, __LINE__) + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,14 +137,16 @@ static int
|
|||||||
f3 (int f1line, int f2line)
|
f3 (int f1line, int f2line)
|
||||||
{
|
{
|
||||||
struct info all[20];
|
struct info all[20];
|
||||||
struct bdata data;
|
struct mdinfo mdall[20];
|
||||||
|
struct mddata data;
|
||||||
int f3line;
|
int f3line;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
data.all = &all[0];
|
data.bdata.all = &all[0];
|
||||||
data.index = 0;
|
data.bdata.index = 0;
|
||||||
data.max = 20;
|
data.bdata.max = 20;
|
||||||
data.failed = 0;
|
data.bdata.failed = 0;
|
||||||
|
data.mdall = &mdall[0];
|
||||||
|
|
||||||
f3line = __LINE__ + 1;
|
f3line = __LINE__ + 1;
|
||||||
i = backtrace_full (state, 0, md_callback_one, error_callback_one, &data);
|
i = backtrace_full (state, 0, md_callback_one, error_callback_one, &data);
|
||||||
@@ -124,24 +154,44 @@ f3 (int f1line, int f2line)
|
|||||||
if (i != 0)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "test1: unexpected return value %d\n", i);
|
fprintf (stderr, "test1: unexpected return value %d\n", i);
|
||||||
data.failed = 1;
|
data.bdata.failed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.index < 3)
|
if (data.bdata.index < 3)
|
||||||
{
|
{
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"test1: not enough frames; got %zu, expected at least 3\n",
|
"test1: not enough frames; got %zu, expected at least 3\n",
|
||||||
data.index);
|
data.bdata.index);
|
||||||
data.failed = 1;
|
data.bdata.failed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
check ("test1", 0, all, f3line, "f3", "mdtest.c", &data.failed);
|
check ("test1", 0, all, f3line, "f3", "mdtest.c", &data.bdata.failed);
|
||||||
check ("test1", 1, all, f2line, "f2", "mdtest.c", &data.failed);
|
check ("test1", 1, all, f2line, "f2", "mdtest.c", &data.bdata.failed);
|
||||||
check ("test1", 2, all, f1line, "test1", "mdtest.c", &data.failed);
|
check ("test1", 2, all, f1line, "test1", "mdtest.c", &data.bdata.failed);
|
||||||
|
|
||||||
printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
|
if (!data.bdata.failed)
|
||||||
|
{
|
||||||
|
/* This assumes a particular pattern for the definitions of f1 and
|
||||||
|
f2, above. */
|
||||||
|
if (data.mdall[1].decl_lineno != f2line - 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"test1: incorrect f2 decl_lineno; got %d, expected %d\n",
|
||||||
|
data.mdall[1].decl_lineno, f2line - 1);
|
||||||
|
data.bdata.failed = 1;
|
||||||
|
}
|
||||||
|
if (data.mdall[2].decl_lineno != f1line - 1)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"test1: incorrect f1 decl_lineno; got %d, expected %d\n",
|
||||||
|
data.mdall[2].decl_lineno, f1line - 1);
|
||||||
|
data.bdata.failed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (data.failed)
|
printf ("%s: backtrace_full noinline\n", data.bdata.failed ? "FAIL" : "PASS");
|
||||||
|
|
||||||
|
if (data.bdata.failed)
|
||||||
++failures;
|
++failures;
|
||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
@@ -169,14 +219,16 @@ static inline int
|
|||||||
f13 (int f1line, int f2line)
|
f13 (int f1line, int f2line)
|
||||||
{
|
{
|
||||||
struct info all[20];
|
struct info all[20];
|
||||||
struct bdata data;
|
struct mdinfo mdall[20];
|
||||||
|
struct mddata data;
|
||||||
int f3line;
|
int f3line;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
data.all = &all[0];
|
data.bdata.all = &all[0];
|
||||||
data.index = 0;
|
data.bdata.index = 0;
|
||||||
data.max = 20;
|
data.bdata.max = 20;
|
||||||
data.failed = 0;
|
data.bdata.failed = 0;
|
||||||
|
data.mdall = &mdall[0];
|
||||||
|
|
||||||
f3line = __LINE__ + 1;
|
f3line = __LINE__ + 1;
|
||||||
i = backtrace_full (state, 0, md_callback_one, error_callback_one, &data);
|
i = backtrace_full (state, 0, md_callback_one, error_callback_one, &data);
|
||||||
@@ -184,16 +236,16 @@ f13 (int f1line, int f2line)
|
|||||||
if (i != 0)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
fprintf (stderr, "test2: unexpected return value %d\n", i);
|
fprintf (stderr, "test2: unexpected return value %d\n", i);
|
||||||
data.failed = 1;
|
data.bdata.failed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
check ("test2", 0, all, f3line, "f13", "mdtest.c", &data.failed);
|
check ("test2", 0, all, f3line, "f13", "mdtest.c", &data.bdata.failed);
|
||||||
check ("test2", 1, all, f2line, "f12", "mdtest.c", &data.failed);
|
check ("test2", 1, all, f2line, "f12", "mdtest.c", &data.bdata.failed);
|
||||||
check ("test2", 2, all, f1line, "test2", "mdtest.c", &data.failed);
|
check ("test2", 2, all, f1line, "test2", "mdtest.c", &data.bdata.failed);
|
||||||
|
|
||||||
printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
|
printf ("%s: backtrace_full inline\n", data.bdata.failed ? "FAIL" : "PASS");
|
||||||
|
|
||||||
if (data.failed)
|
if (data.bdata.failed)
|
||||||
++failures;
|
++failures;
|
||||||
|
|
||||||
return failures;
|
return failures;
|
||||||
|
|||||||
Reference in New Issue
Block a user