authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-31 02:06:47+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-08-31 02:06:47+02:00
logde39011a2da6bc786af5c26d63d5ee7711c63e88
tree65a364a5db87c477a6c207f5602ad8e64628da9a
parenta0e17b82c8ebab4d78ca8b16748246870fff2ec4
parentfb1e767ff8a6f4c32865020e36df4038434ecc65

Merge pull request '`std.debug`: apply stack bias to the frame pointer fetched from the CPU context' (#36667) from alexrp/zig:sparc-unwind-fix into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36667

1 files changed, 7 insertions(+), 20 deletions(-)

lib/std/debug.zig+7-20
......@@ -1086,10 +1086,12 @@ const StackIterator = union(enum) {
10861086 switch (it.*) {
10871087 .ctx_first => |context_ptr| {
10881088 // After the first frame, start actually unwinding.
1089 it.* = if (SelfInfo != void and SelfInfo.can_unwind and fp_usability != .ideal)
1090 .{ .di = .init(context_ptr) }
1091 else
1092 .{ .fp = context_ptr.getFp() };
1089 if (SelfInfo != void and SelfInfo.can_unwind and fp_usability != .ideal) {
1090 it.* = .{ .di = .init(context_ptr) };
1091 } else {
1092 const fp = applyOffset(context_ptr.getFp(), stack_bias) orelse return .end;
1093 it.* = .{ .fp = fp };
1094 }
10931095
10941096 // The caller expects *return* addresses, where they will subtract 1 to find the address of the call.
10951097 // However, we have the actual current PC, which should not be adjusted. Compensate by adding 1.
......@@ -1099,7 +1101,7 @@ const StackIterator = union(enum) {
10991101 const di = getSelfDebugInfo() catch unreachable;
11001102 const ret_addr = di.unwindFrame(io, unwind_context) catch |err| {
11011103 const pc = unwind_context.pc;
1102 const fp = unwind_context.getFp();
1104 const fp = applyOffset(unwind_context.getFp(), stack_bias) orelse return .end;
11031105 unwind_context.deinit();
11041106 it.* = .{ .fp = fp };
11051107 return .{ .switch_to_fp = .{
......@@ -1647,21 +1649,6 @@ fn handleSegfaultPosix(sig: posix.SIG, info: *const posix.siginfo_t, ctx_ptr: ?*
16471649 };
16481650 const opt_cpu_context: ?cpu_context.Native = cpu_context.fromPosixSignalContext(ctx_ptr);
16491651
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
16651652 handleSegfault(addr, name, if (opt_cpu_context) |*ctx| ctx else null);
16661653}
16671654