LibC: Cleanup backtrace code
This commit is contained in:
@@ -31,9 +31,9 @@ struct init_funcs_t
|
|||||||
|
|
||||||
extern "C" char** environ;
|
extern "C" char** environ;
|
||||||
|
|
||||||
|
#define DUMP_BACKTRACE 0
|
||||||
#define DUMP_BACKTRACE 1
|
|
||||||
#define DEMANGLE_BACKTRACE 0
|
#define DEMANGLE_BACKTRACE 0
|
||||||
|
#define BACKTRACE_SIGNALS(X) X(SIGABRT) X(SIGBUS) X(SIGFPE) X(SIGILL) X(SIGSEGV)
|
||||||
|
|
||||||
#if DEMANGLE_BACKTRACE
|
#if DEMANGLE_BACKTRACE
|
||||||
#include <cxxabi.h>
|
#include <cxxabi.h>
|
||||||
@@ -50,7 +50,7 @@ __attribute__((noreturn))
|
|||||||
void __stack_chk_fail(void) { abort(); }
|
void __stack_chk_fail(void) { abort(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __dump_backtrace(int, siginfo_t*, void*);
|
static void __dump_backtrace(int fd, mcontext_t*);
|
||||||
|
|
||||||
extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t fini_funcs)
|
extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t fini_funcs)
|
||||||
{
|
{
|
||||||
@@ -87,15 +87,38 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t
|
|||||||
sigemptyset(&ss);
|
sigemptyset(&ss);
|
||||||
|
|
||||||
const struct sigaction sa {
|
const struct sigaction sa {
|
||||||
.sa_sigaction = __dump_backtrace,
|
.sa_sigaction = [](int sig, siginfo_t*, void* context) -> void {
|
||||||
|
constexpr auto signal_name = [](int signal) -> const char* {
|
||||||
|
switch (signal) {
|
||||||
|
#define BACKTRACE_SIGNAL_CASE(sig) case sig: return #sig;
|
||||||
|
BACKTRACE_SIGNALS(BACKTRACE_SIGNAL_CASE)
|
||||||
|
#undef BACKTRACE_SIGNAL_CASE
|
||||||
|
}
|
||||||
|
return "unknown signal";
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE: we cannot use stddbg as that is not async-signal-safe.
|
||||||
|
// POSIX says dprintf isn't either but our implementation is!
|
||||||
|
|
||||||
|
int fd = open("/dev/debug", O_WRONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
perror("open debug device");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dprintf(fd, "received signal %s, backtrace:\n", signal_name(sig));
|
||||||
|
__dump_backtrace(fd, &static_cast<ucontext_t*>(context)->uc_mcontext);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
raise(sig);
|
||||||
|
},
|
||||||
.sa_mask = ss,
|
.sa_mask = ss,
|
||||||
.sa_flags = SA_RESETHAND | SA_SIGINFO,
|
.sa_flags = SA_RESETHAND | SA_SIGINFO,
|
||||||
};
|
};
|
||||||
|
|
||||||
sigaction(SIGBUS, &sa, nullptr);
|
#define BACKTRACE_SIGNAL_INSTALL(sig) sigaction(sig, &sa, nullptr);
|
||||||
sigaction(SIGFPE, &sa, nullptr);
|
BACKTRACE_SIGNALS(BACKTRACE_SIGNAL_INSTALL)
|
||||||
sigaction(SIGILL, &sa, nullptr);
|
#undef BACKTRACE_SIGNAL_INSTALL
|
||||||
sigaction(SIGSEGV, &sa, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// call global constructors
|
// call global constructors
|
||||||
@@ -151,40 +174,14 @@ static void __dump_symbol(int fd, const void* address)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __dump_backtrace(int sig, siginfo_t*, void* context)
|
static void __dump_backtrace(int fd, mcontext_t* mcontext)
|
||||||
{
|
{
|
||||||
constexpr auto signal_name =
|
|
||||||
[](int signal) -> const char*
|
|
||||||
{
|
|
||||||
switch (signal) {
|
|
||||||
case SIGABRT: return "SIGABRT";
|
|
||||||
case SIGBUS: return "SIGBUS";
|
|
||||||
case SIGFPE: return "SIGFPE";
|
|
||||||
case SIGILL: return "SIGILL";
|
|
||||||
case SIGSEGV: return "SIGSEGV";
|
|
||||||
}
|
|
||||||
return "unknown signal";
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE: we cannot use stddbg as that is not async-signal-safe.
|
|
||||||
// POSIX says dprintf isn't either but our implementation is!
|
|
||||||
|
|
||||||
int fd = open("/dev/debug", O_WRONLY);
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
perror("failed to open debug device for backtrace");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dprintf(fd, "received %s, backtrace:\n", signal_name(sig));
|
|
||||||
|
|
||||||
const auto* ucontext = static_cast<ucontext_t*>(context);
|
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
const uintptr_t stack_base = ucontext->uc_mcontext.gregs[REG_RBP];
|
const uintptr_t stack_base = mcontext->gregs[REG_RBP];
|
||||||
const uintptr_t instruction = ucontext->uc_mcontext.gregs[REG_RIP];
|
const uintptr_t instruction = mcontext->gregs[REG_RIP];
|
||||||
#elif defined(__i686__)
|
#elif defined(__i686__)
|
||||||
const uintptr_t stack_base = ucontext->uc_mcontext.gregs[REG_EBP];
|
const uintptr_t stack_base = mcontext->gregs[REG_EBP];
|
||||||
const uintptr_t instruction = ucontext->uc_mcontext.gregs[REG_EIP];
|
const uintptr_t instruction = mcontext->gregs[REG_EIP];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct stackframe
|
struct stackframe
|
||||||
@@ -201,10 +198,6 @@ static void __dump_backtrace(int sig, siginfo_t*, void* context)
|
|||||||
__dump_symbol(fd, stackframe->ip);
|
__dump_symbol(fd, stackframe->ip);
|
||||||
stackframe = stackframe->bp;
|
stackframe = stackframe->bp;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
raise(sig);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _exit(int status)
|
void _exit(int status)
|
||||||
|
|||||||
Reference in New Issue
Block a user