diff --git a/clang/lib/Headers/unwind.h b/clang/lib/Headers/unwind.h --- a/clang/lib/Headers/unwind.h +++ b/clang/lib/Headers/unwind.h @@ -172,7 +172,8 @@ _UVRSC_CORE = 0, /* integer register */ _UVRSC_VFP = 1, /* vfp */ _UVRSC_WMMXD = 3, /* Intel WMMX data register */ - _UVRSC_WMMXC = 4 /* Intel WMMX control register */ + _UVRSC_WMMXC = 4, /* Intel WMMX control register */ + _UVRSC_PSEUDO = 5 /* Special purpose pseudo register */ } _Unwind_VRS_RegClass; typedef enum { diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h --- a/libunwind/include/libunwind.h +++ b/libunwind/include/libunwind.h @@ -718,7 +718,8 @@ UNW_ARM_WR14 = 126, UNW_ARM_WR15 = 127, // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC} - // 134-143 -- Reserved + // 134-142 -- Reserved + UNW_ARM_RA_AUTH_CODE = 143, // 144-150 -- R8_USR-R14_USR // 151-157 -- R8_FIQ-R14_FIQ // 158-159 -- R13_IRQ-R14_IRQ diff --git a/libunwind/include/unwind_arm_ehabi.h b/libunwind/include/unwind_arm_ehabi.h --- a/libunwind/include/unwind_arm_ehabi.h +++ b/libunwind/include/unwind_arm_ehabi.h @@ -87,10 +87,11 @@ extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); typedef enum { - _UVRSC_CORE = 0, /* integer register */ - _UVRSC_VFP = 1, /* vfp */ + _UVRSC_CORE = 0, /* integer register */ + _UVRSC_VFP = 1, /* vfp */ _UVRSC_WMMXD = 3, /* Intel WMMX data register */ - _UVRSC_WMMXC = 4 /* Intel WMMX control register */ + _UVRSC_WMMXC = 4, /* Intel WMMX control register */ + _UVRSC_PSEUDO = 5 /* Special purpose pseudo register */ } _Unwind_VRS_RegClass; typedef enum { diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -242,6 +242,20 @@ } #endif +#if defined(_LIBUNWIND_IS_NATIVE_ONLY) && defined(_LIBUNWIND_TARGET_ARM) && \ + defined(__ARM_FEATURE_PAUTH) + if ((R::getArch() == REGISTERS_ARM) && + prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE].value) { + pint_t pac = + getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE]); + __asm__ __volatile__("autg %0, %1, %2" + : + : "r"(pac), "r"(returnAddress), "r"(cfa) + :); + } +#endif + #if defined(_LIBUNWIND_TARGET_SPARC) if (R::getArch() == REGISTERS_SPARC) { // Skip call site instruction and delay slot diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -2140,6 +2140,10 @@ uint32_t __pc; // Program counter r15 }; + struct PseudoRegisters { + uint32_t __pac; // Return Authentication Code (PAC) + }; + static void saveVFPWithFSTMD(void*); static void saveVFPWithFSTMX(void*); static void saveVFPv3(void*); @@ -2156,6 +2160,7 @@ // ARM registers GPRs _registers; + PseudoRegisters _pseudo_registers; // We save floating point registers lazily because we can't know ahead of // time which ones are used. See EHABI #4.7. @@ -2193,6 +2198,7 @@ "arm registers do not fit into unw_context_t"); // See __unw_getcontext() note about data. memcpy(&_registers, registers, sizeof(_registers)); + memset(&_pseudo_registers, 0, sizeof(_pseudo_registers)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); #if defined(__ARM_WMMX) @@ -2208,6 +2214,7 @@ _saved_vfp_d0_d15(false), _saved_vfp_d16_d31(false) { memset(&_registers, 0, sizeof(_registers)); + memset(&_pseudo_registers, 0, sizeof(_pseudo_registers)); memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); #if defined(__ARM_WMMX) @@ -2235,6 +2242,11 @@ return true; #endif +#ifdef __ARM_FEATURE_PAUTH + if (regNum == UNW_ARM_RA_AUTH_CODE) + return true; +#endif + return false; } @@ -2261,6 +2273,11 @@ } #endif +#ifdef __ARM_FEATURE_PAUTH + if (regNum == UNW_ARM_RA_AUTH_CODE) + return _pseudo_registers.__pac; +#endif + _LIBUNWIND_ABORT("unsupported arm register"); } @@ -2296,6 +2313,11 @@ } #endif + if (regNum == UNW_ARM_RA_AUTH_CODE) { + _pseudo_registers.__pac = value; + return; + } + _LIBUNWIND_ABORT("unsupported arm register"); } diff --git a/libunwind/src/Unwind-EHABI.cpp b/libunwind/src/Unwind-EHABI.cpp --- a/libunwind/src/Unwind-EHABI.cpp +++ b/libunwind/src/Unwind-EHABI.cpp @@ -261,6 +261,7 @@ size_t offset, size_t len) { bool wrotePC = false; bool finish = false; + bool hasReturnAddrAuthCode = false; while (offset < len && !finish) { uint8_t byte = getByte(data, offset++); if ((byte & 0x80) == 0) { @@ -347,6 +348,10 @@ break; } case 0xb4: + hasReturnAddrAuthCode = true; + _Unwind_VRS_Pop(context, _UVRSC_PSEUDO, + 0 /* Return Address Auth Code */, _UVRSD_UINT32); + break; case 0xb5: case 0xb6: case 0xb7: @@ -422,6 +427,16 @@ if (!wrotePC) { uint32_t lr; _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr); +#ifdef __ARM_FEATURE_PAUTH + if (hasReturnAddrAuthCode) { + uint32_t sp; + uint32_t pac; + _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + _Unwind_VRS_Get(context, _UVRSC_PSEUDO, UNW_ARM_RA_AUTH_CODE, + _UVRSD_UINT32, &pac); + __asm__ __volatile__("autg %0, %1, %2" : : "r"(pac), "r"(lr), "r"(sp) :); + } +#endif _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr); } return _URC_CONTINUE_UNWIND; @@ -941,6 +956,15 @@ case _UVRSC_WMMXD: break; #endif + case _UVRSC_PSEUDO: + // There's only one pseudo-register, PAC, with regno == 0. + if (representation != _UVRSD_UINT32 || regno != 0) + return _UVRSR_FAILED; + return __unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_RA_AUTH_CODE), + *(unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + break; } _LIBUNWIND_ABORT("unsupported register class"); } @@ -995,6 +1019,15 @@ case _UVRSC_WMMXD: break; #endif + case _UVRSC_PSEUDO: + // There's only one pseudo-register, PAC, with regno == 0. + if (representation != _UVRSD_UINT32 || regno != 0) + return _UVRSR_FAILED; + return __unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_RA_AUTH_CODE), + (unw_word_t *)valuep) == UNW_ESUCCESS + ? _UVRSR_OK + : _UVRSR_FAILED; + break; } _LIBUNWIND_ABORT("unsupported register class"); } @@ -1092,6 +1125,20 @@ return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); } + case _UVRSC_PSEUDO: { + if (representation != _UVRSD_UINT32 || discriminator != 0) + return _UVRSR_FAILED; + // Return Address Authentication code (PAC) - discriminator 0 + uint32_t *sp; + if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, + &sp) != _UVRSR_OK) { + return _UVRSR_FAILED; + } + uint32_t pac = *sp++; + _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); + return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_RA_AUTH_CODE, + _UVRSD_UINT32, &pac); + } } _LIBUNWIND_ABORT("unsupported register class"); } diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -655,7 +655,9 @@ #if defined(_LIBUNWIND_TARGET_X86_64) if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true; #elif defined(_LIBUNWIND_TARGET_ARM) - if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true; + if ((regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) || + regNum == UNW_ARM_RA_AUTH_CODE) + return true; #elif defined(_LIBUNWIND_TARGET_AARCH64) if (regNum >= UNW_AARCH64_X0 && regNum <= UNW_ARM64_X30) return true; #endif diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S --- a/libunwind/src/UnwindRegistersRestore.S +++ b/libunwind/src/UnwindRegistersRestore.S @@ -660,7 +660,13 @@ ldr sp, [lr, #52] ldr lr, [lr, #60] @ restore pc into lr #endif +#if defined(__ARM_FEATURE_BTI_DEFAULT) && !defined(__ARM_ARCH_ISA_ARM) + // 'bx' is not BTI setting when used with lr, therefore r12 is used instead + mov r12, lr + JMP(r12) +#else JMP(lr) +#endif @ @ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values) diff --git a/libunwind/src/assembly.h b/libunwind/src/assembly.h --- a/libunwind/src/assembly.h +++ b/libunwind/src/assembly.h @@ -81,7 +81,7 @@ #define PPC64_OPD2 #endif -#if defined(__ARM_FEATURE_BTI_DEFAULT) +#if defined(__aarch64__) && defined(__ARM_FEATURE_BTI_DEFAULT) .pushsection ".note.gnu.property", "a" SEPARATOR \ .balign 8 SEPARATOR \ .long 4 SEPARATOR \ @@ -99,6 +99,17 @@ #define AARCH64_BTI #endif +#if !defined(__aarch64__) +#ifdef __ARM_FEATURE_PAC_DEFAULT + .eabi_attribute Tag_PAC_extension, 2 + .eabi_attribute Tag_PACRET_use, 1 +#endif +#ifdef __ARM_FEATURE_BTI_DEFAULT + .eabi_attribute Tag_BTI_extension, 1 + .eabi_attribute Tag_BTI_use, 1 +#endif +#endif + #define GLUE2(a, b) a ## b #define GLUE(a, b) GLUE2(a, b) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)