Commit ba813d00f5

kcbanner <kcbanner@gmail.com>
2023-07-14 08:50:43
dwarf: add abi.stripInstructionPtrAuthCode
1 parent ec96095
Changed files (3)
lib/std/dwarf/abi.zig
@@ -45,6 +45,27 @@ pub fn spRegNum(reg_context: RegisterContext) u8 {
     };
 }
 
+/// Some platforms use pointer authentication - the upper bits of instruction pointers contain a signature.
+/// This function clears these signature bits to make the pointer usable.
+pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize {
+    if (builtin.cpu.arch == .aarch64) {
+        // `hint 0x07` maps to `xpaclri` (or `nop` if the hardware doesn't support it)
+        // The save / restore is because `xpaclri` operates on x30 (LR)
+        return asm (
+            \\mov x16, x30
+            \\mov x30, x15
+            \\hint 0x07
+            \\mov x15, x30
+            \\mov x30, x16
+            : [ret] "={x15}" (-> usize),
+            : [ptr] "{x15}" (ptr),
+            : "x16"
+        );
+    }
+
+    return ptr;
+}
+
 pub const RegisterContext = struct {
     eh_frame: bool,
     is_macho: bool,
@@ -160,7 +181,6 @@ pub fn regBytes(
     if (!std.debug.have_ucontext) return error.ThreadContextNotSupported;
 
     const ucontext_ptr = thread_context_ptr;
-    var m = &ucontext_ptr.mcontext;
     return switch (builtin.cpu.arch) {
         .x86 => switch (builtin.os.tag) {
             .linux, .netbsd, .solaris => switch (reg_number) {
@@ -216,7 +236,7 @@ pub fn regBytes(
                 14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]),
                 15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]),
                 16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]),
-                17...32 => |i| mem.asBytes(&m.fpregs.xmm[i - 17]),
+                17...32 => |i| mem.asBytes(&ucontext_ptr.mcontext.fpregs.xmm[i - 17]),
                 else => error.InvalidRegister,
             },
             .freebsd => switch (reg_number) {
@@ -313,6 +333,10 @@ pub fn regBytes(
                 30 => mem.asBytes(&ucontext_ptr.mcontext.ss.lr),
                 31 => mem.asBytes(&ucontext_ptr.mcontext.ss.sp),
                 32 => mem.asBytes(&ucontext_ptr.mcontext.ss.pc),
+
+                // TODO: Find storage for this state
+                //34 => mem.asBytes(&ucontext_ptr.ra_sign_state),
+
                 // V0-V31
                 64...95 => mem.asBytes(&ucontext_ptr.mcontext.ns.q[reg_number - 64]),
                 else => error.InvalidRegister,
lib/std/dwarf.zig
@@ -1758,12 +1758,16 @@ pub const DwarfInfo = struct {
         }
 
         if (has_next_ip) {
-            context.pc = mem.readIntSliceNative(usize, try abi.regBytes(context.thread_context, cie.return_address_register, context.reg_context));
+            context.pc = abi.stripInstructionPtrAuthCode(mem.readIntSliceNative(usize, try abi.regBytes(
+                context.thread_context,
+                cie.return_address_register,
+                context.reg_context,
+            )));
         } else {
             context.pc = 0;
         }
 
-        mem.writeIntSliceNative(usize, try abi.regBytes(context.thread_context, abi.spRegNum(context.reg_context), context.reg_context), context.cfa.?);
+        (try abi.regValueNative(usize, context.thread_context, abi.spRegNum(context.reg_context), context.reg_context)).* = context.cfa.?;
 
         // The call instruction will have pushed the address of the instruction that follows the call as the return address
         // 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 {
     stack_machine: expressions.StackMachine(.{ .call_frame_context = true }) = .{},
 
     pub fn init(allocator: mem.Allocator, thread_context: *const debug.ThreadContext, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
-        const pc = mem.readIntSliceNative(usize, try abi.regBytes(thread_context, abi.ipRegNum(), null));
+        const pc = abi.stripInstructionPtrAuthCode((try abi.regValueNative(usize, thread_context, abi.ipRegNum(), null)).*);
 
         const context_copy = try allocator.create(debug.ThreadContext);
         debug.copyContext(thread_context, context_copy);
lib/std/macho.zig
@@ -2459,7 +2459,7 @@ pub fn unwindFrame(context: *dwarf.UnwindContext, unwind_info: []const u8, modul
         else => return error.UnimplementedArch,
     };
 
-    context.pc = new_ip;
+    context.pc = dwarf.abi.stripInstructionPtrAuthCode(new_ip);
     if (context.pc > 0) context.pc -= 1;
     return new_ip;
 }