authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-01-04 14:54:49-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-04 14:54:49-05:00
log09ff03a57a9f2144f0d3e9b0173bac7035d3629b
treec498aa8f839458e5558f8344893579d16a5954ae
parenta3e2ee091139740d076da1176ac8c487ca20a9a6
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

debug: replace RtlCaptureStackBackTrace (which was spuriously failing) with a new implementation which uses RtlVirtualUnwind instead (#12740)

windows: add RtlCaptureContext, RtlLookupFunctionEntry, RtlVirtualUnwind and supporting types windows: fix alignment of CONTEXT structs to match winnt.h as required by RtlCaptureContext (fxsave instr) windows aarch64: fix __chkstk being defined twice if libc is not linked on msvc Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>

4 files changed, 211 insertions(+), 13 deletions(-)

lib/std/debug.zig+45-8
...@@ -206,17 +206,12 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT...@@ -206,17 +206,12 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT
206 if (native_os == .windows) {206 if (native_os == .windows) {
207 const addrs = stack_trace.instruction_addresses;207 const addrs = stack_trace.instruction_addresses;
208 const first_addr = first_address orelse {208 const first_addr = first_address orelse {
209 stack_trace.index = windows.ntdll.RtlCaptureStackBackTrace(209 stack_trace.index = walkStackWindows(addrs[0..]);
210 0,
211 @intCast(u32, addrs.len),
212 @ptrCast(**anyopaque, addrs.ptr),
213 null,
214 );
215 return;210 return;
216 };211 };
217 var addr_buf_stack: [32]usize = undefined;212 var addr_buf_stack: [32]usize = undefined;
218 const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;213 const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
219 const n = windows.ntdll.RtlCaptureStackBackTrace(0, @intCast(u32, addr_buf.len), @ptrCast(**anyopaque, addr_buf.ptr), null);214 const n = walkStackWindows(addr_buf[0..]);
220 const first_index = for (addr_buf[0..n]) |addr, i| {215 const first_index = for (addr_buf[0..n]) |addr, i| {
221 if (addr == first_addr) {216 if (addr == first_addr) {
222 break i;217 break i;
...@@ -573,6 +568,48 @@ pub fn writeCurrentStackTrace(...@@ -573,6 +568,48 @@ pub fn writeCurrentStackTrace(
573 }568 }
574}569}
575570
571pub noinline fn walkStackWindows(addresses: []usize) usize {
572 if (builtin.cpu.arch == .x86) {
573 // RtlVirtualUnwind doesn't exist on x86
574 return windows.ntdll.RtlCaptureStackBackTrace(0, addresses.len, @ptrCast(**anyopaque, addresses.ptr), null);
575 }
576
577 const tib = @ptrCast(*const windows.NT_TIB, &windows.teb().Reserved1);
578
579 var context: windows.CONTEXT = std.mem.zeroes(windows.CONTEXT);
580 windows.ntdll.RtlCaptureContext(&context);
581
582 var i: usize = 0;
583 var image_base: usize = undefined;
584 var history_table: windows.UNWIND_HISTORY_TABLE = std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);
585
586 while (i < addresses.len) : (i += 1) {
587 const current_regs = context.getRegs();
588 if (windows.ntdll.RtlLookupFunctionEntry(current_regs.ip, &image_base, &history_table)) |runtime_function| {
589 var handler_data: ?*anyopaque = null;
590 var establisher_frame: u64 = undefined;
591 _ = windows.ntdll.RtlVirtualUnwind(windows.UNW_FLAG_NHANDLER, image_base, current_regs.ip, runtime_function, &context, &handler_data, &establisher_frame, null);
592 } else {
593 // leaf function
594 context.setIp(@intToPtr(*u64, current_regs.sp).*);
595 context.setSp(current_regs.sp + @sizeOf(usize));
596 }
597
598 const next_regs = context.getRegs();
599 if (next_regs.sp < @ptrToInt(tib.StackLimit) or next_regs.sp > @ptrToInt(tib.StackBase)) {
600 break;
601 }
602
603 if (next_regs.ip == 0) {
604 break;
605 }
606
607 addresses[i] = next_regs.ip;
608 }
609
610 return i;
611}
612
576pub fn writeCurrentStackTraceWindows(613pub fn writeCurrentStackTraceWindows(
577 out_stream: anytype,614 out_stream: anytype,
578 debug_info: *DebugInfo,615 debug_info: *DebugInfo,
...@@ -580,7 +617,7 @@ pub fn writeCurrentStackTraceWindows(...@@ -580,7 +617,7 @@ pub fn writeCurrentStackTraceWindows(
580 start_addr: ?usize,617 start_addr: ?usize,
581) !void {618) !void {
582 var addr_buf: [1024]usize = undefined;619 var addr_buf: [1024]usize = undefined;
583 const n = windows.ntdll.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**anyopaque, &addr_buf), null);620 const n = walkStackWindows(addr_buf[0..]);
584 const addrs = addr_buf[0..n];621 const addrs = addr_buf[0..n];
585 var start_i: usize = if (start_addr) |saddr| blk: {622 var start_i: usize = if (start_addr) |saddr| blk: {
586 for (addrs) |addr, i| {623 for (addrs) |addr, i| {
lib/std/os/windows.zig+119-5
...@@ -31,6 +31,8 @@ pub const winmm = @import("windows/winmm.zig");...@@ -31,6 +31,8 @@ pub const winmm = @import("windows/winmm.zig");
3131
32pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize));32pub const self_process_handle = @intToPtr(HANDLE, maxInt(usize));
3333
34const Self = @This();
35
34pub const OpenError = error{36pub const OpenError = error{
35 IsDir,37 IsDir,
36 NotDir,38 NotDir,
...@@ -3282,7 +3284,7 @@ pub usingnamespace switch (native_arch) {...@@ -3282,7 +3284,7 @@ pub usingnamespace switch (native_arch) {
3282 };3284 };
32833285
3284 pub const CONTEXT = extern struct {3286 pub const CONTEXT = extern struct {
3285 P1Home: DWORD64,3287 P1Home: DWORD64 align(16),
3286 P2Home: DWORD64,3288 P2Home: DWORD64,
3287 P3Home: DWORD64,3289 P3Home: DWORD64,
3288 P4Home: DWORD64,3290 P4Home: DWORD64,
...@@ -3352,9 +3354,28 @@ pub usingnamespace switch (native_arch) {...@@ -3352,9 +3354,28 @@ pub usingnamespace switch (native_arch) {
3352 LastExceptionToRip: DWORD64,3354 LastExceptionToRip: DWORD64,
3353 LastExceptionFromRip: DWORD64,3355 LastExceptionFromRip: DWORD64,
33543356
3355 pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize } {3357 pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize, sp: usize } {
3356 return .{ .bp = ctx.Rbp, .ip = ctx.Rip };3358 return .{ .bp = ctx.Rbp, .ip = ctx.Rip, .sp = ctx.Rsp };
3359 }
3360
3361 pub fn setIp(ctx: *CONTEXT, ip: usize) void {
3362 ctx.Rip = ip;
3357 }3363 }
3364
3365 pub fn setSp(ctx: *CONTEXT, sp: usize) void {
3366 ctx.Rsp = sp;
3367 }
3368 };
3369
3370 pub const RUNTIME_FUNCTION = extern struct {
3371 BeginAddress: DWORD,
3372 EndAddress: DWORD,
3373 UnwindData: DWORD,
3374 };
3375
3376 pub const KNONVOLATILE_CONTEXT_POINTERS = extern struct {
3377 FloatingContext: [16]?*M128A,
3378 IntegerContext: [16]?*ULONG64,
3358 };3379 };
3359 },3380 },
3360 .aarch64 => struct {3381 .aarch64 => struct {
...@@ -3370,7 +3391,7 @@ pub usingnamespace switch (native_arch) {...@@ -3370,7 +3391,7 @@ pub usingnamespace switch (native_arch) {
3370 };3391 };
33713392
3372 pub const CONTEXT = extern struct {3393 pub const CONTEXT = extern struct {
3373 ContextFlags: ULONG,3394 ContextFlags: ULONG align(16),
3374 Cpsr: ULONG,3395 Cpsr: ULONG,
3375 DUMMYUNIONNAME: extern union {3396 DUMMYUNIONNAME: extern union {
3376 DUMMYSTRUCTNAME: extern struct {3397 DUMMYSTRUCTNAME: extern struct {
...@@ -3418,12 +3439,60 @@ pub usingnamespace switch (native_arch) {...@@ -3418,12 +3439,60 @@ pub usingnamespace switch (native_arch) {
3418 Wcr: [2]DWORD,3439 Wcr: [2]DWORD,
3419 Wvr: [2]DWORD64,3440 Wvr: [2]DWORD64,
34203441
3421 pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize } {3442 pub fn getRegs(ctx: *const CONTEXT) struct { bp: usize, ip: usize, sp: usize } {
3422 return .{3443 return .{
3423 .bp = ctx.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Fp,3444 .bp = ctx.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Fp,
3424 .ip = ctx.Pc,3445 .ip = ctx.Pc,
3446 .sp = ctx.Sp,
3425 };3447 };
3426 }3448 }
3449
3450 pub fn setIp(ctx: *CONTEXT, ip: usize) void {
3451 ctx.Pc = ip;
3452 }
3453
3454 pub fn setSp(ctx: *CONTEXT, sp: usize) void {
3455 ctx.Sp = sp;
3456 }
3457 };
3458
3459 pub const RUNTIME_FUNCTION = extern struct {
3460 BeginAddress: DWORD,
3461 DUMMYUNIONNAME: extern union {
3462 UnwindData: DWORD,
3463 DUMMYSTRUCTNAME: packed struct {
3464 Flag: u2,
3465 FunctionLength: u11,
3466 RegF: u3,
3467 RegI: u4,
3468 H: u1,
3469 CR: u2,
3470 FrameSize: u9,
3471 },
3472 },
3473 };
3474
3475 pub const KNONVOLATILE_CONTEXT_POINTERS = extern struct {
3476 X19: ?*DWORD64,
3477 X20: ?*DWORD64,
3478 X21: ?*DWORD64,
3479 X22: ?*DWORD64,
3480 X23: ?*DWORD64,
3481 X24: ?*DWORD64,
3482 X25: ?*DWORD64,
3483 X26: ?*DWORD64,
3484 X27: ?*DWORD64,
3485 X28: ?*DWORD64,
3486 Fp: ?*DWORD64,
3487 Lr: ?*DWORD64,
3488 D8: ?*DWORD64,
3489 D9: ?*DWORD64,
3490 D10: ?*DWORD64,
3491 D11: ?*DWORD64,
3492 D12: ?*DWORD64,
3493 D13: ?*DWORD64,
3494 D14: ?*DWORD64,
3495 D15: ?*DWORD64,
3427 };3496 };
3428 },3497 },
3429 else => struct {},3498 else => struct {},
...@@ -3436,6 +3505,36 @@ pub const EXCEPTION_POINTERS = extern struct {...@@ -3436,6 +3505,36 @@ pub const EXCEPTION_POINTERS = extern struct {
34363505
3437pub const VECTORED_EXCEPTION_HANDLER = *const fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(WINAPI) c_long;3506pub const VECTORED_EXCEPTION_HANDLER = *const fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(WINAPI) c_long;
34383507
3508pub const EXCEPTION_DISPOSITION = i32;
3509pub const EXCEPTION_ROUTINE = *const fn (
3510 ExceptionRecord: ?*EXCEPTION_RECORD,
3511 EstablisherFrame: PVOID,
3512 ContextRecord: *(Self.CONTEXT),
3513 DispatcherContext: PVOID,
3514) callconv(WINAPI) EXCEPTION_DISPOSITION;
3515
3516pub const UNWIND_HISTORY_TABLE_SIZE = 12;
3517pub const UNWIND_HISTORY_TABLE_ENTRY = extern struct {
3518 ImageBase: ULONG64,
3519 FunctionEntry: *Self.RUNTIME_FUNCTION,
3520};
3521
3522pub const UNWIND_HISTORY_TABLE = extern struct {
3523 Count: ULONG,
3524 LocalHint: BYTE,
3525 GlobalHint: BYTE,
3526 Search: BYTE,
3527 Once: BYTE,
3528 LowAddress: ULONG64,
3529 HighAddress: ULONG64,
3530 Entry: [UNWIND_HISTORY_TABLE_SIZE]UNWIND_HISTORY_TABLE_ENTRY,
3531};
3532
3533pub const UNW_FLAG_NHANDLER = 0x0;
3534pub const UNW_FLAG_EHANDLER = 0x1;
3535pub const UNW_FLAG_UHANDLER = 0x2;
3536pub const UNW_FLAG_CHAININFO = 0x4;
3537
3439pub const OBJECT_ATTRIBUTES = extern struct {3538pub const OBJECT_ATTRIBUTES = extern struct {
3440 Length: ULONG,3539 Length: ULONG,
3441 RootDirectory: ?HANDLE,3540 RootDirectory: ?HANDLE,
...@@ -3494,6 +3593,21 @@ pub const TEB = extern struct {...@@ -3494,6 +3593,21 @@ pub const TEB = extern struct {
3494 TlsExpansionSlots: PVOID,3593 TlsExpansionSlots: PVOID,
3495};3594};
34963595
3596pub const EXCEPTION_REGISTRATION_RECORD = extern struct {
3597 Next: ?*EXCEPTION_REGISTRATION_RECORD,
3598 Handler: ?*EXCEPTION_DISPOSITION,
3599};
3600
3601pub const NT_TIB = extern struct {
3602 ExceptionList: ?*EXCEPTION_REGISTRATION_RECORD,
3603 StackBase: PVOID,
3604 StackLimit: PVOID,
3605 SubSystemTib: PVOID,
3606 DUMMYUNIONNAME: extern union { FiberData: PVOID, Version: DWORD },
3607 ArbitraryUserPointer: PVOID,
3608 Self: ?*@This(),
3609};
3610
3497/// Process Environment Block3611/// Process Environment Block
3498/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:3612/// Microsoft documentation of this is incomplete, the fields here are taken from various resources including:
3499/// - https://github.com/wine-mirror/wine/blob/1aff1e6a370ee8c0213a0fd4b220d121da8527aa/include/winternl.h#L2693613/// - https://github.com/wine-mirror/wine/blob/1aff1e6a370ee8c0213a0fd4b220d121da8527aa/include/winternl.h#L269
lib/std/os/windows/kernel32.zig+25
...@@ -5,8 +5,10 @@ const BOOL = windows.BOOL;...@@ -5,8 +5,10 @@ const BOOL = windows.BOOL;
5const BOOLEAN = windows.BOOLEAN;5const BOOLEAN = windows.BOOLEAN;
6const CONDITION_VARIABLE = windows.CONDITION_VARIABLE;6const CONDITION_VARIABLE = windows.CONDITION_VARIABLE;
7const CONSOLE_SCREEN_BUFFER_INFO = windows.CONSOLE_SCREEN_BUFFER_INFO;7const CONSOLE_SCREEN_BUFFER_INFO = windows.CONSOLE_SCREEN_BUFFER_INFO;
8const CONTEXT = windows.CONTEXT;
8const COORD = windows.COORD;9const COORD = windows.COORD;
9const DWORD = windows.DWORD;10const DWORD = windows.DWORD;
11const DWORD64 = windows.DWORD64;
10const FILE_INFO_BY_HANDLE_CLASS = windows.FILE_INFO_BY_HANDLE_CLASS;12const FILE_INFO_BY_HANDLE_CLASS = windows.FILE_INFO_BY_HANDLE_CLASS;
11const HANDLE = windows.HANDLE;13const HANDLE = windows.HANDLE;
12const HMODULE = windows.HMODULE;14const HMODULE = windows.HMODULE;
...@@ -60,6 +62,10 @@ const INIT_ONCE_FN = windows.INIT_ONCE_FN;...@@ -60,6 +62,10 @@ const INIT_ONCE_FN = windows.INIT_ONCE_FN;
60const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;62const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
61const REGSAM = windows.REGSAM;63const REGSAM = windows.REGSAM;
62const LSTATUS = windows.LSTATUS;64const LSTATUS = windows.LSTATUS;
65const UNWIND_HISTORY_TABLE = windows.UNWIND_HISTORY_TABLE;
66const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION;
67const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS;
68const EXCEPTION_ROUTINE = windows.EXCEPTION_ROUTINE;
6369
64pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;70pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
65pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;71pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
...@@ -292,6 +298,25 @@ pub extern "kernel32" fn ReadFile(...@@ -292,6 +298,25 @@ pub extern "kernel32" fn ReadFile(
292298
293pub extern "kernel32" fn RemoveDirectoryW(lpPathName: [*:0]const u16) callconv(WINAPI) BOOL;299pub extern "kernel32" fn RemoveDirectoryW(lpPathName: [*:0]const u16) callconv(WINAPI) BOOL;
294300
301pub extern "kernel32" fn RtlCaptureContext(ContextRecord: *CONTEXT) callconv(WINAPI) void;
302
303pub extern "kernel32" fn RtlLookupFunctionEntry(
304 ControlPc: DWORD64,
305 ImageBase: *DWORD64,
306 HistoryTable: *UNWIND_HISTORY_TABLE,
307) callconv(WINAPI) ?*RUNTIME_FUNCTION;
308
309pub extern "kernel32" fn RtlVirtualUnwind(
310 HandlerType: DWORD,
311 ImageBase: DWORD64,
312 ControlPc: DWORD64,
313 FunctionEntry: *RUNTIME_FUNCTION,
314 ContextRecord: *CONTEXT,
315 HandlerData: *?PVOID,
316 EstablisherFrame: *DWORD64,
317 ContextPointers: ?*KNONVOLATILE_CONTEXT_POINTERS,
318) callconv(WINAPI) *EXCEPTION_ROUTINE;
319
295pub extern "kernel32" fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) callconv(WINAPI) BOOL;320pub extern "kernel32" fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) callconv(WINAPI) BOOL;
296321
297pub extern "kernel32" fn SetConsoleCtrlHandler(322pub extern "kernel32" fn SetConsoleCtrlHandler(
lib/std/os/windows/ntdll.zig+22
...@@ -3,6 +3,7 @@ const windows = std.os.windows;...@@ -3,6 +3,7 @@ const windows = std.os.windows;
33
4const BOOL = windows.BOOL;4const BOOL = windows.BOOL;
5const DWORD = windows.DWORD;5const DWORD = windows.DWORD;
6const DWORD64 = windows.DWORD64;
6const ULONG = windows.ULONG;7const ULONG = windows.ULONG;
7const WINAPI = windows.WINAPI;8const WINAPI = windows.WINAPI;
8const NTSTATUS = windows.NTSTATUS;9const NTSTATUS = windows.NTSTATUS;
...@@ -24,6 +25,11 @@ const SIZE_T = windows.SIZE_T;...@@ -24,6 +25,11 @@ const SIZE_T = windows.SIZE_T;
24const CURDIR = windows.CURDIR;25const CURDIR = windows.CURDIR;
25const PCWSTR = windows.PCWSTR;26const PCWSTR = windows.PCWSTR;
26const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE;27const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE;
28const CONTEXT = windows.CONTEXT;
29const UNWIND_HISTORY_TABLE = windows.UNWIND_HISTORY_TABLE;
30const RUNTIME_FUNCTION = windows.RUNTIME_FUNCTION;
31const KNONVOLATILE_CONTEXT_POINTERS = windows.KNONVOLATILE_CONTEXT_POINTERS;
32const EXCEPTION_ROUTINE = windows.EXCEPTION_ROUTINE;
2733
28pub const THREADINFOCLASS = enum(c_int) {34pub const THREADINFOCLASS = enum(c_int) {
29 ThreadBasicInformation,35 ThreadBasicInformation,
...@@ -99,6 +105,22 @@ pub extern "ntdll" fn RtlCaptureStackBackTrace(...@@ -99,6 +105,22 @@ pub extern "ntdll" fn RtlCaptureStackBackTrace(
99 BackTrace: **anyopaque,105 BackTrace: **anyopaque,
100 BackTraceHash: ?*DWORD,106 BackTraceHash: ?*DWORD,
101) callconv(WINAPI) WORD;107) callconv(WINAPI) WORD;
108pub extern "ntdll" fn RtlCaptureContext(ContextRecord: *CONTEXT) callconv(WINAPI) void;
109pub extern "ntdll" fn RtlLookupFunctionEntry(
110 ControlPc: DWORD64,
111 ImageBase: *DWORD64,
112 HistoryTable: *UNWIND_HISTORY_TABLE,
113) callconv(WINAPI) ?*RUNTIME_FUNCTION;
114pub extern "ntdll" fn RtlVirtualUnwind(
115 HandlerType: DWORD,
116 ImageBase: DWORD64,
117 ControlPc: DWORD64,
118 FunctionEntry: *RUNTIME_FUNCTION,
119 ContextRecord: *CONTEXT,
120 HandlerData: *?PVOID,
121 EstablisherFrame: *DWORD64,
122 ContextPointers: ?*KNONVOLATILE_CONTEXT_POINTERS,
123) callconv(WINAPI) *EXCEPTION_ROUTINE;
102pub extern "ntdll" fn NtQueryInformationFile(124pub extern "ntdll" fn NtQueryInformationFile(
103 FileHandle: HANDLE,125 FileHandle: HANDLE,
104 IoStatusBlock: *IO_STATUS_BLOCK,126 IoStatusBlock: *IO_STATUS_BLOCK,