_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 {
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
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 {
}
#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
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*);
// 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.
"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)
_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)
return true;
#endif
+#ifdef __ARM_FEATURE_PAUTH
+ if (regNum == UNW_ARM_RA_AUTH_CODE)
+ return true;
+#endif
+
return false;
}
}
#endif
+#ifdef __ARM_FEATURE_PAUTH
+ if (regNum == UNW_ARM_RA_AUTH_CODE)
+ return _pseudo_registers.__pac;
+#endif
+
_LIBUNWIND_ABORT("unsupported arm register");
}
}
#endif
+ if (regNum == UNW_ARM_RA_AUTH_CODE) {
+ _pseudo_registers.__pac = value;
+ return;
+ }
+
_LIBUNWIND_ABORT("unsupported arm register");
}
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) {
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:
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;
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");
}
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");
}
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");
}
#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
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)
#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 \
#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)