From patchwork Mon Apr 25 14:03:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: German Gomez X-Patchwork-Id: 53190 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 35F7D3858016 for ; Mon, 25 Apr 2022 14:04:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 35F7D3858016 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1650895453; bh=a3lxPDL/f6lU1ryFuVewLfLXcOlctlRGAW/sBcYBPu4=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Help:List-Subscribe:From:Reply-To:From; b=VdsFlR7bwd63040YEATlGoQXwQd49m3i7vZ3sK5MrzLi0WMAUuq9RHfO8cv2id8nv zv05XzoSgyvaIO8AumigISKvoCB+KEGLLkl82kR1GdfTo5x1uX+zCpPkGCOOSbcRgU MXJJgZp+66hycZK1sItAh1qWLLi0kHql/AjUNtRs= X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 5BAA13858C83 for ; Mon, 25 Apr 2022 14:03:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5BAA13858C83 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1F60011FB; Mon, 25 Apr 2022 07:03:28 -0700 (PDT) Received: from ip-10-252-15-96.eu-west-1.compute.internal (unknown [10.252.15.96]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 7BB473F774; Mon, 25 Apr 2022 07:03:27 -0700 (PDT) To: elfutils-devel@sourceware.org Subject: [PATCH 4/4] libdwfl, eu-stack, aarch64: Add API for setting AARCH64 PAC mask. Date: Mon, 25 Apr 2022 14:03:11 +0000 Message-Id: <20220425140311.95231-5-german.gomez@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220425140311.95231-1-german.gomez@arm.com> References: <20220425140311.95231-1-german.gomez@arm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-Patchwork-Original-From: German Gomez via Elfutils-devel From: German Gomez Reply-To: German Gomez Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org Sender: "Elfutils-devel" 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 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 --- libdw/libdw.map | 5 +++++ libdwfl/dwfl_frame_regs.c | 10 ++++++++++ libdwfl/libdwfl.h | 6 ++++++ libdwfl/linux-pid-attach.c | 34 ++++++++++++++++++++++++++++++++-- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/libdw/libdw.map b/libdw/libdw.map index 4f530378..469c72ab 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -366,3 +366,8 @@ ELFUTILS_0.186 { dwarf_linecontext; dwarf_linefunctionname; } ELFUTILS_0.177; + +ELFUTILS_0.188 { + global: + dwfl_thread_state_aarch64_pauth; +} ELFUTILS_0.186; diff --git a/libdwfl/dwfl_frame_regs.c b/libdwfl/dwfl_frame_regs.c index 83b1abef..f8baf6d3 100644 --- a/libdwfl/dwfl_frame_regs.c +++ b/libdwfl/dwfl_frame_regs.c @@ -59,3 +59,13 @@ dwfl_thread_state_register_pc (Dwfl_Thread *thread, Dwarf_Word pc) state->pc_state = DWFL_FRAME_STATE_PC_SET; } INTDEF(dwfl_thread_state_register_pc) + +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 f98f1d52..9eef703c 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -753,6 +753,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 09cba07b..bf50a5bc 100644 --- a/libdwfl/linux-pid-attach.c +++ b/libdwfl/linux-pid-attach.c @@ -321,6 +321,28 @@ pid_thread_state_registers_cb (int firstreg, unsigned nregs, return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs); } +#if defined(__aarch64__) + +#include /* 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) { @@ -333,8 +355,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