diff options
author | 2020-04-04 14:06:21 +0000 | |
---|---|---|
committer | 2020-04-04 14:06:21 +0000 | |
commit | 233ed438328db8c587872d7af24be341498239b9 (patch) | |
tree | cfd5abc5691ee7ba6bfb0abc80702c833e9da981 /lib/libunwind/src | |
parent | clang bsd.rd is a bit bigger.. (diff) | |
download | wireguard-openbsd-233ed438328db8c587872d7af24be341498239b9.tar.xz wireguard-openbsd-233ed438328db8c587872d7af24be341498239b9.zip |
Fix powerpc libunwind for cpus without altivec.
Defer saving the altivec registers until we need to access them (like
how arm defers saving the VFP registers). This prevents a SIGILL on a
G3 cpu when code throws a C++ exception.
ok kettenis@
Diffstat (limited to 'lib/libunwind/src')
-rw-r--r-- | lib/libunwind/src/Registers.hpp | 16 | ||||
-rw-r--r-- | lib/libunwind/src/UnwindRegistersRestore.S | 12 | ||||
-rw-r--r-- | lib/libunwind/src/UnwindRegistersSave.S | 32 |
3 files changed, 41 insertions, 19 deletions
diff --git a/lib/libunwind/src/Registers.hpp b/lib/libunwind/src/Registers.hpp index 9e69ca8e898..bb23329542e 100644 --- a/lib/libunwind/src/Registers.hpp +++ b/lib/libunwind/src/Registers.hpp @@ -630,7 +630,7 @@ private: unsigned int __lr; /* Link register */ unsigned int __ctr; /* Count register */ unsigned int __mq; /* MQ register (601 only) */ - unsigned int __vrsave; /* Vector Save Register */ + mutable unsigned int __vrsave; /* Vector Save Register */ }; struct ppc_float_state_t { @@ -640,9 +640,11 @@ private: unsigned int __fpscr; /* floating point status register */ }; + void saveVectorRegisters() const; + ppc_thread_state_t _registers; ppc_float_state_t _floatRegisters; - v128 _vectorRegisters[32]; // offset 424 + mutable v128 _vectorRegisters[32]; // offset 424 }; inline Registers_ppc::Registers_ppc(const void *registers) { @@ -657,10 +659,8 @@ inline Registers_ppc::Registers_ppc(const void *registers) { sizeof(_floatRegisters)); static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424, "expected vector register offset to be 424 bytes"); - memcpy(_vectorRegisters, - static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t) + - sizeof(ppc_float_state_t), - sizeof(_vectorRegisters)); + // no values until saveVectorRegisters() + memset(&_vectorRegisters, 0, sizeof(_vectorRegisters)); } inline Registers_ppc::Registers_ppc() { @@ -780,6 +780,7 @@ inline uint32_t Registers_ppc::getRegister(int regNum) const { case UNW_PPC_CR7: return (_registers.__cr & 0x0000000F); case UNW_PPC_VRSAVE: + saveVectorRegisters(); return _registers.__vrsave; } _LIBUNWIND_ABORT("unsupported ppc register"); @@ -932,6 +933,7 @@ inline void Registers_ppc::setRegister(int regNum, uint32_t value) { _registers.__cr |= (value & 0x0000000F); return; case UNW_PPC_VRSAVE: + saveVectorRegisters(); _registers.__vrsave = value; return; // not saved @@ -976,12 +978,14 @@ inline bool Registers_ppc::validVectorRegister(int regNum) const { inline v128 Registers_ppc::getVectorRegister(int regNum) const { assert(validVectorRegister(regNum)); + saveVectorRegisters(); v128 result = _vectorRegisters[regNum - UNW_PPC_V0]; return result; } inline void Registers_ppc::setVectorRegister(int regNum, v128 value) { assert(validVectorRegister(regNum)); + saveVectorRegisters(); _vectorRegisters[regNum - UNW_PPC_V0] = value; } diff --git a/lib/libunwind/src/UnwindRegistersRestore.S b/lib/libunwind/src/UnwindRegistersRestore.S index bca4876dada..494ed42539b 100644 --- a/lib/libunwind/src/UnwindRegistersRestore.S +++ b/lib/libunwind/src/UnwindRegistersRestore.S @@ -476,11 +476,11 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) cmpwi %r5,0 beq Lnovec - subi %r4,%r1,16 - rlwinm %r4,%r4,0,0,27 // mask low 4-bits - // r4 is now a 16-byte aligned pointer into the red zone - // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer - + stwu %r1,-32(%r1) // allocate a stack frame + addi %r4,%r1,16 + clrrwi %r4,%r4,4 + // r4 is now a 16-byte aligned pointer + // the _vectorRegisters may not be 16-byte aligned so copy via r4 #define LOAD_VECTOR_UNALIGNEDl(_index) \ andis. %r0,%r5,(1<<(15-_index)) ;\ @@ -544,6 +544,8 @@ Ldone ## _index: LOAD_VECTOR_UNALIGNEDh(30) LOAD_VECTOR_UNALIGNEDh(31) + addi %r1,%r1,32 // drop the stack frame + Lnovec: lwz %r0, 136(%r3) // __cr mtcrf 255,%r0 diff --git a/lib/libunwind/src/UnwindRegistersSave.S b/lib/libunwind/src/UnwindRegistersSave.S index 27703c54b6c..f2e2ee154fd 100644 --- a/lib/libunwind/src/UnwindRegistersSave.S +++ b/lib/libunwind/src/UnwindRegistersSave.S @@ -599,8 +599,8 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) stw %r30,128(%r3) stw %r31,132(%r3) - // save VRSave register - mfspr %r0,256 + // zero VRSave register; saveVectorRegisters() will save it + li %r0,0 stw %r0,156(%r3) // save CR registers mfcr %r0 @@ -643,12 +643,29 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) stfd %f30,400(%r3) stfd %f31,408(%r3) + li %r3, 0 // return UNW_ESUCCESS + blr - // save vector registers +// +// void libunwind::Registers_ppc::saveVectorRegisters() const +// +// On entry: +// thread_state pointer is in r3 +// +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZNK9libunwind13Registers_ppc19saveVectorRegistersEv) + // return if we have already saved VRsave + lwz %r0,156(%r3) + cmpwi %r0,0 + bnelr + + stwu %r1,-32(%r1) // allocate a stack frame + addi %r4,%r1,16 + clrrwi %r4,%r4,4 + // r4 is now a 16-byte aligned pointer - subi %r4,%r1,16 - rlwinm %r4,%r4,0,0,27 // mask low 4-bits - // r4 is now a 16-byte aligned pointer into the red zone + // save VRsave register + mfvrsave %r0 + stw %r0,156(%r3) #define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ stvx _vec,0,%r4 ;\ @@ -694,10 +711,9 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) SAVE_VECTOR_UNALIGNED(%v30, 424+0x1E0) SAVE_VECTOR_UNALIGNED(%v31, 424+0x1F0) - li %r3, 0 // return UNW_ESUCCESS + addi %r1,%r1,32 // drop the stack frame blr - #elif defined(__arm64__) || defined(__aarch64__) // |