LibC: Cleanup backtrace code

This commit is contained in:
2026-07-07 04:44:44 +03:00
parent 7b4b5a3440
commit b62687f5e7

View File

@@ -31,9 +31,9 @@ struct init_funcs_t
extern "C" char** environ;
#define DUMP_BACKTRACE 1
#define DUMP_BACKTRACE 0
#define DEMANGLE_BACKTRACE 0
#define BACKTRACE_SIGNALS(X) X(SIGABRT) X(SIGBUS) X(SIGFPE) X(SIGILL) X(SIGSEGV)
#if DEMANGLE_BACKTRACE
#include <cxxabi.h>
@@ -50,7 +50,7 @@ __attribute__((noreturn))
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)
{
@@ -87,15 +87,38 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t
sigemptyset(&ss);
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_flags = SA_RESETHAND | SA_SIGINFO,
};
sigaction(SIGBUS, &sa, nullptr);
sigaction(SIGFPE, &sa, nullptr);
sigaction(SIGILL, &sa, nullptr);
sigaction(SIGSEGV, &sa, nullptr);
#define BACKTRACE_SIGNAL_INSTALL(sig) sigaction(sig, &sa, nullptr);
BACKTRACE_SIGNALS(BACKTRACE_SIGNAL_INSTALL)
#undef BACKTRACE_SIGNAL_INSTALL
}
// call global constructors
@@ -151,40 +174,14 @@ static void __dump_symbol(int fd, const void* address)
#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__)
const uintptr_t stack_base = ucontext->uc_mcontext.gregs[REG_RBP];
const uintptr_t instruction = ucontext->uc_mcontext.gregs[REG_RIP];
const uintptr_t stack_base = mcontext->gregs[REG_RBP];
const uintptr_t instruction = mcontext->gregs[REG_RIP];
#elif defined(__i686__)
const uintptr_t stack_base = ucontext->uc_mcontext.gregs[REG_EBP];
const uintptr_t instruction = ucontext->uc_mcontext.gregs[REG_EIP];
const uintptr_t stack_base = mcontext->gregs[REG_EBP];
const uintptr_t instruction = mcontext->gregs[REG_EIP];
#endif
struct stackframe
@@ -201,10 +198,6 @@ static void __dump_backtrace(int sig, siginfo_t*, void* context)
__dump_symbol(fd, stackframe->ip);
stackframe = stackframe->bp;
}
close(fd);
raise(sig);
}
void _exit(int status)