mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Add sigsegv stacktrace in test and regular errors for Darwin Arm64. #1105
This commit is contained in:
committed by
Christoffer Lerno
parent
a50de26c5d
commit
5b83108dd1
@@ -135,11 +135,14 @@ macro bool @typeis(#value, $Type) @const @builtin @deprecated("Use `$typeof(#val
|
||||
}
|
||||
|
||||
|
||||
fn bool print_backtrace(String message, int backtraces_to_ignore) @if (env::NATIVE_STACKTRACE) => @stack_mem(0x1100; Allocator smem)
|
||||
fn bool print_backtrace(String message, int backtraces_to_ignore, void *added_backtrace = null) @if (env::NATIVE_STACKTRACE) => @stack_mem(0x1100; Allocator smem)
|
||||
{
|
||||
void*[256] buffer;
|
||||
void*[] backtraces = backtrace::capture_current(&buffer);
|
||||
backtraces_to_ignore++;
|
||||
if (added_backtrace)
|
||||
{
|
||||
backtraces[++backtraces_to_ignore] = added_backtrace;
|
||||
}
|
||||
@stack_mem(2048; Allocator mem)
|
||||
{
|
||||
BacktraceList? backtrace = backtrace::symbolize_backtrace(mem, backtraces);
|
||||
@@ -941,23 +944,20 @@ macro void* get_returnaddress(int n)
|
||||
}
|
||||
|
||||
module std::core::builtin @if((env::LINUX || env::ANDROID || env::DARWIN) && env::COMPILER_SAFE_MODE && env::DEBUG_SYMBOLS);
|
||||
import libc, std::io;
|
||||
import libc, std::io, std::os::posix;
|
||||
|
||||
fn void sig_panic(String message)
|
||||
{
|
||||
default_panic(message, "???", "???", 0);
|
||||
}
|
||||
|
||||
SignalFunction old_bus_error;
|
||||
SignalFunction old_segmentation_fault;
|
||||
|
||||
fn void sig_bus_error(CInt i)
|
||||
fn void sig_bus_error(CInt i, void* info, void* context)
|
||||
{
|
||||
$if !env::NATIVE_STACKTRACE:
|
||||
sig_panic("Illegal memory access.");
|
||||
$else
|
||||
$if $defined(io::stderr):
|
||||
if (!print_backtrace("Illegal memory access.", 1))
|
||||
if (!print_backtrace("Illegal memory access.", 2, posix::stack_instruction(context)))
|
||||
{
|
||||
io::eprintn("\nERROR: 'Illegal memory access'.");
|
||||
}
|
||||
@@ -966,13 +966,13 @@ fn void sig_bus_error(CInt i)
|
||||
$$trap();
|
||||
}
|
||||
|
||||
fn void sig_segmentation_fault(CInt i)
|
||||
fn void sig_segmentation_fault(CInt i, void* p1, void* context)
|
||||
{
|
||||
$if !env::NATIVE_STACKTRACE:
|
||||
sig_panic("Out of bounds memory access.");
|
||||
$else
|
||||
$if $defined(io::stderr):
|
||||
if (!print_backtrace("Out of bounds memory access.", 1))
|
||||
if (!print_backtrace("Out of bounds memory access.", 2, posix::stack_instruction(context)))
|
||||
{
|
||||
io::eprintn("\nERROR: Memory error without backtrace, possible stack overflow.");
|
||||
}
|
||||
@@ -981,17 +981,12 @@ fn void sig_segmentation_fault(CInt i)
|
||||
$$trap();
|
||||
}
|
||||
|
||||
fn void install_signal_handler(CInt signal, SignalFunction func) @local
|
||||
{
|
||||
SignalFunction old = libc::signal(signal, func);
|
||||
// Restore
|
||||
if ((iptr)old > 1024) libc::signal(signal, old);
|
||||
}
|
||||
|
||||
|
||||
// Clean this up
|
||||
fn void install_signal_handlers() @init(101) @local @if(env::BACKTRACE)
|
||||
{
|
||||
install_signal_handler(libc::SIGBUS, &sig_bus_error);
|
||||
install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
|
||||
posix::install_signal_handler(libc::SIGBUS, &sig_bus_error);
|
||||
posix::install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
module std::core::runtime;
|
||||
import std::core::test @public;
|
||||
import std::core::mem::allocator @public;
|
||||
import libc, std::time, std::io, std::sort;
|
||||
import std::os::env;
|
||||
import libc, std::time, std::io, std::sort, std::os;
|
||||
|
||||
|
||||
alias TestFn = fn void();
|
||||
|
||||
@@ -86,17 +86,21 @@ fn bool terminal_has_ansi_codes() @local => @pool()
|
||||
$endif
|
||||
}
|
||||
|
||||
fn void sig_bus_error(CInt i) @local
|
||||
fn void sig_bus_error(CInt i, void*, void* context) @local @if(env::POSIX)
|
||||
{
|
||||
test_panic("Bus error", "Unknown", "Unknown", 0);
|
||||
panic_test("Bus error", "Unknown", "Unknown", 1, posix::stack_instruction(context));
|
||||
}
|
||||
|
||||
fn void sig_segmentation_fault(CInt i) @local
|
||||
fn void sig_segmentation_fault(CInt i, void*, void* context) @local @if(env::POSIX)
|
||||
{
|
||||
test_panic("Segmentation fault", "Unknown", "Unknown", 0);
|
||||
panic_test("Segmentation fault", "Unknown", "Unknown", 1, posix::stack_instruction(context));
|
||||
}
|
||||
|
||||
fn void test_panic(String message, String file, String function, uint line) @local
|
||||
{
|
||||
panic_test(message, file, function, line);
|
||||
}
|
||||
fn void panic_test(String message, String file, String function, uint line, void* extra_trace = null) @local
|
||||
{
|
||||
if (test_context.is_in_panic) return;
|
||||
test_context.is_in_panic = true;
|
||||
@@ -106,7 +110,7 @@ fn void test_panic(String message, String file, String function, uint line) @loc
|
||||
if (test_context.assert_print_backtrace)
|
||||
{
|
||||
$if env::NATIVE_STACKTRACE:
|
||||
builtin::print_backtrace(message, 0);
|
||||
builtin::print_backtrace(message, extra_trace ? 3 : 0, extra_trace);
|
||||
$endif
|
||||
}
|
||||
io::printf("\nTest failed ^^^ ( %s:%s ) %s\n", file, line, message);
|
||||
@@ -186,9 +190,9 @@ fn bool run_tests(String[] args, TestUnit[] tests) @private
|
||||
io::printn("There are no test units to run.");
|
||||
return true; // no tests == technically a pass
|
||||
}
|
||||
$if !env::NO_LIBC:
|
||||
libc::signal(libc::SIGBUS, &sig_bus_error);
|
||||
libc::signal(libc::SIGSEGV, &sig_segmentation_fault);
|
||||
$if !env::NO_LIBC && env::POSIX:
|
||||
posix::install_signal_handler(libc::SIGBUS, &sig_bus_error);
|
||||
posix::install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault);
|
||||
$endif
|
||||
foreach (&unit : tests)
|
||||
{
|
||||
|
||||
44
lib/std/os/macos/process.c3
Normal file
44
lib/std/os/macos/process.c3
Normal file
@@ -0,0 +1,44 @@
|
||||
module std::os::darwin @if(env::DARWIN);
|
||||
|
||||
alias __Darwin_sigset_t = uint;
|
||||
alias __Darwin_size_t = usz;
|
||||
|
||||
struct __Darwin_arm_exception_state64
|
||||
{
|
||||
ulong __far; /* Virtual Fault Address */
|
||||
uint __esr; /* Exception syndrome */
|
||||
uint __exception; /* number of arm exception taken */
|
||||
}
|
||||
|
||||
struct __Darwin_arm_thread_state64
|
||||
{
|
||||
ulong[29] __x; /* General purpose registers x0-x28 */
|
||||
ulong __fp; /* Frame pointer x29 */
|
||||
ulong __lr; /* Link register x30 */
|
||||
ulong __sp; /* Stack pointer x31 */
|
||||
ulong __pc; /* Program counter */
|
||||
ulong __cpsr; /* Current program status register */
|
||||
ulong __pad; /* Same size for 32-bit or 64-bit clients */
|
||||
}
|
||||
|
||||
struct __Darwin_arm_neon_state64
|
||||
{
|
||||
uint128[32] __v;
|
||||
uint __fpsr;
|
||||
uint __fpcr;
|
||||
}
|
||||
|
||||
struct __Darwin_mcontext64
|
||||
{
|
||||
__Darwin_arm_exception_state64 __es;
|
||||
__Darwin_arm_thread_state64 __ss;
|
||||
__Darwin_arm_neon_state64 __ns;
|
||||
}
|
||||
|
||||
struct __Darwin_sigaltstack
|
||||
{
|
||||
void* ss_sp; /* signal stack base */
|
||||
__Darwin_size_t ss_size; /* signal stack length */
|
||||
int ss_flags; /* SA_DISABLE and/or SA_ONSTACK */
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::os::posix @if(env::POSIX);
|
||||
import libc;
|
||||
import libc, std::os::darwin;
|
||||
|
||||
struct Posix_spawn_file_actions_t
|
||||
{
|
||||
@@ -60,6 +60,15 @@ alias BacktraceFn = fn CInt(void** buffer, CInt size);
|
||||
|
||||
extern fn CInt backtrace(void** buffer, CInt size) @if(env::OPENBSD);
|
||||
|
||||
fn void install_signal_handler(CInt signal, SigActionFunction func)
|
||||
{
|
||||
Sigaction action = {
|
||||
.sa_sigaction = func,
|
||||
};
|
||||
Sigaction old;
|
||||
libc::sigaction(signal, &action, &old);
|
||||
}
|
||||
|
||||
fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD)
|
||||
{
|
||||
if (size < 1) return 0;
|
||||
@@ -75,12 +84,13 @@ fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD)
|
||||
}
|
||||
// Loop through the return addresses until we hit a signal.
|
||||
// This avoids using the frame address.
|
||||
SignalFunction restore_backtrace = fn void(CInt) {
|
||||
libc::longjmp(&backtrace_jmpbuf, 1);
|
||||
};
|
||||
SignalFunction sig_bus = libc::signal(libc::SIGBUS, restore_backtrace);
|
||||
SignalFunction sig_segv = libc::signal(libc::SIGSEGV, restore_backtrace);
|
||||
SignalFunction sig_ill = libc::signal(libc::SIGILL, restore_backtrace);
|
||||
Sigaction restore_backtrace = {
|
||||
.sa_sigaction = fn void(CInt, void*, void*) { libc::longjmp(&backtrace_jmpbuf, 1); },
|
||||
};
|
||||
Sigaction sig_bus, sig_segv, sig_ill;
|
||||
libc::sigaction(libc::SIGBUS, &restore_backtrace, &sig_bus);
|
||||
libc::sigaction(libc::SIGSEGV, &restore_backtrace, &sig_segv);
|
||||
libc::sigaction(libc::SIGILL, &restore_backtrace, &sig_ill);
|
||||
|
||||
void*[128] buffer_first;
|
||||
int i = 0;
|
||||
@@ -90,8 +100,47 @@ fn CInt backtrace(void** buffer, CInt size) @if(!env::OPENBSD)
|
||||
buffer[i] = builtin::get_returnaddress(i);
|
||||
if (!buffer[i]) break;
|
||||
}
|
||||
libc::signal(libc::SIGBUS, sig_bus);
|
||||
libc::signal(libc::SIGSEGV, sig_segv);
|
||||
libc::signal(libc::SIGILL, sig_ill);
|
||||
|
||||
Sigaction old;
|
||||
libc::sigaction(libc::SIGBUS, &sig_bus, &old);
|
||||
libc::sigaction(libc::SIGSEGV, &sig_segv, &old);
|
||||
libc::sigaction(libc::SIGILL, &sig_ill, &old);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
struct PosixUContext_t @if(env::DARWIN)
|
||||
{
|
||||
int uc_onstack;
|
||||
__Darwin_sigset_t uc_sigmask; /* signal mask used by this context */
|
||||
__Darwin_sigaltstack uc_stack; /* stack used by this context */
|
||||
PosixUContext_t* uc_link; /* pointer to resuming context */
|
||||
__Darwin_size_t uc_mcsize; /* size of the machine context passed in */
|
||||
__Darwin_mcontext64* uc_mcontext; /* pointer to machine specific context */
|
||||
}
|
||||
|
||||
alias PosixUContext_t @if(!env::DARWIN) = void;
|
||||
|
||||
macro void* stack_instruction(PosixUContext_t* uc)
|
||||
{
|
||||
$switch:
|
||||
$case env::DARWIN && env::AARCH64:
|
||||
return (void*)uc.uc_mcontext.__ss.__pc + 1;
|
||||
/* $case env::DARWIN && env::X86_64:
|
||||
return uc.uc_mcontext.__ss.__rip;
|
||||
$case env::LINUX && env::X86:
|
||||
return uc.uc_mcontext.gregs[REG_EIP];
|
||||
$case env::LINUX && env::X86_64:
|
||||
return uc.uc_mcontext.gregs[REG_RIP];
|
||||
$case env::LINUX && env::AARCH64:
|
||||
return uc.uc_mcontext.pc;
|
||||
$case env::FREEBSD && env::X86_64:
|
||||
return uc.uc_mcontext.mc_rip;
|
||||
$case env::OPENBSD && env::X86_64:
|
||||
return uc.sc_rip;
|
||||
$case env::NETBSD:
|
||||
uc.uc_mcontext.__gregs[_REG_RIP];*/
|
||||
$default:
|
||||
return null;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user