Commit f1b71053de

Andrew Kelley <superjoe30@gmail.com>
2018-08-29 22:35:51
use RtlCaptureStackBackTrace on windows
1 parent 833477a
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);
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");
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;
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),
                     };
                 }
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;
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"