Author: Piotr Kubaj
Date: 2026-07-25T12:11:31-07:00
New Revision: 6b0a46958c56d91e3b2fd5ffecfe163dde1fac3a

URL: 
https://github.com/llvm/llvm-project/commit/6b0a46958c56d91e3b2fd5ffecfe163dde1fac3a
DIFF: 
https://github.com/llvm/llvm-project/commit/6b0a46958c56d91e3b2fd5ffecfe163dde1fac3a.diff

LOG: [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.

Added: 
    

Modified: 
    libunwind/src/UnwindRegistersSave.S

Removed: 
    


################################################################################
diff  --git a/libunwind/src/UnwindRegistersSave.S 
b/libunwind/src/UnwindRegistersSave.S
index 678187fb52f01..37acbf3c69322 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -424,9 +424,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)      \


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to