https://github.com/kovdan01 created 
https://github.com/llvm/llvm-project/pull/173878

Please pay no attention to this PR, its submitted to trigger build jobs and 
ensure that WIP work is not breaking platforms I can't test locally

>From b824caa6c6cb306e0e024fe9aa872a9a5e3f35bb Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <[email protected]>
Date: Mon, 8 Dec 2025 16:31:10 +0300
Subject: [PATCH 1/2] [PAC][libunwind][AArch64] Keep LR signed when stored in
 context struct

There are two ways of return address signing: pac-ret (enabled via
`-mbranch-protection=pac-ret`) and ptrauth-returns (enabled as part of
Apple's arm64e or experimental pauthtest ABI on Linux).

Previously, signed LR was handled in libunwind as follows:

1. For pac-ret, the signed LR value was authenticated, and the resulting
   unsigned LR value was stored in the context structure.

2. For ptrauth-returns (which is assumed to be a part of a full-fledged
   PAuth ABI like arm64e or pauthtest), the signed LR value was
   re-signed using the same key (IB) and address of the `__pc` field in
   the context structure as a modifier.

This patch unifies the signed LR handling logic by keeping LR signed
for pac-ret similarly to ptrauth-returns. It makes LR substitution in
the context structure harder.

Note that LR signed state or signing scheme for pac-ret might differ between
stack frames. The behavior differs from ptrauth-returns, which has a fixed
signing scheme and is enabled as a part of bigger PAuth ABI which is either
present everywhere or not. In order to handle different signing schemes
across stack frames, new subfields `__state`, `__second_modifier` and
`__use_b_key` of the field `__ra_sign` in the context structure are used.

When stored in the context structure, the pointer is resigned with
maintaining original key and using the address of the `__pc` field in
the structure as a modifier.
---
 libunwind/include/__libunwind_config.h |   4 +-
 libunwind/include/libunwind.h          |   6 +
 libunwind/src/DwarfInstructions.hpp    |  92 +++--------
 libunwind/src/Registers.hpp            | 207 +++++++++++++++++++++----
 libunwind/src/UnwindCursor.hpp         |   8 +-
 libunwind/src/UnwindLevel1.c           |  58 ++++++-
 libunwind/src/UnwindRegistersRestore.S | 163 +++++++++++++++----
 libunwind/src/UnwindRegistersSave.S    | 104 ++++++++++---
 libunwind/src/libunwind.cpp            |  11 ++
 9 files changed, 482 insertions(+), 171 deletions(-)

diff --git a/libunwind/include/__libunwind_config.h 
b/libunwind/include/__libunwind_config.h
index 980d11ef5d4f2..3327272c2a6bc 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -73,11 +73,11 @@
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER 
_LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
 # elif defined(__aarch64__)
 #  define _LIBUNWIND_TARGET_AARCH64 1
-#define _LIBUNWIND_CONTEXT_SIZE 67
+#define _LIBUNWIND_CONTEXT_SIZE 69
 #  if defined(__SEH__)
 #    define _LIBUNWIND_CURSOR_SIZE 164
 #  else
-#define _LIBUNWIND_CURSOR_SIZE 79
+#define _LIBUNWIND_CURSOR_SIZE 81
 #  endif
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER 
_LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
 # elif defined(__arm__)
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 56ca7110274a3..6a56548867642 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -642,6 +642,12 @@ enum {
   // reserved block
   UNW_AARCH64_RA_SIGN_STATE = 34,
 
+  // The following two registers are not real Dwarf registers and use numbers
+  // which are not occupied by real Dwarf registers according to
+  // https://github.com/ARM-software/abi-aa/blob/2025Q1/aadwarf64/aadwarf64.rst
+  UNW_AARCH64_RA_SIGN_SECOND_MODIFIER = 128,
+  UNW_AARCH64_RA_SIGN_USE_B_KEY = 129,
+
   // FP/vector registers
   UNW_AARCH64_V0 = 64,
   UNW_AARCH64_V1 = 65,
diff --git a/libunwind/src/DwarfInstructions.hpp 
b/libunwind/src/DwarfInstructions.hpp
index d2822e8be29ef..ad1555db3abd2 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -75,10 +75,8 @@ class DwarfInstructions {
     __builtin_unreachable();
   }
 #if defined(_LIBUNWIND_TARGET_AARCH64)
-  static bool isReturnAddressSigned(A &addressSpace, R registers, pint_t cfa,
-                                    PrologInfo &prolog);
-  static bool isReturnAddressSignedWithPC(A &addressSpace, R registers,
-                                          pint_t cfa, PrologInfo &prolog);
+  static pint_t getRASignState(A &addressSpace, const R &registers, pint_t cfa,
+                               const PrologInfo &prolog);
 #endif
 };
 
@@ -176,34 +174,13 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
 }
 #if defined(_LIBUNWIND_TARGET_AARCH64)
 template <typename A, typename R>
-bool DwarfInstructions<A, R>::isReturnAddressSigned(A &addressSpace,
-                                                    R registers, pint_t cfa,
-                                                    PrologInfo &prolog) {
-  pint_t raSignState;
-  auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
-  if (regloc.location == CFI_Parser<A>::kRegisterUnused)
-    raSignState = static_cast<pint_t>(regloc.value);
-  else
-    raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
-
-  // Only bit[0] is meaningful.
-  return raSignState & 0x01;
-}
-
-template <typename A, typename R>
-bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
-                                                          R registers,
-                                                          pint_t cfa,
-                                                          PrologInfo &prolog) {
-  pint_t raSignState;
+typename A::pint_t
+DwarfInstructions<A, R>::getRASignState(A &addressSpace, const R &registers,
+                                        pint_t cfa, const PrologInfo &prolog) {
   auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
   if (regloc.location == CFI_Parser<A>::kRegisterUnused)
-    raSignState = static_cast<pint_t>(regloc.value);
-  else
-    raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
-
-  // Only bit[1] is meaningful.
-  return raSignState & 0x02;
+    return static_cast<pint_t>(regloc.value);
+  return getSavedRegister(addressSpace, registers, cfa, regloc);
 }
 #endif
 
@@ -302,54 +279,25 @@ int DwarfInstructions<A, R>::stepWithDwarf(A 
&addressSpace,
 
       isSignalFrame = cieInfo.isSignalFrame;
 
-#if defined(_LIBUNWIND_TARGET_AARCH64) &&                                      
\
-    !defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
-      // There are two ways of return address signing: pac-ret (enabled via
-      // -mbranch-protection=pac-ret) and ptrauth-returns (enabled as part of
-      // Apple's arm64e or experimental pauthtest ABI on Linux). The code
-      // below handles signed RA for pac-ret, while ptrauth-returns uses
-      // different logic.
-      // TODO: unify logic for both cases, see
-      // https://github.com/llvm/llvm-project/issues/160110
-      //
+#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 ((R::getArch() == REGISTERS_ARM64) &&
-          isReturnAddressSigned(addressSpace, registers, cfa, prolog) &&
+      // using the v8.3 pointer authentication extensions. In order to
+      // store signed return address in the registers context structure, we
+      // need to save the signing scheme for this address.
+      pint_t raSignState = getRASignState(addressSpace, registers, cfa, 
prolog);
+      bool isReturnAddressSigned = (raSignState & 1);
+      if ((R::getArch() == REGISTERS_ARM64) && isReturnAddressSigned &&
           returnAddress != 0) {
 #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;
-
-        // We use the hint versions of the authentication instructions below to
-        // ensure they're assembled by the compiler even for targets with no
-        // FEAT_PAuth/FEAT_PAuth_LR support.
-        if (isReturnAddressSignedWithPC(addressSpace, registers, cfa, prolog)) 
{
-          register unsigned long long x15 __asm("x15") =
-              prolog.ptrAuthDiversifier;
-          if (cieInfo.addressesSignedWithBKey) {
-            asm("hint 0x27\n\t" // pacm
-                "hint 0xe"
-                : "+r"(x17)
-                : "r"(x16), "r"(x15)); // autib1716
-          } else {
-            asm("hint 0x27\n\t" // pacm
-                "hint 0xc"
-                : "+r"(x17)
-                : "r"(x16), "r"(x15)); // autia1716
-          }
-        } else {
-          if (cieInfo.addressesSignedWithBKey)
-            asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
-          else
-            asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+        newRegisters.setRegister(UNW_AARCH64_RA_SIGN_STATE, raSignState);
+        if (newRegisters.isReturnAddressSignedWithPC()) {
+          newRegisters.setRegister(UNW_AARCH64_RA_SIGN_SECOND_MODIFIER,
+                                   prolog.ptrAuthDiversifier);
         }
-        returnAddress = x17;
+        newRegisters.setRegister(UNW_AARCH64_RA_SIGN_USE_B_KEY,
+                                 cieInfo.addressesSignedWithBKey ? 1 : 0);
 #endif
       }
 #endif
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 45a2b0921ea3b..2245ccba61e4f 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1877,49 +1877,179 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
 
   uint64_t  getSP() const         { return _registers.__sp; }
   void      setSP(uint64_t value) { _registers.__sp = value; }
+
   uint64_t  getIP() const {
     uint64_t value = _registers.__pc;
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+
+    if (!isReturnAddressSigned())
+      return value;
+
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+    abortCrossRASigning();
+#else
     // Note the value of the PC was signed to its address in the register state
     // but everyone else expects it to be sign by the SP, so convert on return.
-    value = (uint64_t)ptrauth_auth_and_resign((void *)_registers.__pc,
-                                              ptrauth_key_return_address,
-                                              &_registers.__pc,
-                                              ptrauth_key_return_address,
-                                              getSP());
+    register uint64_t x17 __asm("x17") = value;
+    register uint64_t x16 __asm("x16") =
+        reinterpret_cast<uint64_t>(&_registers.__pc);
+    register uint64_t x14 __asm("x14") = getSP();
+    if (isReturnAddressSignedWithPC()) {
+      register uint64_t x15 __asm("x15") =
+          _registers.__ra_sign.__second_modifier;
+      if (isReturnAddressSignedWithBKey()) {
+        asm("hint 0xe    \n\t" // autib1716
+            "mov x16, x14\n\t"
+            "hint 0x27   \n\t" // pacm
+            "hint 0xa        " // pacib1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x15), "r"(x14));
+      } else {
+        asm("hint 0xc    \n\t" // autia1716
+            "mov x16, x14\n\t"
+            "hint 0x27   \n\t" // pacm
+            "hint 0x8        " // pacia1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x15), "r"(x14));
+      }
+    } else {
+      if (isReturnAddressSignedWithBKey()) {
+        asm("hint 0xe    \n\t" // autib1716
+            "mov x16, x14\n\t"
+            "hint 0xa        " // pacib1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x14));
+      } else {
+        asm("hint 0xc    \n\t" // autia1716
+            "mov x16, x14\n\t"
+            "hint 0x8        " // pacia1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x14));
+      }
+    }
+    return x17;
 #endif
-    return value;
   }
+
   void      setIP(uint64_t value) {
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+    if (!isReturnAddressSigned()) {
+      _registers.__pc = value;
+      return;
+    }
+
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+    abortCrossRASigning();
+#else
     // Note the value which was set should have been signed with the SP.
     // We then resign with the slot we are being stored in to so that both SP
     // and LR can't be spoofed at the same time.
-    value = (uint64_t)ptrauth_auth_and_resign((void *)value,
-                                              ptrauth_key_return_address,
-                                              getSP(),
-                                              ptrauth_key_return_address,
-                                              &_registers.__pc);
+    register uint64_t x17 __asm("x17") = value;
+    register uint64_t x16 __asm("x16") = getSP();
+    register uint64_t x14 __asm("x14") =
+        reinterpret_cast<uint64_t>(&_registers.__pc);
+    if (isReturnAddressSignedWithPC()) {
+      register uint64_t x15 __asm("x15") =
+          _registers.__ra_sign.__second_modifier;
+      if (isReturnAddressSignedWithBKey()) {
+        asm("hint 0x27   \n\t" // pacm
+            "hint 0xe    \n\t" // autib1716
+            "mov x16, x14\n\t"
+            "hint 0xa        " // pacib1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x15), "r"(x14));
+      } else {
+        asm("hint 0x27   \n\t" // pacm
+            "hint 0xc    \n\t" // autia1716
+            "mov x16, x14\n\t"
+            "hint 0x8        " // pacia1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x15), "r"(x14));
+      }
+    } else {
+      if (isReturnAddressSignedWithBKey()) {
+        asm("hint 0xe    \n\t" // autib1716
+            "mov x16, x14\n\t"
+            "hint 0xa        " // pacib1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x14));
+      } else {
+        asm("hint 0xc    \n\t" // autia1716
+            "mov x16, x14\n\t"
+            "hint 0x8        " // pacia1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x14));
+      }
+    }
+    _registers.__pc = x17;
 #endif
-    _registers.__pc = value;
   }
+
   uint64_t getFP() const { return _registers.__fp; }
   void setFP(uint64_t value) { _registers.__fp = value; }
 
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+  // NOTE: For full-fledged PAuth ABIs like Apple's arm64e and Linux's
+  // pauthtest link_reg_t is __ptrauth-qualified. So, LR is re-signed with
+  // link_reg_t signing scheme after it is authenticated with this function.
+  // When just pac-ret is used, link_reg_t is not __ptrauth-qualified and LR
+  // remains unsigned after authentication.
+  // TODO: avoid exposing unsigned LR in absence of full-fledged PAuth ABI.
   void
   loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
                                   link_reg_t *referenceAuthedLinkRegister) {
-    // If we are in an arm64/arm64e frame, then the PC should have been signed
-    // with the SP
-    *referenceAuthedLinkRegister =
-      (uint64_t)ptrauth_auth_data((void *)inplaceAuthedLinkRegister,
-                                  ptrauth_key_return_address,
-                                  _registers.__sp);
-  }
+    if (!isReturnAddressSigned()) {
+      *referenceAuthedLinkRegister = inplaceAuthedLinkRegister;
+      return;
+    }
+
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+    abortCrossRASigning();
+#else
+    register reg_t x17 __asm("x17") = inplaceAuthedLinkRegister;
+    register reg_t x16 __asm("x16") = getSP();
+    if (isReturnAddressSignedWithPC()) {
+      register reg_t x15 __asm("x15") = _registers.__ra_sign.__second_modifier;
+      if (isReturnAddressSignedWithBKey()) {
+        asm("hint 0x27\n\t" // pacm
+            "hint 0xe     " // autib1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x15));
+      } else {
+        asm("hint 0x27\n\t" // pacm
+            "hint 0xc     " // autia1716
+            : "+r"(x17)
+            : "r"(x16), "r"(x15));
+      }
+    } else {
+      if (isReturnAddressSignedWithBKey()) {
+        asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
+      } else {
+        asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+      }
+    }
+    *referenceAuthedLinkRegister = x17;
 #endif
+  }
+
+  bool isReturnAddressSigned() const {
+    return _registers.__ra_sign.__state & 1;
+  }
+  bool isReturnAddressSignedWithPC() const {
+    return _registers.__ra_sign.__state & 2;
+  }
+  bool isReturnAddressSignedWithBKey() const {
+    return _registers.__ra_sign.__use_b_key;
+  }
 
 private:
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  void abortCrossRASigning() const {
+    // We should never go here since non-null RA signed state is either set
+    // by architecture-specific __unw_getcontext or by stepWithDwarf which
+    // already contains a corresponding check and should have already
+    // emitted the UNW_ECROSSRASIGNING error.
+    _LIBUNWIND_ABORT("UNW_ECROSSRASIGNING");
+  }
+#endif
+
   uint64_t lazyGetVG() const;
 
   void zaDisable() const {
@@ -1945,7 +2075,12 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
     uint64_t __lr = 0;            // Link register x30
     uint64_t __sp = 0;            // Stack pointer x31
     uint64_t __pc = 0;            // Program counter
-    uint64_t __ra_sign_state = 0; // RA sign state register
+    struct RASign {
+      uint64_t __state = 0;           // RA sign state register
+      uint64_t __second_modifier = 0; // Additional modifier used for RA
+                                      // signing with FEAT_PAuth_LR
+      uint64_t __use_b_key = 0;       // 0 for IA key, 1 for IB key
+    } __ra_sign;
   };
 
   struct Misc {
@@ -1971,14 +2106,13 @@ inline Registers_arm64::Registers_arm64(const void 
*registers) {
   static_assert((check_fit<Registers_arm64, unw_context_t>::does_fit),
                 "arm64 registers do not fit into unw_context_t");
   memcpy(&_registers, registers, sizeof(_registers));
-  static_assert(sizeof(GPRs) == 0x110,
-                "expected VFP registers to be at offset 272");
+  static_assert(sizeof(GPRs) == 0x120,
+                "expected VFP registers to be at offset 288");
   memcpy(_vectorHalfRegisters,
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
   _misc_registers.__vg = 0;
 
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   // We have to do some pointer authentication fixups after this copy,
   // and as part of that we need to load the source pc without
   // authenticating so that we maintain the signature for the resigning
@@ -1987,7 +2121,6 @@ inline Registers_arm64::Registers_arm64(const void 
*registers) {
   memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
           sizeof(pcRegister));
   setIP(pcRegister);
-#endif
 }
 
 inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
@@ -2008,12 +2141,16 @@ inline bool Registers_arm64::validRegister(int regNum) 
const {
     return true;
   if (regNum == UNW_REG_SP)
     return true;
+  if (regNum == UNW_AARCH64_RA_SIGN_STATE)
+    return true;
+  if (regNum == UNW_AARCH64_RA_SIGN_SECOND_MODIFIER)
+    return true;
+  if (regNum == UNW_AARCH64_RA_SIGN_USE_B_KEY)
+    return true;
   if (regNum < 0)
     return false;
   if (regNum > 95)
     return false;
-  if (regNum == UNW_AARCH64_RA_SIGN_STATE)
-    return true;
   if (regNum == UNW_AARCH64_VG)
     return true;
   if ((regNum > 32) && (regNum < 64))
@@ -2041,7 +2178,11 @@ inline uint64_t Registers_arm64::getRegister(int regNum) 
const {
   if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
     return _registers.__sp;
   if (regNum == UNW_AARCH64_RA_SIGN_STATE)
-    return _registers.__ra_sign_state;
+    return _registers.__ra_sign.__state;
+  if (regNum == UNW_AARCH64_RA_SIGN_SECOND_MODIFIER)
+    return _registers.__ra_sign.__second_modifier;
+  if (regNum == UNW_AARCH64_RA_SIGN_USE_B_KEY)
+    return _registers.__ra_sign.__use_b_key;
   if (regNum == UNW_AARCH64_FP)
     return getFP();
   if (regNum == UNW_AARCH64_LR)
@@ -2059,7 +2200,11 @@ inline void Registers_arm64::setRegister(int regNum, 
uint64_t value) {
   else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
     _registers.__sp = value;
   else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
-    _registers.__ra_sign_state = value;
+    _registers.__ra_sign.__state = value;
+  else if (regNum == UNW_AARCH64_RA_SIGN_SECOND_MODIFIER)
+    _registers.__ra_sign.__second_modifier = value;
+  else if (regNum == UNW_AARCH64_RA_SIGN_USE_B_KEY)
+    _registers.__ra_sign.__use_b_key = value;
   else if (regNum == UNW_AARCH64_FP)
     setFP(value);
   else if (regNum == UNW_AARCH64_LR)
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index afa0cae790377..60ef722ae08e5 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1065,7 +1065,7 @@ class UnwindCursor : public AbstractUnwindCursor{
                                const UnwindInfoSections &sects,
                                uint32_t fdeSectionOffsetHint = 0);
   int stepWithDwarfFDE(bool stage2) {
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+#if defined(_LIBUNWIND_TARGET_AARCH64)
     typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
     typename R::link_reg_t pc;
     _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
@@ -2735,7 +2735,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool 
isReturnAddress) {
 #endif
 
   typename R::link_reg_t pc;
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+#if defined(_LIBUNWIND_TARGET_AARCH64) &&                                      
\
+    !(defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32))
   _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
 #else
   pc = rawPC;
@@ -3305,7 +3306,8 @@ void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
 template <typename A, typename R>
 bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
                                          unw_word_t *offset) {
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+#if defined(_LIBUNWIND_TARGET_AARCH64) &&                                      
\
+    !(defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32))
   typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
   typename R::link_reg_t pc;
   _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index 7368b3cb80336..361bf6c3c1575 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -615,14 +615,58 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct 
_Unwind_Context *context) {
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
 
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
-  // If we are in an arm64e frame, then the PC should have been signed with the
-  // sp
+#if defined(_LIBUNWIND_TARGET_AARCH64) &&                                      
\
+    !(defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32))
   {
-    unw_word_t sp;
-    __unw_get_reg(cursor, UNW_REG_SP, &sp);
-    result = (unw_word_t)ptrauth_auth_data((void *)result,
-                                           ptrauth_key_return_address, sp);
+    unw_word_t raSignState, raSignUseBKey;
+    __unw_get_reg(cursor, UNW_AARCH64_RA_SIGN_STATE, &raSignState);
+    __unw_get_reg(cursor, UNW_AARCH64_RA_SIGN_USE_B_KEY, &raSignUseBKey);
+
+    bool isReturnAddressSigned = (raSignState & 1);
+    bool isReturnAddressSignedWithPC = (raSignState & 2);
+
+    if (isReturnAddressSigned) {
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+      // We should never go here since non-null RA signed state is either set
+      // by architecture-specific __unw_getcontext or by stepWithDwarf which
+      // already contains a corresponding check and should have already
+      // emitted the UNW_ECROSSRASIGNING error.
+      _LIBUNWIND_ABORT("UNW_ECROSSRASIGNING");
+#else
+      unw_word_t sp;
+      __unw_get_reg(cursor, UNW_REG_SP, &sp);
+
+      register uint64_t x17 __asm("x17") = result;
+      register uint64_t x16 __asm("x16") = sp;
+
+      if (isReturnAddressSignedWithPC) {
+        unw_word_t raSignSecondModifier;
+        __unw_get_reg(cursor, UNW_AARCH64_RA_SIGN_SECOND_MODIFIER,
+                      &raSignSecondModifier);
+
+        register uint64_t x15 __asm("x15") = raSignSecondModifier;
+
+        if (raSignUseBKey) {
+          __asm__("hint 0x27\n\t" // pacm
+                  "hint 0xe     " // autib1716
+                  : "+r"(x17)
+                  : "r"(x16), "r"(x15));
+        } else {
+          __asm__("hint 0x27\n\t" // pacm
+                  "hint 0xc     " // autia1716
+                  : "+r"(x17)
+                  : "r"(x16), "r"(x15));
+        }
+      } else {
+        if (raSignUseBKey) {
+          __asm__("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
+        } else {
+          __asm__("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+        }
+      }
+      result = x17;
+#endif
+    }
   }
 #endif
 
diff --git a/libunwind/src/UnwindRegistersRestore.S 
b/libunwind/src/UnwindRegistersRestore.S
index 76a80344034f7..a98b9cb85de3c 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -672,7 +672,8 @@ 
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   ldp    x8, x9,  [x0, #0x040]
   ldp    x10,x11, [x0, #0x050]
   ldp    x12,x13, [x0, #0x060]
-  ldp    x14,x15, [x0, #0x070]
+  // x14 and x15 are used as scratch registers in this function
+  // and will be restored later.
   // x16 and x17 were clobbered by the call into the unwinder, so no point in
   // restoring them.
   ldp    x18,x19, [x0, #0x090]
@@ -683,42 +684,143 @@ 
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   ldp    x28,x29, [x0, #0x0E0]
 
 #if defined(__ARM_FP) && __ARM_FP != 0
-  ldp    d0, d1,  [x0, #0x110]
-  ldp    d2, d3,  [x0, #0x120]
-  ldp    d4, d5,  [x0, #0x130]
-  ldp    d6, d7,  [x0, #0x140]
-  ldp    d8, d9,  [x0, #0x150]
-  ldp    d10,d11, [x0, #0x160]
-  ldp    d12,d13, [x0, #0x170]
-  ldp    d14,d15, [x0, #0x180]
-  ldp    d16,d17, [x0, #0x190]
-  ldp    d18,d19, [x0, #0x1A0]
-  ldp    d20,d21, [x0, #0x1B0]
-  ldp    d22,d23, [x0, #0x1C0]
-  ldp    d24,d25, [x0, #0x1D0]
-  ldp    d26,d27, [x0, #0x1E0]
-  ldp    d28,d29, [x0, #0x1F0]
-  ldr    d30,     [x0, #0x200]
-  ldr    d31,     [x0, #0x208]
+  ldp    d0, d1,  [x0, #0x120]
+  ldp    d2, d3,  [x0, #0x130]
+  ldp    d4, d5,  [x0, #0x140]
+  ldp    d6, d7,  [x0, #0x150]
+  ldp    d8, d9,  [x0, #0x160]
+  ldp    d10,d11, [x0, #0x170]
+  ldp    d12,d13, [x0, #0x180]
+  ldp    d14,d15, [x0, #0x190]
+  ldp    d16,d17, [x0, #0x1A0]
+  ldp    d18,d19, [x0, #0x1B0]
+  ldp    d20,d21, [x0, #0x1C0]
+  ldp    d22,d23, [x0, #0x1D0]
+  ldp    d24,d25, [x0, #0x1E0]
+  ldp    d26,d27, [x0, #0x1F0]
+  ldr    d28,     [x0, #0x200]
+  ldr    d29,     [x0, #0x208]
+  ldr    d30,     [x0, #0x210]
+  ldr    d31,     [x0, #0x218]
 #endif
+
+  // The lr value stored in __pc might be signed with IA/IB key (as described
+  // by __ra_sign.__use_b_key field) and &__pc address as a modifier.
+  // If the lr value is signed, re-sign that with the corresponding key
+  // and initial signing scheme using __sp as a modifier and potentially
+  // involving a second modifier (as described by (__ra_sign.__state & 2)).
+
+  ldr    x14,     [x0, #0x0F8]  // x14 = __sp
+  ldr    x15,     [x0, #0x110]  // x15 = __ra_sign.__second_modifier
+  add    x16, x0, #0x100        // x16 = &__pc
+  ldr    x17,     [x0, #0x100]  // x17 = __pc
+
+  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
+  and    x1, x1, #1
+  cbz    x1, .Lresign_end
+
+  // lr needs resign
+  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
+  and    x1, x1, #2
+  cbnz   x1, .Lresign_with_pc
+
+  // lr needs resign without pc as a second modifier
+  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
+  cbnz   x1, .Lresign_with_b_key
+
+  // lr needs resign with A key and without pc as a second modifier
+  hint   0xc                    // autia1716
+  mov    x16, x14               // x16 = __sp
+  hint   0x8                    // pacia1716
+  b .Lresign_end
+
+.Lresign_with_b_key:
+  // lr needs resign with B key and without pc as a second modifier
+  hint   0xe                    // autib1716
+  mov    x16, x14               // x16 = __sp
+  hint   0xa                    // pacib1716
+  b .Lresign_end
+
+.Lresign_with_pc:
+  // lr needs resign with pc as a second modifier
+  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
+  cbnz   x1, .Lresign_with_pc_b_key
+
+  // lr needs resign with A key and pc as a second modifier
+  hint   0xc                    // autia1716
+  mov    x16, x14               // x16 = __sp
+  hint   0x27                   // pacm
+  hint   0x8                    // pacia1716
+  b .Lresign_end
+
+.Lresign_with_pc_b_key:
+  // lr needs resign with B key and pc as a second modifier
+  hint   0xe                    // autib1716
+  mov    x16, x14               // x16 = __sp
+  hint   0x27                   // pacm
+  hint   0xa                    // pacib1716
+  b .Lresign_end
+
+.Lresign_end:
+  mov    lr, x17                // assign final lr value
+  ldp    x14,x15, [x0, #0x070]  // restore x14,x15
+  ldr    x16,     [x0, #0x110]  // second modifier for auti{a|b}sp with PACM
+
   // Finally, restore sp. This must be done after the last read from the
   // context struct, because it is allocated on the stack, and an exception
   // could clobber the de-allocated portion of the stack after sp has been
   // restored.
+  ldr    x17,     [x0, #0x0F8]  // load sp into scratch
 
-  ldr    x16,     [x0, #0x0F8]  // load sp into scratch
-  ldr    lr,      [x0, #0x100]  // restore pc into lr
+  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
+  and    x1, x1, #1
+  cbz    x1, .Lauth_end
 
-#if __has_feature(ptrauth_calls)
-  // The LR is signed with its address inside the register state.  Time
-  // to resign to be a regular ROP protected signed pointer
-  add    x1, x0, #0x100
-  autib  lr, x1
-  pacib  lr, x16  // signed the scratch register for sp
-#endif
+  // lr is signed
+  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
+  and    x1, x1, #2
+  cbnz   x1, .Lauth_with_pc
+
+  // lr is signed without pc as a second modifier
+  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
+  cbnz   x1, .Lauth_with_b_key
+
+  // lr is signed with A key and without pc as a second modifier
+  ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
+  mov    sp,x17                 // restore sp
+  hint   0x1d                   // autiasp
+  ret    x30
+
+.Lauth_with_b_key:
+  // lr is signed with B key and without pc as a second modifier
+  ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
+  mov    sp,x17                 // restore sp
+  hint   0x1f                   // autibsp
+  ret    x30
 
+.Lauth_with_pc:
+  // lr is signed with pc as a second modifier
+  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
+  cbnz   x1, .Lauth_with_pc_b_key
+
+  // lr is signed with A key and pc as a second modifier
+  ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
+  mov    sp,x17                 // restore sp
+  hint   0x27                   // pacm
+  hint   0x1d                   // autiasp
+  ret    x30
+
+.Lauth_with_pc_b_key:
+  // lr is signed with B key and pc as a second modifier
+  ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
+  mov    sp,x17                 // restore sp
+  hint   0x27                   // pacm
+  hint   0x1f                   // autibsp
+  ret    x30
+
+.Lauth_end:
   ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
-  mov    sp,x16                 // restore sp
+  mov    sp,x17                 // restore sp
 #if defined(__ARM_FEATURE_GCS_DEFAULT)
   // If GCS is enabled we need to push the address we're returning to onto the
   // GCS stack. We can't just return using br, as there won't be a BTI landing
@@ -729,12 +831,7 @@ 
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   gcspushm x30
 Lnogcs:
 #endif
-
-#if __has_feature(ptrauth_calls)
-  retab
-#else
   ret    x30                    // jump to pc
-#endif
 
 #elif defined(__arm__) && !defined(__APPLE__)
 
diff --git a/libunwind/src/UnwindRegistersSave.S 
b/libunwind/src/UnwindRegistersSave.S
index f988fd461def1..252353b7861f7 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -769,6 +769,20 @@ LnoR2Fix:
 #define __has_feature(__feature) 0
 #endif
 
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+# define UNW_ARM_FEATURE_PAC_DEFAULT __ARM_FEATURE_PAC_DEFAULT
+#else
+# if __has_feature(ptrauth_returns)
+#  define UNW_ARM_FEATURE_PAC_DEFAULT 2
+# else
+#  define UNW_ARM_FEATURE_PAC_DEFAULT 0
+# endif
+#endif
+
+#define UNW_RA_SIGNED            ((UNW_ARM_FEATURE_PAC_DEFAULT & 3) != 0)
+#define UNW_RA_SIGNED_WITH_B_KEY ((UNW_ARM_FEATURE_PAC_DEFAULT & 2) != 0)
+#define UNW_RA_SIGNED_WITH_PC    ((UNW_ARM_FEATURE_PAC_DEFAULT & 8) != 0)
+
 //
 // extern int __unw_getcontext(unw_context_t* thread_state)
 //
@@ -778,8 +792,16 @@ LnoR2Fix:
   .p2align 2
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 
-#if __has_feature(ptrauth_calls)
-  pacibsp
+#if UNW_RA_SIGNED
+# if UNW_RA_SIGNED_WITH_PC
+  hint   0x27                     // pacm
+.L__unw_getcontext_start:
+# endif
+# if UNW_RA_SIGNED_WITH_B_KEY
+  hint   0x1b                     // pacibsp
+# else
+  hint   0x19                     // paciasp
+# endif
 #endif
 
   stp    x0, x1,  [x0, #0x000]
@@ -801,33 +823,69 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   mov    x1,sp
   str    x1,      [x0, #0x0F8]
   str    x30,     [x0, #0x100]    // store return address as pc
+
+  // Fill subfields of __ra_sign field
+#if UNW_RA_SIGNED
+# if UNW_RA_SIGNED_WITH_PC
+  adrp   x16, .L__unw_getcontext_start
+  add    x16, x16, :lo12:.L__unw_getcontext_start
+  str    x16,     [x0, #0x110]    // __second_modifier = x16
+# else
+  str    xzr,     [x0, #0x110]    // __second_modifier = 0
+# endif
+
+  mov    x16, #1
+  str    x16,     [x0, #0x108]    // __state = 1
+
+# if UNW_RA_SIGNED_WITH_B_KEY
+  str    x16,     [x0, #0x118]    // __use_b_key = 1
+# else
+  str    xzr,     [x0, #0x118]    // __use_b_key = 0
+# endif
+
+  ldr    x16,     [x0, #0x080]    // restore x16 after clobber
+#else
+  str    xzr,     [x0, #0x108]    // __state = 0
+  str    xzr,     [x0, #0x110]    // __second_modifier = 0
+  str    xzr,     [x0, #0x118]    // __use_b_key = 0
+#endif
+
   // skip cpsr
 #if defined(__ARM_FP) && __ARM_FP != 0
-  stp    d0, d1,  [x0, #0x110]
-  stp    d2, d3,  [x0, #0x120]
-  stp    d4, d5,  [x0, #0x130]
-  stp    d6, d7,  [x0, #0x140]
-  stp    d8, d9,  [x0, #0x150]
-  stp    d10,d11, [x0, #0x160]
-  stp    d12,d13, [x0, #0x170]
-  stp    d14,d15, [x0, #0x180]
-  stp    d16,d17, [x0, #0x190]
-  stp    d18,d19, [x0, #0x1A0]
-  stp    d20,d21, [x0, #0x1B0]
-  stp    d22,d23, [x0, #0x1C0]
-  stp    d24,d25, [x0, #0x1D0]
-  stp    d26,d27, [x0, #0x1E0]
-  stp    d28,d29, [x0, #0x1F0]
-  str    d30,     [x0, #0x200]
-  str    d31,     [x0, #0x208]
+  stp    d0, d1,  [x0, #0x120]
+  stp    d2, d3,  [x0, #0x130]
+  stp    d4, d5,  [x0, #0x140]
+  stp    d6, d7,  [x0, #0x150]
+  stp    d8, d9,  [x0, #0x160]
+  stp    d10,d11, [x0, #0x170]
+  stp    d12,d13, [x0, #0x180]
+  stp    d14,d15, [x0, #0x190]
+  stp    d16,d17, [x0, #0x1A0]
+  stp    d18,d19, [x0, #0x1B0]
+  stp    d20,d21, [x0, #0x1C0]
+  stp    d22,d23, [x0, #0x1D0]
+  stp    d24,d25, [x0, #0x1E0]
+  stp    d26,d27, [x0, #0x1F0]
+  str    d28,     [x0, #0x200]
+  str    d29,     [x0, #0x208]
+  str    d30,     [x0, #0x210]
+  str    d31,     [x0, #0x218]
 #endif
   mov    x0, #0                   // return UNW_ESUCCESS
 
-#if __has_feature(ptrauth_calls)
-  retab
-#else
-  ret
+#if UNW_RA_SIGNED
+# if UNW_RA_SIGNED_WITH_PC
+  adrp   x16, .L__unw_getcontext_start
+  add    x16, x16, :lo12:.L__unw_getcontext_start
+  hint   0x27                     // pacm
+# endif
+# if UNW_RA_SIGNED_WITH_B_KEY
+  hint   0x1f                     // autibsp
+# else
+  hint   0x1d                     // autiasp
+# endif
 #endif
+  ret
 
 //
 // extern "C" int64_t __libunwind_Registers_arm64_za_disable()
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index b3036396c379d..9fdeca0cdbe4b 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -162,6 +162,17 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, 
unw_regnum_t regNum,
           _LIBUNWIND_ABORT("Bad unwind through arm64e");
         }
       }
+#elif defined(_LIBUNWIND_TARGET_AARCH64) &&                                    
\
+    !(defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32))
+      // We expect IP register value to be signed only for a full-fledged
+      // PAuth ABI such as Apple's arm64e or Linux's pauthtest. Otherwise,
+      // the value to be assigned to the IP register is an unsigned pointer,
+      // so we need to update RA sign info and mark the pointer as unsigned.
+      // This prevents attempts of unsigned pointer authentication in case
+      // if previously a signed RA was stored in the IP register field.
+      co->setReg(UNW_AARCH64_RA_SIGN_STATE, 0);
+      co->setReg(UNW_AARCH64_RA_SIGN_SECOND_MODIFIER, 0);
+      co->setReg(UNW_AARCH64_RA_SIGN_USE_B_KEY, 0);
 #endif
 
       // If the original call expects stack adjustment, perform this now.

>From a9430a2f4fdb449cd460702dc343853d5bb668da Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <[email protected]>
Date: Sun, 21 Dec 2025 23:47:33 +0300
Subject: [PATCH 2/2] Check signing scheme flags integrity

---
 libunwind/include/libunwind.h          |  10 +-
 libunwind/src/DwarfInstructions.hpp    |  25 +-
 libunwind/src/DwarfParser.hpp          |   2 +-
 libunwind/src/Registers.hpp            | 516 ++++++++++++++++++-------
 libunwind/src/UnwindLevel1.c           | 140 ++++---
 libunwind/src/UnwindRegistersRestore.S | 190 +++++----
 libunwind/src/UnwindRegistersSave.S    |  69 ++--
 libunwind/src/libunwind.cpp            |   7 +-
 8 files changed, 645 insertions(+), 314 deletions(-)

diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 6a56548867642..d711b0cccbfcb 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -642,11 +642,13 @@ enum {
   // reserved block
   UNW_AARCH64_RA_SIGN_STATE = 34,
 
-  // The following two registers are not real Dwarf registers and use numbers
-  // which are not occupied by real Dwarf registers according to
+  // Warning: the two registers below are intended for internal libunwind use
+  // only and should not be used by external code. These are not real Dwarf
+  // registers and they use numbers which are not occupied by real Dwarf
+  // registers according to
   // https://github.com/ARM-software/abi-aa/blob/2025Q1/aadwarf64/aadwarf64.rst
-  UNW_AARCH64_RA_SIGN_SECOND_MODIFIER = 128,
-  UNW_AARCH64_RA_SIGN_USE_B_KEY = 129,
+  UNW_AARCH64_RA_SIGNING_SCHEME_SECOND_MODIFIER = 128,
+  UNW_AARCH64_RA_SIGNING_SCHEME_FLAGS = 129,
 
   // FP/vector registers
   UNW_AARCH64_V0 = 64,
diff --git a/libunwind/src/DwarfInstructions.hpp 
b/libunwind/src/DwarfInstructions.hpp
index ad1555db3abd2..2d5b50031c924 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -75,8 +75,8 @@ class DwarfInstructions {
     __builtin_unreachable();
   }
 #if defined(_LIBUNWIND_TARGET_AARCH64)
-  static pint_t getRASignState(A &addressSpace, const R &registers, pint_t cfa,
-                               const PrologInfo &prolog);
+  static pint_t getRASignedState(A &addressSpace, const R &registers,
+                                        pint_t cfa, const PrologInfo &prolog);
 #endif
 };
 
@@ -174,9 +174,8 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
 }
 #if defined(_LIBUNWIND_TARGET_AARCH64)
 template <typename A, typename R>
-typename A::pint_t
-DwarfInstructions<A, R>::getRASignState(A &addressSpace, const R &registers,
-                                        pint_t cfa, const PrologInfo &prolog) {
+typename A::pint_t DwarfInstructions<A, R>::getRASignedState(
+    A &addressSpace, const R &registers, pint_t cfa, const PrologInfo &prolog) 
{
   auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
   if (regloc.location == CFI_Parser<A>::kRegisterUnused)
     return static_cast<pint_t>(regloc.value);
@@ -284,20 +283,16 @@ int DwarfInstructions<A, R>::stepWithDwarf(A 
&addressSpace,
       // using the v8.3 pointer authentication extensions. In order to
       // store signed return address in the registers context structure, we
       // need to save the signing scheme for this address.
-      pint_t raSignState = getRASignState(addressSpace, registers, cfa, 
prolog);
-      bool isReturnAddressSigned = (raSignState & 1);
-      if ((R::getArch() == REGISTERS_ARM64) && isReturnAddressSigned &&
+      pint_t raSignState =
+          getRASignedState(addressSpace, registers, cfa, prolog);
+      if ((R::getArch() == REGISTERS_ARM64) && raSignState != 0 &&
           returnAddress != 0) {
 #if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
         return UNW_ECROSSRASIGNING;
 #else
-        newRegisters.setRegister(UNW_AARCH64_RA_SIGN_STATE, raSignState);
-        if (newRegisters.isReturnAddressSignedWithPC()) {
-          newRegisters.setRegister(UNW_AARCH64_RA_SIGN_SECOND_MODIFIER,
-                                   prolog.ptrAuthDiversifier);
-        }
-        newRegisters.setRegister(UNW_AARCH64_RA_SIGN_USE_B_KEY,
-                                 cieInfo.addressesSignedWithBKey ? 1 : 0);
+        newRegisters.setRASigningScheme(
+            raSignState, cieInfo.addressesSignedWithBKey,
+            prolog.ptrAuthDiversifier);
 #endif
       }
 #endif
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 2b04ae2831f9a..1b657f290b3ac 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -97,7 +97,7 @@ class CFI_Parser {
     uint32_t          spExtraArgSize;
     RegisterLocation  savedRegisters[kMaxRegisterNumber + 1];
 #if defined(_LIBUNWIND_TARGET_AARCH64)
-    pint_t ptrAuthDiversifier;
+    pint_t ptrAuthDiversifier = 0;
 #endif
     enum class InitializeTime { kLazy, kNormal };
 
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 2245ccba61e4f..69c057758c944 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1842,6 +1842,78 @@ extern "C" void *__libunwind_shstk_get_jump_target() {
 }
 #endif
 
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+
+#define STRING_IMPL(x) #x
+#define STRING(x) STRING_IMPL(x)
+
+#define RUN_IF_PAUTH_FEATURE_PRESENT(scratchReg, code)             \
+  "mrs  " #scratchReg ", ID_AA64ISAR1_EL1"                  "\n\t" \
+  "lsr  " #scratchReg ", " #scratchReg ", #24"              "\n\t" \
+  "ands " #scratchReg ", " #scratchReg ", #255"             "\n\t" \
+  "cbnz " #scratchReg ", .Lcheck_pac_code" STRING(__LINE__) "\n\t" \
+  "mrs  " #scratchReg ", ID_AA64ISAR2_EL1"                  "\n\t" \
+  "lsr  " #scratchReg ", " #scratchReg ", #8"               "\n\t" \
+  "ands " #scratchReg ", " #scratchReg ", #15"              "\n\t" \
+  "cbnz " #scratchReg ", .Lcheck_pac_code" STRING(__LINE__) "\n\t" \
+  "b .Lcheck_pac_end" STRING(__LINE__)                      "\n\t" \
+  ".Lcheck_pac_code" STRING(__LINE__) ":"                   "\n\t" \
+  code                                                      "\n\t" \
+  ".Lcheck_pac_end" STRING(__LINE__) ":"                    "\n\t"
+
+// The '0xc470 + KeyID' trap code is used by LLVM codegen to abort execution
+// on auth failure w/o FPAC. Mimic this behavior assuming GA key ID is 4.
+#define PACGA_TRAP "brk #0xc474\n\t"
+
+#define CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY(schemeReg, schemePacReg, \
+                                             modifierReg, scratchReg) \
+  RUN_IF_PAUTH_FEATURE_PRESENT(                                       \
+    scratchReg,                                                       \
+    "pacga " #modifierReg ", " #schemeReg ", " #modifierReg    "\n\t" \
+    "cmp " #modifierReg ", " #schemePacReg                     "\n\t" \
+    "b.eq  .Lcheck_integrity_success_" STRING(__LINE__)        "\n\t" \
+    PACGA_TRAP                                                 "\n\t" \
+    ".Lcheck_integrity_success_" STRING(__LINE__) ":"          "\n\t" \
+  )
+
+#define CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI(schemeReg)      \
+  "cmp   " #schemeReg ", 5"                                        "\n\t" \
+  "b.eq  .Lcheck_integrity_for_pauthabi_success_" STRING(__LINE__) "\n\t" \
+  PACGA_TRAP                                                       "\n\t" \
+  ".Lcheck_integrity_for_pauthabi_success_" STRING(__LINE__) ":"   "\n\t" \
+
+#define SIGNING_SCHEME_FLAGS_SWITCH(schemeReg, codeIf0, codeIf1, \
+                                    codeIf3, codeIf5, codeIf7)   \
+  "cmp " #schemeReg ", #0"                     "\n\t"            \
+  "b.ne .Lswitch_1_"   STRING(__LINE__)        "\n\t"            \
+  codeIf0                                      "\n\t"            \
+  "b    .Lswitch_end_" STRING(__LINE__)        "\n\t"            \
+  ".Lswitch_1_" STRING(__LINE__) ":"           "\n\t"            \
+  "cmp " #schemeReg ", #1"                     "\n\t"            \
+  "b.ne .Lswitch_3_" STRING(__LINE__)          "\n\t"            \
+  codeIf1                                      "\n\t"            \
+  "b    .Lswitch_end_" STRING(__LINE__)        "\n\t"            \
+  ".Lswitch_3_" STRING(__LINE__) ":"           "\n\t"            \
+  "cmp " #schemeReg ", #3"                     "\n\t"            \
+  "b.ne .Lswitch_5_"   STRING(__LINE__)        "\n\t"            \
+  codeIf3                                      "\n\t"            \
+  "b    .Lswitch_end_" STRING(__LINE__)        "\n\t"            \
+  ".Lswitch_5_" STRING(__LINE__) ":"           "\n\t"            \
+  "cmp " #schemeReg ", #5"                     "\n\t"            \
+  "b.ne .Lswitch_7_"   STRING(__LINE__)        "\n\t"            \
+  codeIf5                                      "\n\t"            \
+  "b    .Lswitch_end_" STRING(__LINE__)        "\n\t"            \
+  ".Lswitch_7_" STRING(__LINE__) ":"           "\n\t"            \
+  "cmp " #schemeReg ", #7"                     "\n\t"            \
+  "b.ne .Lswitch_unexpected" STRING(__LINE__)  "\n\t"            \
+  codeIf7                                      "\n\t"            \
+  "b    .Lswitch_end_" STRING(__LINE__)        "\n\t"            \
+  ".Lswitch_unexpected" STRING(__LINE__) ":"   "\n\t"            \
+  PACGA_TRAP                                   "\n\t"            \
+  ".Lswitch_end_" STRING(__LINE__) ":"         "\n\t"
+
+#endif
+
 class _LIBUNWIND_HIDDEN Registers_arm64 {
 public:
   Registers_arm64() = default;
@@ -1878,108 +1950,112 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   uint64_t  getSP() const         { return _registers.__sp; }
   void      setSP(uint64_t value) { _registers.__sp = value; }
 
-  uint64_t  getIP() const {
+  uint64_t getIP() const {
     uint64_t value = _registers.__pc;
 
-    if (!isReturnAddressSigned())
-      return value;
-
-#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
-    abortCrossRASigning();
-#else
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
     // Note the value of the PC was signed to its address in the register state
     // but everyone else expects it to be sign by the SP, so convert on return.
     register uint64_t x17 __asm("x17") = value;
     register uint64_t x16 __asm("x16") =
         reinterpret_cast<uint64_t>(&_registers.__pc);
-    register uint64_t x14 __asm("x14") = getSP();
-    if (isReturnAddressSignedWithPC()) {
-      register uint64_t x15 __asm("x15") =
-          _registers.__ra_sign.__second_modifier;
-      if (isReturnAddressSignedWithBKey()) {
-        asm("hint 0xe    \n\t" // autib1716
-            "mov x16, x14\n\t"
-            "hint 0x27   \n\t" // pacm
-            "hint 0xa        " // pacib1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x15), "r"(x14));
-      } else {
-        asm("hint 0xc    \n\t" // autia1716
-            "mov x16, x14\n\t"
-            "hint 0x27   \n\t" // pacm
-            "hint 0x8        " // pacia1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x15), "r"(x14));
-      }
-    } else {
-      if (isReturnAddressSignedWithBKey()) {
-        asm("hint 0xe    \n\t" // autib1716
-            "mov x16, x14\n\t"
-            "hint 0xa        " // pacib1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x14));
-      } else {
-        asm("hint 0xc    \n\t" // autia1716
-            "mov x16, x14\n\t"
-            "hint 0x8        " // pacia1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x14));
-      }
-    }
+    register uint64_t x15 __asm("x15") =
+        _registers.__ra_signing_scheme.__second_modifier;
+    register uint64_t x14 __asm("x14") = _registers.__sp;
+    register uint64_t x13 __asm("x13") =
+        reinterpret_cast<uint64_t>(&_registers.__ra_signing_scheme.__flags);
+    register uint64_t x12 __asm("x12") = 
_registers.__ra_signing_scheme.__flags;
+    register uint64_t x11 __asm("x11") =
+        _registers.__ra_signing_scheme.__flags_pac;
+
+    asm(CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY(
+            /*schemeReg=*/x12, /*schemePacReg=*/x11,
+            /*modifierReg=*/x13, /*scratchReg=*/x10)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+    CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI(/*schemeReg=*/x12)
+#endif
+        SIGNING_SCHEME_FLAGS_SWITCH(
+            /*schemeReg=*/x12,
+            /*codeIf0=*/"",
+            /*codeIf1=*/"hint 0xc    \n\t"  // autia1716
+                        "mov x16, x14\n\t"
+                        "hint 0x8    \n\t", // pacia1716
+            /*codeIf3=*/"hint 0x27   \n\t"  // pacm
+                        "hint 0xc    \n\t"  // autia1716
+                        "mov x16, x14\n\t"
+                        "hint 0x27   \n\t"  // pacm
+                        "hint 0x8    \n\t", // pacia1716
+            /*codeIf5=*/"hint 0xe    \n\t"  // autib1716
+                        "mov x16, x14\n\t"
+                        "hint 0xa    \n\t", // pacib1716
+            /*codeIf7=*/"hint 0x27   \n\t"  // pacm
+                        "hint 0xe    \n\t"  // autib1716
+                        "mov x16, x14\n\t"
+                        "hint 0x27   \n\t"  // pacm
+                        "hint 0xa    \n\t"  // pacib1716
+        )
+        : "+r"(x17)
+        : "r"(x16), "r"(x15), "r"(x14), "r"(x13), "r"(x12), "r"(x11)
+    );
     return x17;
+#else
+    if (_registers.__ra_signing_scheme.__flags != 0)
+      abortCrossRASigningSchemeing();
+    return value;
 #endif
   }
 
   void      setIP(uint64_t value) {
-    if (!isReturnAddressSigned()) {
-      _registers.__pc = value;
-      return;
-    }
-
-#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
-    abortCrossRASigning();
-#else
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
     // Note the value which was set should have been signed with the SP.
     // We then resign with the slot we are being stored in to so that both SP
     // and LR can't be spoofed at the same time.
     register uint64_t x17 __asm("x17") = value;
-    register uint64_t x16 __asm("x16") = getSP();
+    register uint64_t x16 __asm("x16") = _registers.__sp;
+    register uint64_t x15 __asm("x15") =
+        _registers.__ra_signing_scheme.__second_modifier;
     register uint64_t x14 __asm("x14") =
         reinterpret_cast<uint64_t>(&_registers.__pc);
-    if (isReturnAddressSignedWithPC()) {
-      register uint64_t x15 __asm("x15") =
-          _registers.__ra_sign.__second_modifier;
-      if (isReturnAddressSignedWithBKey()) {
-        asm("hint 0x27   \n\t" // pacm
-            "hint 0xe    \n\t" // autib1716
-            "mov x16, x14\n\t"
-            "hint 0xa        " // pacib1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x15), "r"(x14));
-      } else {
-        asm("hint 0x27   \n\t" // pacm
-            "hint 0xc    \n\t" // autia1716
-            "mov x16, x14\n\t"
-            "hint 0x8        " // pacia1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x15), "r"(x14));
-      }
-    } else {
-      if (isReturnAddressSignedWithBKey()) {
-        asm("hint 0xe    \n\t" // autib1716
-            "mov x16, x14\n\t"
-            "hint 0xa        " // pacib1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x14));
-      } else {
-        asm("hint 0xc    \n\t" // autia1716
-            "mov x16, x14\n\t"
-            "hint 0x8        " // pacia1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x14));
-      }
-    }
+    register uint64_t x13 __asm("x13") =
+        reinterpret_cast<uint64_t>(&_registers.__ra_signing_scheme.__flags);
+    register uint64_t x12 __asm("x12") = 
_registers.__ra_signing_scheme.__flags;
+    register uint64_t x11 __asm("x11") =
+        _registers.__ra_signing_scheme.__flags_pac;
+
+    asm(CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY(
+            /*schemeReg=*/x12, /*schemePacReg=*/x11, /*modifierReg=*/x13,
+            /*scratchReg=*/x10)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+        CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI(/*schemeReg=*/x12)
+#endif
+        SIGNING_SCHEME_FLAGS_SWITCH(
+            /*schemeReg=*/x12,
+            /*codeIf0=*/"",
+            /*codeIf1=*/"hint 0xc    \n\t"  // autia1716
+                        "mov x16, x14\n\t"
+                        "hint 0x8    \n\t", // pacia1716
+            /*codeIf3=*/"hint 0x27   \n\t"  // pacm
+                        "hint 0xc    \n\t"  // autia1716
+                        "mov x16, x14\n\t"
+                        "hint 0x27   \n\t"  // pacm
+                        "hint 0x8    \n\t", // pacia1716
+            /*codeIf5=*/"hint 0xe    \n\t"  // autib1716
+                        "mov x16, x14\n\t"
+                        "hint 0xa    \n\t", // pacib1716
+            /*codeIf7=*/"hint 0x27   \n\t"  // pacm
+                        "hint 0xe    \n\t"  // autib1716
+                        "mov x16, x14\n\t"
+                        "hint 0x27   \n\t"  // pacm
+                        "hint 0xa    \n\t"  // pacib1716
+        )
+        : "+r"(x17)
+        : "r"(x16), "r"(x15), "r"(x14), "r"(x13), "r"(x12), "r"(x11)
+    );
     _registers.__pc = x17;
+#else
+    if (_registers.__ra_signing_scheme.__flags != 0)
+      abortCrossRASigningSchemeing();
+    _registers.__pc = value;
 #endif
   }
 
@@ -1995,60 +2071,172 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   void
   loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
                                   link_reg_t *referenceAuthedLinkRegister) {
-    if (!isReturnAddressSigned()) {
-      *referenceAuthedLinkRegister = inplaceAuthedLinkRegister;
-      return;
-    }
-
-#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
-    abortCrossRASigning();
-#else
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
     register reg_t x17 __asm("x17") = inplaceAuthedLinkRegister;
-    register reg_t x16 __asm("x16") = getSP();
-    if (isReturnAddressSignedWithPC()) {
-      register reg_t x15 __asm("x15") = _registers.__ra_sign.__second_modifier;
-      if (isReturnAddressSignedWithBKey()) {
-        asm("hint 0x27\n\t" // pacm
-            "hint 0xe     " // autib1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x15));
-      } else {
-        asm("hint 0x27\n\t" // pacm
-            "hint 0xc     " // autia1716
-            : "+r"(x17)
-            : "r"(x16), "r"(x15));
-      }
-    } else {
-      if (isReturnAddressSignedWithBKey()) {
-        asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
-      } else {
-        asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
-      }
-    }
+    register reg_t x16 __asm("x16") = _registers.__sp;
+    register uint64_t x15 __asm("x15") =
+        _registers.__ra_signing_scheme.__second_modifier;
+    register uint64_t x13 __asm("x13") =
+        reinterpret_cast<uint64_t>(&_registers.__ra_signing_scheme.__flags);
+    register uint64_t x12 __asm("x12") = 
_registers.__ra_signing_scheme.__flags;
+    register uint64_t x11 __asm("x11") =
+        _registers.__ra_signing_scheme.__flags_pac;
+
+    asm(CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY(
+            /*schemeReg=*/x12, /*schemePacReg=*/x11, /*modifierReg=*/x13,
+            /*scratchReg=*/x10)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+        CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI(/*schemeReg=*/x12)
+#endif
+        SIGNING_SCHEME_FLAGS_SWITCH(
+            /*schemeReg=*/x12,
+            /*codeIf0=*/"",
+            /*codeIf1=*/"hint 0xc \n\t", // autia1716
+            /*codeIf3=*/"hint 0x27\n\t"  // pacm
+                        "hint 0xc \n\t", // autia1716
+            /*codeIf5=*/"hint 0xe \n\t", // autib1716
+            /*codeIf7=*/"hint 0x27\n\t"  // pacm
+                        "hint 0xe \n\t"  // autib1716
+        )
+        : "+r"(x17)
+        : "r"(x16), "r"(x15), "r"(x13), "r"(x12), "r"(x11)
+    );
     *referenceAuthedLinkRegister = x17;
+#else
+    if (_registers.__ra_signing_scheme.__flags != 0)
+      abortCrossRASigningSchemeing();
+    *referenceAuthedLinkRegister = inplaceAuthedLinkRegister;
 #endif
   }
 
-  bool isReturnAddressSigned() const {
-    return _registers.__ra_sign.__state & 1;
-  }
-  bool isReturnAddressSignedWithPC() const {
-    return _registers.__ra_sign.__state & 2;
-  }
-  bool isReturnAddressSignedWithBKey() const {
-    return _registers.__ra_sign.__use_b_key;
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  void setRASigningScheme(uint64_t raSignState,
+                                   bool isRASigningSchemeedWithBKey,
+                                   uint64_t secondModifier) {
+    register uint64_t x16 __asm("x16") =
+        raSignState + (isRASigningSchemeedWithBKey ? 4 : 0);
+    register uint64_t x17 __asm("x17") =
+        reinterpret_cast<uint64_t>(&_registers.__ra_signing_scheme.__flags);
+    register uint64_t x15 __asm("x15") = secondModifier;
+
+    asm(
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+        CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI(/*schemeReg=*/x16)
+#endif
+        SIGNING_SCHEME_FLAGS_SWITCH(
+            /*schemeReg=*/x16,
+            /*codeIf0=*/"cbnz  x15, .Lsetscheme_unexpected\n\t",
+            /*codeIf1=*/"cbnz  x15, .Lsetscheme_unexpected\n\t",
+            /*codeIf3=*/"cbz   x15, .Lsetscheme_unexpected\n\t",
+            /*codeIf5=*/"cbnz  x15, .Lsetscheme_unexpected\n\t",
+            /*codeIf7=*/"cbz   x15, .Lsetscheme_unexpected\n\t"
+            )
+        "b .Lsetscheme_ok       \n\t"
+        ".Lsetscheme_unexpected:\n\t"
+        PACGA_TRAP             "\n\t"
+        ".Lsetscheme_ok:        \n\t"
+        "str x16, [x17, #0]     \n\t"
+        RUN_IF_PAUTH_FEATURE_PRESENT(
+            /*scratchReg=*/x14,
+            "pacga x16, x16, x17 \n\t"
+            "str   x16, [x17, #8]\n\t"
+            )
+        "str   x15, [x17, #16]\n\t"
+        :
+        : "r"(x17), "r"(x16), "r"(x15)
+        );
   }
+#endif // defined(_LIBUNWIND_IS_NATIVE_ONLY)
 
 private:
 #if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
-  void abortCrossRASigning() const {
+  void abortCrossRASigningSchemeing() const {
     // We should never go here since non-null RA signed state is either set
     // by architecture-specific __unw_getcontext or by stepWithDwarf which
     // already contains a corresponding check and should have already
     // emitted the UNW_ECROSSRASIGNING error.
     _LIBUNWIND_ABORT("UNW_ECROSSRASIGNING");
   }
+#else
+  void setZeroSigningScheme() {
+    register uint64_t x17 __asm("x17") =
+        reinterpret_cast<uint64_t>(&_registers.__ra_signing_scheme.__flags);
+
+    asm(// Ensure that second modifier is zero
+        "ldr x16, [x17, #16]\n\t"
+        "cbz .Lsetzero_ok   \n\t"
+        PACGA_TRAP         "\n\t"
+        ".Lsetzero_ok:      \n\t"
+        // Assign zero to signing scheme flags field
+        "str xzr, [x17, #0] \n\t"
+        // Compute PAC for signing scheme flags field
+        RUN_IF_PAUTH_FEATURE_PRESENT(
+            /*scratchReg=*/x14,
+            "pacga x16, xzr, x17 \n\t"
+            "str   x16, [x17, #8]\n\t"
+        )
+        :
+        : "r"(x17)
+    );
+  }
+
+  void recomputeSigningSchemeFlagsPAC(const uint8_t *oldModifier) {
+    register uint64_t x17 __asm("x17") =
+        reinterpret_cast<uint64_t>(oldModifier);
+    register uint64_t x16 __asm("x16") = 
_registers.__ra_signing_scheme.__flags;
+    register uint64_t x15 __asm("x15") =
+        _registers.__ra_signing_scheme.__flags_pac;
+    register uint64_t x14 __asm("x14") =
+        reinterpret_cast<uint64_t>(&_registers.__ra_signing_scheme.__flags);
+    asm(CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY(
+            /*schemeReg=*/x16, /*schemePacReg=*/x15,
+            /*modifierReg=*/x17, /*scratchReg=*/x13)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+        CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI(/*schemeReg=*/x16)
+#endif
+        RUN_IF_PAUTH_FEATURE_PRESENT(
+            /*scratchReg=*/x13,
+            "pacga x16, x16, x14 \n\t"
+            "str   x16, [x14, #8]\n\t"
+        )
+        :
+        : "r"(x17), "r"(x16), "r"(x15), "r"(x14)
+    );
+  }
+
+  // Is PAuth is available, returns signing scheme flags value with embedded
+  // PAC computed with GA key and SP modifier. The PAC computed by PACGA only
+  // occupies most-significant 32 bits of 64-bit value, which are not
+  // overlapping with bits occupied by valid flags values.
+  // If PAuth is not available, just returns signing scheme flags.
+  uint64_t getRASigningSchemeFlags() const {
+    register uint64_t x17 __asm("x17") =
+        reinterpret_cast<uint64_t>(&_registers.__ra_signing_scheme.__flags);
+    register uint64_t x16 __asm("x16") = 
_registers.__ra_signing_scheme.__flags;
+    register uint64_t x15 __asm("x15") =
+        _registers.__ra_signing_scheme.__flags_pac;
+    register uint64_t x14 __asm("x14") = _registers.__sp;
+
+    // TODO: reuse code from CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY macro.
+    asm(
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+        CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI(/*schemeReg=*/x16)
 #endif
+        RUN_IF_PAUTH_FEATURE_PRESENT(
+            /*scratchReg=*/x13,
+            "pacga x17, x16, x17          \n\t"
+            "cmp   x17, x15               \n\t"
+            "b.eq  .Lget_ra_scheme_success\n\t"
+            PACGA_TRAP                   "\n\t"
+            ".Lget_ra_scheme_success:     \n\t"
+            "pacga x14, x16, x14          \n\t"
+            "orr   x16, x14, x16          \n\t"
+        )
+        : "+r"(x16)
+        : "r"(x17), "r"(x15), "r"(x14));
+    return x16;
+  }
+#endif // !defined(_LIBUNWIND_IS_NATIVE_ONLY)
 
   uint64_t lazyGetVG() const;
 
@@ -2075,12 +2263,25 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
     uint64_t __lr = 0;            // Link register x30
     uint64_t __sp = 0;            // Stack pointer x31
     uint64_t __pc = 0;            // Program counter
-    struct RASign {
-      uint64_t __state = 0;           // RA sign state register
-      uint64_t __second_modifier = 0; // Additional modifier used for RA
-                                      // signing with FEAT_PAuth_LR
-      uint64_t __use_b_key = 0;       // 0 for IA key, 1 for IB key
-    } __ra_sign;
+    struct RASigningScheme {
+      // Bitmask for RA signing parameters:
+      // - bit 0: is RA signed;
+      // - bit 1: is RA signed with second modifier;
+      // - bit 2: is RA signed with B key.
+      // Valid values: 0, 1, 3, 5, 7. Note that it does not directly
+      // correspond to any physical or Dwarf registers.
+      uint64_t __flags = 0;
+
+      // Pointer authentication code for the `__flags` value computed with GA
+      // key (if `pacga` instruction is available) and address diversity. It is
+      // crucial to check integrity of `__flags` since the signing scheme is
+      // defined at runtime and attacker can substitute both the pointer and 
the
+      // signing scheme.
+      uint64_t __flags_pac = 0;
+
+      // Additional modifier used for RA signing with FEAT_PAuth_LR.
+      uint64_t __second_modifier = 0;
+    } __ra_signing_scheme;
   };
 
   struct Misc {
@@ -2120,6 +2321,10 @@ inline Registers_arm64::Registers_arm64(const void 
*registers) {
   uint64_t pcRegister = 0;
   memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
           sizeof(pcRegister));
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  recomputeSigningSchemeFlagsPAC(
+      (const uint8_t *)registers + offsetof(GPRs, 
__ra_signing_scheme.__flags));
+#endif
   setIP(pcRegister);
 }
 
@@ -2130,6 +2335,9 @@ inline Registers_arm64::Registers_arm64(const 
Registers_arm64 &other) {
 inline Registers_arm64 &
 Registers_arm64::operator=(const Registers_arm64 &other) {
   memmove(static_cast<void *>(this), &other, sizeof(*this));
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  recomputeSigningSchemeFlagsPAC((const uint8_t 
*)&other._registers.__ra_signing_scheme.__flags);
+#endif
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());
@@ -2141,12 +2349,16 @@ inline bool Registers_arm64::validRegister(int regNum) 
const {
     return true;
   if (regNum == UNW_REG_SP)
     return true;
+  // UNW_AARCH64_RA_SIGN_STATE is a Dwarf pseudo-register and is not stored in
+  // the context struct.
   if (regNum == UNW_AARCH64_RA_SIGN_STATE)
+    return false;
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  if (regNum == UNW_AARCH64_RA_SIGNING_SCHEME_SECOND_MODIFIER)
     return true;
-  if (regNum == UNW_AARCH64_RA_SIGN_SECOND_MODIFIER)
-    return true;
-  if (regNum == UNW_AARCH64_RA_SIGN_USE_B_KEY)
+  if (regNum == UNW_AARCH64_RA_SIGNING_SCHEME_FLAGS)
     return true;
+#endif
   if (regNum < 0)
     return false;
   if (regNum > 95)
@@ -2177,12 +2389,12 @@ inline uint64_t Registers_arm64::getRegister(int 
regNum) const {
     return getIP();
   if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
     return _registers.__sp;
-  if (regNum == UNW_AARCH64_RA_SIGN_STATE)
-    return _registers.__ra_sign.__state;
-  if (regNum == UNW_AARCH64_RA_SIGN_SECOND_MODIFIER)
-    return _registers.__ra_sign.__second_modifier;
-  if (regNum == UNW_AARCH64_RA_SIGN_USE_B_KEY)
-    return _registers.__ra_sign.__use_b_key;
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+  if (regNum == UNW_AARCH64_RA_SIGNING_SCHEME_SECOND_MODIFIER)
+    return _registers.__ra_signing_scheme.__second_modifier;
+  if (regNum == UNW_AARCH64_RA_SIGNING_SCHEME_FLAGS)
+    return getRASigningSchemeFlags();
+#endif
   if (regNum == UNW_AARCH64_FP)
     return getFP();
   if (regNum == UNW_AARCH64_LR)
@@ -2199,12 +2411,21 @@ inline void Registers_arm64::setRegister(int regNum, 
uint64_t value) {
     setIP(value);
   else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
     _registers.__sp = value;
-  else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
-    _registers.__ra_sign.__state = value;
-  else if (regNum == UNW_AARCH64_RA_SIGN_SECOND_MODIFIER)
-    _registers.__ra_sign.__second_modifier = value;
-  else if (regNum == UNW_AARCH64_RA_SIGN_USE_B_KEY)
-    _registers.__ra_sign.__use_b_key = value;
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+  else if (regNum == UNW_AARCH64_RA_SIGNING_SCHEME_SECOND_MODIFIER ||
+           regNum == UNW_AARCH64_RA_SIGNING_SCHEME_FLAGS)
+    _LIBUNWIND_ABORT("Cannot change signing scheme for PAuth-enabled ABI");
+#else
+  else if (regNum == UNW_AARCH64_RA_SIGNING_SCHEME_SECOND_MODIFIER) {
+    assert(value == 0 && "Expect value 0 when called from __unw_set_reg");
+    _registers.__ra_signing_scheme.__second_modifier = 0;
+  } else if (regNum == UNW_AARCH64_RA_SIGNING_SCHEME_FLAGS) {
+    assert(value == 0 && "Expect value 0 when called from __unw_set_reg");
+    setZeroSigningScheme();
+  }
+#endif
+#endif
   else if (regNum == UNW_AARCH64_FP)
     setFP(value);
   else if (regNum == UNW_AARCH64_LR)
@@ -2387,6 +2608,17 @@ inline v128 Registers_arm64::getVectorRegister(int) 
const {
 inline void Registers_arm64::setVectorRegister(int, v128) {
   _LIBUNWIND_ABORT("no arm64 vector register support yet");
 }
+
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
+#undef SIGNING_SCHEME_FLAGS_SWITCH
+#undef CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI
+#undef CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY
+#undef PACGA_TRAP
+#undef RUN_IF_PAUTH_FEATURE_PRESENT
+#undef STRING
+#undef STRING_IMPL
+#endif
+
 #endif // _LIBUNWIND_TARGET_AARCH64
 
 #if defined(_LIBUNWIND_TARGET_ARM)
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index 361bf6c3c1575..8c7a5f20fcc4f 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -616,57 +616,101 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct 
_Unwind_Context *context) {
   __unw_get_reg(cursor, UNW_REG_IP, &result);
 
 #if defined(_LIBUNWIND_TARGET_AARCH64) &&                                      
\
+    defined(_LIBUNWIND_IS_NATIVE_ONLY) &&                                      
\
     !(defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32))
   {
-    unw_word_t raSignState, raSignUseBKey;
-    __unw_get_reg(cursor, UNW_AARCH64_RA_SIGN_STATE, &raSignState);
-    __unw_get_reg(cursor, UNW_AARCH64_RA_SIGN_USE_B_KEY, &raSignUseBKey);
-
-    bool isReturnAddressSigned = (raSignState & 1);
-    bool isReturnAddressSignedWithPC = (raSignState & 2);
-
-    if (isReturnAddressSigned) {
-#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
-      // We should never go here since non-null RA signed state is either set
-      // by architecture-specific __unw_getcontext or by stepWithDwarf which
-      // already contains a corresponding check and should have already
-      // emitted the UNW_ECROSSRASIGNING error.
-      _LIBUNWIND_ABORT("UNW_ECROSSRASIGNING");
-#else
-      unw_word_t sp;
-      __unw_get_reg(cursor, UNW_REG_SP, &sp);
-
-      register uint64_t x17 __asm("x17") = result;
-      register uint64_t x16 __asm("x16") = sp;
-
-      if (isReturnAddressSignedWithPC) {
-        unw_word_t raSignSecondModifier;
-        __unw_get_reg(cursor, UNW_AARCH64_RA_SIGN_SECOND_MODIFIER,
-                      &raSignSecondModifier);
-
-        register uint64_t x15 __asm("x15") = raSignSecondModifier;
-
-        if (raSignUseBKey) {
-          __asm__("hint 0x27\n\t" // pacm
-                  "hint 0xe     " // autib1716
-                  : "+r"(x17)
-                  : "r"(x16), "r"(x15));
-        } else {
-          __asm__("hint 0x27\n\t" // pacm
-                  "hint 0xc     " // autia1716
-                  : "+r"(x17)
-                  : "r"(x16), "r"(x15));
-        }
-      } else {
-        if (raSignUseBKey) {
-          __asm__("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
-        } else {
-          __asm__("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
-        }
-      }
-      result = x17;
+    unw_word_t raSigningSchemeFlagsWithPAC;
+    __unw_get_reg(cursor, UNW_AARCH64_RA_SIGNING_SCHEME_FLAGS,
+                  &raSigningSchemeFlagsWithPAC);
+    unw_word_t raSigningSchemeFlags =
+        raSigningSchemeFlagsWithPAC & 0x00000000ffffffffull;
+    unw_word_t raSigningSchemeFlagsPAC =
+        raSigningSchemeFlagsWithPAC & 0xffffffff00000000ull;
+
+    unw_word_t sp;
+    __unw_get_reg(cursor, UNW_REG_SP, &sp);
+
+    unw_word_t raSigningSchemeSecondModifier;
+    __unw_get_reg(cursor, UNW_AARCH64_RA_SIGNING_SCHEME_SECOND_MODIFIER,
+                  &raSigningSchemeSecondModifier);
+
+    register uint64_t x17 __asm("x17") = result;
+    register uint64_t x16 __asm("x16") = sp;
+    register uint64_t x15 __asm("x15") = raSigningSchemeSecondModifier;
+    register uint64_t x14 __asm("x14") = raSigningSchemeFlags;
+    register uint64_t x13 __asm("x13") = raSigningSchemeFlagsPAC;
+
+    // TODO: make similar code from Registers.hpp reusable and adopt it here.
+    __asm__(
+        // Check if PAuth feature is available. See also
+        // RUN_IF_PAUTH_FEATURE_PRESENT in Registers.hpp
+        "mrs  x12, ID_AA64ISAR1_EL1 \n\t"
+        "lsr  x12, x12, #24         \n\t"
+        "ands x12, x12, #255        \n\t"
+        "cbnz x12, .Lcheck_pac      \n\t"
+        "mrs  x12, ID_AA64ISAR2_EL1 \n\t"
+        "lsr  x12, x12, #8          \n\t"
+        "ands x12, x12, #15         \n\t"
+        "cbnz x12, .Lcheck_pac      \n\t"
+        "b .Lno_pauth               \n\t"
+        ".Lcheck_pac:               \n\t"
+
+        // See also CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY in Registers.hpp.
+        "pacga x12, x14, x16  \n\t"
+        "cmp   x12, x13       \n\t"
+        "b.eq  .Lpacga_success\n\t"
+        "brk   #0xc474        \n\t"
+        ".Lpacga_success:     \n\t"
+        ".Lno_pauth:          \n\t"
+
+        // See also CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI
+        // in Registers.hpp.
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+        "cmp   x14, 5            \n\t"
+        "b.eq  .Lpauthabi_success\n\t"
+        "brk   #0xc474           \n\t"
+        ".Lpauthabi_success:     \n\t"
 #endif
-    }
+
+        // See also SIGNING_SCHEME_FLAGS_SWITCH in Registers.hpp.
+        "cmp   x14, #0     \n\t"
+        "b.ne  .Lswitch_1  \n\t"
+        "b     .Lswitch_end\n\t"
+
+        ".Lswitch_1:       \n\t"
+        "cmp   x14, #1     \n\t"
+        "b.ne  .Lswitch_3  \n\t"
+        "hint 0xc          \n\t" // autia1716
+        "b     .Lswitch_end\n\t"
+
+        ".Lswitch_3:       \n\t"
+        "cmp   x14, #3     \n\t"
+        "b.ne  .Lswitch_5  \n\t"
+        "hint 0x27         \n\t" // pacm
+        "hint 0xc          \n\t" // autia1716
+        "b     .Lswitch_end\n\t"
+
+        ".Lswitch_5:       \n\t"
+        "cmp   x14, #5     \n\t"
+        "b.ne  .Lswitch_7  \n\t"
+        "hint 0xe          \n\t" // autib1716
+        "b     .Lswitch_end\n\t"
+
+        ".Lswitch_7:       \n\t"
+        "cmp   x14, #7     \n\t"
+        "b.ne  .Lswitch_unexpected\n\t"
+        "hint 0x27         \n\t" // pacm
+        "hint 0xe          \n\t" // autib1716
+        "b     .Lswitch_end\n\t"
+
+        ".Lswitch_unexpected:\n\t"
+        "brk   #0xc474       \n\t"
+
+        ".Lswitch_end:\n\t"
+        : "+r"(x17)
+        : "r"(x16), "r"(x15), "r"(x14), "r"(x13)
+    );
+    result = x17;
   }
 #endif
 
diff --git a/libunwind/src/UnwindRegistersRestore.S 
b/libunwind/src/UnwindRegistersRestore.S
index a98b9cb85de3c..e7a212acc7c1f 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -704,64 +704,97 @@ 
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   ldr    d31,     [x0, #0x218]
 #endif
 
-  // The lr value stored in __pc might be signed with IA/IB key (as described
-  // by __ra_sign.__use_b_key field) and &__pc address as a modifier.
-  // If the lr value is signed, re-sign that with the corresponding key
-  // and initial signing scheme using __sp as a modifier and potentially
-  // involving a second modifier (as described by (__ra_sign.__state & 2)).
+  // The lr value stored in __pc might be signed with IA/IB key, &__pc address
+  // as a modifier and an optional second modifier. If the lr value is signed,
+  // re-sign that with the corresponding key and initial signing scheme using
+  // __sp as a modifier and potentially involving a second modifier
+  // (as described by '__ra_signing_scheme.__flags & 2').
 
   ldr    x14,     [x0, #0x0F8]  // x14 = __sp
-  ldr    x15,     [x0, #0x110]  // x15 = __ra_sign.__second_modifier
+  ldr    x15,     [x0, #0x118]  // x15 = __ra_signing_scheme.__second_modifier
+  ldr    x1,      [x0, #0x108]  // x1 = __ra_signing_scheme.__flags
+  ldr    x16,      [x0, #0x110]  // x16 = __ra_signing_scheme.__flags_pac
+
+  // Check if PAuth feature is available. See also
+  // RUN_IF_PAUTH_FEATURE_PRESENT in Registers.hpp
+  mrs  x17, ID_AA64ISAR1_EL1
+  lsr  x17, x17, #24
+  ands x17, x17, #255
+  cbnz x17, .Lcheck_pac
+  mrs  x17, ID_AA64ISAR2_EL1
+  lsr  x17, x17, #8
+  ands x17, x17, #15
+  cbnz x17, .Lcheck_pac
+  b .Lno_pauth
+  .Lcheck_pac:
+
+  // See also CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY in Registers.hpp.
+  add   x17, x0, #0x108
+  pacga x17, x1, x17
+  cmp   x17, x16
+  b.eq  .Lpacga_success
+  brk   #0xc474
+  .Lpacga_success:
+  .Lno_pauth:
+
+  // See also CHECK_SIGNING_SCHEME_FLAGS_INTEGRITY_FOR_PAUTHABI
+  // in Registers.hpp.
+#if __has_feature(ptrauth_returns)
+  cmp   x1, #5
+  b.eq  .Lpauthabi_success
+  brk   #0xc474
+  .Lpauthabi_success:
+#endif
+
   add    x16, x0, #0x100        // x16 = &__pc
   ldr    x17,     [x0, #0x100]  // x17 = __pc
 
-  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
-  and    x1, x1, #1
-  cbz    x1, .Lresign_end
-
-  // lr needs resign
-  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
-  and    x1, x1, #2
-  cbnz   x1, .Lresign_with_pc
-
-  // lr needs resign without pc as a second modifier
-  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
-  cbnz   x1, .Lresign_with_b_key
-
-  // lr needs resign with A key and without pc as a second modifier
-  hint   0xc                    // autia1716
-  mov    x16, x14               // x16 = __sp
-  hint   0x8                    // pacia1716
-  b .Lresign_end
-
-.Lresign_with_b_key:
-  // lr needs resign with B key and without pc as a second modifier
-  hint   0xe                    // autib1716
-  mov    x16, x14               // x16 = __sp
-  hint   0xa                    // pacib1716
-  b .Lresign_end
-
-.Lresign_with_pc:
-  // lr needs resign with pc as a second modifier
-  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
-  cbnz   x1, .Lresign_with_pc_b_key
-
-  // lr needs resign with A key and pc as a second modifier
-  hint   0xc                    // autia1716
-  mov    x16, x14               // x16 = __sp
-  hint   0x27                   // pacm
-  hint   0x8                    // pacia1716
-  b .Lresign_end
-
-.Lresign_with_pc_b_key:
-  // lr needs resign with B key and pc as a second modifier
-  hint   0xe                    // autib1716
-  mov    x16, x14               // x16 = __sp
-  hint   0x27                   // pacm
-  hint   0xa                    // pacib1716
-  b .Lresign_end
+  // See also SIGNING_SCHEME_FLAGS_SWITCH in Registers.hpp.
+  cmp   x1, #0
+  b.ne  .Lswitch_1716_1
+  b     .Lswitch_1716_end
+
+  .Lswitch_1716_1:
+  cmp   x1, #1
+  b.ne  .Lswitch_1716_3
+  hint 0xc     // autia1716
+  mov x16, x14
+  hint 0x8     // pacia1716
+  b     .Lswitch_1716_end
+
+  .Lswitch_1716_3:
+  cmp   x1, #3
+  b.ne  .Lswitch_1716_5
+  hint 0x27    // pacm
+  hint 0xc     // autia1716
+  mov x16, x14
+  hint 0x27    // pacm
+  hint 0x8     // pacia1716
+  b     .Lswitch_1716_end
+
+  .Lswitch_1716_5:
+  cmp   x1, #5
+  b.ne  .Lswitch_1716_7
+  hint 0xe     // autib1716
+  mov x16, x14
+  hint 0xa     // pacib1716
+  b     .Lswitch_1716_end
+
+  .Lswitch_1716_7:
+  cmp   x1, #7
+  b.ne  .Lswitch_1716_unexpected
+  hint 0x27    // pacm
+  hint 0xe     // autib1716
+  mov x16, x14
+  hint 0x27    // pacm
+  hint 0xa     // pacib1716
+  b     .Lswitch_1716_end
+
+  .Lswitch_1716_unexpected:
+  brk   #0xc474
+
+  .Lswitch_1716_end:
 
-.Lresign_end:
   mov    lr, x17                // assign final lr value
   ldp    x14,x15, [x0, #0x070]  // restore x14,x15
   ldr    x16,     [x0, #0x110]  // second modifier for auti{a|b}sp with PACM
@@ -770,55 +803,56 @@ 
DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   // context struct, because it is allocated on the stack, and an exception
   // could clobber the de-allocated portion of the stack after sp has been
   // restored.
-  ldr    x17,     [x0, #0x0F8]  // load sp into scratch
 
-  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
-  and    x1, x1, #1
-  cbz    x1, .Lauth_end
+  ldr    x17,     [x0, #0x0F8]  // load sp into scratch
 
-  // lr is signed
-  ldr    x1,      [x0, #0x108]  // x1 = __ra_sign.__state
-  and    x1, x1, #2
-  cbnz   x1, .Lauth_with_pc
+  // Integrity of the signing scheme stored in x1 was checked above and no
+  // manipulations on x1 were performed since then, so skip this check.
 
-  // lr is signed without pc as a second modifier
-  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
-  cbnz   x1, .Lauth_with_b_key
+  // See also SIGNING_SCHEME_FLAGS_SWITCH in Registers.hpp.
+  cmp   x1, #0
+  b.ne  .Lswitch_lrsp_1
+  b     .Lswitch_lrsp_end
 
-  // lr is signed with A key and without pc as a second modifier
+  .Lswitch_lrsp_1:
+  cmp   x1, #1
+  b.ne  .Lswitch_lrsp_3
   ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
   mov    sp,x17                 // restore sp
   hint   0x1d                   // autiasp
   ret    x30
 
-.Lauth_with_b_key:
-  // lr is signed with B key and without pc as a second modifier
+  .Lswitch_lrsp_3:
+  cmp   x1, #3
+  b.ne  .Lswitch_lrsp_5
   ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
   mov    sp,x17                 // restore sp
-  hint   0x1f                   // autibsp
+  hint   0x27                   // pacm
+  hint   0x1d                   // autiasp
   ret    x30
 
-.Lauth_with_pc:
-  // lr is signed with pc as a second modifier
-  ldr    x1,      [x0, #0x118]  // x1 = __ra_sign.__use_b_key
-  cbnz   x1, .Lauth_with_pc_b_key
-
-  // lr is signed with A key and pc as a second modifier
+  .Lswitch_lrsp_5:
+  cmp   x1, #5
+  b.ne  .Lswitch_lrsp_7
   ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
   mov    sp,x17                 // restore sp
-  hint   0x27                   // pacm
-  hint   0x1d                   // autiasp
+  hint   0x1f                   // autibsp
   ret    x30
 
-.Lauth_with_pc_b_key:
-  // lr is signed with B key and pc as a second modifier
+  .Lswitch_lrsp_7:
+  cmp   x1, #7
+  b.ne  .Lswitch_lrsp_unexpected
+
   ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
   mov    sp,x17                 // restore sp
   hint   0x27                   // pacm
   hint   0x1f                   // autibsp
   ret    x30
 
-.Lauth_end:
+  .Lswitch_lrsp_unexpected:
+  brk   #0xc474
+
+.Lswitch_lrsp_end:
   ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
   mov    sp,x17                 // restore sp
 #if defined(__ARM_FEATURE_GCS_DEFAULT)
diff --git a/libunwind/src/UnwindRegistersSave.S 
b/libunwind/src/UnwindRegistersSave.S
index 252353b7861f7..4c4942982f159 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -783,6 +783,24 @@ LnoR2Fix:
 #define UNW_RA_SIGNED_WITH_B_KEY ((UNW_ARM_FEATURE_PAC_DEFAULT & 2) != 0)
 #define UNW_RA_SIGNED_WITH_PC    ((UNW_ARM_FEATURE_PAC_DEFAULT & 8) != 0)
 
+#if UNW_RA_SIGNED
+# if UNW_RA_SIGNED_WITH_PC
+#  if UNW_RA_SIGNED_WITH_B_KEY
+#   define UNW_RA_SIGNING_SCHEME 7
+#  else
+#   define UNW_RA_SIGNING_SCHEME 3
+#  endif
+# else
+#  if UNW_RA_SIGNED_WITH_B_KEY
+#   define UNW_RA_SIGNING_SCHEME 5
+#  else
+#   define UNW_RA_SIGNING_SCHEME 1
+#  endif
+# endif
+#else
+# define UNW_RA_SIGNING_SCHEME 0
+#endif
+
 //
 // extern int __unw_getcontext(unw_context_t* thread_state)
 //
@@ -824,31 +842,38 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   str    x1,      [x0, #0x0F8]
   str    x30,     [x0, #0x100]    // store return address as pc
 
-  // Fill subfields of __ra_sign field
-#if UNW_RA_SIGNED
-# if UNW_RA_SIGNED_WITH_PC
-  adrp   x16, .L__unw_getcontext_start
-  add    x16, x16, :lo12:.L__unw_getcontext_start
-  str    x16,     [x0, #0x110]    // __second_modifier = x16
-# else
-  str    xzr,     [x0, #0x110]    // __second_modifier = 0
-# endif
-
-  mov    x16, #1
-  str    x16,     [x0, #0x108]    // __state = 1
-
-# if UNW_RA_SIGNED_WITH_B_KEY
-  str    x16,     [x0, #0x118]    // __use_b_key = 1
+  // Fill subfields of __ra_signing_scheme field
+
+  mov    x16, #UNW_RA_SIGNING_SCHEME
+  str    x16,     [x0, #0x108]    // __flags
+
+  // Check if PAuth feature is available. See also
+  // RUN_IF_PAUTH_FEATURE_PRESENT in Registers.hpp
+  mrs    x17, ID_AA64ISAR1_EL1
+  lsr    x17, x17, #24
+  ands   x17, x17, #255
+  cbnz   x17, .Lcompute_pac
+  mrs    x17, ID_AA64ISAR2_EL1
+  lsr    x17, x17, #8
+  ands   x17, x17, #15
+  cbnz   x17, .Lcompute_pac
+  str    xzr,     [x0, #0x110]    // __flags_pac
+  b      .Lno_pauth
+  .Lcompute_pac:
+  add    x17, x0, #0x108
+  pacga  x17, x16, x17
+  str    x17,     [x0, #0x110]    // __flags_pac
+  .Lno_pauth:
+
+#if UNW_RA_SIGNED_WITH_PC
+  adrp   x17, .L__unw_getcontext_start
+  add    x17, x17, :lo12:.L__unw_getcontext_start
 # else
-  str    xzr,     [x0, #0x118]    // __use_b_key = 0
+  mov    x17, xzr
 # endif
+  str    x17,     [x0, #0x118]    // __second_modifier = x17
 
-  ldr    x16,     [x0, #0x080]    // restore x16 after clobber
-#else
-  str    xzr,     [x0, #0x108]    // __state = 0
-  str    xzr,     [x0, #0x110]    // __second_modifier = 0
-  str    xzr,     [x0, #0x118]    // __use_b_key = 0
-#endif
+  ldp    x16,x17, [x0, #0x080]    // restore x16 and x17 after clobber
 
   // skip cpsr
 #if defined(__ARM_FP) && __ARM_FP != 0
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 9fdeca0cdbe4b..400a41fc677f5 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -162,7 +162,7 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, 
unw_regnum_t regNum,
           _LIBUNWIND_ABORT("Bad unwind through arm64e");
         }
       }
-#elif defined(_LIBUNWIND_TARGET_AARCH64) &&                                    
\
+#elif defined(_LIBUNWIND_TARGET_AARCH64) && defined(_LIBUNWIND_IS_NATIVE_ONLY) 
&&    \
     !(defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32))
       // We expect IP register value to be signed only for a full-fledged
       // PAuth ABI such as Apple's arm64e or Linux's pauthtest. Otherwise,
@@ -170,9 +170,8 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, 
unw_regnum_t regNum,
       // so we need to update RA sign info and mark the pointer as unsigned.
       // This prevents attempts of unsigned pointer authentication in case
       // if previously a signed RA was stored in the IP register field.
-      co->setReg(UNW_AARCH64_RA_SIGN_STATE, 0);
-      co->setReg(UNW_AARCH64_RA_SIGN_SECOND_MODIFIER, 0);
-      co->setReg(UNW_AARCH64_RA_SIGN_USE_B_KEY, 0);
+      co->setReg(UNW_AARCH64_RA_SIGNING_SCHEME_SECOND_MODIFIER, 0);
+      co->setReg(UNW_AARCH64_RA_SIGNING_SCHEME_FLAGS, 0);
 #endif
 
       // If the original call expects stack adjustment, perform this now.

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to