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/SelfInfo.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/SelfInfo.zig')
| -rw-r--r-- | lib/std/debug/SelfInfo.zig | 72 |
1 files changed, 66 insertions, 6 deletions
diff --git a/lib/std/debug/SelfInfo.zig b/lib/std/debug/SelfInfo.zig index 9fa57208e1..1f913efeea 100644 --- a/lib/std/debug/SelfInfo.zig +++ b/lib/std/debug/SelfInfo.zig @@ -1,8 +1,6 @@ //! Cross-platform abstraction for this binary's own debug information, with a //! goal of minimal code bloat and compilation speed penalty. -// MLUGG TODO: audit use of errors in this file. ideally, introduce some concrete error sets - const builtin = @import("builtin"); const native_os = builtin.os.tag; const native_endian = native_arch.endian(); @@ -21,6 +19,19 @@ const SelfInfo = @This(); modules: std.AutoArrayHashMapUnmanaged(usize, Module.DebugInfo), lookup_cache: Module.LookupCache, +pub const Error = error{ + /// The required debug info is invalid or corrupted. + InvalidDebugInfo, + /// The required debug info could not be found. + MissingDebugInfo, + /// The required debug info was found, and may be valid, but is not supported by this implementation. + UnsupportedDebugInfo, + /// The required debug info could not be read from disk due to some IO error. + ReadFailed, + OutOfMemory, + Unexpected, +}; + /// Indicates whether the `SelfInfo` implementation has support for this target. pub const target_supported: bool = switch (native_os) { .linux, @@ -82,7 +93,7 @@ test { _ = &deinit; } -pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usize { +pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) Error!usize { comptime assert(supports_unwinding); const module: Module = try .lookup(&self.lookup_cache, gpa, context.pc); const gop = try self.modules.getOrPut(gpa, module.key()); @@ -92,7 +103,7 @@ pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !us return module.unwindFrame(gpa, gop.value_ptr, context); } -pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std.debug.Symbol { +pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) Error!std.debug.Symbol { comptime assert(target_supported); const module: Module = try .lookup(&self.lookup_cache, gpa, address); const gop = try self.modules.getOrPut(gpa, module.key()); @@ -102,7 +113,7 @@ pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std. return module.getSymbolAtAddress(gpa, gop.value_ptr, address); } -pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize) error{ Unexpected, OutOfMemory, MissingDebugInfo }![]const u8 { +pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize) Error![]const u8 { comptime assert(target_supported); const module: Module = try .lookup(&self.lookup_cache, gpa, address); return module.name; @@ -271,12 +282,61 @@ pub const UnwindContext = struct { /// may require lazily loading the data in those sections. /// /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info - /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section. pub fn unwindFrameDwarf( context: *UnwindContext, unwind: *const Dwarf.Unwind, load_offset: usize, explicit_fde_offset: ?usize, + ) Error!usize { + return unwindFrameDwarfInner(context, unwind, load_offset, explicit_fde_offset) catch |err| switch (err) { + error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory => |e| return e, + + error.UnimplementedArch, + error.UnimplementedOs, + error.ThreadContextNotSupported, + error.UnimplementedRegisterRule, + error.UnsupportedAddrSize, + error.UnsupportedDwarfVersion, + error.UnimplementedUserOpcode, + error.UnimplementedExpressionCall, + error.UnimplementedOpcode, + error.UnimplementedTypedComparison, + error.UnimplementedTypeConversion, + error.UnknownExpressionOpcode, + => return error.UnsupportedDebugInfo, + + error.InvalidRegister, + error.RegisterContextRequired, + error.ReadFailed, + error.EndOfStream, + error.IncompatibleRegisterSize, + error.Overflow, + error.StreamTooLong, + error.InvalidOperand, + error.InvalidOpcode, + error.InvalidOperation, + error.InvalidCFARule, + error.IncompleteExpressionContext, + error.InvalidCFAOpcode, + error.InvalidExpression, + error.InvalidFrameBase, + error.InvalidIntegralTypeSize, + error.InvalidSubExpression, + error.InvalidTypeLength, + error.TruncatedIntegralType, + error.DivisionByZero, + error.InvalidExpressionValue, + error.NoExpressionValue, + error.RegisterSizeMismatch, + error.InvalidCFA, + => return error.InvalidDebugInfo, + }; + } + fn unwindFrameDwarfInner( + context: *UnwindContext, + unwind: *const Dwarf.Unwind, + load_offset: usize, + explicit_fde_offset: ?usize, ) !usize { if (!supports_unwinding) return error.UnsupportedCpuArchitecture; if (context.pc == 0) return 0; |
