]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl, aarch64: extend dwfl_thread_state_registers to handle PAC
authorSteve Capper <steve.capper@arm.com>
Mon, 26 Aug 2024 10:52:56 +0000 (11:52 +0100)
committerMark Wielaard <mark@klomp.org>
Fri, 30 Aug 2024 13:10:39 +0000 (15:10 +0200)
On AArch64 systems with pointer authentication enabled, one needs to
know the PAC mask in order to unwind functions that employ PAC.

This patch extends dwfl_thread_state_registers to handle the PAC mask
information by introducing a special register -2. (-1 is used in a
similar manner already for handling the program counter).

The AArch64 linux process attach logic is also extended to query ptrace
for the PAC mask.

A subsequent patch will add support for retrieving the PAC mask from an
AArch64 linux core file.

Signed-off-by: Steve Capper <steve.capper@arm.com>
backends/aarch64_initreg.c
libdwfl/dwfl_frame_regs.c
libdwfl/linux-pid-attach.c

index 4661068a56b84ca207ffe9bf6b97f764d2f1f60d..5ec45ea60d8db4424c4c6046e178582361f7fbc5 100644 (file)
@@ -36,6 +36,7 @@
 # include <linux/uio.h>
 # include <sys/user.h>
 # include <sys/ptrace.h>
+# include <asm/ptrace.h>
 /* Deal with old glibc defining user_pt_regs instead of user_regs_struct.  */
 # ifndef HAVE_SYS_USER_REGS
 #  define user_regs_struct user_pt_regs
@@ -57,12 +58,18 @@ aarch64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)),
 
   /* General registers.  */
   struct user_regs_struct gregs;
+  struct user_pac_mask pac_mask;
   struct iovec iovec;
   iovec.iov_base = &gregs;
   iovec.iov_len = sizeof (gregs);
   if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iovec) != 0)
     return false;
 
+  iovec.iov_base = &pac_mask;
+  iovec.iov_len = sizeof (pac_mask);
+  if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_PAC_MASK, &iovec) != 0)
+    pac_mask.insn_mask = 0;
+
   /* X0..X30 plus SP.  */
   if (! setfunc (0, 32, (Dwarf_Word *) &gregs.regs[0], arg))
     return false;
@@ -71,6 +78,9 @@ aarch64_set_initial_registers_tid (pid_t tid __attribute__ ((unused)),
   if (! setfunc (-1, 1, (Dwarf_Word *) &gregs.pc, arg))
     return false;
 
+  if (! setfunc (-2, 1, (Dwarf_Word *) &pac_mask.insn_mask, arg))
+    return false;
+
   /* ELR cannot be found.  */
 
   /* RA_SIGN_STATE cannot be found */
index a4bd38849a9a40199084d4844d98ac159b9e4fd9..572ac6761ea8b50476e0b5bf2734450feaf67cd5 100644 (file)
@@ -39,6 +39,12 @@ dwfl_thread_state_registers (Dwfl_Thread *thread, int firstreg,
   Dwfl_Frame *state = thread->unwound;
   assert (state && state->unwound == NULL);
   assert (state->initial_frame);
+
+  if (firstreg == -2 && nregs == 1) {
+    thread->aarch64.pauth_insn_mask = regs[0];
+    return true;
+  }
+
   for (unsigned regno = firstreg; regno < firstreg + nregs; regno++)
     if (! __libdwfl_frame_reg_set (state, regno, regs[regno - firstreg]))
       {
index de8678572d1222245ce7f7ee0ad233dbe2d86573..0eec1e886975ede0c1db83b6774b78cdda62cca1 100644 (file)
@@ -309,13 +309,18 @@ pid_thread_state_registers_cb (int firstreg, unsigned nregs,
                               const Dwarf_Word *regs, void *arg)
 {
   Dwfl_Thread *thread = (Dwfl_Thread *) arg;
-  if (firstreg < 0)
+  if (firstreg == -1)
     {
-      assert (firstreg == -1);
       assert (nregs == 1);
       INTUSE(dwfl_thread_state_register_pc) (thread, *regs);
       return true;
     }
+  else if (firstreg == -2)
+    {
+      assert (nregs == 1);
+      INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
+      return true;
+     }
   assert (nregs > 0);
   return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
 }