libbacktrace: use ELF symbol table if no debug info available

PR libbacktrace/97080
	* fileline.c (backtrace_syminfo_to_full_callback): New function.
	(backtrace_syminfo_to_full_error_callback): New function.
	* elf.c (elf_nodebug): Call syminfo_fn if possible.
	* internal.h (struct backtrace_call_full): Define.
	(backtrace_syminfo_to_full_callback): Declare.
	(backtrace_syminfo_to_full_error_callback): Declare.
	* mtest.c (f3): Only check all[i] if data.index permits.
This commit is contained in:
Ian Lance Taylor 2020-09-16 17:03:52 -07:00
parent fd111c419d
commit 90c2545651
4 changed files with 115 additions and 39 deletions

View File

@ -547,18 +547,6 @@ elf_crc32_file (struct backtrace_state *state, int descriptor,
return ret;
}
/* A dummy callback function used when we can't find any debug info. */
static int
elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
uintptr_t pc ATTRIBUTE_UNUSED,
backtrace_full_callback callback ATTRIBUTE_UNUSED,
backtrace_error_callback error_callback, void *data)
{
error_callback (data, "no debug info in ELF executable", -1);
return 0;
}
/* A dummy callback function used when we can't find a symbol
table. */
@ -571,6 +559,33 @@ elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
error_callback (data, "no symbol table in ELF executable", -1);
}
/* A callback function used when we can't find any debug info. */
static int
elf_nodebug (struct backtrace_state *state, uintptr_t pc,
backtrace_full_callback callback,
backtrace_error_callback error_callback, void *data)
{
if (state->syminfo_fn != NULL && state->syminfo_fn != elf_nosyms)
{
struct backtrace_call_full bdata;
/* Fetch symbol information so that we can least get the
function name. */
bdata.full_callback = callback;
bdata.full_error_callback = error_callback;
bdata.full_data = data;
bdata.ret = 0;
state->syminfo_fn (state, pc, backtrace_syminfo_to_full_callback,
backtrace_syminfo_to_full_error_callback, &bdata);
return bdata.ret;
}
error_callback (data, "no debug info in ELF executable", -1);
return 0;
}
/* Compare struct elf_symbol for qsort. */
static int

View File

@ -317,3 +317,30 @@ backtrace_syminfo (struct backtrace_state *state, uintptr_t pc,
state->syminfo_fn (state, pc, callback, error_callback, data);
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, 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

@ -326,6 +326,31 @@ extern int backtrace_dwarf_add (struct backtrace_state *state,
void *data, fileline *fileline_fn,
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. */
extern int backtrace_uncompress_zdebug (struct backtrace_state *,

View File

@ -156,40 +156,49 @@ f3 (int f1line __attribute__ ((unused)), int f2line __attribute__ ((unused)))
}
}
if (all[0].function == NULL)
if (data.index > 0)
{
fprintf (stderr, "test1: [0]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[0].function, "f3") != 0)
{
fprintf (stderr, "test1: [0]: got %s expected %s\n",
all[0].function, "f3");
data.failed = 1;
if (all[0].function == NULL)
{
fprintf (stderr, "test1: [0]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[0].function, "f3") != 0)
{
fprintf (stderr, "test1: [0]: got %s expected %s\n",
all[0].function, "f3");
data.failed = 1;
}
}
if (all[1].function == NULL)
if (data.index > 1)
{
fprintf (stderr, "test1: [1]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[1].function, "f2") != 0)
{
fprintf (stderr, "test1: [1]: got %s expected %s\n",
all[0].function, "f2");
data.failed = 1;
if (all[1].function == NULL)
{
fprintf (stderr, "test1: [1]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[1].function, "f2") != 0)
{
fprintf (stderr, "test1: [1]: got %s expected %s\n",
all[0].function, "f2");
data.failed = 1;
}
}
if (all[2].function == NULL)
if (data.index > 2)
{
fprintf (stderr, "test1: [2]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[2].function, "test1") != 0)
{
fprintf (stderr, "test1: [2]: got %s expected %s\n",
all[0].function, "test1");
data.failed = 1;
if (all[2].function == NULL)
{
fprintf (stderr, "test1: [2]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[2].function, "test1") != 0)
{
fprintf (stderr, "test1: [2]: got %s expected %s\n",
all[0].function, "test1");
data.failed = 1;
}
}
printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");