| ... | @@ -73,44 +73,26 @@ pub fn deinit(self: *SelfInfo) void { | ... | @@ -73,44 +73,26 @@ pub fn deinit(self: *SelfInfo) void { |
| 73 | | 73 | |
| 74 | pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usize { | 74 | pub fn unwindFrame(self: *SelfInfo, gpa: Allocator, context: *UnwindContext) !usize { |
| 75 | comptime assert(target_supported); | 75 | comptime assert(target_supported); |
| 76 | const module: Module = try .lookup(&self.lookup_cache, gpa, context.pc); // MLUGG TODO: don't take gpa | 76 | const module: Module = try .lookup(&self.lookup_cache, gpa, context.pc); |
| 77 | const gop = try self.modules.getOrPut(gpa, module.load_offset); | 77 | const gop = try self.modules.getOrPut(gpa, module.load_offset); |
| 78 | if (!gop.found_existing) gop.value_ptr.* = .init; | 78 | if (!gop.found_existing) gop.value_ptr.* = .init; |
| 79 | if (!gop.value_ptr.loaded_unwind) { | 79 | if (!gop.value_ptr.loaded_unwind) { |
| 80 | try module.loadUnwindInfo(gpa, &gop.value_ptr.di); | 80 | try module.loadUnwindInfo(gpa, &gop.value_ptr.di); |
| 81 | gop.value_ptr.loaded_unwind = true; | 81 | gop.value_ptr.loaded_unwind = true; |
| 82 | } | 82 | } |
| 83 | // MLUGG TODO: the stuff below is impl! | 83 | return module.unwindFrame(gpa, &gop.value_ptr.di, context); |
| 84 | if (native_os.isDarwin()) { | | |
| 85 | // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding | | |
| 86 | // via DWARF before attempting to use the compact unwind info will produce incorrect results. | | |
| 87 | if (gop.value_ptr.di.unwind_info) |unwind_info| { | | |
| 88 | if (unwindFrameMachO( | | |
| 89 | module.text_base, | | |
| 90 | module.load_offset, | | |
| 91 | context, | | |
| 92 | unwind_info, | | |
| 93 | gop.value_ptr.di.eh_frame, | | |
| 94 | )) |return_address| { | | |
| 95 | return return_address; | | |
| 96 | } else |err| { | | |
| 97 | if (err != error.RequiresDWARFUnwind) return err; | | |
| 98 | } | | |
| 99 | } | | |
| 100 | return error.MissingUnwindInfo; | | |
| 101 | } | | |
| 102 | return unwindFrameDwarf(&gop.value_ptr.di.unwind, module.load_offset, context, null); | | |
| 103 | } | 84 | } |
| 104 | | 85 | |
| 105 | pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std.debug.Symbol { | 86 | pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std.debug.Symbol { |
| 106 | comptime assert(target_supported); | 87 | comptime assert(target_supported); |
| 107 | const module: Module = try .lookup(&self.lookup_cache, gpa, address); // MLUGG TODO: don't take gpa | 88 | const module: Module = try .lookup(&self.lookup_cache, gpa, address); |
| 108 | const gop = try self.modules.getOrPut(gpa, module.key()); | 89 | const gop = try self.modules.getOrPut(gpa, module.key()); |
| 109 | if (!gop.found_existing) gop.value_ptr.* = .init; | 90 | if (!gop.found_existing) gop.value_ptr.* = .init; |
| 110 | if (!gop.value_ptr.loaded_debug) { | 91 | if (!gop.value_ptr.loaded_debug) { |
| 111 | // MLUGG TODO: this overloads the name 'debug info' with including vs excluding unwind info | 92 | // MLUGG TODO: this overloads the name 'debug info' with including vs excluding unwind info |
| 112 | // figure out a better name for one or the other (i think the inner one is maybe 'symbol info' or something idk) | 93 | // figure out a better name for one or the other (i think the inner one is maybe 'symbol info' or something idk) |
| 113 | try module.loadDebugInfo(gpa, &gop.value_ptr.di); | 94 | try module.loadDebugInfo(gpa, &gop.value_ptr.di); |
| | 95 | gop.value_ptr.loaded_debug = true; |
| 114 | } | 96 | } |
| 115 | return module.getSymbolAtAddress(gpa, &gop.value_ptr.di, address); | 97 | return module.getSymbolAtAddress(gpa, &gop.value_ptr.di, address); |
| 116 | } | 98 | } |
| ... | @@ -120,7 +102,7 @@ pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std. | ... | @@ -120,7 +102,7 @@ pub fn getSymbolAtAddress(self: *SelfInfo, gpa: Allocator, address: usize) !std. |
| 120 | /// a path that doesn't rely on any side-effects of a prior successful module lookup. | 102 | /// a path that doesn't rely on any side-effects of a prior successful module lookup. |
| 121 | pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize) error{ Unexpected, OutOfMemory, MissingDebugInfo }![]const u8 { | 103 | pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize) error{ Unexpected, OutOfMemory, MissingDebugInfo }![]const u8 { |
| 122 | comptime assert(target_supported); | 104 | comptime assert(target_supported); |
| 123 | const module: Module = try .lookup(&self.lookup_cache, gpa, address); // MLUGG TODO: don't take gpa | 105 | const module: Module = try .lookup(&self.lookup_cache, gpa, address); |
| 124 | return module.name; | 106 | return module.name; |
| 125 | } | 107 | } |
| 126 | | 108 | |
| ... | @@ -251,6 +233,18 @@ const Module = switch (native_os) { | ... | @@ -251,6 +233,18 @@ const Module = switch (native_os) { |
| 251 | }, | 233 | }, |
| 252 | }; | 234 | }; |
| 253 | } | 235 | } |
| | 236 | fn unwindFrame(module: *const Module, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize { |
| | 237 | _ = gpa; |
| | 238 | const unwind_info = di.unwind_info orelse return error.MissingUnwindInfo; |
| | 239 | // MLUGG TODO: inline |
| | 240 | return unwindFrameMachO( |
| | 241 | module.text_base, |
| | 242 | module.load_offset, |
| | 243 | context, |
| | 244 | unwind_info, |
| | 245 | di.eh_frame, |
| | 246 | ); |
| | 247 | } |
| 254 | const LookupCache = void; | 248 | const LookupCache = void; |
| 255 | const DebugInfo = struct { | 249 | const DebugInfo = struct { |
| 256 | mapped_memory: []align(std.heap.page_size_min) const u8, | 250 | mapped_memory: []align(std.heap.page_size_min) const u8, |
| ... | @@ -499,12 +493,16 @@ const Module = switch (native_os) { | ... | @@ -499,12 +493,16 @@ const Module = switch (native_os) { |
| 499 | const section_bytes = module.gnu_eh_frame orelse return error.MissingUnwindInfo; // MLUGG TODO: load from file | 493 | const section_bytes = module.gnu_eh_frame orelse return error.MissingUnwindInfo; // MLUGG TODO: load from file |
| 500 | const section_vaddr: u64 = @intFromPtr(section_bytes.ptr) - module.load_offset; | 494 | const section_vaddr: u64 = @intFromPtr(section_bytes.ptr) - module.load_offset; |
| 501 | const header: Dwarf.Unwind.EhFrameHeader = try .parse(section_vaddr, section_bytes, @sizeOf(usize), native_endian); | 495 | const header: Dwarf.Unwind.EhFrameHeader = try .parse(section_vaddr, section_bytes, @sizeOf(usize), native_endian); |
| 502 | try di.unwind.loadFromEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr)); | 496 | di.unwind = .initEhFrameHdr(header, section_vaddr, @ptrFromInt(module.load_offset + header.eh_frame_vaddr)); |
| 503 | try di.unwind.prepareLookup(gpa, @sizeOf(usize), native_endian); | 497 | try di.unwind.prepareLookup(gpa, @sizeOf(usize), native_endian); |
| 504 | } | 498 | } |
| 505 | fn getSymbolAtAddress(module: *const Module, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol { | 499 | fn getSymbolAtAddress(module: *const Module, gpa: Allocator, di: *DebugInfo, address: usize) !std.debug.Symbol { |
| 506 | return di.em.getSymbolAtAddress(gpa, native_endian, module.load_offset, address); | 500 | return di.em.getSymbolAtAddress(gpa, native_endian, module.load_offset, address); |
| 507 | } | 501 | } |
| | 502 | fn unwindFrame(module: *const Module, gpa: Allocator, di: *DebugInfo, context: *UnwindContext) !usize { |
| | 503 | _ = gpa; |
| | 504 | return unwindFrameDwarf(&di.unwind, module.load_offset, context, null); |
| | 505 | } |
| 508 | }, | 506 | }, |
| 509 | .uefi, .windows => struct { | 507 | .uefi, .windows => struct { |
| 510 | base_address: usize, | 508 | base_address: usize, |
| ... | @@ -1507,9 +1505,12 @@ fn unwindFrameMachO( | ... | @@ -1507,9 +1505,12 @@ fn unwindFrameMachO( |
| 1507 | .DWARF => { | 1505 | .DWARF => { |
| 1508 | const eh_frame = opt_eh_frame orelse return error.MissingEhFrame; | 1506 | const eh_frame = opt_eh_frame orelse return error.MissingEhFrame; |
| 1509 | const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - load_offset; | 1507 | const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - load_offset; |
| 1510 | var dwarf_unwind: Dwarf.Unwind = .init; | 1508 | return unwindFrameDwarf( |
| 1511 | dwarf_unwind.loadFromSection(.eh_frame, eh_frame_vaddr, eh_frame); | 1509 | &.initSection(.eh_frame, eh_frame_vaddr, eh_frame), |
| 1512 | return unwindFrameDwarf(&dwarf_unwind, load_offset, context, @intCast(encoding.value.x86_64.dwarf)); | 1510 | load_offset, |
| | 1511 | context, |
| | 1512 | @intCast(encoding.value.x86_64.dwarf), |
| | 1513 | ); |
| 1513 | }, | 1514 | }, |
| 1514 | }, | 1515 | }, |
| 1515 | .aarch64, .aarch64_be => switch (encoding.mode.arm64) { | 1516 | .aarch64, .aarch64_be => switch (encoding.mode.arm64) { |
| ... | @@ -1524,9 +1525,12 @@ fn unwindFrameMachO( | ... | @@ -1524,9 +1525,12 @@ fn unwindFrameMachO( |
| 1524 | .DWARF => { | 1525 | .DWARF => { |
| 1525 | const eh_frame = opt_eh_frame orelse return error.MissingEhFrame; | 1526 | const eh_frame = opt_eh_frame orelse return error.MissingEhFrame; |
| 1526 | const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - load_offset; | 1527 | const eh_frame_vaddr = @intFromPtr(eh_frame.ptr) - load_offset; |
| 1527 | var dwarf_unwind: Dwarf.Unwind = .init; | 1528 | return unwindFrameDwarf( |
| 1528 | dwarf_unwind.loadFromSection(.eh_frame, eh_frame_vaddr, eh_frame); | 1529 | &.initSection(.eh_frame, eh_frame_vaddr, eh_frame), |
| 1529 | return unwindFrameDwarf(dwarf_unwind, load_offset, context, @intCast(encoding.value.arm64.dwarf)); | 1530 | load_offset, |
| | 1531 | context, |
| | 1532 | @intCast(encoding.value.x86_64.dwarf), |
| | 1533 | ); |
| 1530 | }, | 1534 | }, |
| 1531 | .FRAME => ip: { | 1535 | .FRAME => ip: { |
| 1532 | const frame = encoding.value.arm64.frame; | 1536 | const frame = encoding.value.arm64.frame; |