| author | |
| committer | |
| log | 53ca4118bdd3908092a53b6b4c59762a85b78dfc |
| tree | 62dfc2d29502bb0eb259903c19cc9c354c17bae1 |
| parent | a1359ac3abbb83f30719f596180f1e923da3a8f2 |
4 files changed, 65 insertions(+), 15 deletions(-)
std/debug.zig+27-8| ... | ... | @@ -2311,23 +2311,31 @@ fn getDebugInfoAllocator() *mem.Allocator { |
| 2311 | 2311 | } |
| 2312 | 2312 | |
| 2313 | 2313 | /// Whether or not the current target can print useful debug information when a segfault occurs. |
| 2314 | pub const have_segfault_handling_support = builtin.arch == .x86_64 and builtin.os == .linux; | |
| 2314 | pub const have_segfault_handling_support = (builtin.arch == .x86_64 and builtin.os == .linux) or builtin.os == .windows; | |
| 2315 | 2315 | |
| 2316 | 2316 | /// Attaches a global SIGSEGV handler which calls @panic("segmentation fault"); |
| 2317 | 2317 | pub fn attachSegfaultHandler() void { |
| 2318 | 2318 | if (!have_segfault_handling_support) { |
| 2319 | 2319 | @compileError("segfault handler not supported for this target"); |
| 2320 | 2320 | } |
| 2321 | var act = os.Sigaction{ | |
| 2322 | .sigaction = handleSegfault, | |
| 2323 | .mask = os.empty_sigset, | |
| 2324 | .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND), | |
| 2325 | }; | |
| 2321 | switch (builtin.os) { | |
| 2322 | .linux => { | |
| 2323 | var act = os.Sigaction{ | |
| 2324 | .sigaction = handleSegfaultLinux, | |
| 2325 | .mask = os.empty_sigset, | |
| 2326 | .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND), | |
| 2327 | }; | |
| 2326 | 2328 | |
| 2327 | os.sigaction(os.SIGSEGV, &act, null); | |
| 2329 | os.sigaction(os.SIGSEGV, &act, null); | |
| 2330 | }, | |
| 2331 | .windows => { | |
| 2332 | _ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); | |
| 2333 | }, | |
| 2334 | else => unreachable, | |
| 2335 | } | |
| 2328 | 2336 | } |
| 2329 | 2337 | |
| 2330 | extern fn handleSegfault(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn { | |
| 2338 | extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) noreturn { | |
| 2331 | 2339 | // Reset to the default handler so that if a segfault happens in this handler it will crash |
| 2332 | 2340 | // the process. Also when this handler returns, the original instruction will be repeated |
| 2333 | 2341 | // 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_ |
| 2350 | 2358 | // the segfault. So we simply abort here. |
| 2351 | 2359 | os.abort(); |
| 2352 | 2360 | } |
| 2361 | ||
| 2362 | stdcallcc fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) c_long { | |
| 2363 | const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress); | |
| 2364 | switch (info.ExceptionRecord.ExceptionCode) { | |
| 2365 | windows.EXCEPTION_DATATYPE_MISALIGNMENT => panicExtra(null, exception_address, "Unaligned Memory Access"), | |
| 2366 | windows.EXCEPTION_ACCESS_VIOLATION => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", info.ExceptionRecord.ExceptionInformation[1]), | |
| 2367 | windows.EXCEPTION_ILLEGAL_INSTRUCTION => panicExtra(null, exception_address, "Illegal Instruction"), | |
| 2368 | windows.EXCEPTION_STACK_OVERFLOW => panicExtra(null, exception_address, "Stack Overflow"), | |
| 2369 | else => return windows.EXCEPTION_CONTINUE_SEARCH, | |
| 2370 | } | |
| 2371 | } |
std/os/windows/bits.zig+22| ... | ... | @@ -539,3 +539,25 @@ pub const FORMAT_MESSAGE_FROM_STRING = 0x00000400; |
| 539 | 539 | pub const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; |
| 540 | 540 | pub const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; |
| 541 | 541 | pub const FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF; |
| 542 | ||
| 543 | pub const EXCEPTION_DATATYPE_MISALIGNMENT = 0x80000002; | |
| 544 | pub const EXCEPTION_ACCESS_VIOLATION = 0xc0000005; | |
| 545 | pub const EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d; | |
| 546 | pub const EXCEPTION_STACK_OVERFLOW = 0xc00000fd; | |
| 547 | pub const EXCEPTION_CONTINUE_SEARCH = 0; | |
| 548 | ||
| 549 | pub const EXCEPTION_RECORD = extern struct { | |
| 550 | ExceptionCode: u32, | |
| 551 | ExceptionFlags: u32, | |
| 552 | ExceptionRecord: *EXCEPTION_RECORD, | |
| 553 | ExceptionAddress: *c_void, | |
| 554 | NumberParameters: u32, | |
| 555 | ExceptionInformation: [15]usize, | |
| 556 | }; | |
| 557 | ||
| 558 | pub const EXCEPTION_POINTERS = extern struct { | |
| 559 | ExceptionRecord: *EXCEPTION_RECORD, | |
| 560 | ContextRecord: *c_void, | |
| 561 | }; | |
| 562 | ||
| 563 | pub const VECTORED_EXCEPTION_HANDLER = stdcallcc fn (ExceptionInfo: *EXCEPTION_POINTERS) c_long; |
std/os/windows/kernel32.zig+2| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | usingnamespace @import("bits.zig"); |
| 2 | 2 | |
| 3 | pub extern "kernel32" stdcallcc fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) ?*c_void; | |
| 4 | ||
| 3 | 5 | pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL; |
| 4 | 6 | |
| 5 | 7 | pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL; |
std/special/start.zig+14-7| ... | ... | @@ -24,6 +24,16 @@ comptime { |
| 24 | 24 | } |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | fn enableSegfaultHandler() void { | |
| 28 | const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) | |
| 29 | root.enable_segfault_handler | |
| 30 | else | |
| 31 | std.debug.runtime_safety and std.debug.have_segfault_handling_support; | |
| 32 | if (enable_segfault_handler) { | |
| 33 | std.debug.attachSegfaultHandler(); | |
| 34 | } | |
| 35 | } | |
| 36 | ||
| 27 | 37 | extern fn wasm_freestanding_start() void { |
| 28 | 38 | _ = callMain(); |
| 29 | 39 | } |
| ... | ... | @@ -61,6 +71,9 @@ extern fn WinMainCRTStartup() noreturn { |
| 61 | 71 | if (!builtin.single_threaded) { |
| 62 | 72 | _ = @import("start_windows_tls.zig"); |
| 63 | 73 | } |
| 74 | ||
| 75 | enableSegfaultHandler(); | |
| 76 | ||
| 64 | 77 | std.os.windows.kernel32.ExitProcess(callMain()); |
| 65 | 78 | } |
| 66 | 79 | |
| ... | ... | @@ -100,13 +113,7 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { |
| 100 | 113 | std.os.argv = argv[0..argc]; |
| 101 | 114 | std.os.environ = envp; |
| 102 | 115 | |
| 103 | const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) | |
| 104 | root.enable_segfault_handler | |
| 105 | else | |
| 106 | std.debug.runtime_safety and std.debug.have_segfault_handling_support; | |
| 107 | if (enable_segfault_handler) { | |
| 108 | std.debug.attachSegfaultHandler(); | |
| 109 | } | |
| 116 | enableSegfaultHandler(); | |
| 110 | 117 | |
| 111 | 118 | return callMain(); |
| 112 | 119 | } |