authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-04-18 00:01:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-18 18:20:15-07:00
loge82596950f731c0de12997fa7d224b1e0d33c9d3
tree5a84e26f7520c557e55ba2d46f23eb780ef55692
parent34286530b7c8beb070368b54abd8ec67a7344119

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

1 files changed, 68 insertions(+), 17 deletions(-)

lib/std/debug.zig+68-17
......@@ -183,6 +183,11 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
183183 return;
184184 };
185185 const tty_config = detectTTYConfig(io.getStdErr());
186 if (native_os == .windows) {
187 writeCurrentStackTraceWindows(stderr, debug_info, tty_config, ip) catch return;
188 return;
189 }
190
186191 printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return;
187192 var it = StackIterator.init(null, bp);
188193 while (it.next()) |return_address| {
......@@ -595,7 +600,16 @@ pub noinline fn walkStackWindows(addresses: []usize) usize {
595600 if (windows.ntdll.RtlLookupFunctionEntry(current_regs.ip, &image_base, &history_table)) |runtime_function| {
596601 var handler_data: ?*anyopaque = null;
597602 var establisher_frame: u64 = undefined;
598 _ = windows.ntdll.RtlVirtualUnwind(windows.UNW_FLAG_NHANDLER, image_base, current_regs.ip, runtime_function, &context, &handler_data, &establisher_frame, null);
603 _ = windows.ntdll.RtlVirtualUnwind(
604 windows.UNW_FLAG_NHANDLER,
605 image_base,
606 current_regs.ip,
607 runtime_function,
608 &context,
609 &handler_data,
610 &establisher_frame,
611 null,
612 );
599613 } else {
600614 // leaf function
601615 context.setIp(@intToPtr(*u64, current_regs.sp).*);
......@@ -769,23 +783,29 @@ test "machoSearchSymbols" {
769783 try testing.expectEqual(&symbols[2], machoSearchSymbols(&symbols, 5000).?);
770784}
771785
786fn printUnknownSource(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {
787 const module_name = debug_info.getModuleNameForAddress(address);
788 return printLineInfo(
789 out_stream,
790 null,
791 address,
792 "???",
793 module_name orelse "???",
794 tty_config,
795 printLineFromFileAnyOs,
796 );
797}
798
772799pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: TTY.Config) !void {
773800 const module = debug_info.getModuleForAddress(address) catch |err| switch (err) {
774 error.MissingDebugInfo, error.InvalidDebugInfo => {
775 return printLineInfo(
776 out_stream,
777 null,
778 address,
779 "???",
780 "???",
781 tty_config,
782 printLineFromFileAnyOs,
783 );
784 },
801 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
785802 else => return err,
786803 };
787804
788 const symbol_info = try module.getSymbolAtAddress(debug_info.allocator, address);
805 const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) {
806 error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config),
807 else => return err,
808 };
789809 defer symbol_info.deinit(debug_info.allocator);
790810
791811 return printLineInfo(
......@@ -1275,15 +1295,16 @@ fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 {
12751295 }
12761296}
12771297
1278pub const ModuleInfo = struct {
1298pub const WindowsModuleInfo = struct {
12791299 base_address: usize,
12801300 size: u32,
1301 name: []const u8,
12811302};
12821303
12831304pub const DebugInfo = struct {
12841305 allocator: mem.Allocator,
12851306 address_map: std.AutoHashMap(usize, *ModuleDebugInfo),
1286 modules: if (native_os == .windows) std.ArrayListUnmanaged(ModuleInfo) else void,
1307 modules: if (native_os == .windows) std.ArrayListUnmanaged(WindowsModuleInfo) else void,
12871308
12881309 pub fn init(allocator: mem.Allocator) !DebugInfo {
12891310 var debug_info = DebugInfo{
......@@ -1299,7 +1320,6 @@ pub const DebugInfo = struct {
12991320 else => |err| return windows.unexpectedError(err),
13001321 }
13011322 }
1302
13031323 defer windows.CloseHandle(handle);
13041324
13051325 var module_entry: windows.MODULEENTRY32 = undefined;
......@@ -1313,6 +1333,7 @@ pub const DebugInfo = struct {
13131333 const module_info = try debug_info.modules.addOne(allocator);
13141334 module_info.base_address = @ptrToInt(module_entry.modBaseAddr);
13151335 module_info.size = module_entry.modBaseSize;
1336 module_info.name = allocator.dupe(u8, mem.sliceTo(&module_entry.szModule, 0)) catch &.{};
13161337 module_valid = windows.kernel32.Module32Next(handle, &module_entry) == 1;
13171338 }
13181339 }
......@@ -1328,7 +1349,12 @@ pub const DebugInfo = struct {
13281349 self.allocator.destroy(mdi);
13291350 }
13301351 self.address_map.deinit();
1331 if (native_os == .windows) self.modules.deinit(self.allocator);
1352 if (native_os == .windows) {
1353 for (self.modules.items) |module| {
1354 self.allocator.free(module.name);
1355 }
1356 self.modules.deinit(self.allocator);
1357 }
13321358 }
13331359
13341360 pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
......@@ -1351,6 +1377,22 @@ pub const DebugInfo = struct {
13511377 }
13521378 }
13531379
1380 pub fn getModuleNameForAddress(self: *DebugInfo, address: usize) ?[]const u8 {
1381 if (builtin.zig_backend == .stage2_c) {
1382 return null;
1383 } else if (comptime builtin.target.isDarwin()) {
1384 return null;
1385 } else if (native_os == .windows) {
1386 return self.lookupModuleNameWin32(address);
1387 } else if (native_os == .haiku) {
1388 return null;
1389 } else if (comptime builtin.target.isWasm()) {
1390 return null;
1391 } else {
1392 return null;
1393 }
1394 }
1395
13541396 fn lookupModuleDyld(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
13551397 const image_count = std.c._dyld_image_count();
13561398
......@@ -1428,6 +1470,15 @@ pub const DebugInfo = struct {
14281470 return error.MissingDebugInfo;
14291471 }
14301472
1473 fn lookupModuleNameWin32(self: *DebugInfo, address: usize) ?[]const u8 {
1474 for (self.modules.items) |module| {
1475 if (address >= module.base_address and address < module.base_address + module.size) {
1476 return module.name;
1477 }
1478 }
1479 return null;
1480 }
1481
14311482 fn lookupModuleDl(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
14321483 var ctx: struct {
14331484 // Input