From ba813d00f57542483cac108223c7b2c4353c14e0 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Fri, 14 Jul 2023 02:50:43 -0400 Subject: [PATCH] dwarf: add abi.stripInstructionPtrAuthCode --- lib/std/dwarf.zig | 10 +++++++--- lib/std/dwarf/abi.zig | 28 ++++++++++++++++++++++++++-- lib/std/macho.zig | 2 +- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 393973741374f19231ae816c8e375f7a89399c18..f9b36f2aa2ad8ede4a56f757c2af0b6051a621d6 100644 --- a/lib/std/dwarf.zig +++ b/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); diff --git a/lib/std/dwarf/abi.zig b/lib/std/dwarf/abi.zig index 9b13db8535bdc2a074a29e23b6e185083574dfe8..d56ae2733d06e01d3df82243e22fc994593dd2b7 100644 --- a/lib/std/dwarf/abi.zig +++ b/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, diff --git a/lib/std/macho.zig b/lib/std/macho.zig index 0433c8d692e75f9473116d9f7d7432f19fc02929..dbf49b5f3d9268a5f3e51f7ceacf3e9a9d536c6a 100644 --- a/lib/std/macho.zig +++ b/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; } -- 2.54.0