| 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,12 +1758,16 @@ pub const DwarfInfo = struct { |
| 1758 | } | 1758 | } |
| 1759 | 1759 | ||
| 1760 | if (has_next_ip) { | 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 | } else { | 1766 | } else { |
| 1763 | context.pc = 0; | 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 | // The call instruction will have pushed the address of the instruction that follows the call as the return address | 1772 | // The call instruction will have pushed the address of the instruction that follows the call as the return address |
| 1769 | // However, this return address may be past the end of the function if the caller was `noreturn`. By subtracting one, | 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,7 +1790,7 @@ pub const UnwindContext = struct { |
| 1786 | stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{}, | 1790 | stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{}, |
| 1787 | 1791 | ||
| 1788 | pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext { | 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 | const context_copy = try allocator.create(debug.ThreadContext); | 1795 | const context_copy = try allocator.create(debug.ThreadContext); |
| 1792 | debug.copyContext(thread_context, context_copy); | 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,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 | pub const RegisterContext = struct { | 69 | pub const RegisterContext = struct { |
| 49 | eh_frame: bool, | 70 | eh_frame: bool, |
| 50 | is_macho: bool, | 71 | is_macho: bool, |
| ... | @@ -160,7 +181,6 @@ pub fn regBytes( | ... | @@ -160,7 +181,6 @@ pub fn regBytes( |
| 160 | if (!std.debug.have_ucontext) return error.ThreadContextNotSupported; | 181 | if (!std.debug.have_ucontext) return error.ThreadContextNotSupported; |
| 161 | 182 | ||
| 162 | const ucontext_ptr = thread_context_ptr; | 183 | const ucontext_ptr = thread_context_ptr; |
| 163 | var m = &ucontext_ptr.mcontext; | ||
| 164 | return switch (builtin.cpu.arch) { | 184 | return switch (builtin.cpu.arch) { |
| 165 | .x86 => switch (builtin.os.tag) { | 185 | .x86 => switch (builtin.os.tag) { |
| 166 | .linux, .netbsd, .solaris => switch (reg_number) { | 186 | .linux, .netbsd, .solaris => switch (reg_number) { |
| ... | @@ -216,7 +236,7 @@ pub fn regBytes( | ... | @@ -216,7 +236,7 @@ pub fn regBytes( |
| 216 | 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]), | 236 | 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]), |
| 217 | 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]), | 237 | 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]), |
| 218 | 16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]), | 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 | else => error.InvalidRegister, | 240 | else => error.InvalidRegister, |
| 221 | }, | 241 | }, |
| 222 | .freebsd => switch (reg_number) { | 242 | .freebsd => switch (reg_number) { |
| ... | @@ -313,6 +333,10 @@ pub fn regBytes( | ... | @@ -313,6 +333,10 @@ pub fn regBytes( |
| 313 | 30 => mem.asBytes(&ucontext_ptr.mcontext.ss.lr), | 333 | 30 => mem.asBytes(&ucontext_ptr.mcontext.ss.lr), |
| 314 | 31 => mem.asBytes(&ucontext_ptr.mcontext.ss.sp), | 334 | 31 => mem.asBytes(&ucontext_ptr.mcontext.ss.sp), |
| 315 | 32 => mem.asBytes(&ucontext_ptr.mcontext.ss.pc), | 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 | // V0-V31 | 340 | // V0-V31 |
| 317 | 64...95 => mem.asBytes(&ucontext_ptr.mcontext.ns.q[reg_number - 64]), | 341 | 64...95 => mem.asBytes(&ucontext_ptr.mcontext.ns.q[reg_number - 64]), |
| 318 | else => error.InvalidRegister, | 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,7 +2459,7 @@ pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, modul |
| 2459 | else => return error.UnimplementedArch, | 2459 | else => return error.UnimplementedArch, |
| 2460 | }; | 2460 | }; |
| 2461 | 2461 | ||
| 2462 | context.pc = new_ip; | 2462 | context.pc = dwarf.abi.stripInstructionPtrAuthCode(new_ip); |
| 2463 | if (context.pc > 0) context.pc -= 1; | 2463 | if (context.pc > 0) context.pc -= 1; |
| 2464 | return new_ip; | 2464 | return new_ip; |
| 2465 | } | 2465 | } |