| ... | @@ -1086,10 +1086,12 @@ const StackIterator = union(enum) { | ... | @@ -1086,10 +1086,12 @@ const StackIterator = union(enum) { |
| 1086 | switch (it.*) { | 1086 | switch (it.*) { |
| 1087 | .ctx_first => |context_ptr| { | 1087 | .ctx_first => |context_ptr| { |
| 1088 | // After the first frame, start actually unwinding. | 1088 | // After the first frame, start actually unwinding. |
| 1089 | it.* = if (SelfInfo != void and SelfInfo.can_unwind and fp_usability != .ideal) | 1089 | if (SelfInfo != void and SelfInfo.can_unwind and fp_usability != .ideal) { |
| 1090 | .{ .di = .init(context_ptr) } | 1090 | it.* = .{ .di = .init(context_ptr) }; |
| 1091 | else | 1091 | } else { |
| 1092 | .{ .fp = context_ptr.getFp() }; | 1092 | const fp = applyOffset(context_ptr.getFp(), stack_bias) orelse return .end; |
| | 1093 | it.* = .{ .fp = fp }; |
| | 1094 | } |
| 1093 | | 1095 | |
| 1094 | // The caller expects *return* addresses, where they will subtract 1 to find the address of the call. | 1096 | // The caller expects *return* addresses, where they will subtract 1 to find the address of the call. |
| 1095 | // However, we have the actual current PC, which should not be adjusted. Compensate by adding 1. | 1097 | // However, we have the actual current PC, which should not be adjusted. Compensate by adding 1. |
| ... | @@ -1099,7 +1101,7 @@ const StackIterator = union(enum) { | ... | @@ -1099,7 +1101,7 @@ const StackIterator = union(enum) { |
| 1099 | const di = getSelfDebugInfo() catch unreachable; | 1101 | const di = getSelfDebugInfo() catch unreachable; |
| 1100 | const ret_addr = di.unwindFrame(io, unwind_context) catch |err| { | 1102 | const ret_addr = di.unwindFrame(io, unwind_context) catch |err| { |
| 1101 | const pc = unwind_context.pc; | 1103 | const pc = unwind_context.pc; |
| 1102 | const fp = unwind_context.getFp(); | 1104 | const fp = applyOffset(unwind_context.getFp(), stack_bias) orelse return .end; |
| 1103 | unwind_context.deinit(); | 1105 | unwind_context.deinit(); |
| 1104 | it.* = .{ .fp = fp }; | 1106 | it.* = .{ .fp = fp }; |
| 1105 | return .{ .switch_to_fp = .{ | 1107 | return .{ .switch_to_fp = .{ |
| ... | @@ -1647,21 +1649,6 @@ fn handleSegfaultPosix(sig: posix.SIG, info: *const posix.siginfo_t, ctx_ptr: ?* | ... | @@ -1647,21 +1649,6 @@ fn handleSegfaultPosix(sig: posix.SIG, info: *const posix.siginfo_t, ctx_ptr: ?* |
| 1647 | }; | 1649 | }; |
| 1648 | const opt_cpu_context: ?cpu_context.Native = cpu_context.fromPosixSignalContext(ctx_ptr); | 1650 | const opt_cpu_context: ?cpu_context.Native = cpu_context.fromPosixSignalContext(ctx_ptr); |
| 1649 | | 1651 | |
| 1650 | if (native_arch.isSPARC()) { | | |
| 1651 | // It's unclear to me whether this is a QEMU bug or also real kernel behavior, but in the | | |
| 1652 | // former, I observed that the most recent register window wasn't getting spilled on the | | |
| 1653 | // stack as expected when a signal arrived. A `flushw` from the signal handler does not | | |
| 1654 | // appear to be sufficient either. On the other hand, when doing a synchronous stack trace | | |
| 1655 | // and using `flushw`, this all appears to work as expected. So, *probably* a QEMU bug, but | | |
| 1656 | // someone with real SPARC hardware should verify. | | |
| 1657 | // | | |
| 1658 | // In any case, the register save area exists specifically so that register windows can be | | |
| 1659 | // spilled asynchronously. This means that it should be perfectly fine for us to manually do | | |
| 1660 | // so here. | | |
| 1661 | const ctx = opt_cpu_context.?; | | |
| 1662 | @as(*[16]usize, @ptrFromInt(ctx.o[6] + StackIterator.stack_bias)).* = ctx.l ++ ctx.i; | | |
| 1663 | } | | |
| 1664 | | | |
| 1665 | handleSegfault(addr, name, if (opt_cpu_context) |*ctx| ctx else null); | 1652 | handleSegfault(addr, name, if (opt_cpu_context) |*ctx| ctx else null); |
| 1666 | } | 1653 | } |
| 1667 | | 1654 | |