git: ac26e70f96c0 - stable/15 - Merge commit 6b0a46958c56 from llvm-project (by Piotr Kubaj):

Jessica Clarke <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a74cc70.31cd8.6716e0fc__39878.146855493$1786039463$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by jrtc27:

URL: https://cgit.FreeBSD.org/src/commit/?id=ac26e70f96c0d4acd9b1ece52c8768784f2586f8

commit ac26e70f96c0d4acd9b1ece52c8768784f2586f8
Author:     Jessica Clarke <[email protected]>
AuthorDate: 2026-07-28 11:54:04 +0000
Commit:     Jessica Clarke <[email protected]>
CommitDate: 2026-08-06 18:02:34 +0000

    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
    
    (cherry picked from commit 70509d1d9cba254dfd5b3dd83d8a011b5e125788)
---
 contrib/llvm-project/libunwind/src/UnwindRegistersSave.S | 4 ++++
 1 file changed, 4 insertions(+)

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)      \
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.