use RtlCaptureStackBackTrace on windows

master
Andrew Kelley 2018-08-29 16:35:51 -04:00
parent 833477abf5
commit f1b71053de
6 changed files with 33 additions and 3 deletions

View File

@ -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"

View File

@ -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);

View File

@ -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),
};
}

View File

@ -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;

View File

@ -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");

3
std/os/windows/ntdll.zig Normal file
View File

@ -0,0 +1,3 @@
use @import("index.zig");
pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;