mirror of
https://github.com/ianlancetaylor/libbacktrace.git
synced 2026-09-07 12:17:06 +08:00
libbacktrace: support returning discriminator field
Based on patch from Andi Kleen. * backtrace.h (backtrace_create_state): Rewrite comment to change threaded parameter to flags. (backtrace_full_callback, backtrace_syminfo_callback): Document behavior change if moredata flag is set. (struct backtrace_moredata): Define. * backtrace-supported.h.in (BACKTRACE_SUPPORTS_MOREDATA): Define. * internal.h (struct backtrace_state): Add moredata field. (BACKTRACE_MOREDATA_VERSION): Define. * state.c (backtrace_create_state): Change threaded parameter to flags. Set state moredata field based on flags. * dwarf.c (struct line): Add disc field. (struct function): Add caller_disc field. (call_callback): New static function. (add_line): Add disc parameter. Change all callers. Store disc in new line value. (read_line_program): Track discriminator value. (read_line_info): Initialize disc field in final line entry. (read_function_entry): Handle DW_AT_GNU_discriminator. (report_inlined_functions): Add disc parameter. Change all callers. Call call_callback rather than calling callback directly. (dwarf_lookup_pc): Handle inlined discriminators. Call call_callback rather than calling callback directly. (dwarf_fileline): Call call_callback rather than calling callback directly. * elf.c (elf_syminfo): Pass moredata if requested. * macho.c (macho_syminfo): Likewise. * pecoff.c (coff_syminfo): Likewise. * xcoff.c (xcoff_syminfo): Likewise. (xcoff_lookup_pc): Likewise. * backtrace.c: #include <string.h>. (unwind): Pass moredata if requested. * unknown.c: #include <string.h>. (unknown_fileline): Pass moredata if requested. * fileline.c (backtrace_syminfo_to_full_callback): Add comment about moredata. * mdtest.c: New test file. * Makefile.am (mdtest_SOURCES): Define. (mdtest_CFLAGS, mdtest_LDFLAGS, mdtest_LDADD): Define. (BUILDTESTS): Add mdtest. * Makefile.in: Regenerate.
This commit is contained in:
@@ -568,6 +568,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. */
|
||||
@@ -597,6 +599,9 @@ struct function
|
||||
/* If this is an inlined function, the line number of the call
|
||||
site. */
|
||||
int caller_lineno;
|
||||
/* If this is an inlined function, the discriminator of the call
|
||||
site. */
|
||||
unsigned int caller_disc;
|
||||
/* Map PC ranges to inlined functions. */
|
||||
struct function_addrs *function_addrs;
|
||||
size_t function_addrs_count;
|
||||
@@ -1060,6 +1065,28 @@ read_initial_length (struct dwarf_buf *buf, int *is_dwarf64)
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Call the callback function, which differs based on the moredata state
|
||||
flag. */
|
||||
|
||||
static int
|
||||
call_callback (struct backtrace_state *state, backtrace_full_callback callback,
|
||||
void *data, uintptr_t pc, const char *filename, int lineno,
|
||||
const char *function, unsigned int disc)
|
||||
{
|
||||
if (!state->moredata)
|
||||
return callback (data, pc, filename, lineno, function);
|
||||
else
|
||||
{
|
||||
struct backtrace_moredata md;
|
||||
|
||||
memset (&md, 0, sizeof md);
|
||||
md.backtrace_version = BACKTRACE_MOREDATA_VERSION;
|
||||
md.backtrace_data = data;
|
||||
md.backtrace_discriminator = disc;
|
||||
return callback ((void *) &md, pc, filename, lineno, function);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free an abbreviations structure. */
|
||||
|
||||
static void
|
||||
@@ -2818,7 +2845,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)
|
||||
{
|
||||
@@ -2830,7 +2857,13 @@ add_line (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
{
|
||||
ln = (struct line *) vec->vec.base + (vec->count - 1);
|
||||
if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno)
|
||||
return 1;
|
||||
{
|
||||
/* We only care about the discriminator if moredata is true. */
|
||||
if (!state->moredata)
|
||||
return 1;
|
||||
if (disc == ln->disc)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ln = ((struct line *)
|
||||
@@ -2845,6 +2878,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;
|
||||
@@ -3263,6 +3297,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
const char *reset_filename;
|
||||
const char *filename;
|
||||
int lineno;
|
||||
unsigned int disc;
|
||||
|
||||
address = 0;
|
||||
op_index = 0;
|
||||
@@ -3272,6 +3307,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
reset_filename = "";
|
||||
filename = reset_filename;
|
||||
lineno = 1;
|
||||
disc = 0;
|
||||
while (line_buf->left > 0)
|
||||
{
|
||||
unsigned int op;
|
||||
@@ -3288,8 +3324,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)
|
||||
{
|
||||
@@ -3307,6 +3344,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);
|
||||
@@ -3362,8 +3400,7 @@ read_line_program (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
}
|
||||
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))
|
||||
@@ -3376,8 +3413,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:
|
||||
{
|
||||
@@ -3517,6 +3555,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))
|
||||
@@ -3846,6 +3885,11 @@ read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_AT_GNU_discriminator:
|
||||
if (val.encoding == ATTR_VAL_UINT)
|
||||
function->caller_disc = val.u.uint;
|
||||
break;
|
||||
|
||||
case DW_AT_call_line:
|
||||
if (val.encoding == ATTR_VAL_UINT)
|
||||
function->caller_lineno = val.u.uint;
|
||||
@@ -4086,13 +4130,15 @@ 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, LINENO, and DISC 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,
|
||||
unsigned int *disc)
|
||||
{
|
||||
struct function_addrs *p;
|
||||
struct function_addrs *match;
|
||||
@@ -4144,20 +4190,22 @@ 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. */
|
||||
ret = callback (data, pc, *filename, *lineno, inlined->name);
|
||||
ret = call_callback (state, callback, data, pc, *filename, *lineno,
|
||||
inlined->name, *disc);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* Our caller will report the caller of the inlined function; tell
|
||||
it the appropriate filename and line number. */
|
||||
it the appropriate filename, line number, and discriminator. */
|
||||
*filename = inlined->caller_filename;
|
||||
*lineno = inlined->caller_lineno;
|
||||
*disc = inlined->caller_disc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4184,6 +4232,7 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
struct function *function;
|
||||
const char *filename;
|
||||
int lineno;
|
||||
unsigned int disc;
|
||||
int ret;
|
||||
|
||||
*found = 1;
|
||||
@@ -4325,7 +4374,7 @@ 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);
|
||||
return callback (data, pc, NULL, 0, NULL);
|
||||
return call_callback (state, callback, data, pc, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/* Search for PC within this unit. */
|
||||
@@ -4372,13 +4421,15 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
entry->u->abs_filename = filename;
|
||||
}
|
||||
|
||||
return callback (data, pc, entry->u->abs_filename, 0, NULL);
|
||||
return call_callback (state, callback, data, pc, entry->u->abs_filename,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
/* Search for function name within this unit. */
|
||||
|
||||
if (entry->u->function_addrs_count == 0)
|
||||
return callback (data, pc, ln->filename, ln->lineno, NULL);
|
||||
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
||||
NULL, ln->disc);
|
||||
|
||||
p = ((struct function_addrs *)
|
||||
bsearch (&pc, entry->u->function_addrs,
|
||||
@@ -4386,7 +4437,8 @@ 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);
|
||||
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
||||
NULL, ln->disc);
|
||||
|
||||
/* 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
|
||||
@@ -4410,19 +4462,22 @@ dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata,
|
||||
--p;
|
||||
}
|
||||
if (fmatch == NULL)
|
||||
return callback (data, pc, ln->filename, ln->lineno, NULL);
|
||||
return call_callback (state, callback, data, pc, ln->filename, ln->lineno,
|
||||
NULL, ln->disc);
|
||||
|
||||
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;
|
||||
|
||||
return callback (data, pc, filename, lineno, function->name);
|
||||
return call_callback (state, callback, data, pc, filename, lineno,
|
||||
function->name, disc);
|
||||
}
|
||||
|
||||
|
||||
@@ -4472,7 +4527,7 @@ dwarf_fileline (struct backtrace_state *state, uintptr_t pc,
|
||||
|
||||
/* FIXME: See if any libraries have been dlopen'ed. */
|
||||
|
||||
return callback (data, pc, NULL, 0, NULL);
|
||||
return call_callback (state, callback, data, pc, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
/* Initialize our data structures from the DWARF debug info for a
|
||||
|
||||
Reference in New Issue
Block a user