diff --git a/common/debug.c b/common/debug.c index febedfe84..dc6e70ecf 100644 --- a/common/debug.c +++ b/common/debug.c @@ -1,16 +1,62 @@ +#include +#include #include #include #include +#include +#include #include #include #include #include +static struct backtrace_state *backtrace_state; + +static int backtrace_status(void *unused, uintptr_t pc, + const char *filename, int lineno, + const char *function) +{ + status_trace("backtrace: %s:%u (%s) %p", + filename, lineno, function, (void *)pc); + return 0; +} + +static void crashdump(int sig) +{ + /* We do stderr first, since it's most reliable. */ + warnx("Fatal signal %u", sig); + backtrace_print(backtrace_state, 0, stderr); + + /* Now send to parent. */ + backtrace_full(backtrace_state, 0, backtrace_status, NULL, NULL); + status_failed(STATUS_FAIL_INTERNAL_ERROR, "FATAL SIGNAL %u", sig); +} + +static void crashlog_activate(void) +{ + struct sigaction sa; + + sa.sa_handler = crashdump; + sigemptyset(&sa.sa_mask); + + /* We want to fall through to default handler */ + sa.sa_flags = SA_RESETHAND; + sigaction(SIGILL, &sa, NULL); + sigaction(SIGABRT, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); +} + void subdaemon_debug(int argc, char *argv[]) { int i; bool printed = false; + err_set_progname(argv[0]); + backtrace_state = backtrace_create_state(argv[0], 0, NULL, NULL); + crashlog_activate(); + for (i = 1; i < argc; i++) { if (strstarts(argv[i], "--dev-disconnect=")) { dev_disconnect_init(atoi(argv[i]