Blame SOURCES/gcc48-aarch64-pauth.patch

57942a
2017-01-19  Jiong Wang  <jiong.wang@arm.com>
57942a
57942a
	* config/aarch64/aarch64-unwind.h: New file.
57942a
	(DWARF_REGNUM_AARCH64_RA_STATE): Define.
57942a
	(MD_POST_EXTRACT_ROOT_ADDR): New target marcro and define it on AArch64.
57942a
	(MD_POST_EXTRACT_FRAME_ADDR): Likewise.
57942a
	(MD_POST_FROB_EH_HANDLER_ADDR): Likewise.
57942a
	(MD_FROB_UPDATE_CONTEXT): Define it on AArch64.
57942a
	(aarch64_post_extract_frame_addr): New function.
57942a
	(aarch64_post_frob_eh_handler_addr): New function.
57942a
	(aarch64_frob_update_context): New function.
57942a
	* config/aarch64/linux-unwind.h: Include aarch64-unwind.h
57942a
	* config.host (aarch64*-*-elf, aarch64*-*-rtems*,
57942a
	aarch64*-*-freebsd*):
57942a
	Initialize md_unwind_header to include aarch64-unwind.h.
57942a
	* unwind-dw2.c (struct _Unwind_Context): Define "RA_A_SIGNED_BIT".
57942a
	(execute_cfa_program): Multiplex DW_CFA_GNU_window_save for
57942a
	__aarch64__.
57942a
	(uw_update_context): Honor MD_POST_EXTRACT_FRAME_ADDR.
57942a
	(uw_init_context_1): Honor MD_POST_EXTRACT_ROOT_ADDR.
57942a
	(uw_frob_return_addr): New function.
57942a
	(uw_install_context): Use uw_frob_return_addr.
57942a
57942a
--- libgcc/config.host	(revision 244672)
57942a
+++ libgcc/config.host	(revision 244674)
57942a
@@ -284,6 +284,7 @@
57942a
 	extra_parts="$extra_parts crtbegin.o crtend.o crti.o crtn.o"
57942a
 	tmake_file="${tmake_file} ${cpu_type}/t-aarch64"
57942a
 	tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp"
57942a
+	md_unwind_header=aarch64/aarch64-unwind.h
57942a
 	;;
57942a
 aarch64*-*-linux*)
57942a
 	md_unwind_header=aarch64/linux-unwind.h
57942a
--- libgcc/config/aarch64/aarch64-unwind.h	(nonexistent)
57942a
+++ libgcc/config/aarch64/aarch64-unwind.h	(revision 244674)
57942a
@@ -0,0 +1,89 @@
57942a
+/* Copyright (C) 2017 Free Software Foundation, Inc.
57942a
+   Contributed by ARM Ltd.
57942a
+
57942a
+This file is part of GCC.
57942a
+
57942a
+GCC is free software; you can redistribute it and/or modify it under
57942a
+the terms of the GNU General Public License as published by the Free
57942a
+Software Foundation; either version 3, or (at your option) any later
57942a
+version.
57942a
+
57942a
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
57942a
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
57942a
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
57942a
+for more details.
57942a
+
57942a
+Under Section 7 of GPL version 3, you are granted additional
57942a
+permissions described in the GCC Runtime Library Exception, version
57942a
+3.1, as published by the Free Software Foundation.
57942a
+
57942a
+You should have received a copy of the GNU General Public License and
57942a
+a copy of the GCC Runtime Library Exception along with this program;
57942a
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
57942a
+<http://www.gnu.org/licenses/>.  */
57942a
+
57942a
+#ifndef AARCH64_UNWIND_H
57942a
+#define AARCH64_UNWIND_H
57942a
+
57942a
+#define DWARF_REGNUM_AARCH64_RA_STATE 34
57942a
+
57942a
+#define MD_POST_EXTRACT_ROOT_ADDR(addr) \
57942a
+  ({ void *__addr; asm ("mov x30, %0; hint 7; mov %0, x30" \
57942a
+			: "=r" (__addr) : "0" (addr) : "x30", "cc"); __addr; })
57942a
+#define MD_POST_EXTRACT_FRAME_ADDR(context, fs, addr) \
57942a
+  aarch64_post_extract_frame_addr (context, fs, addr)
57942a
+#define MD_POST_FROB_EH_HANDLER_ADDR(current, target, addr) \
57942a
+  aarch64_post_frob_eh_handler_addr (current, target, addr)
57942a
+#define MD_FROB_UPDATE_CONTEXT(context, fs) \
57942a
+  aarch64_frob_update_context (context, fs)
57942a
+
57942a
+/* Do AArch64 private extraction on ADDR based on context info CONTEXT and
57942a
+   unwind frame info FS.  If ADDR is signed, we do address authentication on it
57942a
+   using CFA of current frame.  */
57942a
+
57942a
+static inline void *
57942a
+aarch64_post_extract_frame_addr (struct _Unwind_Context *context,
57942a
+				 _Unwind_FrameState *fs, void *addr)
57942a
+{
57942a
+  if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
57942a
+    {
57942a
+      _Unwind_Word salt = (_Unwind_Word) context->cfa;
57942a
+      asm ("mov x17, %0; mov x16, %1; hint 12; mov %0, x17"
57942a
+	   : "+r" (addr) : "r" (salt) : "x16", "x17", "cc");
57942a
+    }
57942a
+  return addr;
57942a
+}
57942a
+
57942a
+/* Do AArch64 private frob on exception handler's address HANDLER_ADDR before
57942a
+   installing it into current context CURRENT.  TARGET is currently not used.
57942a
+   We need to sign exception handler's address if CURRENT itself is signed.  */
57942a
+
57942a
+static inline void *
57942a
+aarch64_post_frob_eh_handler_addr (struct _Unwind_Context *current,
57942a
+				   struct _Unwind_Context *target
57942a
+				   ATTRIBUTE_UNUSED,
57942a
+				   void *handler_addr)
57942a
+{
57942a
+  if (current->flags & RA_A_SIGNED_BIT)
57942a
+    asm ("mov x17, %0; mov x16, %1; hint 8; mov %0, x17"
57942a
+	  : "+r" (handler_addr) : "r" ((_Unwind_Word) current->cfa)
57942a
+	  : "x16", "x17", "cc");
57942a
+  return handler_addr;
57942a
+}
57942a
+
57942a
+/* Do AArch64 private initialization on CONTEXT based on frame info FS.  Mark
57942a
+   CONTEXT as return address signed if bit 0 of DWARF_REGNUM_AARCH64_RA_STATE is
57942a
+   set.  */
57942a
+
57942a
+static inline void
57942a
+aarch64_frob_update_context (struct _Unwind_Context *context,
57942a
+			     _Unwind_FrameState *fs)
57942a
+{
57942a
+  if (fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset & 0x1)
57942a
+    /* The flag is used for re-authenticating EH handler's address.  */
57942a
+    context->flags |= RA_A_SIGNED_BIT;
57942a
+
57942a
+  return;
57942a
+}
57942a
+
57942a
+#endif /* defined AARCH64_UNWIND_H */
57942a
--- libgcc/config/aarch64/linux-unwind.h	(revision 244672)
57942a
+++ libgcc/config/aarch64/linux-unwind.h	(revision 244674)
57942a
@@ -24,6 +24,7 @@
57942a
 
57942a
 #include <signal.h>
57942a
 #include <sys/ucontext.h>
57942a
+#include "config/aarch64/aarch64-unwind.h"
57942a
 
57942a
 #define MD_FALLBACK_FRAME_STATE_FOR aarch64_fallback_frame_state
57942a
 
57942a
--- libgcc/unwind-dw2.c	(revision 244672)
57942a
+++ libgcc/unwind-dw2.c	(revision 244674)
57942a
@@ -136,6 +136,8 @@ struct _Unwind_Context
57942a
 #define SIGNAL_FRAME_BIT ((~(_Unwind_Word) 0 >> 1) + 1)
57942a
   /* Context which has version/args_size/by_value fields.  */
57942a
 #define EXTENDED_CONTEXT_BIT ((~(_Unwind_Word) 0 >> 2) + 1)
57942a
+  /* Bit reserved on AArch64, return address has been signed with A key.  */
57942a
+#define RA_A_SIGNED_BIT ((~(_Unwind_Word) 0 >> 3) + 1)
57942a
   _Unwind_Word flags;
57942a
   /* 0 for now, can be increased when further fields are added to
57942a
      struct _Unwind_Context.  */
57942a
@@ -1189,6 +1191,11 @@ execute_cfa_program (const unsigned char
57942a
 	  break;
57942a
 
57942a
 	case DW_CFA_GNU_window_save:
57942a
+#ifdef __aarch64__
57942a
+	  /* This CFA is multiplexed with Sparc.  On AArch64 it's used to toggle
57942a
+	     return address signing status.  */
57942a
+	  fs->regs.reg[DWARF_REGNUM_AARCH64_RA_STATE].loc.offset ^= 1;
57942a
+#else
57942a
 	  /* ??? Hardcoded for SPARC register window configuration.  */
57942a
 	  if (DWARF_FRAME_REGISTERS >= 32)
57942a
 	    for (reg = 16; reg < 32; ++reg)
57942a
@@ -1192,6 +1199,7 @@ execute_cfa_program (const unsigned char
57942a
 		fs->regs.reg[reg].how = REG_SAVED_OFFSET;
57942a
 		fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
57942a
 	      }
57942a
+#endif
57942a
 	  break;
57942a
 
57942a
 	case DW_CFA_GNU_args_size:
57942a
@@ -1513,10 +1521,15 @@ uw_update_context (struct _Unwind_Contex
57942a
        stack frame.  */
57942a
     context->ra = 0;
57942a
   else
57942a
-    /* Compute the return address now, since the return address column
57942a
-       can change from frame to frame.  */
57942a
-    context->ra = __builtin_extract_return_addr
57942a
-      (_Unwind_GetPtr (context, fs->retaddr_column));
57942a
+    {
57942a
+      /* Compute the return address now, since the return address column
57942a
+	 can change from frame to frame.  */
57942a
+      context->ra = __builtin_extract_return_addr
57942a
+	(_Unwind_GetPtr (context, fs->retaddr_column));
57942a
+#ifdef MD_POST_EXTRACT_FRAME_ADDR
57942a
+      context->ra = MD_POST_EXTRACT_FRAME_ADDR (context, fs, context->ra);
57942a
+#endif
57942a
+    }
57942a
 }
57942a
 
57942a
 static void
57942a
@@ -1550,6 +1563,9 @@ uw_init_context_1 (struct _Unwind_Contex
57942a
 		   void *outer_cfa, void *outer_ra)
57942a
 {
57942a
   void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
57942a
+#ifdef MD_POST_EXTRACT_ROOT_ADDR
57942a
+  ra = MD_POST_EXTRACT_ROOT_ADDR (ra);
57942a
+#endif
57942a
   _Unwind_FrameState fs;
57942a
   _Unwind_SpTmp sp_slot;
57942a
   _Unwind_Reason_Code code;
57942a
@@ -1586,6 +1602,9 @@ uw_init_context_1 (struct _Unwind_Contex
57942a
      initialization context, then we can't see it in the given
57942a
      call frame data.  So have the initialization context tell us.  */
57942a
   context->ra = __builtin_extract_return_addr (outer_ra);
57942a
+#ifdef MD_POST_EXTRACT_ROOT_ADDR
57942a
+  context->ra = MD_POST_EXTRACT_ROOT_ADDR (context->ra);
57942a
+#endif
57942a
 }
57942a
 
57942a
 static void _Unwind_DebugHook (void *, void *)
57942a
@@ -1608,6 +1627,10 @@ _Unwind_DebugHook (void *cfa __attribute
57942a
 #endif
57942a
 }
57942a
57942a
+#ifndef MD_POST_FROB_EH_HANDLER_ADDR
57942a
+#define MD_POST_FROB_EH_HANDLER_ADDR(c, t, r) r
57942a
+#endif 
57942a
+
57942a
 /* Install TARGET into CURRENT so that we can return to it.  This is a
57942a
    macro because __builtin_eh_return must be invoked in the context of
57942a
    our caller.  */
57942a
@@ -1621,6 +1644,8 @@ _Unwind_DebugHook (void *cfa __attribute
57942a
     {									\
57942a
       long offset = uw_install_context_1 ((CURRENT), (TARGET));		\
57942a
       void *handler = __builtin_frob_return_addr ((TARGET)->ra);	\
57942a
+      handler = (MD_POST_FROB_EH_HANDLER_ADDR ((CURRENT), (TARGET),	\
57942a
+		  handler));						\
57942a
       _Unwind_DebugHook ((TARGET)->cfa, handler);			\
57942a
       __builtin_eh_return (offset, handler);				\
57942a
     }									\