| ... | @@ -159,7 +159,7 @@ pub fn copyContext(source: *const ThreadContext, dest: *ThreadContext) void { | ... | @@ -159,7 +159,7 @@ pub fn copyContext(source: *const ThreadContext, dest: *ThreadContext) void { |
| 159 | relocateContext(dest); | 159 | relocateContext(dest); |
| 160 | } | 160 | } |
| 161 | | 161 | |
| 162 | /// Updates any internal points in the context to reflect its current location | 162 | /// Updates any internal pointers in the context to reflect its current location |
| 163 | pub fn relocateContext(context: *ThreadContext) void { | 163 | pub fn relocateContext(context: *ThreadContext) void { |
| 164 | return switch (native_os) { | 164 | return switch (native_os) { |
| 165 | .macos => { | 165 | .macos => { |
| ... | @@ -176,7 +176,7 @@ pub const have_getcontext = @hasDecl(os.system, "getcontext") and | ... | @@ -176,7 +176,7 @@ pub const have_getcontext = @hasDecl(os.system, "getcontext") and |
| 176 | }); | 176 | }); |
| 177 | | 177 | |
| 178 | /// Capture the current context. The register values in the context will reflect the | 178 | /// Capture the current context. The register values in the context will reflect the |
| 179 | /// state after the platform `getcontext` function returned. | 179 | /// state after the platform `getcontext` function returns. |
| 180 | /// | 180 | /// |
| 181 | /// It is valid to call this if the platform doesn't have context capturing support, | 181 | /// It is valid to call this if the platform doesn't have context capturing support, |
| 182 | /// in that case false will be returned. | 182 | /// in that case false will be returned. |
| ... | @@ -229,7 +229,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void { | ... | @@ -229,7 +229,7 @@ pub fn dumpStackTraceFromBase(context: *const ThreadContext) void { |
| 229 | | 229 | |
| 230 | var it = StackIterator.initWithContext(null, debug_info, context) catch return; | 230 | var it = StackIterator.initWithContext(null, debug_info, context) catch return; |
| 231 | defer it.deinit(); | 231 | defer it.deinit(); |
| 232 | printSourceAtAddress(debug_info, stderr, it.dwarf_context.pc, tty_config) catch return; | 232 | printSourceAtAddress(debug_info, stderr, it.unwind_state.?.dwarf_context.pc, tty_config) catch return; |
| 233 | | 233 | |
| 234 | while (it.next()) |return_address| { | 234 | while (it.next()) |return_address| { |
| 235 | if (it.getLastError()) |unwind_error| | 235 | if (it.getLastError()) |unwind_error| |
| ... | @@ -487,11 +487,13 @@ pub const StackIterator = struct { | ... | @@ -487,11 +487,13 @@ pub const StackIterator = struct { |
| 487 | fp: usize, | 487 | fp: usize, |
| 488 | | 488 | |
| 489 | // When DebugInfo and a register context is available, this iterator can unwind | 489 | // When DebugInfo and a register context is available, this iterator can unwind |
| 490 | // stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer). | 490 | // stacks with frames that don't use a frame pointer (ie. -fomit-frame-pointer), |
| 491 | debug_info: ?*DebugInfo, | 491 | // using DWARF and MachO unwind info. |
| 492 | dwarf_context: if (have_ucontext) DW.UnwindContext else void = undefined, | 492 | unwind_state: if (have_ucontext) ?struct { |
| 493 | last_error: if (have_ucontext) ?UnwindError else void = undefined, | 493 | debug_info: *DebugInfo, |
| 494 | last_error_address: if (have_ucontext) usize else void = undefined, | 494 | dwarf_context: DW.UnwindContext, |
| | 495 | last_error: ?UnwindError = null, |
| | 496 | } else void = if (have_ucontext) null else {}, |
| 495 | | 497 | |
| 496 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { | 498 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { |
| 497 | if (native_arch == .sparc64) { | 499 | if (native_arch == .sparc64) { |
| ... | @@ -504,32 +506,33 @@ pub const StackIterator = struct { | ... | @@ -504,32 +506,33 @@ pub const StackIterator = struct { |
| 504 | return StackIterator{ | 506 | return StackIterator{ |
| 505 | .first_address = first_address, | 507 | .first_address = first_address, |
| 506 | .fp = fp orelse @frameAddress(), | 508 | .fp = fp orelse @frameAddress(), |
| 507 | .debug_info = null, | | |
| 508 | }; | 509 | }; |
| 509 | } | 510 | } |
| 510 | | 511 | |
| 511 | pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator { | 512 | pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator { |
| 512 | var iterator = init(first_address, null); | 513 | var iterator = init(first_address, null); |
| 513 | iterator.debug_info = debug_info; | 514 | iterator.unwind_state = .{ |
| 514 | iterator.dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context, &isValidMemory); | 515 | .debug_info = debug_info, |
| 515 | iterator.last_error = null; | 516 | .dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context, &isValidMemory), |
| | 517 | }; |
| | 518 | |
| 516 | return iterator; | 519 | return iterator; |
| 517 | } | 520 | } |
| 518 | | 521 | |
| 519 | pub fn deinit(self: *StackIterator) void { | 522 | pub fn deinit(self: *StackIterator) void { |
| 520 | if (have_ucontext and self.debug_info != null) self.dwarf_context.deinit(); | 523 | if (have_ucontext and self.unwind_state != null) self.unwind_state.?.dwarf_context.deinit(); |
| 521 | } | 524 | } |
| 522 | | 525 | |
| 523 | pub fn getLastError(self: *StackIterator) ?struct { | 526 | pub fn getLastError(self: *StackIterator) ?struct { |
| 524 | address: usize, | | |
| 525 | err: UnwindError, | 527 | err: UnwindError, |
| | 528 | address: usize, |
| 526 | } { | 529 | } { |
| 527 | if (have_ucontext) { | 530 | if (!have_ucontext) return null; |
| 528 | if (self.last_error) |err| { | 531 | if (self.unwind_state) |*unwind_state| { |
| 529 | self.last_error = null; | 532 | if (unwind_state.last_error) |err| { |
| 530 | return .{ | 533 | return .{ |
| 531 | .address = self.last_error_address, | | |
| 532 | .err = err, | 534 | .err = err, |
| | 535 | .address = unwind_state.dwarf_context.pc, |
| 533 | }; | 536 | }; |
| 534 | } | 537 | } |
| 535 | } | 538 | } |
| ... | @@ -620,13 +623,14 @@ pub const StackIterator = struct { | ... | @@ -620,13 +623,14 @@ pub const StackIterator = struct { |
| 620 | } | 623 | } |
| 621 | | 624 | |
| 622 | fn next_unwind(self: *StackIterator) !usize { | 625 | fn next_unwind(self: *StackIterator) !usize { |
| 623 | const module = try self.debug_info.?.getModuleForAddress(self.dwarf_context.pc); | 626 | const unwind_state = &self.unwind_state.?; |
| | 627 | const module = try unwind_state.debug_info.getModuleForAddress(unwind_state.dwarf_context.pc); |
| 624 | switch (native_os) { | 628 | switch (native_os) { |
| 625 | .macos, .ios, .watchos, .tvos => { | 629 | .macos, .ios, .watchos, .tvos => { |
| 626 | // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding | 630 | // __unwind_info is a requirement for unwinding on Darwin. It may fall back to DWARF, but unwinding |
| 627 | // via DWARF before attempting to use the compact unwind info will produce incorrect results. | 631 | // via DWARF before attempting to use the compact unwind info will produce incorrect results. |
| 628 | if (module.unwind_info) |unwind_info| { | 632 | if (module.unwind_info) |unwind_info| { |
| 629 | if (macho.unwindFrame(&self.dwarf_context, unwind_info, module.base_address)) |return_address| { | 633 | if (macho.unwindFrame(&unwind_state.dwarf_context, unwind_info, module.base_address)) |return_address| { |
| 630 | return return_address; | 634 | return return_address; |
| 631 | } else |err| { | 635 | } else |err| { |
| 632 | if (err != error.RequiresDWARFUnwind) return err; | 636 | if (err != error.RequiresDWARFUnwind) return err; |
| ... | @@ -636,23 +640,25 @@ pub const StackIterator = struct { | ... | @@ -636,23 +640,25 @@ pub const StackIterator = struct { |
| 636 | else => {}, | 640 | else => {}, |
| 637 | } | 641 | } |
| 638 | | 642 | |
| 639 | if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| { | 643 | if (try module.getDwarfInfoForAddress(unwind_state.debug_info.allocator, unwind_state.dwarf_context.pc)) |di| { |
| 640 | return di.unwindFrame(&self.dwarf_context, module.base_address); | 644 | return di.unwindFrame(&unwind_state.dwarf_context, module.base_address); |
| 641 | } else return error.MissingDebugInfo; | 645 | } else return error.MissingDebugInfo; |
| 642 | } | 646 | } |
| 643 | | 647 | |
| 644 | fn next_internal(self: *StackIterator) ?usize { | 648 | fn next_internal(self: *StackIterator) ?usize { |
| 645 | if (have_ucontext and self.debug_info != null) { | 649 | if (have_ucontext) { |
| 646 | if (self.dwarf_context.pc == 0) return null; | 650 | if (self.unwind_state) |*unwind_state| { |
| 647 | if (self.next_unwind()) |return_address| { | 651 | if (unwind_state.dwarf_context.pc == 0) return null; |
| 648 | return return_address; | 652 | if (unwind_state.last_error == null) { |
| 649 | } else |err| { | 653 | if (self.next_unwind()) |return_address| { |
| 650 | self.last_error = err; | 654 | return return_address; |
| 651 | self.last_error_address = self.dwarf_context.pc; | 655 | } else |err| { |
| 652 | | 656 | unwind_state.last_error = err; |
| 653 | // Fall back to fp unwinding on the first failure, as the register context won't have been updated | 657 | |
| 654 | self.fp = self.dwarf_context.getFp() catch 0; | 658 | // Fall back to fp-based unwinding on the first failure |
| 655 | self.debug_info = null; | 659 | self.fp = unwind_state.dwarf_context.getFp() catch 0; |
| | 660 | } |
| | 661 | } |
| 656 | } | 662 | } |
| 657 | } | 663 | } |
| 658 | | 664 | |
| ... | @@ -862,16 +868,12 @@ pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: us | ... | @@ -862,16 +868,12 @@ pub fn printUnwindError(debug_info: *DebugInfo, out_stream: anytype, address: us |
| 862 | pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void { | 868 | pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void { |
| 863 | const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { | 869 | const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { |
| 864 | error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), | 870 | error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), |
| 865 | else => { | 871 | else => return err, |
| 866 | return err; | | |
| 867 | }, | | |
| 868 | }; | 872 | }; |
| 869 | | 873 | |
| 870 | const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) { | 874 | const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) { |
| 871 | error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), | 875 | error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), |
| 872 | else => { | 876 | else => return err, |
| 873 | return err; | | |
| 874 | }, | | |
| 875 | }; | 877 | }; |
| 876 | defer symbol_info.deinit(debug_info.allocator); | 878 | defer symbol_info.deinit(debug_info.allocator); |
| 877 | | 879 | |