Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
libunwind/src/Registers.hpp
Show First 20 Lines • Show All 2,134 Lines • ▼ Show 20 Lines | |||||
private: | private: | ||||
struct GPRs { | struct GPRs { | ||||
uint32_t __r[13]; // r0-r12 | uint32_t __r[13]; // r0-r12 | ||||
uint32_t __sp; // Stack pointer r13 | uint32_t __sp; // Stack pointer r13 | ||||
uint32_t __lr; // Link register r14 | uint32_t __lr; // Link register r14 | ||||
uint32_t __pc; // Program counter r15 | uint32_t __pc; // Program counter r15 | ||||
}; | }; | ||||
struct PseudoRegisters { | |||||
uint32_t __pac; // Return Authentication Code (PAC) | |||||
}; | |||||
static void saveVFPWithFSTMD(void*); | static void saveVFPWithFSTMD(void*); | ||||
static void saveVFPWithFSTMX(void*); | static void saveVFPWithFSTMX(void*); | ||||
static void saveVFPv3(void*); | static void saveVFPv3(void*); | ||||
static void restoreVFPWithFLDMD(void*); | static void restoreVFPWithFLDMD(void*); | ||||
static void restoreVFPWithFLDMX(void*); | static void restoreVFPWithFLDMX(void*); | ||||
static void restoreVFPv3(void*); | static void restoreVFPv3(void*); | ||||
#if defined(__ARM_WMMX) | #if defined(__ARM_WMMX) | ||||
static void saveiWMMX(void*); | static void saveiWMMX(void*); | ||||
static void saveiWMMXControl(uint32_t*); | static void saveiWMMXControl(uint32_t*); | ||||
static void restoreiWMMX(void*); | static void restoreiWMMX(void*); | ||||
static void restoreiWMMXControl(uint32_t*); | static void restoreiWMMXControl(uint32_t*); | ||||
#endif | #endif | ||||
void restoreCoreAndJumpTo(); | void restoreCoreAndJumpTo(); | ||||
// ARM registers | // ARM registers | ||||
GPRs _registers; | GPRs _registers; | ||||
PseudoRegisters _pseudo_registers; | |||||
// We save floating point registers lazily because we can't know ahead of | // We save floating point registers lazily because we can't know ahead of | ||||
// time which ones are used. See EHABI #4.7. | // time which ones are used. See EHABI #4.7. | ||||
// Whether D0-D15 are saved in the FTSMX instead of FSTMD format. | // Whether D0-D15 are saved in the FTSMX instead of FSTMD format. | ||||
// | // | ||||
// See EHABI #7.5 that explains how matching instruction sequences for load | // See EHABI #7.5 that explains how matching instruction sequences for load | ||||
// and store need to be used to correctly restore the exact register bits. | // and store need to be used to correctly restore the exact register bits. | ||||
Show All 21 Lines | |||||
inline Registers_arm::Registers_arm(const void *registers) | inline Registers_arm::Registers_arm(const void *registers) | ||||
: _use_X_for_vfp_save(false), | : _use_X_for_vfp_save(false), | ||||
_saved_vfp_d0_d15(false), | _saved_vfp_d0_d15(false), | ||||
_saved_vfp_d16_d31(false) { | _saved_vfp_d16_d31(false) { | ||||
static_assert((check_fit<Registers_arm, unw_context_t>::does_fit), | static_assert((check_fit<Registers_arm, unw_context_t>::does_fit), | ||||
"arm registers do not fit into unw_context_t"); | "arm registers do not fit into unw_context_t"); | ||||
// See __unw_getcontext() note about data. | // See __unw_getcontext() note about data. | ||||
memcpy(&_registers, registers, sizeof(_registers)); | 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_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); | ||||
memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); | memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); | ||||
#if defined(__ARM_WMMX) | #if defined(__ARM_WMMX) | ||||
_saved_iwmmx = false; | _saved_iwmmx = false; | ||||
_saved_iwmmx_control = false; | _saved_iwmmx_control = false; | ||||
memset(&_iwmmx, 0, sizeof(_iwmmx)); | memset(&_iwmmx, 0, sizeof(_iwmmx)); | ||||
memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); | memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); | ||||
#endif | #endif | ||||
} | } | ||||
inline Registers_arm::Registers_arm() | inline Registers_arm::Registers_arm() | ||||
: _use_X_for_vfp_save(false), | : _use_X_for_vfp_save(false), | ||||
_saved_vfp_d0_d15(false), | _saved_vfp_d0_d15(false), | ||||
_saved_vfp_d16_d31(false) { | _saved_vfp_d16_d31(false) { | ||||
memset(&_registers, 0, sizeof(_registers)); | 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_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad)); | ||||
memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); | memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31)); | ||||
#if defined(__ARM_WMMX) | #if defined(__ARM_WMMX) | ||||
_saved_iwmmx = false; | _saved_iwmmx = false; | ||||
_saved_iwmmx_control = false; | _saved_iwmmx_control = false; | ||||
memset(&_iwmmx, 0, sizeof(_iwmmx)); | memset(&_iwmmx, 0, sizeof(_iwmmx)); | ||||
memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); | memset(&_iwmmx_control, 0, sizeof(_iwmmx_control)); | ||||
#endif | #endif | ||||
Show All 11 Lines | inline bool Registers_arm::validRegister(int regNum) const { | ||||
if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) | if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) | ||||
return true; | return true; | ||||
#if defined(__ARM_WMMX) | #if defined(__ARM_WMMX) | ||||
if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) | if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) | ||||
return true; | return true; | ||||
#endif | #endif | ||||
#ifdef __ARM_FEATURE_PAUTH | |||||
if (regNum == UNW_ARM_RA_AUTH_CODE) | |||||
danielkiss: Maybe we could gate this on __ARM_FEATURE_PAUTH because it won't work anyway without the… | |||||
return true; | |||||
#endif | |||||
return false; | return false; | ||||
} | } | ||||
inline uint32_t Registers_arm::getRegister(int regNum) const { | inline uint32_t Registers_arm::getRegister(int regNum) const { | ||||
if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) | if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) | ||||
return _registers.__sp; | return _registers.__sp; | ||||
if (regNum == UNW_ARM_LR) | if (regNum == UNW_ARM_LR) | ||||
Show All 10 Lines | if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) { | ||||
if (!_saved_iwmmx_control) { | if (!_saved_iwmmx_control) { | ||||
_saved_iwmmx_control = true; | _saved_iwmmx_control = true; | ||||
saveiWMMXControl(_iwmmx_control); | saveiWMMXControl(_iwmmx_control); | ||||
} | } | ||||
return _iwmmx_control[regNum - UNW_ARM_WC0]; | return _iwmmx_control[regNum - UNW_ARM_WC0]; | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef __ARM_FEATURE_PAUTH | |||||
if (regNum == UNW_ARM_RA_AUTH_CODE) | |||||
ditto, maybe better to run into a _LIBUNWIND_ABORT instead debugging a silently skipping the authentication. danielkiss: ditto, maybe better to run into a `_LIBUNWIND_ABORT` instead debugging a silently skipping the… | |||||
return _pseudo_registers.__pac; | |||||
#endif | |||||
_LIBUNWIND_ABORT("unsupported arm register"); | _LIBUNWIND_ABORT("unsupported arm register"); | ||||
} | } | ||||
inline void Registers_arm::setRegister(int regNum, uint32_t value) { | inline void Registers_arm::setRegister(int regNum, uint32_t value) { | ||||
if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) { | if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) { | ||||
_registers.__sp = value; | _registers.__sp = value; | ||||
return; | return; | ||||
} | } | ||||
Show All 19 Lines | if (!_saved_iwmmx_control) { | ||||
_saved_iwmmx_control = true; | _saved_iwmmx_control = true; | ||||
saveiWMMXControl(_iwmmx_control); | saveiWMMXControl(_iwmmx_control); | ||||
} | } | ||||
_iwmmx_control[regNum - UNW_ARM_WC0] = value; | _iwmmx_control[regNum - UNW_ARM_WC0] = value; | ||||
return; | return; | ||||
} | } | ||||
#endif | #endif | ||||
if (regNum == UNW_ARM_RA_AUTH_CODE) { | |||||
_pseudo_registers.__pac = value; | |||||
return; | |||||
} | |||||
_LIBUNWIND_ABORT("unsupported arm register"); | _LIBUNWIND_ABORT("unsupported arm register"); | ||||
} | } | ||||
inline const char *Registers_arm::getRegisterName(int regNum) { | inline const char *Registers_arm::getRegisterName(int regNum) { | ||||
switch (regNum) { | switch (regNum) { | ||||
case UNW_REG_IP: | case UNW_REG_IP: | ||||
case UNW_ARM_IP: // UNW_ARM_R15 is alias | case UNW_ARM_IP: // UNW_ARM_R15 is alias | ||||
return "pc"; | return "pc"; | ||||
▲ Show 20 Lines • Show All 2,203 Lines • Show Last 20 Lines |
Maybe we could gate this on __ARM_FEATURE_PAUTH because it won't work anyway without the feature enabled for libunwind.