From 53ca4118bdd3908092a53b6b4c59762a85b78dfc Mon Sep 17 00:00:00 2001 From: emekoi Date: Wed, 3 Jul 2019 10:16:52 -0500 Subject: [PATCH] added segfault handler support for windows --- std/debug.zig | 35 +++++++++++++++++++++++++++-------- std/os/windows/bits.zig | 22 ++++++++++++++++++++++ std/os/windows/kernel32.zig | 2 ++ std/special/start.zig | 21 ++++++++++++++------- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/std/debug.zig b/std/debug.zig index 6e6c171f45..c21e2126a7 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -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, + } +} diff --git a/std/os/windows/bits.zig b/std/os/windows/bits.zig index c99f3ae463..fe72a710eb 100644 --- a/std/os/windows/bits.zig +++ b/std/os/windows/bits.zig @@ -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; diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 27516342ac..494da90d72 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -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; diff --git a/std/special/start.zig b/std/special/start.zig index f2572def05..454c6166f9 100644 --- a/std/special/start.zig +++ b/std/special/start.zig @@ -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(); }