From patchwork Fri Nov 11 18:36:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiong Wang X-Patchwork-Id: 81890 Delivered-To: patch@linaro.org Received: by 10.140.97.165 with SMTP id m34csp1405920qge; Fri, 11 Nov 2016 10:37:13 -0800 (PST) X-Received: by 10.99.166.2 with SMTP id t2mr21956451pge.149.1478889433772; Fri, 11 Nov 2016 10:37:13 -0800 (PST) Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id o69si11491949pfi.265.2016.11.11.10.37.13 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Nov 2016 10:37:13 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-return-441181-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org; spf=pass (google.com: domain of gcc-patches-return-441181-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom=gcc-patches-return-441181-patch=linaro.org@gcc.gnu.org DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; q=dns; s=default; b=hjBCR1aCy9U/K47fm YZAN8JPTPVBu1Ucv9ffsWJQk0kLjoo5KPI6rRJ34Qbd4zdXLyDdeWeEQ03ghFxSF DKRn+qqE+ynUanFOU4b9NgcaidedP75lm0Dt/rzmyBy3c4nemiuKTdWj+rE6Z4BV C6mcAg5jWVuW7K1DbEEDomj/6I= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:references:cc:message-id:date:mime-version :in-reply-to:content-type; s=default; bh=d/4q7mpf3wMnJ0qgmkA20QS zEzI=; b=WPwoVRqnVv6JntUlXubZvPg7TnLaGqjzNWy2BLNE/Yx1Z7GnFDcfED3 GcvCx5RjT65G1FgPYc1I4GAIwM38m4eIqY1Jcd41kCiMKHl8PwWczN4Fpi0VKIv+ CYNYvoI7KC0Knu0T/p1e5vVQZkIcNgmMWBkMok+wcbakc3dhQFxo= Received: (qmail 89879 invoked by alias); 11 Nov 2016 18:36:54 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 89524 invoked by uid 89); 11 Nov 2016 18:36:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.8 required=5.0 tests=BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=served, resign X-HELO: foss.arm.com Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 11 Nov 2016 18:36:42 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 73A6516; Fri, 11 Nov 2016 10:36:41 -0800 (PST) Received: from [10.2.206.198] (e104437-lin.cambridge.arm.com [10.2.206.198]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C927B3F24D; Fri, 11 Nov 2016 10:36:40 -0800 (PST) From: Jiong Wang Subject: [8/9][AArch64, libgcc] Runtime support for AArch64 DWARF operations To: gcc-patches References: <72418e98-a400-c503-e8ce-c3fbe1ecc4a7@foss.arm.com> <64dd1b38-ff0a-5df0-1d3c-2fbf083e2697@foss.arm.com> <532363d6-0b33-491f-264d-9cd627713bf6@foss.arm.com> <172bd740-755c-5267-3a9d-692c84d25395@foss.arm.com> <9333e644-4daa-38e3-690e-2ea3473b0f29@foss.arm.com> Cc: "Richard Earnshaw (lists)" , James Greenhalgh Message-ID: <1a156de9-b632-92a9-0e6a-24b67e915f81@foss.arm.com> Date: Fri, 11 Nov 2016 18:36:39 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: <9333e644-4daa-38e3-690e-2ea3473b0f29@foss.arm.com> X-IsSubscribed: yes This patch add AArch64 specific runtime EH unwinding support for DW_OP_AARCH64_pauth, DW_OP_AARCH64_paciasp and DW_OP_AARCH64_paciasp_deref. The semantics of them are described at the specification in patch [1/9]. The support includes: * Parsing these DWARF operations. Perform unwinding actions according to their semantics. * Handling eh_return multi return paths. Function calling __builtin_eh_return (_Unwind_RaiseException*) will have multiple return paths. One is for normal exit, the other is for install EH handler. If the _Unwind_RaiseException itself is return address signed, then there will always be return address authentication before return, however, if the return path in _Unwind_RaiseException if from installing EH handler the address of which has already been authenticated during unwinding, then we need to re-sign that address, so when the execution flow continues at _Unwind_RaiseException's epilogue, the authentication still works correctly. OK for trunk? libgcc/ 2016-11-11 Jiong Wang * config/aarch64/unwind-aarch64.c (RA_SIGN_BIT): New flag to indicate one frame is return address signed. (execute_stack_op): Handle DW_OP_AARCH64_pauth, DW_OP_AARCH64_paciasp, DW_OP_AARCH64_paciasp_deref. (uw_init_context): Call aarch64_uw_init_context_1. (uw_init_context_1): Rename to aarch64_uw_init_context_1. Strip signature for seed address. (uw_install_context): Re-sign handler's address so it works correctly with caller's context. (uw_install_context_1): by_value[LR] can be true, after return address signing LR will come from DWARF value expression rule which is a by_value true rule. diff --git a/libgcc/config/aarch64/unwind-aarch64.c b/libgcc/config/aarch64/unwind-aarch64.c index 1fb6026d123f8e7fc676f5e95e8e66caccf3d6ff..f6441a56960dbd4b754f8fc17d581402389a4812 100644 --- a/libgcc/config/aarch64/unwind-aarch64.c +++ b/libgcc/config/aarch64/unwind-aarch64.c @@ -37,6 +37,10 @@ #include "gthr.h" #include "unwind-dw2.h" +/* This AArch64 implementation is exactly the same as libgcc/unwind-dw2.c, + except we have a customized uw_init_context_1 to handle pointer + authentication. */ + #ifdef HAVE_SYS_SDT_H #include #endif @@ -67,7 +71,7 @@ waste. However, some runtime libraries supplied with ICC do contain such an unorthodox transition, as well as the unwind info to match. This loss of register restoration doesn't matter in practice, because the exception - is caught in the native unix abi, where all of the xmm registers are + is caught in the native unix abi, where all of the xmm registers are call clobbered. Ideally, we'd record some bit to notice when we're failing to restore some @@ -136,6 +140,8 @@ struct _Unwind_Context #define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1) /* Context which has version/args_size/by_value fields. */ #define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1) + /* Return address has been signed. */ +#define RA_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1) _Unwind_Word flags; /* 0 for now, can be increased when further fields are added to struct _Unwind_Context. */ @@ -908,6 +914,89 @@ execute_stack_op (const unsigned char *op_ptr, const unsigned char *op_end, case DW_OP_nop: goto no_push; + case DW_OP_AARCH64_paciasp: + { + _Unwind_Word lr_value = _Unwind_GetGR (context, LR_REGNUM); + /* Note: initial is guaranteed to be CFA by DWARF specification. */ + result + = (_Unwind_Word) __builtin_aarch64_autia1716 ((void *) lr_value, + initial); + context->flags |= RA_SIGNED_BIT; + break; + } + + case DW_OP_AARCH64_paciasp_deref: + { + _sleb128_t offset; + op_ptr = read_sleb128 (op_ptr, &offset); + result = (_Unwind_Word) read_pointer ((void *) initial + offset); + result + = (_Unwind_Word) __builtin_aarch64_autia1716 ((void *) result, + initial); + context->flags |= RA_SIGNED_BIT; + break; + } + + case DW_OP_AARCH64_pauth: + { + _uleb128_t auth_descriptor; + op_ptr = read_uleb128 (op_ptr, &auth_descriptor); + enum aarch64_pauth_action_type action_code = + (enum aarch64_pauth_action_type) (auth_descriptor & 0xf); + context->flags |= RA_SIGNED_BIT; + + /* Different action may take different number of operands. + AARCH64_PAUTH_DROP* takes one operand while AARCH64_PAUTH_AUTH + takes two and both of them produce one result. */ + switch (action_code) + { + case AARCH64_PAUTH_DROP_I: + { + /* Fetch the value to drop signature. */ + stack_elt -= 1; + result = stack[stack_elt]; + result + = (_Unwind_Word) + __builtin_aarch64_xpaclri ((void *) result); + break; + } + case AARCH64_PAUTH_AUTH: + { + enum aarch64_pauth_key_index key_index = + (enum aarch64_pauth_key_index) + (auth_descriptor >> 4) & 0xf; + + /* Fetch the value to be authenticated and the key. */ + stack_elt -= 2; + _Unwind_Word key = stack[stack_elt]; + result = stack[stack_elt + 1]; + + switch (key_index) + { + case AARCH64_PAUTH_IKEY_A: + result + = (_Unwind_Word) + __builtin_aarch64_autia1716 ((void *) result, key); + break; + case AARCH64_PAUTH_IKEY_B: + result + = (_Unwind_Word) + __builtin_aarch64_autib1716 ((void *) result, key); + break; + default: + /* For C++ exception unwinding, only instruction + pointers are expected. */ + gcc_unreachable (); + } + } + break; + default: + gcc_unreachable (); + } + + break; + } + default: gcc_unreachable (); } @@ -1534,8 +1623,8 @@ uw_advance_context (struct _Unwind_Context *context, _Unwind_FrameState *fs) /* Do any necessary initialization to access arbitrary stack frames. \ On the SPARC, this means flushing the register windows. */ \ __builtin_unwind_init (); \ - uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ - __builtin_return_address (0)); \ + aarch64_uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \ + __builtin_return_address (0)); \ } \ while (0) @@ -1546,10 +1635,15 @@ init_dwarf_reg_size_table (void) } static void __attribute__((noinline)) -uw_init_context_1 (struct _Unwind_Context *context, - void *outer_cfa, void *outer_ra) +aarch64_uw_init_context_1 (struct _Unwind_Context *context, + void *outer_cfa, void *outer_ra) { void *ra = __builtin_extract_return_addr (__builtin_return_address (0)); + /* Drop authentication signature for inner RA. It's anyway will be + authenticated later before return if return addresss signing is enabled for + libgcc. Here it's served as the seed address which will be used for table + searching, we need the original address. */ + ra = __builtin_aarch64_xpaclri (ra); _Unwind_FrameState fs; _Unwind_SpTmp sp_slot; _Unwind_Reason_Code code; @@ -1586,6 +1680,11 @@ uw_init_context_1 (struct _Unwind_Context *context, initialization context, then we can't see it in the given call frame data. So have the initialization context tell us. */ context->ra = __builtin_extract_return_addr (outer_ra); + void *orig_ra = __builtin_aarch64_xpaclri (context->ra); + if (context->ra != orig_ra) + context->flags |= RA_SIGNED_BIT; + /* Same reason as described at this function start. */ + context->ra = orig_ra; } static void _Unwind_DebugHook (void *, void *) @@ -1610,13 +1709,22 @@ _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)), /* Install TARGET into CURRENT so that we can return to it. This is a macro because __builtin_eh_return must be invoked in the context of - our caller. */ + our caller. + + For AArch64 pointer authentication, as target EH handler's address is + already authenticated, we need to sign it again with the original SP + of CURRENT. */ #define uw_install_context(CURRENT, TARGET) \ do \ { \ long offset = uw_install_context_1 ((CURRENT), (TARGET)); \ void *handler = __builtin_frob_return_addr ((TARGET)->ra); \ + if ((CURRENT)->flags & RA_SIGNED_BIT) \ + handler \ + = __builtin_aarch64_paci1716 (handler, \ + (_Unwind_Word) \ + (CURRENT)->cfa); \ _Unwind_DebugHook ((TARGET)->cfa, handler); \ __builtin_eh_return (offset, handler); \ } \ @@ -1639,7 +1747,8 @@ uw_install_context_1 (struct _Unwind_Context *current, void *c = (void *) (_Unwind_Internal_Ptr) current->reg[i]; void *t = (void *) (_Unwind_Internal_Ptr)target->reg[i]; - gcc_assert (current->by_value[i] == 0); + gcc_assert (current->by_value[i] == 0 + || i == (AARCH64_DWARF_R0 + LR_REGNUM)); if (target->by_value[i] && c) { _Unwind_Word w;