aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
authorCasey Banner <kcbanner@gmail.com>2023-01-04 14:54:49 -0500
committerGitHub <noreply@github.com>2023-01-04 14:54:49 -0500
commit09ff03a57a9f2144f0d3e9b0173bac7035d3629b (patch)
treec498aa8f839458e5558f8344893579d16a5954ae /lib/std/debug.zig
parenta3e2ee091139740d076da1176ac8c487ca20a9a6 (diff)
downloadzig-09ff03a57a9f2144f0d3e9b0173bac7035d3629b.tar.gz
zig-09ff03a57a9f2144f0d3e9b0173bac7035d3629b.zip
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>
Diffstat (limited to 'lib/std/debug.zig')
-rw-r--r--lib/std/debug.zig53
1 files changed, 45 insertions, 8 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index 5bfac5bcb7..933af55cc9 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -206,17 +206,12 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *std.builtin.StackT
if (native_os == .windows) {
const addrs = stack_trace.instruction_addresses;
const first_addr = first_address orelse {
- stack_trace.index = windows.ntdll.RtlCaptureStackBackTrace(
- 0,
- @intCast(u32, addrs.len),
- @ptrCast(**anyopaque, addrs.ptr),
- null,
- );
+ stack_trace.index = walkStackWindows(addrs[0..]);
return;
};
var addr_buf_stack: [32]usize = undefined;
const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
- const n = windows.ntdll.RtlCaptureStackBackTrace(0, @intCast(u32, addr_buf.len), @ptrCast(**anyopaque, addr_buf.ptr), null);
+ const n = walkStackWindows(addr_buf[0..]);
const first_index = for (addr_buf[0..n]) |addr, i| {
if (addr == first_addr) {
break i;
@@ -573,6 +568,48 @@ pub fn writeCurrentStackTrace(
}
}
+pub noinline fn walkStackWindows(addresses: []usize) usize {
+ if (builtin.cpu.arch == .x86) {
+ // RtlVirtualUnwind doesn't exist on x86
+ return windows.ntdll.RtlCaptureStackBackTrace(0, addresses.len, @ptrCast(**anyopaque, addresses.ptr), null);
+ }
+
+ const tib = @ptrCast(*const windows.NT_TIB, &windows.teb().Reserved1);
+
+ var context: windows.CONTEXT = std.mem.zeroes(windows.CONTEXT);
+ windows.ntdll.RtlCaptureContext(&context);
+
+ var i: usize = 0;
+ var image_base: usize = undefined;
+ var history_table: windows.UNWIND_HISTORY_TABLE = std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);
+
+ while (i < addresses.len) : (i += 1) {
+ const current_regs = context.getRegs();
+ if (windows.ntdll.RtlLookupFunctionEntry(current_regs.ip, &image_base, &history_table)) |runtime_function| {
+ var handler_data: ?*anyopaque = null;
+ var establisher_frame: u64 = undefined;
+ _ = windows.ntdll.RtlVirtualUnwind(windows.UNW_FLAG_NHANDLER, image_base, current_regs.ip, runtime_function, &context, &handler_data, &establisher_frame, null);
+ } else {
+ // leaf function
+ context.setIp(@intToPtr(*u64, current_regs.sp).*);
+ context.setSp(current_regs.sp + @sizeOf(usize));
+ }
+
+ const next_regs = context.getRegs();
+ if (next_regs.sp < @ptrToInt(tib.StackLimit) or next_regs.sp > @ptrToInt(tib.StackBase)) {
+ break;
+ }
+
+ if (next_regs.ip == 0) {
+ break;
+ }
+
+ addresses[i] = next_regs.ip;
+ }
+
+ return i;
+}
+
pub fn writeCurrentStackTraceWindows(
out_stream: anytype,
debug_info: *DebugInfo,
@@ -580,7 +617,7 @@ pub fn writeCurrentStackTraceWindows(
start_addr: ?usize,
) !void {
var addr_buf: [1024]usize = undefined;
- const n = windows.ntdll.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**anyopaque, &addr_buf), null);
+ const n = walkStackWindows(addr_buf[0..]);
const addrs = addr_buf[0..n];
var start_i: usize = if (start_addr) |saddr| blk: {
for (addrs) |addr, i| {