aboutsummaryrefslogtreecommitdiff
path: root/lib/std/debug.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-09-03 15:42:33 +0100
committermlugg <mlugg@mlugg.co.uk>2025-09-30 13:44:50 +0100
commitc895aa7a35b178576b89e600a20af9d16da36dea (patch)
tree0816ce721cd4343b5abd3c86187ca064b8826420 /lib/std/debug.zig
parentdd9cb1beead2d0b9a22decf089aadf51cfe90da8 (diff)
downloadzig-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.zig52
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,