[libcxx-commits] [compiler-rt] [libcxx] [libcxxabi] [libunwind] [runtimes][PAC] Harden unwinding when possible (PR #143230)

Oliver Hunt via libcxx-commits libcxx-commits at lists.llvm.org
Sun Oct 19 19:45:40 PDT 2025


https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/143230

>From e7f03a8770c74a630c51bf536bbe37a2ebab5820 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 5 Aug 2025 18:16:32 -0700
Subject: [PATCH 01/28] [runtimes][PAC] Harden unwinding when possible
 (#138571)

This hardens the unwinding logic and datastructures on systems
that support pointer authentication.
The approach taken to hardening is to harden the schemas of as many
high value fields in the myriad structs as possible, and then also
explicitly qualify local variables referencing privileged or security
critical values.
This does introduce ABI linkage between libcxx, libcxxabi, and
libunwind but those are in principle separate from the OS itself
so we've kept the schema definitions in the library specific headers
rather than ptrauth.h
---
 compiler-rt/lib/builtins/gcc_personality_v0.c |  76 ++++++++++-
 libcxxabi/include/__cxxabi_config.h           |  47 +++++++
 libcxxabi/src/cxa_exception.h                 |  33 +++--
 libcxxabi/src/cxa_personality.cpp             | 103 +++++++++++++--
 libunwind/include/libunwind.h                 | 114 ++++++++++++++--
 libunwind/src/AddressSpace.hpp                |  32 +++--
 libunwind/src/CompactUnwinder.hpp             |  18 ++-
 libunwind/src/DwarfInstructions.hpp           |  22 ++--
 libunwind/src/DwarfParser.hpp                 |  43 +++++-
 libunwind/src/Registers.hpp                   | 124 ++++++++++++++++--
 libunwind/src/UnwindCursor.hpp                |  71 +++++++---
 libunwind/src/UnwindLevel1.c                  |  38 +++++-
 libunwind/src/UnwindRegistersRestore.S        |  20 ++-
 libunwind/src/UnwindRegistersSave.S           |  10 ++
 libunwind/src/libunwind.cpp                   |  40 +++++-
 15 files changed, 691 insertions(+), 100 deletions(-)

diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
index ef63a5fb83472..36a50fa266235 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -30,6 +30,45 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
                                             _Unwind_Personality_Fn);
 #endif
 
+#if __has_feature(ptrauth_qualifier)
+#include <ptrauth.h>
+#if __has_feature(ptrauth_restricted_intptr_qualifier)
+#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated,            \
+                                              discriminator)                   \
+  __ptrauth_restricted_intptr(key, addressDiscriminated, discriminator)
+#else
+#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated,            \
+                                              discriminator)                   \
+  __ptrauth(key, addressDiscriminated, discriminator)
+#endif
+#else
+#define __ptrauth_gcc_personality_intptr(...)
+#endif
+
+#define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer
+
+// ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB
+#define __ptrauth_gcc_personality_func_start \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0xDFEB)
+
+// ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC
+#define __ptrauth_gcc_personality_start \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0x52DC)
+
+// ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7
+#define __ptrauth_gcc_personality_length \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0xFFF7)
+
+// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") == 0x6498
+#define __ptrauth_gcc_personality_lpoffset \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0x6498)
+
+// ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134
+#define __ptrauth_gcc_personality_lpad_disc 0xA134
+#define __ptrauth_gcc_personality_lpad \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
+                                   __ptrauth_gcc_personality_lpad_disc)
+
 // Pointer encodings documented at:
 //   http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
 
@@ -205,7 +244,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
     return continueUnwind(exceptionObject, context);
 
   uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
-  uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
+  uintptr_t __ptrauth_gcc_personality_func_start funcStart =
+    (uintptr_t)_Unwind_GetRegionStart(context);
   uintptr_t pcOffset = pc - funcStart;
 
   // Parse LSDA header.
@@ -224,11 +264,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
   const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
   const uint8_t *p = callSiteTableStart;
   while (p < callSiteTableEnd) {
-    uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
-    size_t length = readEncodedPointer(&p, callSiteEncoding);
-    size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+    uintptr_t __ptrauth_gcc_personality_start start =
+      readEncodedPointer(&p, callSiteEncoding);
+    size_t __ptrauth_gcc_personality_length length =
+      readEncodedPointer(&p, callSiteEncoding);
+    size_t __ptrauth_gcc_personality_lpoffset landingPadOffset =
+      readEncodedPointer(&p, callSiteEncoding);
     readULEB128(&p); // action value not used for C code
-    if (landingPad == 0)
+    if (landingPadOffset == 0)
       continue; // no landing pad for this entry
     if ((start <= pcOffset) && (pcOffset < (start + length))) {
       // Found landing pad for the PC.
@@ -238,7 +281,28 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
                     (uintptr_t)exceptionObject);
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
-      _Unwind_SetIP(context, (funcStart + landingPad));
+      size_t __ptrauth_gcc_personality_lpad landingPad =
+          funcStart + landingPadOffset;
+#if __has_feature(ptrauth_qualifier)
+      uintptr_t stackPointer = _Unwind_GetGR(context, -2);
+      const uintptr_t existingDiscriminator =
+        ptrauth_blend_discriminator(&landingPad,
+                                    __ptrauth_gcc_personality_lpad_disc);
+      // newIP is authenticated as if it were qualified with a pseudo qualifier
+      // along the lines of:
+      //   __ptrauth(ptrauth_key_return_address, <stackPointer>, 0)
+      // where the stack pointer is used in place of the strict storage
+      // address.
+      uintptr_t newIP =
+        (uintptr_t)ptrauth_auth_and_resign(*(void **)&landingPad,
+                                           __ptrauth_gcc_personality_func_key,
+                                           existingDiscriminator,
+                                           ptrauth_key_return_address,
+                                           stackPointer);
+      _Unwind_SetIP(context, newIP);
+#else
+      _Unwind_SetIP(context, landingPad);
+#endif
       return _URC_INSTALL_CONTEXT;
     }
   }
diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 759445dac91f9..9962c81c0c61c 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -48,6 +48,7 @@
   #define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
   #define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
  #endif
+
 #else
  #if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
   #define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
@@ -103,6 +104,52 @@
 #define _LIBCXXABI_DTOR_FUNC
 #endif
 
+#if __has_include(<ptrauth.h>)
+#  include <ptrauth.h>
+#endif
+
+#if __has_extension(ptrauth_qualifier)
+
+// ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
+#  define __ptrauth_cxxabi_action_record \
+            __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFC91)
+
+// ptrauth_string_discriminator("__cxa_exception::languageSpecificData") == 0xE8EE
+#  define __ptrauth_cxxabi_lsd \
+            __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)
+
+// ptrauth_string_discriminator("__cxa_exception::catchTemp") == 0xFA58
+#  define __ptrauth_cxxabi_catch_temp \
+            __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFA58)
+
+// ptrauth_string_discriminator("__cxa_exception::adjustedPtr") == 0x99E4
+#  define __ptrauth_cxxabi_adjusted_ptr \
+            __ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)
+
+// ptrauth_string_discriminator("__cxa_exception::unexpectedHandler") == 0x99A9
+#  define __ptrauth_cxxabi_unexpected_handler \
+            __ptrauth(ptrauth_key_function_pointer, 1, 0x99A9)
+
+// ptrauth_string_discriminator("__cxa_exception::terminateHandler") == 0x0886)
+#  define __ptrauth_cxxabi_terminate_handler \
+            __ptrauth(ptrauth_key_function_pointer, 1, 0x886)
+
+// ptrauth_string_discriminator("__cxa_exception::exceptionDestructor") == 0xC088
+#  define __ptrauth_cxxabi_exception_destructor \
+            __ptrauth(ptrauth_key_function_pointer, 1, 0xC088)
+
+#else
+
+#  define __ptrauth_cxxabi_action_record
+#  define __ptrauth_cxxabi_lsd
+#  define __ptrauth_cxxabi_catch_temp
+#  define __ptrauth_cxxabi_adjusted_ptr
+#  define __ptrauth_cxxabi_unexpected_handler
+#  define __ptrauth_cxxabi_terminate_handler
+#  define __ptrauth_cxxabi_exception_destructor
+
+#endif
+
 #if __cplusplus < 201103L
 #  define _LIBCXXABI_NOEXCEPT throw()
 #else
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index aba08f2992103..d59ddcefad151 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,10 +47,11 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
+             exceptionDestructor)(void*);
 #endif
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler  terminateHandler;
+    std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
+    std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -61,10 +62,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void *catchTemp;
-    void *adjustedPtr;
+    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
+    void* __ptrauth_cxxabi_catch_temp catchTemp;
+    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -79,6 +80,8 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
 // http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
 // The layout of this structure MUST match the layout of __cxa_exception, with
 // primaryException instead of referenceCount.
+// The tags used in the pointer authentication qualifiers also need to match
+// those of the corresponding members in __cxa_exception.
 struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
     void* reserve; // padding.
@@ -86,9 +89,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
-    std::unexpected_handler unexpectedHandler;
-    std::terminate_handler terminateHandler;
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
+             exceptionDestructor)(void*);
+    std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
+    std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
 
     __cxa_exception *nextException;
 
@@ -99,10 +103,11 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char *actionRecord;
-    const unsigned char *languageSpecificData;
-    void * catchTemp;
-    void *adjustedPtr;
+
+    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
+    void* __ptrauth_cxxabi_catch_temp catchTemp;
+    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 5f6e75c5be19c..ef59cba21e272 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -21,6 +21,49 @@
 #include "cxa_handlers.h"
 #include "private_typeinfo.h"
 #include "unwind.h"
+#include "libunwind.h"
+
+#if __has_include(<ptrauth.h>)
+#  include <ptrauth.h>
+#endif
+
+#if __has_extension(ptrauth_qualifier)
+// The actual value of the discriminators listed below is not important.
+// The derivation of the constants is only being included for the purpose
+// of maintaining a record of how they were originally produced.
+
+// ptrauth_string_discriminator("scan_results::languageSpecificData") == 0xE50D)
+#define __ptrauth_scan_results_lsd \
+  __ptrauth(ptrauth_key_process_dependent_code, 1, 0xE50D)
+
+// ptrauth_string_discriminator("scan_results::actionRecord") == 0x9823
+#define __ptrauth_scan_results_action_record \
+  __ptrauth(ptrauth_key_process_dependent_code, 1, 0x9823)
+
+// scan result is broken up as we have a manual re-sign that requires each component
+#define __ptrauth_scan_results_landingpad_key ptrauth_key_process_dependent_code
+// ptrauth_string_discriminator("scan_results::landingPad") == 0xD27C
+#define __ptrauth_scan_results_landingpad_disc 0xD27C
+#define __ptrauth_scan_results_landingpad \
+   __ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
+
+#if __has_extension(__ptrauth_restricted_intptr)
+#define __ptrauth_scan_results_landingpad_intptr \
+   __ptrauth_restricted_intptr(__ptrauth_scan_results_landingpad_key, 1, \
+                               __ptrauth_scan_results_landingpad_disc)
+#else
+#define __ptrauth_scan_results_landingpad_intptr \
+   __ptrauth(__ptrauth_scan_results_landingpad_key, 1, \
+             __ptrauth_scan_results_landingpad_disc)
+#endif
+
+#else
+#define __ptrauth_scan_results_lsd
+#define __ptrauth_scan_results_action_record
+#define __ptrauth_scan_results_landingpad
+#define __ptrauth_scan_results_landingpad_intptr
+#endif
+
 
 // TODO: This is a temporary workaround for libc++abi to recognize that it's being
 // built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION
@@ -527,12 +570,17 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
 namespace
 {
 
+typedef const uint8_t* __ptrauth_scan_results_lsd lsd_ptr_t;
+typedef const uint8_t* __ptrauth_scan_results_action_record action_ptr_t;
+typedef uintptr_t __ptrauth_scan_results_landingpad_intptr landing_pad_t;
+typedef void* __ptrauth_scan_results_landingpad landing_pad_ptr_t;
+
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
-    const uint8_t* actionRecord;         // Currently unused.  Retained to ease future maintenance.
-    const uint8_t* languageSpecificData;  // Needed only for __cxa_call_unexpected
-    uintptr_t      landingPad;   // null -> nothing found, else something found
+    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future maintenance.
+    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t landingPad;       // null -> nothing found, else something found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -541,7 +589,33 @@ struct scan_results
 };
 
 }  // unnamed namespace
+}
+
+namespace {
+// The logical model for casting authenticated function pointers makes
+// it impossible to directly cast them without breaking the authentication,
+// as a result we need this pair of helpers.
+template <typename PtrType>
+void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
+  union {
+    landing_pad_t* as_landing_pad;
+    landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  *u.as_pointer = out;
+}
 
+static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
+  union {
+    const landing_pad_t* as_landing_pad;
+    const landing_pad_ptr_t* as_pointer;
+  } u;
+  u.as_landing_pad = &results.landingPad;
+  return *u.as_pointer;
+}
+} // unnamed namespace
+
+extern "C" {
 static
 void
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
@@ -557,7 +631,21 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
                 reinterpret_cast<uintptr_t>(unwind_exception));
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
                 static_cast<uintptr_t>(results.ttypeIndex));
+#if __has_feature(ptrauth_qualifier)
+  auto stack_pointer = _Unwind_GetGR(context, UNW_REG_SP);
+  // We manually re-sign the IP as the __ptrauth qualifiers cannot
+  // express the required relationship with the destination address
+  const auto existingDiscriminator = ptrauth_blend_discriminator(
+      &results.landingPad, __ptrauth_scan_results_landingpad_disc);
+  unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stack_pointer, 0) */ =
+      (unw_word_t)ptrauth_auth_and_resign(*(void**)&results.landingPad,
+                                          __ptrauth_scan_results_landingpad_key,
+                                          existingDiscriminator,
+                                          ptrauth_key_return_address, stack_pointer);
+  _Unwind_SetIP(context, newIP);
+#else
   _Unwind_SetIP(context, results.landingPad);
+#endif
 }
 
 /*
@@ -691,12 +779,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
         // The call sites are ordered in increasing value of start
         uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
-        uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
+        landing_pad_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if ((start <= ipOffset) && (ipOffset < (start + length)))
 #else  // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
         // ip is 1-based index into this table
-        uintptr_t landingPad = readULEB128(&callSitePtr);
+        landing_pad_t landingPad = readULEB128(&callSitePtr);
         uintptr_t actionEntry = readULEB128(&callSitePtr);
         if (--ip == 0)
 #endif // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__
@@ -935,8 +1023,7 @@ __gxx_personality_v0
         results.ttypeIndex = exception_header->handlerSwitchValue;
         results.actionRecord = exception_header->actionRecord;
         results.languageSpecificData = exception_header->languageSpecificData;
-        results.landingPad =
-            reinterpret_cast<uintptr_t>(exception_header->catchTemp);
+        set_landing_pad_as_ptr(results, exception_header->catchTemp);
         results.adjustedPtr = exception_header->adjustedPtr;
 
         // Jump to the handler.
@@ -970,7 +1057,7 @@ __gxx_personality_v0
             exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
             exc->actionRecord = results.actionRecord;
             exc->languageSpecificData = results.languageSpecificData;
-            exc->catchTemp = reinterpret_cast<void*>(results.landingPad);
+            exc->catchTemp = get_landing_pad_as_ptr(results);
             exc->adjustedPtr = results.adjustedPtr;
 #ifdef __WASM_EXCEPTIONS__
             // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 94928f436025a..1580575aabe74 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -43,6 +43,103 @@
   #define LIBUNWIND_AVAIL
 #endif
 
+#if __has_extension(ptrauth_qualifier)
+
+  #if __has_include(<ptrauth.h>)
+    #include <ptrauth.h>
+  #endif
+
+  #if __has_extension(ptrauth_restricted_intptr_qualifier)
+    #define __unwind_ptrauth_restricted_intptr(...) \
+      __ptrauth_restricted_intptr(__VA_ARGS__)
+  #else
+    #define __unwind_ptrauth_restricted_intptr(...) \
+      __ptrauth(__VA_ARGS__)
+  #endif
+
+// ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
+  #define __ptrauth_unwind_personality_fn_disc 0x7405
+
+  #define __ptrauth_unwind_personality_fn \
+    __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_personality_fn_disc)
+
+  #define __ptrauth_unwind_personality_fn_intptr \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, __ptrauth_unwind_personality_fn_disc)
+
+// ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
+  #define __ptrauth_unwind_proc_startip \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xCA2C)
+
+// ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
+  #define __ptrauth_unwind_proc_endip \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xE183)
+
+// ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
+  #define __ptrauth_unwind_proc_lsda \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x83DE)
+
+// ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
+  #define __ptrauth_unwind_proc_flags \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x79A1)
+
+// ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
+  #define __ptrauth_unwind_proc_info \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xC20C)
+
+// ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
+  #define __ptrauth_unwind_proc_extra \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x03DF)
+
+// ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
+  #define __ptrauth_unwind_arm64_link_reg \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1, 0x8301)
+
+// ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
+  #define __ptrauth_unwind_info_section_dso_base \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4FF5)
+
+// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
+  #define __ptrauth_unwind_info_dwarf_section \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4974)
+
+// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A
+  #define __ptrauth_unwind_info_dwarf_section_length \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x2A9A)
+
+// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B
+  #define __ptrauth_unwind_info_compact_unwind_section \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xA27B)
+
+// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A
+  #define __ptrauth_unwind_info_compact_unwind_section_length \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x5D0A)
+
+// ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
+  #define __ptrauth_unwind_cfi_personality_disc 0x6A40
+  #define __ptrauth_unwind_cfi_personality \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \
+                                       __ptrauth_unwind_cfi_personality_disc)
+
+#else
+
+  #define __ptrauth_unwind_personality_fn
+  #define __ptrauth_unwind_personality_fn_intptr
+  #define __ptrauth_unwind_proc_startip
+  #define __ptrauth_unwind_proc_endip
+  #define __ptrauth_unwind_proc_lsda
+  #define __ptrauth_unwind_proc_flags
+  #define __ptrauth_unwind_proc_info
+  #define __ptrauth_unwind_proc_extra
+  #define __ptrauth_unwind_arm64_link_reg
+  #define __ptrauth_unwind_info_section_dso_base
+  #define __ptrauth_unwind_info_dwarf_section
+  #define __ptrauth_unwind_info_dwarf_section_length
+  #define __ptrauth_unwind_info_compact_unwind_section
+  #define __ptrauth_unwind_info_compact_unwind_section_length
+  #define __ptrauth_unwind_cfi_personality
+
+#endif
+
 #if defined(_WIN32) && defined(__SEH__)
   #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16)))
 #else
@@ -88,17 +185,18 @@ typedef double unw_fpreg_t;
 #endif
 
 struct unw_proc_info_t {
-  unw_word_t  start_ip;         /* start address of function */
-  unw_word_t  end_ip;           /* address after end of function */
-  unw_word_t  lsda;             /* address of language specific data area, */
-                                /*  or zero if not used */
-  unw_word_t  handler;          /* personality routine, or zero if not used */
+  unw_word_t __ptrauth_unwind_proc_startip start_ip; /* start address of function */
+  unw_word_t __ptrauth_unwind_proc_endip end_ip; /* address after end of function */
+  unw_word_t __ptrauth_unwind_proc_lsda lsda; /* address of language specific data area, */
+            /* or zero if not used */
+
+  unw_word_t __ptrauth_unwind_personality_fn_intptr handler;
   unw_word_t  gp;               /* not used */
-  unw_word_t  flags;            /* not used */
+  unw_word_t __ptrauth_unwind_proc_flags flags; /* not used */
   uint32_t    format;           /* compact unwind encoding, or zero if none */
   uint32_t    unwind_info_size; /* size of DWARF unwind info, or zero if none */
-  unw_word_t  unwind_info;      /* address of DWARF unwind info, or zero */
-  unw_word_t  extra;            /* mach_header of mach-o image containing func */
+  unw_word_t __ptrauth_unwind_proc_info unwind_info; /* address of DWARF unwind info, or zero */
+  unw_word_t __ptrauth_unwind_proc_extra extra; /* mach_header of mach-o image containing func */
 };
 typedef struct unw_proc_info_t unw_proc_info_t;
 
diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
index 5551c7d4bef1c..987b0710ea99a 100644
--- a/libunwind/src/AddressSpace.hpp
+++ b/libunwind/src/AddressSpace.hpp
@@ -129,26 +129,26 @@ struct UnwindInfoSections {
     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) ||                              \
     defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
   // No dso_base for SEH.
-  uintptr_t       dso_base;
+  uintptr_t __ptrauth_unwind_info_section_dso_base dso_base = 0;
 #endif
 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
-  size_t          text_segment_length;
+  size_t text_segment_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-  uintptr_t       dwarf_section;
-  size_t          dwarf_section_length;
+  uintptr_t __ptrauth_unwind_info_dwarf_section dwarf_section = 0;
+  size_t __ptrauth_unwind_info_dwarf_section_length dwarf_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
-  uintptr_t       dwarf_index_section;
-  size_t          dwarf_index_section_length;
+  uintptr_t dwarf_index_section = 0;
+  size_t dwarf_index_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-  uintptr_t       compact_unwind_section;
-  size_t          compact_unwind_section_length;
+  uintptr_t __ptrauth_unwind_info_compact_unwind_section compact_unwind_section = 0;
+  size_t __ptrauth_unwind_info_compact_unwind_section_length compact_unwind_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_ARM_EHABI)
-  uintptr_t       arm_section;
-  size_t          arm_section_length;
+  uintptr_t arm_section = 0;
+  size_t arm_section_length = 0;
 #endif
 };
 
@@ -196,7 +196,7 @@ class _LIBUNWIND_HIDDEN LocalAddressSpace {
   static int64_t  getSLEB128(pint_t &addr, pint_t end);
 
   pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
-                     pint_t datarelBase = 0);
+                     pint_t datarelBase = 0, pint_t *resultAddr = nullptr);
   bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
                         unw_word_t *offset);
   bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
@@ -269,7 +269,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
 
 inline LocalAddressSpace::pint_t
 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
-                               pint_t datarelBase) {
+                               pint_t datarelBase, pint_t *resultAddr) {
   pint_t startAddr = addr;
   const uint8_t *p = (uint8_t *)addr;
   pint_t result;
@@ -353,8 +353,14 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
     break;
   }
 
-  if (encoding & DW_EH_PE_indirect)
+  if (encoding & DW_EH_PE_indirect) {
+    if (resultAddr)
+      *resultAddr = result;
     result = getP(result);
+  } else {
+    if (resultAddr)
+      *resultAddr = startAddr;
+  }
 
   return result;
 }
diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp
index a7a8a153d86a4..272352ab63e84 100644
--- a/libunwind/src/CompactUnwinder.hpp
+++ b/libunwind/src/CompactUnwinder.hpp
@@ -601,11 +601,13 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
     savedRegisterLoc -= 8;
   }
 
+  Registers_arm64::reg_t linkRegister = registers.getRegister(UNW_AARCH64_LR);
+
   // subtract stack size off of sp
   registers.setSP(savedRegisterLoc);
 
   // set pc to be value in lr
-  registers.setIP(registers.getRegister(UNW_AARCH64_LR));
+  registers.setIP(linkRegister);
 
   return UNW_STEP_SUCCESS;
 }
@@ -614,7 +616,7 @@ template <typename A>
 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
     compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
     Registers_arm64 &registers) {
-  uint64_t savedRegisterLoc = registers.getFP() - 8;
+  Registers_arm64::reg_t savedRegisterLoc = registers.getFP() - 8;
 
   if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
     registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
@@ -680,11 +682,19 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
     savedRegisterLoc -= 8;
   }
 
-  uint64_t fp = registers.getFP();
+  Registers_arm64::reg_t fp = registers.getFP();
   // fp points to old fp
   registers.setFP(addressSpace.get64(fp));
-  // old sp is fp less saved fp and lr
+
+  // old sp is fp less saved fp and lr. Set this before FP & LR because in
+  // arm64e it's the discriminator used for those registers.
   registers.setSP(fp + 16);
+
+  Registers_arm64::reg_t oldfp = addressSpace.get64(fp);
+
+  // fp points to old fp
+  registers.setFP(oldfp);
+
   // pop return address into pc
   registers.setIP(addressSpace.get64(fp + 8));
 
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index e7be0d6d5d635..7039d81c58c23 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -22,6 +22,9 @@
 #include "dwarf2.h"
 #include "libunwind_ext.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
 
 namespace libunwind {
 
@@ -34,8 +37,9 @@ class DwarfInstructions {
   typedef typename A::pint_t pint_t;
   typedef typename A::sint_t sint_t;
 
-  static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
-                           R &registers, bool &isSignalFrame, bool stage2);
+  static int stepWithDwarf(A &addressSpace, typename R::link_reg_t &pc,
+                           pint_t fdeStart, R &registers, bool &isSignalFrame,
+                           bool stage2);
 
 private:
 
@@ -63,10 +67,11 @@ class DwarfInstructions {
                                   pint_t cfa, const RegisterLocation &savedReg);
 
   static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
-                       const R &registers) {
-    if (prolog.cfaRegister != 0)
-      return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
-             prolog.cfaRegisterOffset);
+                       R &registers) {
+    if (prolog.cfaRegister != 0) {
+      uintptr_t cfaRegister = registers.getRegister((int)prolog.cfaRegister);
+      return (pint_t)(cfaRegister + prolog.cfaRegisterOffset);
+    }
     if (prolog.cfaExpression != 0)
       return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
                                 registers, 0);
@@ -207,7 +212,8 @@ bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
 #endif
 
 template <typename A, typename R>
-int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
+int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
+                                           typename R::link_reg_t &pc,
                                            pint_t fdeStart, R &registers,
                                            bool &isSignalFrame, bool stage2) {
   FDE_Info fdeInfo;
@@ -264,7 +270,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
       // by a CFI directive later on.
       newRegisters.setSP(cfa);
 
-      pint_t returnAddress = 0;
+      typename R::reg_t returnAddress = 0;
       constexpr int lastReg = R::lastDwarfRegNum();
       static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
                         lastReg,
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 25250e0810987..0fee0646a9cac 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -23,6 +23,10 @@
 
 #include "config.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
 namespace libunwind {
 
 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
@@ -33,6 +37,7 @@ template <typename A>
 class CFI_Parser {
 public:
   typedef typename A::pint_t pint_t;
+  typedef pint_t __ptrauth_unwind_cfi_personality personality_t;
 
   /// Information encoded in a CIE (Common Information Entry)
   struct CIE_Info {
@@ -43,7 +48,7 @@ class CFI_Parser {
     uint8_t   lsdaEncoding;
     uint8_t   personalityEncoding;
     uint8_t   personalityOffsetInCIE;
-    pint_t    personality;
+    personality_t personality;
     uint32_t  codeAlignFactor;
     int       dataAlignFactor;
     bool      isSignalFrame;
@@ -313,6 +318,17 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
   }
   return false;
 }
+namespace {
+// This helper function handles setting the manually signed personality on
+// CIE_Info without attempt to authenticate and/or re-sign
+template <typename CIE_Info, typename T>
+void set_cie_info_personality(CIE_Info *info, T signed_personality) {
+  static_assert(sizeof(info->personality) == sizeof(signed_personality),
+                "Signed personality is the wrong size");
+  memmove((void *)&info->personality, (void *)&signed_personality,
+          sizeof(signed_personality));
+}
+}
 
 /// Extract info from a CIE
 template <typename A>
@@ -369,6 +385,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
   cieInfo->returnAddressRegister = (uint8_t)raReg;
   // parse augmentation data based on augmentation string
   const char *result = NULL;
+  pint_t resultAddr = 0;
   if (addressSpace.get8(strStart) == 'z') {
     // parse augmentation data length
     addressSpace.getULEB128(p, cieContentEnd);
@@ -377,13 +394,31 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
       case 'z':
         cieInfo->fdesHaveAugmentationData = true;
         break;
-      case 'P':
+      case 'P': {
         cieInfo->personalityEncoding = addressSpace.get8(p);
         ++p;
         cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
-        cieInfo->personality = addressSpace
-            .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+        pint_t personality = addressSpace.getEncodedP(
+            p, cieContentEnd, cieInfo->personalityEncoding,
+            /*datarelBase=*/0, &resultAddr);
+#if __has_feature(ptrauth_calls)
+        if (personality) {
+          // The GOT for the personality function was signed address
+          // authenticated. Manually re-sign with the CIE_Info::personality
+          // schema. If we could guarantee the encoding of the personality we
+          // could avoid this by simply giving resultAddr the correct ptrauth
+          // schema and performing an assignment.
+          const auto discriminator = ptrauth_blend_discriminator(
+              &cieInfo->personality, __ptrauth_unwind_cfi_personality_disc);
+          void *signedPtr = ptrauth_auth_and_resign(
+              (void *)personality, ptrauth_key_function_pointer, resultAddr,
+              ptrauth_key_function_pointer, discriminator);
+          personality = (pint_t)signedPtr;
+        }
+#endif
+        set_cie_info_personality(cieInfo, personality);
         break;
+      }
       case 'L':
         cieInfo->lsdaEncoding = addressSpace.get8(p);
         ++p;
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 8b3055f5cd7cd..b0f887b43fa3f 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -18,6 +18,11 @@
 #include "config.h"
 #include "libunwind.h"
 #include "shadow_stack_unwind.h"
+#include "libunwind_ext.h"
+
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
 
 namespace libunwind {
 
@@ -93,6 +98,13 @@ class _LIBUNWIND_HIDDEN Registers_x86 {
   uint32_t  getEDI() const         { return _registers.__edi; }
   void      setEDI(uint32_t value) { _registers.__edi = value; }
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
 private:
   struct GPRs {
     unsigned int __eax;
@@ -311,6 +323,13 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 {
   uint64_t  getR15() const         { return _registers.__r15; }
   void      setR15(uint64_t value) { _registers.__r15 = value; }
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
 private:
   struct GPRs {
     uint64_t __rax;
@@ -622,6 +641,13 @@ class _LIBUNWIND_HIDDEN Registers_ppc {
   uint64_t  getLR() const         { return _registers.__lr; }
   void      setLR(uint32_t value) { _registers.__lr = value; }
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
 private:
   struct ppc_thread_state_t {
     unsigned int __srr0; /* Instruction address register (PC) */
@@ -1826,6 +1852,8 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
 public:
   Registers_arm64();
   Registers_arm64(const void *registers);
+  Registers_arm64(const Registers_arm64&);
+  Registers_arm64& operator=(const Registers_arm64&);
 
   bool        validRegister(int num) const;
   uint64_t    getRegister(int num) const;
@@ -1845,10 +1873,58 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
 
   uint64_t  getSP() const         { return _registers.__sp; }
   void      setSP(uint64_t value) { _registers.__sp = value; }
-  uint64_t  getIP() const         { return _registers.__pc; }
-  void      setIP(uint64_t value) { _registers.__pc = value; }
-  uint64_t  getFP() const         { return _registers.__fp; }
-  void      setFP(uint64_t value) { _registers.__fp = value; }
+  uint64_t  getIP() const         {
+    uint64_t value = _registers.__pc;
+#if __has_feature(ptrauth_calls)
+    // 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());
+#endif
+    return value;
+  }
+  void      setIP(uint64_t value) {
+#if __has_feature(ptrauth_calls)
+    // 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);
+#endif
+    _registers.__pc = value;
+  }
+  uint64_t getFP() const { return _registers.__fp; }
+  void setFP(uint64_t value) { _registers.__fp = value; }
+
+  typedef uint64_t reg_t;
+  typedef uint64_t __ptrauth_unwind_arm64_link_reg link_reg_t;
+
+  void
+  loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
+                                  link_reg_t *referenceAuthedLinkRegister) {
+#if __has_feature(ptrauth_calls)
+    // 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);
+#else
+    *referenceAuthedLinkRegister = inplaceAuthedLinkRegister;
+#endif
+  }
+
+  // arm64_32 and i386 simulator hack
+  void      loadAndAuthenticateLinkRegister(uint32_t srcLinkRegister,
+                                            uint32_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
 
 private:
   uint64_t lazyGetVG() const;
@@ -1889,6 +1965,31 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   memcpy(_vectorHalfRegisters,
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
+#if __has_feature(ptrauth_calls)
+  uint64_t pcRegister = 0;
+  memcpy(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
+         sizeof(pcRegister));
+  setIP(pcRegister);
+  uint64_t fpRegister = 0;
+  memcpy(&fpRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __fp),
+         sizeof(fpRegister));
+  setFP(fpRegister);
+#endif
+}
+
+inline Registers_arm64::Registers_arm64(const Registers_arm64& other) {
+  *this = other;
+}
+
+inline Registers_arm64& Registers_arm64::operator=(const Registers_arm64& other) {
+  memcpy(&_registers, &other._registers, sizeof(_registers));
+  memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
+         sizeof(_vectorHalfRegisters));
+#if __has_feature(ptrauth_calls)
+  setIP(other.getIP());
+  setFP(other.getFP());
+#endif
+  return *this;
 }
 
 inline Registers_arm64::Registers_arm64() {
@@ -1930,13 +2031,13 @@ inline uint64_t Registers_arm64::lazyGetVG() const {
 
 inline uint64_t Registers_arm64::getRegister(int regNum) const {
   if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
-    return _registers.__pc;
+    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_FP)
-    return _registers.__fp;
+    return getFP();
   if (regNum == UNW_AARCH64_LR)
     return _registers.__lr;
   if (regNum == UNW_AARCH64_VG)
@@ -1948,13 +2049,13 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const {
 
 inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
   if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
-    _registers.__pc = 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_FP)
-    _registers.__fp = value;
+    setFP(value);
   else if (regNum == UNW_AARCH64_LR)
     _registers.__lr = value;
   else if (regNum == UNW_AARCH64_VG)
@@ -2172,6 +2273,13 @@ class _LIBUNWIND_HIDDEN Registers_arm {
   uint32_t  getIP() const         { return _registers.__pc; }
   void      setIP(uint32_t value) { _registers.__pc = value; }
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
+                                       link_reg_t *dstLinkRegister) {
+    *dstLinkRegister = srcLinkRegister;
+  }
+
   void saveVFPAsX() {
     assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
     _use_X_for_vfp_save = true;
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 9a1afd3721f5a..6e50e51ecb213 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -111,6 +111,10 @@ extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
 
 #endif
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
 namespace libunwind {
 
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -1047,18 +1051,22 @@ class UnwindCursor : public AbstractUnwindCursor{
   bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo,
                          const typename CFI_Parser<A>::CIE_Info &cieInfo,
                          pint_t pc, uintptr_t dso_base);
-  bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
-                                            uint32_t fdeSectionOffsetHint=0);
+  bool getInfoFromDwarfSection(const typename R::link_reg_t &pc,
+                               const UnwindInfoSections &sects,
+                               uint32_t fdeSectionOffsetHint = 0);
   int stepWithDwarfFDE(bool stage2) {
+    typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
+    typename R::link_reg_t pc;
+    _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
     return DwarfInstructions<A, R>::stepWithDwarf(
-        _addressSpace, (pint_t)this->getReg(UNW_REG_IP),
-        (pint_t)_info.unwind_info, _registers, _isSignalFrame, stage2);
+        _addressSpace, pc, (pint_t)_info.unwind_info, _registers,
+        _isSignalFrame, stage2);
   }
 #endif
 
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-  bool getInfoFromCompactEncodingSection(pint_t pc,
-                                            const UnwindInfoSections &sects);
+  bool getInfoFromCompactEncodingSection(const typename R::link_reg_t &pc,
+                                         const UnwindInfoSections &sects);
   int stepWithCompactEncoding(bool stage2 = false) {
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
     if ( compactSaysUseDwarf() )
@@ -1683,9 +1691,9 @@ bool UnwindCursor<A, R>::getInfoFromFdeCie(
 }
 
 template <typename A, typename R>
-bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
-                                                const UnwindInfoSections &sects,
-                                                uint32_t fdeSectionOffsetHint) {
+bool UnwindCursor<A, R>::getInfoFromDwarfSection(
+    const typename R::link_reg_t &pc, const UnwindInfoSections &sects,
+    uint32_t fdeSectionOffsetHint) {
   typename CFI_Parser<A>::FDE_Info fdeInfo;
   typename CFI_Parser<A>::CIE_Info cieInfo;
   bool foundFDE = false;
@@ -1742,9 +1750,21 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
 
 
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+// This helper function handles setting the manually signed handler on
+// unw_proc_info without attempt to authenticate and/or re-sign
+namespace {
+template <typename T>
+void set_proc_info_handler(unw_proc_info_t &info, T signed_handler) {
+  static_assert(sizeof(info.handler) == sizeof(signed_handler),
+                "Signed handler is the wrong size");
+  memmove((void *)&info.handler, (void *)&signed_handler,
+          sizeof(signed_handler));
+}
+} // unnamed namespace
+
 template <typename A, typename R>
-bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
-                                              const UnwindInfoSections &sects) {
+bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
+    const typename R::link_reg_t &pc, const UnwindInfoSections &sects) {
   const bool log = false;
   if (log)
     fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n",
@@ -1975,6 +1995,16 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
         personalityIndex * sizeof(uint32_t));
     pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
     personality = _addressSpace.getP(personalityPointer);
+#if __has_feature(ptrauth_calls)
+    // The GOT for the personality function was signed address authenticated.
+    // Resign is as a regular function pointer.
+    const auto discriminator = ptrauth_blend_discriminator(
+        &_info.handler, __ptrauth_unwind_personality_fn_disc);
+    void *signedPtr = ptrauth_auth_and_resign(
+        (void *)personality, ptrauth_key_function_pointer, personalityPointer,
+        ptrauth_key_function_pointer, discriminator);
+    personality = (__typeof(personality))signedPtr;
+#endif
     if (log)
       fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
                       "personalityDelta=0x%08X, personality=0x%08llX\n",
@@ -1988,7 +2018,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
   _info.start_ip = funcStart;
   _info.end_ip = funcEnd;
   _info.lsda = lsda;
-  _info.handler = personality;
+  set_proc_info_handler(_info, personality);
   _info.gp = 0;
   _info.flags = 0;
   _info.format = encoding;
@@ -2641,13 +2671,17 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
   _isSigReturn = false;
 #endif
 
-  pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
+
 #if defined(_LIBUNWIND_ARM_EHABI)
   // Remove the thumb bit so the IP represents the actual instruction address.
   // This matches the behaviour of _Unwind_GetIP on arm.
-  pc &= (pint_t)~0x1;
+  rawPC &= (pint_t)~0x1;
 #endif
 
+  typename R::link_reg_t pc;
+  _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
+
   // Exit early if at the top of the stack.
   if (pc == 0) {
     _unwindInfoMissing = true;
@@ -3196,9 +3230,12 @@ 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) {
-  return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP),
-                                         buf, bufLen, offset);
+                                         unw_word_t *offset) {
+  typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
+  typename R::link_reg_t pc;
+  _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
+
+  return _addressSpace.findFunctionName(pc, buf, bufLen, offset);
 }
 
 #if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index f3b451ad9b730..f3fd8a1d915e1 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -31,6 +31,10 @@
 #include "shadow_stack_unwind.h"
 #include "unwind.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
+
 #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) &&   \
     !defined(__wasm__)
 
@@ -90,6 +94,19 @@
   } while (0)
 #endif
 
+// There is not currently a clean way to cast between an authenticated
+// integer and an authenticated function pointer, so we need this helper
+// function to keep things clean.
+static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
+  union {
+    void *opaque_handler;
+    _Unwind_Personality_Fn __ptrauth_unwind_personality_fn *
+        handler;
+  } u;
+  u.opaque_handler = (void *)&frameInfo->handler;
+  return *u.handler;
+}
+
 static _Unwind_Reason_Code
 unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
   __unw_init_local(cursor, uc);
@@ -147,8 +164,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
     // If there is a personality routine, ask it if it will want to stop at
     // this frame.
     if (frameInfo.handler != 0) {
-      _Unwind_Personality_Fn p =
-          (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
+      _Unwind_Personality_Fn p = get_handler_function(&frameInfo);
       _LIBUNWIND_TRACE_UNWINDING(
           "unwind_phase1(ex_obj=%p): calling personality function %p",
           (void *)exception_object, (void *)(uintptr_t)p);
@@ -276,8 +292,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor,
     ++framesWalked;
     // If there is a personality routine, tell it we are unwinding.
     if (frameInfo.handler != 0) {
-      _Unwind_Personality_Fn p =
-          (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
+      _Unwind_Personality_Fn p = get_handler_function(&frameInfo);
       _Unwind_Action action = _UA_CLEANUP_PHASE;
       if (sp == exception_object->private_2) {
         // Tell personality this was the frame it marked in phase 1.
@@ -394,8 +409,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
     ++framesWalked;
     // If there is a personality routine, tell it we are unwinding.
     if (frameInfo.handler != 0) {
-      _Unwind_Personality_Fn p =
-          (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
+      _Unwind_Personality_Fn p = get_handler_function(&frameInfo);
       _LIBUNWIND_TRACE_UNWINDING(
           "unwind_phase2_forced(ex_obj=%p): calling personality function %p",
           (void *)exception_object, (void *)(uintptr_t)p);
@@ -597,6 +611,18 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
   unw_cursor_t *cursor = (unw_cursor_t *)context;
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
+
+#if __has_feature(ptrauth_calls)
+  // If we are in an arm64e frame, then the PC should have been signed with the
+  // sp
+  {
+    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);
+  }
+#endif
+
   _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
                        (void *)context, result);
   return (uintptr_t)result;
diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index 1077d80bc90de..92a71fe992c65 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -659,7 +659,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   ldp    x24,x25, [x0, #0x0C0]
   ldp    x26,x27, [x0, #0x0D0]
   ldp    x28,x29, [x0, #0x0E0]
-  ldr    x30,     [x0, #0x100]  // restore pc into lr
+
 #if defined(__ARM_FP) && __ARM_FP != 0
   ldp    d0, d1,  [x0, #0x110]
   ldp    d2, d3,  [x0, #0x120]
@@ -683,7 +683,18 @@ 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    x16,     [x0, #0x0F8]
+
+  ldr    x16,     [x0, #0x0F8]  // load sp into scratch
+  ldr    lr,      [x0, #0x100]  // restore pc into lr
+
+#if __has_feature(ptrauth_calls)
+  // The LR is signed with its address inside the register state.  Time
+  // to resign to be a regular ROP signed pointer
+  add    x1, x0, #0x100
+  autib  lr, x1
+  pacib  lr, x16  // signed the scratch register for sp
+#endif
+
   ldp    x0, x1,  [x0, #0x000]  // restore x0,x1
   mov    sp,x16                 // restore sp
 #if defined(__ARM_FEATURE_GCS_DEFAULT)
@@ -696,7 +707,12 @@ 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 8bf99ebd942fa..fe3ba7842619f 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -769,6 +769,11 @@ LnoR2Fix:
 //
   .p2align 2
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+
+#if __has_feature(ptrauth_calls)
+  pacibsp
+#endif
+
   stp    x0, x1,  [x0, #0x000]
   stp    x2, x3,  [x0, #0x010]
   stp    x4, x5,  [x0, #0x020]
@@ -809,7 +814,12 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   str    d31,     [x0, #0x208]
 #endif
   mov    x0, #0                   // return UNW_ESUCCESS
+
+#if __has_feature(ptrauth_calls)
+  retab
+#else
   ret
+#endif
 
 #elif defined(__arm__) && !defined(__APPLE__)
 
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index cf39ec5f7dbdf..e84774bf5aed0 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -14,7 +14,11 @@
 #include "config.h"
 #include "libunwind_ext.h"
 
+#if __has_include(<ptrauth.h>)
+#include <ptrauth.h>
+#endif
 #include <stdlib.h>
+#include <sys/types.h>
 
 // Define the __has_feature extension for compilers that do not support it so
 // that we can later check for the presence of ASan in a compiler-neutral way.
@@ -118,14 +122,42 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
   typedef LocalAddressSpace::pint_t pint_t;
   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
   if (co->validReg(regNum)) {
-    co->setReg(regNum, (pint_t)value);
     // special case altering IP to re-find info (being called by personality
     // function)
     if (regNum == UNW_REG_IP) {
       unw_proc_info_t info;
       // First, get the FDE for the old location and then update it.
       co->getInfo(&info);
-      co->setInfoBasedOnIPRegister(false);
+
+#if __has_feature(ptrauth_calls)
+      // It is only valid to set the IP within the current function.
+      // This is important for ptrauth, otherwise the IP cannot be correctly
+      // signed.
+      unw_word_t stripped_value =
+          (unw_word_t)ptrauth_strip((void *)value, ptrauth_key_return_address);
+      [[maybe_unused]]stripped_value;
+      assert(stripped_value >= info.start_ip && stripped_value <= info.end_ip);
+#endif
+
+      pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
+
+#if __has_feature(ptrauth_calls)
+      {
+        // PC should have been signed with the sp, so we verify that
+        // roundtripping does not fail.
+        pint_t pc = (pint_t)co->getReg(UNW_REG_IP);
+        if (ptrauth_auth_and_resign((void *)pc, ptrauth_key_return_address, sp,
+                                    ptrauth_key_return_address,
+                                    sp) != (void *)pc) {
+          _LIBUNWIND_LOG("Bad unwind through arm64e (0x%llX, 0x%llX)->0x%llX\n",
+                         pc, sp,
+                         (pint_t)ptrauth_auth_data(
+                             (void *)pc, ptrauth_key_return_address, sp));
+          _LIBUNWIND_ABORT("Bad unwind through arm64e");
+        }
+      }
+#endif
+
       // If the original call expects stack adjustment, perform this now.
       // Normal frame unwinding would have included the offset already in the
       // CFA computation.
@@ -134,6 +166,10 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
       // any such platforms and Clang doesn't export a macro for them.
       if (info.gp)
         co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
+      co->setReg(UNW_REG_IP, value);
+      co->setInfoBasedOnIPRegister(false);
+    } else {
+      co->setReg(regNum, (pint_t)value);
     }
     return UNW_ESUCCESS;
   }

>From 61b763aa1412a755f9fa6c18e82ed712bb6dc0b6 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 6 Aug 2025 00:10:14 -0700
Subject: [PATCH 02/28] Updating to include some fixes I lost in the last
 update

At some point I lost the changes to loadAndAuthenticateLinkRegister
I also updated schema names in libunwind to be more consistent
Finally while looking at the total diff I saw some places that
the formatting could be improved.
---
 libcxxabi/include/__cxxabi_config.h    |  1 -
 libcxxabi/src/cxa_personality.cpp      | 14 ++--
 libunwind/include/libunwind.h          | 93 +++++++++++++-------------
 libunwind/src/AddressSpace.hpp         | 25 ++++---
 libunwind/src/DwarfParser.hpp          |  4 +-
 libunwind/src/Registers.hpp            | 49 ++++----------
 libunwind/src/UnwindCursor.hpp         | 27 ++++++--
 libunwind/src/UnwindLevel1.c           |  2 +-
 libunwind/src/UnwindRegistersRestore.S |  2 +-
 libunwind/src/libunwind.cpp            |  2 -
 10 files changed, 106 insertions(+), 113 deletions(-)

diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 9962c81c0c61c..769f73ccb1a70 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -48,7 +48,6 @@
   #define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
   #define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
  #endif
-
 #else
  #if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
   #define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index ef59cba21e272..3b95f27f62bd9 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -578,9 +578,9 @@ typedef void* __ptrauth_scan_results_landingpad landing_pad_ptr_t;
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
-    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future maintenance.
-    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
-    landing_pad_t landingPad;       // null -> nothing found, else something found
+    action_ptr_t   actionRecord; // Currently unused.  Retained to ease future maintenance.
+    lsd_ptr_t      languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t  landingPad;   // null -> nothing found, else something found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -589,7 +589,7 @@ struct scan_results
 };
 
 }  // unnamed namespace
-}
+} // extern "C"
 
 namespace {
 // The logical model for casting authenticated function pointers makes
@@ -632,16 +632,16 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
                 static_cast<uintptr_t>(results.ttypeIndex));
 #if __has_feature(ptrauth_qualifier)
-  auto stack_pointer = _Unwind_GetGR(context, UNW_REG_SP);
+  auto stackPointer = _Unwind_GetGR(context, UNW_REG_SP);
   // We manually re-sign the IP as the __ptrauth qualifiers cannot
   // express the required relationship with the destination address
   const auto existingDiscriminator = ptrauth_blend_discriminator(
       &results.landingPad, __ptrauth_scan_results_landingpad_disc);
-  unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stack_pointer, 0) */ =
+  unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stackPointer, 0) */ =
       (unw_word_t)ptrauth_auth_and_resign(*(void**)&results.landingPad,
                                           __ptrauth_scan_results_landingpad_key,
                                           existingDiscriminator,
-                                          ptrauth_key_return_address, stack_pointer);
+                                          ptrauth_key_return_address, stackPointer);
   _Unwind_SetIP(context, newIP);
 #else
   _Unwind_SetIP(context, results.landingPad);
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 1580575aabe74..19d53f3cb729e 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -58,85 +58,86 @@
   #endif
 
 // ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
-  #define __ptrauth_unwind_personality_fn_disc 0x7405
+  #define __ptrauth_unwind_upi_handler_disc 0x7405
 
-  #define __ptrauth_unwind_personality_fn \
-    __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_personality_fn_disc)
+  #define __ptrauth_unwind_upi_handler \
+    __ptrauth(ptrauth_key_function_pointer, 1, __ptrauth_unwind_upi_handler_disc)
 
-  #define __ptrauth_unwind_personality_fn_intptr \
-    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, __ptrauth_unwind_personality_fn_disc)
+  #define __ptrauth_unwind_upi_handler_intptr \
+    __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,\
+                                       __ptrauth_unwind_upi_handler_disc)
 
 // ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
-  #define __ptrauth_unwind_proc_startip \
+  #define __ptrauth_unwind_upi_startip \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xCA2C)
 
 // ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
-  #define __ptrauth_unwind_proc_endip \
+  #define __ptrauth_unwind_upi_endip \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xE183)
 
 // ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
-  #define __ptrauth_unwind_proc_lsda \
+  #define __ptrauth_unwind_upi_lsda \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x83DE)
 
 // ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
-  #define __ptrauth_unwind_proc_flags \
+  #define __ptrauth_unwind_upi_flags \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x79A1)
 
 // ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
-  #define __ptrauth_unwind_proc_info \
+  #define __ptrauth_unwind_upi_info \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xC20C)
 
 // ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
-  #define __ptrauth_unwind_proc_extra \
+  #define __ptrauth_unwind_upi_extra \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x03DF)
 
 // ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
-  #define __ptrauth_unwind_arm64_link_reg \
+  #define __ptrauth_unwind_registers_arm64_link_reg \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1, 0x8301)
 
 // ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
-  #define __ptrauth_unwind_info_section_dso_base \
+  #define __ptrauth_unwind_uis_dso_base \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4FF5)
 
 // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
-  #define __ptrauth_unwind_info_dwarf_section \
+  #define __ptrauth_unwind_uis_dwarf_section \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4974)
 
 // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A
-  #define __ptrauth_unwind_info_dwarf_section_length \
+  #define __ptrauth_unwind_uis_dwarf_section_length \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x2A9A)
 
 // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B
-  #define __ptrauth_unwind_info_compact_unwind_section \
+  #define __ptrauth_unwind_uis_compact_unwind_section \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xA27B)
 
 // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A
-  #define __ptrauth_unwind_info_compact_unwind_section_length \
+  #define __ptrauth_unwind_uis_compact_unwind_section_length \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x5D0A)
 
 // ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
-  #define __ptrauth_unwind_cfi_personality_disc 0x6A40
-  #define __ptrauth_unwind_cfi_personality \
+  #define __ptrauth_unwind_cie_info_personality_disc 0x6A40
+  #define __ptrauth_unwind_cie_info_personality \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \
-                                       __ptrauth_unwind_cfi_personality_disc)
+                                       __ptrauth_unwind_cie_info_personality_disc)
 
 #else
 
-  #define __ptrauth_unwind_personality_fn
-  #define __ptrauth_unwind_personality_fn_intptr
-  #define __ptrauth_unwind_proc_startip
-  #define __ptrauth_unwind_proc_endip
-  #define __ptrauth_unwind_proc_lsda
-  #define __ptrauth_unwind_proc_flags
-  #define __ptrauth_unwind_proc_info
-  #define __ptrauth_unwind_proc_extra
-  #define __ptrauth_unwind_arm64_link_reg
-  #define __ptrauth_unwind_info_section_dso_base
-  #define __ptrauth_unwind_info_dwarf_section
-  #define __ptrauth_unwind_info_dwarf_section_length
-  #define __ptrauth_unwind_info_compact_unwind_section
-  #define __ptrauth_unwind_info_compact_unwind_section_length
-  #define __ptrauth_unwind_cfi_personality
+  #define __ptrauth_unwind_upi_handler
+  #define __ptrauth_unwind_upi_handler_intptr
+  #define __ptrauth_unwind_upi_startip
+  #define __ptrauth_unwind_upi_endip
+  #define __ptrauth_unwind_upi_lsda
+  #define __ptrauth_unwind_upi_flags
+  #define __ptrauth_unwind_upi_info
+  #define __ptrauth_unwind_upi_extra
+  #define __ptrauth_unwind_registers_arm64_link_reg
+  #define __ptrauth_unwind_uis_dso_base
+  #define __ptrauth_unwind_uis_dwarf_section
+  #define __ptrauth_unwind_uis_dwarf_section_length
+  #define __ptrauth_unwind_uis_compact_unwind_section
+  #define __ptrauth_unwind_uis_compact_unwind_section_length
+  #define __ptrauth_unwind_cie_info_personality
 
 #endif
 
@@ -185,18 +186,18 @@ typedef double unw_fpreg_t;
 #endif
 
 struct unw_proc_info_t {
-  unw_word_t __ptrauth_unwind_proc_startip start_ip; /* start address of function */
-  unw_word_t __ptrauth_unwind_proc_endip end_ip; /* address after end of function */
-  unw_word_t __ptrauth_unwind_proc_lsda lsda; /* address of language specific data area, */
-            /* or zero if not used */
+  unw_word_t __ptrauth_unwind_upi_startip start_ip; /* start address of function */
+  unw_word_t __ptrauth_unwind_upi_endip end_ip;     /* address after end of function */
+  unw_word_t __ptrauth_unwind_upi_lsda lsda;        /* address of language specific data area, */
+                                                    /* or zero if not used */
 
-  unw_word_t __ptrauth_unwind_personality_fn_intptr handler;
-  unw_word_t  gp;               /* not used */
-  unw_word_t __ptrauth_unwind_proc_flags flags; /* not used */
-  uint32_t    format;           /* compact unwind encoding, or zero if none */
-  uint32_t    unwind_info_size; /* size of DWARF unwind info, or zero if none */
-  unw_word_t __ptrauth_unwind_proc_info unwind_info; /* address of DWARF unwind info, or zero */
-  unw_word_t __ptrauth_unwind_proc_extra extra; /* mach_header of mach-o image containing func */
+  unw_word_t __ptrauth_unwind_upi_handler_intptr handler;
+  unw_word_t  gp;                                   /* not used */
+  unw_word_t __ptrauth_unwind_upi_flags flags;      /* not used */
+  uint32_t    format;                               /* compact unwind encoding, or zero if none */
+  uint32_t    unwind_info_size;                     /* size of DWARF unwind info, or zero if none */
+  unw_word_t __ptrauth_unwind_upi_info unwind_info; /* address of DWARF unwind info, or zero */
+  unw_word_t __ptrauth_unwind_upi_extra extra;      /* mach_header of mach-o image containing func */
 };
 typedef struct unw_proc_info_t unw_proc_info_t;
 
diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
index 987b0710ea99a..63f9cb367ec0c 100644
--- a/libunwind/src/AddressSpace.hpp
+++ b/libunwind/src/AddressSpace.hpp
@@ -129,26 +129,31 @@ struct UnwindInfoSections {
     defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) ||                              \
     defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
   // No dso_base for SEH.
-  uintptr_t __ptrauth_unwind_info_section_dso_base dso_base = 0;
+  uintptr_t __ptrauth_unwind_uis_dso_base
+                  dso_base = 0;
 #endif
 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
-  size_t text_segment_length = 0;
+  size_t          text_segment_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-  uintptr_t __ptrauth_unwind_info_dwarf_section dwarf_section = 0;
-  size_t __ptrauth_unwind_info_dwarf_section_length dwarf_section_length = 0;
+  uintptr_t __ptrauth_unwind_uis_dwarf_section
+                  dwarf_section = 0;
+  size_t __ptrauth_unwind_uis_dwarf_section_length
+                  dwarf_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
-  uintptr_t dwarf_index_section = 0;
-  size_t dwarf_index_section_length = 0;
+  uintptr_t       dwarf_index_section;
+  size_t          dwarf_index_section_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-  uintptr_t __ptrauth_unwind_info_compact_unwind_section compact_unwind_section = 0;
-  size_t __ptrauth_unwind_info_compact_unwind_section_length compact_unwind_section_length = 0;
+  uintptr_t __ptrauth_unwind_uis_compact_unwind_section
+                  compact_unwind_section = 0;
+  size_t __ptrauth_unwind_uis_compact_unwind_section_length
+                  compact_unwind_section_length = 0;
 #endif
 #if defined(_LIBUNWIND_ARM_EHABI)
-  uintptr_t arm_section = 0;
-  size_t arm_section_length = 0;
+  uintptr_t       arm_section;
+  size_t          arm_section_length;
 #endif
 };
 
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 0fee0646a9cac..d5641d4b6362c 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -37,7 +37,7 @@ template <typename A>
 class CFI_Parser {
 public:
   typedef typename A::pint_t pint_t;
-  typedef pint_t __ptrauth_unwind_cfi_personality personality_t;
+  typedef pint_t __ptrauth_unwind_cie_info_personality personality_t;
 
   /// Information encoded in a CIE (Common Information Entry)
   struct CIE_Info {
@@ -409,7 +409,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
           // could avoid this by simply giving resultAddr the correct ptrauth
           // schema and performing an assignment.
           const auto discriminator = ptrauth_blend_discriminator(
-              &cieInfo->personality, __ptrauth_unwind_cfi_personality_disc);
+              &cieInfo->personality, __ptrauth_unwind_cie_info_personality_disc);
           void *signedPtr = ptrauth_auth_and_resign(
               (void *)personality, ptrauth_key_function_pointer, resultAddr,
               ptrauth_key_function_pointer, discriminator);
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index b0f887b43fa3f..70c36dc376ab9 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -100,10 +100,6 @@ class _LIBUNWIND_HIDDEN Registers_x86 {
 
   typedef uint32_t reg_t;
   typedef uint32_t link_reg_t;
-  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
-                                       link_reg_t *dstLinkRegister) {
-    *dstLinkRegister = srcLinkRegister;
-  }
 
 private:
   struct GPRs {
@@ -325,10 +321,6 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 {
 
   typedef uint64_t reg_t;
   typedef uint64_t link_reg_t;
-  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
-                                       link_reg_t *dstLinkRegister) {
-    *dstLinkRegister = srcLinkRegister;
-  }
 
 private:
   struct GPRs {
@@ -643,10 +635,6 @@ class _LIBUNWIND_HIDDEN Registers_ppc {
 
   typedef uint32_t reg_t;
   typedef uint32_t link_reg_t;
-  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
-                                       link_reg_t *dstLinkRegister) {
-    *dstLinkRegister = srcLinkRegister;
-  }
 
 private:
   struct ppc_thread_state_t {
@@ -1903,28 +1891,20 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   void setFP(uint64_t value) { _registers.__fp = value; }
 
   typedef uint64_t reg_t;
-  typedef uint64_t __ptrauth_unwind_arm64_link_reg link_reg_t;
+  typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t;
 
+#if __has_feature(ptrauth_calls)
   void
   loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
                                   link_reg_t *referenceAuthedLinkRegister) {
-#if __has_feature(ptrauth_calls)
     // 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);
-#else
-    *referenceAuthedLinkRegister = inplaceAuthedLinkRegister;
-#endif
-  }
-
-  // arm64_32 and i386 simulator hack
-  void      loadAndAuthenticateLinkRegister(uint32_t srcLinkRegister,
-                                            uint32_t *dstLinkRegister) {
-    *dstLinkRegister = srcLinkRegister;
+    *referenceAuthedLinkRegister =
+      (uint64_t)ptrauth_auth_data((void *)inplaceAuthedLinkRegister,
+                                  ptrauth_key_return_address,
+                                  _registers.__sp);
   }
+#endif
 
 private:
   uint64_t lazyGetVG() const;
@@ -1966,14 +1946,14 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
 #if __has_feature(ptrauth_calls)
+  // 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
+  // performed by setIP.
   uint64_t pcRegister = 0;
   memcpy(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
          sizeof(pcRegister));
   setIP(pcRegister);
-  uint64_t fpRegister = 0;
-  memcpy(&fpRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __fp),
-         sizeof(fpRegister));
-  setFP(fpRegister);
 #endif
 }
 
@@ -1986,8 +1966,9 @@ inline Registers_arm64& Registers_arm64::operator=(const Registers_arm64& other)
   memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
          sizeof(_vectorHalfRegisters));
 #if __has_feature(ptrauth_calls)
+  // We perform this step to ensure that we correctly authenticate and re-sign
+  // the pc after the bitwise copy.
   setIP(other.getIP());
-  setFP(other.getFP());
 #endif
   return *this;
 }
@@ -2275,10 +2256,6 @@ class _LIBUNWIND_HIDDEN Registers_arm {
 
   typedef uint32_t reg_t;
   typedef uint32_t link_reg_t;
-  void      loadAndAuthenticateLinkRegister(reg_t srcLinkRegister,
-                                       link_reg_t *dstLinkRegister) {
-    *dstLinkRegister = srcLinkRegister;
-  }
 
   void saveVFPAsX() {
     assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 6e50e51ecb213..7a978b5f558bb 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1055,9 +1055,13 @@ class UnwindCursor : public AbstractUnwindCursor{
                                const UnwindInfoSections &sects,
                                uint32_t fdeSectionOffsetHint = 0);
   int stepWithDwarfFDE(bool stage2) {
+#if __has_extension(ptrauth_calls)
     typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
     typename R::link_reg_t pc;
     _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
+#else
+    typename R::link_reg_t pc = this->getReg(UNW_REG_IP);
+#endif
     return DwarfInstructions<A, R>::stepWithDwarf(
         _addressSpace, pc, (pint_t)_info.unwind_info, _registers,
         _isSignalFrame, stage2);
@@ -1997,12 +2001,14 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
     personality = _addressSpace.getP(personalityPointer);
 #if __has_feature(ptrauth_calls)
     // The GOT for the personality function was signed address authenticated.
-    // Resign is as a regular function pointer.
-    const auto discriminator = ptrauth_blend_discriminator(
-        &_info.handler, __ptrauth_unwind_personality_fn_disc);
-    void *signedPtr = ptrauth_auth_and_resign(
-        (void *)personality, ptrauth_key_function_pointer, personalityPointer,
-        ptrauth_key_function_pointer, discriminator);
+    // Resign it as a regular function pointer.
+    const auto discriminator =
+      ptrauth_blend_discriminator(&_info.handler,
+                                  __ptrauth_unwind_upi_handler_disc);
+    void *signedPtr =
+      ptrauth_auth_and_resign((void *)personality, ptrauth_key_function_pointer,
+                              personalityPointer, ptrauth_key_function_pointer,
+                              discriminator);
     personality = (__typeof(personality))signedPtr;
 #endif
     if (log)
@@ -2680,7 +2686,11 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
 #endif
 
   typename R::link_reg_t pc;
+#if __has_extension(ptrauth_calls)
   _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
+#else
+  pc = rawPC;
+#endif
 
   // Exit early if at the top of the stack.
   if (pc == 0) {
@@ -3231,10 +3241,13 @@ 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 __has_extension(ptrauth_calls)
   typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
   typename R::link_reg_t pc;
   _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
-
+#else
+  typename R::link_reg_t pc = this->getReg(UNW_REG_IP);
+#endif
   return _addressSpace.findFunctionName(pc, buf, bufLen, offset);
 }
 
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index f3fd8a1d915e1..1df65437cd333 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -100,7 +100,7 @@
 static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
   union {
     void *opaque_handler;
-    _Unwind_Personality_Fn __ptrauth_unwind_personality_fn *
+    _Unwind_Personality_Fn __ptrauth_unwind_upi_handler *
         handler;
   } u;
   u.opaque_handler = (void *)&frameInfo->handler;
diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index 92a71fe992c65..5d71d2cf61ad9 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -689,7 +689,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
 
 #if __has_feature(ptrauth_calls)
   // The LR is signed with its address inside the register state.  Time
-  // to resign to be a regular ROP signed pointer
+  // 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
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index e84774bf5aed0..4f3c4313e19e5 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -137,11 +137,9 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
           (unw_word_t)ptrauth_strip((void *)value, ptrauth_key_return_address);
       [[maybe_unused]]stripped_value;
       assert(stripped_value >= info.start_ip && stripped_value <= info.end_ip);
-#endif
 
       pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
 
-#if __has_feature(ptrauth_calls)
       {
         // PC should have been signed with the sp, so we verify that
         // roundtripping does not fail.

>From 6e696ad4628adf62daea65256355fc5bbf9a89e4 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 6 Aug 2025 12:59:44 -0700
Subject: [PATCH 03/28] Build fix due to not testing the build after apply
 review feedback \o/

---
 libunwind/src/libunwind.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 4f3c4313e19e5..e37d1fc32548b 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -133,9 +133,8 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
       // It is only valid to set the IP within the current function.
       // This is important for ptrauth, otherwise the IP cannot be correctly
       // signed.
-      unw_word_t stripped_value =
+      [[maybe_unused]]unw_word_t stripped_value =
           (unw_word_t)ptrauth_strip((void *)value, ptrauth_key_return_address);
-      [[maybe_unused]]stripped_value;
       assert(stripped_value >= info.start_ip && stripped_value <= info.end_ip);
 
       pint_t sp = (pint_t)co->getReg(UNW_REG_SP);

>From 27d43afe0da27b8aa043c4f2d35378ae94bc9cf8 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 6 Aug 2025 14:03:21 -0700
Subject: [PATCH 04/28] work around a bug where clang reports a template
 function as unused

---
 libunwind/src/DwarfParser.hpp | 3 ++-
 libunwind/src/libunwind.cpp   | 6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index d5641d4b6362c..04e016440190d 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -322,7 +322,8 @@ namespace {
 // This helper function handles setting the manually signed personality on
 // CIE_Info without attempt to authenticate and/or re-sign
 template <typename CIE_Info, typename T>
-void set_cie_info_personality(CIE_Info *info, T signed_personality) {
+[[maybe_unused]] void set_cie_info_personality(CIE_Info *info,
+                                               T signed_personality) {
   static_assert(sizeof(info->personality) == sizeof(signed_personality),
                 "Signed personality is the wrong size");
   memmove((void *)&info->personality, (void *)&signed_personality,
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index e37d1fc32548b..a5c945676633a 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -129,6 +129,8 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
       // First, get the FDE for the old location and then update it.
       co->getInfo(&info);
 
+      pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
+
 #if __has_feature(ptrauth_calls)
       // It is only valid to set the IP within the current function.
       // This is important for ptrauth, otherwise the IP cannot be correctly
@@ -137,8 +139,6 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
           (unw_word_t)ptrauth_strip((void *)value, ptrauth_key_return_address);
       assert(stripped_value >= info.start_ip && stripped_value <= info.end_ip);
 
-      pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
-
       {
         // PC should have been signed with the sp, so we verify that
         // roundtripping does not fail.
@@ -162,7 +162,7 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
       // this should actually be - info.gp. LLVM doesn't currently support
       // any such platforms and Clang doesn't export a macro for them.
       if (info.gp)
-        co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
+        co->setReg(UNW_REG_SP, sp + info.gp);
       co->setReg(UNW_REG_IP, value);
       co->setInfoBasedOnIPRegister(false);
     } else {

>From 8dc31944f4c5dcc99b3e1086b0f11a4f7af18407 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 6 Aug 2025 14:41:21 -0700
Subject: [PATCH 05/28] And another one

---
 libcxxabi/src/cxa_personality.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 3b95f27f62bd9..7885134406fca 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -596,7 +596,7 @@ namespace {
 // it impossible to directly cast them without breaking the authentication,
 // as a result we need this pair of helpers.
 template <typename PtrType>
-void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
+[[maybe_unused]] void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
   union {
     landing_pad_t* as_landing_pad;
     landing_pad_ptr_t* as_pointer;

>From d3ba2f8298de5249347a1b27ea2c29e99d441096 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 6 Aug 2025 14:48:27 -0700
Subject: [PATCH 06/28] Add all the required reg_t and link_reg_t decls, and
 unify location

---
 libunwind/src/Registers.hpp | 63 ++++++++++++++++++++++++++++---------
 1 file changed, 48 insertions(+), 15 deletions(-)

diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 70c36dc376ab9..8c81882577d24 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -65,6 +65,9 @@ class _LIBUNWIND_HIDDEN Registers_x86 {
   Registers_x86();
   Registers_x86(const void *registers);
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint32_t    getRegister(int num) const;
   void        setRegister(int num, uint32_t value);
@@ -98,9 +101,6 @@ class _LIBUNWIND_HIDDEN Registers_x86 {
   uint32_t  getEDI() const         { return _registers.__edi; }
   void      setEDI(uint32_t value) { _registers.__edi = value; }
 
-  typedef uint32_t reg_t;
-  typedef uint32_t link_reg_t;
-
 private:
   struct GPRs {
     unsigned int __eax;
@@ -286,6 +286,9 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 {
   Registers_x86_64();
   Registers_x86_64(const void *registers);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint64_t    getRegister(int num) const;
   void        setRegister(int num, uint64_t value);
@@ -319,9 +322,6 @@ class _LIBUNWIND_HIDDEN Registers_x86_64 {
   uint64_t  getR15() const         { return _registers.__r15; }
   void      setR15(uint64_t value) { _registers.__r15 = value; }
 
-  typedef uint64_t reg_t;
-  typedef uint64_t link_reg_t;
-
 private:
   struct GPRs {
     uint64_t __rax;
@@ -608,6 +608,9 @@ class _LIBUNWIND_HIDDEN Registers_ppc {
   Registers_ppc();
   Registers_ppc(const void *registers);
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint32_t    getRegister(int num) const;
   void        setRegister(int num, uint32_t value);
@@ -633,9 +636,6 @@ class _LIBUNWIND_HIDDEN Registers_ppc {
   uint64_t  getLR() const         { return _registers.__lr; }
   void      setLR(uint32_t value) { _registers.__lr = value; }
 
-  typedef uint32_t reg_t;
-  typedef uint32_t link_reg_t;
-
 private:
   struct ppc_thread_state_t {
     unsigned int __srr0; /* Instruction address register (PC) */
@@ -1183,6 +1183,9 @@ class _LIBUNWIND_HIDDEN Registers_ppc64 {
   Registers_ppc64();
   Registers_ppc64(const void *registers);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint64_t    getRegister(int num) const;
   void        setRegister(int num, uint64_t value);
@@ -1843,6 +1846,9 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   Registers_arm64(const Registers_arm64&);
   Registers_arm64& operator=(const Registers_arm64&);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t;
+
   bool        validRegister(int num) const;
   uint64_t    getRegister(int num) const;
   void        setRegister(int num, uint64_t value);
@@ -1890,9 +1896,6 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   uint64_t getFP() const { return _registers.__fp; }
   void setFP(uint64_t value) { _registers.__fp = value; }
 
-  typedef uint64_t reg_t;
-  typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t;
-
 #if __has_feature(ptrauth_calls)
   void
   loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
@@ -2230,6 +2233,9 @@ class _LIBUNWIND_HIDDEN Registers_arm {
   Registers_arm();
   Registers_arm(const void *registers);
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint32_t    getRegister(int num) const;
   void        setRegister(int num, uint32_t value);
@@ -2254,9 +2260,6 @@ class _LIBUNWIND_HIDDEN Registers_arm {
   uint32_t  getIP() const         { return _registers.__pc; }
   void      setIP(uint32_t value) { _registers.__pc = value; }
 
-  typedef uint32_t reg_t;
-  typedef uint32_t link_reg_t;
-
   void saveVFPAsX() {
     assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
     _use_X_for_vfp_save = true;
@@ -2738,6 +2741,9 @@ class _LIBUNWIND_HIDDEN Registers_or1k {
   Registers_or1k();
   Registers_or1k(const void *registers);
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint32_t    getRegister(int num) const;
   void        setRegister(int num, uint32_t value);
@@ -2937,6 +2943,9 @@ class _LIBUNWIND_HIDDEN Registers_mips_o32 {
   Registers_mips_o32();
   Registers_mips_o32(const void *registers);
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint32_t    getRegister(int num) const;
   void        setRegister(int num, uint32_t value);
@@ -3272,6 +3281,9 @@ class _LIBUNWIND_HIDDEN Registers_mips_newabi {
   Registers_mips_newabi();
   Registers_mips_newabi(const void *registers);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint64_t    getRegister(int num) const;
   void        setRegister(int num, uint64_t value);
@@ -3575,6 +3587,9 @@ class _LIBUNWIND_HIDDEN Registers_sparc {
   Registers_sparc();
   Registers_sparc(const void *registers);
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint32_t    getRegister(int num) const;
   void        setRegister(int num, uint32_t value);
@@ -3761,6 +3776,9 @@ class _LIBUNWIND_HIDDEN Registers_sparc64 {
   Registers_sparc64() = default;
   Registers_sparc64(const void *registers);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+
   bool validRegister(int num) const;
   uint64_t getRegister(int num) const;
   void setRegister(int num, uint64_t value);
@@ -3946,6 +3964,9 @@ class _LIBUNWIND_HIDDEN Registers_hexagon {
   Registers_hexagon();
   Registers_hexagon(const void *registers);
 
+  typedef uint32_t reg_t;
+  typedef uint32_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint32_t    getRegister(int num) const;
   void        setRegister(int num, uint32_t value);
@@ -4161,6 +4182,9 @@ class _LIBUNWIND_HIDDEN Registers_riscv {
   Registers_riscv();
   Registers_riscv(const void *registers);
 
+  typedef ::libunwind::reg_t reg_t;
+  typedef ::libunwind::reg_t link_reg_t;
+
   bool        validRegister(int num) const;
   reg_t       getRegister(int num) const;
   void        setRegister(int num, reg_t value);
@@ -4458,6 +4482,9 @@ class _LIBUNWIND_HIDDEN Registers_ve {
   Registers_ve();
   Registers_ve(const void *registers);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint64_t    getRegister(int num) const;
   void        setRegister(int num, uint64_t value);
@@ -4901,6 +4928,9 @@ class _LIBUNWIND_HIDDEN Registers_s390x {
   Registers_s390x();
   Registers_s390x(const void *registers);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+
   bool        validRegister(int num) const;
   uint64_t    getRegister(int num) const;
   void        setRegister(int num, uint64_t value);
@@ -5189,6 +5219,9 @@ class _LIBUNWIND_HIDDEN Registers_loongarch {
   Registers_loongarch();
   Registers_loongarch(const void *registers);
 
+  typedef uint64_t reg_t;
+  typedef uint64_t link_reg_t;
+
   bool validRegister(int num) const;
   uint64_t getRegister(int num) const;
   void setRegister(int num, uint64_t value);

>From c1ec8d6dd9c4b43e8101bccfe0408eab4e43e4c5 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 6 Aug 2025 15:45:32 -0700
Subject: [PATCH 07/28] This erroneous error is annoying

---
 libcxxabi/src/cxa_personality.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 7885134406fca..c5c72f39289d5 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -605,7 +605,7 @@ template <typename PtrType>
   *u.as_pointer = out;
 }
 
-static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
+[[maybe_unused]] static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
   union {
     const landing_pad_t* as_landing_pad;
     const landing_pad_ptr_t* as_pointer;

>From 7a78b25fac118a473f38178f10870543dcf68aa1 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 6 Aug 2025 19:13:08 -0700
Subject: [PATCH 08/28] Remove header include that is unnecessary but
 apparently works in some places

---
 libcxxabi/src/cxa_personality.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index c5c72f39289d5..22a70c62691bf 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -21,7 +21,6 @@
 #include "cxa_handlers.h"
 #include "private_typeinfo.h"
 #include "unwind.h"
-#include "libunwind.h"
 
 #if __has_include(<ptrauth.h>)
 #  include <ptrauth.h>

>From a5cd944e86a9493987f0f7c76c840ea8585ebdb1 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 2 Sep 2025 15:59:58 -0700
Subject: [PATCH 09/28] Update for feature check changes

---
 compiler-rt/lib/builtins/crtbegin.c                | 10 ++++++++--
 compiler-rt/lib/builtins/gcc_personality_v0.c      |  8 ++++++--
 .../lib/sanitizer_common/sanitizer_ptrauth.h       |  2 +-
 .../test/asan/TestCases/Darwin/linked-only.cpp     |  4 ++--
 compiler-rt/test/asan/TestCases/zero_page_pc.cpp   |  4 ++--
 .../TestCases/sanitizer_coverage_control_flow.cpp  |  2 +-
 .../TypeCheck/vptr-corrupted-vtable-itanium.cpp    |  9 ++++++---
 libcxx/src/include/overridable_function.h          |  6 +++---
 libcxxabi/include/__cxxabi_config.h                |  6 +++++-
 libcxxabi/src/cxa_exception.h                      |  4 ++--
 libcxxabi/src/cxa_personality.cpp                  |  8 ++------
 libcxxabi/src/private_typeinfo.cpp                 |  4 ++--
 libunwind/include/libunwind.h                      | 13 +++++++++----
 libunwind/src/DwarfInstructions.hpp                |  4 ----
 libunwind/src/DwarfParser.hpp                      |  6 +-----
 libunwind/src/Registers.hpp                        | 14 +++++---------
 libunwind/src/UnwindCursor.hpp                     | 12 ++++--------
 libunwind/src/UnwindLevel1.c                       |  6 +-----
 libunwind/src/UnwindRegistersRestore.S             |  4 ++--
 libunwind/src/UnwindRegistersSave.S                |  4 ++--
 libunwind/src/libunwind.cpp                        |  5 +----
 21 files changed, 65 insertions(+), 70 deletions(-)

diff --git a/compiler-rt/lib/builtins/crtbegin.c b/compiler-rt/lib/builtins/crtbegin.c
index 8b5f98fdd04ed..b743ee472f6f4 100644
--- a/compiler-rt/lib/builtins/crtbegin.c
+++ b/compiler-rt/lib/builtins/crtbegin.c
@@ -16,6 +16,12 @@
 #include <ptrauth.h>
 #endif
 
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#define __crtbegin_has_ptrauth 1
+#else
+#define __crtbegin_has_ptrauth 0
+#endif
+
 __attribute__((visibility("hidden"))) void *__dso_handle = &__dso_handle;
 
 #ifdef EH_USE_FRAME_REGISTRY
@@ -66,7 +72,7 @@ __attribute__((section(".init_array"), used)) static void *__init =
     ptrauth_sign_constant(&__do_init, ptrauth_key_init_fini_pointer,
                           __ptrauth_init_fini_discriminator);
 #  endif
-# elif __has_feature(ptrauth_calls)
+# elif __crtbegin_has_ptrauth
 #  ifdef __aarch64__
 // If ptrauth_init_fini feature is not present, compiler emits raw unsigned
 // pointers in .init_array. Use inline assembly to avoid implicit signing of
@@ -148,7 +154,7 @@ __attribute__((section(".fini_array"), used)) static void *__fini =
     ptrauth_sign_constant(&__do_fini, ptrauth_key_init_fini_pointer,
                           __ptrauth_init_fini_discriminator);
 #  endif
-# elif __has_feature(ptrauth_calls)
+# elif __crtbegin_has_ptrauth
 #  ifdef __aarch64__
 // If ptrauth_init_fini feature is not present, compiler emits raw unsigned
 // pointers in .fini_array. Use inline assembly to avoid implicit signing of
diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
index 36a50fa266235..b7e2d5ba9c601 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -30,8 +30,11 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
                                             _Unwind_Personality_Fn);
 #endif
 
-#if __has_feature(ptrauth_qualifier)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
 #include <ptrauth.h>
+
+#define __gcc_personality_has_ptrauth 1
+
 #if __has_feature(ptrauth_restricted_intptr_qualifier)
 #define __ptrauth_gcc_personality_intptr(key, addressDiscriminated,            \
                                               discriminator)                   \
@@ -42,6 +45,7 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
   __ptrauth(key, addressDiscriminated, discriminator)
 #endif
 #else
+#define __gcc_personality_has_ptrauth 0
 #define __ptrauth_gcc_personality_intptr(...)
 #endif
 
@@ -283,7 +287,7 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
       size_t __ptrauth_gcc_personality_lpad landingPad =
           funcStart + landingPadOffset;
-#if __has_feature(ptrauth_qualifier)
+#if __gcc_personality_has_ptrauth
       uintptr_t stackPointer = _Unwind_GetGR(context, -2);
       const uintptr_t existingDiscriminator =
         ptrauth_blend_discriminator(&landingPad,
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
index 265a9925a15a0..e48036507a4af 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
@@ -9,7 +9,7 @@
 #ifndef SANITIZER_PTRAUTH_H
 #define SANITIZER_PTRAUTH_H
 
-#if __has_feature(ptrauth_intrinsics)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
 #  include <ptrauth.h>
 #elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
 // On the stack the link register is protected with Pointer
diff --git a/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp b/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp
index d404af6ff05fb..0ccdfef3dc330 100644
--- a/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp
+++ b/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp
@@ -10,7 +10,7 @@
 #include <string.h>
 
 #include "sanitizer/asan_interface.h"
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
 #  include <ptrauth.h>
 #endif
 
@@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
   // CHECK: =-1=
 
   char *mainptr;
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
   mainptr = (char *)ptrauth_strip((void *)&main, ptrauth_key_return_address);
 #else
   mainptr = (char *)&main;
diff --git a/compiler-rt/test/asan/TestCases/zero_page_pc.cpp b/compiler-rt/test/asan/TestCases/zero_page_pc.cpp
index 66396a817be14..5b2a0d36a666e 100644
--- a/compiler-rt/test/asan/TestCases/zero_page_pc.cpp
+++ b/compiler-rt/test/asan/TestCases/zero_page_pc.cpp
@@ -9,14 +9,14 @@
 #  define __has_feature(x) 0
 #endif
 
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
 #  include <ptrauth.h>
 #endif
 
 typedef void void_f();
 int main() {
   void_f *func = (void_f *)0x4;
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
   func = ptrauth_sign_unauthenticated(
       func, ptrauth_key_function_pointer, 0);
 #endif
diff --git a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
index 5223af07f18ae..1dae589cde898 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
+++ b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
@@ -8,7 +8,7 @@
 
 #include <cstdint>
 #include <cstdio>
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
   #include <ptrauth.h>
 #else
   #define ptrauth_strip(__value, __key) (__value)
diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
index 9c47b69dbb6aa..ccee5eea386f6 100644
--- a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
+++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
@@ -6,8 +6,11 @@
 
 #include <typeinfo>
 
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#define __has_ptrauth 1
 #include <ptrauth.h>
+#else
+#define __has_ptrauth 0
 #endif
 
 struct S {
@@ -28,7 +31,7 @@ int main(int argc, char **argv) {
   S Obj;
   void *Ptr = &Obj;
   void *VtablePtr = *reinterpret_cast<void**>(Ptr);
-#if __has_feature(ptrauth_calls)
+#if __has_ptrauth
   VtablePtr = ptrauth_strip(VtablePtr, 0);
 #endif
   VtablePrefix* Prefix = reinterpret_cast<VtablePrefix*>(VtablePtr) - 1;
@@ -39,7 +42,7 @@ int main(int argc, char **argv) {
 
   // Hack Vtable ptr for Obj.
   void *FakeVtablePtr = static_cast<void*>(&FakePrefix[1]);
-#if __has_feature(ptrauth_calls)
+#if __has_ptrauth
   FakeVtablePtr = ptrauth_sign_unauthenticated(
       FakeVtablePtr, ptrauth_key_cxx_vtable_pointer, 0);
 #endif
diff --git a/libcxx/src/include/overridable_function.h b/libcxx/src/include/overridable_function.h
index 0b43f271486c1..1f75f5e668238 100644
--- a/libcxx/src/include/overridable_function.h
+++ b/libcxx/src/include/overridable_function.h
@@ -13,7 +13,7 @@
 #include <__config>
 #include <cstdint>
 
-#if __has_feature(ptrauth_calls)
+#if __ptrauth_cxxabi_has_ptrauth
 #  include <ptrauth.h>
 #endif
 
@@ -83,7 +83,7 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
   uintptr_t __end   = reinterpret_cast<uintptr_t>(&__lcxx_override_end);
   uintptr_t __ptr   = reinterpret_cast<uintptr_t>(_Func);
 
-#  if __has_feature(ptrauth_calls)
+#  if __ptrauth_cxxabi_has_ptrauth
   // We must pass a void* to ptrauth_strip since it only accepts a pointer type. Also, in particular,
   // we must NOT pass a function pointer, otherwise we will strip the function pointer, and then attempt
   // to authenticate and re-sign it when casting it to a uintptr_t again, which will fail because we just
@@ -117,7 +117,7 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
   uintptr_t __end   = reinterpret_cast<uintptr_t>(&__stop___lcxx_override);
   uintptr_t __ptr   = reinterpret_cast<uintptr_t>(_Func);
 
-#  if __has_feature(ptrauth_calls)
+#  if __ptrauth_cxxabi_has_ptrauth
   // We must pass a void* to ptrauth_strip since it only accepts a pointer type. See full explanation above.
   __ptr = reinterpret_cast<uintptr_t>(ptrauth_strip(reinterpret_cast<void*>(__ptr), ptrauth_key_function_pointer));
 #  endif
diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 769f73ccb1a70..d49c291ca3727 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -107,7 +107,9 @@
 #  include <ptrauth.h>
 #endif
 
-#if __has_extension(ptrauth_qualifier)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+
+#  define __ptrauth_cxxabi_has_ptrauth 1
 
 // ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
 #  define __ptrauth_cxxabi_action_record \
@@ -139,6 +141,8 @@
 
 #else
 
+#  define __ptrauth_cxxabi_has_ptrauth 0
+
 #  define __ptrauth_cxxabi_action_record
 #  define __ptrauth_cxxabi_lsd
 #  define __ptrauth_cxxabi_catch_temp
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index d59ddcefad151..97be422cc60bb 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,7 +47,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
+    void (_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
              exceptionDestructor)(void*);
 #endif
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
@@ -89,7 +89,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
+    void (_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
              exceptionDestructor)(void*);
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 22a70c62691bf..1d9e5545d1f49 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -22,11 +22,7 @@
 #include "private_typeinfo.h"
 #include "unwind.h"
 
-#if __has_include(<ptrauth.h>)
-#  include <ptrauth.h>
-#endif
-
-#if __has_extension(ptrauth_qualifier)
+#if __ptrauth_cxxabi_has_ptrauth
 // The actual value of the discriminators listed below is not important.
 // The derivation of the constants is only being included for the purpose
 // of maintaining a record of how they were originally produced.
@@ -630,7 +626,7 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
                 reinterpret_cast<uintptr_t>(unwind_exception));
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
                 static_cast<uintptr_t>(results.ttypeIndex));
-#if __has_feature(ptrauth_qualifier)
+#if __ptrauth_cxxabi_has_ptrauth
   auto stackPointer = _Unwind_GetGR(context, UNW_REG_SP);
   // We manually re-sign the IP as the __ptrauth qualifiers cannot
   // express the required relationship with the destination address
diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index 01a1d2603b18d..f3cf1e5be0624 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -53,13 +53,13 @@
 #include <atomic>
 #endif
 
-#if __has_feature(ptrauth_calls)
+#if __ptrauth_cxxabi_has_ptrauth
 #include <ptrauth.h>
 #endif
 
 template <typename T>
 static inline T* strip_vtable(T* vtable) {
-#if __has_feature(ptrauth_calls)
+#if __ptrauth_cxxabi_has_ptrauth
   vtable = ptrauth_strip(vtable, ptrauth_key_cxx_vtable_pointer);
 #endif
   return vtable;
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 19d53f3cb729e..1160a8a04861c 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -43,11 +43,13 @@
   #define LIBUNWIND_AVAIL
 #endif
 
-#if __has_extension(ptrauth_qualifier)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
 
-  #if __has_include(<ptrauth.h>)
-    #include <ptrauth.h>
-  #endif
+  #include <ptrauth.h>
+
+  // Local "has pointer auth" macro to for backwards compatibility
+  // with compilers that do not provide the __PTRAUTH__ macro
+  #define __libunwind_has_ptrauth 1
 
   #if __has_extension(ptrauth_restricted_intptr_qualifier)
     #define __unwind_ptrauth_restricted_intptr(...) \
@@ -122,6 +124,9 @@
                                        __ptrauth_unwind_cie_info_personality_disc)
 
 #else
+  // We explicitly define the not enabled case so that checks fail if they
+  // do not include the correct definitions.
+  #define __libunwind_has_ptrauth 0
 
   #define __ptrauth_unwind_upi_handler
   #define __ptrauth_unwind_upi_handler_intptr
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index 7039d81c58c23..b34d9d77b9ee5 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -22,10 +22,6 @@
 #include "dwarf2.h"
 #include "libunwind_ext.h"
 
-#if __has_include(<ptrauth.h>)
-#include <ptrauth.h>
-#endif
-
 namespace libunwind {
 
 
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 04e016440190d..5e494de10bdc2 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -23,10 +23,6 @@
 
 #include "config.h"
 
-#if __has_include(<ptrauth.h>)
-#include <ptrauth.h>
-#endif
-
 namespace libunwind {
 
 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
@@ -402,7 +398,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
         pint_t personality = addressSpace.getEncodedP(
             p, cieContentEnd, cieInfo->personalityEncoding,
             /*datarelBase=*/0, &resultAddr);
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
         if (personality) {
           // The GOT for the personality function was signed address
           // authenticated. Manually re-sign with the CIE_Info::personality
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 8c81882577d24..6233d70ab6dc3 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -20,10 +20,6 @@
 #include "shadow_stack_unwind.h"
 #include "libunwind_ext.h"
 
-#if __has_include(<ptrauth.h>)
-#include <ptrauth.h>
-#endif
-
 namespace libunwind {
 
 // For emulating 128-bit registers
@@ -1869,7 +1865,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   void      setSP(uint64_t value) { _registers.__sp = value; }
   uint64_t  getIP() const         {
     uint64_t value = _registers.__pc;
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
     // 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,
@@ -1881,7 +1877,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
     return value;
   }
   void      setIP(uint64_t value) {
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
     // 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.
@@ -1896,7 +1892,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   uint64_t getFP() const { return _registers.__fp; }
   void setFP(uint64_t value) { _registers.__fp = value; }
 
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
   void
   loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
                                   link_reg_t *referenceAuthedLinkRegister) {
@@ -1948,7 +1944,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   memcpy(_vectorHalfRegisters,
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
   // 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
@@ -1968,7 +1964,7 @@ inline Registers_arm64& Registers_arm64::operator=(const Registers_arm64& other)
   memcpy(&_registers, &other._registers, sizeof(_registers));
   memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
          sizeof(_vectorHalfRegisters));
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 7a978b5f558bb..dea7effa37631 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -111,10 +111,6 @@ extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
 
 #endif
 
-#if __has_include(<ptrauth.h>)
-#include <ptrauth.h>
-#endif
-
 namespace libunwind {
 
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -1055,7 +1051,7 @@ class UnwindCursor : public AbstractUnwindCursor{
                                const UnwindInfoSections &sects,
                                uint32_t fdeSectionOffsetHint = 0);
   int stepWithDwarfFDE(bool stage2) {
-#if __has_extension(ptrauth_calls)
+#if __libunwind_has_ptrauth
     typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
     typename R::link_reg_t pc;
     _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
@@ -1999,7 +1995,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
         personalityIndex * sizeof(uint32_t));
     pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
     personality = _addressSpace.getP(personalityPointer);
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
     // The GOT for the personality function was signed address authenticated.
     // Resign it as a regular function pointer.
     const auto discriminator =
@@ -2686,7 +2682,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
 #endif
 
   typename R::link_reg_t pc;
-#if __has_extension(ptrauth_calls)
+#if __libunwind_has_ptrauth
   _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
 #else
   pc = rawPC;
@@ -3241,7 +3237,7 @@ 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 __has_extension(ptrauth_calls)
+#if __libunwind_has_ptrauth
   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 1df65437cd333..d924a718a914d 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -31,10 +31,6 @@
 #include "shadow_stack_unwind.h"
 #include "unwind.h"
 
-#if __has_include(<ptrauth.h>)
-#include <ptrauth.h>
-#endif
-
 #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) &&   \
     !defined(__wasm__)
 
@@ -612,7 +608,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
 
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
   // If we are in an arm64e frame, then the PC should have been signed with the
   // sp
   {
diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index 5d71d2cf61ad9..a11b6dd9a1e86 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -687,7 +687,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   ldr    x16,     [x0, #0x0F8]  // load sp into scratch
   ldr    lr,      [x0, #0x100]  // restore pc into lr
 
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
   // 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
@@ -708,7 +708,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
 Lnogcs:
 #endif
 
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
   retab
 #else
   ret    x30                    // jump to pc
diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index fe3ba7842619f..80a4692f2222e 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -770,7 +770,7 @@ LnoR2Fix:
   .p2align 2
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
   pacibsp
 #endif
 
@@ -815,7 +815,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 #endif
   mov    x0, #0                   // return UNW_ESUCCESS
 
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
   retab
 #else
   ret
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index a5c945676633a..0dce8dea49e78 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -14,9 +14,6 @@
 #include "config.h"
 #include "libunwind_ext.h"
 
-#if __has_include(<ptrauth.h>)
-#include <ptrauth.h>
-#endif
 #include <stdlib.h>
 #include <sys/types.h>
 
@@ -131,7 +128,7 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
 
       pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
 
-#if __has_feature(ptrauth_calls)
+#if __libunwind_has_ptrauth
       // It is only valid to set the IP within the current function.
       // This is important for ptrauth, otherwise the IP cannot be correctly
       // signed.

>From c2c0190b0b1bc6ad8beb3ac98748cd3a2d14b8c3 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 3 Sep 2025 18:08:48 -0700
Subject: [PATCH 10/28] yet more cleaning up

---
 compiler-rt/lib/builtins/crtbegin.c               | 10 ++--------
 compiler-rt/lib/builtins/gcc_personality_v0.c     |  7 ++-----
 .../lib/sanitizer_common/sanitizer_ptrauth.h      |  2 +-
 .../test/asan/TestCases/Darwin/linked-only.cpp    |  4 ++--
 compiler-rt/test/asan/TestCases/zero_page_pc.cpp  |  4 ++--
 .../TestCases/sanitizer_coverage_control_flow.cpp |  2 +-
 .../TypeCheck/vptr-corrupted-vtable-itanium.cpp   |  8 +++-----
 libcxx/src/include/overridable_function.h         |  6 +++---
 libcxxabi/include/__cxxabi_config.h               |  6 +-----
 libcxxabi/src/cxa_exception.cpp                   |  4 +++-
 libcxxabi/src/cxa_personality.cpp                 | 15 ++++++++++-----
 libcxxabi/src/private_typeinfo.cpp                |  4 ++--
 libunwind/include/libunwind.h                     |  9 +--------
 libunwind/src/DwarfParser.hpp                     |  2 +-
 libunwind/src/Registers.hpp                       | 10 +++++-----
 libunwind/src/UnwindCursor.hpp                    |  8 ++++----
 libunwind/src/UnwindLevel1.c                      |  2 +-
 libunwind/src/UnwindRegistersRestore.S            |  4 ++--
 libunwind/src/UnwindRegistersSave.S               |  4 ++--
 libunwind/src/libunwind.cpp                       |  2 +-
 20 files changed, 49 insertions(+), 64 deletions(-)

diff --git a/compiler-rt/lib/builtins/crtbegin.c b/compiler-rt/lib/builtins/crtbegin.c
index b743ee472f6f4..8b5f98fdd04ed 100644
--- a/compiler-rt/lib/builtins/crtbegin.c
+++ b/compiler-rt/lib/builtins/crtbegin.c
@@ -16,12 +16,6 @@
 #include <ptrauth.h>
 #endif
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
-#define __crtbegin_has_ptrauth 1
-#else
-#define __crtbegin_has_ptrauth 0
-#endif
-
 __attribute__((visibility("hidden"))) void *__dso_handle = &__dso_handle;
 
 #ifdef EH_USE_FRAME_REGISTRY
@@ -72,7 +66,7 @@ __attribute__((section(".init_array"), used)) static void *__init =
     ptrauth_sign_constant(&__do_init, ptrauth_key_init_fini_pointer,
                           __ptrauth_init_fini_discriminator);
 #  endif
-# elif __crtbegin_has_ptrauth
+# elif __has_feature(ptrauth_calls)
 #  ifdef __aarch64__
 // If ptrauth_init_fini feature is not present, compiler emits raw unsigned
 // pointers in .init_array. Use inline assembly to avoid implicit signing of
@@ -154,7 +148,7 @@ __attribute__((section(".fini_array"), used)) static void *__fini =
     ptrauth_sign_constant(&__do_fini, ptrauth_key_init_fini_pointer,
                           __ptrauth_init_fini_discriminator);
 #  endif
-# elif __crtbegin_has_ptrauth
+# elif __has_feature(ptrauth_calls)
 #  ifdef __aarch64__
 // If ptrauth_init_fini feature is not present, compiler emits raw unsigned
 // pointers in .fini_array. Use inline assembly to avoid implicit signing of
diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
index b7e2d5ba9c601..881f119a5d453 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -30,11 +30,9 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
                                             _Unwind_Personality_Fn);
 #endif
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
 #include <ptrauth.h>
 
-#define __gcc_personality_has_ptrauth 1
-
 #if __has_feature(ptrauth_restricted_intptr_qualifier)
 #define __ptrauth_gcc_personality_intptr(key, addressDiscriminated,            \
                                               discriminator)                   \
@@ -45,7 +43,6 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
   __ptrauth(key, addressDiscriminated, discriminator)
 #endif
 #else
-#define __gcc_personality_has_ptrauth 0
 #define __ptrauth_gcc_personality_intptr(...)
 #endif
 
@@ -287,7 +284,7 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
       _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
       size_t __ptrauth_gcc_personality_lpad landingPad =
           funcStart + landingPadOffset;
-#if __gcc_personality_has_ptrauth
+#if __has_feature(ptrauth_calls)
       uintptr_t stackPointer = _Unwind_GetGR(context, -2);
       const uintptr_t existingDiscriminator =
         ptrauth_blend_discriminator(&landingPad,
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
index e48036507a4af..8c3c063d7948e 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
@@ -9,7 +9,7 @@
 #ifndef SANITIZER_PTRAUTH_H
 #define SANITIZER_PTRAUTH_H
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
 #  include <ptrauth.h>
 #elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
 // On the stack the link register is protected with Pointer
diff --git a/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp b/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp
index 0ccdfef3dc330..d404af6ff05fb 100644
--- a/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp
+++ b/compiler-rt/test/asan/TestCases/Darwin/linked-only.cpp
@@ -10,7 +10,7 @@
 #include <string.h>
 
 #include "sanitizer/asan_interface.h"
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
 #  include <ptrauth.h>
 #endif
 
@@ -27,7 +27,7 @@ int main(int argc, char *argv[]) {
   // CHECK: =-1=
 
   char *mainptr;
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
   mainptr = (char *)ptrauth_strip((void *)&main, ptrauth_key_return_address);
 #else
   mainptr = (char *)&main;
diff --git a/compiler-rt/test/asan/TestCases/zero_page_pc.cpp b/compiler-rt/test/asan/TestCases/zero_page_pc.cpp
index 5b2a0d36a666e..66396a817be14 100644
--- a/compiler-rt/test/asan/TestCases/zero_page_pc.cpp
+++ b/compiler-rt/test/asan/TestCases/zero_page_pc.cpp
@@ -9,14 +9,14 @@
 #  define __has_feature(x) 0
 #endif
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
 #  include <ptrauth.h>
 #endif
 
 typedef void void_f();
 int main() {
   void_f *func = (void_f *)0x4;
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
   func = ptrauth_sign_unauthenticated(
       func, ptrauth_key_function_pointer, 0);
 #endif
diff --git a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
index 1dae589cde898..5223af07f18ae 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
+++ b/compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp
@@ -8,7 +8,7 @@
 
 #include <cstdint>
 #include <cstdio>
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
   #include <ptrauth.h>
 #else
   #define ptrauth_strip(__value, __key) (__value)
diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
index ccee5eea386f6..b955cff7fcbf8 100644
--- a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
+++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
@@ -6,11 +6,9 @@
 
 #include <typeinfo>
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
-#define __has_ptrauth 1
+#if __has_feature(ptrauth_calls)
 #include <ptrauth.h>
 #else
-#define __has_ptrauth 0
 #endif
 
 struct S {
@@ -31,7 +29,7 @@ int main(int argc, char **argv) {
   S Obj;
   void *Ptr = &Obj;
   void *VtablePtr = *reinterpret_cast<void**>(Ptr);
-#if __has_ptrauth
+#if __has_feature(ptrauth_calls)
   VtablePtr = ptrauth_strip(VtablePtr, 0);
 #endif
   VtablePrefix* Prefix = reinterpret_cast<VtablePrefix*>(VtablePtr) - 1;
@@ -42,7 +40,7 @@ int main(int argc, char **argv) {
 
   // Hack Vtable ptr for Obj.
   void *FakeVtablePtr = static_cast<void*>(&FakePrefix[1]);
-#if __has_ptrauth
+#if __has_feature(ptrauth_calls)
   FakeVtablePtr = ptrauth_sign_unauthenticated(
       FakeVtablePtr, ptrauth_key_cxx_vtable_pointer, 0);
 #endif
diff --git a/libcxx/src/include/overridable_function.h b/libcxx/src/include/overridable_function.h
index 1f75f5e668238..0b43f271486c1 100644
--- a/libcxx/src/include/overridable_function.h
+++ b/libcxx/src/include/overridable_function.h
@@ -13,7 +13,7 @@
 #include <__config>
 #include <cstdint>
 
-#if __ptrauth_cxxabi_has_ptrauth
+#if __has_feature(ptrauth_calls)
 #  include <ptrauth.h>
 #endif
 
@@ -83,7 +83,7 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
   uintptr_t __end   = reinterpret_cast<uintptr_t>(&__lcxx_override_end);
   uintptr_t __ptr   = reinterpret_cast<uintptr_t>(_Func);
 
-#  if __ptrauth_cxxabi_has_ptrauth
+#  if __has_feature(ptrauth_calls)
   // We must pass a void* to ptrauth_strip since it only accepts a pointer type. Also, in particular,
   // we must NOT pass a function pointer, otherwise we will strip the function pointer, and then attempt
   // to authenticate and re-sign it when casting it to a uintptr_t again, which will fail because we just
@@ -117,7 +117,7 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept {
   uintptr_t __end   = reinterpret_cast<uintptr_t>(&__stop___lcxx_override);
   uintptr_t __ptr   = reinterpret_cast<uintptr_t>(_Func);
 
-#  if __ptrauth_cxxabi_has_ptrauth
+#  if __has_feature(ptrauth_calls)
   // We must pass a void* to ptrauth_strip since it only accepts a pointer type. See full explanation above.
   __ptr = reinterpret_cast<uintptr_t>(ptrauth_strip(reinterpret_cast<void*>(__ptr), ptrauth_key_function_pointer));
 #  endif
diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index d49c291ca3727..672926ecec930 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -107,9 +107,7 @@
 #  include <ptrauth.h>
 #endif
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
-
-#  define __ptrauth_cxxabi_has_ptrauth 1
+#if __has_feature(ptrauth_calls)
 
 // ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
 #  define __ptrauth_cxxabi_action_record \
@@ -141,8 +139,6 @@
 
 #else
 
-#  define __ptrauth_cxxabi_has_ptrauth 0
-
 #  define __ptrauth_cxxabi_action_record
 #  define __ptrauth_cxxabi_lsd
 #  define __ptrauth_cxxabi_catch_temp
diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp
index 92901a83bfd03..8a77e8c1230a7 100644
--- a/libcxxabi/src/cxa_exception.cpp
+++ b/libcxxabi/src/cxa_exception.cpp
@@ -192,7 +192,9 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
         std::terminate();
     __cxa_exception *exception_header =
         static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
-    ::memset(exception_header, 0, actual_size);
+    // We warn on memset to a non-trivially castable type. We might want to
+    // change that diagnostic to not fire on a trivially obvious zero fill.
+    ::memset(static_cast<void *>(exception_header), 0, actual_size);
     return thrown_object_from_cxa_exception(exception_header);
 }
 
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 1d9e5545d1f49..e3c8e7b6847da 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -20,9 +20,13 @@
 #include "cxa_exception.h"
 #include "cxa_handlers.h"
 #include "private_typeinfo.h"
-#include "unwind.h"
 
-#if __ptrauth_cxxabi_has_ptrauth
+#if __has_feature(ptrauth_calls)
+
+// CXXABI depends on defintions in libunwind as pointer auth couples the
+// definitions
+#include "libunwind.h"
+
 // The actual value of the discriminators listed below is not important.
 // The derivation of the constants is only being included for the purpose
 // of maintaining a record of how they were originally produced.
@@ -626,17 +630,18 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
                 reinterpret_cast<uintptr_t>(unwind_exception));
   _Unwind_SetGR(context, __builtin_eh_return_data_regno(1),
                 static_cast<uintptr_t>(results.ttypeIndex));
-#if __ptrauth_cxxabi_has_ptrauth
+#if __has_feature(ptrauth_calls)
   auto stackPointer = _Unwind_GetGR(context, UNW_REG_SP);
   // We manually re-sign the IP as the __ptrauth qualifiers cannot
   // express the required relationship with the destination address
   const auto existingDiscriminator = ptrauth_blend_discriminator(
       &results.landingPad, __ptrauth_scan_results_landingpad_disc);
   unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stackPointer, 0) */ =
-      (unw_word_t)ptrauth_auth_and_resign(*(void**)&results.landingPad,
+      (unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad,
                                           __ptrauth_scan_results_landingpad_key,
                                           existingDiscriminator,
-                                          ptrauth_key_return_address, stackPointer);
+                                          ptrauth_key_return_address,
+                                          stackPointer);
   _Unwind_SetIP(context, newIP);
 #else
   _Unwind_SetIP(context, results.landingPad);
diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp
index f3cf1e5be0624..01a1d2603b18d 100644
--- a/libcxxabi/src/private_typeinfo.cpp
+++ b/libcxxabi/src/private_typeinfo.cpp
@@ -53,13 +53,13 @@
 #include <atomic>
 #endif
 
-#if __ptrauth_cxxabi_has_ptrauth
+#if __has_feature(ptrauth_calls)
 #include <ptrauth.h>
 #endif
 
 template <typename T>
 static inline T* strip_vtable(T* vtable) {
-#if __ptrauth_cxxabi_has_ptrauth
+#if __has_feature(ptrauth_calls)
   vtable = ptrauth_strip(vtable, ptrauth_key_cxx_vtable_pointer);
 #endif
   return vtable;
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 1160a8a04861c..8798248395901 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -43,14 +43,10 @@
   #define LIBUNWIND_AVAIL
 #endif
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
 
   #include <ptrauth.h>
 
-  // Local "has pointer auth" macro to for backwards compatibility
-  // with compilers that do not provide the __PTRAUTH__ macro
-  #define __libunwind_has_ptrauth 1
-
   #if __has_extension(ptrauth_restricted_intptr_qualifier)
     #define __unwind_ptrauth_restricted_intptr(...) \
       __ptrauth_restricted_intptr(__VA_ARGS__)
@@ -124,9 +120,6 @@
                                        __ptrauth_unwind_cie_info_personality_disc)
 
 #else
-  // We explicitly define the not enabled case so that checks fail if they
-  // do not include the correct definitions.
-  #define __libunwind_has_ptrauth 0
 
   #define __ptrauth_unwind_upi_handler
   #define __ptrauth_unwind_upi_handler_intptr
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 5e494de10bdc2..25f0ee41feaec 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -398,7 +398,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
         pint_t personality = addressSpace.getEncodedP(
             p, cieContentEnd, cieInfo->personalityEncoding,
             /*datarelBase=*/0, &resultAddr);
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
         if (personality) {
           // The GOT for the personality function was signed address
           // authenticated. Manually re-sign with the CIE_Info::personality
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 6233d70ab6dc3..286016fad19f9 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1865,7 +1865,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   void      setSP(uint64_t value) { _registers.__sp = value; }
   uint64_t  getIP() const         {
     uint64_t value = _registers.__pc;
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
     // 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,
@@ -1877,7 +1877,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
     return value;
   }
   void      setIP(uint64_t value) {
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
     // 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.
@@ -1892,7 +1892,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   uint64_t getFP() const { return _registers.__fp; }
   void setFP(uint64_t value) { _registers.__fp = value; }
 
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
   void
   loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
                                   link_reg_t *referenceAuthedLinkRegister) {
@@ -1944,7 +1944,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   memcpy(_vectorHalfRegisters,
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
   // 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
@@ -1964,7 +1964,7 @@ inline Registers_arm64& Registers_arm64::operator=(const Registers_arm64& other)
   memcpy(&_registers, &other._registers, sizeof(_registers));
   memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
          sizeof(_vectorHalfRegisters));
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index dea7effa37631..c5371fc444995 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1051,7 +1051,7 @@ class UnwindCursor : public AbstractUnwindCursor{
                                const UnwindInfoSections &sects,
                                uint32_t fdeSectionOffsetHint = 0);
   int stepWithDwarfFDE(bool stage2) {
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
     typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
     typename R::link_reg_t pc;
     _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
@@ -1995,7 +1995,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
         personalityIndex * sizeof(uint32_t));
     pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
     personality = _addressSpace.getP(personalityPointer);
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
     // The GOT for the personality function was signed address authenticated.
     // Resign it as a regular function pointer.
     const auto discriminator =
@@ -2682,7 +2682,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
 #endif
 
   typename R::link_reg_t pc;
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
   _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
 #else
   pc = rawPC;
@@ -3237,7 +3237,7 @@ 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 __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
   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 d924a718a914d..50d270a3eb53a 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -608,7 +608,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
 
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
   // If we are in an arm64e frame, then the PC should have been signed with the
   // sp
   {
diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index a11b6dd9a1e86..5d71d2cf61ad9 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -687,7 +687,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
   ldr    x16,     [x0, #0x0F8]  // load sp into scratch
   ldr    lr,      [x0, #0x100]  // restore pc into lr
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#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
@@ -708,7 +708,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
 Lnogcs:
 #endif
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
   retab
 #else
   ret    x30                    // jump to pc
diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index 80a4692f2222e..fe3ba7842619f 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -770,7 +770,7 @@ LnoR2Fix:
   .p2align 2
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
   pacibsp
 #endif
 
@@ -815,7 +815,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 #endif
   mov    x0, #0                   // return UNW_ESUCCESS
 
-#if __has_feature(ptrauth_calls) || defined(__PTRAUTH__)
+#if __has_feature(ptrauth_calls)
   retab
 #else
   ret
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 0dce8dea49e78..90fec3027ebe0 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -128,7 +128,7 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
 
       pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
 
-#if __libunwind_has_ptrauth
+#if __has_feature(ptrauth_calls)
       // It is only valid to set the IP within the current function.
       // This is important for ptrauth, otherwise the IP cannot be correctly
       // signed.

>From 3e59382376da1ab0aa779b37f8ee849bb363c133 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Thu, 4 Sep 2025 13:00:26 -0700
Subject: [PATCH 11/28] cleanup compiler-rt formatting

---
 compiler-rt/lib/builtins/gcc_personality_v0.c | 53 ++++++++++---------
 .../vptr-corrupted-vtable-itanium.cpp         |  1 -
 2 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
index 881f119a5d453..86c8766bf71bb 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -35,11 +35,11 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
 
 #if __has_feature(ptrauth_restricted_intptr_qualifier)
 #define __ptrauth_gcc_personality_intptr(key, addressDiscriminated,            \
-                                              discriminator)                   \
+                                         discriminator)                        \
   __ptrauth_restricted_intptr(key, addressDiscriminated, discriminator)
 #else
 #define __ptrauth_gcc_personality_intptr(key, addressDiscriminated,            \
-                                              discriminator)                   \
+                                         discriminator)                        \
   __ptrauth(key, addressDiscriminated, discriminator)
 #endif
 #else
@@ -49,25 +49,30 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
 #define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer
 
 // ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB
-#define __ptrauth_gcc_personality_func_start \
-  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0xDFEB)
+#define __ptrauth_gcc_personality_func_start                                   \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1,      \
+                                   0xDFEB)
 
 // ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC
-#define __ptrauth_gcc_personality_start \
-  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0x52DC)
+#define __ptrauth_gcc_personality_start                                        \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1,      \
+                                   0x52DC)
 
 // ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7
-#define __ptrauth_gcc_personality_length \
-  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0xFFF7)
+#define __ptrauth_gcc_personality_length                                       \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1,      \
+                                   0xFFF7)
 
-// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") == 0x6498
-#define __ptrauth_gcc_personality_lpoffset \
-  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0x6498)
+// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") ==
+// 0x6498
+#define __ptrauth_gcc_personality_lpoffset                                     \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1,      \
+                                   0x6498)
 
 // ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134
 #define __ptrauth_gcc_personality_lpad_disc 0xA134
-#define __ptrauth_gcc_personality_lpad \
-  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
+#define __ptrauth_gcc_personality_lpad                                         \
+  __ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1,      \
                                    __ptrauth_gcc_personality_lpad_disc)
 
 // Pointer encodings documented at:
@@ -246,7 +251,7 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
 
   uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
   uintptr_t __ptrauth_gcc_personality_func_start funcStart =
-    (uintptr_t)_Unwind_GetRegionStart(context);
+      (uintptr_t)_Unwind_GetRegionStart(context);
   uintptr_t pcOffset = pc - funcStart;
 
   // Parse LSDA header.
@@ -266,11 +271,11 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
   const uint8_t *p = callSiteTableStart;
   while (p < callSiteTableEnd) {
     uintptr_t __ptrauth_gcc_personality_start start =
-      readEncodedPointer(&p, callSiteEncoding);
+        readEncodedPointer(&p, callSiteEncoding);
     size_t __ptrauth_gcc_personality_length length =
-      readEncodedPointer(&p, callSiteEncoding);
+        readEncodedPointer(&p, callSiteEncoding);
     size_t __ptrauth_gcc_personality_lpoffset landingPadOffset =
-      readEncodedPointer(&p, callSiteEncoding);
+        readEncodedPointer(&p, callSiteEncoding);
     readULEB128(&p); // action value not used for C code
     if (landingPadOffset == 0)
       continue; // no landing pad for this entry
@@ -286,20 +291,16 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
           funcStart + landingPadOffset;
 #if __has_feature(ptrauth_calls)
       uintptr_t stackPointer = _Unwind_GetGR(context, -2);
-      const uintptr_t existingDiscriminator =
-        ptrauth_blend_discriminator(&landingPad,
-                                    __ptrauth_gcc_personality_lpad_disc);
+      const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
+          &landingPad, __ptrauth_gcc_personality_lpad_disc);
       // newIP is authenticated as if it were qualified with a pseudo qualifier
       // along the lines of:
       //   __ptrauth(ptrauth_key_return_address, <stackPointer>, 0)
       // where the stack pointer is used in place of the strict storage
       // address.
-      uintptr_t newIP =
-        (uintptr_t)ptrauth_auth_and_resign(*(void **)&landingPad,
-                                           __ptrauth_gcc_personality_func_key,
-                                           existingDiscriminator,
-                                           ptrauth_key_return_address,
-                                           stackPointer);
+      uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
+          *(void **)&landingPad, __ptrauth_gcc_personality_func_key,
+          existingDiscriminator, ptrauth_key_return_address, stackPointer);
       _Unwind_SetIP(context, newIP);
 #else
       _Unwind_SetIP(context, landingPad);
diff --git a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
index b955cff7fcbf8..9c47b69dbb6aa 100644
--- a/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
+++ b/compiler-rt/test/ubsan/TestCases/TypeCheck/vptr-corrupted-vtable-itanium.cpp
@@ -8,7 +8,6 @@
 
 #if __has_feature(ptrauth_calls)
 #include <ptrauth.h>
-#else
 #endif
 
 struct S {

>From ef030712e047cb7840578d00909159eb2446baab Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Thu, 4 Sep 2025 13:05:55 -0700
Subject: [PATCH 12/28] update libcxxabi formatting

---
 libcxxabi/include/__cxxabi_config.h | 21 ++++------
 libcxxabi/src/cxa_exception.cpp     |  2 +-
 libcxxabi/src/cxa_exception.h       |  6 +--
 libcxxabi/src/cxa_personality.cpp   | 60 +++++++++++++----------------
 4 files changed, 36 insertions(+), 53 deletions(-)

diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 672926ecec930..51b821241f162 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -110,32 +110,25 @@
 #if __has_feature(ptrauth_calls)
 
 // ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
-#  define __ptrauth_cxxabi_action_record \
-            __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFC91)
+#  define __ptrauth_cxxabi_action_record __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFC91)
 
 // ptrauth_string_discriminator("__cxa_exception::languageSpecificData") == 0xE8EE
-#  define __ptrauth_cxxabi_lsd \
-            __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)
+#  define __ptrauth_cxxabi_lsd __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)
 
 // ptrauth_string_discriminator("__cxa_exception::catchTemp") == 0xFA58
-#  define __ptrauth_cxxabi_catch_temp \
-            __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFA58)
+#  define __ptrauth_cxxabi_catch_temp __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFA58)
 
 // ptrauth_string_discriminator("__cxa_exception::adjustedPtr") == 0x99E4
-#  define __ptrauth_cxxabi_adjusted_ptr \
-            __ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)
+#  define __ptrauth_cxxabi_adjusted_ptr __ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)
 
 // ptrauth_string_discriminator("__cxa_exception::unexpectedHandler") == 0x99A9
-#  define __ptrauth_cxxabi_unexpected_handler \
-            __ptrauth(ptrauth_key_function_pointer, 1, 0x99A9)
+#  define __ptrauth_cxxabi_unexpected_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x99A9)
 
 // ptrauth_string_discriminator("__cxa_exception::terminateHandler") == 0x0886)
-#  define __ptrauth_cxxabi_terminate_handler \
-            __ptrauth(ptrauth_key_function_pointer, 1, 0x886)
+#  define __ptrauth_cxxabi_terminate_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x886)
 
 // ptrauth_string_discriminator("__cxa_exception::exceptionDestructor") == 0xC088
-#  define __ptrauth_cxxabi_exception_destructor \
-            __ptrauth(ptrauth_key_function_pointer, 1, 0xC088)
+#  define __ptrauth_cxxabi_exception_destructor __ptrauth(ptrauth_key_function_pointer, 1, 0xC088)
 
 #else
 
diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp
index 8a77e8c1230a7..73ba21c1df7c1 100644
--- a/libcxxabi/src/cxa_exception.cpp
+++ b/libcxxabi/src/cxa_exception.cpp
@@ -194,7 +194,7 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
         static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
     // We warn on memset to a non-trivially castable type. We might want to
     // change that diagnostic to not fire on a trivially obvious zero fill.
-    ::memset(static_cast<void *>(exception_header), 0, actual_size);
+    ::memset(static_cast<void*>(exception_header), 0, actual_size);
     return thrown_object_from_cxa_exception(exception_header);
 }
 
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index 97be422cc60bb..aa8969e596ca2 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,8 +47,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void (_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
-             exceptionDestructor)(void*);
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
 #endif
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
@@ -89,8 +88,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void (_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
-             exceptionDestructor)(void*);
+    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
 
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index e3c8e7b6847da..81ad3a073b5c3 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -25,45 +25,40 @@
 
 // CXXABI depends on defintions in libunwind as pointer auth couples the
 // definitions
-#include "libunwind.h"
+#  include "libunwind.h"
 
 // The actual value of the discriminators listed below is not important.
 // The derivation of the constants is only being included for the purpose
 // of maintaining a record of how they were originally produced.
 
 // ptrauth_string_discriminator("scan_results::languageSpecificData") == 0xE50D)
-#define __ptrauth_scan_results_lsd \
-  __ptrauth(ptrauth_key_process_dependent_code, 1, 0xE50D)
+#  define __ptrauth_scan_results_lsd __ptrauth(ptrauth_key_process_dependent_code, 1, 0xE50D)
 
 // ptrauth_string_discriminator("scan_results::actionRecord") == 0x9823
-#define __ptrauth_scan_results_action_record \
-  __ptrauth(ptrauth_key_process_dependent_code, 1, 0x9823)
+#  define __ptrauth_scan_results_action_record __ptrauth(ptrauth_key_process_dependent_code, 1, 0x9823)
 
 // scan result is broken up as we have a manual re-sign that requires each component
-#define __ptrauth_scan_results_landingpad_key ptrauth_key_process_dependent_code
+#  define __ptrauth_scan_results_landingpad_key ptrauth_key_process_dependent_code
 // ptrauth_string_discriminator("scan_results::landingPad") == 0xD27C
-#define __ptrauth_scan_results_landingpad_disc 0xD27C
-#define __ptrauth_scan_results_landingpad \
-   __ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
-
-#if __has_extension(__ptrauth_restricted_intptr)
-#define __ptrauth_scan_results_landingpad_intptr \
-   __ptrauth_restricted_intptr(__ptrauth_scan_results_landingpad_key, 1, \
-                               __ptrauth_scan_results_landingpad_disc)
-#else
-#define __ptrauth_scan_results_landingpad_intptr \
-   __ptrauth(__ptrauth_scan_results_landingpad_key, 1, \
-             __ptrauth_scan_results_landingpad_disc)
-#endif
+#  define __ptrauth_scan_results_landingpad_disc 0xD27C
+#  define __ptrauth_scan_results_landingpad                                                                            \
+    __ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
+
+#  if __has_extension(__ptrauth_restricted_intptr)
+#    define __ptrauth_scan_results_landingpad_intptr                                                                   \
+      __ptrauth_restricted_intptr(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
+#  else
+#    define __ptrauth_scan_results_landingpad_intptr                                                                   \
+      __ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
+#  endif
 
 #else
-#define __ptrauth_scan_results_lsd
-#define __ptrauth_scan_results_action_record
-#define __ptrauth_scan_results_landingpad
-#define __ptrauth_scan_results_landingpad_intptr
+#  define __ptrauth_scan_results_lsd
+#  define __ptrauth_scan_results_action_record
+#  define __ptrauth_scan_results_landingpad
+#  define __ptrauth_scan_results_landingpad_intptr
 #endif
 
-
 // TODO: This is a temporary workaround for libc++abi to recognize that it's being
 // built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION
 // in LLVM 15 -- we can remove this workaround after shipping LLVM 17. Once we remove
@@ -577,9 +572,9 @@ typedef void* __ptrauth_scan_results_landingpad landing_pad_ptr_t;
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
-    action_ptr_t   actionRecord; // Currently unused.  Retained to ease future maintenance.
-    lsd_ptr_t      languageSpecificData; // Needed only for __cxa_call_unexpected
-    landing_pad_t  landingPad;   // null -> nothing found, else something found
+    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future maintenance.
+    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t landingPad;       // null -> nothing found, else something found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -634,14 +629,11 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
   auto stackPointer = _Unwind_GetGR(context, UNW_REG_SP);
   // We manually re-sign the IP as the __ptrauth qualifiers cannot
   // express the required relationship with the destination address
-  const auto existingDiscriminator = ptrauth_blend_discriminator(
-      &results.landingPad, __ptrauth_scan_results_landingpad_disc);
+  const auto existingDiscriminator =
+      ptrauth_blend_discriminator(&results.landingPad, __ptrauth_scan_results_landingpad_disc);
   unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stackPointer, 0) */ =
-      (unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad,
-                                          __ptrauth_scan_results_landingpad_key,
-                                          existingDiscriminator,
-                                          ptrauth_key_return_address,
-                                          stackPointer);
+      (unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad, __ptrauth_scan_results_landingpad_key,
+                                          existingDiscriminator, ptrauth_key_return_address, stackPointer);
   _Unwind_SetIP(context, newIP);
 #else
   _Unwind_SetIP(context, results.landingPad);

>From 5b832beb1fa762f471b9ac36b3bd76ce3b728db3 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sat, 27 Sep 2025 15:52:34 -0700
Subject: [PATCH 13/28] Just make this a release mode failure

---
 libunwind/src/libunwind.cpp | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 90fec3027ebe0..b21699dd7f50a 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -129,14 +129,28 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
       pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
 
 #if __has_feature(ptrauth_calls)
-      // It is only valid to set the IP within the current function.
-      // This is important for ptrauth, otherwise the IP cannot be correctly
-      // signed.
-      [[maybe_unused]]unw_word_t stripped_value =
-          (unw_word_t)ptrauth_strip((void *)value, ptrauth_key_return_address);
-      assert(stripped_value >= info.start_ip && stripped_value <= info.end_ip);
-
       {
+        // It is only valid to set the IP within the current function.
+        // This is important for ptrauth, otherwise the IP cannot be correctly
+        // signed.
+        // We re-sign to a more usable form and then use it directly.
+        union {
+          unw_word_t opaque_value;
+          unw_word_t
+            __unwind_ptrauth_restricted_intptr(ptrauth_key_return_address, 1, 0)
+            authenticated_value;
+        } u;
+        u.opaque_value = (uint64_t)ptrauth_auth_and_resign(
+          (void *)value,
+          ptrauth_key_return_address,
+          getSP(),
+          ptrauth_key_return_address,
+          &u.opaque_value);
+
+        if (u.authenticated_value < info.start_ip ||
+            u.authenticated_value > info.end_ip)
+          _LIBUNWIND_ABORT("PC vs frame info mismatch");
+
         // PC should have been signed with the sp, so we verify that
         // roundtripping does not fail.
         pint_t pc = (pint_t)co->getReg(UNW_REG_IP);

>From 49a011100bd22479a337fca2cf45beaeee8e8ad0 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sat, 27 Sep 2025 17:42:43 -0700
Subject: [PATCH 14/28] Address comments

---
 .../lib/sanitizer_common/sanitizer_ptrauth.h  |  2 +-
 libcxxabi/src/cxa_exception.h                 | 20 +++++++++----------
 libcxxabi/src/cxa_personality.cpp             | 15 +++++++++-----
 libunwind/include/libunwind.h                 |  4 +++-
 libunwind/src/CompactUnwinder.hpp             | 10 +++-------
 libunwind/src/DwarfInstructions.hpp           | 16 +++++++--------
 libunwind/src/DwarfParser.hpp                 |  6 ++++++
 7 files changed, 41 insertions(+), 32 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
index 8c3c063d7948e..265a9925a15a0 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h
@@ -9,7 +9,7 @@
 #ifndef SANITIZER_PTRAUTH_H
 #define SANITIZER_PTRAUTH_H
 
-#if __has_feature(ptrauth_calls)
+#if __has_feature(ptrauth_intrinsics)
 #  include <ptrauth.h>
 #elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
 // On the stack the link register is protected with Pointer
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index aa8969e596ca2..1c84f75262758 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,7 +47,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
+    void(_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
 #endif
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
@@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
-    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
-    void* __ptrauth_cxxabi_catch_temp catchTemp;
-    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
+    const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
+    void *__ptrauth_cxxabi_catch_temp catchTemp;
+    void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -88,7 +88,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
+    void(_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
 
@@ -102,10 +102,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #else
     int handlerSwitchValue;
 
-    const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
-    const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
-    void* __ptrauth_cxxabi_catch_temp catchTemp;
-    void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
+    const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
+    const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
+    void *__ptrauth_cxxabi_catch_temp catchTemp;
+    void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
 #endif
 
 #if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 81ad3a073b5c3..4d2c13a15ecac 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -564,10 +564,10 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
 namespace
 {
 
-typedef const uint8_t* __ptrauth_scan_results_lsd lsd_ptr_t;
-typedef const uint8_t* __ptrauth_scan_results_action_record action_ptr_t;
+typedef const uint8_t *__ptrauth_scan_results_lsd lsd_ptr_t;
+typedef const uint8_t *__ptrauth_scan_results_action_record action_ptr_t;
 typedef uintptr_t __ptrauth_scan_results_landingpad_intptr landing_pad_t;
-typedef void* __ptrauth_scan_results_landingpad landing_pad_ptr_t;
+typedef void *__ptrauth_scan_results_landingpad landing_pad_ptr_t;
 
 struct scan_results
 {
@@ -585,12 +585,16 @@ struct scan_results
 }  // unnamed namespace
 } // extern "C"
 
+#if !defined(_LIBCXXABI_ARM_EHABI)
 namespace {
 // The logical model for casting authenticated function pointers makes
 // it impossible to directly cast them without breaking the authentication,
 // as a result we need this pair of helpers.
+//
+// __ptrauth_nop_cast cannot be used here as the authentication schemas include
+// address diversification.
 template <typename PtrType>
-[[maybe_unused]] void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
+void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
   union {
     landing_pad_t* as_landing_pad;
     landing_pad_ptr_t* as_pointer;
@@ -599,7 +603,7 @@ template <typename PtrType>
   *u.as_pointer = out;
 }
 
-[[maybe_unused]] static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
+static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
   union {
     const landing_pad_t* as_landing_pad;
     const landing_pad_ptr_t* as_pointer;
@@ -608,6 +612,7 @@ template <typename PtrType>
   return *u.as_pointer;
 }
 } // unnamed namespace
+#endif
 
 extern "C" {
 static
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 8798248395901..5d5b583bbb072 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -119,6 +119,9 @@
     __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \
                                        __ptrauth_unwind_cie_info_personality_disc)
 
+// ptrauth_string_discriminator("personality") == 0x7EAD)
+  #define __ptrauth_unwind_pacret_personality_disc 0x7EAD
+
 #else
 
   #define __ptrauth_unwind_upi_handler
@@ -136,7 +139,6 @@
   #define __ptrauth_unwind_uis_compact_unwind_section
   #define __ptrauth_unwind_uis_compact_unwind_section_length
   #define __ptrauth_unwind_cie_info_personality
-
 #endif
 
 #if defined(_WIN32) && defined(__SEH__)
diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp
index 272352ab63e84..041fa8ae2b296 100644
--- a/libunwind/src/CompactUnwinder.hpp
+++ b/libunwind/src/CompactUnwinder.hpp
@@ -683,17 +683,13 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
   }
 
   Registers_arm64::reg_t fp = registers.getFP();
-  // fp points to old fp
-  registers.setFP(addressSpace.get64(fp));
 
-  // old sp is fp less saved fp and lr. Set this before FP & LR because in
-  // arm64e it's the discriminator used for those registers.
+  // old sp is fp less saved fp and lr. Set this before LR because in arm64e
+  // it's the authentication discriminator.
   registers.setSP(fp + 16);
 
-  Registers_arm64::reg_t oldfp = addressSpace.get64(fp);
-
   // fp points to old fp
-  registers.setFP(oldfp);
+  registers.setFP(addressSpace.get64(fp));
 
   // pop return address into pc
   registers.setIP(addressSpace.get64(fp + 8));
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index b34d9d77b9ee5..5370fe0fa52cd 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -63,7 +63,7 @@ class DwarfInstructions {
                                   pint_t cfa, const RegisterLocation &savedReg);
 
   static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
-                       R &registers) {
+                       const R &registers) {
     if (prolog.cfaRegister != 0) {
       uintptr_t cfaRegister = registers.getRegister((int)prolog.cfaRegister);
       return (pint_t)(cfaRegister + prolog.cfaRegisterOffset);
@@ -209,7 +209,7 @@ bool DwarfInstructions<A, R>::isReturnAddressSignedWithPC(A &addressSpace,
 
 template <typename A, typename R>
 int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
-                                           typename R::link_reg_t &pc,
+                                           const typename R::link_reg_t &pc,
                                            pint_t fdeStart, R &registers,
                                            bool &isSignalFrame, bool stage2) {
   FDE_Info fdeInfo;
@@ -302,12 +302,12 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
 
       isSignalFrame = cieInfo.isSignalFrame;
 
-#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 defined(__ARM64E__)
+      // If the target is using the arm64e ABI then the return address has
+      // been signed using the stack pointer as a diversifier. The original
+      // return address needs to be authenticated before the it 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) &&
           returnAddress != 0) {
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 25f0ee41feaec..fe200307d013f 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -405,6 +405,12 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
           // schema. If we could guarantee the encoding of the personality we
           // could avoid this by simply giving resultAddr the correct ptrauth
           // schema and performing an assignment.
+#ifdef __ARM64E__
+          const auto oldDiscriminator = resultAddr;
+#else
+          const auto oldDiscriminator = ptrauth_blend_discriminator(
+              (void*)resultAddr, __ptrauth_unwind_pacret_personality_disc);
+#endif
           const auto discriminator = ptrauth_blend_discriminator(
               &cieInfo->personality, __ptrauth_unwind_cie_info_personality_disc);
           void *signedPtr = ptrauth_auth_and_resign(

>From fc1375a44d15b70461ab317e0d989f749d7ccb8d Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sat, 27 Sep 2025 19:20:34 -0700
Subject: [PATCH 15/28] Sigh, actually make sure it builds, also address
 warnings

---
 libunwind/src/DwarfInstructions.hpp |  2 +-
 libunwind/src/DwarfParser.hpp       |  9 +++++----
 libunwind/src/Registers.hpp         | 13 +++++++------
 libunwind/src/UnwindCursor.hpp      | 18 ++++++++----------
 libunwind/src/UnwindLevel1.c        |  5 ++---
 libunwind/src/libunwind.cpp         | 14 +++++---------
 6 files changed, 28 insertions(+), 33 deletions(-)

diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index 5370fe0fa52cd..f80286252613d 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -33,7 +33,7 @@ class DwarfInstructions {
   typedef typename A::pint_t pint_t;
   typedef typename A::sint_t sint_t;
 
-  static int stepWithDwarf(A &addressSpace, typename R::link_reg_t &pc,
+  static int stepWithDwarf(A &addressSpace, const typename R::link_reg_t &pc,
                            pint_t fdeStart, R &registers, bool &isSignalFrame,
                            bool stage2);
 
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index fe200307d013f..cca3ae0ccb515 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -409,13 +409,14 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
           const auto oldDiscriminator = resultAddr;
 #else
           const auto oldDiscriminator = ptrauth_blend_discriminator(
-              (void*)resultAddr, __ptrauth_unwind_pacret_personality_disc);
+              (void *)resultAddr, __ptrauth_unwind_pacret_personality_disc);
 #endif
           const auto discriminator = ptrauth_blend_discriminator(
-              &cieInfo->personality, __ptrauth_unwind_cie_info_personality_disc);
+              &cieInfo->personality,
+              __ptrauth_unwind_cie_info_personality_disc);
           void *signedPtr = ptrauth_auth_and_resign(
-              (void *)personality, ptrauth_key_function_pointer, resultAddr,
-              ptrauth_key_function_pointer, discriminator);
+              (void *)personality, ptrauth_key_function_pointer,
+              oldDiscriminator, ptrauth_key_function_pointer, discriminator);
           personality = (pint_t)signedPtr;
         }
 #endif
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 286016fad19f9..adbab66877a25 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -17,8 +17,8 @@
 
 #include "config.h"
 #include "libunwind.h"
-#include "shadow_stack_unwind.h"
 #include "libunwind_ext.h"
+#include "shadow_stack_unwind.h"
 
 namespace libunwind {
 
@@ -1839,8 +1839,8 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
 public:
   Registers_arm64();
   Registers_arm64(const void *registers);
-  Registers_arm64(const Registers_arm64&);
-  Registers_arm64& operator=(const Registers_arm64&);
+  Registers_arm64(const Registers_arm64 &);
+  Registers_arm64 &operator=(const Registers_arm64 &);
 
   typedef uint64_t reg_t;
   typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t;
@@ -1863,7 +1863,7 @@ 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 __has_feature(ptrauth_calls)
     // Note the value of the PC was signed to its address in the register state
@@ -1956,11 +1956,12 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
 #endif
 }
 
-inline Registers_arm64::Registers_arm64(const Registers_arm64& other) {
+inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
   *this = other;
 }
 
-inline Registers_arm64& Registers_arm64::operator=(const Registers_arm64& other) {
+inline Registers_arm64 &
+Registers_arm64::operator=(const Registers_arm64 &other) {
   memcpy(&_registers, &other._registers, sizeof(_registers));
   memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
          sizeof(_vectorHalfRegisters));
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index c5371fc444995..b02ef5f330db3 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1367,13 +1367,13 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
                 "UnwindCursor<> does not fit in unw_cursor_t");
   static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
                 "UnwindCursor<> requires more alignment than unw_cursor_t");
-  memset(&_info, 0, sizeof(_info));
+  memset(static_cast<void *>(&_info), 0, sizeof(_info));
 }
 
 template <typename A, typename R>
 UnwindCursor<A, R>::UnwindCursor(A &as, void *)
     : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
-  memset(&_info, 0, sizeof(_info));
+  memset(static_cast<void *>(&_info), 0, sizeof(_info));
   // FIXME
   // fill in _registers from thread arg
 }
@@ -1998,13 +1998,11 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
 #if __has_feature(ptrauth_calls)
     // The GOT for the personality function was signed address authenticated.
     // Resign it as a regular function pointer.
-    const auto discriminator =
-      ptrauth_blend_discriminator(&_info.handler,
-                                  __ptrauth_unwind_upi_handler_disc);
-    void *signedPtr =
-      ptrauth_auth_and_resign((void *)personality, ptrauth_key_function_pointer,
-                              personalityPointer, ptrauth_key_function_pointer,
-                              discriminator);
+    const auto discriminator = ptrauth_blend_discriminator(
+        &_info.handler, __ptrauth_unwind_upi_handler_disc);
+    void *signedPtr = ptrauth_auth_and_resign(
+        (void *)personality, ptrauth_key_function_pointer, personalityPointer,
+        ptrauth_key_function_pointer, discriminator);
     personality = (__typeof(personality))signedPtr;
 #endif
     if (log)
@@ -3229,7 +3227,7 @@ template <typename A, typename R> int UnwindCursor<A, R>::step(bool stage2) {
 template <typename A, typename R>
 void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
   if (_unwindInfoMissing)
-    memset(info, 0, sizeof(*info));
+    memset(static_cast<void *>(info), 0, sizeof(*info));
   else
     *info = _info;
 }
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index 50d270a3eb53a..eab2920f6749f 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -96,8 +96,7 @@
 static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
   union {
     void *opaque_handler;
-    _Unwind_Personality_Fn __ptrauth_unwind_upi_handler *
-        handler;
+    _Unwind_Personality_Fn __ptrauth_unwind_upi_handler *handler;
   } u;
   u.opaque_handler = (void *)&frameInfo->handler;
   return *u.handler;
@@ -608,7 +607,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
 
-#if __has_feature(ptrauth_calls)
+#if defined(__ARM64E__)
   // If we are in an arm64e frame, then the PC should have been signed with the
   // sp
   {
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index b21699dd7f50a..41f92aaba2a0b 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -15,7 +15,6 @@
 #include "libunwind_ext.h"
 
 #include <stdlib.h>
-#include <sys/types.h>
 
 // Define the __has_feature extension for compilers that do not support it so
 // that we can later check for the presence of ASan in a compiler-neutral way.
@@ -137,15 +136,12 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
         union {
           unw_word_t opaque_value;
           unw_word_t
-            __unwind_ptrauth_restricted_intptr(ptrauth_key_return_address, 1, 0)
-            authenticated_value;
+              __unwind_ptrauth_restricted_intptr(ptrauth_key_return_address, 1,
+                                                 0) authenticated_value;
         } u;
         u.opaque_value = (uint64_t)ptrauth_auth_and_resign(
-          (void *)value,
-          ptrauth_key_return_address,
-          getSP(),
-          ptrauth_key_return_address,
-          &u.opaque_value);
+            (void *)value, ptrauth_key_return_address, sp,
+            ptrauth_key_return_address, &u.opaque_value);
 
         if (u.authenticated_value < info.start_ip ||
             u.authenticated_value > info.end_ip)
@@ -157,7 +153,7 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
         if (ptrauth_auth_and_resign((void *)pc, ptrauth_key_return_address, sp,
                                     ptrauth_key_return_address,
                                     sp) != (void *)pc) {
-          _LIBUNWIND_LOG("Bad unwind through arm64e (0x%llX, 0x%llX)->0x%llX\n",
+          _LIBUNWIND_LOG("Bad unwind through arm64e (0x%zX, 0x%zX)->0x%zX\n",
                          pc, sp,
                          (pint_t)ptrauth_auth_data(
                              (void *)pc, ptrauth_key_return_address, sp));

>From 782cbdb961b889c9b1244fd710e2bc51cc501fbd Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Mon, 29 Sep 2025 17:13:51 -0700
Subject: [PATCH 16/28] Updating for feedback

---
 libcxxabi/src/cxa_exception.h          |  4 ++--
 libunwind/include/__libunwind_config.h |  5 +++++
 libunwind/src/DwarfInstructions.hpp    | 21 +++++++++++++++------
 3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index 1c84f75262758..2eb77d8612788 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -47,7 +47,7 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
     // In Wasm, a destructor returns its argument
     void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
 #else
-    void(_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
+    void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
 #endif
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
@@ -88,7 +88,7 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #endif
 
     std::type_info *exceptionType;
-    void(_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void*);
+    void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
     std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
     std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
 
diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 544b3ec96216a..1e5232392de79 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -73,6 +73,11 @@
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
 # elif defined(__aarch64__)
 #  define _LIBUNWIND_TARGET_AARCH64 1
+#  if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
+#    define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
+#  elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
+#    #error "Either both or none of ptrauth_calls and ptrauth_returns is allowed to be enabled"
+#  endif
 #define _LIBUNWIND_CONTEXT_SIZE 67
 #  if defined(__SEH__)
 #    define _LIBUNWIND_CURSOR_SIZE 164
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index f80286252613d..d9fa76c57da47 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -302,12 +302,21 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
 
       isSignalFrame = cieInfo.isSignalFrame;
 
-#if defined(__ARM64E__)
-      // If the target is using the arm64e ABI then the return address has
-      // been signed using the stack pointer as a diversifier. The original
-      // return address needs to be authenticated before the it is restored.
-      // autia1716 is used instead of autia as autia1716 assembles to a NOP on
-      // pre-v8.3a architectures.
+#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 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) &&
           returnAddress != 0) {

>From 34555e79ba8c8a946d1407d99c91b74c25f9f36a Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 30 Sep 2025 13:21:32 -0700
Subject: [PATCH 17/28] whoops, wrong test

---
 libcxxabi/src/cxa_personality.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 4d2c13a15ecac..14e6f4b07461d 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -44,7 +44,7 @@
 #  define __ptrauth_scan_results_landingpad                                                                            \
     __ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
 
-#  if __has_extension(__ptrauth_restricted_intptr)
+#  if __has_extension(ptrauth_restricted_intptr_qualifier)
 #    define __ptrauth_scan_results_landingpad_intptr                                                                   \
       __ptrauth_restricted_intptr(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
 #  else

>From d70e80219a05ecf1d07ca812a5a085c44f653555 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Thu, 2 Oct 2025 18:34:58 -0700
Subject: [PATCH 18/28] You would not believe how long it took to find this

---
 libunwind/src/DwarfParser.hpp | 2 +-
 libunwind/src/UnwindLevel1.c  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index cca3ae0ccb515..b6c9447ad2bec 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -405,7 +405,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
           // schema. If we could guarantee the encoding of the personality we
           // could avoid this by simply giving resultAddr the correct ptrauth
           // schema and performing an assignment.
-#ifdef __ARM64E__
+#if defined(__arm64e__)
           const auto oldDiscriminator = resultAddr;
 #else
           const auto oldDiscriminator = ptrauth_blend_discriminator(
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index eab2920f6749f..eee22eb628611 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -607,7 +607,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
 
-#if defined(__ARM64E__)
+#if defined(__arm64e__)
   // If we are in an arm64e frame, then the PC should have been signed with the
   // sp
   {

>From 7192221c69ff2ad79131fa759889be0d251ed5b7 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 7 Oct 2025 15:55:32 -0700
Subject: [PATCH 19/28] Addressing some feedback

* Add note for `__ptrauth_restricted_intptr`
* Rename confusing parameter in set_landing_pad_as_ptr
* Rename __ptrauth_unwind_pacret_personality_disc to
  __ptrauth_unwind_pauthtest_personality_disc
---
 compiler-rt/lib/builtins/gcc_personality_v0.c |  3 ++
 libcxxabi/src/cxa_personality.cpp             |  7 ++--
 libunwind/include/libunwind.h                 | 35 ++++++++++---------
 libunwind/src/DwarfParser.hpp                 |  2 +-
 libunwind/src/UnwindLevel1.c                  |  2 +-
 5 files changed, 29 insertions(+), 20 deletions(-)

diff --git a/compiler-rt/lib/builtins/gcc_personality_v0.c b/compiler-rt/lib/builtins/gcc_personality_v0.c
index 86c8766bf71bb..3ed17fa788c28 100644
--- a/compiler-rt/lib/builtins/gcc_personality_v0.c
+++ b/compiler-rt/lib/builtins/gcc_personality_v0.c
@@ -33,6 +33,9 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
 #if __has_feature(ptrauth_calls)
 #include <ptrauth.h>
 
+// `__ptrauth_restricted_intptr` is a feature of apple clang that predates
+// support for direct application of `__ptrauth` to integer types. This
+// guard is necessary to support compilation with those compiler.
 #if __has_feature(ptrauth_restricted_intptr_qualifier)
 #define __ptrauth_gcc_personality_intptr(key, addressDiscriminated,            \
                                          discriminator)                        \
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index 14e6f4b07461d..c98de92db152e 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -44,6 +44,9 @@
 #  define __ptrauth_scan_results_landingpad                                                                            \
     __ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
 
+// `__ptrauth_restricted_intptr` is a feature of apple clang that predates
+// support for direct application of `__ptrauth` to integer types. This
+// guard is necessary to support compilation with those compiler.
 #  if __has_extension(ptrauth_restricted_intptr_qualifier)
 #    define __ptrauth_scan_results_landingpad_intptr                                                                   \
       __ptrauth_restricted_intptr(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc)
@@ -594,13 +597,13 @@ namespace {
 // __ptrauth_nop_cast cannot be used here as the authentication schemas include
 // address diversification.
 template <typename PtrType>
-void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) {
+void set_landing_pad_as_ptr(scan_results& results, const PtrType& landingPad) {
   union {
     landing_pad_t* as_landing_pad;
     landing_pad_ptr_t* as_pointer;
   } u;
   u.as_landing_pad = &results.landingPad;
-  *u.as_pointer = out;
+  *u.as_pointer = landingPad;
 }
 
 static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 5d5b583bbb072..49adadd44f076 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -47,6 +47,9 @@
 
   #include <ptrauth.h>
 
+  // `__ptrauth_restricted_intptr` is a feature of apple clang that predates
+  // support for direct application of `__ptrauth` to integer types. This
+  // guard is necessary to support compilation with those compiler.
   #if __has_extension(ptrauth_restricted_intptr_qualifier)
     #define __unwind_ptrauth_restricted_intptr(...) \
       __ptrauth_restricted_intptr(__VA_ARGS__)
@@ -55,7 +58,7 @@
       __ptrauth(__VA_ARGS__)
   #endif
 
-// ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
+  // ptrauth_string_discriminator("unw_proc_info_t::handler") == 0x7405
   #define __ptrauth_unwind_upi_handler_disc 0x7405
 
   #define __ptrauth_unwind_upi_handler \
@@ -65,62 +68,62 @@
     __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1,\
                                        __ptrauth_unwind_upi_handler_disc)
 
-// ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
+  // ptrauth_string_discriminator("unw_proc_info_t::start_ip") == 0xCA2C
   #define __ptrauth_unwind_upi_startip \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xCA2C)
 
-// ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
+  // ptrauth_string_discriminator("unw_proc_info_t::end_ip") == 0xE183
   #define __ptrauth_unwind_upi_endip \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_independent_code, 1, 0xE183)
 
-// ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
+  // ptrauth_string_discriminator("unw_proc_info_t::lsda") == 0x83DE
   #define __ptrauth_unwind_upi_lsda \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x83DE)
 
-// ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
+  // ptrauth_string_discriminator("unw_proc_info_t::flags") == 0x79A1
   #define __ptrauth_unwind_upi_flags \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x79A1)
 
-// ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
+  // ptrauth_string_discriminator("unw_proc_info_t::unwind_info") == 0xC20C
   #define __ptrauth_unwind_upi_info \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xC20C)
 
-// ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
+  // ptrauth_string_discriminator("unw_proc_info_t::extra") == 0x03DF
   #define __ptrauth_unwind_upi_extra \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x03DF)
 
-// ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
+  // ptrauth_string_discriminator("Registers_arm64::link_reg_t") == 0x8301
   #define __ptrauth_unwind_registers_arm64_link_reg \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_code, 1, 0x8301)
 
-// ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
+  // ptrauth_string_discriminator("UnwindInfoSections::dso_base") == 0x4FF5
   #define __ptrauth_unwind_uis_dso_base \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4FF5)
 
-// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
+  // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section") == 0x4974
   #define __ptrauth_unwind_uis_dwarf_section \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x4974)
 
-// ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A
+  // ptrauth_string_discriminator("UnwindInfoSections::dwarf_section_length") == 0x2A9A
   #define __ptrauth_unwind_uis_dwarf_section_length \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x2A9A)
 
-// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B
+  // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section") == 0xA27B
   #define __ptrauth_unwind_uis_compact_unwind_section \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0xA27B)
 
-// ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A
+  // ptrauth_string_discriminator("UnwindInfoSections::compact_unwind_section_length") == 0x5D0A
   #define __ptrauth_unwind_uis_compact_unwind_section_length \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_process_dependent_data, 1, 0x5D0A)
 
-// ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
+  // ptrauth_string_discriminator("CIE_Info::personality") == 0x6A40
   #define __ptrauth_unwind_cie_info_personality_disc 0x6A40
   #define __ptrauth_unwind_cie_info_personality \
     __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 1, \
                                        __ptrauth_unwind_cie_info_personality_disc)
 
-// ptrauth_string_discriminator("personality") == 0x7EAD)
-  #define __ptrauth_unwind_pacret_personality_disc 0x7EAD
+  // ptrauth_string_discriminator("personality") == 0x7EAD)
+  #define __ptrauth_unwind_pauthtest_personality_disc 0x7EAD
 
 #else
 
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index b6c9447ad2bec..026919b4e1cb2 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -409,7 +409,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
           const auto oldDiscriminator = resultAddr;
 #else
           const auto oldDiscriminator = ptrauth_blend_discriminator(
-              (void *)resultAddr, __ptrauth_unwind_pacret_personality_disc);
+              (void *)resultAddr, __ptrauth_unwind_pauthtest_personality_disc);
 #endif
           const auto discriminator = ptrauth_blend_discriminator(
               &cieInfo->personality,
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index eee22eb628611..a67f5a9d9d2e1 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -607,7 +607,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
   unw_word_t result;
   __unw_get_reg(cursor, UNW_REG_IP, &result);
 
-#if defined(__arm64e__)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   // If we are in an arm64e frame, then the PC should have been signed with the
   // sp
   {

>From 0d482fae39dcadc0c4c491dc6d74bee62be63f30 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 7 Oct 2025 18:34:50 -0700
Subject: [PATCH 20/28] cleaning up the [ab]use of unions

---
 libunwind/src/UnwindLevel1.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index a67f5a9d9d2e1..6c560773ce62f 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -94,12 +94,30 @@
 // integer and an authenticated function pointer, so we need this helper
 // function to keep things clean.
 static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
-  union {
-    void *opaque_handler;
-    _Unwind_Personality_Fn __ptrauth_unwind_upi_handler *handler;
-  } u;
-  u.opaque_handler = (void *)&frameInfo->handler;
-  return *u.handler;
+  // Converting from an authenticated integer to a _Unwind_Personality_Fn
+  // requires multiple steps, but as the schema of _Unwind_Personality_Fn is
+  // not address diversified we can mostly just rely on automatic re-signing
+  // by clang.
+
+  // Step 1. Assign from the address diversified integer in frameInfo->handler
+  //         to the non-address diversified schema of `_Unwind_Personality_Fn`
+  uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer,
+                                               0,
+                                               ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
+    reauthenticatedIntegerHandler = frameInfo->handler;
+
+  // Step 2. Memcpy from our re-signed integer typed handler to an
+  //         _Unwind_Personality_Fn typed local - this avoids any confused
+  //         re-signing of values that already have a signature.
+  _Unwind_Personality_Fn handler;
+  uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 0,
+                  ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
+                  f;
+  memcpy(&handler, (void *)&reauthenticatedIntegerHandler,
+         sizeof(_Unwind_Personality_Fn));
+
+  // Step 3. Finally return the correctly typed and signed value.
+  return handler;
 }
 
 static _Unwind_Reason_Code

>From 8d7e5264c32272d163e23e61ba625a405a59e6df Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 7 Oct 2025 22:56:08 -0700
Subject: [PATCH 21/28] Addressing myriad feedback

---
 libunwind/include/__libunwind_config.h | 16 +++++++++-------
 libunwind/include/libunwind.h          |  2 +-
 libunwind/src/DwarfParser.hpp          |  2 +-
 libunwind/src/Registers.hpp            | 10 +++++-----
 libunwind/src/UnwindCursor.hpp         |  8 ++++----
 libunwind/src/UnwindLevel1.c           |  3 ---
 libunwind/src/libunwind.cpp            |  2 +-
 7 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 1e5232392de79..a1da29dfc50f4 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -73,16 +73,11 @@
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
 # elif defined(__aarch64__)
 #  define _LIBUNWIND_TARGET_AARCH64 1
-#  if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
-#    define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
-#  elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
-#    #error "Either both or none of ptrauth_calls and ptrauth_returns is allowed to be enabled"
-#  endif
-#define _LIBUNWIND_CONTEXT_SIZE 67
+#  define _LIBUNWIND_CONTEXT_SIZE 67
 #  if defined(__SEH__)
 #    define _LIBUNWIND_CURSOR_SIZE 164
 #  else
-#define _LIBUNWIND_CURSOR_SIZE 79
+#    define _LIBUNWIND_CURSOR_SIZE 79
 #  endif
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
 # elif defined(__arm__)
@@ -217,4 +212,11 @@
 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
 #endif // _LIBUNWIND_IS_NATIVE_ONLY
 
+#if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
+#  define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
+#elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
+#  error "Either both or none of ptrauth_calls and ptrauth_returns "\
+           "is allowed to be enabled"
+#endif
+
 #endif // ____LIBUNWIND_CONFIG_H__
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 49adadd44f076..2947f99ac032a 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -43,7 +43,7 @@
   #define LIBUNWIND_AVAIL
 #endif
 
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
 
   #include <ptrauth.h>
 
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 026919b4e1cb2..2eaf8a84e737c 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -398,7 +398,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
         pint_t personality = addressSpace.getEncodedP(
             p, cieContentEnd, cieInfo->personalityEncoding,
             /*datarelBase=*/0, &resultAddr);
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
         if (personality) {
           // The GOT for the personality function was signed address
           // authenticated. Manually re-sign with the CIE_Info::personality
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index adbab66877a25..aeaf5c4007d59 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1865,7 +1865,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   void      setSP(uint64_t value) { _registers.__sp = value; }
   uint64_t  getIP() const {
     uint64_t value = _registers.__pc;
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
     // 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,
@@ -1877,7 +1877,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
     return value;
   }
   void      setIP(uint64_t value) {
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
     // 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.
@@ -1892,7 +1892,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
   uint64_t getFP() const { return _registers.__fp; }
   void setFP(uint64_t value) { _registers.__fp = value; }
 
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   void
   loadAndAuthenticateLinkRegister(reg_t inplaceAuthedLinkRegister,
                                   link_reg_t *referenceAuthedLinkRegister) {
@@ -1944,7 +1944,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   memcpy(_vectorHalfRegisters,
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
-#if __has_feature(ptrauth_calls)
+#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
@@ -1965,7 +1965,7 @@ Registers_arm64::operator=(const Registers_arm64 &other) {
   memcpy(&_registers, &other._registers, sizeof(_registers));
   memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
          sizeof(_vectorHalfRegisters));
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index b02ef5f330db3..435c4d9138408 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1051,7 +1051,7 @@ class UnwindCursor : public AbstractUnwindCursor{
                                const UnwindInfoSections &sects,
                                uint32_t fdeSectionOffsetHint = 0);
   int stepWithDwarfFDE(bool stage2) {
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
     typename R::reg_t rawPC = this->getReg(UNW_REG_IP);
     typename R::link_reg_t pc;
     _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
@@ -1995,7 +1995,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
         personalityIndex * sizeof(uint32_t));
     pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
     personality = _addressSpace.getP(personalityPointer);
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
     // The GOT for the personality function was signed address authenticated.
     // Resign it as a regular function pointer.
     const auto discriminator = ptrauth_blend_discriminator(
@@ -2680,7 +2680,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
 #endif
 
   typename R::link_reg_t pc;
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   _registers.loadAndAuthenticateLinkRegister(rawPC, &pc);
 #else
   pc = rawPC;
@@ -3235,7 +3235,7 @@ 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 __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   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 6c560773ce62f..8e2b104f999e2 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -110,9 +110,6 @@ static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
   //         _Unwind_Personality_Fn typed local - this avoids any confused
   //         re-signing of values that already have a signature.
   _Unwind_Personality_Fn handler;
-  uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer, 0,
-                  ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
-                  f;
   memcpy(&handler, (void *)&reauthenticatedIntegerHandler,
          sizeof(_Unwind_Personality_Fn));
 
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 41f92aaba2a0b..8acdd0b720238 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -127,7 +127,7 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
 
       pint_t sp = (pint_t)co->getReg(UNW_REG_SP);
 
-#if __has_feature(ptrauth_calls)
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
       {
         // It is only valid to set the IP within the current function.
         // This is important for ptrauth, otherwise the IP cannot be correctly

>From 0f2679a4a76bc0e6b88d407ed3c536b44b08680e Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Wed, 8 Oct 2025 16:51:55 -0700
Subject: [PATCH 22/28] Fixing remaining issues

Stop using unions to deal with the pointer auth cast semantics,
instead perform manual re-signing. This means the templated helper
functions no longer need to be templates and so don't need to be
in a separated non-extern "C" block.

Fixing up the comments.
---
 libcxxabi/include/__cxxabi_config.h    |   4 +-
 libcxxabi/src/cxa_exception.h          |   5 +-
 libcxxabi/src/cxa_personality.cpp      | 102 +++++++++++++++----------
 libunwind/include/__libunwind_config.h |   6 +-
 libunwind/include/libunwind.h          |   6 +-
 libunwind/src/CompactUnwinder.hpp      |  15 ++--
 libunwind/src/DwarfParser.hpp          |  21 ++---
 libunwind/src/Registers.hpp            |   8 +-
 libunwind/src/UnwindCursor.hpp         |  19 ++---
 libunwind/src/UnwindLevel1.c           |  24 ++----
 10 files changed, 110 insertions(+), 100 deletions(-)

diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 51b821241f162..f5101dbc9e599 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -116,7 +116,9 @@
 #  define __ptrauth_cxxabi_lsd __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)
 
 // ptrauth_string_discriminator("__cxa_exception::catchTemp") == 0xFA58
-#  define __ptrauth_cxxabi_catch_temp __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFA58)
+#  define __ptrauth_cxxabi_catch_temp_disc 0xFA58
+#  define __ptrauth_cxxabi_catch_temp_key ptrauth_key_process_dependent_data
+#  define __ptrauth_cxxabi_catch_temp __ptrauth(__ptrauth_cxxabi_catch_temp_key, 1, __ptrauth_cxxabi_catch_temp_disc)
 
 // ptrauth_string_discriminator("__cxa_exception::adjustedPtr") == 0x99E4
 #  define __ptrauth_cxxabi_adjusted_ptr __ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)
diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h
index 2eb77d8612788..fa4c4dc55bde2 100644
--- a/libcxxabi/src/cxa_exception.h
+++ b/libcxxabi/src/cxa_exception.h
@@ -79,8 +79,8 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
 // http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
 // The layout of this structure MUST match the layout of __cxa_exception, with
 // primaryException instead of referenceCount.
-// The tags used in the pointer authentication qualifiers also need to match
-// those of the corresponding members in __cxa_exception.
+// The pointer authentication schemas specified here must also match those of
+// the corresponding members in __cxa_exception.
 struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
 #if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
     void* reserve; // padding.
@@ -101,7 +101,6 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
     int propagationCount;
 #else
     int handlerSwitchValue;
-
     const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
     const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
     void *__ptrauth_cxxabi_catch_temp catchTemp;
diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp
index c98de92db152e..b7eb0f23dbe06 100644
--- a/libcxxabi/src/cxa_personality.cpp
+++ b/libcxxabi/src/cxa_personality.cpp
@@ -575,9 +575,9 @@ typedef void *__ptrauth_scan_results_landingpad landing_pad_ptr_t;
 struct scan_results
 {
     int64_t        ttypeIndex;   // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
-    action_ptr_t actionRecord;   // Currently unused.  Retained to ease future maintenance.
-    lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
-    landing_pad_t landingPad;       // null -> nothing found, else something found
+    action_ptr_t   actionRecord; // Currently unused.  Retained to ease future maintenance.
+    lsd_ptr_t      languageSpecificData; // Needed only for __cxa_call_unexpected
+    landing_pad_t  landingPad;   // null -> nothing found, else something found
     void*          adjustedPtr;  // Used in cxa_exception.cpp
     _Unwind_Reason_Code reason;  // One of _URC_FATAL_PHASE1_ERROR,
                                  //        _URC_FATAL_PHASE2_ERROR,
@@ -586,38 +586,7 @@ struct scan_results
 };
 
 }  // unnamed namespace
-} // extern "C"
-
-#if !defined(_LIBCXXABI_ARM_EHABI)
-namespace {
-// The logical model for casting authenticated function pointers makes
-// it impossible to directly cast them without breaking the authentication,
-// as a result we need this pair of helpers.
-//
-// __ptrauth_nop_cast cannot be used here as the authentication schemas include
-// address diversification.
-template <typename PtrType>
-void set_landing_pad_as_ptr(scan_results& results, const PtrType& landingPad) {
-  union {
-    landing_pad_t* as_landing_pad;
-    landing_pad_ptr_t* as_pointer;
-  } u;
-  u.as_landing_pad = &results.landingPad;
-  *u.as_pointer = landingPad;
-}
 
-static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
-  union {
-    const landing_pad_t* as_landing_pad;
-    const landing_pad_ptr_t* as_pointer;
-  } u;
-  u.as_landing_pad = &results.landingPad;
-  return *u.as_pointer;
-}
-} // unnamed namespace
-#endif
-
-extern "C" {
 static
 void
 set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
@@ -638,10 +607,14 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
   // We manually re-sign the IP as the __ptrauth qualifiers cannot
   // express the required relationship with the destination address
   const auto existingDiscriminator =
-      ptrauth_blend_discriminator(&results.landingPad, __ptrauth_scan_results_landingpad_disc);
+      ptrauth_blend_discriminator(&results.landingPad,
+                                  __ptrauth_scan_results_landingpad_disc);
   unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stackPointer, 0) */ =
-      (unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad, __ptrauth_scan_results_landingpad_key,
-                                          existingDiscriminator, ptrauth_key_return_address, stackPointer);
+      (unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad,
+                                          __ptrauth_scan_results_landingpad_key,
+                                          existingDiscriminator,
+                                          ptrauth_key_return_address,
+                                          stackPointer);
   _Unwind_SetIP(context, newIP);
 #else
   _Unwind_SetIP(context, results.landingPad);
@@ -991,6 +964,57 @@ _UA_CLEANUP_PHASE
 */
 
 #if !defined(_LIBCXXABI_ARM_EHABI)
+
+// We use these helper functions to work around the behavior of casting between
+// integers (even those that are authenticated) and authenticated pointers.
+// Because the schemas being used are address discriminated we cannot use a
+// trivial value union to coerce the types so instead we perform the re-signing
+// manually.
+using __cxa_catch_temp_type = decltype(__cxa_exception::catchTemp);
+static inline void set_landing_pad(scan_results& results,
+                                   const __cxa_catch_temp_type& source) {
+#if __has_feature(ptrauth_calls)
+  const uintptr_t sourceDiscriminator =
+      ptrauth_blend_discriminator(&source, __ptrauth_cxxabi_catch_temp_disc);
+  const uintptr_t targetDiscriminator =
+      ptrauth_blend_discriminator(&results.landingPad,
+                                  __ptrauth_scan_results_landingpad_disc);
+  uintptr_t reauthenticatedLandingPad =
+      (uintptr_t)ptrauth_auth_and_resign(*reinterpret_cast<void* const*>(&source),
+                                         __ptrauth_cxxabi_catch_temp_key,
+                                         sourceDiscriminator,
+                                         __ptrauth_scan_results_landingpad_key,
+                                         targetDiscriminator);
+  memmove(reinterpret_cast<void *>(&results.landingPad),
+          reinterpret_cast<void *>(&reauthenticatedLandingPad),
+          sizeof(reauthenticatedLandingPad));
+#else
+  results.landingPad = reinterpret_cast<landing_pad_t>(source);
+#endif
+}
+
+static inline void get_landing_pad(__cxa_catch_temp_type &dest,
+                                   const scan_results &results) {
+#if __has_feature(ptrauth_calls)
+  const uintptr_t sourceDiscriminator =
+      ptrauth_blend_discriminator(&results.landingPad,
+                                  __ptrauth_scan_results_landingpad_disc);
+  const uintptr_t targetDiscriminator =
+      ptrauth_blend_discriminator(&dest, __ptrauth_cxxabi_catch_temp_disc);
+  uintptr_t reauthenticatedPointer =
+      (uintptr_t)ptrauth_auth_and_resign(*reinterpret_cast<void* const*>(&results.landingPad),
+                                         __ptrauth_scan_results_landingpad_key,
+                                         sourceDiscriminator,
+                                         __ptrauth_cxxabi_catch_temp_key,
+                                         targetDiscriminator);
+  memmove(reinterpret_cast<void *>(&dest),
+          reinterpret_cast<void *>(&reauthenticatedPointer),
+          sizeof(reauthenticatedPointer));
+#else
+  dest = reinterpret_cast<__cxa_catch_temp_type>(results.landingPad);
+#endif
+}
+
 #ifdef __WASM_EXCEPTIONS__
 _Unwind_Reason_Code __gxx_personality_wasm0
 #elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
@@ -1023,7 +1047,7 @@ __gxx_personality_v0
         results.ttypeIndex = exception_header->handlerSwitchValue;
         results.actionRecord = exception_header->actionRecord;
         results.languageSpecificData = exception_header->languageSpecificData;
-        set_landing_pad_as_ptr(results, exception_header->catchTemp);
+        set_landing_pad(results, exception_header->catchTemp);
         results.adjustedPtr = exception_header->adjustedPtr;
 
         // Jump to the handler.
@@ -1057,7 +1081,7 @@ __gxx_personality_v0
             exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
             exc->actionRecord = results.actionRecord;
             exc->languageSpecificData = results.languageSpecificData;
-            exc->catchTemp = get_landing_pad_as_ptr(results);
+            get_landing_pad(exc->catchTemp, results);
             exc->adjustedPtr = results.adjustedPtr;
 #ifdef __WASM_EXCEPTIONS__
             // Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the
diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index a1da29dfc50f4..343934e885368 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 67
 #  if defined(__SEH__)
 #    define _LIBUNWIND_CURSOR_SIZE 164
 #  else
-#    define _LIBUNWIND_CURSOR_SIZE 79
+#define _LIBUNWIND_CURSOR_SIZE 79
 #  endif
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
 # elif defined(__arm__)
@@ -216,7 +216,7 @@
 #  define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
 #elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
 #  error "Either both or none of ptrauth_calls and ptrauth_returns "\
-           "is allowed to be enabled"
+         "is allowed to be enabled"
 #endif
 
 #endif // ____LIBUNWIND_CONFIG_H__
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index 2947f99ac032a..18684ce311f95 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -127,6 +127,7 @@
 
 #else
 
+  #define __unwind_ptrauth_restricted_intptr(...)
   #define __ptrauth_unwind_upi_handler
   #define __ptrauth_unwind_upi_handler_intptr
   #define __ptrauth_unwind_upi_startip
@@ -142,6 +143,7 @@
   #define __ptrauth_unwind_uis_compact_unwind_section
   #define __ptrauth_unwind_uis_compact_unwind_section_length
   #define __ptrauth_unwind_cie_info_personality
+
 #endif
 
 #if defined(_WIN32) && defined(__SEH__)
@@ -197,8 +199,8 @@ struct unw_proc_info_t {
   unw_word_t __ptrauth_unwind_upi_handler_intptr handler;
   unw_word_t  gp;                                   /* not used */
   unw_word_t __ptrauth_unwind_upi_flags flags;      /* not used */
-  uint32_t    format;                               /* compact unwind encoding, or zero if none */
-  uint32_t    unwind_info_size;                     /* size of DWARF unwind info, or zero if none */
+  uint32_t   format;                                /* compact unwind encoding, or zero if none */
+  uint32_t   unwind_info_size;                      /* size of DWARF unwind info, or zero if none */
   unw_word_t __ptrauth_unwind_upi_info unwind_info; /* address of DWARF unwind info, or zero */
   unw_word_t __ptrauth_unwind_upi_extra extra;      /* mach_header of mach-o image containing func */
 };
diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp
index 041fa8ae2b296..cd2e0e3431314 100644
--- a/libunwind/src/CompactUnwinder.hpp
+++ b/libunwind/src/CompactUnwinder.hpp
@@ -601,12 +601,16 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
     savedRegisterLoc -= 8;
   }
 
+  // We load the link register prior to setting the new SP as the authentication
+  // schema for LR entangles the SP of the old frame into the diversifier.
   Registers_arm64::reg_t linkRegister = registers.getRegister(UNW_AARCH64_LR);
 
   // subtract stack size off of sp
   registers.setSP(savedRegisterLoc);
 
-  // set pc to be value in lr
+  // Set pc to be value in lr. This needs to be performed after the new SP has
+  // been set, as the PC authentication schema entangles the SP of the new
+  // frame.
   registers.setIP(linkRegister);
 
   return UNW_STEP_SUCCESS;
@@ -684,13 +688,14 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
 
   Registers_arm64::reg_t fp = registers.getFP();
 
-  // old sp is fp less saved fp and lr. Set this before LR because in arm64e
-  // it's the authentication discriminator.
-  registers.setSP(fp + 16);
-
   // fp points to old fp
   registers.setFP(addressSpace.get64(fp));
 
+  // Old sp is fp less saved fp and lr. We need to set this prior to setting
+  // the lr as the pointer authentication schema for the lr incorporates the
+  // sp as part of the diversifier.
+  registers.setSP(fp + 16);
+
   // pop return address into pc
   registers.setIP(addressSpace.get64(fp + 8));
 
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 2eaf8a84e737c..dbd7d65c354aa 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -23,6 +23,10 @@
 
 #include "config.h"
 
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
+#include <ptrauth.h>
+#endif
+
 namespace libunwind {
 
 /// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
@@ -314,18 +318,6 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
   }
   return false;
 }
-namespace {
-// This helper function handles setting the manually signed personality on
-// CIE_Info without attempt to authenticate and/or re-sign
-template <typename CIE_Info, typename T>
-[[maybe_unused]] void set_cie_info_personality(CIE_Info *info,
-                                               T signed_personality) {
-  static_assert(sizeof(info->personality) == sizeof(signed_personality),
-                "Signed personality is the wrong size");
-  memmove((void *)&info->personality, (void *)&signed_personality,
-          sizeof(signed_personality));
-}
-}
 
 /// Extract info from a CIE
 template <typename A>
@@ -420,7 +412,10 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
           personality = (pint_t)signedPtr;
         }
 #endif
-        set_cie_info_personality(cieInfo, personality);
+        // We use memmove to set the CIE personality as we have already
+        // re-signed the pointer to the correct schema.
+        memmove((void *)&cieInfo->personality, (void *)&personality,
+                sizeof(personality));
         break;
       }
       case 'L':
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index aeaf5c4007d59..e7dc889da17fc 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1950,7 +1950,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   // authenticating so that we maintain the signature for the resigning
   // performed by setIP.
   uint64_t pcRegister = 0;
-  memcpy(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
+  memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
          sizeof(pcRegister));
   setIP(pcRegister);
 #endif
@@ -1962,9 +1962,9 @@ inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
 
 inline Registers_arm64 &
 Registers_arm64::operator=(const Registers_arm64 &other) {
-  memcpy(&_registers, &other._registers, sizeof(_registers));
-  memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
-         sizeof(_vectorHalfRegisters));
+  memmove(&_registers, &other._registers, sizeof(_registers));
+  memmove(_vectorHalfRegisters, &other._vectorHalfRegisters,
+          sizeof(_vectorHalfRegisters));
 #if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 435c4d9138408..6893982451381 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1750,18 +1750,6 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(
 
 
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-// This helper function handles setting the manually signed handler on
-// unw_proc_info without attempt to authenticate and/or re-sign
-namespace {
-template <typename T>
-void set_proc_info_handler(unw_proc_info_t &info, T signed_handler) {
-  static_assert(sizeof(info.handler) == sizeof(signed_handler),
-                "Signed handler is the wrong size");
-  memmove((void *)&info.handler, (void *)&signed_handler,
-          sizeof(signed_handler));
-}
-} // unnamed namespace
-
 template <typename A, typename R>
 bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
     const typename R::link_reg_t &pc, const UnwindInfoSections &sects) {
@@ -2018,7 +2006,12 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
   _info.start_ip = funcStart;
   _info.end_ip = funcEnd;
   _info.lsda = lsda;
-  set_proc_info_handler(_info, personality);
+  // We use memmove to copy the personality function as we have already manually
+  // re-signed the pointer, and assigning directly will attempt to incorrectly
+  // sign the already signed value.
+  memmove(reinterpret_cast<void *>(&_info.handler),
+          reinterpret_cast<void *>(&personality),
+          sizeof(personality));
   _info.gp = 0;
   _info.flags = 0;
   _info.format = encoding;
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index 8e2b104f999e2..994b116f696a8 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -90,30 +90,20 @@
   } while (0)
 #endif
 
-// There is not currently a clean way to cast between an authenticated
-// integer and an authenticated function pointer, so we need this helper
-// function to keep things clean.
+// We need this helper function as the semantics of casting between integers and
+// function pointers mean that we end up with a function pointer without the
+// correct signature. Instead we assign to an integer with a matching schema,
+// and then memmove the result into a variable of the correct type. This memmove
+// is possible as `_Unwind_Personality_Fn` is a standard function pointer, and
+// as such is not address diversified.
 static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
-  // Converting from an authenticated integer to a _Unwind_Personality_Fn
-  // requires multiple steps, but as the schema of _Unwind_Personality_Fn is
-  // not address diversified we can mostly just rely on automatic re-signing
-  // by clang.
-
-  // Step 1. Assign from the address diversified integer in frameInfo->handler
-  //         to the non-address diversified schema of `_Unwind_Personality_Fn`
   uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer,
                                                0,
                                                ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
     reauthenticatedIntegerHandler = frameInfo->handler;
-
-  // Step 2. Memcpy from our re-signed integer typed handler to an
-  //         _Unwind_Personality_Fn typed local - this avoids any confused
-  //         re-signing of values that already have a signature.
   _Unwind_Personality_Fn handler;
-  memcpy(&handler, (void *)&reauthenticatedIntegerHandler,
+  memmove(&handler, (void *)&reauthenticatedIntegerHandler,
          sizeof(_Unwind_Personality_Fn));
-
-  // Step 3. Finally return the correctly typed and signed value.
   return handler;
 }
 

>From 74de39bee52903e0f6b02e5f9d774be0b234388d Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Tue, 14 Oct 2025 21:07:42 -0700
Subject: [PATCH 23/28] formatting corrections

---
 libunwind/src/DwarfInstructions.hpp | 2 +-
 libunwind/src/Registers.hpp         | 2 +-
 libunwind/src/UnwindCursor.hpp      | 3 +--
 libunwind/src/UnwindLevel1.c        | 2 +-
 4 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index d9fa76c57da47..d2822e8be29ef 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -302,7 +302,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace,
 
       isSignalFrame = cieInfo.isSignalFrame;
 
-#if defined(_LIBUNWIND_TARGET_AARCH64) && \
+#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
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index e7dc889da17fc..e7bf80ce80ebc 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1951,7 +1951,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   // performed by setIP.
   uint64_t pcRegister = 0;
   memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
-         sizeof(pcRegister));
+          sizeof(pcRegister));
   setIP(pcRegister);
 #endif
 }
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 6893982451381..7ec5f9e91578a 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -2010,8 +2010,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
   // re-signed the pointer, and assigning directly will attempt to incorrectly
   // sign the already signed value.
   memmove(reinterpret_cast<void *>(&_info.handler),
-          reinterpret_cast<void *>(&personality),
-          sizeof(personality));
+          reinterpret_cast<void *>(&personality), sizeof(personality));
   _info.gp = 0;
   _info.flags = 0;
   _info.format = encoding;
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index 994b116f696a8..b0cd60dfb9141 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/libunwind/src/UnwindLevel1.c
@@ -103,7 +103,7 @@ static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
     reauthenticatedIntegerHandler = frameInfo->handler;
   _Unwind_Personality_Fn handler;
   memmove(&handler, (void *)&reauthenticatedIntegerHandler,
-         sizeof(_Unwind_Personality_Fn));
+          sizeof(_Unwind_Personality_Fn));
   return handler;
 }
 

>From a9d911322fe3020fd098ff0d6cbf6745b66b93e6 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Thu, 16 Oct 2025 23:33:56 -0700
Subject: [PATCH 24/28] A somewhat gross 'lets see if this is the bot issue'
 change

---
 libunwind/src/Registers.hpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index e7bf80ce80ebc..7d7bf4b87fc3d 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1839,8 +1839,10 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
 public:
   Registers_arm64();
   Registers_arm64(const void *registers);
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   Registers_arm64(const Registers_arm64 &);
   Registers_arm64 &operator=(const Registers_arm64 &);
+#endif
 
   typedef uint64_t reg_t;
   typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t;
@@ -1956,6 +1958,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
 #endif
 }
 
+#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
 inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
   *this = other;
 }
@@ -1965,13 +1968,11 @@ Registers_arm64::operator=(const Registers_arm64 &other) {
   memmove(&_registers, &other._registers, sizeof(_registers));
   memmove(_vectorHalfRegisters, &other._vectorHalfRegisters,
           sizeof(_vectorHalfRegisters));
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());
-#endif
-  return *this;
 }
+#endif
 
 inline Registers_arm64::Registers_arm64() {
   memset(&_registers, 0, sizeof(_registers));

>From 3c5a77696429f0eb4c4c7e3dd462d10b1760650c Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Fri, 17 Oct 2025 11:44:28 -0700
Subject: [PATCH 25/28] Ooooh, this might be it -- also it remains absurd that
 this isn't an error

---
 libunwind/src/Registers.hpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 7d7bf4b87fc3d..b8c027c6027b1 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1839,10 +1839,8 @@ class _LIBUNWIND_HIDDEN Registers_arm64 {
 public:
   Registers_arm64();
   Registers_arm64(const void *registers);
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
   Registers_arm64(const Registers_arm64 &);
   Registers_arm64 &operator=(const Registers_arm64 &);
-#endif
 
   typedef uint64_t reg_t;
   typedef uint64_t __ptrauth_unwind_registers_arm64_link_reg link_reg_t;
@@ -1958,7 +1956,6 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
 #endif
 }
 
-#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
 inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
   *this = other;
 }
@@ -1971,8 +1968,8 @@ Registers_arm64::operator=(const Registers_arm64 &other) {
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());
+  return *this;
 }
-#endif
 
 inline Registers_arm64::Registers_arm64() {
   memset(&_registers, 0, sizeof(_registers));

>From 865181e71daae27c2bb6215c92d4be2f28d49886 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Fri, 17 Oct 2025 18:44:27 -0700
Subject: [PATCH 26/28] Let's stop doing this in the fragile field by field way

---
 libunwind/src/Registers.hpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index b8c027c6027b1..dc9f4575dd618 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1944,6 +1944,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   memcpy(_vectorHalfRegisters,
          static_cast<const uint8_t *>(registers) + sizeof(GPRs),
          sizeof(_vectorHalfRegisters));
+
 #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
@@ -1962,9 +1963,7 @@ inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
 
 inline Registers_arm64 &
 Registers_arm64::operator=(const Registers_arm64 &other) {
-  memmove(&_registers, &other._registers, sizeof(_registers));
-  memmove(_vectorHalfRegisters, &other._vectorHalfRegisters,
-          sizeof(_vectorHalfRegisters));
+  memmove(this, &other, sizeof(Registers_arm64));
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());

>From 5e03a33d78f9cf0c66bb052f739cc52411cae9c2 Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Fri, 17 Oct 2025 22:31:41 -0700
Subject: [PATCH 27/28] Fix the build because I am clever

---
 libunwind/src/Registers.hpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index dc9f4575dd618..5a5b57835379a 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -1944,6 +1944,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
   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,
@@ -1963,7 +1964,7 @@ inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
 
 inline Registers_arm64 &
 Registers_arm64::operator=(const Registers_arm64 &other) {
-  memmove(this, &other, sizeof(Registers_arm64));
+  memmove(static_cast<void *>(this), &other, sizeof(*this));
   // We perform this step to ensure that we correctly authenticate and re-sign
   // the pc after the bitwise copy.
   setIP(other.getIP());
@@ -1971,8 +1972,7 @@ Registers_arm64::operator=(const Registers_arm64 &other) {
 }
 
 inline Registers_arm64::Registers_arm64() {
-  memset(&_registers, 0, sizeof(_registers));
-  memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters));
+  memset(static_cast<void *>(this), 0, sizeof(*this));
 }
 
 inline bool Registers_arm64::validRegister(int regNum) const {

>From 1839bb4f3ee8c4dad986dbdf9a2eed83c8aa245a Mon Sep 17 00:00:00 2001
From: Oliver Hunt <oliver at apple.com>
Date: Sun, 19 Oct 2025 19:44:52 -0700
Subject: [PATCH 28/28] Remove union, improve comments.

---
 libunwind/src/libunwind.cpp | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 8acdd0b720238..951d87db868bc 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -129,22 +129,24 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
 
 #if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
       {
-        // It is only valid to set the IP within the current function.
-        // This is important for ptrauth, otherwise the IP cannot be correctly
-        // signed.
-        // We re-sign to a more usable form and then use it directly.
-        union {
-          unw_word_t opaque_value;
-          unw_word_t
+        // It is only valid to set the IP within the current function. This is
+        // important for ptrauth, otherwise the IP cannot be correctly signed.
+        // The current signature of `value` is via the schema:
+        //   __ptrauth(ptrauth_key_return_address, <<sp>>, 0)
+        // For this to be generally usable we manually re-sign it to the
+        // directly supported schema:
+        //   __ptrauth(ptrauth_key_return_address, 1, 0)
+        unw_word_t
               __unwind_ptrauth_restricted_intptr(ptrauth_key_return_address, 1,
                                                  0) authenticated_value;
-        } u;
-        u.opaque_value = (uint64_t)ptrauth_auth_and_resign(
+        unw_word_t opaque_value = (uint64_t)ptrauth_auth_and_resign(
             (void *)value, ptrauth_key_return_address, sp,
-            ptrauth_key_return_address, &u.opaque_value);
-
-        if (u.authenticated_value < info.start_ip ||
-            u.authenticated_value > info.end_ip)
+            ptrauth_key_return_address, &authenticated_value);
+        memmove(reinterpret_cast<void *>(&authenticated_value),
+                reinterpret_cast<void *>(&opaque_value),
+                sizeof(authenticated_value));
+        if (authenticated_value < info.start_ip ||
+            authenticated_value > info.end_ip)
           _LIBUNWIND_ABORT("PC vs frame info mismatch");
 
         // PC should have been signed with the sp, so we verify that



More information about the libcxx-commits mailing list