Optionally allow unknown symbols in the backtrace tests

This is useful to test unwinding without debug information. The
binaries being examined might still have frame pointers that allow
us to bridge the unknown symbols.

Signed-off-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Ulf Hermann
2017-02-10 15:19:40 +01:00
committed by Mark Wielaard
parent a9d7469866
commit f9971cb422
3 changed files with 38 additions and 12 deletions
+6
View File
@@ -1,3 +1,9 @@
2017-02-09 Ulf Hermann <ulf.hermann@qt.io>
* backtrace.c: Add an option to allow unknown symbols in the trace
* backtrace-substr.sh: Add an option to allow unknown symbols
to check_core() and allow failed symbol lookups in check_err()
2017-02-09 Ulf Hermann <ulf.hermann@qt.io>
* backtrace-data.c: Don't assert that symbols are found.
+10 -4
View File
@@ -44,9 +44,12 @@ check_gsignal()
# In some cases we cannot reliably find out we got behind _start as some
# operating system do not properly terminate CFI by undefined PC.
# Ignore it here as it is a bug of OS, not a bug of elfutils.
# If the CFI is not terminated correctly, we might find another frame by
# checking for frame pointers. This is still not our problem, but only
# gives an error message when trying to look up the function name.
check_err()
{
if [ $(egrep -v <$1 'dwfl_thread_getframes: (No DWARF information found|no matching address range)$' \
if [ $(egrep -v <$1 'dwfl_thread_getframes: (No DWARF information found|no matching address range|address out of range)$' \
| wc -c) \
-eq 0 ]
then
@@ -61,7 +64,9 @@ check_all()
bt=$1
err=$2
testname=$3
check_main $bt $testname
if [ "x$4" != "x--allow-unknown" ]; then
check_main $bt $testname
fi
check_gsignal $bt $testname
check_err $err $testname
}
@@ -98,13 +103,14 @@ check_native_unsupported()
check_core()
{
arch=$1
args=$2
testfiles backtrace.$arch.{exec,core}
tempfiles backtrace.$arch.{bt,err}
echo ./backtrace ./backtrace.$arch.{exec,core}
testrun ${abs_builddir}/backtrace -e ./backtrace.$arch.exec --core=./backtrace.$arch.core 1>backtrace.$arch.bt 2>backtrace.$arch.err || true
testrun ${abs_builddir}/backtrace $args -e ./backtrace.$arch.exec --core=./backtrace.$arch.core 1>backtrace.$arch.bt 2>backtrace.$arch.err || true
cat backtrace.$arch.{bt,err}
check_unsupported backtrace.$arch.err backtrace.$arch.core
check_all backtrace.$arch.{bt,err} backtrace.$arch.core
check_all backtrace.$arch.{bt,err} backtrace.$arch.core $args
}
# Backtrace live process.
+22 -8
View File
@@ -64,6 +64,7 @@ dump_modules (Dwfl_Module *mod, void **userdata __attribute__ ((unused)),
return DWARF_CB_OK;
}
static bool allow_unknown;
static bool use_raise_jmp_patching;
static pid_t check_tid;
@@ -78,7 +79,8 @@ callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
seen_main = true;
if (pc == 0)
{
assert (seen_main);
if (!allow_unknown)
assert (seen_main);
return;
}
if (check_tid == 0)
@@ -103,11 +105,12 @@ callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
&& (strcmp (symname, "__kernel_vsyscall") == 0
|| strcmp (symname, "__libc_do_syscall") == 0))
reduce_frameno = true;
else
else if (!allow_unknown || symname)
assert (symname && strcmp (symname, "raise") == 0);
break;
case 1:
assert (symname != NULL && strcmp (symname, "sigusr2") == 0);
if (!allow_unknown || symname)
assert (symname != NULL && strcmp (symname, "sigusr2") == 0);
break;
case 2: // x86_64 only
/* __restore_rt - glibc maybe does not have to have this symbol. */
@@ -116,20 +119,24 @@ callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
if (use_raise_jmp_patching)
{
/* Verify we trapped on the very first instruction of jmp. */
assert (symname != NULL && strcmp (symname, "jmp") == 0);
if (!allow_unknown || symname)
assert (symname != NULL && strcmp (symname, "jmp") == 0);
mod = dwfl_addrmodule (dwfl, pc - 1);
if (mod)
symname2 = dwfl_module_addrname (mod, pc - 1);
assert (symname2 == NULL || strcmp (symname2, "jmp") != 0);
if (!allow_unknown || symname2)
assert (symname2 == NULL || strcmp (symname2, "jmp") != 0);
break;
}
/* FALLTHRU */
case 4:
assert (symname != NULL && strcmp (symname, "stdarg") == 0);
if (!allow_unknown || symname)
assert (symname != NULL && strcmp (symname, "stdarg") == 0);
break;
case 5:
/* Verify we trapped on the very last instruction of child. */
assert (symname != NULL && strcmp (symname, "backtracegen") == 0);
if (!allow_unknown || symname)
assert (symname != NULL && strcmp (symname, "backtracegen") == 0);
mod = dwfl_addrmodule (dwfl, pc);
if (mod)
symname2 = dwfl_module_addrname (mod, pc);
@@ -138,7 +145,7 @@ callback_verify (pid_t tid, unsigned frameno, Dwarf_Addr pc,
// there is no guarantee that the compiler doesn't reorder the
// instructions or even inserts some padding instructions at the end
// (which apparently happens on ppc64).
if (use_raise_jmp_patching)
if (use_raise_jmp_patching && (!allow_unknown || symname2))
assert (symname2 == NULL || strcmp (symname2, "backtracegen") != 0);
break;
}
@@ -424,10 +431,12 @@ exec_dump (const char *exec)
}
#define OPT_BACKTRACE_EXEC 0x100
#define OPT_ALLOW_UNKNOWN 0x200
static const struct argp_option options[] =
{
{ "backtrace-exec", OPT_BACKTRACE_EXEC, "EXEC", 0, N_("Run executable"), 0 },
{ "allow-unknown", OPT_ALLOW_UNKNOWN, 0, 0, N_("Allow unknown symbols"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
};
@@ -445,6 +454,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
exec_dump (arg);
exit (0);
case OPT_ALLOW_UNKNOWN:
allow_unknown = true;
break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -463,6 +476,7 @@ main (int argc __attribute__ ((unused)), char **argv)
(void) setlocale (LC_ALL, "");
elf_version (EV_CURRENT);
allow_unknown = false;
Dwfl *dwfl = NULL;
const struct argp_child argp_children[] =