@@ -617,7 +617,7 @@ pub const StackUnwindOptions = struct {
617617pub noinline fn captureCurrentStackTrace (options : StackUnwindOptions , addr_buf : []usize ) StackTrace {
618618 const empty_trace : StackTrace = .{ .index = 0 , .instruction_addresses = &.{} };
619619 if (! std .options .allow_stack_tracing ) return empty_trace ;
620- var it = StackIterator .init (options .context ) catch return empty_trace ;
620+ var it : StackIterator = .init (options .context );
621621 defer it .deinit ();
622622 if (! it .stratOk (options .allow_unsafe_unwind )) return empty_trace ;
623623 var total_frames : usize = 0 ;
@@ -671,14 +671,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri
671671 return ;
672672 },
673673 };
674- var it = StackIterator .init (options .context ) catch | err | switch (err ) {
675- error .CannotUnwindFromContext = > {
676- tty_config .setColor (writer , .dim ) catch {};
677- try writer .print ("Cannot print stack trace: context unwind unavailable for target\n " , .{});
678- tty_config .setColor (writer , .reset ) catch {};
679- return ;
680- },
681- };
674+ var it : StackIterator = .init (options .context );
682675 defer it .deinit ();
683676 if (! it .stratOk (options .allow_unsafe_unwind )) {
684677 tty_config .setColor (writer , .dim ) catch {};
@@ -821,22 +814,32 @@ pub fn dumpStackTrace(st: *const StackTrace) void {
821814}
822815
823816const StackIterator = union (enum ) {
817+ /// We will first report the current PC of this `CpuContextPtr`, then we will switch to a
818+ /// different strategy to actually unwind.
819+ ctx_first : CpuContextPtr ,
824820 /// Unwinding using debug info (e.g. DWARF CFI).
825- di : if (SelfInfo != void and SelfInfo .can_unwind ) SelfInfo .UnwindContext else noreturn ,
826- /// We will first report the *current* PC of this `UnwindContext`, then we will switch to `di`.
827- di_first : if (SelfInfo != void and SelfInfo .can_unwind ) SelfInfo .UnwindContext else noreturn ,
821+ di : if (SelfInfo != void and SelfInfo .can_unwind and fp_usability != .ideal )
822+ SelfInfo .UnwindContext
823+ else
824+ noreturn ,
828825 /// Naive frame-pointer-based unwinding. Very simple, but typically unreliable.
829826 fp : usize ,
830827
831828 /// It is important that this function is marked `inline` so that it can safely use
832829 /// `@frameAddress` and `cpu_context.Native.current` as the caller's stack frame and
833830 /// our own are one and the same.
834- inline fn init (opt_context_ptr : ? CpuContextPtr ) error {CannotUnwindFromContext }! StackIterator {
831+ ///
832+ /// `opt_context_ptr` must remain valid while the `StackIterator` is used.
833+ inline fn init (opt_context_ptr : ? CpuContextPtr ) StackIterator {
835834 if (opt_context_ptr ) | context_ptr | {
836- if (SelfInfo == void or ! SelfInfo .can_unwind ) return error .CannotUnwindFromContext ;
837- // Use `di_first` here so we report the PC in the context before unwinding any further.
838- return .{ .di_first = .init (context_ptr ) };
835+ // Use `ctx_first` here so we report the PC in the context before unwinding any further.
836+ return .{ .ctx_first = context_ptr };
839837 }
838+
839+ // Otherwise, we're going to capture the current context or frame address, so we don't need
840+ // `ctx_first`, because the first PC is in `std.debug` and we need to unwind before reaching
841+ // a frame we want to report.
842+
840843 // Workaround the C backend being unable to use inline assembly on MSVC by disabling the
841844 // call to `current`. This effectively constrains stack trace collection and dumping to FP
842845 // unwinding when building with CBE for MSVC.
@@ -846,8 +849,6 @@ const StackIterator = union(enum) {
846849 cpu_context .Native != noreturn and
847850 fp_usability != .ideal )
848851 {
849- // We don't need `di_first` here, because our PC is in `std.debug`; we're only interested
850- // in our caller's frame and above.
851852 return .{ .di = .init (&.current ()) };
852853 }
853854 return .{
@@ -866,8 +867,9 @@ const StackIterator = union(enum) {
866867 }
867868 fn deinit (si : * StackIterator ) void {
868869 switch (si .* ) {
870+ .ctx_first = > {},
869871 .fp = > {},
870- .di , .di_first = > | * unwind_context | unwind_context .deinit (getDebugInfoAllocator ()),
872+ .di = > | * unwind_context | unwind_context .deinit (getDebugInfoAllocator ()),
871873 }
872874 }
873875
@@ -931,7 +933,7 @@ const StackIterator = union(enum) {
931933 /// Whether the current unwind strategy is allowed given `allow_unsafe`.
932934 fn stratOk (it : * const StackIterator , allow_unsafe : bool ) bool {
933935 return switch (it .* ) {
934- .di , .di_first = > true ,
936+ .ctx_first , .di = > true ,
935937 // If we omitted frame pointers from *this* compilation, FP unwinding would crash
936938 // immediately regardless of anything. But FPs could also be omitted from a different
937939 // linked object, so it's not guaranteed to be safe, unless the target specifically
@@ -959,13 +961,16 @@ const StackIterator = union(enum) {
959961
960962 fn next (it : * StackIterator ) Result {
961963 switch (it .* ) {
962- .di_first = > | unwind_context | {
963- const first_pc = unwind_context .pc ;
964- if (first_pc == 0 ) return .end ;
965- it .* = .{ .di = unwind_context };
964+ .ctx_first = > | context_ptr | {
965+ // After the first frame, start actually unwinding.
966+ it .* = if (SelfInfo != void and SelfInfo .can_unwind and fp_usability != .ideal )
967+ .{ .di = .init (context_ptr ) }
968+ else
969+ .{ .fp = context_ptr .getFp () };
970+
966971 // The caller expects *return* addresses, where they will subtract 1 to find the address of the call.
967972 // However, we have the actual current PC, which should not be adjusted. Compensate by adding 1.
968- return .{ .frame = first_pc + | 1 };
973+ return .{ .frame = context_ptr . getPc () + | 1 };
969974 },
970975 .di = > | * unwind_context | {
971976 const di = getSelfDebugInfo () catch unreachable ;
0 commit comments