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