diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2025-09-03 15:42:33 +0100 |
|---|---|---|
| committer | mlugg <mlugg@mlugg.co.uk> | 2025-09-30 13:44:50 +0100 |
| commit | c895aa7a35b178576b89e600a20af9d16da36dea (patch) | |
| tree | 0816ce721cd4343b5abd3c86187ca064b8826420 /lib/std/debug.zig | |
| parent | dd9cb1beead2d0b9a22decf089aadf51cfe90da8 (diff) | |
| download | zig-c895aa7a35b178576b89e600a20af9d16da36dea.tar.gz zig-c895aa7a35b178576b89e600a20af9d16da36dea.zip | |
std.debug.SelfInfo: concrete error sets
The downside of this commit is that more precise errors are no longer
propagated up. However, these errors were pretty useless in isolation
due to them having no context; and regardless, we intentionally swallow
most of them in `std.debug` anyway. Therefore, this is better in
practice, because it allows `std.debug` to give slightly more useful
warnings when handling errors. This commit does that for unwind errors,
for instance, which differentiate between the unwind info being corrupt
vs missing vs inaccessible vs unsupported.
A better solution would be to also include more detailed information via
the diagnostics pattern, but this commit is an incremental improvement.
Diffstat (limited to 'lib/std/debug.zig')
| -rw-r--r-- | lib/std/debug.zig | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 505677dcb6..d005dd7841 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -766,11 +766,6 @@ pub fn writeStackTrace( } } -pub const UnwindError = if (have_ucontext) - @typeInfo(@typeInfo(@TypeOf(SelfInfo.unwindFrame)).@"fn".return_type.?).error_union.error_set -else - void; - pub const StackIterator = struct { // Skip every frame before this address is found. first_address: ?usize, @@ -783,7 +778,7 @@ pub const StackIterator = struct { unwind_state: if (have_ucontext) ?struct { debug_info: *SelfInfo, dwarf_context: SelfInfo.UnwindContext, - last_error: ?UnwindError = null, + last_error: ?SelfInfo.Error = null, failed: bool = false, } else void = if (have_ucontext) null else {}, @@ -821,7 +816,7 @@ pub const StackIterator = struct { } pub fn getLastError(it: *StackIterator) ?struct { - err: UnwindError, + err: SelfInfo.Error, address: usize, } { if (!have_ucontext) return null; @@ -1037,17 +1032,29 @@ fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writ } } -fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwind_err: UnwindError, tty_config: tty.Config) !void { +fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwind_err: SelfInfo.Error, tty_config: tty.Config) !void { const module_name = debug_info.getModuleNameForAddress(getDebugInfoAllocator(), address) catch |err| switch (err) { - error.MissingDebugInfo => "???", + error.InvalidDebugInfo, error.MissingDebugInfo, error.UnsupportedDebugInfo, error.ReadFailed => "???", error.Unexpected, error.OutOfMemory => |e| return e, }; try tty_config.setColor(writer, .dim); - // MLUGG TODO this makes no sense given that MissingUnwindInfo exists? - if (unwind_err == error.MissingDebugInfo) { - try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); - } else { - try writer.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, unwind_err }); + switch (unwind_err) { + error.Unexpected, error.OutOfMemory => |e| return e, + error.MissingDebugInfo => { + try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); + }, + error.InvalidDebugInfo, + error.UnsupportedDebugInfo, + error.ReadFailed, + => { + const caption: []const u8 = switch (unwind_err) { + error.InvalidDebugInfo => "invalid unwind info", + error.UnsupportedDebugInfo => "unsupported unwind info", + error.ReadFailed => "filesystem error", + else => unreachable, + }; + try writer.print("Unwind error at address `{s}:0x{x}` ({s}), trace may be incomplete\n\n", .{ module_name, address, caption }); + }, } try tty_config.setColor(writer, .reset); } @@ -1055,12 +1062,17 @@ fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwi pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) !void { const gpa = getDebugInfoAllocator(); const symbol: Symbol = debug_info.getSymbolAtAddress(gpa, address) catch |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => .{ - .name = null, - .compile_unit_name = null, - .source_location = null, + error.MissingDebugInfo, + error.UnsupportedDebugInfo, + error.InvalidDebugInfo, + => .{ .name = null, .compile_unit_name = null, .source_location = null }, + error.ReadFailed => s: { + try tty_config.setColor(writer, .dim); + try writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{}); + try tty_config.setColor(writer, .reset); + break :s .{ .name = null, .compile_unit_name = null, .source_location = null }; }, - else => |e| return e, + error.OutOfMemory, error.Unexpected => |e| return e, }; defer if (symbol.source_location) |sl| gpa.free(sl.file_name); return printLineInfo( @@ -1069,7 +1081,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usi address, symbol.name orelse "???", symbol.compile_unit_name orelse debug_info.getModuleNameForAddress(gpa, address) catch |err| switch (err) { - error.MissingDebugInfo => "???", + error.InvalidDebugInfo, error.MissingDebugInfo, error.UnsupportedDebugInfo, error.ReadFailed => "???", error.Unexpected, error.OutOfMemory => |e| return e, }, tty_config, |
