[libunwind] r349140 - [AArch64][libunwind] Unwinding support for return address signing

Luke Cheeseman via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 14 03:30:12 PST 2018


Author: lukecheeseman
Date: Fri Dec 14 03:30:12 2018
New Revision: 349140

URL: http://llvm.org/viewvc/llvm-project?rev=349140&view=rev
Log:
[AArch64][libunwind] Unwinding support for return address signing

- Follow up to revision r342895
- gcc would not build libunwind with the earlier patch as the autia1716
  instruction wasn't allowed to be assembled for pre armv8.3a targets
- The autia1716 instruction lives in the hint space encodings so is a valid
  instruction for all armv8a targets
- To work around this I have swapped out the autia1716 instruction for the hint
  instruction

Differential Revision: https://reviews.llvm.org/D55700


Modified:
    libunwind/trunk/include/libunwind.h
    libunwind/trunk/src/DwarfInstructions.hpp
    libunwind/trunk/src/DwarfParser.hpp
    libunwind/trunk/src/Registers.hpp
    libunwind/trunk/src/dwarf2.h

Modified: libunwind/trunk/include/libunwind.h
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/include/libunwind.h?rev=349140&r1=349139&r2=349140&view=diff
==============================================================================
--- libunwind/trunk/include/libunwind.h (original)
+++ libunwind/trunk/include/libunwind.h Fri Dec 14 03:30:12 2018
@@ -57,6 +57,9 @@ enum {
   UNW_EINVAL        = -6547, /* unsupported operation or bad value */
   UNW_EBADVERSION   = -6548, /* unwind info has unsupported version */
   UNW_ENOINFO       = -6549  /* no unwind info found */
+#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */
+#endif
 };
 
 struct unw_context_t {
@@ -547,6 +550,8 @@ enum {
   UNW_ARM64_X31 = 31,
   UNW_ARM64_SP  = 31,
   // reserved block
+  UNW_ARM64_RA_SIGN_STATE = 34,
+  // reserved block
   UNW_ARM64_D0  = 64,
   UNW_ARM64_D1  = 65,
   UNW_ARM64_D2  = 66,

Modified: libunwind/trunk/src/DwarfInstructions.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/DwarfInstructions.hpp?rev=349140&r1=349139&r2=349140&view=diff
==============================================================================
--- libunwind/trunk/src/DwarfInstructions.hpp (original)
+++ libunwind/trunk/src/DwarfInstructions.hpp Fri Dec 14 03:30:12 2018
@@ -198,6 +198,27 @@ int DwarfInstructions<A, R>::stepWithDwa
       // restoring SP means setting it to CFA.
       newRegisters.setSP(cfa);
 
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+      // If the target is aarch64 then the return address may have been signed
+      // using the v8.3 pointer authentication extensions. The original
+      // return address needs to be authenticated before the return address is
+      // restored. autia1716 is used instead of autia as autia1716 assembles
+      // to a NOP on pre-v8.3a architectures.
+      if (prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+        return UNW_ECROSSRASIGNING;
+#else
+        register unsigned long long x17 __asm("x17") = returnAddress;
+        register unsigned long long x16 __asm("x16") = cfa;
+
+        // This is the autia1716 instruction. The hint instruction is used here
+        // as gcc does not assemble autia1716 for pre armv8.3a targets.
+        asm("hint 0xc": "+r"(x17): "r"(x16));
+        returnAddress = x17;
+#endif
+      }
+#endif
+
       // Return address is address after call site instruction, so setting IP to
       // that does simualates a return.
       newRegisters.setIP(returnAddress);

Modified: libunwind/trunk/src/DwarfParser.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/DwarfParser.hpp?rev=349140&r1=349139&r2=349140&view=diff
==============================================================================
--- libunwind/trunk/src/DwarfParser.hpp (original)
+++ libunwind/trunk/src/DwarfParser.hpp Fri Dec 14 03:30:12 2018
@@ -666,6 +666,14 @@ bool CFI_Parser<A>::parseInstructions(A
       _LIBUNWIND_TRACE_DWARF(
           "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
       break;
+
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+    case DW_CFA_AARCH64_negate_ra_state:
+      results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
+      _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
+      break;
+#endif
+
     default:
       operand = opcode & 0x3F;
       switch (opcode & 0xC0) {

Modified: libunwind/trunk/src/Registers.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/Registers.hpp?rev=349140&r1=349139&r2=349140&view=diff
==============================================================================
--- libunwind/trunk/src/Registers.hpp (original)
+++ libunwind/trunk/src/Registers.hpp Fri Dec 14 03:30:12 2018
@@ -1786,7 +1786,7 @@ private:
     uint64_t __lr;    // Link register x30
     uint64_t __sp;    // Stack pointer x31
     uint64_t __pc;    // Program counter
-    uint64_t padding; // 16-byte align
+    uint64_t __ra_sign_state; // RA sign state register
   };
 
   GPRs    _registers;
@@ -1822,6 +1822,8 @@ inline bool Registers_arm64::validRegist
     return false;
   if (regNum > 95)
     return false;
+  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+    return true;
   if ((regNum > 31) && (regNum < 64))
     return false;
   return true;
@@ -1832,6 +1834,8 @@ inline uint64_t Registers_arm64::getRegi
     return _registers.__pc;
   if (regNum == UNW_REG_SP)
     return _registers.__sp;
+  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+    return _registers.__ra_sign_state;
   if ((regNum >= 0) && (regNum < 32))
     return _registers.__x[regNum];
   _LIBUNWIND_ABORT("unsupported arm64 register");
@@ -1842,6 +1846,8 @@ inline void Registers_arm64::setRegister
     _registers.__pc = value;
   else if (regNum == UNW_REG_SP)
     _registers.__sp = value;
+  else if (regNum == UNW_ARM64_RA_SIGN_STATE)
+    _registers.__ra_sign_state = value;
   else if ((regNum >= 0) && (regNum < 32))
     _registers.__x[regNum] = value;
   else

Modified: libunwind/trunk/src/dwarf2.h
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/dwarf2.h?rev=349140&r1=349139&r2=349140&view=diff
==============================================================================
--- libunwind/trunk/src/dwarf2.h (original)
+++ libunwind/trunk/src/dwarf2.h Fri Dec 14 03:30:12 2018
@@ -49,7 +49,10 @@ enum {
   // GNU extensions
   DW_CFA_GNU_window_save              = 0x2D,
   DW_CFA_GNU_args_size                = 0x2E,
-  DW_CFA_GNU_negative_offset_extended = 0x2F
+  DW_CFA_GNU_negative_offset_extended = 0x2F,
+
+  // AARCH64 extensions
+  DW_CFA_AARCH64_negate_ra_state      = 0x2D
 };
 
 




More information about the cfe-commits mailing list