diff mbox

[Ping~] Re: [5/5][libgcc] Runtime support for AArch64 return address signing (needs new target macros)

Message ID f2c6a806-4c38-834d-8cb2-14f968a1b4b4@foss.arm.com
State New
Headers show

Commit Message

Jiong Wang Jan. 18, 2017, 5:07 p.m. UTC
On 12/01/17 18:10, Jiong Wang wrote:
> On 06/01/17 11:47, Jiong Wang wrote:
>> This is the update on libgcc unwinder support according to new DWARF proposal.
>>
>> As Joseph commented, duplication of unwind-dw2.c is not encouraged in libgcc,
>> But from this patch, you can see there are a few places we need to modify for
>> AArch64 in unwind-aarch64.c, so the file duplication approach is acceptable?
>>
>>
>> libgcc/
>>
>> 2017-01-06  Jiong Wang  <jiong.wang@arm.com>
>>
>>         * config/aarch64/unwind-aarch64.c (DWARF_REGNUM_AARCH64_RA_STATE,
>>         RA_A_SIGNED_BIT): New macros.
>>         (execute_cfa_program): Multiplex DW_CFA_GNU_window_save on AArch64.
>>         (uw_frame_state_for): Clear bit[0] of DWARF_REGNUM_AARCH64_RA_STATE.
>>         (uw_update_context): Authenticate return address according to
>>         DWARF_REGNUM_AARCH64_RA_STATE.
>>         (uw_init_context_1): Strip signature of seed address.
>>         (uw_install_context): Re-authenticate EH handler's address.
>>
> Ping~
>
> For comparision, I have also attached the patch using the target macros.
>
> Four new target macros are introduced:
>
>   MD_POST_EXTRACT_ROOT_ADDR
>   MD_POST_EXTRACT_FRAME_ADDR
>   MD_POST_FROB_EH_HANDLER_ADDR
>   MD_POST_INIT_CONTEXT
>
> MD_POST_EXTRACT_ROOT_ADDR is to do target private post processing on the address
> inside _Unwind* functions, they are serving as root address to start the
> unwinding.  MD_POST_EXTRACT_FRAME_ADDR is to do target private post processing
> on th address inside the real user program which throws the exceptions.
>
> MD_POST_FROB_EH_HANDLER_ADDR is to do target private frob on the EH handler's
> address before we install it into current context.
>
> MD_POST_INIT_CONTEXT it to do target private initialization on the context
> structure after common initialization.
>
> One "__aarch64__" macro check is needed to multiplex DW_CFA_window_save.

Ping ~

Could global reviewers or libgcc maintainers please give a review on the generic
part change?

One small change is I removed MD_POST_INIT_CONTEXT as I found there is
MD_FROB_UPDATE_CONTEXT which serve the same purpose.  I still need to define

    MD_POST_EXTRACT_ROOT_ADDR
    MD_POST_EXTRACT_FRAME_ADDR
    MD_POST_FROB_EH_HANDLER_ADDR

And do one __aarch64__ check to multiplexing DW_CFA_GNU_window_save.

Thanks.

libgcc/ChangeLog:

2017-01-18  Jiong Wang  <jiong.wang@arm.com>

         * config/aarch64/aarch64-unwind.h: New file.
         (DWARF_REGNUM_AARCH64_RA_STATE): Define.
         (MD_POST_EXTRACT_ROOT_ADDR): Define.
         (MD_POST_EXTRACT_FRAME_ADDR): Define.
         (MD_POST_FROB_EH_HANDLER_ADDR): Define.
         (MD_FROB_UPDATE_CONTEXT): Define.
         (aarch64_post_extract_frame_addr): New function.
         (aarch64_post_frob_eh_handler_addr): New function.
         (aarch64_frob_update_context): New function.
         * config/aarch64/linux-unwind.h: Include aarch64-unwind.h
         * config.host (aarch64*-*-elf, aarch64*-*-rtems*, aarch64*-*-freebsd*):
         Initialize md_unwind_header to include aarch64-unwind.h.
         * unwind-dw2.c (struct _Unwind_Context): Define "RA_A_SIGNED_BIT".
         (execute_cfa_program): Multiplex DW_CFA_GNU_window_save for __aarch64__.
         (uw_update_context): Honor MD_POST_EXTRACT_FRAME_ADDR.
         (uw_init_context_1): Honor MD_POST_EXTRACT_ROOT_ADDR.
         (uw_frob_return_addr): New function.
         (_Unwind_DebugHook): Use uw_frob_return_addr.

Comments

Richard Earnshaw (lists) Jan. 19, 2017, 2:18 p.m. UTC | #1
On 18/01/17 17:07, Jiong Wang wrote:
> On 12/01/17 18:10, Jiong Wang wrote:
>> On 06/01/17 11:47, Jiong Wang wrote:
>>> This is the update on libgcc unwinder support according to new DWARF
>>> proposal.
>>>
>>> As Joseph commented, duplication of unwind-dw2.c is not encouraged in
>>> libgcc,
>>> But from this patch, you can see there are a few places we need to
>>> modify for
>>> AArch64 in unwind-aarch64.c, so the file duplication approach is
>>> acceptable?
>>>
>>>
>>> libgcc/
>>>
>>> 2017-01-06  Jiong Wang  <jiong.wang@arm.com>
>>>
>>>         * config/aarch64/unwind-aarch64.c
>>> (DWARF_REGNUM_AARCH64_RA_STATE,
>>>         RA_A_SIGNED_BIT): New macros.
>>>         (execute_cfa_program): Multiplex DW_CFA_GNU_window_save on
>>> AArch64.
>>>         (uw_frame_state_for): Clear bit[0] of
>>> DWARF_REGNUM_AARCH64_RA_STATE.
>>>         (uw_update_context): Authenticate return address according to
>>>         DWARF_REGNUM_AARCH64_RA_STATE.
>>>         (uw_init_context_1): Strip signature of seed address.
>>>         (uw_install_context): Re-authenticate EH handler's address.
>>>
>> Ping~
>>
>> For comparision, I have also attached the patch using the target macros.
>>
>> Four new target macros are introduced:
>>
>>   MD_POST_EXTRACT_ROOT_ADDR
>>   MD_POST_EXTRACT_FRAME_ADDR
>>   MD_POST_FROB_EH_HANDLER_ADDR
>>   MD_POST_INIT_CONTEXT
>>
>> MD_POST_EXTRACT_ROOT_ADDR is to do target private post processing on
>> the address
>> inside _Unwind* functions, they are serving as root address to start the
>> unwinding.  MD_POST_EXTRACT_FRAME_ADDR is to do target private post
>> processing
>> on th address inside the real user program which throws the exceptions.
>>
>> MD_POST_FROB_EH_HANDLER_ADDR is to do target private frob on the EH
>> handler's
>> address before we install it into current context.
>>
>> MD_POST_INIT_CONTEXT it to do target private initialization on the
>> context
>> structure after common initialization.
>>
>> One "__aarch64__" macro check is needed to multiplex DW_CFA_window_save.
> 
> Ping ~
> 
> Could global reviewers or libgcc maintainers please give a review on the
> generic
> part change?
> 
> One small change is I removed MD_POST_INIT_CONTEXT as I found there is
> MD_FROB_UPDATE_CONTEXT which serve the same purpose.  I still need to
> define
> 
>    MD_POST_EXTRACT_ROOT_ADDR
>    MD_POST_EXTRACT_FRAME_ADDR
>    MD_POST_FROB_EH_HANDLER_ADDR
> 
> And do one __aarch64__ check to multiplexing DW_CFA_GNU_window_save.
> 
> Thanks.
> 
> libgcc/ChangeLog:
> 
> 2017-01-18  Jiong Wang  <jiong.wang@arm.com>
> 
>         * config/aarch64/aarch64-unwind.h: New file.
>         (DWARF_REGNUM_AARCH64_RA_STATE): Define.
>         (MD_POST_EXTRACT_ROOT_ADDR): Define.
>         (MD_POST_EXTRACT_FRAME_ADDR): Define.
>         (MD_POST_FROB_EH_HANDLER_ADDR): Define.
>         (MD_FROB_UPDATE_CONTEXT): Define.
>         (aarch64_post_extract_frame_addr): New function.
>         (aarch64_post_frob_eh_handler_addr): New function.
>         (aarch64_frob_update_context): New function.
>         * config/aarch64/linux-unwind.h: Include aarch64-unwind.h
>         * config.host (aarch64*-*-elf, aarch64*-*-rtems*,
> aarch64*-*-freebsd*):
>         Initialize md_unwind_header to include aarch64-unwind.h.
>         * unwind-dw2.c (struct _Unwind_Context): Define "RA_A_SIGNED_BIT".
>         (execute_cfa_program): Multiplex DW_CFA_GNU_window_save for
> __aarch64__.
>         (uw_update_context): Honor MD_POST_EXTRACT_FRAME_ADDR.
>         (uw_init_context_1): Honor MD_POST_EXTRACT_ROOT_ADDR.
>         (uw_frob_return_addr): New function.
>         (_Unwind_DebugHook): Use uw_frob_return_addr.
> 
> 

Comments inline.

> 1.patch
> 
> 
> diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
> index 8085a42ace15d53f4cb0c6681717012d906a6d47..cf640135275deb76b820f8209fa51eacfd64c4a2 100644
> --- a/libgcc/unwind-dw2.c
> +++ b/libgcc/unwind-dw2.c
> @@ -136,6 +136,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)
> +  /* Bit reserved on AArch64, return address has been signed with A key.  */
> +#define RA_A_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1)

Why is this here?   It appears to only be used within the
AArch64-specific header file.

>    _Unwind_Word flags;
>    /* 0 for now, can be increased when further fields are added to
>       struct _Unwind_Context.  */
> @@ -1185,6 +1187,11 @@ execute_cfa_program (const unsigned char *insn_ptr,
>  	  break;
>  
>  	case DW_CFA_GNU_window_save:
> +#ifdef __aarch64__
> +	  /* This CFA is multiplexed with Sparc.  On AArch64 it's used to toggle
> +	     return address signing status.  */
> +	  fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset ^= 1;
> +#else
>  	  /* ??? Hardcoded for SPARC register window configuration.  */
>  	  if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
>  	    for (reg = 16; reg < 32; ++reg)
> @@ -1192,6 +1199,7 @@ execute_cfa_program (const unsigned char *insn_ptr,
>  		fs->regs.reg[reg].how = REG_SAVED_OFFSET;
>  		fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
>  	      }
> +#endif
>  	  break;
>  
>  	case DW_CFA_GNU_args_size:
> @@ -1513,10 +1521,15 @@ uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
>         stack frame.  */
>      context->ra = 0;
>    else
> -    /* Compute the return address now, since the return address column
> -       can change from frame to frame.  */
> -    context->ra = __builtin_extract_return_addr
> -      (_Unwind_GetPtr (context, fs->retaddr_column));
> +    {
> +      /* Compute the return address now, since the return address column
> +	 can change from frame to frame.  */
> +      context->ra = __builtin_extract_return_addr
> +	(_Unwind_GetPtr (context, fs->retaddr_column));
> +#ifdef MD_POST_EXTRACT_FRAME_ADDR
> +      context->ra = MD_POST_EXTRACT_FRAME_ADDR (context, fs, context->ra);
> +#endif
> +    }
>  }
>  
>  static void
> @@ -1550,6 +1563,9 @@ uw_init_context_1 (struct _Unwind_Context *context,
>  		   void *outer_cfa, void *outer_ra)
>  {
>    void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
> +#ifdef MD_POST_EXTRACT_ROOT_ADDR
> +  ra = MD_POST_EXTRACT_ROOT_ADDR (ra);
> +#endif
>    _Unwind_FrameState fs;
>    _Unwind_SpTmp sp_slot;
>    _Unwind_Reason_Code code;
> @@ -1586,6 +1602,9 @@ 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);
> +#ifdef MD_POST_EXTRACT_ROOT_ADDR
> +  context->ra = MD_POST_EXTRACT_ROOT_ADDR (context->ra);
> +#endif
>  }
>  
>  static void _Unwind_DebugHook (void *, void *)
> @@ -1608,6 +1627,20 @@ _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
>  #endif
>  }
>  
> +/* Frob exception handler's address kept in TARGET before installing into
> +   CURRENT context.  */
> +
> +static void *
> +uw_frob_return_addr (struct _Unwind_Context *current,
> +		     struct _Unwind_Context *target)
> +{
> +  void *ret_addr = __builtin_frob_return_addr (target->ra);
> +#ifdef MD_POST_FROB_EH_HANDLER_ADDR
> +  ret_addr = MD_POST_FROB_EH_HANDLER_ADDR (current, target, ret_addr);
> +#endif
> +  return ret_addr;
> +}
> +

I think this function should be marked inline.  The optimizers would
probably inline it anyway, but it seems wrong for us to rely on that.

>  /* 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.  */
> @@ -1616,7 +1649,7 @@ _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
>    do									\
>      {									\
>        long offset = uw_install_context_1 ((CURRENT), (TARGET));		\
> -      void *handler = __builtin_frob_return_addr ((TARGET)->ra);	\
> +      void *handler = uw_frob_return_addr ((CURRENT), (TARGET));	\
>        _Unwind_DebugHook ((TARGET)->cfa, handler);			\
>        __builtin_eh_return (offset, handler);				\
>      }									\
> diff --git a/libgcc/config.host b/libgcc/config.host
> index 6f2e458e74e776a6b7a310919558bcca76389232..540bfa9635802adabb36a2d1b7cf3416462c59f3 100644
> --- a/libgcc/config.host
> +++ b/libgcc/config.host
> @@ -331,11 +331,13 @@ aarch64*-*-elf | aarch64*-*-rtems*)
>  	extra_parts="$extra_parts crtfastmath.o"
>  	tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
>  	tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
> +	md_unwind_header=aarch64/aarch64-unwind.h
>  	;;
>  aarch64*-*-freebsd*)
>  	extra_parts="$extra_parts crtfastmath.o"
>  	tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
>  	tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
> +	md_unwind_header=aarch64/aarch64-unwind.h
>  	;;
>  aarch64*-*-linux*)
>  	extra_parts="$extra_parts crtfastmath.o"
> diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..a57cae0ff54ea7e11c32362677c0b51501a9f727
> --- /dev/null
> +++ b/libgcc/config/aarch64/aarch64-unwind.h
> @@ -0,0 +1,87 @@
> +/* Copyright (C) 2017 Free Software Foundation, Inc.
> +   Contributed by ARM Ltd.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +Under Section 7 of GPL version 3, you are granted additional
> +permissions described in the GCC Runtime Library Exception, version
> +3.1, as published by the Free Software Foundation.
> +
> +You should have received a copy of the GNU General Public License and
> +a copy of the GCC Runtime Library Exception along with this program;
> +see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
> +<http://www.gnu.org/licenses/>.  */
> +
> +#ifndef AARCH64_UNWIND_H
> +#define AARCH64_UNWIND_H
> +
> +#define DWARF_REGNUM_AARCH64_RA_STATE 34
> +
> +#define MD_POST_EXTRACT_ROOT_ADDR(addr)  __builtin_aarch64_xpaclri (addr)
> +#define MD_POST_EXTRACT_FRAME_ADDR(context, fs, addr) \
> +  aarch64_post_extract_frame_addr (context, fs, addr)
> +#define MD_POST_FROB_EH_HANDLER_ADDR(current, target, addr) \
> +  aarch64_post_frob_eh_handler_addr (current, target, addr)
> +#define MD_FROB_UPDATE_CONTEXT(context, fs) \
> +  aarch64_frob_update_context (context, fs)
> +
> +/* Do AArch64 private extraction on ADDR based on context info CONTEXT and
> +   unwind frame info FS.  If ADDR is signed, we do address authentication on it
> +   using CFA of current frame.  */
> +

All the functions in this HEADER file should be marked inline.

> +static void *
> +aarch64_post_extract_frame_addr (struct _Unwind_Context *context,
> +				 _Unwind_FrameState *fs, void *addr)
> +{
> +  if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
> +    {
> +      _Unwind_Word salt = (_Unwind_Word) context->cfa;
> +      return __builtin_aarch64_autia1716 (addr, salt);
> +    }
> +  else
> +    return addr;
> +}
> +
> +/* Do AArch64 private frob on exception handler's address HANDLER_ADDR before
> +   installing it into current context CURRENT.  TARGET is currently not used.
> +   We need to sign exception handler's address if CURRENT itself is signed.  */
> +
> +static void *
> +aarch64_post_frob_eh_handler_addr (struct _Unwind_Context *current,
> +				   struct _Unwind_Context *target
> +				   ATTRIBUTE_UNUSED,
> +				   void *handler_addr)
> +{
> +  if (current->flags & RA_A_SIGNED_BIT)
> +    return __builtin_aarch64_pacia1716 (handler_addr,
> +					(_Unwind_Word) current->cfa);
> +  else
> +    return handler_addr;
> +}
> +
> +/* Do AArch64 private initialization on CONTEXT based on frame info FS.  Mark
> +   CONTEXT as return address signed if bit 0 of DWARF_REGNUM_AARCH64_RA_STATE is
> +   set.  */
> +
> +static void
> +aarch64_frob_update_context (struct _Unwind_Context *context,
> +			     _Unwind_FrameState *fs)
> +{
> +  if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
> +    /* The flag is used for re-authenticating EH handler's address.  */
> +    context->flags |= RA_A_SIGNED_BIT;
> +
> +  return;
> +}
> +
> +#endif /* defined AARCH64_UNWIND_H */
> diff --git a/libgcc/config/aarch64/linux-unwind.h b/libgcc/config/aarch64/linux-unwind.h
> index 1256f010007ac964de8bb895379a7d893a446bd9..75774b30c080ad2361fb37c7208bcf3d3b57d77a 100644
> --- a/libgcc/config/aarch64/linux-unwind.h
> +++ b/libgcc/config/aarch64/linux-unwind.h
> @@ -24,6 +24,7 @@
>  
>  #include <signal.h>
>  #include <sys/ucontext.h>
> +#include "aarch64-unwind.h"
>  
>  
>  /* Since insns are always stored LE, on a BE system the opcodes will
> 

R.
diff mbox

Patch

diff --git a/libgcc/unwind-dw2.c b/libgcc/unwind-dw2.c
index 8085a42ace15d53f4cb0c6681717012d906a6d47..cf640135275deb76b820f8209fa51eacfd64c4a2 100644
--- a/libgcc/unwind-dw2.c
+++ b/libgcc/unwind-dw2.c
@@ -136,6 +136,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)
+  /* Bit reserved on AArch64, return address has been signed with A key.  */
+#define RA_A_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.  */
@@ -1185,6 +1187,11 @@  execute_cfa_program (const unsigned char *insn_ptr,
 	  break;
 
 	case DW_CFA_GNU_window_save:
+#ifdef __aarch64__
+	  /* This CFA is multiplexed with Sparc.  On AArch64 it's used to toggle
+	     return address signing status.  */
+	  fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset ^= 1;
+#else
 	  /* ??? Hardcoded for SPARC register window configuration.  */
 	  if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
 	    for (reg = 16; reg < 32; ++reg)
@@ -1192,6 +1199,7 @@  execute_cfa_program (const unsigned char *insn_ptr,
 		fs->regs.reg[reg].how = REG_SAVED_OFFSET;
 		fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
 	      }
+#endif
 	  break;
 
 	case DW_CFA_GNU_args_size:
@@ -1513,10 +1521,15 @@  uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
        stack frame.  */
     context->ra = 0;
   else
-    /* Compute the return address now, since the return address column
-       can change from frame to frame.  */
-    context->ra = __builtin_extract_return_addr
-      (_Unwind_GetPtr (context, fs->retaddr_column));
+    {
+      /* Compute the return address now, since the return address column
+	 can change from frame to frame.  */
+      context->ra = __builtin_extract_return_addr
+	(_Unwind_GetPtr (context, fs->retaddr_column));
+#ifdef MD_POST_EXTRACT_FRAME_ADDR
+      context->ra = MD_POST_EXTRACT_FRAME_ADDR (context, fs, context->ra);
+#endif
+    }
 }
 
 static void
@@ -1550,6 +1563,9 @@  uw_init_context_1 (struct _Unwind_Context *context,
 		   void *outer_cfa, void *outer_ra)
 {
   void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
+#ifdef MD_POST_EXTRACT_ROOT_ADDR
+  ra = MD_POST_EXTRACT_ROOT_ADDR (ra);
+#endif
   _Unwind_FrameState fs;
   _Unwind_SpTmp sp_slot;
   _Unwind_Reason_Code code;
@@ -1586,6 +1602,9 @@  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);
+#ifdef MD_POST_EXTRACT_ROOT_ADDR
+  context->ra = MD_POST_EXTRACT_ROOT_ADDR (context->ra);
+#endif
 }
 
 static void _Unwind_DebugHook (void *, void *)
@@ -1608,6 +1627,20 @@  _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
 #endif
 }
 
+/* Frob exception handler's address kept in TARGET before installing into
+   CURRENT context.  */
+
+static void *
+uw_frob_return_addr (struct _Unwind_Context *current,
+		     struct _Unwind_Context *target)
+{
+  void *ret_addr = __builtin_frob_return_addr (target->ra);
+#ifdef MD_POST_FROB_EH_HANDLER_ADDR
+  ret_addr = MD_POST_FROB_EH_HANDLER_ADDR (current, target, ret_addr);
+#endif
+  return ret_addr;
+}
+
 /* 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.  */
@@ -1616,7 +1649,7 @@  _Unwind_DebugHook (void *cfa __attribute__ ((__unused__)),
   do									\
     {									\
       long offset = uw_install_context_1 ((CURRENT), (TARGET));		\
-      void *handler = __builtin_frob_return_addr ((TARGET)->ra);	\
+      void *handler = uw_frob_return_addr ((CURRENT), (TARGET));	\
       _Unwind_DebugHook ((TARGET)->cfa, handler);			\
       __builtin_eh_return (offset, handler);				\
     }									\
diff --git a/libgcc/config.host b/libgcc/config.host
index 6f2e458e74e776a6b7a310919558bcca76389232..540bfa9635802adabb36a2d1b7cf3416462c59f3 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -331,11 +331,13 @@  aarch64*-*-elf | aarch64*-*-rtems*)
 	extra_parts="$extra_parts crtfastmath.o"
 	tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
 	tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
+	md_unwind_header=aarch64/aarch64-unwind.h
 	;;
 aarch64*-*-freebsd*)
 	extra_parts="$extra_parts crtfastmath.o"
 	tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
 	tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm"
+	md_unwind_header=aarch64/aarch64-unwind.h
 	;;
 aarch64*-*-linux*)
 	extra_parts="$extra_parts crtfastmath.o"
diff --git a/libgcc/config/aarch64/aarch64-unwind.h b/libgcc/config/aarch64/aarch64-unwind.h
new file mode 100644
index 0000000000000000000000000000000000000000..a57cae0ff54ea7e11c32362677c0b51501a9f727
--- /dev/null
+++ b/libgcc/config/aarch64/aarch64-unwind.h
@@ -0,0 +1,87 @@ 
+/* Copyright (C) 2017 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef AARCH64_UNWIND_H
+#define AARCH64_UNWIND_H
+
+#define DWARF_REGNUM_AARCH64_RA_STATE 34
+
+#define MD_POST_EXTRACT_ROOT_ADDR(addr)  __builtin_aarch64_xpaclri (addr)
+#define MD_POST_EXTRACT_FRAME_ADDR(context, fs, addr) \
+  aarch64_post_extract_frame_addr (context, fs, addr)
+#define MD_POST_FROB_EH_HANDLER_ADDR(current, target, addr) \
+  aarch64_post_frob_eh_handler_addr (current, target, addr)
+#define MD_FROB_UPDATE_CONTEXT(context, fs) \
+  aarch64_frob_update_context (context, fs)
+
+/* Do AArch64 private extraction on ADDR based on context info CONTEXT and
+   unwind frame info FS.  If ADDR is signed, we do address authentication on it
+   using CFA of current frame.  */
+
+static void *
+aarch64_post_extract_frame_addr (struct _Unwind_Context *context,
+				 _Unwind_FrameState *fs, void *addr)
+{
+  if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
+    {
+      _Unwind_Word salt = (_Unwind_Word) context->cfa;
+      return __builtin_aarch64_autia1716 (addr, salt);
+    }
+  else
+    return addr;
+}
+
+/* Do AArch64 private frob on exception handler's address HANDLER_ADDR before
+   installing it into current context CURRENT.  TARGET is currently not used.
+   We need to sign exception handler's address if CURRENT itself is signed.  */
+
+static void *
+aarch64_post_frob_eh_handler_addr (struct _Unwind_Context *current,
+				   struct _Unwind_Context *target
+				   ATTRIBUTE_UNUSED,
+				   void *handler_addr)
+{
+  if (current->flags & RA_A_SIGNED_BIT)
+    return __builtin_aarch64_pacia1716 (handler_addr,
+					(_Unwind_Word) current->cfa);
+  else
+    return handler_addr;
+}
+
+/* Do AArch64 private initialization on CONTEXT based on frame info FS.  Mark
+   CONTEXT as return address signed if bit 0 of DWARF_REGNUM_AARCH64_RA_STATE is
+   set.  */
+
+static void
+aarch64_frob_update_context (struct _Unwind_Context *context,
+			     _Unwind_FrameState *fs)
+{
+  if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
+    /* The flag is used for re-authenticating EH handler's address.  */
+    context->flags |= RA_A_SIGNED_BIT;
+
+  return;
+}
+
+#endif /* defined AARCH64_UNWIND_H */
diff --git a/libgcc/config/aarch64/linux-unwind.h b/libgcc/config/aarch64/linux-unwind.h
index 1256f010007ac964de8bb895379a7d893a446bd9..75774b30c080ad2361fb37c7208bcf3d3b57d77a 100644
--- a/libgcc/config/aarch64/linux-unwind.h
+++ b/libgcc/config/aarch64/linux-unwind.h
@@ -24,6 +24,7 @@ 
 
 #include <signal.h>
 #include <sys/ucontext.h>
+#include "aarch64-unwind.h"
 
 
 /* Since insns are always stored LE, on a BE system the opcodes will