added segfault handler support for windows

This commit is contained in:
emekoi 2019-07-03 10:16:52 -05:00 committed by Andrew Kelley
parent a1359ac3ab
commit 53ca4118bd
4 changed files with 65 additions and 15 deletions

View File

@ -2311,23 +2311,31 @@ fn getDebugInfoAllocator() *mem.Allocator {
}
/// Whether or not the current target can print useful debug information when a segfault occurs.
pub const have_segfault_handling_support = builtin.arch == .x86_64 and builtin.os == .linux;
pub const have_segfault_handling_support = (builtin.arch == .x86_64 and builtin.os == .linux) or builtin.os == .windows;
/// Attaches a global SIGSEGV handler which calls @panic("segmentation fault");
pub fn attachSegfaultHandler() void {
if (!have_segfault_handling_support) {
@compileError("segfault handler not supported for this target");
}
var act = os.Sigaction{
.sigaction = handleSegfault,
.mask = os.empty_sigset,
.flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND),
};
switch (builtin.os) {
.linux => {
var act = os.Sigaction{
.sigaction = handleSegfaultLinux,
.mask = os.empty_sigset,
.flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND),
};
os.sigaction(os.SIGSEGV, &act, null);
os.sigaction(os.SIGSEGV, &act, null);
},
.windows => {
_ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
},
else => unreachable,
}
}
extern fn handleSegfault(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn {
extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn {
// Reset to the default handler so that if a segfault happens in this handler it will crash
// the process. Also when this handler returns, the original instruction will be repeated
// and the resulting segfault will crash the process rather than continually dump stack traces.
@ -2350,3 +2358,14 @@ extern fn handleSegfault(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_
// the segfault. So we simply abort here.
os.abort();
}
stdcallcc fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) c_long {
const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress);
switch (info.ExceptionRecord.ExceptionCode) {
windows.EXCEPTION_DATATYPE_MISALIGNMENT => panicExtra(null, exception_address, "Unaligned Memory Access"),
windows.EXCEPTION_ACCESS_VIOLATION => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", info.ExceptionRecord.ExceptionInformation[1]),
windows.EXCEPTION_ILLEGAL_INSTRUCTION => panicExtra(null, exception_address, "Illegal Instruction"),
windows.EXCEPTION_STACK_OVERFLOW => panicExtra(null, exception_address, "Stack Overflow"),
else => return windows.EXCEPTION_CONTINUE_SEARCH,
}
}

View File

@ -539,3 +539,25 @@ pub const FORMAT_MESSAGE_FROM_STRING = 0x00000400;
pub const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
pub const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
pub const FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF;
pub const EXCEPTION_DATATYPE_MISALIGNMENT = 0x80000002;
pub const EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
pub const EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d;
pub const EXCEPTION_STACK_OVERFLOW = 0xc00000fd;
pub const EXCEPTION_CONTINUE_SEARCH = 0;
pub const EXCEPTION_RECORD = extern struct {
ExceptionCode: u32,
ExceptionFlags: u32,
ExceptionRecord: *EXCEPTION_RECORD,
ExceptionAddress: *c_void,
NumberParameters: u32,
ExceptionInformation: [15]usize,
};
pub const EXCEPTION_POINTERS = extern struct {
ExceptionRecord: *EXCEPTION_RECORD,
ContextRecord: *c_void,
};
pub const VECTORED_EXCEPTION_HANDLER = stdcallcc fn (ExceptionInfo: *EXCEPTION_POINTERS) c_long;

View File

@ -1,5 +1,7 @@
usingnamespace @import("bits.zig");
pub extern "kernel32" stdcallcc fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) ?*c_void;
pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;
pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;

View File

@ -24,6 +24,16 @@ comptime {
}
}
fn enableSegfaultHandler() void {
const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
root.enable_segfault_handler
else
std.debug.runtime_safety and std.debug.have_segfault_handling_support;
if (enable_segfault_handler) {
std.debug.attachSegfaultHandler();
}
}
extern fn wasm_freestanding_start() void {
_ = callMain();
}
@ -61,6 +71,9 @@ extern fn WinMainCRTStartup() noreturn {
if (!builtin.single_threaded) {
_ = @import("start_windows_tls.zig");
}
enableSegfaultHandler();
std.os.windows.kernel32.ExitProcess(callMain());
}
@ -100,13 +113,7 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
std.os.argv = argv[0..argc];
std.os.environ = envp;
const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
root.enable_segfault_handler
else
std.debug.runtime_safety and std.debug.have_segfault_handling_support;
if (enable_segfault_handler) {
std.debug.attachSegfaultHandler();
}
enableSegfaultHandler();
return callMain();
}