Skip to content

Commit

Permalink
libbacktrace: use ELF symbol table if no debug info available
Browse files Browse the repository at this point in the history
	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.
  • Loading branch information
ianlancetaylor committed Sep 28, 2020
1 parent 753968c commit c8a81d4
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 39 deletions.
39 changes: 27 additions & 12 deletions elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */

Expand All @@ -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
Expand Down
27 changes: 27 additions & 0 deletions fileline.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
25 changes: 25 additions & 0 deletions internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 *,
Expand Down
63 changes: 36 additions & 27 deletions mtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
fprintf (stderr, "test1: [1]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[1].function, "f2") != 0)
if (data.index > 1)
{
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)
{
fprintf (stderr, "test1: [2]: missing function name\n");
data.failed = 1;
}
else if (strcmp (all[2].function, "test1") != 0)
if (data.index > 2)
{
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");
Expand Down

0 comments on commit c8a81d4

Please sign in to comment.