From 01417356c9662773bf0b9ef0a3ef4c45d69eb52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 18 Oct 2026 17:02:58 +0200 Subject: [PATCH 1/4] std.macho: add new UNWIND_ARM64_MODE.FRAME_PAUTH_LR tag --- lib/std/macho.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/std/macho.zig b/lib/std/macho.zig index 8a2a90438ab3c090d02debb9ce7a81f15dfb0294..b0e5aaa32f6a4ab24187f472999cb75c06b9c411 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -2137,6 +2137,7 @@ pub const UNWIND_ARM64_MODE = enum(u4) { FRAMELESS = 2, DWARF = 3, FRAME = 4, + FRAME_PAUTH_LR = 5, }; pub const UNWIND_ARM64_FRAME_X19_X20_PAIR: u32 = 0x00000001; -- 2.54.0 From f03e7e318a3205b0e82751af541dbf7a0a633d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 18 Oct 2026 17:03:22 +0200 Subject: [PATCH 2/4] std.debug.SelfInfo.MachO: handle new UNWIND_ARM64_MODE.FRAME_PAUTH_LR --- lib/std/debug/SelfInfo/MachO.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index 22430159cfd00e1efa57933a70af214b4b3803c3..59b9a524b01d4f68d5b8854d1b64d70bbb4fba9f 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -417,7 +417,7 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize { const rules = try context.computeRules(gpa, dwarf, unwind.vmaddr_slide, encoding.value.arm64.dwarf); return context.next(gpa, &rules); }, - .FRAME => ip: { + .FRAME, .FRAME_PAUTH_LR => ip: { const frame = encoding.value.arm64.frame; const fp = (try dwarfRegNative(&context.cpu_state, fp_reg_num)).*; -- 2.54.0 From 701b4e10c670e550a878ce9a0e422c61cf14c29a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 18 Oct 2026 17:16:00 +0200 Subject: [PATCH 3/4] std.macho: fix CompactUnwindEncoding.value.arm64.frame layout --- lib/std/macho.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/macho.zig b/lib/std/macho.zig index b0e5aaa32f6a4ab24187f472999cb75c06b9c411..340ed9b380f3bdaf3c4c98198ad8194a78f5c688 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -2190,13 +2190,14 @@ pub const CompactUnwindEncoding = packed struct(u32) { x25_x26: u1, x27_x28: u1, }, + unused: u3 = 0, d_reg_pairs: packed struct(u4) { d8_d9: u1, d10_d11: u1, d12_d13: u1, d14_d15: u1, }, - _: u15, + _: u12, }, frameless: packed struct(u24) { _: u12 = 0, -- 2.54.0 From 26500dafe53d1e4215adb411045d1680f75da685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sun, 18 Oct 2026 17:19:27 +0200 Subject: [PATCH 4/4] std.debug.SelfInfo.MachO: fix xreg/dreg restore logic in compact unwinding The old logic advanced in the wrong direction and also overwrote one register in consecutive pairs. I'm not aware of any case where this matters in practice since macOS mandates the use of an FP register on AArch64, but we should still get it right. --- lib/std/debug/SelfInfo/MachO.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index 59b9a524b01d4f68d5b8854d1b64d70bbb4fba9f..f68572d1ca07fab3f0a9249f1bdf42c85ba9ee2e 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -426,10 +426,10 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize { var reg_addr = fp - @sizeOf(usize); inline for (@typeInfo(@TypeOf(frame.x_reg_pairs)).@"struct".field_names, 0..) |field_name, i| { if (@field(frame.x_reg_pairs, field_name) != 0) { - (try dwarfRegNative(&context.cpu_state, 19 + i)).* = @as(*const usize, @ptrFromInt(reg_addr)).*; - reg_addr += @sizeOf(usize); - (try dwarfRegNative(&context.cpu_state, 20 + i)).* = @as(*const usize, @ptrFromInt(reg_addr)).*; - reg_addr += @sizeOf(usize); + (try dwarfRegNative(&context.cpu_state, 19 + i * 2)).* = @as(*const usize, @ptrFromInt(reg_addr)).*; + reg_addr -= @sizeOf(usize); + (try dwarfRegNative(&context.cpu_state, 20 + i * 2)).* = @as(*const usize, @ptrFromInt(reg_addr)).*; + reg_addr -= @sizeOf(usize); } } @@ -437,7 +437,7 @@ fn unwindFrameInner(si: *SelfInfo, io: Io, context: *UnwindContext) !usize { // vector registers in the AArch64 `cpu_context` anyway, so there's no reason to // fail a legitimate unwind just because we're asked to restore the registers here. // If some weird/broken unwind info tells us to read them later, we will fail then. - reg_addr += 16 * @as(usize, @popCount(@as(u4, @bitCast(frame.d_reg_pairs)))); + reg_addr -= 16 * @as(usize, @popCount(@as(u4, @bitCast(frame.d_reg_pairs)))); const new_ip = @as(*const usize, @ptrFromInt(ip_ptr)).*; const new_fp = @as(*const usize, @ptrFromInt(fp)).*; -- 2.54.0