Merge pull request #4319 from Rocknest/windows-traces

Bring windows segfault handler on par with linux
master
Andrew Kelley 2020-01-30 09:26:39 -05:00 committed by GitHub
commit 0303e7bd8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 258 additions and 8 deletions

View File

@ -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)

View File

@ -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;