From 5e9d0d31df76cb9ca7b78d9de7c8f377a606c903 Mon Sep 17 00:00:00 2001 From: ex0dus-0x Date: Fri, 27 Dec 2019 10:44:13 -0500 Subject: [PATCH] Improve backtrace routine --- src/include/deepstate/DeepState.h | 62 ++++++++++++++++++++----------- src/lib/DeepState.c | 3 +- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index b531c92f..d16cd0ce 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -59,6 +59,10 @@ #define DEEPSTATE_SIZE 8192 #endif +#ifndef DEEPSTATE_CRASH_MAX_FRAMES +#define DEEPSTATE_CRASH_MAX_FRAMES 63 +#endif + #ifndef DEEPSTATE_MAX_SWARM_CONFIGS #define DEEPSTATE_MAX_SWARM_CONFIGS 1024 #endif @@ -524,21 +528,38 @@ extern void DeepState_SaveFailingTest(void); extern void DeepState_SaveCrashingTest(void); /* Emit test function backtrace after test crashes. */ -static void DeepState_EmitBacktrace(int signum, siginfo_t *sig, void *context) { +static void DeepState_EmitBacktrace(int signum, siginfo_t *sig, void *_context) { - DeepState_LogFormat(DeepState_LogInfo, "Test crashed with: %s", sys_siglist[sig->si_status]); + /* output information about the signal caught and the exception that occurred */ + const char *result; + if (!sig->si_status) + result = sys_siglist[signum]; + else + result = sys_siglist[sig->si_status]; + DeepState_LogFormat(DeepState_LogError, "Signal caught in test: %s (error: %d)", result, sig->si_signo); - void *array[10]; + /* return a backtrace */ size_t size; - char **strings; + void *back_addrs[DEEPSTATE_CRASH_MAX_FRAMES]; + char **symbols; - size = backtrace(array, 10); - strings = backtrace_symbols(array, size); + size = backtrace(back_addrs, DEEPSTATE_CRASH_MAX_FRAMES); + if (size == 0) + DeepState_Abandon("Cannot retrieve backtrace stack addresses"); + symbols = backtrace_symbols(back_addrs, size); + if (symbols == NULL) + DeepState_Abandon("Cannot retrieve symbols for stack addresses"); + + DeepState_LogFormat(DeepState_LogTrace, "======= Backtrace: ========="); for (size_t i = 0; i < size; i++) - DeepState_LogFormat(DeepState_LogTrace, "%s", strings[i]); + DeepState_LogFormat(DeepState_LogTrace, "%s", symbols[i]); + DeepState_LogFormat(DeepState_LogTrace, "==========================="); - free(strings); + /* cleanup resources and exit */ + free(symbols); + DeepState_CleanUp(); + exit(DeepState_TestRunCrash); } @@ -712,19 +733,6 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) { /* Fork and run `test`. */ static enum DeepState_TestRunResult DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { - - /* If flag is set, install a signal handler for SIGCHLD */ - /* TODO(alan): use handler as "multiplexer" and handle child signal */ - if (FLAGS_verbose_crash_trace) { - struct sigaction sigact, oldact; - - sigact.sa_flags = SA_SIGINFO | SA_NOCLDWAIT; - sigact.sa_sigaction = DeepState_EmitBacktrace; - - sigaction(SIGCHLD, &sigact, &oldact); - } - - pid_t test_pid; if (FLAGS_fork) { test_pid = fork(); @@ -737,6 +745,18 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { if (FLAGS_fork) { waitpid(test_pid, &wstatus, 0); } else { + + /* If flag is set, install a "multiplexed" signal handler + * in order to backtrace and cleanup without an abrupt exit. */ + if (FLAGS_verbose_crash_trace) { + struct sigaction sigact; + sigact.sa_flags = SA_SIGINFO; + sigact.sa_sigaction = DeepState_EmitBacktrace; + + for (int i = 0; i <= sizeof(sys_siglist); i++) + sigaction(i, &sigact, 0); + } + wstatus = DeepState_RunTestNoFork(test); DeepState_CleanUp(); } diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 5cbf281f..cb7161b4 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -43,9 +43,8 @@ DEFINE_bool(abort_on_fail, ExecutionGroup, false, "Abort on file replay failure DEFINE_bool(exit_on_fail, ExecutionGroup, false, "Exit with status 255 on test failure."); DEFINE_int(min_log_level, ExecutionGroup, 0, "Minimum level of logging to output (default 2, 0=debug, 1=trace, 2=info, ...)."); DEFINE_int(timeout, ExecutionGroup, 120, "Timeout for brute force fuzzing."); -DEFINE_uint(num_workers, ExecutionGroup, 1, "Number of workers to spawn for testing and test generation."); DEFINE_bool(verbose_reads, ExecutionGroup, false, "Report on bytes being read during execution of test."); -DEFINE_bool(verbose_crash_trace, ExecutionGroup, false, "If test crashes, report an execution backtrace after abrupt exit."); +DEFINE_bool(verbose_crash_trace, ExecutionGroup, false, "If unforked test crashes, report crash information and backtrace."); /* Fuzzing and symex related options, baked in to perform analysis-related tasks without auxiliary tools */ DEFINE_bool(fuzz, AnalysisGroup, false, "Perform brute force unguided fuzzing.");