aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJessica Clarke <jrtc27@FreeBSD.org>2026-07-28 11:54:04 +0000
committerJessica Clarke <jrtc27@FreeBSD.org>2026-07-28 11:54:04 +0000
commit70509d1d9cba254dfd5b3dd83d8a011b5e125788 (patch)
treed87b54d4332476c753e9e9773fe0056a1a588779
parentc6f5d8fb269fd67a8206420b4e7d67a93bc80733 (diff)
Merge commit 6b0a46958c56 from llvm-project (by Piotr Kubaj):
[libunwind][PPC64] Fix unw_getcontext corrupting callee-saved VSX registers on LE (#198371) This is the first of two independent fixes for libunwind on ppc64le (ELFv2 ABI, little-endian), where two separate bugs together cause SIGSEGV during backtracing. This commit addresses the VSX register corruption; the TOC-restore fault is handled in a follow-up. Both were discovered while debugging lang/rust build failures with RUST_BACKTRACE=1 on FreeBSD/powerpc64le (IBM POWER9). On ppc64le, `unw_getcontext` saves each VS register with an in-place `xxswapd n, n` followed by `stxvd2x`. The swap is needed because `stxvd2x` stores doublewords in the wrong order on LE. However, the macro never applies a second `xxswapd` to restore the register after the store, so all 64 VS registers are permanently corrupted on return from `unw_getcontext`. This affects every callee-saved VSX register: f14-f31 (VSR14-VSR31) and VR20-VR31 (VSR52-VSR63). After `_Unwind_Backtrace` returns, any code that uses these registers sees wrong values. In practice this manifests as SIGSEGV inside hashbrown's `reserve_rehash`: VR20-VR31 are corrupted before a SIMD comparison loop runs, producing an out-of-bounds access. Fix: add a second `xxswapd n, n` after the `stxvd2x` store. Since `xxswapd` is its own inverse, the pair is a no-op on the architectural register while still writing the correctly byte-swapped value to memory. MFC after: 1 week
-rw-r--r--contrib/llvm-project/libunwind/src/UnwindRegistersSave.S4
1 files changed, 4 insertions, 0 deletions
diff --git a/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S b/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S
index 5139a551ad24..bd41dfcb9db4 100644
--- a/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S
+++ b/contrib/llvm-project/libunwind/src/UnwindRegistersSave.S
@@ -418,9 +418,13 @@ LnoR2Fix:
// register in the incorrect doubleword order.
// FIXME: when supporting targets older than Power9 on LE is no longer required
// this can be changed to simply `stxv n, 16 * n(4)`.
+// Restore the register after storing: xxswapd is its own inverse, so a second
+// xxswapd undoes the in-place corruption of callee-saved VSRs (f14-f31,
+// VR20-VR31) that would otherwise persist after unw_getcontext returns.
#define PPC64_STVS(n) \
xxswapd n, n ;\
stxvd2x n, 0, 4 ;\
+ xxswapd n, n ;\
addi 4, 4, 16
#else
#define PPC64_STVS(n) \