| author | |
| committer | |
| log | ba813d00f57542483cac108223c7b2c4353c14e0 |
| tree | fc2e1e789b084afe26f608a174eee9696c96d6f4 |
| parent | ec96095efd8671ae280df15eaf73f63bf029fbfa |
3 files changed, 34 insertions(+), 6 deletions(-)
lib/std/dwarf.zig+7-3| ... | ... | @@ -1758,12 +1758,16 @@ pub const DwarfInfo = struct { |
| 1758 | 1758 | } |
| 1759 | 1759 | |
| 1760 | 1760 | if (has_next_ip) { |
| 1761 | context.pc = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, cie.return_address_register, context.reg_context)); | |
| 1761 | context.pc = abi.stripInstructionPtrAuthCode(mem.readIntSliceNative(usize, try abi.regBytes( | |
| 1762 | context.thread_context, | |
| 1763 | cie.return_address_register, | |
| 1764 | context.reg_context, | |
| 1765 | ))); | |
| 1762 | 1766 | } else { |
| 1763 | 1767 | context.pc = 0; |
| 1764 | 1768 | } |
| 1765 | 1769 | |
| 1766 | mem.writeIntSliceNative(usize, try abi.regBytes(context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?); | |
| 1770 | (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?; | |
| 1767 | 1771 | |
| 1768 | 1772 | // The call instruction will have pushed the address of the instruction that follows the call as the return address |
| 1769 | 1773 | // However, this return address may be past the end of the function if the caller was `noreturn`. By subtracting one, |
| ... | ... | @@ -1786,7 +1790,7 @@ pub const UnwindContext = struct { |
| 1786 | 1790 | stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{}, |
| 1787 | 1791 | |
| 1788 | 1792 | pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext { |
| 1789 | const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null)); | |
| 1793 | const pc = abi.stripInstructionPtrAuthCode((try abi.regValueNative(usize, thread_context, abi.ipRegNum(), null)).*); | |
| 1790 | 1794 | |
| 1791 | 1795 | const context_copy = try allocator.create(debug.ThreadContext); |
| 1792 | 1796 | debug.copyContext(thread_context, context_copy); |
lib/std/dwarf/abi.zig+26-2| ... | ... | @@ -45,6 +45,27 @@ pub fn spRegNum(reg_context: RegisterContext) u8 { |
| 45 | 45 | }; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | /// Some platforms use pointer authentication - the upper bits of instruction pointers contain a signature. | |
| 49 | /// This function clears these signature bits to make the pointer usable. | |
| 50 | pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { | |
| 51 | if (builtin.cpu.arch == .aarch64) { | |
| 52 | // `hint 0x07` maps to `xpaclri` (or `nop` if the hardware doesn't support it) | |
| 53 | // The save / restore is because `xpaclri` operates on x30 (LR) | |
| 54 | return asm ( | |
| 55 | \\mov x16, x30 | |
| 56 | \\mov x30, x15 | |
| 57 | \\hint 0x07 | |
| 58 | \\mov x15, x30 | |
| 59 | \\mov x30, x16 | |
| 60 | : [ret] "={x15}" (-> usize), | |
| 61 | : [ptr] "{x15}" (ptr), | |
| 62 | : "x16" | |
| 63 | ); | |
| 64 | } | |
| 65 | ||
| 66 | return ptr; | |
| 67 | } | |
| 68 | ||
| 48 | 69 | pub const RegisterContext = struct { |
| 49 | 70 | eh_frame: bool, |
| 50 | 71 | is_macho: bool, |
| ... | ... | @@ -160,7 +181,6 @@ pub fn regBytes( |
| 160 | 181 | if (!std.debug.have_ucontext) return error.ThreadContextNotSupported; |
| 161 | 182 | |
| 162 | 183 | const ucontext_ptr = thread_context_ptr; |
| 163 | var m = &ucontext_ptr.mcontext; | |
| 164 | 184 | return switch (builtin.cpu.arch) { |
| 165 | 185 | .x86 => switch (builtin.os.tag) { |
| 166 | 186 | .linux, .netbsd, .solaris => switch (reg_number) { |
| ... | ... | @@ -216,7 +236,7 @@ pub fn regBytes( |
| 216 | 236 | 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]), |
| 217 | 237 | 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]), |
| 218 | 238 | 16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]), |
| 219 | 17...32 => |i| mem.asBytes(&m.fpregs.xmm[i - 17]), | |
| 239 | 17...32 => |i| mem.asBytes(&ucontext_ptr.mcontext.fpregs.xmm[i - 17]), | |
| 220 | 240 | else => error.InvalidRegister, |
| 221 | 241 | }, |
| 222 | 242 | .freebsd => switch (reg_number) { |
| ... | ... | @@ -313,6 +333,10 @@ pub fn regBytes( |
| 313 | 333 | 30 => mem.asBytes(&ucontext_ptr.mcontext.ss.lr), |
| 314 | 334 | 31 => mem.asBytes(&ucontext_ptr.mcontext.ss.sp), |
| 315 | 335 | 32 => mem.asBytes(&ucontext_ptr.mcontext.ss.pc), |
| 336 | ||
| 337 | // TODO: Find storage for this state | |
| 338 | //34 => mem.asBytes(&ucontext_ptr.ra_sign_state), | |
| 339 | ||
| 316 | 340 | // V0-V31 |
| 317 | 341 | 64...95 => mem.asBytes(&ucontext_ptr.mcontext.ns.q[reg_number - 64]), |
| 318 | 342 | else => error.InvalidRegister, |
lib/std/macho.zig+1-1| ... | ... | @@ -2459,7 +2459,7 @@ pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, modul |
| 2459 | 2459 | else => return error.UnimplementedArch, |
| 2460 | 2460 | }; |
| 2461 | 2461 | |
| 2462 | context.pc = new_ip; | |
| 2462 | context.pc = dwarf.abi.stripInstructionPtrAuthCode(new_ip); | |
| 2463 | 2463 | if (context.pc > 0) context.pc -= 1; |
| 2464 | 2464 | return new_ip; |
| 2465 | 2465 | } |