From f1b71053de6c5e71e2e1f73daeaff29280b69350 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 29 Aug 2018 16:35:51 -0400 Subject: [PATCH] use RtlCaptureStackBackTrace on windows --- CMakeLists.txt | 1 + std/debug/index.zig | 24 +++++++++++++++++++++++- std/os/file.zig | 1 + std/os/index.zig | 6 ++++-- std/os/windows/index.zig | 1 + std/os/windows/ntdll.zig | 3 +++ 6 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 std/os/windows/ntdll.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d8ace6a6..5664f1db1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -578,6 +578,7 @@ set(ZIG_STD_FILES "os/windows/error.zig" "os/windows/index.zig" "os/windows/kernel32.zig" + "os/windows/ntdll.zig" "os/windows/ole32.zig" "os/windows/shell32.zig" "os/windows/shlwapi.zig" diff --git a/std/debug/index.zig b/std/debug/index.zig index 38d60a681..1bf38a9fb 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -195,6 +195,10 @@ pub inline fn getReturnAddress(frame_count: usize) usize { } pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { + switch (builtin.os) { + builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, allocator, debug_info, tty_color, start_addr), + else => {}, + } const AddressState = union(enum) { NotLookingForStartAddress, LookingForStartAddress: usize, @@ -227,6 +231,24 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_ } } +pub fn writeCurrentStackTraceWindows(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, + tty_color: bool, start_addr: ?usize) !void +{ + var addr_buf: [1024]usize = undefined; + const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast + const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null); + const addrs = addr_buf[0..n]; + var start_i: usize = if (start_addr) |saddr| blk: { + for (addrs) |addr, i| { + if (addr == saddr) break :blk i; + } + return; + } else 0; + for (addrs[start_i..]) |addr| { + try printSourceAtAddress(debug_info, out_stream, addr, tty_color); + } +} + pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { switch (builtin.os) { builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color), @@ -237,7 +259,7 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us } fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { - const base_address = @ptrToInt(windows.GetModuleHandleW(null)); // returned HMODULE points to our executable file in memory + const base_address = os.getBaseAddress(); const relative_address = address - base_address; std.debug.warn("{x} - {x} => {x}\n", address, base_address, relative_address); try di.pdb.getSourceLine(relative_address); diff --git a/std/os/file.zig b/std/os/file.zig index d63cb1dea..e90275ec7 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -271,6 +271,7 @@ pub const File = struct { const err = windows.GetLastError(); return switch (err) { windows.ERROR.INVALID_PARAMETER => unreachable, + windows.ERROR.INVALID_HANDLE => unreachable, else => os.unexpectedErrorWindows(err), }; } diff --git a/std/os/index.zig b/std/os/index.zig index 74f94dce5..03337b63b 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -661,6 +661,7 @@ pub fn getBaseAddress() usize { return phdr - @sizeOf(ElfHeader); }, builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header), + builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), else => @compileError("Unsupported OS"), } } @@ -2069,7 +2070,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons } // TODO make this a build variable that you can set -const unexpected_error_tracing = false; +const unexpected_error_tracing = true; const UnexpectedError = error{ /// The Operating System returned an undocumented error code. Unexpected, @@ -2088,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError { /// Call this when you made a windows DLL call or something that does SetLastError /// and you get an unexpected error. pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError { - if (true) { + if (unexpected_error_tracing) { debug.warn("unexpected GetLastError(): {}\n", err); + @breakpoint(); debug.dumpCurrentStackTrace(null); } return error.Unexpected; diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index 5c68176c5..ca6299dc5 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -3,6 +3,7 @@ const assert = std.debug.assert; pub use @import("advapi32.zig"); pub use @import("kernel32.zig"); +pub use @import("ntdll.zig"); pub use @import("ole32.zig"); pub use @import("shell32.zig"); pub use @import("shlwapi.zig"); diff --git a/std/os/windows/ntdll.zig b/std/os/windows/ntdll.zig new file mode 100644 index 000000000..acb78a59f --- /dev/null +++ b/std/os/windows/ntdll.zig @@ -0,0 +1,3 @@ +use @import("index.zig"); + +pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;