From 8f7fd5c7f363315f0f014cb9f1b8edac264bfb14 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Thu, 16 Jul 2026 12:58:25 +0100 Subject: [PATCH] std.debug.SelfInfo.Elf: fall back to symtab search more often Symtab search is always a reasonable fallback if debug information is absent, invalid, or unsupported. Therefore, by changing the error handling here to get symbols from the symtab even if `std.debug.Dwarf` returns an error, we make stack traces slightly better in some cases. This affects the self-hosted `Elf2` linker: that linker does not yet understand DWARF sections, so it ends up emitting incomplete (or sometimes invalid) DWARF. However, it still has a valid symtab, so we should at least be able to see function symbol names in the stack trace! Before this patch, we just saw "???" for everything, but after this patch, we do indeed get the symbol names. --- lib/std/debug/SelfInfo/Elf.zig | 49 +++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index 4e7fba60796adbb2f78a53b795aed5724eecd096..7a81b4cba894fd238d72e5e1c74cdc3df8ae176a 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -46,20 +46,30 @@ pub fn getSymbols( const vaddr = address - module.load_offset; const loaded_elf = try module.getLoadedElf(gpa, io); - if (loaded_elf.file.dwarf) |*dwarf| { - if (!loaded_elf.scanned_dwarf) { - dwarf.open(gpa, native_endian) catch |err| switch (err) { + const dwarf_err: ?Error = err: { + const dwarf = &(loaded_elf.file.dwarf orelse break :err null); + switch (loaded_elf.dwarf) { + .not_scanned => if (dwarf.open(gpa, native_endian)) { + loaded_elf.dwarf = .ok; + } else |err| switch (err) { error.InvalidDebugInfo, - error.MissingDebugInfo, - error.OutOfMemory, - => |e| return e, error.EndOfStream, error.Overflow, error.ReadFailed, error.StreamTooLong, - => return error.InvalidDebugInfo, - }; - loaded_elf.scanned_dwarf = true; + => { + loaded_elf.dwarf = .invalid; + break :err error.InvalidDebugInfo; + }, + error.MissingDebugInfo => { + loaded_elf.dwarf = .missing; + break :err error.MissingDebugInfo; + }, + error.OutOfMemory => |e| return e, + }, + .invalid => break :err error.InvalidDebugInfo, + .missing => break :err error.MissingDebugInfo, + .ok => {}, } return dwarf.getSymbols( symbol_allocator, @@ -68,14 +78,27 @@ pub fn getSymbols( vaddr, resolve_inline_callers, symbols, - ); - } + ) catch |err| switch (err) { + error.InvalidDebugInfo, + error.MissingDebugInfo, + error.UnsupportedDebugInfo, + => |e| break :err e, + + error.ReadFailed, + error.OutOfMemory, + error.Canceled, + error.Unexpected, + => |e| return e, + }; + }; // When DWARF is unavailable, fall back to searching the symtab. try symbols.append(symbol_allocator, loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo, error.BadSymtab => return error.InvalidDebugInfo, error.OutOfMemory => |e| return e, }); + // After searching the symtab, still report the DWARF error. + if (dwarf_err) |e| return e; } pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { const gpa = std.debug.getDebugInfoAllocator(); @@ -251,7 +274,7 @@ const Module = struct { const LoadedElf = struct { file: std.debug.ElfFile, - scanned_dwarf: bool, + dwarf: enum { not_scanned, invalid, missing, ok }, }; const UnwindSections = struct { @@ -377,7 +400,7 @@ const Module = struct { return .{ .file = elf_file, - .scanned_dwarf = false, + .dwarf = .not_scanned, }; } }; -- 2.54.0