authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-29 16:35:51-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-29 16:35:51-04:00
logf1b71053de6c5e71e2e1f73daeaff29280b69350
tree6e27b78ebc073622dec68d49f809fe5ceb5fe674
parent833477abf5a7df2c8861a2df11fae2105016e087

use RtlCaptureStackBackTrace on windows


6 files changed, 33 insertions(+), 3 deletions(-)

CMakeLists.txt+1
...@@ -578,6 +578,7 @@ set(ZIG_STD_FILES...@@ -578,6 +578,7 @@ set(ZIG_STD_FILES
578 "os/windows/error.zig"578 "os/windows/error.zig"
579 "os/windows/index.zig"579 "os/windows/index.zig"
580 "os/windows/kernel32.zig"580 "os/windows/kernel32.zig"
581 "os/windows/ntdll.zig"
581 "os/windows/ole32.zig"582 "os/windows/ole32.zig"
582 "os/windows/shell32.zig"583 "os/windows/shell32.zig"
583 "os/windows/shlwapi.zig"584 "os/windows/shlwapi.zig"
std/debug/index.zig+23-1
...@@ -195,6 +195,10 @@ pub inline fn getReturnAddress(frame_count: usize) usize {...@@ -195,6 +195,10 @@ pub inline fn getReturnAddress(frame_count: usize) usize {
195}195}
196196
197pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {197pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
198 switch (builtin.os) {
199 builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, allocator, debug_info, tty_color, start_addr),
200 else => {},
201 }
198 const AddressState = union(enum) {202 const AddressState = union(enum) {
199 NotLookingForStartAddress,203 NotLookingForStartAddress,
200 LookingForStartAddress: usize,204 LookingForStartAddress: usize,
...@@ -227,6 +231,24 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_...@@ -227,6 +231,24 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_
227 }231 }
228}232}
229233
234pub fn writeCurrentStackTraceWindows(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo,
235 tty_color: bool, start_addr: ?usize) !void
236{
237 var addr_buf: [1024]usize = undefined;
238 const casted_len = @intCast(u32, addr_buf.len); // TODO shouldn't need this cast
239 const n = windows.RtlCaptureStackBackTrace(0, casted_len, @ptrCast(**c_void, &addr_buf), null);
240 const addrs = addr_buf[0..n];
241 var start_i: usize = if (start_addr) |saddr| blk: {
242 for (addrs) |addr, i| {
243 if (addr == saddr) break :blk i;
244 }
245 return;
246 } else 0;
247 for (addrs[start_i..]) |addr| {
248 try printSourceAtAddress(debug_info, out_stream, addr, tty_color);
249 }
250}
251
230pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {252pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
231 switch (builtin.os) {253 switch (builtin.os) {
232 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),254 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...@@ -237,7 +259,7 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us
237}259}
238260
239fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {261fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
240 const base_address = @ptrToInt(windows.GetModuleHandleW(null)); // returned HMODULE points to our executable file in memory262 const base_address = os.getBaseAddress();
241 const relative_address = address - base_address;263 const relative_address = address - base_address;
242 std.debug.warn("{x} - {x} => {x}\n", address, base_address, relative_address);264 std.debug.warn("{x} - {x} => {x}\n", address, base_address, relative_address);
243 try di.pdb.getSourceLine(relative_address);265 try di.pdb.getSourceLine(relative_address);
std/os/file.zig+1
...@@ -271,6 +271,7 @@ pub const File = struct {...@@ -271,6 +271,7 @@ pub const File = struct {
271 const err = windows.GetLastError();271 const err = windows.GetLastError();
272 return switch (err) {272 return switch (err) {
273 windows.ERROR.INVALID_PARAMETER => unreachable,273 windows.ERROR.INVALID_PARAMETER => unreachable,
274 windows.ERROR.INVALID_HANDLE => unreachable,
274 else => os.unexpectedErrorWindows(err),275 else => os.unexpectedErrorWindows(err),
275 };276 };
276 }277 }
std/os/index.zig+4-2
...@@ -661,6 +661,7 @@ pub fn getBaseAddress() usize {...@@ -661,6 +661,7 @@ pub fn getBaseAddress() usize {
661 return phdr - @sizeOf(ElfHeader);661 return phdr - @sizeOf(ElfHeader);
662 },662 },
663 builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),663 builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),
664 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
664 else => @compileError("Unsupported OS"),665 else => @compileError("Unsupported OS"),
665 }666 }
666}667}
...@@ -2069,7 +2070,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons...@@ -2069,7 +2070,7 @@ fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []cons
2069}2070}
20702071
2071// TODO make this a build variable that you can set2072// TODO make this a build variable that you can set
2072const unexpected_error_tracing = false;2073const unexpected_error_tracing = true;
2073const UnexpectedError = error{2074const UnexpectedError = error{
2074 /// The Operating System returned an undocumented error code.2075 /// The Operating System returned an undocumented error code.
2075 Unexpected,2076 Unexpected,
...@@ -2088,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {...@@ -2088,8 +2089,9 @@ pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
2088/// Call this when you made a windows DLL call or something that does SetLastError2089/// Call this when you made a windows DLL call or something that does SetLastError
2089/// and you get an unexpected error.2090/// and you get an unexpected error.
2090pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {2091pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2091 if (true) {2092 if (unexpected_error_tracing) {
2092 debug.warn("unexpected GetLastError(): {}\n", err);2093 debug.warn("unexpected GetLastError(): {}\n", err);
2094 @breakpoint();
2093 debug.dumpCurrentStackTrace(null);2095 debug.dumpCurrentStackTrace(null);
2094 }2096 }
2095 return error.Unexpected;2097 return error.Unexpected;
std/os/windows/index.zig+1
...@@ -3,6 +3,7 @@ const assert = std.debug.assert;...@@ -3,6 +3,7 @@ const assert = std.debug.assert;
33
4pub use @import("advapi32.zig");4pub use @import("advapi32.zig");
5pub use @import("kernel32.zig");5pub use @import("kernel32.zig");
6pub use @import("ntdll.zig");
6pub use @import("ole32.zig");7pub use @import("ole32.zig");
7pub use @import("shell32.zig");8pub use @import("shell32.zig");
8pub use @import("shlwapi.zig");9pub use @import("shlwapi.zig");
std/os/windows/ntdll.zig created+3
...@@ -0,0 +1,3 @@
1use @import("index.zig");
2
3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;