diff options
| author | kcbanner <kcbanner@gmail.com> | 2023-04-18 00:01:41 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-04-18 18:20:15 -0700 |
| commit | e82596950f731c0de12997fa7d224b1e0d33c9d3 (patch) | |
| tree | 5a84e26f7520c557e55ba2d46f23eb780ef55692 /lib/std/debug.zig | |
| parent | 34286530b7c8beb070368b54abd8ec67a7344119 (diff) | |
| download | zig-e82596950f731c0de12997fa7d224b1e0d33c9d3.tar.gz zig-e82596950f731c0de12997fa7d224b1e0d33c9d3.zip | |
debug: fix missing stack traces during crashes on windows
- walk the stack via the method that is aware of unwind info (fixes x86_64 / aarch64 traces)
- enhance the output for frames where the debug info isn't available by printing the module name
Diffstat (limited to 'lib/std/debug.zig')
| -rw-r--r-- | lib/std/debug.zig | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 933792add4..663540c182 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -183,6 +183,11 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { return; }; const tty_config = detectTTYConfig(io.getStdErr()); + if (native_os == .windows) { + writeCurrentStackTraceWindows(stderr, debug_info, tty_config, ip) catch return; + return; + } + printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; var it = StackIterator.init(null, bp); while (it.next()) |return_address| { @@ -595,7 +600,16 @@ pub noinline fn walkStackWindows(addresses: []usize) usize { 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); + _ = 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).*); @@ -769,23 +783,29 @@ test "machoSearchSymbols" { try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?); } +fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void { + const module_name = debug_info.getModuleNameForAddress(address); + return printLineInfo( + out_stream, + null, + address, + "???", + module_name orelse "???", + tty_config, + printLineFromFileAnyOs, + ); +} + pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void { const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => { - return printLineInfo( - out_stream, - null, - address, - "???", - "???", - tty_config, - printLineFromFileAnyOs, - ); - }, + error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), else => return err, }; - const symbol_info = try module.getSymbolAtAddress(debug_info.allocator, address); + const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) { + error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), + else => return err, + }; defer symbol_info.deinit(debug_info.allocator); return printLineInfo( @@ -1275,15 +1295,16 @@ fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 { } } -pub const ModuleInfo = struct { +pub const WindowsModuleInfo = struct { base_address: usize, size: u32, + name: []const u8, }; pub const DebugInfo = struct { allocator: mem.Allocator, address_map: std.AutoHashMap(usize, *ModuleDebugInfo), - modules: if (native_os == .windows) std.ArrayListUnmanaged(ModuleInfo) else void, + modules: if (native_os == .windows) std.ArrayListUnmanaged(WindowsModuleInfo) else void, pub fn init(allocator: mem.Allocator) !DebugInfo { var debug_info = DebugInfo{ @@ -1299,7 +1320,6 @@ pub const DebugInfo = struct { else => |err| return windows.unexpectedError(err), } } - defer windows.CloseHandle(handle); var module_entry: windows.MODULEENTRY32 = undefined; @@ -1313,6 +1333,7 @@ pub const DebugInfo = struct { const module_info = try debug_info.modules.addOne(allocator); module_info.base_address = @ptrToInt(module_entry.modBaseAddr); module_info.size = module_entry.modBaseSize; + module_info.name = allocator.dupe(u8, mem.sliceTo(&module_entry.szModule, 0)) catch &.{}; module_valid = windows.kernel32.Module32Next(handle, &module_entry) == 1; } } @@ -1328,7 +1349,12 @@ pub const DebugInfo = struct { self.allocator.destroy(mdi); } self.address_map.deinit(); - if (native_os == .windows) self.modules.deinit(self.allocator); + if (native_os == .windows) { + for (self.modules.items) |module| { + self.allocator.free(module.name); + } + self.modules.deinit(self.allocator); + } } pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo { @@ -1351,6 +1377,22 @@ pub const DebugInfo = struct { } } + pub fn getModuleNameForAddress(self: *DebugInfo, address: usize) ?[]const u8 { + if (builtin.zig_backend == .stage2_c) { + return null; + } else if (comptime builtin.target.isDarwin()) { + return null; + } else if (native_os == .windows) { + return self.lookupModuleNameWin32(address); + } else if (native_os == .haiku) { + return null; + } else if (comptime builtin.target.isWasm()) { + return null; + } else { + return null; + } + } + fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ModuleDebugInfo { const image_count = std.c._dyld_image_count(); @@ -1428,6 +1470,15 @@ pub const DebugInfo = struct { return error.MissingDebugInfo; } + fn lookupModuleNameWin32(self: *DebugInfo, address: usize) ?[]const u8 { + for (self.modules.items) |module| { + if (address >= module.base_address and address < module.base_address + module.size) { + return module.name; + } + } + return null; + } + fn lookupModuleDl(self: *DebugInfo, address: usize) !*ModuleDebugInfo { var ctx: struct { // Input |
