From patchwork Wed Mar 6 13:33:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Hayward X-Patchwork-Id: 31729 Received: (qmail 34501 invoked by alias); 6 Mar 2019 13:33:43 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 34410 invoked by uid 89); 6 Mar 2019 13:33:42 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=2486 X-HELO: EUR03-VE1-obe.outbound.protection.outlook.com Received: from mail-eopbgr50089.outbound.protection.outlook.com (HELO EUR03-VE1-obe.outbound.protection.outlook.com) (40.107.5.89) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 06 Mar 2019 13:33:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector1-arm-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=PpPH2NiFmuHUQFuK2Vzdi2wqq5NwQLAEarco5JVwP3Q=; b=cjRMaX47kNjjPSL7CmPHIni6Ljnb3v2nf5J755L1+nBlN7Q2Uc+pm3Tph/NtuWT5RQ+UMC0CjRfW7jHr6U7pRFERxtd96ioKHbbbNYHiRa2alYWQCM4f31spQYgD9YkXG8ed5FpluWrEi3bAE77x/TJ/hzMlQwojJ0C8yaYoEBw= Received: from DB6PR0802MB2133.eurprd08.prod.outlook.com (10.172.227.22) by DB6PR0802MB2406.eurprd08.prod.outlook.com (10.172.250.9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1665.19; Wed, 6 Mar 2019 13:33:37 +0000 Received: from DB6PR0802MB2133.eurprd08.prod.outlook.com ([fe80::e974:35a7:c83c:e5b7]) by DB6PR0802MB2133.eurprd08.prod.outlook.com ([fe80::e974:35a7:c83c:e5b7%3]) with mapi id 15.20.1686.018; Wed, 6 Mar 2019 13:33:37 +0000 From: Alan Hayward To: "gdb-patches@sourceware.org" CC: nd , Alan Hayward Subject: [PATCH v2 6/8] AArch64: DWARF unwinder support for signed return addresses Date: Wed, 6 Mar 2019 13:33:36 +0000 Message-ID: <20190306133325.2531-7-alan.hayward@arm.com> References: <20190306133325.2531-1-alan.hayward@arm.com> In-Reply-To: <20190306133325.2531-1-alan.hayward@arm.com> authentication-results: spf=none (sender IP is ) smtp.mailfrom=Alan.Hayward@arm.com; received-spf: None (protection.outlook.com: arm.com does not designate permitted sender hosts) x-ms-exchange-senderadcheck: 1 MIME-Version: 1.0 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-IsSubscribed: yes Pauth address signing is enabled at binary compile time. When enabled the return addresses for functions may be mangled. This patch adds functionality to restore the original address for use in the DWARF unwinder. DW_CFA_AARCH64_negate_ra_state in a binary indicates the toggling of address signing between enabled and disabled. Ensure the state is stored in the DWARF register ra_state. Ensure the pauth DWARF registers are initialised. gdb/ChangeLog: 2019-03-06 Alan Hayward Jiong Wang * aarch64-tdep.c (aarch64_frame_unmask_address): New function. (aarch64_dwarf2_prev_register): Unmask PC value. (aarch64_dwarf2_frame_init_reg): Init pauth registers. (aarch64_execute_dwarf_cfa_vendor_op): Check for DW_CFA_AARCH64_negate_ra_state. (aarch64_gdbarch_init): Add aarch64_execute_dwarf_cfa_vendor_op. --- gdb/aarch64-tdep.c | 87 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 01e98b7195..07430c0f25 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -34,6 +34,7 @@ #include "frame-base.h" #include "trad-frame.h" #include "objfiles.h" +#include "dwarf2.h" #include "dwarf2-frame.h" #include "gdbtypes.h" #include "prologue-value.h" @@ -248,6 +249,26 @@ class instruction_reader : public abstract_instruction_reader } // namespace +/* If address signing is enabled, mask off the signature bits from ADDR, using + the register values in THIS_FRAME. */ + +static CORE_ADDR +aarch64_frame_unmask_address (struct gdbarch_tdep *tdep, + struct frame_info *this_frame, + CORE_ADDR addr) +{ + if (tdep->has_pauth () + && frame_unwind_register_unsigned (this_frame, + tdep->pauth_ra_state_regnum)) + { + int cmask_num = AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base); + CORE_ADDR cmask = frame_unwind_register_unsigned (this_frame, cmask_num); + addr = addr & ~cmask; + } + + return addr; +} + /* Analyze a prologue, looking for a recognizable stack frame and frame pointer. Scan until we encounter a store that could clobber the stack frame unexpectedly, or an unknown instruction. */ @@ -1013,12 +1034,14 @@ static struct value * aarch64_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache, int regnum) { + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame)); CORE_ADDR lr; switch (regnum) { case AARCH64_PC_REGNUM: lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM); + lr = aarch64_frame_unmask_address (tdep, this_frame, lr); return frame_unwind_got_constant (this_frame, regnum, lr); default: @@ -1027,6 +1050,9 @@ aarch64_dwarf2_prev_register (struct frame_info *this_frame, } } +static const unsigned char op_lit0 = DW_OP_lit0; +static const unsigned char op_lit1 = DW_OP_lit1; + /* Implement the "init_reg" dwarf2_frame_ops method. */ static void @@ -1034,18 +1060,72 @@ aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, struct dwarf2_frame_state_reg *reg, struct frame_info *this_frame) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + switch (regnum) { case AARCH64_PC_REGNUM: reg->how = DWARF2_FRAME_REG_FN; reg->loc.fn = aarch64_dwarf2_prev_register; - break; + return; + case AARCH64_SP_REGNUM: reg->how = DWARF2_FRAME_REG_CFA; - break; + return; + } + + /* Init pauth registers. */ + if (tdep->has_pauth ()) + { + if (regnum == tdep->pauth_ra_state_regnum) + { + /* Initialize RA_STATE to zero. */ + reg->how = DWARF2_FRAME_REG_SAVED_VAL_EXP; + reg->loc.exp.start = &op_lit0; + reg->loc.exp.len = 1; + return; + } + else if (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base) + || regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base)) + { + reg->how = DWARF2_FRAME_REG_SAME_VALUE; + return; + } } } +/* Implement the execute_dwarf_cfa_vendor_op method. */ + +static bool +aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op, + struct dwarf2_frame_state *fs) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct dwarf2_frame_state_reg *ra_state; + + if (tdep->has_pauth () && op == DW_CFA_AARCH64_negate_ra_state) + { + /* Allocate RA_STATE column if it's not allocated yet. */ + fs->regs.alloc_regs (AARCH64_DWARF_PAUTH_RA_STATE + 1); + + /* Toggle the status of RA_STATE between 0 and 1. */ + ra_state = &(fs->regs.reg[AARCH64_DWARF_PAUTH_RA_STATE]); + ra_state->how = DWARF2_FRAME_REG_SAVED_VAL_EXP; + + if (ra_state->loc.exp.start == nullptr + || ra_state->loc.exp.start == &op_lit0) + ra_state->loc.exp.start = &op_lit1; + else + ra_state->loc.exp.start = &op_lit0; + + ra_state->loc.exp.len = 1; + + return true; + } + + return false; +} + /* When arguments must be pushed onto the stack, they go on in reverse order. The code below implements a FILO (stack) to do this. */ @@ -3192,6 +3272,9 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) gdbarch_init_osabi (info, gdbarch); dwarf2_frame_set_init_reg (gdbarch, aarch64_dwarf2_frame_init_reg); + /* Register DWARF CFA vendor handler. */ + set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch, + aarch64_execute_dwarf_cfa_vendor_op); /* Add some default predicates. */ frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);