aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-01-30 09:26:39 -0500
committerGitHub <noreply@github.com>2020-01-30 09:26:39 -0500
commit0303e7bd8e4fb245b4dfae51c7c1e34a66e0855c (patch)
tree28721c76baf99b6c07bafe3a797073a43a112f2a /lib
parente77a102e24c351a56cdda5bad5a46dcd58101c23 (diff)
parenta5f18c2b2ae86126e0fd0cba67676ae68ba0f1df (diff)
downloadzig-0303e7bd8e4fb245b4dfae51c7c1e34a66e0855c.tar.gz
zig-0303e7bd8e4fb245b4dfae51c7c1e34a66e0855c.zip
Merge pull request #4319 from Rocknest/windows-traces
Bring windows segfault handler on par with linux
Diffstat (limited to 'lib')
-rw-r--r--lib/std/debug.zig37
-rw-r--r--lib/std/os/windows/bits.zig229
2 files changed, 258 insertions, 8 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index a5fd1a4712..28340fede2 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -131,6 +131,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
const tty_config = detectTTYConfig();
printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return;
const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*;
+ if (first_return_address == 0) return; // The whole call stack may be optimized out
printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return;
var it = StackIterator{
.first_addr = null,
@@ -325,6 +326,7 @@ pub const StackIterator = struct {
}
const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*;
+ if (return_address == 0) return null;
return return_address;
}
};
@@ -470,7 +472,7 @@ fn printSourceAtAddressWindows(
line_index += @sizeOf(pdb.LineNumberEntry);
const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
- if (relative_address <= vaddr_start) {
+ if (relative_address < vaddr_start) {
break;
}
}
@@ -2309,16 +2311,39 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_vo
}
fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.Stdcall) 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", .{}),
+ windows.EXCEPTION_DATATYPE_MISALIGNMENT => handleSegfaultWindowsExtra(info, 0, "Unaligned Memory Access"),
+ windows.EXCEPTION_ACCESS_VIOLATION => handleSegfaultWindowsExtra(info, 1, null),
+ windows.EXCEPTION_ILLEGAL_INSTRUCTION => handleSegfaultWindowsExtra(info, 2, null),
+ windows.EXCEPTION_STACK_OVERFLOW => handleSegfaultWindowsExtra(info, 0, "Stack Overflow"),
else => return windows.EXCEPTION_CONTINUE_SEARCH,
}
}
+// zig won't let me use an anon enum here https://github.com/ziglang/zig/issues/3707
+fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: u8, comptime format: ?[]const u8) noreturn {
+ const exception_address = @ptrToInt(info.ExceptionRecord.ExceptionAddress);
+ if (@hasDecl(windows, "CONTEXT")) {
+ const regs = info.ContextRecord.getRegs();
+ switch (msg) {
+ 0 => std.debug.warn("{}\n", .{format.?}),
+ 1 => std.debug.warn("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}),
+ 2 => std.debug.warn("Illegal instruction at address 0x{x}\n", .{regs.ip}),
+ else => unreachable,
+ }
+
+ dumpStackTraceFromBase(regs.bp, regs.ip);
+ os.abort();
+ } else {
+ switch (msg) {
+ 0 => panicExtra(null, exception_address, format.?, .{}),
+ 1 => panicExtra(null, exception_address, "Segmentation fault at address 0x{x}", .{info.ExceptionRecord.ExceptionInformation[1]}),
+ 2 => panicExtra(null, exception_address, "Illegal Instruction", .{}),
+ else => unreachable,
+ }
+ }
+}
+
pub fn dumpStackPointerAddr(prefix: []const u8) void {
const sp = asm (""
: [argc] "={rsp}" (-> usize)
diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig
index 328732e0c7..b184e68f62 100644
--- a/lib/std/os/windows/bits.zig
+++ b/lib/std/os/windows/bits.zig
@@ -23,7 +23,6 @@ pub const BOOL = c_int;
pub const BOOLEAN = BYTE;
pub const BYTE = u8;
pub const CHAR = u8;
-pub const DWORD = u32;
pub const FLOAT = f32;
pub const HANDLE = *c_void;
pub const HCRYPTPROV = ULONG_PTR;
@@ -52,6 +51,8 @@ pub const DWORD_PTR = ULONG_PTR;
pub const UNICODE = false;
pub const WCHAR = u16;
pub const WORD = u16;
+pub const DWORD = u32;
+pub const DWORD64 = u64;
pub const LARGE_INTEGER = i64;
pub const USHORT = u16;
pub const SHORT = i16;
@@ -887,9 +888,233 @@ pub const EXCEPTION_RECORD = extern struct {
ExceptionInformation: [15]usize,
};
+pub usingnamespace switch (builtin.arch) {
+ .i386 => struct {
+ pub const FLOATING_SAVE_AREA = extern struct {
+ ControlWord: DWORD,
+ StatusWord: DWORD,
+ TagWord: DWORD,
+ ErrorOffset: DWORD,
+ ErrorSelector: DWORD,
+ DataOffset: DWORD,
+ DataSelector: DWORD,
+ RegisterArea: [80]BYTE,
+ Cr0NpxState: DWORD,
+ };
+
+ pub const CONTEXT = extern struct {
+ ContextFlags: DWORD,
+ Dr0: DWORD,
+ Dr1: DWORD,
+ Dr2: DWORD,
+ Dr3: DWORD,
+ Dr6: DWORD,
+ Dr7: DWORD,
+ FloatSave: FLOATING_SAVE_AREA,
+ SegGs: DWORD,
+ SegFs: DWORD,
+ SegEs: DWORD,
+ SegDs: DWORD,
+ Edi: DWORD,
+ Esi: DWORD,
+ Ebx: DWORD,
+ Edx: DWORD,
+ Ecx: DWORD,
+ Eax: DWORD,
+ Ebp: DWORD,
+ Eip: DWORD,
+ SegCs: DWORD,
+ EFlags: DWORD,
+ Esp: DWORD,
+ SegSs: DWORD,
+ ExtendedRegisters: [512]BYTE,
+
+ pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} {
+ return .{.bp = ctx.Ebp, .ip = ctx.Eip};
+ }
+ };
+
+ pub const PCONTEXT = *CONTEXT;
+ },
+ .x86_64 => struct {
+ pub const M128A = extern struct {
+ Low: ULONGLONG,
+ High: LONGLONG,
+ };
+
+ pub const XMM_SAVE_AREA32 = extern struct {
+ ControlWord: WORD,
+ StatusWord: WORD,
+ TagWord: BYTE,
+ Reserved1: BYTE,
+ ErrorOpcode: WORD,
+ ErrorOffset: DWORD,
+ ErrorSelector: WORD,
+ Reserved2: WORD,
+ DataOffset: DWORD,
+ DataSelector: WORD,
+ Reserved3: WORD,
+ MxCsr: DWORD,
+ MxCsr_Mask: DWORD,
+ FloatRegisters: [8]M128A,
+ XmmRegisters: [16]M128A,
+ Reserved4: [96]BYTE,
+ };
+
+ pub const CONTEXT = extern struct {
+ P1Home: DWORD64,
+ P2Home: DWORD64,
+ P3Home: DWORD64,
+ P4Home: DWORD64,
+ P5Home: DWORD64,
+ P6Home: DWORD64,
+ ContextFlags: DWORD,
+ MxCsr: DWORD,
+ SegCs: WORD,
+ SegDs: WORD,
+ SegEs: WORD,
+ SegFs: WORD,
+ SegGs: WORD,
+ SegSs: WORD,
+ EFlags: DWORD,
+ Dr0: DWORD64,
+ Dr1: DWORD64,
+ Dr2: DWORD64,
+ Dr3: DWORD64,
+ Dr6: DWORD64,
+ Dr7: DWORD64,
+ Rax: DWORD64,
+ Rcx: DWORD64,
+ Rdx: DWORD64,
+ Rbx: DWORD64,
+ Rsp: DWORD64,
+ Rbp: DWORD64,
+ Rsi: DWORD64,
+ Rdi: DWORD64,
+ R8: DWORD64,
+ R9: DWORD64,
+ R10: DWORD64,
+ R11: DWORD64,
+ R12: DWORD64,
+ R13: DWORD64,
+ R14: DWORD64,
+ R15: DWORD64,
+ Rip: DWORD64,
+ DUMMYUNIONNAME: extern union {
+ FltSave: XMM_SAVE_AREA32,
+ FloatSave: XMM_SAVE_AREA32,
+ DUMMYSTRUCTNAME: extern struct {
+ Header: [2]M128A,
+ Legacy: [8]M128A,
+ Xmm0: M128A,
+ Xmm1: M128A,
+ Xmm2: M128A,
+ Xmm3: M128A,
+ Xmm4: M128A,
+ Xmm5: M128A,
+ Xmm6: M128A,
+ Xmm7: M128A,
+ Xmm8: M128A,
+ Xmm9: M128A,
+ Xmm10: M128A,
+ Xmm11: M128A,
+ Xmm12: M128A,
+ Xmm13: M128A,
+ Xmm14: M128A,
+ Xmm15: M128A,
+ },
+ },
+ VectorRegister: [26]M128A,
+ VectorControl: DWORD64,
+ DebugControl: DWORD64,
+ LastBranchToRip: DWORD64,
+ LastBranchFromRip: DWORD64,
+ LastExceptionToRip: DWORD64,
+ LastExceptionFromRip: DWORD64,
+
+ pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} {
+ return .{.bp = ctx.Rbp, .ip = ctx.Rip};
+ }
+ };
+
+ pub const PCONTEXT = *CONTEXT;
+ },
+ .aarch64 => struct {
+ pub const NEON128 = extern union {
+ DUMMYSTRUCTNAME: extern struct {
+ Low: ULONGLONG,
+ High: LONGLONG,
+ },
+ D: [2]f64,
+ S: [4]f32,
+ H: [8]WORD,
+ B: [16]BYTE,
+ };
+
+ pub const CONTEXT = extern struct {
+ ContextFlags: ULONG,
+ Cpsr: ULONG,
+ DUMMYUNIONNAME: extern union {
+ DUMMYSTRUCTNAME: extern struct {
+ X0: DWORD64,
+ X1: DWORD64,
+ X2: DWORD64,
+ X3: DWORD64,
+ X4: DWORD64,
+ X5: DWORD64,
+ X6: DWORD64,
+ X7: DWORD64,
+ X8: DWORD64,
+ X9: DWORD64,
+ X10: DWORD64,
+ X11: DWORD64,
+ X12: DWORD64,
+ X13: DWORD64,
+ X14: DWORD64,
+ X15: DWORD64,
+ X16: DWORD64,
+ X17: DWORD64,
+ X18: DWORD64,
+ X19: DWORD64,
+ X20: DWORD64,
+ X21: DWORD64,
+ X22: DWORD64,
+ X23: DWORD64,
+ X24: DWORD64,
+ X25: DWORD64,
+ X26: DWORD64,
+ X27: DWORD64,
+ X28: DWORD64,
+ Fp: DWORD64,
+ Lr: DWORD64,
+ },
+ X: [31]DWORD64,
+ },
+ Sp: DWORD64,
+ Pc: DWORD64,
+ V: [32]NEON128,
+ Fpcr: DWORD,
+ Fpsr: DWORD,
+ Bcr: [8]DWORD,
+ Bvr: [8]DWORD64,
+ Wcr: [2]DWORD,
+ Wvr: [2]DWORD64,
+
+ pub fn getRegs(ctx: *const CONTEXT) struct {bp: usize, ip: usize} {
+ return .{.bp = ctx.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Fp, .ip = ctx.Pc};
+ }
+ };
+
+ pub const PCONTEXT = *CONTEXT;
+ },
+ else => struct {
+ pub const PCONTEXT = *c_void;
+ },
+};
+
pub const EXCEPTION_POINTERS = extern struct {
ExceptionRecord: *EXCEPTION_RECORD,
- ContextRecord: *c_void,
+ ContextRecord: PCONTEXT,
};
pub const VECTORED_EXCEPTION_HANDLER = fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(.Stdcall) c_long;