summaryrefslogtreecommitdiffstats
path: root/lib/libunwind/src
diff options
context:
space:
mode:
authorgkoehler <gkoehler@openbsd.org>2020-04-04 14:06:21 +0000
committergkoehler <gkoehler@openbsd.org>2020-04-04 14:06:21 +0000
commit233ed438328db8c587872d7af24be341498239b9 (patch)
treecfd5abc5691ee7ba6bfb0abc80702c833e9da981 /lib/libunwind/src
parentclang bsd.rd is a bit bigger.. (diff)
downloadwireguard-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.hpp16
-rw-r--r--lib/libunwind/src/UnwindRegistersRestore.S12
-rw-r--r--lib/libunwind/src/UnwindRegistersSave.S32
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__)
//