From: German Gomez <[email protected]>
Add user API for setting the PAC mask.
The function is intended to be called in
Dwfl_Thread_Callbacks.set_initial_registers.
Testing notes:
... consider the following program.c
| int a = 0;
| void leaf(void) {
| for (;;)
| a += a;
| }
| void parent(void) {
| leaf();
| }
| int main(void) {
| parent();
| return 0;
| }
... compiled with "gcc-10 -O0 -g -mbranch-protection=pac-ret+leaf program.c"
... should yield the correct call stack, without mangled addresses:
| $ eu-stack -p <PID>
|
| PID 760267 - process
| TID 760267:
| #0 0x0000aaaaaebd0804 leaf
| #1 0x0000aaaaaebd0818 parent
| #2 0x0000aaaaaebd0838 main
| #3 0x0000ffffbd52ad50 __libc_start_main
| #4 0x0000aaaaaebd0694 $x
Signed-off-by: German Gomez <[email protected]>
Signed-off-by: Steve Capper <[email protected]>
---
libdw/libdw.map | 1 +
libdwfl/dwfl_frame_regs.c | 10 ++++++++++
libdwfl/libdwfl.h | 6 ++++++
libdwfl/linux-pid-attach.c | 34 ++++++++++++++++++++++++++++++++--
4 files changed, 49 insertions(+), 2 deletions(-)
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 3c5ce8dc..84393f4b 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -377,4 +377,5 @@ ELFUTILS_0.188 {
ELFUTILS_0.191 {
global:
dwarf_cu_dwp_section_info;
+ dwfl_thread_state_aarch64_pauth;
} ELFUTILS_0.188;
diff --git a/libdwfl/dwfl_frame_regs.c b/libdwfl/dwfl_frame_regs.c
index a4bd3884..29e3d0b1 100644
--- a/libdwfl/dwfl_frame_regs.c
+++ b/libdwfl/dwfl_frame_regs.c
@@ -71,3 +71,13 @@ dwfl_frame_reg (Dwfl_Frame *state, unsigned regno,
Dwarf_Word *val)
return res;
}
INTDEF(dwfl_frame_reg)
+
+void
+dwfl_thread_state_aarch64_pauth(Dwfl_Thread *thread, Dwarf_Word insn_mask)
+{
+ Dwfl_Frame *state = thread->unwound;
+ assert (state && state->unwound == NULL);
+ assert (state->initial_frame);
+ thread->aarch64.pauth_insn_mask = insn_mask;
+}
+INTDEF(dwfl_thread_state_aarch64_pauth)
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 49ad6664..3ab07514 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -763,6 +763,12 @@ bool dwfl_thread_state_registers (Dwfl_Thread *thread, int
firstreg,
void dwfl_thread_state_register_pc (Dwfl_Thread *thread, Dwarf_Word pc)
__nonnull_attribute__ (1);
+/* Called by Dwfl_Thread_Callbacks.set_initial_registers implementation.
+ On AARCH64 platforms with Pointer Authentication, the bits from this mask
+ indicate the position of the PAC bits in return addresses. */
+void dwfl_thread_state_aarch64_pauth (Dwfl_Thread *thread, Dwarf_Word
insn_mask)
+ __nonnull_attribute__ (1);
+
/* Iterate through the threads for a process. Returns zero if all threads have
been processed by the callback, returns -1 on error, or the value of the
callback when not DWARF_CB_OK. -1 returned on error will set dwfl_errno ().
diff --git a/libdwfl/linux-pid-attach.c b/libdwfl/linux-pid-attach.c
index de867857..e68af4a9 100644
--- a/libdwfl/linux-pid-attach.c
+++ b/libdwfl/linux-pid-attach.c
@@ -320,6 +320,28 @@ pid_thread_state_registers_cb (int firstreg, unsigned
nregs,
return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
}
+#if defined(__aarch64__)
+
+#include <linux/ptrace.h> /* struct user_pac_mask */
+
+static void
+pid_set_aarch64_pauth(Dwfl_Thread *thread, pid_t tid)
+{
+ struct user_pac_mask pac_mask;
+ struct iovec iovec;
+
+ iovec.iov_base = &pac_mask;
+ iovec.iov_len = sizeof (pac_mask);
+
+ /* If the ptrace returns an error, the system may not support pointer
+ authentication. In that case, set the masks to 0 (no PAC bits). */
+ if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_PAC_MASK, &iovec))
+ pac_mask.insn_mask = 0;
+
+ INTUSE(dwfl_thread_state_aarch64_pauth) (thread, pac_mask.insn_mask);
+}
+#endif /* __aarch64__ */
+
static bool
pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
{
@@ -332,8 +354,16 @@ pid_set_initial_registers (Dwfl_Thread *thread, void
*thread_arg)
pid_arg->tid_attached = tid;
Dwfl_Process *process = thread->process;
Ebl *ebl = process->ebl;
- return ebl_set_initial_registers_tid (ebl, tid,
- pid_thread_state_registers_cb, thread);
+ if (!ebl_set_initial_registers_tid (ebl, tid,
+ pid_thread_state_registers_cb, thread))
+ return false;
+
+#if defined(__aarch64__)
+ /* Set aarch64 pointer authentication data. */
+ pid_set_aarch64_pauth(thread, tid);
+#endif
+
+ return true;
}
static void
--
2.39.2