| author | |
| committer | |
| log | 0303e7bd8e4fb245b4dfae51c7c1e34a66e0855c |
| tree | 28721c76baf99b6c07bafe3a797073a43a112f2a |
| parent | e77a102e24c351a56cdda5bad5a46dcd58101c23 |
| parent | a5f18c2b2ae86126e0fd0cba67676ae68ba0f1df |
| signature |
Bring windows segfault handler on par with linux 2 files changed, 258 insertions(+), 8 deletions(-)
lib/std/debug.zig+31-6| ... | @@ -131,6 +131,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { | ... | @@ -131,6 +131,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { |
| 131 | const tty_config = detectTTYConfig(); | 131 | const tty_config = detectTTYConfig(); |
| 132 | printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; | 132 | printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; |
| 133 | const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; | 133 | const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; |
| 134 | if (first_return_address == 0) return; // The whole call stack may be optimized out | ||
| 134 | printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return; | 135 | printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return; |
| 135 | var it = StackIterator{ | 136 | var it = StackIterator{ |
| 136 | .first_addr = null, | 137 | .first_addr = null, |
| ... | @@ -325,6 +326,7 @@ pub const StackIterator = struct { | ... | @@ -325,6 +326,7 @@ pub const StackIterator = struct { |
| 325 | } | 326 | } |
| 326 | 327 | ||
| 327 | const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*; | 328 | const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*; |
| 329 | if (return_address == 0) return null; | ||
| 328 | return return_address; | 330 | return return_address; |
| 329 | } | 331 | } |
| 330 | }; | 332 | }; |
| ... | @@ -470,7 +472,7 @@ fn printSourceAtAddressWindows( | ... | @@ -470,7 +472,7 @@ fn printSourceAtAddressWindows( |
| 470 | line_index += @sizeOf(pdb.LineNumberEntry); | 472 | line_index += @sizeOf(pdb.LineNumberEntry); |
| 471 | 473 | ||
| 472 | const vaddr_start = frag_vaddr_start + line_num_entry.Offset; | 474 | const vaddr_start = frag_vaddr_start + line_num_entry.Offset; |
| 473 | if (relative_address <= vaddr_start) { | 475 | if (relative_address < vaddr_start) { |
| 474 | break; | 476 | break; |
| 475 | } | 477 | } |
| 476 | } | 478 | } |
| ... | @@ -2309,16 +2311,39 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_vo | ... | @@ -2309,16 +2311,39 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_vo |
| 2309 | } | 2311 | } |
| 2310 | 2312 | ||
| 2311 | fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.Stdcall) c_long { | 2313 | fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.Stdcall) c_long { |
| 2312 | const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress); | ||
| 2313 | switch (info.ExceptionRecord.ExceptionCode) { | 2314 | switch (info.ExceptionRecord.ExceptionCode) { |
| 2314 | windows.EXCEPTION_DATATYPE_MISALIGNMENT => panicExtra(null, exception_address, "Unaligned Memory Access", .{}), | 2315 | windows.EXCEPTION_DATATYPE_MISALIGNMENT => handleSegfaultWindowsExtra(info, 0, "Unaligned Memory Access"), |
| 2315 | windows.EXCEPTION_ACCESS_VIOLATION => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", .{info.ExceptionRecord.ExceptionInformation[1]}), | 2316 | windows.EXCEPTION_ACCESS_VIOLATION => handleSegfaultWindowsExtra(info, 1, null), |
| 2316 | windows.EXCEPTION_ILLEGAL_INSTRUCTION => panicExtra(null, exception_address, "Illegal Instruction", .{}), | 2317 | windows.EXCEPTION_ILLEGAL_INSTRUCTION => handleSegfaultWindowsExtra(info, 2, null), |
| 2317 | windows.EXCEPTION_STACK_OVERFLOW => panicExtra(null, exception_address, "Stack Overflow", .{}), | 2318 | windows.EXCEPTION_STACK_OVERFLOW => handleSegfaultWindowsExtra(info, 0, "Stack Overflow"), |
| 2318 | else => return windows.EXCEPTION_CONTINUE_SEARCH, | 2319 | else => return windows.EXCEPTION_CONTINUE_SEARCH, |
| 2319 | } | 2320 | } |
| 2320 | } | 2321 | } |
| 2321 | 2322 | ||
| 2323 | // zig won't let me use an anon enum here https://github.com/ziglang/zig/issues/3707 | ||
| 2324 | fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u8, comptime format: ?[]const u8) noreturn { | ||
| 2325 | const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress); | ||
| 2326 | if (@hasDecl(windows, "CONTEXT")) { | ||
| 2327 | const regs = info.ContextRecord.getRegs(); | ||
| 2328 | switch (msg) { | ||
| 2329 | 0 => std.debug.warn("{}\n", .{format.?}), | ||
| 2330 | 1 => std.debug.warn("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), | ||
| 2331 | 2 => std.debug.warn("Illegal instruction at address 0x{x}\n", .{regs.ip}), | ||
| 2332 | else => unreachable, | ||
| 2333 | } | ||
| 2334 | |||
| 2335 | dumpStackTraceFromBase(regs.bp, regs.ip); | ||
| 2336 | os.abort(); | ||
| 2337 | } else { | ||
| 2338 | switch (msg) { | ||
| 2339 | 0 => panicExtra(null, exception_address, format.?, .{}), | ||
| 2340 | 1 => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", .{info.ExceptionRecord.ExceptionInformation[1]}), | ||
| 2341 | 2 => panicExtra(null, exception_address, "Illegal Instruction", .{}), | ||
| 2342 | else => unreachable, | ||
| 2343 | } | ||
| 2344 | } | ||
| 2345 | } | ||
| 2346 | |||
| 2322 | pub fn dumpStackPointerAddr(prefix: []const u8) void { | 2347 | pub fn dumpStackPointerAddr(prefix: []const u8) void { |
| 2323 | const sp = asm ("" | 2348 | const sp = asm ("" |
| 2324 | : [argc] "={rsp}" (-> usize) | 2349 | : [argc] "={rsp}" (-> usize) |
lib/std/os/windows/bits.zig+227-2| ... | @@ -23,7 +23,6 @@ pub const BOOL = c_int; | ... | @@ -23,7 +23,6 @@ pub const BOOL = c_int; |
| 23 | pub const BOOLEAN = BYTE; | 23 | pub const BOOLEAN = BYTE; |
| 24 | pub const BYTE = u8; | 24 | pub const BYTE = u8; |
| 25 | pub const CHAR = u8; | 25 | pub const CHAR = u8; |
| 26 | pub const DWORD = u32; | ||
| 27 | pub const FLOAT = f32; | 26 | pub const FLOAT = f32; |
| 28 | pub const HANDLE = *c_void; | 27 | pub const HANDLE = *c_void; |
| 29 | pub const HCRYPTPROV = ULONG_PTR; | 28 | pub const HCRYPTPROV = ULONG_PTR; |
| ... | @@ -52,6 +51,8 @@ pub const DWORD_PTR = ULONG_PTR; | ... | @@ -52,6 +51,8 @@ pub const DWORD_PTR = ULONG_PTR; |
| 52 | pub const UNICODE = false; | 51 | pub const UNICODE = false; |
| 53 | pub const WCHAR = u16; | 52 | pub const WCHAR = u16; |
| 54 | pub const WORD = u16; | 53 | pub const WORD = u16; |
| 54 | pub const DWORD = u32; | ||
| 55 | pub const DWORD64 = u64; | ||
| 55 | pub const LARGE_INTEGER = i64; | 56 | pub const LARGE_INTEGER = i64; |
| 56 | pub const USHORT = u16; | 57 | pub const USHORT = u16; |
| 57 | pub const SHORT = i16; | 58 | pub const SHORT = i16; |
| ... | @@ -887,9 +888,233 @@ pub const EXCEPTION_RECORD = extern struct { | ... | @@ -887,9 +888,233 @@ pub const EXCEPTION_RECORD = extern struct { |
| 887 | ExceptionInformation: [15]usize, | 888 | ExceptionInformation: [15]usize, |
| 888 | }; | 889 | }; |
| 889 | 890 | ||
| 891 | pub usingnamespace switch (builtin.arch) { | ||
| 892 | .i386 => struct { | ||
| 893 | pub const FLOATING_SAVE_AREA = extern struct { | ||
| 894 | ControlWord: DWORD, | ||
| 895 | StatusWord: DWORD, | ||
| 896 | TagWord: DWORD, | ||
| 897 | ErrorOffset: DWORD, | ||
| 898 | ErrorSelector: DWORD, | ||
| 899 | DataOffset: DWORD, | ||
| 900 | DataSelector: DWORD, | ||
| 901 | RegisterArea: [80]BYTE, | ||
| 902 | Cr0NpxState: DWORD, | ||
| 903 | }; | ||
| 904 | |||
| 905 | pub const CONTEXT = extern struct { | ||
| 906 | ContextFlags: DWORD, | ||
| 907 | Dr0: DWORD, | ||
| 908 | Dr1: DWORD, | ||
| 909 | Dr2: DWORD, | ||
| 910 | Dr3: DWORD, | ||
| 911 | Dr6: DWORD, | ||
| 912 | Dr7: DWORD, | ||
| 913 | FloatSave: FLOATING_SAVE_AREA, | ||
| 914 | SegGs: DWORD, | ||
| 915 | SegFs: DWORD, | ||
| 916 | SegEs: DWORD, | ||
| 917 | SegDs: DWORD, | ||
| 918 | Edi: DWORD, | ||
| 919 | Esi: DWORD, | ||
| 920 | Ebx: DWORD, | ||
| 921 | Edx: DWORD, | ||
| 922 | Ecx: DWORD, | ||
| 923 | Eax: DWORD, | ||
| 924 | Ebp: DWORD, | ||
| 925 | Eip: DWORD, | ||
| 926 | SegCs: DWORD, | ||
| 927 | EFlags: DWORD, | ||
| 928 | Esp: DWORD, | ||
| 929 | SegSs: DWORD, | ||
| 930 | ExtendedRegisters: [512]BYTE, | ||
| 931 | |||
| 932 | pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} { | ||
| 933 | return .{.bp = ctx.Ebp, .ip = ctx.Eip}; | ||
| 934 | } | ||
| 935 | }; | ||
| 936 | |||
| 937 | pub const PCONTEXT = *CONTEXT; | ||
| 938 | }, | ||
| 939 | .x86_64 => struct { | ||
| 940 | pub const M128A = extern struct { | ||
| 941 | Low: ULONGLONG, | ||
| 942 | High: LONGLONG, | ||
| 943 | }; | ||
| 944 | |||
| 945 | pub const XMM_SAVE_AREA32 = extern struct { | ||
| 946 | ControlWord: WORD, | ||
| 947 | StatusWord: WORD, | ||
| 948 | TagWord: BYTE, | ||
| 949 | Reserved1: BYTE, | ||
| 950 | ErrorOpcode: WORD, | ||
| 951 | ErrorOffset: DWORD, | ||
| 952 | ErrorSelector: WORD, | ||
| 953 | Reserved2: WORD, | ||
| 954 | DataOffset: DWORD, | ||
| 955 | DataSelector: WORD, | ||
| 956 | Reserved3: WORD, | ||
| 957 | MxCsr: DWORD, | ||
| 958 | MxCsr_Mask: DWORD, | ||
| 959 | FloatRegisters: [8]M128A, | ||
| 960 | XmmRegisters: [16]M128A, | ||
| 961 | Reserved4: [96]BYTE, | ||
| 962 | }; | ||
| 963 | |||
| 964 | pub const CONTEXT = extern struct { | ||
| 965 | P1Home: DWORD64, | ||
| 966 | P2Home: DWORD64, | ||
| 967 | P3Home: DWORD64, | ||
| 968 | P4Home: DWORD64, | ||
| 969 | P5Home: DWORD64, | ||
| 970 | P6Home: DWORD64, | ||
| 971 | ContextFlags: DWORD, | ||
| 972 | MxCsr: DWORD, | ||
| 973 | SegCs: WORD, | ||
| 974 | SegDs: WORD, | ||
| 975 | SegEs: WORD, | ||
| 976 | SegFs: WORD, | ||
| 977 | SegGs: WORD, | ||
| 978 | SegSs: WORD, | ||
| 979 | EFlags: DWORD, | ||
| 980 | Dr0: DWORD64, | ||
| 981 | Dr1: DWORD64, | ||
| 982 | Dr2: DWORD64, | ||
| 983 | Dr3: DWORD64, | ||
| 984 | Dr6: DWORD64, | ||
| 985 | Dr7: DWORD64, | ||
| 986 | Rax: DWORD64, | ||
| 987 | Rcx: DWORD64, | ||
| 988 | Rdx: DWORD64, | ||
| 989 | Rbx: DWORD64, | ||
| 990 | Rsp: DWORD64, | ||
| 991 | Rbp: DWORD64, | ||
| 992 | Rsi: DWORD64, | ||
| 993 | Rdi: DWORD64, | ||
| 994 | R8: DWORD64, | ||
| 995 | R9: DWORD64, | ||
| 996 | R10: DWORD64, | ||
| 997 | R11: DWORD64, | ||
| 998 | R12: DWORD64, | ||
| 999 | R13: DWORD64, | ||
| 1000 | R14: DWORD64, | ||
| 1001 | R15: DWORD64, | ||
| 1002 | Rip: DWORD64, | ||
| 1003 | DUMMYUNIONNAME: extern union { | ||
| 1004 | FltSave: XMM_SAVE_AREA32, | ||
| 1005 | FloatSave: XMM_SAVE_AREA32, | ||
| 1006 | DUMMYSTRUCTNAME: extern struct { | ||
| 1007 | Header: [2]M128A, | ||
| 1008 | Legacy: [8]M128A, | ||
| 1009 | Xmm0: M128A, | ||
| 1010 | Xmm1: M128A, | ||
| 1011 | Xmm2: M128A, | ||
| 1012 | Xmm3: M128A, | ||
| 1013 | Xmm4: M128A, | ||
| 1014 | Xmm5: M128A, | ||
| 1015 | Xmm6: M128A, | ||
| 1016 | Xmm7: M128A, | ||
| 1017 | Xmm8: M128A, | ||
| 1018 | Xmm9: M128A, | ||
| 1019 | Xmm10: M128A, | ||
| 1020 | Xmm11: M128A, | ||
| 1021 | Xmm12: M128A, | ||
| 1022 | Xmm13: M128A, | ||
| 1023 | Xmm14: M128A, | ||
| 1024 | Xmm15: M128A, | ||
| 1025 | }, | ||
| 1026 | }, | ||
| 1027 | VectorRegister: [26]M128A, | ||
| 1028 | VectorControl: DWORD64, | ||
| 1029 | DebugControl: DWORD64, | ||
| 1030 | LastBranchToRip: DWORD64, | ||
| 1031 | LastBranchFromRip: DWORD64, | ||
| 1032 | LastExceptionToRip: DWORD64, | ||
| 1033 | LastExceptionFromRip: DWORD64, | ||
| 1034 | |||
| 1035 | pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} { | ||
| 1036 | return .{.bp = ctx.Rbp, .ip = ctx.Rip}; | ||
| 1037 | } | ||
| 1038 | }; | ||
| 1039 | |||
| 1040 | pub const PCONTEXT = *CONTEXT; | ||
| 1041 | }, | ||
| 1042 | .aarch64 => struct { | ||
| 1043 | pub const NEON128 = extern union { | ||
| 1044 | DUMMYSTRUCTNAME: extern struct { | ||
| 1045 | Low: ULONGLONG, | ||
| 1046 | High: LONGLONG, | ||
| 1047 | }, | ||
| 1048 | D: [2]f64, | ||
| 1049 | S: [4]f32, | ||
| 1050 | H: [8]WORD, | ||
| 1051 | B: [16]BYTE, | ||
| 1052 | }; | ||
| 1053 | |||
| 1054 | pub const CONTEXT = extern struct { | ||
| 1055 | ContextFlags: ULONG, | ||
| 1056 | Cpsr: ULONG, | ||
| 1057 | DUMMYUNIONNAME: extern union { | ||
| 1058 | DUMMYSTRUCTNAME: extern struct { | ||
| 1059 | X0: DWORD64, | ||
| 1060 | X1: DWORD64, | ||
| 1061 | X2: DWORD64, | ||
| 1062 | X3: DWORD64, | ||
| 1063 | X4: DWORD64, | ||
| 1064 | X5: DWORD64, | ||
| 1065 | X6: DWORD64, | ||
| 1066 | X7: DWORD64, | ||
| 1067 | X8: DWORD64, | ||
| 1068 | X9: DWORD64, | ||
| 1069 | X10: DWORD64, | ||
| 1070 | X11: DWORD64, | ||
| 1071 | X12: DWORD64, | ||
| 1072 | X13: DWORD64, | ||
| 1073 | X14: DWORD64, | ||
| 1074 | X15: DWORD64, | ||
| 1075 | X16: DWORD64, | ||
| 1076 | X17: DWORD64, | ||
| 1077 | X18: DWORD64, | ||
| 1078 | X19: DWORD64, | ||
| 1079 | X20: DWORD64, | ||
| 1080 | X21: DWORD64, | ||
| 1081 | X22: DWORD64, | ||
| 1082 | X23: DWORD64, | ||
| 1083 | X24: DWORD64, | ||
| 1084 | X25: DWORD64, | ||
| 1085 | X26: DWORD64, | ||
| 1086 | X27: DWORD64, | ||
| 1087 | X28: DWORD64, | ||
| 1088 | Fp: DWORD64, | ||
| 1089 | Lr: DWORD64, | ||
| 1090 | }, | ||
| 1091 | X: [31]DWORD64, | ||
| 1092 | }, | ||
| 1093 | Sp: DWORD64, | ||
| 1094 | Pc: DWORD64, | ||
| 1095 | V: [32]NEON128, | ||
| 1096 | Fpcr: DWORD, | ||
| 1097 | Fpsr: DWORD, | ||
| 1098 | Bcr: [8]DWORD, | ||
| 1099 | Bvr: [8]DWORD64, | ||
| 1100 | Wcr: [2]DWORD, | ||
| 1101 | Wvr: [2]DWORD64, | ||
| 1102 | |||
| 1103 | pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} { | ||
| 1104 | return .{.bp = ctx.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Fp, .ip = ctx.Pc}; | ||
| 1105 | } | ||
| 1106 | }; | ||
| 1107 | |||
| 1108 | pub const PCONTEXT = *CONTEXT; | ||
| 1109 | }, | ||
| 1110 | else => struct { | ||
| 1111 | pub const PCONTEXT = *c_void; | ||
| 1112 | }, | ||
| 1113 | }; | ||
| 1114 | |||
| 890 | pub const EXCEPTION_POINTERS = extern struct { | 1115 | pub const EXCEPTION_POINTERS = extern struct { |
| 891 | ExceptionRecord: *EXCEPTION_RECORD, | 1116 | ExceptionRecord: *EXCEPTION_RECORD, |
| 892 | ContextRecord: *c_void, | 1117 | ContextRecord: PCONTEXT, |
| 893 | }; | 1118 | }; |
| 894 | 1119 | ||
| 895 | pub const VECTORED_EXCEPTION_HANDLER = fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(.Stdcall) c_long; | 1120 | pub const VECTORED_EXCEPTION_HANDLER = fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(.Stdcall) c_long; |