Linux: implement signal stacktrace using SA_SIGINFO + sigaltstack (#2653)

* Linux: implement signal stacktrace using SA_SIGINFO + sigaltstack

Adds proper signal handlers for SIGSEGV/SIGBUS/SIGILL on Linux,
enables backtraces from signal context, and exits with correct POSIX
signal codes (128+signal). Fixes missing "signal stacktrace" support

Signed-off-by: Manuel Barrio Linares <mbarriolinares@gmail.com>

* defer libc::dlclose(handle);

Signed-off-by: Manuel Barrio Linares <mbarriolinares@gmail.com>

* fix double backtrace on panic

Signed-off-by: Manuel Barrio Linares <mbarriolinares@gmail.com>

* add guards for Linux X86_64

- remove comments
- uncomment MContext_t for Linux AARCH64

Signed-off-by: Manuel Barrio Linares <mbarriolinares@gmail.com>

* fix guards, missed in two places

Signed-off-by: Manuel Barrio Linares <mbarriolinares@gmail.com>

---------

Signed-off-by: Manuel Barrio Linares <mbarriolinares@gmail.com>
Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
Manu Linares
2025-12-19 23:07:23 -03:00
committed by GitHub
parent 85166bc706
commit d2f59c5b3f
3 changed files with 103 additions and 29 deletions

View File

@@ -208,6 +208,7 @@ fn bool print_backtrace(String message, int backtraces_to_ignore, void *added_ba
fn void default_panic(String message, String file, String function, uint line) @if(env::NATIVE_STACKTRACE)
{
in_panic = true;
$if $defined(io::stderr) && env::PANIC_MSG:
if (!print_backtrace(message, 2))
{
@@ -224,7 +225,7 @@ macro void abort(String string = "Unrecoverable error reached", ...) @format(0)
$$trap();
}
bool in_panic @local = false;
bool in_panic @private = false;
fn void default_panic(String message, String file, String function, uint line) @if (!env::NATIVE_STACKTRACE)
{
@@ -997,7 +998,7 @@ fn void sig_bus_error(CInt i, void* info, void* context)
}
$endif
$endif
$$trap();
os::fastexit(128 + i);
}
fn void sig_segmentation_fault(CInt i, void* p1, void* context)
@@ -1012,15 +1013,39 @@ fn void sig_segmentation_fault(CInt i, void* p1, void* context)
}
$endif
$endif
$$trap();
os::fastexit(128 + i);
}
fn void sig_illegal_instruction(CInt i, void* p1, void* context)
{
if (in_panic) os::fastexit(128 + i);
$if !env::NATIVE_STACKTRACE:
sig_panic("Illegal instruction.");
$else
$if $defined(io::stderr):
if (!print_backtrace("Illegal instruction.", 2, posix::stack_instruction(context)))
{
io::eprintn("\nERROR: Illegal instruction.");
}
$endif
$endif
os::fastexit(128 + i);
}
char[64 * 1024] sig_stack @local @if(env::BACKTRACE && env::LINUX);
// Clean this up
fn void install_signal_handlers() @init(101) @local @if(env::BACKTRACE)
{
$if env::LINUX:
Stack_t ss = {
.ss_sp = &sig_stack,
.ss_size = sig_stack.len
};
libc::sigaltstack(&ss, null);
$endif
posix::install_signal_handler(libc::SIGBUS, &sig_bus_error);
posix::install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
posix::install_signal_handler(libc::SIGILL, &sig_illegal_instruction);
}