[lldb] [llvm] [lldb][AArch64][Linux] Handle SME only and kernels < 6.19 (PR #189982)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 1 08:44:35 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: David Spickett (DavidSpickett)
<details>
<summary>Changes</summary>
Part of #<!-- -->138717.
The feature we need to use to restore non-streaming mode after an expression enters streaming mode was only added recently in kernel 6.19.
There is no other way to restore this state, so I have adjusted the code to use the normal FP restore path for every state other than: on an SME only system and in streaming mode and restoring non-streaming state
If that fails, we're on < 6.19 and all we can do is bail out.
I've updated the tests to check kernel version and for < 6.19 remove any expression tests that hit this specific state. I could have set up expected state for them, but it's basically undefined behaviour, and I think it would make the already complex tests even worse.
Documentation now mentions the required version, and release notes link to that documentation.
Tested on an ARM FVP configured to SME only with kernel 6.18 and 6.19, and a Graviton 3 with only SVE.
---
Full diff: https://github.com/llvm/llvm-project/pull/189982.diff
4 Files Affected:
- (modified) lldb/docs/use/aarch64-linux.md (+5-1)
- (modified) lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp (+30-15)
- (modified) lldb/test/API/linux/aarch64/sme_only_registers/TestSMEOnlyRegisters.py (+10)
- (modified) llvm/docs/ReleaseNotes.md (+5-3)
``````````diff
diff --git a/lldb/docs/use/aarch64-linux.md b/lldb/docs/use/aarch64-linux.md
index f48693ab58704..9202b897f1f0b 100644
--- a/lldb/docs/use/aarch64-linux.md
+++ b/lldb/docs/use/aarch64-linux.md
@@ -297,7 +297,11 @@ written to the non-existent non-streaming SVE register set, with the vector
length set to 0 to cause the process to exit streaming mode and apply those
FPSIMD values to the `V` registers.
-This is only used for this purpose. Otherwise, in non-streaming mode FP
+This feature was added in version 6.19 of the Linux kernel. On older versions,
+LLDB will attempt the restore and it will fail. This will result in the mode
+and some register state not being restored.
+
+This feature is only used for this purpose. Otherwise, in non-streaming mode FP
registers are accessed using the FP register set, and in streaming mode using
the streaming SVE register set.
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 193c201f7929d..dee598c945bb1 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -1163,14 +1163,26 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
std::bind(&NativeRegisterContextLinux_arm64::WriteAllSVE, this));
break;
case RegisterSetType::FPR: {
+ m_sve_buffer_is_valid = false;
+ m_sve_header_is_valid = false;
+ m_sve_state = SVEState::Unknown;
+ ConfigureRegisterContext();
+
+ // If we are on an SME only system and currently in streaming mode, about
+ // to restore non-streaming FP data.
if (!GetRegisterInfo().IsSVEPresent() &&
- GetRegisterInfo().IsSSVEPresent()) {
- // On an SME only system, if we get here then we were outside of
- // streaming mode when the registers were saved. We may be in streaming
- // mode at the current moment, so we need to to exit it. The kernel
- // allows us to do this by writing FPSIMD format data to the
- // non-streaming SVE register set, with a vector length of 0 set. This
- // is only done in this specific situation.
+ GetRegisterInfo().IsSSVEPresent() &&
+ m_sve_state == SVEState::Streaming) {
+ // We can only restore this data on kernel versions >= 6.19, so
+ // attempt it and if it fails, we will skip restoring the data.
+ //
+ // To attempt the restore we write FPSIMD format data to NT_ARM_SVE,
+ // with the vector length set to 0. If supported, this will switch
+ // modes from streaming to non-streaming and update the FP registers
+ // with the values we provided.
+ //
+ // This interface is only used by LLDB in this one specific
+ // circumstance.
size_t data_size = sve::ptrace_fpsimd_offset + GetFPRSize();
// NT_ARM_SVE data must be a multiple of 128 bits, and the FPU data size
@@ -1197,16 +1209,19 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
// exiting streaming mode.
error = WriteRegisterSet(&ioVec, sve_fpsimd_data.size(), NT_ARM_SVE);
- // Wrote FPU, and SVE overlaps FPU.
- m_fpu_is_valid = false;
- m_sve_buffer_is_valid = false;
- m_sve_header_is_valid = false;
+ if (error.Success()) {
+ // Wrote FPU, and SVE overlaps FPU.
+ m_fpu_is_valid = false;
+ m_sve_buffer_is_valid = false;
+ m_sve_header_is_valid = false;
- m_sve_state = SVEState::Unknown;
- ConfigureRegisterContext();
+ m_sve_state = SVEState::Unknown;
+ ConfigureRegisterContext();
- // Consume FP register set.
- src += GetFPRSize();
+ // Consume FP register set.
+ src += GetFPRSize();
+ }
+ // Else it failed, and we have no other way to restore the data.
} else {
error = RestoreRegisters(
GetFPRBuffer(), &src, GetFPRSize(), m_fpu_is_valid,
diff --git a/lldb/test/API/linux/aarch64/sme_only_registers/TestSMEOnlyRegisters.py b/lldb/test/API/linux/aarch64/sme_only_registers/TestSMEOnlyRegisters.py
index 9f2ca64267eb2..dee60ae3c7bb9 100644
--- a/lldb/test/API/linux/aarch64/sme_only_registers/TestSMEOnlyRegisters.py
+++ b/lldb/test/API/linux/aarch64/sme_only_registers/TestSMEOnlyRegisters.py
@@ -525,6 +525,16 @@ def test_expr_restore(self):
# Then all combinations of different states.
expr_tests.extend(list(permutations(states, 2)))
+ platform = self.dbg.GetSelectedPlatform()
+ # The feature we use to get from streaming mode back to non-streaming
+ # mode was added in 6.19. Without it we simply cannot restore FP state.
+ # So remove any test going that restores to non-streaming mode
+ # from streaming mode.
+ if not (
+ platform.GetOSMajorVersion() >= 6 and platform.GetOSMinorVersion() >= 19
+ ):
+ expr_tests = list(filter(lambda p: p[1][0] == Mode.SIMD, expr_tests))
+
if self.TraceOn():
print("Expression tests:")
pprint(expr_tests)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 450b65a80c5cd..373301707e2df 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -275,9 +275,11 @@ Changes to LLDB
* On Arm Linux, the tpidruro register can now be read. Writing to this register is not supported.
* Thread local variables are now supported on Arm Linux if the program being debugged is using glibc.
* LLDB now supports AArch64 Linux systems that only have SME (as opposed to
- SVE and SME). Prior to this version of LLDB, there was a bug that caused LLDB
- to crash on startup on these systems
- ([#138717](https://github.com/llvm/llvm-project/issues/138717)).
+ SVE and SME). See the AArch64 Linux [documentation](https://lldb.llvm.org/use/aarch64-linux.html#sme-only-systems)
+ for more details.
+
+ Prior to this version of LLDB, there was a bug that caused LLDB to crash on
+ startup on these systems ([#138717](https://github.com/llvm/llvm-project/issues/138717)).
This affected LLDB versions from 18 up to and including 22. 17 and below are not affected.
If you are using such a system and cannot change LLDB version, or want to package
an affected version in a way that is compatible with these systems, the issue
``````````
</details>
https://github.com/llvm/llvm-project/pull/189982
More information about the llvm-commits
mailing list