Skip to content

Instantly share code, notes, and snippets.

@JCash
Last active December 29, 2020 18:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JCash/95f3d3aee4b626a4ee0499a3503ad303 to your computer and use it in GitHub Desktop.
Save JCash/95f3d3aee4b626a4ee0499a3503ad303 to your computer and use it in GitHub Desktop.
signal handler + test cases (gcc -g test.c) (testing on macOS)

build

$ gcc -g test.c

Types of crashes:

  • TEST_ABORT=1 (calls assert(false))
  • TEST_SEGV=1 (generates a segv)
  • (no test type) (just generates a callstack())

Types of backends:

  • TEST_UNW - libunwind
  • TEST_UNW_BACKTRACE - unwind
  • TEST_BACKTRACE - execinfo/backtrace()

Examples:

$ TEST_ABORT=1 TEST_UNW=1 ./a.out

$ TEST_ABORT=1 TEST_BACKTRACE=1 ./a.out

#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <unwind.h>
#include <execinfo.h>
static const int SIGNAL_MAX = 64;
// This array contains the default behavior for each signal.
static struct sigaction sigdfl[SIGNAL_MAX];
// Call this function to get a backtrace.
void unwind(unw_context_t* ctx) {
unw_cursor_t cursor;
unw_context_t context;
// Initialize cursor to current frame for local unwinding.
if (ctx == 0)
{
unw_getcontext(&context);
unw_init_local(&cursor, &context);
} else
{
unw_init_local(&cursor, ctx);
}
// Unwind frames one by one, going up the frame stack.
while (unw_step(&cursor) > 0) {
unw_word_t offset, pc;
unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (pc == 0) {
break;
}
printf("0x%llx:", pc);
char sym[256];
if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
printf(" (%s+0x%llx)\n", sym, offset);
} else {
printf(" -- error: unable to obtain symbol name for this frame\n");
}
}
}
void backtrace_execinfo()
{
const int maxptrs = 32;
void* ptrs[maxptrs];
int ptrcount = backtrace(ptrs, maxptrs);
char** stacktrace = backtrace_symbols(ptrs, ptrcount);
for (uint32_t i = 0; i < ptrcount; ++i)
{
printf("%p: %s\n", ptrs[i], stacktrace[i]);
}
}
static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) {
uintptr_t pc = _Unwind_GetIP(context);
if (pc) {
printf("unwind got pc ... %p\n", (void*)pc);
}
return _URC_NO_REASON;
}
ssize_t unwind_backtrace() {
_Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, 0);
return rc == _URC_END_OF_STACK ? 0 : -1;
}
// ************************************************************************************************************************
// ************************************************************************************************************************
// ************************************************************************************************************************
void do_backtrace(void* ctx)
{
if (getenv("TEST_UNW") != 0)
unwind(ctx);
if (getenv("TEST_UNW_BACKTRACE") != 0)
unwind_backtrace();
if (getenv("TEST_BACKTRACE") != 0)
backtrace_execinfo();
}
void foo() {
if (getenv("TEST_ABORT") != 0)
{
printf("ABORT\n");
assert(0 && "Make some noise!");
}
if (getenv("TEST_SEGV") != 0)
{
printf("SEGV\n");
int* i = 0;
*i = 18;
}
printf("BACKTRACE\n");
do_backtrace(0);
}
void bar() {
foo();
}
static void Handler(const int signum, siginfo_t *const si, void *const sc)
{
// The previous (default) behavior is restored for the signal.
// Unless this is done first thing in the signal handler we'll
// be stuck in a signal-handler loop forever.
ucontext_t* ctx = 0;//(ucontext_t*)sc;
sigaction(signum, &sigdfl[signum], NULL);
do_backtrace(ctx);
}
void InstallOnSignal(int signum)
{
//assert(signum >= 0 && signum < SIGNAL_MAX);
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = Handler;
sa.sa_flags = SA_SIGINFO;
// The current (default) behavior is stored in sigdfl.
sigaction(signum, &sa, &sigdfl[signum]);
}
void InstallHandler()
{
InstallOnSignal(SIGSEGV);
InstallOnSignal(SIGBUS);
InstallOnSignal(SIGTRAP);
InstallOnSignal(SIGILL);
InstallOnSignal(SIGABRT);
}
int main(int argc, char **argv) {
InstallHandler();
bar();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment