authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-03 15:42:33+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-30 13:44:50+01:00
logc895aa7a35b178576b89e600a20af9d16da36dea
tree0816ce721cd4343b5abd3c86187ca064b8826420
parentdd9cb1beead2d0b9a22decf089aadf51cfe90da8
signaturelock-open Commit is signed but in an unrecognized format.

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.

6 files changed, 230 insertions(+), 103 deletions(-)

lib/std/debug.zig+32-20
...@@ -766,11 +766,6 @@ pub fn writeStackTrace(...@@ -766,11 +766,6 @@ pub fn writeStackTrace(
766 }766 }
767}767}
768768
769pub const UnwindError = if (have_ucontext)
770 @typeInfo(@typeInfo(@TypeOf(SelfInfo.unwindFrame)).@"fn".return_type.?).error_union.error_set
771else
772 void;
773
774pub const StackIterator = struct {769pub const StackIterator = struct {
775 // Skip every frame before this address is found.770 // Skip every frame before this address is found.
776 first_address: ?usize,771 first_address: ?usize,
...@@ -783,7 +778,7 @@ pub const StackIterator = struct {...@@ -783,7 +778,7 @@ pub const StackIterator = struct {
783 unwind_state: if (have_ucontext) ?struct {778 unwind_state: if (have_ucontext) ?struct {
784 debug_info: *SelfInfo,779 debug_info: *SelfInfo,
785 dwarf_context: SelfInfo.UnwindContext,780 dwarf_context: SelfInfo.UnwindContext,
786 last_error: ?UnwindError = null,781 last_error: ?SelfInfo.Error = null,
787 failed: bool = false,782 failed: bool = false,
788 } else void = if (have_ucontext) null else {},783 } else void = if (have_ucontext) null else {},
789784
...@@ -821,7 +816,7 @@ pub const StackIterator = struct {...@@ -821,7 +816,7 @@ pub const StackIterator = struct {
821 }816 }
822817
823 pub fn getLastError(it: *StackIterator) ?struct {818 pub fn getLastError(it: *StackIterator) ?struct {
824 err: UnwindError,819 err: SelfInfo.Error,
825 address: usize,820 address: usize,
826 } {821 } {
827 if (!have_ucontext) return null;822 if (!have_ucontext) return null;
...@@ -1037,17 +1032,29 @@ fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writ...@@ -1037,17 +1032,29 @@ fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writ
1037 }1032 }
1038}1033}
10391034
1040fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwind_err: UnwindError, tty_config: tty.Config) !void {1035fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwind_err: SelfInfo.Error, tty_config: tty.Config) !void {
1041 const module_name = debug_info.getModuleNameForAddress(getDebugInfoAllocator(), address) catch |err| switch (err) {1036 const module_name = debug_info.getModuleNameForAddress(getDebugInfoAllocator(), address) catch |err| switch (err) {
1042 error.MissingDebugInfo => "???",1037 error.InvalidDebugInfo, error.MissingDebugInfo, error.UnsupportedDebugInfo, error.ReadFailed => "???",
1043 error.Unexpected, error.OutOfMemory => |e| return e,1038 error.Unexpected, error.OutOfMemory => |e| return e,
1044 };1039 };
1045 try tty_config.setColor(writer, .dim);1040 try tty_config.setColor(writer, .dim);
1046 // MLUGG TODO this makes no sense given that MissingUnwindInfo exists?1041 switch (unwind_err) {
1047 if (unwind_err == error.MissingDebugInfo) {1042 error.Unexpected, error.OutOfMemory => |e| return e,
1048 try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address });1043 error.MissingDebugInfo => {
1049 } else {1044 try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address });
1050 try writer.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, unwind_err });1045 },
1046 error.InvalidDebugInfo,
1047 error.UnsupportedDebugInfo,
1048 error.ReadFailed,
1049 => {
1050 const caption: []const u8 = switch (unwind_err) {
1051 error.InvalidDebugInfo => "invalid unwind info",
1052 error.UnsupportedDebugInfo => "unsupported unwind info",
1053 error.ReadFailed => "filesystem error",
1054 else => unreachable,
1055 };
1056 try writer.print("Unwind error at address `{s}:0x{x}` ({s}), trace may be incomplete\n\n", .{ module_name, address, caption });
1057 },
1051 }1058 }
1052 try tty_config.setColor(writer, .reset);1059 try tty_config.setColor(writer, .reset);
1053}1060}
...@@ -1055,12 +1062,17 @@ fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwi...@@ -1055,12 +1062,17 @@ fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, unwi
1055pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) !void {1062pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: tty.Config) !void {
1056 const gpa = getDebugInfoAllocator();1063 const gpa = getDebugInfoAllocator();
1057 const symbol: Symbol = debug_info.getSymbolAtAddress(gpa, address) catch |err| switch (err) {1064 const symbol: Symbol = debug_info.getSymbolAtAddress(gpa, address) catch |err| switch (err) {
1058 error.MissingDebugInfo, error.InvalidDebugInfo => .{1065 error.MissingDebugInfo,
1059 .name = null,1066 error.UnsupportedDebugInfo,
1060 .compile_unit_name = null,1067 error.InvalidDebugInfo,
1061 .source_location = null,1068 => .{ .name = null, .compile_unit_name = null, .source_location = null },
1069 error.ReadFailed => s: {
1070 try tty_config.setColor(writer, .dim);
1071 try writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{});
1072 try tty_config.setColor(writer, .reset);
1073 break :s .{ .name = null, .compile_unit_name = null, .source_location = null };
1062 },1074 },
1063 else => |e| return e,1075 error.OutOfMemory, error.Unexpected => |e| return e,
1064 };1076 };
1065 defer if (symbol.source_location) |sl| gpa.free(sl.file_name);1077 defer if (symbol.source_location) |sl| gpa.free(sl.file_name);
1066 return printLineInfo(1078 return printLineInfo(
...@@ -1069,7 +1081,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usi...@@ -1069,7 +1081,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usi
1069 address,1081 address,
1070 symbol.name orelse "???",1082 symbol.name orelse "???",
1071 symbol.compile_unit_name orelse debug_info.getModuleNameForAddress(gpa, address) catch |err| switch (err) {1083 symbol.compile_unit_name orelse debug_info.getModuleNameForAddress(gpa, address) catch |err| switch (err) {
1072 error.MissingDebugInfo => "???",1084 error.InvalidDebugInfo, error.MissingDebugInfo, error.UnsupportedDebugInfo, error.ReadFailed => "???",
1073 error.Unexpected, error.OutOfMemory => |e| return e,1085 error.Unexpected, error.OutOfMemory => |e| return e,
1074 },1086 },
1075 tty_config,1087 tty_config,
lib/std/debug/Dwarf.zig+1-1
...@@ -1418,7 +1418,7 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 {...@@ -1418,7 +1418,7 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 {
1418 4 => 14, // R141418 4 => 14, // R14
1419 5 => 15, // R151419 5 => 15, // R15
1420 6 => 6, // RBP1420 6 => 6, // RBP
1421 else => error.InvalidUnwindRegisterNumber,1421 else => error.InvalidRegister,
1422 };1422 };
1423}1423}
14241424
lib/std/debug/SelfInfo.zig+66-6
...@@ -1,8 +1,6 @@...@@ -1,8 +1,6 @@
1//! Cross-platform abstraction for this binary's own debug information, with a1//! Cross-platform abstraction for this binary's own debug information, with a
2//! goal of minimal code bloat and compilation speed penalty.2//! goal of minimal code bloat and compilation speed penalty.
33
4// MLUGG TODO: audit use of errors in this file. ideally, introduce some concrete error sets
5
6const builtin = @import("builtin");4const builtin = @import("builtin");
7const native_os = builtin.os.tag;5const native_os = builtin.os.tag;
8const native_endian = native_arch.endian();6const native_endian = native_arch.endian();
...@@ -21,6 +19,19 @@ const SelfInfo = @This();...@@ -21,6 +19,19 @@ const SelfInfo = @This();
21modules: std.AutoArrayHashMapUnmanaged(usize, Module.DebugInfo),19modules: std.AutoArrayHashMapUnmanaged(usize, Module.DebugInfo),
22lookup_cache: Module.LookupCache,20lookup_cache: Module.LookupCache,
2321
22pub const Error = error{
23 /// The required debug info is invalid or corrupted.
24 InvalidDebugInfo,
25 /// The required debug info could not be found.
26 MissingDebugInfo,
27 /// The required debug info was found, and may be valid, but is not supported by this implementation.
28 UnsupportedDebugInfo,
29 /// The required debug info could not be read from disk due to some IO error.
30 ReadFailed,
31 OutOfMemory,
32 Unexpected,
33};
34
24/// Indicates whether the `SelfInfo` implementation has support for this target.35/// Indicates whether the `SelfInfo` implementation has support for this target.
25pub const target_supported: bool = switch (native_os) {36pub const target_supported: bool = switch (native_os) {
26 .linux,37 .linux,
...@@ -82,7 +93,7 @@ test {...@@ -82,7 +93,7 @@ test {
82 _ = &deinit;93 _ = &deinit;
83}94}
8495
85pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usize {96pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) Error!usize {
86 comptime assert(supports_unwinding);97 comptime assert(supports_unwinding);
87 const module: Module = try .lookup(&self.lookup_cache, gpa, context.pc);98 const module: Module = try .lookup(&self.lookup_cache, gpa, context.pc);
88 const gop = try self.modules.getOrPut(gpa, module.key());99 const gop = try self.modules.getOrPut(gpa, module.key());
...@@ -92,7 +103,7 @@ pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !us...@@ -92,7 +103,7 @@ pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !us
92 return module.unwindFrame(gpa, gop.value_ptr, context);103 return module.unwindFrame(gpa, gop.value_ptr, context);
93}104}
94105
95pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std.debug.Symbol {106pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) Error!std.debug.Symbol {
96 comptime assert(target_supported);107 comptime assert(target_supported);
97 const module: Module = try .lookup(&self.lookup_cache, gpa, address);108 const module: Module = try .lookup(&self.lookup_cache, gpa, address);
98 const gop = try self.modules.getOrPut(gpa, module.key());109 const gop = try self.modules.getOrPut(gpa, module.key());
...@@ -102,7 +113,7 @@ pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std....@@ -102,7 +113,7 @@ pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std.
102 return module.getSymbolAtAddress(gpa, gop.value_ptr, address);113 return module.getSymbolAtAddress(gpa, gop.value_ptr, address);
103}114}
104115
105pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize) error{ Unexpected, OutOfMemory, MissingDebugInfo }![]const u8 {116pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize) Error![]const u8 {
106 comptime assert(target_supported);117 comptime assert(target_supported);
107 const module: Module = try .lookup(&self.lookup_cache, gpa, address);118 const module: Module = try .lookup(&self.lookup_cache, gpa, address);
108 return module.name;119 return module.name;
...@@ -271,12 +282,61 @@ pub const UnwindContext = struct {...@@ -271,12 +282,61 @@ pub const UnwindContext = struct {
271 /// may require lazily loading the data in those sections.282 /// may require lazily loading the data in those sections.
272 ///283 ///
273 /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info284 /// `explicit_fde_offset` is for cases where the FDE offset is known, such as when __unwind_info
274 /// defers unwinding to DWARF. This is an offset into the `.eh_frame` section.
275 pub fn unwindFrameDwarf(285 pub fn unwindFrameDwarf(
276 context: *UnwindContext,286 context: *UnwindContext,
277 unwind: *const Dwarf.Unwind,287 unwind: *const Dwarf.Unwind,
278 load_offset: usize,288 load_offset: usize,
279 explicit_fde_offset: ?usize,289 explicit_fde_offset: ?usize,
290 ) Error!usize {
291 return unwindFrameDwarfInner(context, unwind, load_offset, explicit_fde_offset) catch |err| switch (err) {
292 error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory => |e| return e,
293
294 error.UnimplementedArch,
295 error.UnimplementedOs,
296 error.ThreadContextNotSupported,
297 error.UnimplementedRegisterRule,
298 error.UnsupportedAddrSize,
299 error.UnsupportedDwarfVersion,
300 error.UnimplementedUserOpcode,
301 error.UnimplementedExpressionCall,
302 error.UnimplementedOpcode,
303 error.UnimplementedTypedComparison,
304 error.UnimplementedTypeConversion,
305 error.UnknownExpressionOpcode,
306 => return error.UnsupportedDebugInfo,
307
308 error.InvalidRegister,
309 error.RegisterContextRequired,
310 error.ReadFailed,
311 error.EndOfStream,
312 error.IncompatibleRegisterSize,
313 error.Overflow,
314 error.StreamTooLong,
315 error.InvalidOperand,
316 error.InvalidOpcode,
317 error.InvalidOperation,
318 error.InvalidCFARule,
319 error.IncompleteExpressionContext,
320 error.InvalidCFAOpcode,
321 error.InvalidExpression,
322 error.InvalidFrameBase,
323 error.InvalidIntegralTypeSize,
324 error.InvalidSubExpression,
325 error.InvalidTypeLength,
326 error.TruncatedIntegralType,
327 error.DivisionByZero,
328 error.InvalidExpressionValue,
329 error.NoExpressionValue,
330 error.RegisterSizeMismatch,
331 error.InvalidCFA,
332 => return error.InvalidDebugInfo,
333 };
334 }
335 fn unwindFrameDwarfInner(
336 context: *UnwindContext,
337 unwind: *const Dwarf.Unwind,
338 load_offset: usize,
339 explicit_fde_offset: ?usize,
280 ) !usize {340 ) !usize {
281 if (!supports_unwinding) return error.UnsupportedCpuArchitecture;341 if (!supports_unwinding) return error.UnsupportedCpuArchitecture;
282 if (context.pc == 0) return 0;342 if (context.pc == 0) return 0;
lib/std/debug/SelfInfo/DarwinModule.zig+56-44
...@@ -7,7 +7,9 @@ pub fn key(m: *const DarwinModule) usize {...@@ -7,7 +7,9 @@ pub fn key(m: *const DarwinModule) usize {
7 return m.text_base;7 return m.text_base;
8}8}
99
10pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !DarwinModule {10/// No cache needed, because `_dyld_get_image_header` etc are already fast.
11pub const LookupCache = void;
12pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) Error!DarwinModule {
11 _ = cache;13 _ = cache;
12 _ = gpa;14 _ = gpa;
13 const image_count = std.c._dyld_image_count();15 const image_count = std.c._dyld_image_count();
...@@ -186,8 +188,11 @@ fn loadFullInfo(module: *const DarwinModule, gpa: Allocator) !DebugInfo.Full {...@@ -186,8 +188,11 @@ fn loadFullInfo(module: *const DarwinModule, gpa: Allocator) !DebugInfo.Full {
186 .ofiles = .empty,188 .ofiles = .empty,
187 };189 };
188}190}
189pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol {191pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo, address: usize) Error!std.debug.Symbol {
190 if (di.full == null) di.full = try module.loadFullInfo(gpa);192 if (di.full == null) di.full = module.loadFullInfo(gpa) catch |err| switch (err) {
193 error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory, error.Unexpected => |e| return e,
194 else => return error.ReadFailed,
195 };
191 const full = &di.full.?;196 const full = &di.full.?;
192197
193 const vaddr = address - module.load_offset;198 const vaddr = address - module.load_offset;
...@@ -215,14 +220,9 @@ pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *Debu...@@ -215,14 +220,9 @@ pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *Debu
215 const gop = try full.ofiles.getOrPut(gpa, symbol.ofile);220 const gop = try full.ofiles.getOrPut(gpa, symbol.ofile);
216 if (!gop.found_existing) {221 if (!gop.found_existing) {
217 const o_file_path = mem.sliceTo(full.strings[symbol.ofile..], 0);222 const o_file_path = mem.sliceTo(full.strings[symbol.ofile..], 0);
218 gop.value_ptr.* = DebugInfo.loadOFile(gpa, o_file_path) catch |err| {223 gop.value_ptr.* = DebugInfo.loadOFile(gpa, o_file_path) catch {
219 defer _ = full.ofiles.pop().?;224 _ = full.ofiles.pop().?;
220 switch (err) {225 return sym_only_result;
221 error.MissingDebugInfo,
222 error.InvalidDebugInfo,
223 => return sym_only_result,
224 else => |e| return e,
225 }
226 };226 };
227 }227 }
228 break :of gop.value_ptr;228 break :of gop.value_ptr;
...@@ -234,10 +234,7 @@ pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *Debu...@@ -234,10 +234,7 @@ pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *Debu
234 ) orelse return sym_only_result;234 ) orelse return sym_only_result;
235 const symbol_ofile_vaddr = o_file.symtab[symbol_index].n_value;235 const symbol_ofile_vaddr = o_file.symtab[symbol_index].n_value;
236236
237 const compile_unit = o_file.dwarf.findCompileUnit(native_endian, symbol_ofile_vaddr) catch |err| switch (err) {237 const compile_unit = o_file.dwarf.findCompileUnit(native_endian, symbol_ofile_vaddr) catch return sym_only_result;
238 error.MissingDebugInfo, error.InvalidDebugInfo => return sym_only_result,
239 else => |e| return e,
240 };
241238
242 return .{239 return .{
243 .name = o_file.dwarf.getSymbolName(symbol_ofile_vaddr) orelse stab_symbol,240 .name = o_file.dwarf.getSymbolName(symbol_ofile_vaddr) orelse stab_symbol,
...@@ -255,28 +252,44 @@ pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *Debu...@@ -255,28 +252,44 @@ pub fn getSymbolAtAddress(module: *const DarwinModule, gpa: Allocator, di: *Debu
255 native_endian,252 native_endian,
256 compile_unit,253 compile_unit,
257 symbol_ofile_vaddr + address_symbol_offset,254 symbol_ofile_vaddr + address_symbol_offset,
258 ) catch |err| switch (err) {255 ) catch null,
259 error.MissingDebugInfo, error.InvalidDebugInfo => null,
260 else => return err,
261 },
262 };256 };
263}257}
264/// Unwind a frame using MachO compact unwind info (from __unwind_info).258/// Unwind a frame using MachO compact unwind info (from __unwind_info).
265/// If the compact encoding can't encode a way to unwind a frame, it will259/// If the compact encoding can't encode a way to unwind a frame, it will
266/// defer unwinding to DWARF, in which case `.eh_frame` will be used if available.260/// defer unwinding to DWARF, in which case `.eh_frame` will be used if available.
267pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize {261pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) Error!usize {
262 return unwindFrameInner(module, gpa, di, context) catch |err| switch (err) {
263 error.InvalidDebugInfo,
264 error.MissingDebugInfo,
265 error.UnsupportedDebugInfo,
266 error.ReadFailed,
267 error.OutOfMemory,
268 error.Unexpected,
269 => |e| return e,
270 error.UnimplementedArch,
271 error.UnimplementedOs,
272 error.ThreadContextNotSupported,
273 => return error.UnsupportedDebugInfo,
274 error.InvalidRegister,
275 error.RegisterContextRequired,
276 error.IncompatibleRegisterSize,
277 => return error.InvalidDebugInfo,
278 };
279}
280fn unwindFrameInner(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize {
268 _ = gpa;281 _ = gpa;
269 if (di.unwind == null) di.unwind = module.loadUnwindInfo();282 if (di.unwind == null) di.unwind = module.loadUnwindInfo();
270 const unwind = &di.unwind.?;283 const unwind = &di.unwind.?;
271284
272 const unwind_info = unwind.unwind_info orelse return error.MissingUnwindInfo;285 const unwind_info = unwind.unwind_info orelse return error.MissingDebugInfo;
273 if (unwind_info.len < @sizeOf(macho.unwind_info_section_header)) return error.InvalidUnwindInfo;286 if (unwind_info.len < @sizeOf(macho.unwind_info_section_header)) return error.InvalidDebugInfo;
274 const header: *align(1) const macho.unwind_info_section_header = @ptrCast(unwind_info);287 const header: *align(1) const macho.unwind_info_section_header = @ptrCast(unwind_info);
275288
276 const index_byte_count = header.indexCount * @sizeOf(macho.unwind_info_section_header_index_entry);289 const index_byte_count = header.indexCount * @sizeOf(macho.unwind_info_section_header_index_entry);
277 if (unwind_info.len < header.indexSectionOffset + index_byte_count) return error.InvalidUnwindInfo;290 if (unwind_info.len < header.indexSectionOffset + index_byte_count) return error.InvalidDebugInfo;
278 const indices: []align(1) const macho.unwind_info_section_header_index_entry = @ptrCast(unwind_info[header.indexSectionOffset..][0..index_byte_count]);291 const indices: []align(1) const macho.unwind_info_section_header_index_entry = @ptrCast(unwind_info[header.indexSectionOffset..][0..index_byte_count]);
279 if (indices.len == 0) return error.MissingUnwindInfo;292 if (indices.len == 0) return error.MissingDebugInfo;
280293
281 // offset of the PC into the `__TEXT` segment294 // offset of the PC into the `__TEXT` segment
282 const pc_text_offset = context.pc - module.text_base;295 const pc_text_offset = context.pc - module.text_base;
...@@ -296,15 +309,15 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -296,15 +309,15 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
296 break :index .{ indices[left].secondLevelPagesSectionOffset, indices[left].functionOffset };309 break :index .{ indices[left].secondLevelPagesSectionOffset, indices[left].functionOffset };
297 };310 };
298 // An offset of 0 is a sentinel indicating a range does not have unwind info.311 // An offset of 0 is a sentinel indicating a range does not have unwind info.
299 if (start_offset == 0) return error.MissingUnwindInfo;312 if (start_offset == 0) return error.MissingDebugInfo;
300313
301 const common_encodings_byte_count = header.commonEncodingsArrayCount * @sizeOf(macho.compact_unwind_encoding_t);314 const common_encodings_byte_count = header.commonEncodingsArrayCount * @sizeOf(macho.compact_unwind_encoding_t);
302 if (unwind_info.len < header.commonEncodingsArraySectionOffset + common_encodings_byte_count) return error.InvalidUnwindInfo;315 if (unwind_info.len < header.commonEncodingsArraySectionOffset + common_encodings_byte_count) return error.InvalidDebugInfo;
303 const common_encodings: []align(1) const macho.compact_unwind_encoding_t = @ptrCast(316 const common_encodings: []align(1) const macho.compact_unwind_encoding_t = @ptrCast(
304 unwind_info[header.commonEncodingsArraySectionOffset..][0..common_encodings_byte_count],317 unwind_info[header.commonEncodingsArraySectionOffset..][0..common_encodings_byte_count],
305 );318 );
306319
307 if (unwind_info.len < start_offset + @sizeOf(macho.UNWIND_SECOND_LEVEL)) return error.InvalidUnwindInfo;320 if (unwind_info.len < start_offset + @sizeOf(macho.UNWIND_SECOND_LEVEL)) return error.InvalidDebugInfo;
308 const kind: *align(1) const macho.UNWIND_SECOND_LEVEL = @ptrCast(unwind_info[start_offset..]);321 const kind: *align(1) const macho.UNWIND_SECOND_LEVEL = @ptrCast(unwind_info[start_offset..]);
309322
310 const entry: struct {323 const entry: struct {
...@@ -312,15 +325,15 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -312,15 +325,15 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
312 raw_encoding: u32,325 raw_encoding: u32,
313 } = switch (kind.*) {326 } = switch (kind.*) {
314 .REGULAR => entry: {327 .REGULAR => entry: {
315 if (unwind_info.len < start_offset + @sizeOf(macho.unwind_info_regular_second_level_page_header)) return error.InvalidUnwindInfo;328 if (unwind_info.len < start_offset + @sizeOf(macho.unwind_info_regular_second_level_page_header)) return error.InvalidDebugInfo;
316 const page_header: *align(1) const macho.unwind_info_regular_second_level_page_header = @ptrCast(unwind_info[start_offset..]);329 const page_header: *align(1) const macho.unwind_info_regular_second_level_page_header = @ptrCast(unwind_info[start_offset..]);
317330
318 const entries_byte_count = page_header.entryCount * @sizeOf(macho.unwind_info_regular_second_level_entry);331 const entries_byte_count = page_header.entryCount * @sizeOf(macho.unwind_info_regular_second_level_entry);
319 if (unwind_info.len < start_offset + entries_byte_count) return error.InvalidUnwindInfo;332 if (unwind_info.len < start_offset + entries_byte_count) return error.InvalidDebugInfo;
320 const entries: []align(1) const macho.unwind_info_regular_second_level_entry = @ptrCast(333 const entries: []align(1) const macho.unwind_info_regular_second_level_entry = @ptrCast(
321 unwind_info[start_offset + page_header.entryPageOffset ..][0..entries_byte_count],334 unwind_info[start_offset + page_header.entryPageOffset ..][0..entries_byte_count],
322 );335 );
323 if (entries.len == 0) return error.InvalidUnwindInfo;336 if (entries.len == 0) return error.InvalidDebugInfo;
324337
325 var left: usize = 0;338 var left: usize = 0;
326 var len: usize = entries.len;339 var len: usize = entries.len;
...@@ -339,15 +352,15 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -339,15 +352,15 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
339 };352 };
340 },353 },
341 .COMPRESSED => entry: {354 .COMPRESSED => entry: {
342 if (unwind_info.len < start_offset + @sizeOf(macho.unwind_info_compressed_second_level_page_header)) return error.InvalidUnwindInfo;355 if (unwind_info.len < start_offset + @sizeOf(macho.unwind_info_compressed_second_level_page_header)) return error.InvalidDebugInfo;
343 const page_header: *align(1) const macho.unwind_info_compressed_second_level_page_header = @ptrCast(unwind_info[start_offset..]);356 const page_header: *align(1) const macho.unwind_info_compressed_second_level_page_header = @ptrCast(unwind_info[start_offset..]);
344357
345 const entries_byte_count = page_header.entryCount * @sizeOf(macho.UnwindInfoCompressedEntry);358 const entries_byte_count = page_header.entryCount * @sizeOf(macho.UnwindInfoCompressedEntry);
346 if (unwind_info.len < start_offset + entries_byte_count) return error.InvalidUnwindInfo;359 if (unwind_info.len < start_offset + entries_byte_count) return error.InvalidDebugInfo;
347 const entries: []align(1) const macho.UnwindInfoCompressedEntry = @ptrCast(360 const entries: []align(1) const macho.UnwindInfoCompressedEntry = @ptrCast(
348 unwind_info[start_offset + page_header.entryPageOffset ..][0..entries_byte_count],361 unwind_info[start_offset + page_header.entryPageOffset ..][0..entries_byte_count],
349 );362 );
350 if (entries.len == 0) return error.InvalidUnwindInfo;363 if (entries.len == 0) return error.InvalidDebugInfo;
351364
352 var left: usize = 0;365 var left: usize = 0;
353 var len: usize = entries.len;366 var len: usize = entries.len;
...@@ -372,26 +385,26 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -372,26 +385,26 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
372385
373 const local_index = entry.encodingIndex - common_encodings.len;386 const local_index = entry.encodingIndex - common_encodings.len;
374 const local_encodings_byte_count = page_header.encodingsCount * @sizeOf(macho.compact_unwind_encoding_t);387 const local_encodings_byte_count = page_header.encodingsCount * @sizeOf(macho.compact_unwind_encoding_t);
375 if (unwind_info.len < start_offset + page_header.encodingsPageOffset + local_encodings_byte_count) return error.InvalidUnwindInfo;388 if (unwind_info.len < start_offset + page_header.encodingsPageOffset + local_encodings_byte_count) return error.InvalidDebugInfo;
376 const local_encodings: []align(1) const macho.compact_unwind_encoding_t = @ptrCast(389 const local_encodings: []align(1) const macho.compact_unwind_encoding_t = @ptrCast(
377 unwind_info[start_offset + page_header.encodingsPageOffset ..][0..local_encodings_byte_count],390 unwind_info[start_offset + page_header.encodingsPageOffset ..][0..local_encodings_byte_count],
378 );391 );
379 if (local_index >= local_encodings.len) return error.InvalidUnwindInfo;392 if (local_index >= local_encodings.len) return error.InvalidDebugInfo;
380 break :entry .{393 break :entry .{
381 .function_offset = function_offset,394 .function_offset = function_offset,
382 .raw_encoding = local_encodings[local_index],395 .raw_encoding = local_encodings[local_index],
383 };396 };
384 },397 },
385 else => return error.InvalidUnwindInfo,398 else => return error.InvalidDebugInfo,
386 };399 };
387400
388 if (entry.raw_encoding == 0) return error.NoUnwindInfo;401 if (entry.raw_encoding == 0) return error.MissingDebugInfo;
389 const reg_context: Dwarf.abi.RegisterContext = .{ .eh_frame = false, .is_macho = true };402 const reg_context: Dwarf.abi.RegisterContext = .{ .eh_frame = false, .is_macho = true };
390403
391 const encoding: macho.CompactUnwindEncoding = @bitCast(entry.raw_encoding);404 const encoding: macho.CompactUnwindEncoding = @bitCast(entry.raw_encoding);
392 const new_ip = switch (builtin.cpu.arch) {405 const new_ip = switch (builtin.cpu.arch) {
393 .x86_64 => switch (encoding.mode.x86_64) {406 .x86_64 => switch (encoding.mode.x86_64) {
394 .OLD => return error.UnimplementedUnwindEncoding,407 .OLD => return error.UnsupportedDebugInfo,
395 .RBP_FRAME => ip: {408 .RBP_FRAME => ip: {
396 const frame = encoding.value.x86_64.frame;409 const frame = encoding.value.x86_64.frame;
397410
...@@ -493,7 +506,7 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -493,7 +506,7 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
493 break :ip new_ip;506 break :ip new_ip;
494 },507 },
495 .DWARF => {508 .DWARF => {
496 const eh_frame = unwind.eh_frame orelse return error.MissingEhFrame;509 const eh_frame = unwind.eh_frame orelse return error.MissingDebugInfo;
497 const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - module.load_offset;510 const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - module.load_offset;
498 return context.unwindFrameDwarf(511 return context.unwindFrameDwarf(
499 &.initSection(.eh_frame, eh_frame_vaddr, eh_frame),512 &.initSection(.eh_frame, eh_frame_vaddr, eh_frame),
...@@ -503,7 +516,7 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -503,7 +516,7 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
503 },516 },
504 },517 },
505 .aarch64, .aarch64_be => switch (encoding.mode.arm64) {518 .aarch64, .aarch64_be => switch (encoding.mode.arm64) {
506 .OLD => return error.UnimplementedUnwindEncoding,519 .OLD => return error.UnsupportedDebugInfo,
507 .FRAMELESS => ip: {520 .FRAMELESS => ip: {
508 const sp = (try regValueNative(context.thread_context, spRegNum(reg_context), reg_context)).*;521 const sp = (try regValueNative(context.thread_context, spRegNum(reg_context), reg_context)).*;
509 const new_sp = sp + encoding.value.arm64.frameless.stack_size * 16;522 const new_sp = sp + encoding.value.arm64.frameless.stack_size * 16;
...@@ -512,7 +525,7 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -512,7 +525,7 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
512 break :ip new_ip;525 break :ip new_ip;
513 },526 },
514 .DWARF => {527 .DWARF => {
515 const eh_frame = unwind.eh_frame orelse return error.MissingEhFrame;528 const eh_frame = unwind.eh_frame orelse return error.MissingDebugInfo;
516 const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - module.load_offset;529 const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - module.load_offset;
517 return context.unwindFrameDwarf(530 return context.unwindFrameDwarf(
518 &.initSection(.eh_frame, eh_frame_vaddr, eh_frame),531 &.initSection(.eh_frame, eh_frame_vaddr, eh_frame),
...@@ -568,8 +581,6 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,...@@ -568,8 +581,6 @@ pub fn unwindFrame(module: *const DarwinModule, gpa: Allocator, di: *DebugInfo,
568 if (context.pc > 0) context.pc -= 1;581 if (context.pc > 0) context.pc -= 1;
569 return new_ip;582 return new_ip;
570}583}
571/// No cache needed, because `_dyld_get_image_header` etc are already fast.
572pub const LookupCache = void;
573pub const DebugInfo = struct {584pub const DebugInfo = struct {
574 unwind: ?Unwind,585 unwind: ?Unwind,
575 // MLUGG TODO: awful field name586 // MLUGG TODO: awful field name
...@@ -785,7 +796,7 @@ const ip_reg_num = Dwarf.abi.ipRegNum(builtin.target.cpu.arch).?;...@@ -785,7 +796,7 @@ const ip_reg_num = Dwarf.abi.ipRegNum(builtin.target.cpu.arch).?;
785fn mapDebugInfoFile(path: []const u8) ![]align(std.heap.page_size_min) const u8 {796fn mapDebugInfoFile(path: []const u8) ![]align(std.heap.page_size_min) const u8 {
786 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {797 const file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
787 error.FileNotFound => return error.MissingDebugInfo,798 error.FileNotFound => return error.MissingDebugInfo,
788 else => |e| return e,799 else => return error.ReadFailed,
789 };800 };
790 defer file.close();801 defer file.close();
791802
...@@ -812,6 +823,7 @@ const mem = std.mem;...@@ -812,6 +823,7 @@ const mem = std.mem;
812const posix = std.posix;823const posix = std.posix;
813const testing = std.testing;824const testing = std.testing;
814const UnwindContext = std.debug.SelfInfo.UnwindContext;825const UnwindContext = std.debug.SelfInfo.UnwindContext;
826const Error = std.debug.SelfInfo.Error;
815const regBytes = Dwarf.abi.regBytes;827const regBytes = Dwarf.abi.regBytes;
816const regValueNative = Dwarf.abi.regValueNative;828const regValueNative = Dwarf.abi.regValueNative;
817829
lib/std/debug/SelfInfo/ElfModule.zig+63-25
...@@ -21,7 +21,7 @@ pub const DebugInfo = struct {...@@ -21,7 +21,7 @@ pub const DebugInfo = struct {
21pub fn key(m: ElfModule) usize {21pub fn key(m: ElfModule) usize {
22 return m.load_offset;22 return m.load_offset;
23}23}
24pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !ElfModule {24pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) Error!ElfModule {
25 _ = cache;25 _ = cache;
26 _ = gpa;26 _ = gpa;
27 if (builtin.target.os.tag == .haiku) @panic("TODO implement lookup module for Haiku");27 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 {...@@ -92,42 +92,79 @@ pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !ElfModule {
92 };92 };
93 return error.MissingDebugInfo;93 return error.MissingDebugInfo;
94}94}
95fn loadDwarf(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) !void {95fn loadDwarf(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) Error!void {
96 if (module.name.len > 0) {96 const load_result = if (module.name.len > 0) res: {
97 di.loaded_elf = Dwarf.ElfModule.load(gpa, .{97 break :res Dwarf.ElfModule.load(gpa, .{
98 .root_dir = .cwd(),98 .root_dir = .cwd(),
99 .sub_path = module.name,99 .sub_path = module.name,
100 }, module.build_id, null, null, null) catch |err| switch (err) {100 }, module.build_id, null, null, null);
101 error.FileNotFound => return error.MissingDebugInfo,101 } else res: {
102 error.Overflow => return error.InvalidDebugInfo,102 const path = std.fs.selfExePathAlloc(gpa) catch |err| switch (err) {
103 else => |e| return e,103 error.OutOfMemory => |e| return e,
104 else => return error.ReadFailed,
104 };105 };
105 } else {
106 const path = try std.fs.selfExePathAlloc(gpa);
107 defer gpa.free(path);106 defer gpa.free(path);
108 di.loaded_elf = Dwarf.ElfModule.load(gpa, .{107 break :res Dwarf.ElfModule.load(gpa, .{
109 .root_dir = .cwd(),108 .root_dir = .cwd(),
110 .sub_path = path,109 .sub_path = path,
111 }, module.build_id, null, null, null) catch |err| switch (err) {110 }, module.build_id, null, null, null);
112 error.FileNotFound => return error.MissingDebugInfo,111 };
113 error.Overflow => return error.InvalidDebugInfo,112 di.loaded_elf = load_result catch |err| switch (err) {
114 else => |e| return e,113 error.FileNotFound => return error.MissingDebugInfo,
115 };114
116 }115 error.OutOfMemory,
116 error.InvalidDebugInfo,
117 error.MissingDebugInfo,
118 error.Unexpected,
119 => |e| return e,
120
121 error.InvalidElfEndian,
122 error.InvalidElfMagic,
123 error.InvalidElfVersion,
124 error.InvalidUtf8,
125 error.InvalidWtf8,
126 error.EndOfStream,
127 error.Overflow,
128 error.UnimplementedDwarfForeignEndian, // this should be impossible as we're looking at the debug info for this process
129 => return error.InvalidDebugInfo,
130
131 else => return error.ReadFailed,
132 };
117}133}
118pub fn getSymbolAtAddress(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol {134pub fn getSymbolAtAddress(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, address: usize) Error!std.debug.Symbol {
119 if (di.loaded_elf == null) try module.loadDwarf(gpa, di);135 if (di.loaded_elf == null) try module.loadDwarf(gpa, di);
120 const vaddr = address - module.load_offset;136 const vaddr = address - module.load_offset;
121 return di.loaded_elf.?.dwarf.getSymbol(gpa, native_endian, vaddr);137 return di.loaded_elf.?.dwarf.getSymbol(gpa, native_endian, vaddr) catch |err| switch (err) {
138 error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory => |e| return e,
139 error.ReadFailed,
140 error.EndOfStream,
141 error.Overflow,
142 error.StreamTooLong,
143 => return error.InvalidDebugInfo,
144 };
122}145}
123fn loadUnwindInfo(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) !void {146fn loadUnwindInfo(module: *const ElfModule, gpa: Allocator, di: *DebugInfo) Error!void {
124 const section_bytes = module.gnu_eh_frame orelse return error.MissingUnwindInfo; // MLUGG TODO: load from file147 const section_bytes = module.gnu_eh_frame orelse return error.MissingDebugInfo; // MLUGG TODO: load from file
148
125 const section_vaddr: u64 = @intFromPtr(section_bytes.ptr) - module.load_offset;149 const section_vaddr: u64 = @intFromPtr(section_bytes.ptr) - module.load_offset;
126 const header: Dwarf.Unwind.EhFrameHeader = try .parse(section_vaddr, section_bytes, @sizeOf(usize), native_endian);150 const header = Dwarf.Unwind.EhFrameHeader.parse(section_vaddr, section_bytes, @sizeOf(usize), native_endian) catch |err| switch (err) {
127 di.unwind = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr));151 error.ReadFailed => unreachable, // it's all fixed buffers
128 try di.unwind.?.prepareLookup(gpa, @sizeOf(usize), native_endian);152 error.InvalidDebugInfo => |e| return e,
153 error.EndOfStream, error.Overflow => return error.InvalidDebugInfo,
154 error.UnsupportedAddrSize => return error.UnsupportedDebugInfo,
155 };
156
157 var unwind: Dwarf.Unwind = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr));
158 unwind.prepareLookup(gpa, @sizeOf(usize), native_endian) catch |err| switch (err) {
159 error.ReadFailed => unreachable, // it's all fixed buffers
160 error.InvalidDebugInfo, error.MissingDebugInfo, error.OutOfMemory => |e| return e,
161 error.EndOfStream, error.Overflow, error.StreamTooLong => return error.InvalidDebugInfo,
162 error.UnsupportedAddrSize, error.UnsupportedDwarfVersion => return error.UnsupportedDebugInfo,
163 };
164
165 di.unwind = unwind;
129}166}
130pub fn unwindFrame(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize {167pub fn unwindFrame(module: *const ElfModule, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) Error!usize {
131 if (di.unwind == null) try module.loadUnwindInfo(gpa, di);168 if (di.unwind == null) try module.loadUnwindInfo(gpa, di);
132 return context.unwindFrameDwarf(&di.unwind.?, module.load_offset, null);169 return context.unwindFrameDwarf(&di.unwind.?, module.load_offset, null);
133}170}
...@@ -140,6 +177,7 @@ const Dwarf = std.debug.Dwarf;...@@ -140,6 +177,7 @@ const Dwarf = std.debug.Dwarf;
140const elf = std.elf;177const elf = std.elf;
141const mem = std.mem;178const mem = std.mem;
142const UnwindContext = std.debug.SelfInfo.UnwindContext;179const UnwindContext = std.debug.SelfInfo.UnwindContext;
180const Error = std.debug.SelfInfo.Error;
143181
144const builtin = @import("builtin");182const builtin = @import("builtin");
145const native_endian = builtin.target.cpu.arch.endian();183const native_endian = builtin.target.cpu.arch.endian();
lib/std/debug/SelfInfo/WindowsModule.zig+12-7
...@@ -5,7 +5,7 @@ handle: windows.HMODULE,...@@ -5,7 +5,7 @@ handle: windows.HMODULE,
5pub fn key(m: WindowsModule) usize {5pub fn key(m: WindowsModule) usize {
6 return m.base_address;6 return m.base_address;
7}7}
8pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !WindowsModule {8pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) std.debug.SelfInfo.Error!WindowsModule {
9 if (lookupInCache(cache, address)) |m| return m;9 if (lookupInCache(cache, address)) |m| return m;
10 {10 {
11 // Check a new module hasn't been loaded11 // Check a new module hasn't been loaded
...@@ -29,18 +29,23 @@ pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !WindowsModul...@@ -29,18 +29,23 @@ pub fn lookup(cache: *LookupCache, gpa: Allocator, address: usize) !WindowsModul
29 if (lookupInCache(cache, address)) |m| return m;29 if (lookupInCache(cache, address)) |m| return m;
30 return error.MissingDebugInfo;30 return error.MissingDebugInfo;
31}31}
32pub fn getSymbolAtAddress(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol {32pub fn getSymbolAtAddress(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo, address: usize) std.debug.SelfInfo.Error!std.debug.Symbol {
33 if (!di.loaded) try module.loadLocationInfo(gpa, di);33 if (!di.loaded) module.loadDebugInfo(gpa, di) catch |err| switch (err) {
34 error.OutOfMemory, error.InvalidDebugInfo, error.MissingDebugInfo, error.Unexpected => |e| return e,
35 error.FileNotFound => return error.MissingDebugInfo,
36 error.UnknownPDBVersion => return error.UnsupportedDebugInfo,
37 else => return error.ReadFailed,
38 };
34 // Translate the runtime address into a virtual address into the module39 // Translate the runtime address into a virtual address into the module
35 const vaddr = address - module.base_address;40 const vaddr = address - module.base_address;
3641
37 if (di.pdb != null) {42 if (di.pdb != null) {
38 if (try di.getSymbolFromPdb(vaddr)) |symbol| return symbol;43 if (di.getSymbolFromPdb(vaddr) catch return error.InvalidDebugInfo) |symbol| return symbol;
39 }44 }
4045
41 if (di.dwarf) |*dwarf| {46 if (di.dwarf) |*dwarf| {
42 const dwarf_address = vaddr + di.coff_image_base;47 const dwarf_address = vaddr + di.coff_image_base;
43 return dwarf.getSymbol(gpa, native_endian, dwarf_address);48 return dwarf.getSymbol(gpa, native_endian, dwarf_address) catch return error.InvalidDebugInfo;
44 }49 }
4550
46 return error.MissingDebugInfo;51 return error.MissingDebugInfo;
...@@ -59,7 +64,7 @@ fn lookupInCache(cache: *const LookupCache, address: usize) ?WindowsModule {...@@ -59,7 +64,7 @@ fn lookupInCache(cache: *const LookupCache, address: usize) ?WindowsModule {
59 }64 }
60 return null;65 return null;
61}66}
62fn loadLocationInfo(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo) !void {67fn loadDebugInfo(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo) !void {
63 const mapped_ptr: [*]const u8 = @ptrFromInt(module.base_address);68 const mapped_ptr: [*]const u8 = @ptrFromInt(module.base_address);
64 const mapped = mapped_ptr[0..module.size];69 const mapped = mapped_ptr[0..module.size];
65 var coff_obj = coff.Coff.init(mapped, true) catch return error.InvalidDebugInfo;70 var coff_obj = coff.Coff.init(mapped, true) catch return error.InvalidDebugInfo;
...@@ -151,7 +156,7 @@ fn loadLocationInfo(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo...@@ -151,7 +156,7 @@ fn loadLocationInfo(module: *const WindowsModule, gpa: Allocator, di: *DebugInfo
151156
152 di.pdb = Pdb.init(gpa, path) catch |err| switch (err) {157 di.pdb = Pdb.init(gpa, path) catch |err| switch (err) {
153 error.FileNotFound, error.IsDir => break :pdb,158 error.FileNotFound, error.IsDir => break :pdb,
154 else => return err,159 else => |e| return e,
155 };160 };
156 try di.pdb.?.parseInfoStream();161 try di.pdb.?.parseInfoStream();
157 try di.pdb.?.parseDbiStream();162 try di.pdb.?.parseDbiStream();