| 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,23 +2311,31 @@ fn getDebugInfoAllocator() *mem.Allocator { |
| 2311 | } | 2311 | } |
| 2312 | 2312 | ||
| 2313 | /// Whether or not the current target can print useful debug information when a segfault occurs. | 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 | /// Attaches a global SIGSEGV handler which calls @panic("segmentation fault"); | 2316 | /// Attaches a global SIGSEGV handler which calls @panic("segmentation fault"); |
| 2317 | pub fn attachSegfaultHandler() void { | 2317 | pub fn attachSegfaultHandler() void { |
| 2318 | if (!have_segfault_handling_support) { | 2318 | if (!have_segfault_handling_support) { |
| 2319 | @compileError("segfault handler not supported for this target"); | 2319 | @compileError("segfault handler not supported for this target"); |
| 2320 | } | 2320 | } |
| 2321 | var act = os.Sigaction{ | 2321 | switch (builtin.os) { |
| 2322 | .sigaction = handleSegfault, | 2322 | .linux => { |
| 2323 | .mask = os.empty_sigset, | 2323 | var act = os.Sigaction{ |
| 2324 | .flags = (os.SA_SIGINFO | os.SA_RESTART | os.SA_RESETHAND), | 2324 | .sigaction = handleSegfaultLinux, |
| 2325 | }; | 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 | // Reset to the default handler so that if a segfault happens in this handler it will crash | 2339 | // Reset to the default handler so that if a segfault happens in this handler it will crash |
| 2332 | // the process. Also when this handler returns, the original instruction will be repeated | 2340 | // the process. Also when this handler returns, the original instruction will be repeated |
| 2333 | // and the resulting segfault will crash the process rather than continually dump stack traces. | 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,3 +2358,14 @@ extern fn handleSegfault(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_ |
| 2350 | // the segfault. So we simply abort here. | 2358 | // the segfault. So we simply abort here. |
| 2351 | os.abort(); | 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,3 +539,25 @@ pub const FORMAT_MESSAGE_FROM_STRING = 0x00000400; |
| 539 | pub const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; | 539 | pub const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; |
| 540 | pub const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; | 540 | pub const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; |
| 541 | pub const FORMAT_MESSAGE_MAX_WIDTH_MASK = 0x000000FF; | 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,5 +1,7 @@ |
| 1 | usingnamespace @import("bits.zig"); | 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 | pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL; | 5 | pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL; |
| 4 | 6 | ||
| 5 | pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL; | 7 | pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL; |
std/special/start.zig+14-7| ... | @@ -24,6 +24,16 @@ comptime { | ... | @@ -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 | extern fn wasm_freestanding_start() void { | 37 | extern fn wasm_freestanding_start() void { |
| 28 | _ = callMain(); | 38 | _ = callMain(); |
| 29 | } | 39 | } |
| ... | @@ -61,6 +71,9 @@ extern fn WinMainCRTStartup() noreturn { | ... | @@ -61,6 +71,9 @@ extern fn WinMainCRTStartup() noreturn { |
| 61 | if (!builtin.single_threaded) { | 71 | if (!builtin.single_threaded) { |
| 62 | _ = @import("start_windows_tls.zig"); | 72 | _ = @import("start_windows_tls.zig"); |
| 63 | } | 73 | } |
| 74 | |||
| 75 | enableSegfaultHandler(); | ||
| 76 | |||
| 64 | std.os.windows.kernel32.ExitProcess(callMain()); | 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,13 +113,7 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { |
| 100 | std.os.argv = argv[0..argc]; | 113 | std.os.argv = argv[0..argc]; |
| 101 | std.os.environ = envp; | 114 | std.os.environ = envp; |
| 102 | 115 | ||
| 103 | const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler")) | 116 | enableSegfaultHandler(); |
| 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 | } | ||
| 110 | 117 | ||
| 111 | return callMain(); | 118 | return callMain(); |
| 112 | } | 119 | } |