option(LIBUNWIND_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF)
option(LIBUNWIND_ENABLE_SHARED "Build libunwind as a shared library." ON)
option(LIBUNWIND_ENABLE_CROSS_UNWINDING "Enable cross-platform unwinding support." OFF)
+option(LIBUNWIND_ENABLE_ARM_WMMX "Enable unwinding support for ARM WMMX registers." OFF)
set(LIBUNWIND_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.")
set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.")
list(APPEND LIBUNWIND_COMPILE_FLAGS -D_LIBUNWIND_IS_NATIVE_ONLY)
endif ()
+# ARM WMMX register support
+if (LIBUNWIND_ENABLE_ARM_WMMX)
+ # __ARM_WMMX is a compiler pre-define (as per the ACLE 2.0). Clang does not
+ # define this macro for any supported target at present. Therefore, here we
+ # provide the option to explicitly enable support for WMMX registers in the
+ # unwinder.
+ list(APPEND LIBUNWIND_COMPILE_FLAGS -D__ARM_WMMX)
+endif ()
+
# This is the _ONLY_ place where add_definitions is called.
if (MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
# define _LIBUNWIND_CURSOR_SIZE 78
# elif defined(__arm__)
# define _LIBUNWIND_TARGET_ARM 1
-# define _LIBUNWIND_CONTEXT_SIZE 60
-# define _LIBUNWIND_CURSOR_SIZE 67
+# if defined(__ARM_WMMX)
+# define _LIBUNWIND_CONTEXT_SIZE 60
+# define _LIBUNWIND_CURSOR_SIZE 67
+# else
+# define _LIBUNWIND_CONTEXT_SIZE 42
+# define _LIBUNWIND_CURSOR_SIZE 49
+# endif
# elif defined(__or1k__)
# define _LIBUNWIND_TARGET_OR1K 1
# define _LIBUNWIND_CONTEXT_SIZE 16
}
if (_saved_vfp_d16_d31)
restoreVFPv3(_vfp_d16_d31);
+#if defined(__ARM_WMMX)
if (_saved_iwmmx)
restoreiWMMX(_iwmmx);
if (_saved_iwmmx_control)
restoreiWMMXControl(_iwmmx_control);
+#endif
}
private:
static void saveVFPWithFSTMD(unw_fpreg_t*);
static void saveVFPWithFSTMX(unw_fpreg_t*);
static void saveVFPv3(unw_fpreg_t*);
- static void saveiWMMX(unw_fpreg_t*);
- static void saveiWMMXControl(uint32_t*);
static void restoreVFPWithFLDMD(unw_fpreg_t*);
static void restoreVFPWithFLDMX(unw_fpreg_t*);
static void restoreVFPv3(unw_fpreg_t*);
+#if defined(__ARM_WMMX)
+ static void saveiWMMX(unw_fpreg_t*);
+ static void saveiWMMXControl(uint32_t*);
static void restoreiWMMX(unw_fpreg_t*);
static void restoreiWMMXControl(uint32_t*);
+#endif
void restoreCoreAndJumpTo();
// ARM registers
bool _saved_vfp_d0_d15;
// Whether VFPv3 D16-D31 are saved.
bool _saved_vfp_d16_d31;
- // Whether iWMMX data registers are saved.
- bool _saved_iwmmx;
- // Whether iWMMX control registers are saved.
- bool _saved_iwmmx_control;
// VFP registers D0-D15, + padding if saved using FSTMX
unw_fpreg_t _vfp_d0_d15_pad[17];
// VFPv3 registers D16-D31, always saved using FSTMD
unw_fpreg_t _vfp_d16_d31[16];
+#if defined(__ARM_WMMX)
+ // Whether iWMMX data registers are saved.
+ bool _saved_iwmmx;
+ // Whether iWMMX control registers are saved.
+ bool _saved_iwmmx_control;
// iWMMX registers
unw_fpreg_t _iwmmx[16];
// iWMMX control registers
uint32_t _iwmmx_control[4];
+#endif
};
inline Registers_arm::Registers_arm(const void *registers)
: _use_X_for_vfp_save(false),
_saved_vfp_d0_d15(false),
- _saved_vfp_d16_d31(false),
- _saved_iwmmx(false),
- _saved_iwmmx_control(false) {
+ _saved_vfp_d16_d31(false) {
static_assert((check_fit<Registers_arm, unw_context_t>::does_fit),
"arm registers do not fit into unw_context_t");
// See unw_getcontext() note about data.
memcpy(&_registers, registers, sizeof(_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_iwmmx = false;
+ _saved_iwmmx_control = false;
memset(&_iwmmx, 0, sizeof(_iwmmx));
memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+#endif
}
inline Registers_arm::Registers_arm()
: _use_X_for_vfp_save(false),
_saved_vfp_d0_d15(false),
- _saved_vfp_d16_d31(false),
- _saved_iwmmx(false),
- _saved_iwmmx_control(false) {
+ _saved_vfp_d16_d31(false) {
memset(&_registers, 0, sizeof(_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_iwmmx = false;
+ _saved_iwmmx_control = false;
memset(&_iwmmx, 0, sizeof(_iwmmx));
memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+#endif
}
inline bool Registers_arm::validRegister(int regNum) const {
return true;
if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15)
return true;
+#if defined(__ARM_WMMX)
if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3)
return true;
+#endif
return false;
}
return _registers.__pc;
if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
return _registers.__r[regNum];
+#if defined(__ARM_WMMX)
if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
if (!_saved_iwmmx_control) {
_saved_iwmmx_control = true;
}
return _iwmmx_control[regNum - UNW_ARM_WC0];
}
+#endif
_LIBUNWIND_ABORT("unsupported arm register");
}
_registers.__pc = value;
else if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
_registers.__r[regNum] = value;
+#if defined(__ARM_WMMX)
else if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
if (!_saved_iwmmx_control) {
_saved_iwmmx_control = true;
saveiWMMXControl(_iwmmx_control);
}
_iwmmx_control[regNum - UNW_ARM_WC0] = value;
- } else
+ }
+#endif
+ else
_LIBUNWIND_ABORT("unsupported arm register");
}
// NOTE: Consider the intel MMX registers floating points so the
// unw_get_fpreg can be used to transmit the 64-bit data back.
return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31))
- || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15));
+#if defined(__ARM_WMMX)
+ || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15))
+#endif
+ ;
}
inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) {
saveVFPv3(_vfp_d16_d31);
}
return _vfp_d16_d31[regNum - UNW_ARM_D16];
- } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+ }
+#if defined(__ARM_WMMX)
+ else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
if (!_saved_iwmmx) {
_saved_iwmmx = true;
saveiWMMX(_iwmmx);
}
return _iwmmx[regNum - UNW_ARM_WR0];
- } else {
- _LIBUNWIND_ABORT("Unknown ARM float register");
}
+#endif
+ else
+ _LIBUNWIND_ABORT("Unknown ARM float register");
}
inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) {
saveVFPv3(_vfp_d16_d31);
}
_vfp_d16_d31[regNum - UNW_ARM_D16] = value;
- } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+ }
+#if defined(__ARM_WMMX)
+ else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
if (!_saved_iwmmx) {
_saved_iwmmx = true;
saveiWMMX(_iwmmx);
}
_iwmmx[regNum - UNW_ARM_WR0] = value;
- } else {
- _LIBUNWIND_ABORT("Unknown ARM float register");
}
+#endif
+ else
+ _LIBUNWIND_ABORT("Unknown ARM float register");
}
inline bool Registers_arm::validVectorRegister(int) const {
}
case 0xc0: {
switch (byte) {
+#if defined(__ARM_WMMX)
case 0xc0:
case 0xc1:
case 0xc2:
_Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE);
break;
}
+#endif
case 0xc8:
case 0xc9: {
uint8_t v = getByte(data, offset++);
*(unw_word_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
- case _UVRSC_WMMXC:
- if (representation != _UVRSD_UINT32 || regno > 3)
- return _UVRSR_FAILED;
- return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
- *(unw_word_t *)valuep) == UNW_ESUCCESS
- ? _UVRSR_OK
- : _UVRSR_FAILED;
case _UVRSC_VFP:
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED;
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#if defined(__ARM_WMMX)
+ case _UVRSC_WMMXC:
+ if (representation != _UVRSD_UINT32 || regno > 3)
+ return _UVRSR_FAILED;
+ return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
+ *(unw_word_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
case _UVRSC_WMMXD:
if (representation != _UVRSD_DOUBLE || regno > 31)
return _UVRSR_FAILED;
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#endif
}
_LIBUNWIND_ABORT("unsupported register class");
}
(unw_word_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
- case _UVRSC_WMMXC:
- if (representation != _UVRSD_UINT32 || regno > 3)
- return _UVRSR_FAILED;
- return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
- (unw_word_t *)valuep) == UNW_ESUCCESS
- ? _UVRSR_OK
- : _UVRSR_FAILED;
case _UVRSC_VFP:
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED;
(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#if defined(__ARM_WMMX)
+ case _UVRSC_WMMXC:
+ if (representation != _UVRSD_UINT32 || regno > 3)
+ return _UVRSR_FAILED;
+ return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
+ (unw_word_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
case _UVRSC_WMMXD:
if (representation != _UVRSD_DOUBLE || regno > 31)
return _UVRSR_FAILED;
(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#endif
}
_LIBUNWIND_ABORT("unsupported register class");
}
vldmia r0, {d16-d31}
JMP(lr)
+#if defined(__ARM_WMMX)
+
@
@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
@
@
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8
ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8
ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8
ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8
ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8
ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8
-#endif
JMP(lr)
@
@
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4
ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4
ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4
ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4
-#endif
JMP(lr)
+#endif
+
#elif defined(__or1k__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
vstmia r0, {d16-d31}
JMP(lr)
+#if defined(_LIBUNWIND_ARM_WMMX)
+
@
@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
@
@
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8
stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8
stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8
stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8
stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8
-#endif
JMP(lr)
@
@
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4
stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4
-#endif
JMP(lr)
+#endif
+
#elif defined(__or1k__)
#