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/ElfModule.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/ElfModule.zig')
| -rw-r--r-- | lib/std/debug/SelfInfo/ElfModule.zig | 88 |
1 files changed, 63 insertions, 25 deletions
diff --git a/lib/std/debug/SelfInfo/ElfModule.zig b/lib/std/debug/SelfInfo/ElfModule.zig index 6c1da9d8da..25ce1827b7 100644 --- a/lib/std/debug/SelfInfo/ElfModule.zig +++ b/lib/std/debug/SelfInfo/ElfModule.zig @@ -21,7 +21,7 @@ pub const DebugInfo = struct { pub fn key(m: ElfModule) usize { return m.load_offset; } -pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !ElfModule { +pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) Error!ElfModule { _ = cache; _ = gpa; if (builtin.target.os.tag == .haiku) @panic("TODO implement lookup module for Haiku"); @@ -92,42 +92,79 @@ pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !ElfModule { }; return error.MissingDebugInfo; } -fn loadDwarf(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) !void { - if (module.name.len > 0) { - di.loaded_elf = Dwarf.ElfModule.load(gpa, .{ +fn loadDwarf(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) Error!void { + const load_result = if (module.name.len > 0) res: { + break :res Dwarf.ElfModule.load(gpa, .{ .root_dir = .cwd(), .sub_path = module.name, - }, module.build_id, null, null, null) catch |err| switch (err) { - error.FileNotFound => return error.MissingDebugInfo, - error.Overflow => return error.InvalidDebugInfo, - else => |e| return e, + }, module.build_id, null, null, null); + } else res: { + const path = std.fs.selfExePathAlloc(gpa) catch |err| switch (err) { + error.OutOfMemory => |e| return e, + else => return error.ReadFailed, }; - } else { - const path = try std.fs.selfExePathAlloc(gpa); defer gpa.free(path); - di.loaded_elf = Dwarf.ElfModule.load(gpa, .{ + break :res Dwarf.ElfModule.load(gpa, .{ .root_dir = .cwd(), .sub_path = path, - }, module.build_id, null, null, null) catch |err| switch (err) { - error.FileNotFound => return error.MissingDebugInfo, - error.Overflow => return error.InvalidDebugInfo, - else => |e| return e, - }; - } + }, module.build_id, null, null, null); + }; + di.loaded_elf = load_result catch |err| switch (err) { + error.FileNotFound => return error.MissingDebugInfo, + + error.OutOfMemory, + error.InvalidDebugInfo, + error.MissingDebugInfo, + error.Unexpected, + => |e| return e, + + error.InvalidElfEndian, + error.InvalidElfMagic, + error.InvalidElfVersion, + error.InvalidUtf8, + error.InvalidWtf8, + error.EndOfStream, + error.Overflow, + error.UnimplementedDwarfForeignEndian, // this should be impossible as we're looking at the debug info for this process + => return error.InvalidDebugInfo, + + else => return error.ReadFailed, + }; } -pub fn getSymbolAtAddress(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol { +pub fn getSymbolAtAddress(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, address: usize) Error!std.debug.Symbol { if (di.loaded_elf == null) try module.loadDwarf(gpa, di); const vaddr = address - module.load_offset; - return di.loaded_elf.?.dwarf.getSymbol(gpa, native_endian, vaddr); + return di.loaded_elf.?.dwarf.getSymbol(gpa, native_endian, vaddr) catch |err| switch (err) { + error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory => |e| return e, + error.ReadFailed, + error.EndOfStream, + error.Overflow, + error.StreamTooLong, + => return error.InvalidDebugInfo, + }; } -fn loadUnwindInfo(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) !void { - const section_bytes = module.gnu_eh_frame orelse return error.MissingUnwindInfo; // MLUGG TODO: load from file +fn loadUnwindInfo(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) Error!void { + const section_bytes = module.gnu_eh_frame orelse return error.MissingDebugInfo; // MLUGG TODO: load from file + const section_vaddr: u64 = @intFromPtr(section_bytes.ptr) - module.load_offset; - const header: Dwarf.Unwind.EhFrameHeader = try .parse(section_vaddr, section_bytes, @sizeOf(usize), native_endian); - di.unwind = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr)); - try di.unwind.?.prepareLookup(gpa, @sizeOf(usize), native_endian); + const header = Dwarf.Unwind.EhFrameHeader.parse(section_vaddr, section_bytes, @sizeOf(usize), native_endian) catch |err| switch (err) { + error.ReadFailed => unreachable, // it's all fixed buffers + error.InvalidDebugInfo => |e| return e, + error.EndOfStream, error.Overflow => return error.InvalidDebugInfo, + error.UnsupportedAddrSize => return error.UnsupportedDebugInfo, + }; + + var unwind: Dwarf.Unwind = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr)); + unwind.prepareLookup(gpa, @sizeOf(usize), native_endian) catch |err| switch (err) { + error.ReadFailed => unreachable, // it's all fixed buffers + error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory => |e| return e, + error.EndOfStream, error.Overflow, error.StreamTooLong => return error.InvalidDebugInfo, + error.UnsupportedAddrSize, error.UnsupportedDwarfVersion => return error.UnsupportedDebugInfo, + }; + + di.unwind = unwind; } -pub fn unwindFrame(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize { +pub fn unwindFrame(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) Error!usize { if (di.unwind == null) try module.loadUnwindInfo(gpa, di); return context.unwindFrameDwarf(&di.unwind.?, module.load_offset, null); } @@ -140,6 +177,7 @@ const Dwarf = std.debug.Dwarf; const elf = std.elf; const mem = std.mem; const UnwindContext = std.debug.SelfInfo.UnwindContext; +const Error = std.debug.SelfInfo.Error; const builtin = @import("builtin"); const native_endian = builtin.target.cpu.arch.endian(); |
