https://github.com/ojhunt updated https://github.com/llvm/llvm-project/pull/143230
>From 7882528d14f3e7c7f834c82735b950b5a4d4a87f Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Tue, 5 Aug 2025 18:16:32 -0700 Subject: [PATCH 1/6] [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 b2dae8feed9a3..82737f5aec2f4 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 ®isters) { - 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 ®isters, bool &isSignalFrame, bool stage2); + static int stepWithDwarf(A &addressSpace, typename R::link_reg_t &pc, + pint_t fdeStart, R ®isters, 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 ®isters) { - if (prolog.cfaRegister != 0) - return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + - prolog.cfaRegisterOffset); + R ®isters) { + 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 ®isters, 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 7e85025dd054d..375abaaae8dc7 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 2c3bfb7e8428a..5c2aafe7124f9 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: struct GPRs { @@ -1877,6 +1953,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() { @@ -1902,13 +2003,13 @@ inline bool Registers_arm64::validRegister(int regNum) 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 >= 0) && (regNum < 29)) @@ -1918,13 +2019,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 >= 0) && (regNum < 29)) @@ -2140,6 +2241,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 §s, - uint32_t fdeSectionOffsetHint=0); + bool getInfoFromDwarfSection(const typename R::link_reg_t &pc, + const UnwindInfoSections §s, + 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 §s); + bool getInfoFromCompactEncodingSection(const typename R::link_reg_t &pc, + const UnwindInfoSections §s); 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 §s, - uint32_t fdeSectionOffsetHint) { +bool UnwindCursor<A, R>::getInfoFromDwarfSection( + const typename R::link_reg_t &pc, const UnwindInfoSections §s, + 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 §s) { +bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection( + const typename R::link_reg_t &pc, const UnwindInfoSections §s) { 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 5e199188945df..632c662cc11e5 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -657,7 +657,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] @@ -681,7 +681,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) @@ -694,7 +705,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 5139a551ad245..74c5301674abc 100644 --- a/libunwind/src/UnwindRegistersSave.S +++ b/libunwind/src/UnwindRegistersSave.S @@ -767,6 +767,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] @@ -807,7 +812,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 062b3f2705cb25c363d027c1622483edd5ef4962 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 6 Aug 2025 00:10:14 -0700 Subject: [PATCH 2/6] 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 82737f5aec2f4..8259be4263084 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 375abaaae8dc7..e9ed0e79e89c9 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 5c2aafe7124f9..20bfe4f7a8306 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: struct GPRs { @@ -1954,14 +1934,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 } @@ -1974,8 +1954,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; } @@ -2243,10 +2224,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 §s, 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 632c662cc11e5..3ab9477b8a670 100644 --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -687,7 +687,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 6e33c116a8258bc1b08e2a25743f677108c9a136 Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 6 Aug 2025 12:59:44 -0700 Subject: [PATCH 3/6] 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 9148b296a36cd9ece10033275a95ab22f7d28dec Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 6 Aug 2025 14:03:21 -0700 Subject: [PATCH 4/6] 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 e9ed0e79e89c9..627d339c0282a 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 2468194697c0f8ab8e536b90355ce186a97fc99f Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 6 Aug 2025 14:41:21 -0700 Subject: [PATCH 5/6] 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 d8f55749c49a1c251bb4e57519f08dd8df74a50f Mon Sep 17 00:00:00 2001 From: Oliver Hunt <oli...@apple.com> Date: Wed, 6 Aug 2025 14:48:27 -0700 Subject: [PATCH 6/6] 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 20bfe4f7a8306..74c2d599948da 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, @@ -2198,6 +2201,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); @@ -2222,9 +2228,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; @@ -2706,6 +2709,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); @@ -2905,6 +2911,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); @@ -3240,6 +3249,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); @@ -3543,6 +3555,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); @@ -3729,6 +3744,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); @@ -3914,6 +3932,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); @@ -4129,6 +4150,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); @@ -4426,6 +4450,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); @@ -4869,6 +4896,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); @@ -5157,6 +5187,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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits