authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-16 12:58:25+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-17 15:56:36+02:00
log8f7fd5c7f363315f0f014cb9f1b8edac264bfb14
tree0fc27c709dc223e660e288ee1d23ea970f24bfb6
parentf1d454d535c96a1b1eee74a026a231af106448fb

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.

1 files changed, 36 insertions(+), 13 deletions(-)

lib/std/debug/SelfInfo/Elf.zig+36-13
...@@ -46,20 +46,30 @@ pub fn getSymbols(...@@ -46,20 +46,30 @@ pub fn getSymbols(
46 const vaddr = address - module.load_offset;46 const vaddr = address - module.load_offset;
4747
48 const loaded_elf = try module.getLoadedElf(gpa, io);48 const loaded_elf = try module.getLoadedElf(gpa, io);
49 if (loaded_elf.file.dwarf) |*dwarf| {49 const dwarf_err: ?Error = err: {
50 if (!loaded_elf.scanned_dwarf) {50 const dwarf = &(loaded_elf.file.dwarf orelse break :err null);
51 dwarf.open(gpa, native_endian) catch |err| switch (err) {51 switch (loaded_elf.dwarf) {
52 .not_scanned => if (dwarf.open(gpa, native_endian)) {
53 loaded_elf.dwarf = .ok;
54 } else |err| switch (err) {
52 error.InvalidDebugInfo,55 error.InvalidDebugInfo,
53 error.MissingDebugInfo,
54 error.OutOfMemory,
55 => |e| return e,
56 error.EndOfStream,56 error.EndOfStream,
57 error.Overflow,57 error.Overflow,
58 error.ReadFailed,58 error.ReadFailed,
59 error.StreamTooLong,59 error.StreamTooLong,
60 => return error.InvalidDebugInfo,60 => {
61 };61 loaded_elf.dwarf = .invalid;
62 loaded_elf.scanned_dwarf = true;62 break :err error.InvalidDebugInfo;
63 },
64 error.MissingDebugInfo => {
65 loaded_elf.dwarf = .missing;
66 break :err error.MissingDebugInfo;
67 },
68 error.OutOfMemory => |e| return e,
69 },
70 .invalid => break :err error.InvalidDebugInfo,
71 .missing => break :err error.MissingDebugInfo,
72 .ok => {},
63 }73 }
64 return dwarf.getSymbols(74 return dwarf.getSymbols(
65 symbol_allocator,75 symbol_allocator,
...@@ -68,14 +78,27 @@ pub fn getSymbols(...@@ -68,14 +78,27 @@ pub fn getSymbols(
68 vaddr,78 vaddr,
69 resolve_inline_callers,79 resolve_inline_callers,
70 symbols,80 symbols,
71 );81 ) catch |err| switch (err) {
72 }82 error.InvalidDebugInfo,
83 error.MissingDebugInfo,
84 error.UnsupportedDebugInfo,
85 => |e| break :err e,
86
87 error.ReadFailed,
88 error.OutOfMemory,
89 error.Canceled,
90 error.Unexpected,
91 => |e| return e,
92 };
93 };
73 // When DWARF is unavailable, fall back to searching the symtab.94 // When DWARF is unavailable, fall back to searching the symtab.
74 try symbols.append(symbol_allocator, loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) {95 try symbols.append(symbol_allocator, loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) {
75 error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo,96 error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo,
76 error.BadSymtab => return error.InvalidDebugInfo,97 error.BadSymtab => return error.InvalidDebugInfo,
77 error.OutOfMemory => |e| return e,98 error.OutOfMemory => |e| return e,
78 });99 });
100 // After searching the symtab, still report the DWARF error.
101 if (dwarf_err) |e| return e;
79}102}
80pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {103pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 {
81 const gpa = std.debug.getDebugInfoAllocator();104 const gpa = std.debug.getDebugInfoAllocator();
...@@ -251,7 +274,7 @@ const Module = struct {...@@ -251,7 +274,7 @@ const Module = struct {
251274
252 const LoadedElf = struct {275 const LoadedElf = struct {
253 file: std.debug.ElfFile,276 file: std.debug.ElfFile,
254 scanned_dwarf: bool,277 dwarf: enum { not_scanned, invalid, missing, ok },
255 };278 };
256279
257 const UnwindSections = struct {280 const UnwindSections = struct {
...@@ -377,7 +400,7 @@ const Module = struct {...@@ -377,7 +400,7 @@ const Module = struct {
377400
378 return .{401 return .{
379 .file = elf_file,402 .file = elf_file,
380 .scanned_dwarf = false,403 .dwarf = .not_scanned,
381 };404 };
382 }405 }
383};406};