On 11/11/16 18:22, Jiong Wang wrote:
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<jiong.w...@arm.com>

         * 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.


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.w...@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.

diff --git a/libgcc/config/aarch64/unwind-aarch64.c b/libgcc/config/aarch64/unwind-aarch64.c
index 1fb6026d123f8e7fc676f5e95e8e66caccf3d6ff..11e3c9f724c9bc5796103a0d973bfe769d23b6e7 100644
--- a/libgcc/config/aarch64/unwind-aarch64.c
+++ b/libgcc/config/aarch64/unwind-aarch64.c
@@ -37,6 +37,9 @@
 #include "gthr.h"
 #include "unwind-dw2.h"
 
+/* This is a copy of libgcc/unwind-dw2.c with AArch64 return address signing
+   support.  */
+
 #ifdef HAVE_SYS_SDT_H
 #include <sys/sdt.h>
 #endif
@@ -55,6 +58,8 @@
 #define PRE_GCC3_DWARF_FRAME_REGISTERS __LIBGCC_DWARF_FRAME_REGISTERS__
 #endif
 
+#define DWARF_REGNUM_AARCH64_RA_STATE 32
+
 /* ??? For the public function interfaces, we tend to gcc_assert that the
    column numbers are in range.  For the dwarf2 unwind info this does happen,
    although so far in a case that doesn't actually matter.
@@ -136,6 +141,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 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,13 +1192,9 @@ execute_cfa_program (const unsigned char *insn_ptr,
 	  break;
 
 	case DW_CFA_GNU_window_save:
-	  /* ??? Hardcoded for SPARC register window configuration.  */
-	  if (__LIBGCC_DWARF_FRAME_REGISTERS__ >= 32)
-	    for (reg = 16; reg < 32; ++reg)
-	      {
-		fs->regs.reg[reg].how = REG_SAVED_OFFSET;
-		fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
-	      }
+	  /* 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;
 	  break;
 
 	case DW_CFA_GNU_args_size:
@@ -1263,6 +1266,8 @@ uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
   /* First decode all the insns in the CIE.  */
   end = (const unsigned char *) next_fde ((const struct dwarf_fde *) cie);
   execute_cfa_program (insn, end, context, fs);
+  /* Clear bit 0 of RA_STATE pseudo register.  */
+  fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset &= ~0x1;
 
   /* Locate augmentation for the fde.  */
   aug = (const unsigned char *) fde + sizeof (*fde);
@@ -1513,10 +1518,19 @@ 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));
+      if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
+	{
+	  _Unwind_Word salt = (_Unwind_Word) context->cfa;
+	  context->ra
+	    = (void *) __builtin_aarch64_autia1716 (context->ra, salt);
+	}
+    }
 }
 
 static void
@@ -1550,6 +1564,11 @@ 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 +1605,10 @@ 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);
+  context->ra = __builtin_aarch64_xpaclri (context->ra);
+  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;
 }
 
 static void _Unwind_DebugHook (void *, void *)
@@ -1610,13 +1633,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_A_SIGNED_BIT)				\
+	handler								\
+	  = __builtin_aarch64_pacia1716 (handler,			\
+					 (_Unwind_Word)			\
+					 (CURRENT)->cfa);		\
       _Unwind_DebugHook ((TARGET)->cfa, handler);			\
       __builtin_eh_return (offset, handler);				\
     }									\

Reply via email to