[Lldb-commits] [lldb] 636d8a2 - [lldb][AArch64][Linux] Track all register cache validity in one place (#197113)

via lldb-commits lldb-commits at lists.llvm.org
Tue Jul 28 02:05:48 PDT 2026


Author: David Spickett
Date: 2026-07-28T10:05:43+01:00
New Revision: 636d8a253e71651ffa75f3bb515a14de0f20341d

URL: https://github.com/llvm/llvm-project/commit/636d8a253e71651ffa75f3bb515a14de0f20341d
DIFF: https://github.com/llvm/llvm-project/commit/636d8a253e71651ffa75f3bb515a14de0f20341d.diff

LOG: [lldb][AArch64][Linux] Track all register cache validity in one place (#197113)

In this change I've expanded the existing RegisterSetType enum
to be used as part of a singular cache tracking object which replaces
all the separate booleans. These booleans were hard to track and 
set/reset in the right places.

This new validity object can be reset by default constructing,
and uses a member initialiser so everything starts out as invalid.

RegisterSetType is now a bitmask enum for easier storage.
It's 32-bit now which is enough for now. Just in case we expand it. 
(and I previously updated all sizeof calls to use RegisterSetType
instead of the raw type)

The SME and SME 2 entries have been renamed to ZA and ZT
as this is what ptrace calls them. Note that SME's pseudo registers
are still managed in their own unique way, I hope to address that
later.

Over time, RegisterSetType will become the key for all the 
operations in the register context. You can see a preview of
that "vision" in #193174.

For instance getting the buffer location and size, looking up
the ptrace set number, finding out what a set write invalidates,
and so on.

I did consider using optional for the register storage. I think this
could work if we had done it from the beginning but starting from
this point it has too many issues with it.

* We cannot assume that sizeof(buffer) == sizeof(buffer_type). Which
leads to some places where you have to write sizeof(some_generic_type).
Which is not ideal. Being able to use the member variable name is
clearer.
* We have to make the buffer "valid" before trying to read, then make it
invalid if it fails. Rather than read and if it succeeds mark it valid.
3 steps vs. 2.
* Some things like SVE resize the buffer when we get the new vector
length, then at some point later assume the buffer can hold the result
of a read. We'd have to track the expected size separately, and use that
to resize it just before read. Which is not difficult, but it's a
different strategy and I don't want to disturb all the SVE/SME handling
at this stage.
* Though our buffer + bool is in theory an optional, the way the class
is designed where one thing fills the buffer and another reads from it
later, the flexibility of when to set the bool does help us. Versus the
automatic handling optional does.

Once this whole class has been simplified and I can see the "unusual"
code paths more easily, I might revisit the optional idea.

Added: 
    

Modified: 
    lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
    lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 3377c8d018629..82d6f8658c30b 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -180,18 +180,6 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
   m_max_hwp_supported = 16;
   m_max_hbp_supported = 16;
 
-  m_gpr_is_valid = false;
-  m_fpu_is_valid = false;
-  m_sve_buffer_is_valid = false;
-  m_sve_header_is_valid = false;
-  m_pac_mask_is_valid = false;
-  m_mte_ctrl_is_valid = false;
-  m_tls_is_valid = false;
-  m_zt_buffer_is_valid = false;
-  m_fpmr_is_valid = false;
-  m_gcs_is_valid = false;
-  m_poe_is_valid = false;
-
   // SME adds the tpidr2 register
   m_tls_size = GetRegisterInfo().IsSSVEPresent() ? sizeof(m_tls_regs)
                                                  : sizeof(m_tls_regs.tpidr_reg);
@@ -623,7 +611,7 @@ Status NativeRegisterContextLinux_arm64::WriteRegister(
         uint64_t vg_value = reg_value.GetAsUInt64();
 
         if (sve::vl_valid(vg_value * 8)) {
-          if (m_sve_header_is_valid && vg_value == GetSVERegVG())
+          if (IsValid(RegisterSetType::SVE_HEADER) && vg_value == GetSVERegVG())
             return error;
 
           SetSVERegVG(vg_value);
@@ -632,11 +620,11 @@ Status NativeRegisterContextLinux_arm64::WriteRegister(
           if (error.Success()) {
             // Changing VG during streaming mode also changes the size of ZA.
             if (m_sve_state == SVEState::Streaming)
-              m_za_header_is_valid = false;
+              Invalidate(RegisterSetType::ZA_HEADER);
             ConfigureRegisterContext();
           }
 
-          if (m_sve_header_is_valid && vg_value == GetSVERegVG())
+          if (IsValid(RegisterSetType::SVE_HEADER) && vg_value == GetSVERegVG())
             return error;
         }
 
@@ -809,7 +797,7 @@ NativeRegisterContextLinux_arm64::CacheAllRegisters(uint32_t &cached_size) {
     cached_size += sizeof(RegisterSetType) + m_za_header.size;
     // For the same reason, we need to force it to be re-read so that it will
     // always contain the real header.
-    m_za_buffer_is_valid = false;
+    Invalidate(RegisterSetType::ZA);
     error = ReadZA();
     if (error.Fail())
       return error;
@@ -939,7 +927,7 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
     // Use the header size not the buffer size, as we may be using the buffer
     // for fake data, which we do not want to write out.
     assert(m_za_header.size <= GetZABufferSize());
-    dst = AddSavedRegisters(dst, RegisterSetType::SME, GetZABuffer(),
+    dst = AddSavedRegisters(dst, RegisterSetType::ZA, GetZABuffer(),
                             m_za_header.size);
   }
 
@@ -956,7 +944,7 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
 
   if ((m_sve_state == SVEState::Streaming) && GetRegisterInfo().IsZAPresent()) {
     assert(m_za_header.size <= GetZABufferSize());
-    dst = AddSavedRegisters(dst, RegisterSetType::SME, GetZABuffer(),
+    dst = AddSavedRegisters(dst, RegisterSetType::ZA, GetZABuffer(),
                             m_za_header.size);
   }
 
@@ -970,7 +958,7 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
       GetRegisterInfo().IsZTPresent() &&
       // And ZA is enabled.
       m_za_header.size > sizeof(m_za_header))
-    dst = AddSavedRegisters(dst, RegisterSetType::SME2, GetZTBuffer(),
+    dst = AddSavedRegisters(dst, RegisterSetType::ZT, GetZTBuffer(),
                             GetZTBufferSize());
 
   if (GetRegisterInfo().IsMTEPresent()) {
@@ -999,10 +987,12 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
   return error;
 }
 
-static Status RestoreRegisters(void *buffer, const uint8_t **src, size_t len,
-                               bool &is_valid, std::function<Status()> writer) {
+Status NativeRegisterContextLinux_arm64::RestoreRegisters(
+    void *buffer, const uint8_t **src, size_t len,
+    const NativeRegisterContextLinux_arm64::RegisterSetType set,
+    std::function<Status()> writer) {
   ::memcpy(buffer, *src, len);
-  is_valid = true;
+  MakeValid(set);
   *src += len;
   return writer();
 }
@@ -1057,7 +1047,7 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
     switch (kind) {
     case RegisterSetType::GPR:
       error = RestoreRegisters(
-          GetGPRBuffer(), &src, GetGPRBufferSize(), m_gpr_is_valid,
+          GetGPRBuffer(), &src, GetGPRBufferSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WriteGPR, this));
       break;
     case RegisterSetType::SVE:
@@ -1069,14 +1059,14 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
       // not want src to be modified yet.
       ::memcpy(GetSVEHeader(), src, GetSVEHeaderSize());
       if (!sve::vl_valid(m_sve_header.vl)) {
-        m_sve_header_is_valid = false;
+        Invalidate(RegisterSetType::SVE_HEADER);
         error = Status::FromErrorStringWithFormat(
             "NativeRegisterContextLinux_arm64::%s "
             "Invalid SVE header in data_sp",
             __FUNCTION__);
         return error;
       }
-      m_sve_header_is_valid = true;
+      MakeValid(RegisterSetType::SVE_HEADER);
       error = WriteSVEHeader();
       if (error.Fail())
         return error;
@@ -1088,12 +1078,11 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
 
       // Write header and register data, incrementing src this time.
       error = RestoreRegisters(
-          GetSVEBuffer(), &src, GetSVEBufferSize(), m_sve_buffer_is_valid,
+          GetSVEBuffer(), &src, GetSVEBufferSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WriteAllSVE, this));
       break;
     case RegisterSetType::FPR: {
-      m_sve_buffer_is_valid = false;
-      m_sve_header_is_valid = false;
+      Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
       m_sve_state = SVEState::Unknown;
       ConfigureRegisterContext();
 
@@ -1144,9 +1133,8 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
 
         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;
+          Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
+                     RegisterSetType::SVE);
 
           m_sve_state = SVEState::Unknown;
           ConfigureRegisterContext();
@@ -1155,22 +1143,22 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
         // the others.
       } else {
         error = RestoreRegisters(
-            GetFPRBuffer(), &src, GetFPRSize(), m_fpu_is_valid,
+            GetFPRBuffer(), &src, GetFPRSize(), kind,
             std::bind(&NativeRegisterContextLinux_arm64::WriteFPR, this));
       }
       break;
     }
     case RegisterSetType::MTE:
       error = RestoreRegisters(
-          GetMTEControl(), &src, GetMTEControlSize(), m_mte_ctrl_is_valid,
+          GetMTEControl(), &src, GetMTEControlSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WriteMTEControl, this));
       break;
     case RegisterSetType::TLS:
       error = RestoreRegisters(
-          GetTLSBuffer(), &src, GetTLSBufferSize(), m_tls_is_valid,
+          GetTLSBuffer(), &src, GetTLSBufferSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WriteTLS, this));
       break;
-    case RegisterSetType::SME:
+    case RegisterSetType::ZA:
       // To enable or disable ZA you write the regset with or without register
       // data. The kernel detects this by looking at the ioVec's length, not the
       // ZA header size you pass in. Therefore we must write header and register
@@ -1182,7 +1170,7 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
       // this so WriteZA uses the correct size.
       m_za_ptrace_payload.resize(m_za_header.size);
       ::memcpy(GetZABuffer(), src, GetZABufferSize());
-      m_za_buffer_is_valid = true;
+      MakeValid(RegisterSetType::ZA);
 
       error = WriteZA();
       if (error.Fail())
@@ -1197,17 +1185,17 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
       error = ReadZA();
       src += GetZABufferSize();
       break;
-    case RegisterSetType::SME2:
+    case RegisterSetType::ZT:
       // Doing this would activate an inactive ZA, however we will only get here
       // if the state we are restoring had an active ZA. Restoring ZT0 will
       // always come after restoring ZA.
       error = RestoreRegisters(
-          GetZTBuffer(), &src, GetZTBufferSize(), m_zt_buffer_is_valid,
+          GetZTBuffer(), &src, GetZTBufferSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WriteZT, this));
       break;
     case RegisterSetType::FPMR:
       error = RestoreRegisters(
-          GetFPMRBuffer(), &src, GetFPMRBufferSize(), m_fpmr_is_valid,
+          GetFPMRBuffer(), &src, GetFPMRBufferSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WriteFPMR, this));
       break;
     case RegisterSetType::GCS: {
@@ -1215,7 +1203,7 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
       // to keep things simple we will not revert any change to the
       // PR_SHADOW_STACK_ENABLE bit. Instead patch in the current enable bit
       // into the registers we are about to restore.
-      m_gcs_is_valid = false;
+      Invalidate(RegisterSetType::GCS);
       error = ReadGCS();
       if (error.Fail())
         return error;
@@ -1229,7 +1217,7 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
       const uint8_t *new_gcs_src =
           reinterpret_cast<const uint8_t *>(&new_gcs_regs);
       error = RestoreRegisters(
-          GetGCSBuffer(), &new_gcs_src, GetGCSBufferSize(), m_gcs_is_valid,
+          GetGCSBuffer(), &new_gcs_src, GetGCSBufferSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WriteGCS, this));
       src += GetGCSBufferSize();
 
@@ -1237,9 +1225,14 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues(
     }
     case RegisterSetType::POE:
       error = RestoreRegisters(
-          GetPOEBuffer(), &src, GetPOEBufferSize(), m_poe_is_valid,
+          GetPOEBuffer(), &src, GetPOEBufferSize(), kind,
           std::bind(&NativeRegisterContextLinux_arm64::WritePOE, this));
       break;
+    case RegisterSetType::PAC:
+    case RegisterSetType::SVE_HEADER:
+    case RegisterSetType::ZA_HEADER:
+      // These are not saved or restored.
+      break;
     }
 
     if (error.Fail())
@@ -1279,7 +1272,7 @@ NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) {
 Status NativeRegisterContextLinux_arm64::ReadGPR() {
   Status error;
 
-  if (m_gpr_is_valid)
+  if (IsValid(RegisterSetType::GPR))
     return error;
 
   struct iovec ioVec;
@@ -1289,7 +1282,7 @@ Status NativeRegisterContextLinux_arm64::ReadGPR() {
   error = ReadRegisterSet(&ioVec, GetGPRBufferSize(), llvm::ELF::NT_PRSTATUS);
 
   if (error.Success())
-    m_gpr_is_valid = true;
+    MakeValid(RegisterSetType::GPR);
 
   return error;
 }
@@ -1303,7 +1296,7 @@ Status NativeRegisterContextLinux_arm64::WriteGPR() {
   ioVec.iov_base = GetGPRBuffer();
   ioVec.iov_len = GetGPRBufferSize();
 
-  m_gpr_is_valid = false;
+  Invalidate(RegisterSetType::GPR);
 
   return WriteRegisterSet(&ioVec, GetGPRBufferSize(), llvm::ELF::NT_PRSTATUS);
 }
@@ -1311,7 +1304,7 @@ Status NativeRegisterContextLinux_arm64::WriteGPR() {
 Status NativeRegisterContextLinux_arm64::ReadFPR() {
   Status error;
 
-  if (m_fpu_is_valid)
+  if (IsValid(RegisterSetType::FPR))
     return error;
 
   struct iovec ioVec;
@@ -1320,7 +1313,7 @@ Status NativeRegisterContextLinux_arm64::ReadFPR() {
 
   error = ReadRegisterSet(&ioVec, GetFPRSize(), llvm::ELF::NT_FPREGSET);
   if (error.Success())
-    m_fpu_is_valid = true;
+    MakeValid(RegisterSetType::FPR);
 
   return error;
 }
@@ -1334,28 +1327,15 @@ Status NativeRegisterContextLinux_arm64::WriteFPR() {
   ioVec.iov_base = GetFPRBuffer();
   ioVec.iov_len = GetFPRSize();
 
-  m_fpu_is_valid = false;
   // SVE Z registers overlap the FP registers.
-  m_sve_buffer_is_valid = false;
-  m_sve_header_is_valid = false;
+  Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
+             RegisterSetType::SVE);
 
   return WriteRegisterSet(&ioVec, GetFPRSize(), llvm::ELF::NT_FPREGSET);
 }
 
 void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() {
-  m_gpr_is_valid = false;
-  m_fpu_is_valid = false;
-  m_sve_buffer_is_valid = false;
-  m_sve_header_is_valid = false;
-  m_za_buffer_is_valid = false;
-  m_za_header_is_valid = false;
-  m_pac_mask_is_valid = false;
-  m_mte_ctrl_is_valid = false;
-  m_tls_is_valid = false;
-  m_zt_buffer_is_valid = false;
-  m_fpmr_is_valid = false;
-  m_gcs_is_valid = false;
-  m_poe_is_valid = false;
+  m_validity = static_cast<RegisterSetType>(0);
 
   // Update SVE and ZA registers in case there is change in configuration.
   ConfigureRegisterContext();
@@ -1374,7 +1354,7 @@ unsigned NativeRegisterContextLinux_arm64::GetSVERegSet() {
 Status NativeRegisterContextLinux_arm64::ReadSVEHeader() {
   Status error;
 
-  if (m_sve_header_is_valid)
+  if (IsValid(RegisterSetType::SVE_HEADER))
     return error;
 
   struct iovec ioVec;
@@ -1384,7 +1364,7 @@ Status NativeRegisterContextLinux_arm64::ReadSVEHeader() {
   error = ReadRegisterSet(&ioVec, GetSVEHeaderSize(), GetSVERegSet());
 
   if (error.Success())
-    m_sve_header_is_valid = true;
+    MakeValid(RegisterSetType::SVE_HEADER);
 
   return error;
 }
@@ -1392,7 +1372,7 @@ Status NativeRegisterContextLinux_arm64::ReadSVEHeader() {
 Status NativeRegisterContextLinux_arm64::ReadPAuthMask() {
   Status error;
 
-  if (m_pac_mask_is_valid)
+  if (IsValid(RegisterSetType::PAC))
     return error;
 
   struct iovec ioVec;
@@ -1402,7 +1382,7 @@ Status NativeRegisterContextLinux_arm64::ReadPAuthMask() {
   error = ReadRegisterSet(&ioVec, GetPACMaskSize(), llvm::ELF::NT_ARM_PAC_MASK);
 
   if (error.Success())
-    m_pac_mask_is_valid = true;
+    MakeValid(RegisterSetType::PAC);
 
   return error;
 }
@@ -1418,16 +1398,15 @@ Status NativeRegisterContextLinux_arm64::WriteSVEHeader() {
   ioVec.iov_base = GetSVEHeader();
   ioVec.iov_len = GetSVEHeaderSize();
 
-  m_sve_buffer_is_valid = false;
-  m_sve_header_is_valid = false;
-  m_fpu_is_valid = false;
+  Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
+             RegisterSetType::SVE);
 
   return WriteRegisterSet(&ioVec, GetSVEHeaderSize(), GetSVERegSet());
 }
 
 Status NativeRegisterContextLinux_arm64::ReadAllSVE() {
   Status error;
-  if (m_sve_buffer_is_valid)
+  if (IsValid(RegisterSetType::SVE))
     return error;
 
   struct iovec ioVec;
@@ -1437,7 +1416,7 @@ Status NativeRegisterContextLinux_arm64::ReadAllSVE() {
   error = ReadRegisterSet(&ioVec, GetSVEBufferSize(), GetSVERegSet());
 
   if (error.Success())
-    m_sve_buffer_is_valid = true;
+    MakeValid(RegisterSetType::SVE);
 
   return error;
 }
@@ -1454,9 +1433,8 @@ Status NativeRegisterContextLinux_arm64::WriteAllSVE() {
   ioVec.iov_base = GetSVEBuffer();
   ioVec.iov_len = GetSVEBufferSize();
 
-  m_sve_buffer_is_valid = false;
-  m_sve_header_is_valid = false;
-  m_fpu_is_valid = false;
+  Invalidate(RegisterSetType::FPR, RegisterSetType::SVE_HEADER,
+             RegisterSetType::SVE);
 
   return WriteRegisterSet(&ioVec, GetSVEBufferSize(), GetSVERegSet());
 }
@@ -1482,7 +1460,7 @@ Status NativeRegisterContextLinux_arm64::ReadSMEControl() {
 Status NativeRegisterContextLinux_arm64::ReadMTEControl() {
   Status error;
 
-  if (m_mte_ctrl_is_valid)
+  if (IsValid(RegisterSetType::MTE))
     return error;
 
   struct iovec ioVec;
@@ -1493,7 +1471,7 @@ Status NativeRegisterContextLinux_arm64::ReadMTEControl() {
                           llvm::ELF::NT_ARM_TAGGED_ADDR_CTRL);
 
   if (error.Success())
-    m_mte_ctrl_is_valid = true;
+    MakeValid(RegisterSetType::MTE);
 
   return error;
 }
@@ -1509,7 +1487,7 @@ Status NativeRegisterContextLinux_arm64::WriteMTEControl() {
   ioVec.iov_base = GetMTEControl();
   ioVec.iov_len = GetMTEControlSize();
 
-  m_mte_ctrl_is_valid = false;
+  Invalidate(RegisterSetType::MTE);
 
   return WriteRegisterSet(&ioVec, GetMTEControlSize(),
                           llvm::ELF::NT_ARM_TAGGED_ADDR_CTRL);
@@ -1518,7 +1496,7 @@ Status NativeRegisterContextLinux_arm64::WriteMTEControl() {
 Status NativeRegisterContextLinux_arm64::ReadTLS() {
   Status error;
 
-  if (m_tls_is_valid)
+  if (IsValid(RegisterSetType::TLS))
     return error;
 
   struct iovec ioVec;
@@ -1528,7 +1506,7 @@ Status NativeRegisterContextLinux_arm64::ReadTLS() {
   error = ReadRegisterSet(&ioVec, GetTLSBufferSize(), llvm::ELF::NT_ARM_TLS);
 
   if (error.Success())
-    m_tls_is_valid = true;
+    MakeValid(RegisterSetType::TLS);
 
   return error;
 }
@@ -1544,7 +1522,7 @@ Status NativeRegisterContextLinux_arm64::WriteTLS() {
   ioVec.iov_base = GetTLSBuffer();
   ioVec.iov_len = GetTLSBufferSize();
 
-  m_tls_is_valid = false;
+  Invalidate(RegisterSetType::TLS);
 
   return WriteRegisterSet(&ioVec, GetTLSBufferSize(), llvm::ELF::NT_ARM_TLS);
 }
@@ -1552,7 +1530,7 @@ Status NativeRegisterContextLinux_arm64::WriteTLS() {
 Status NativeRegisterContextLinux_arm64::ReadGCS() {
   Status error;
 
-  if (m_gcs_is_valid)
+  if (IsValid(RegisterSetType::GCS))
     return error;
 
   struct iovec ioVec;
@@ -1562,7 +1540,7 @@ Status NativeRegisterContextLinux_arm64::ReadGCS() {
   error = ReadRegisterSet(&ioVec, GetGCSBufferSize(), llvm::ELF::NT_ARM_GCS);
 
   if (error.Success())
-    m_gcs_is_valid = true;
+    MakeValid(RegisterSetType::GCS);
 
   return error;
 }
@@ -1578,7 +1556,7 @@ Status NativeRegisterContextLinux_arm64::WriteGCS() {
   ioVec.iov_base = GetGCSBuffer();
   ioVec.iov_len = GetGCSBufferSize();
 
-  m_gcs_is_valid = false;
+  Invalidate(RegisterSetType::GCS);
 
   return WriteRegisterSet(&ioVec, GetGCSBufferSize(), llvm::ELF::NT_ARM_GCS);
 }
@@ -1586,7 +1564,7 @@ Status NativeRegisterContextLinux_arm64::WriteGCS() {
 Status NativeRegisterContextLinux_arm64::ReadZAHeader() {
   Status error;
 
-  if (m_za_header_is_valid)
+  if (IsValid(RegisterSetType::ZA_HEADER))
     return error;
 
   struct iovec ioVec;
@@ -1596,7 +1574,7 @@ Status NativeRegisterContextLinux_arm64::ReadZAHeader() {
   error = ReadRegisterSet(&ioVec, GetZAHeaderSize(), llvm::ELF::NT_ARM_ZA);
 
   if (error.Success())
-    m_za_header_is_valid = true;
+    MakeValid(RegisterSetType::ZA_HEADER);
 
   return error;
 }
@@ -1604,7 +1582,7 @@ Status NativeRegisterContextLinux_arm64::ReadZAHeader() {
 Status NativeRegisterContextLinux_arm64::ReadZA() {
   Status error;
 
-  if (m_za_buffer_is_valid)
+  if (IsValid(RegisterSetType::ZA))
     return error;
 
   struct iovec ioVec;
@@ -1614,7 +1592,7 @@ Status NativeRegisterContextLinux_arm64::ReadZA() {
   error = ReadRegisterSet(&ioVec, GetZABufferSize(), llvm::ELF::NT_ARM_ZA);
 
   if (error.Success())
-    m_za_buffer_is_valid = true;
+    MakeValid(RegisterSetType::ZA);
 
   return error;
 }
@@ -1633,10 +1611,9 @@ Status NativeRegisterContextLinux_arm64::WriteZA() {
   ioVec.iov_base = GetZABuffer();
   ioVec.iov_len = GetZABufferSize();
 
-  m_za_buffer_is_valid = false;
-  m_za_header_is_valid = false;
-  // Writing to ZA may enable ZA, which means ZT0 may change too.
-  m_zt_buffer_is_valid = false;
+  Invalidate(RegisterSetType::ZA_HEADER, RegisterSetType::ZA,
+             // Writing to ZA may enable ZA, which means ZT0 may change too.
+             RegisterSetType::ZT);
 
   return WriteRegisterSet(&ioVec, GetZABufferSize(), llvm::ELF::NT_ARM_ZA);
 }
@@ -1644,7 +1621,7 @@ Status NativeRegisterContextLinux_arm64::WriteZA() {
 Status NativeRegisterContextLinux_arm64::ReadZT() {
   Status error;
 
-  if (m_zt_buffer_is_valid)
+  if (IsValid(RegisterSetType::ZT))
     return error;
 
   struct iovec ioVec;
@@ -1652,7 +1629,8 @@ Status NativeRegisterContextLinux_arm64::ReadZT() {
   ioVec.iov_len = GetZTBufferSize();
 
   error = ReadRegisterSet(&ioVec, GetZTBufferSize(), llvm::ELF::NT_ARM_ZT);
-  m_zt_buffer_is_valid = error.Success();
+  if (error.Success())
+    MakeValid(RegisterSetType::ZT);
 
   return error;
 }
@@ -1668,11 +1646,10 @@ Status NativeRegisterContextLinux_arm64::WriteZT() {
   ioVec.iov_base = GetZTBuffer();
   ioVec.iov_len = GetZTBufferSize();
 
-  m_zt_buffer_is_valid = false;
-  // Writing to an inactive ZT0 will enable ZA as well, which invalidates our
-  // current copy of it.
-  m_za_buffer_is_valid = false;
-  m_za_header_is_valid = false;
+  Invalidate(RegisterSetType::ZT,
+             // Writing to an inactive ZT0 will enable ZA as well,
+             // which invalidates our current copy of it.
+             RegisterSetType::ZA_HEADER, RegisterSetType::ZA);
 
   return WriteRegisterSet(&ioVec, GetZTBufferSize(), llvm::ELF::NT_ARM_ZT);
 }
@@ -1680,7 +1657,7 @@ Status NativeRegisterContextLinux_arm64::WriteZT() {
 Status NativeRegisterContextLinux_arm64::ReadFPMR() {
   Status error;
 
-  if (m_fpmr_is_valid)
+  if (IsValid(RegisterSetType::FPMR))
     return error;
 
   struct iovec ioVec;
@@ -1690,7 +1667,7 @@ Status NativeRegisterContextLinux_arm64::ReadFPMR() {
   error = ReadRegisterSet(&ioVec, GetFPMRBufferSize(), llvm::ELF::NT_ARM_FPMR);
 
   if (error.Success())
-    m_fpmr_is_valid = true;
+    MakeValid(RegisterSetType::FPMR);
 
   return error;
 }
@@ -1706,7 +1683,7 @@ Status NativeRegisterContextLinux_arm64::WriteFPMR() {
   ioVec.iov_base = GetFPMRBuffer();
   ioVec.iov_len = GetFPMRBufferSize();
 
-  m_fpmr_is_valid = false;
+  Invalidate(RegisterSetType::FPMR);
 
   return WriteRegisterSet(&ioVec, GetFPMRBufferSize(), llvm::ELF::NT_ARM_FPMR);
 }
@@ -1714,7 +1691,7 @@ Status NativeRegisterContextLinux_arm64::WriteFPMR() {
 Status NativeRegisterContextLinux_arm64::ReadPOE() {
   Status error;
 
-  if (m_poe_is_valid)
+  if (IsValid(RegisterSetType::POE))
     return error;
 
   struct iovec ioVec;
@@ -1724,7 +1701,7 @@ Status NativeRegisterContextLinux_arm64::ReadPOE() {
   error = ReadRegisterSet(&ioVec, GetPOEBufferSize(), llvm::ELF::NT_ARM_POE);
 
   if (error.Success())
-    m_poe_is_valid = true;
+    MakeValid(RegisterSetType::POE);
 
   return error;
 }
@@ -1740,7 +1717,7 @@ Status NativeRegisterContextLinux_arm64::WritePOE() {
   ioVec.iov_base = GetPOEBuffer();
   ioVec.iov_len = GetPOEBufferSize();
 
-  m_poe_is_valid = false;
+  Invalidate(RegisterSetType::POE);
 
   return WriteRegisterSet(&ioVec, GetPOEBufferSize(), llvm::ELF::NT_ARM_POE);
 }
@@ -1751,14 +1728,14 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
   // streaming SVE mode.
   // If m_sve_state is set to SVEState::Disabled on first stop, code below will
   // be deemed non operational for the lifetime of current process.
-  if (!m_sve_header_is_valid && m_sve_state != SVEState::Disabled) {
+  if (!IsValid(RegisterSetType::SVE_HEADER) &&
+      m_sve_state != SVEState::Disabled) {
     // Systems may have SVE and/or SME. If they are SME only, the SVE regset
     // cannot be read from but the SME one can. If they have both SVE and SME,
     // only the active mode will return valid register data.
 
     // Check for SME.
-    m_sve_header_is_valid = false;
-    m_sve_buffer_is_valid = false;
+    Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
     m_sve_state = SVEState::Streaming;
     Status error = ReadSVEHeader();
 
@@ -1768,8 +1745,7 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
         ((m_sve_header.flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve);
 
     // Check for SVE.
-    m_sve_header_is_valid = false;
-    m_sve_buffer_is_valid = false;
+    Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
     m_sve_state = SVEState::Full;
     error = ReadSVEHeader();
 
@@ -1798,9 +1774,7 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
     if (m_sve_state == SVEState::Full || m_sve_state == SVEState::FPSIMD ||
         m_sve_state == SVEState::Streaming ||
         m_sve_state == SVEState::StreamingFPSIMD) {
-
-      m_sve_header_is_valid = false;
-      m_sve_buffer_is_valid = false;
+      Invalidate(RegisterSetType::SVE_HEADER, RegisterSetType::SVE);
       error = ReadSVEHeader();
 
       // On every stop we configure SVE vector length by calling
@@ -1814,7 +1788,7 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
     }
   }
 
-  if (!m_za_header_is_valid) {
+  if (!IsValid(RegisterSetType::ZA_HEADER)) {
     Status error = ReadZAHeader();
     if (error.Success()) {
       uint32_t vq = RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64SVE;
@@ -1823,7 +1797,7 @@ void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
 
       GetRegisterInfo().ConfigureVectorLengthZA(vq);
       m_za_ptrace_payload.resize(m_za_header.size);
-      m_za_buffer_is_valid = false;
+      Invalidate(RegisterSetType::ZA);
     }
   }
 }

diff  --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
index 41266f7082880..0414e5b6e612d 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -16,6 +16,8 @@
 #include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
+#include "llvm/ADT/BitmaskEnum.h"
+
 #include <asm/ptrace.h>
 
 namespace lldb_private {
@@ -79,36 +81,58 @@ class NativeRegisterContextLinux_arm64
   lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) override;
 
 private:
-  enum RegisterSetType : uint32_t {
-    GPR, // General purpose registers.
-    SVE, // Used for SVE registers in streaming or non-streaming mode.
-    FPR, // When there is no SVE, or SVE in FPSIMD mode, or streaming only SVE
-         // that is in non-streaming mode.
-    // Pointer authentication registers are read only, so not included here.
-    MTE,  // Memory tagging control registers.
-    TLS,  // Thread local storage registers.
-    SME,  // ZA only, because SVCR and SVG are pseudo registers.
-    SME2, // ZT only.
-    FPMR, // Floating point mode control registers.
-    GCS,  // Guarded Control Stack registers.
-    POE,  // Permission Overlay registers.
+  // Bit mask enum used to refer to the types of registers we support. Currently
+  // used for tracking cache validity and ReadAll/WriteAllRegister data. Will
+  // be used for much more in future.
+  enum class RegisterSetType : uint32_t {
+    // General purpose registers.
+    GPR = 1 << 0,
+    // When there is no SVE, or SVE in FPSIMD mode, or streaming only SVE that
+    // is in non-streaming mode.
+    FPR = 1 << 1,
+    // Used for SVE registers in streaming or non-streaming mode.
+    SVE = 1 << 2,
+    // Only the ptrace header for SVE.
+    SVE_HEADER = 1 << 3,
+    // Pointer authentication mask registers.
+    PAC = 1 << 4,
+    // Memory tagging control registers.
+    MTE = 1 << 5,
+    // Thread local storage registers.
+    TLS = 1 << 6,
+    // ZA only, because SVCR and SVG are pseudo registers.
+    ZA = 1 << 7,
+    // Only the ptrace header for ZA.
+    ZA_HEADER = 1 << 8,
+    // ZT only.
+    ZT = 1 << 9,
+    // Floating point mode control registers.
+    FPMR = 1 << 10,
+    // Guarded Control Stack registers.
+    GCS = 1 << 11,
+    // Permission Overlay registers.
+    POE = 1 << 12,
+    LLVM_MARK_AS_BITMASK_ENUM(POE),
   };
 
-  bool m_gpr_is_valid;
-  bool m_fpu_is_valid;
-  bool m_sve_buffer_is_valid;
-  bool m_mte_ctrl_is_valid;
-  bool m_zt_buffer_is_valid;
-  bool m_fpmr_is_valid;
-
-  bool m_sve_header_is_valid;
-  bool m_za_buffer_is_valid;
-  bool m_za_header_is_valid;
-  bool m_pac_mask_is_valid;
-  bool m_tls_is_valid;
+  RegisterSetType m_validity = static_cast<RegisterSetType>(0);
+
+  void MakeValid(RegisterSetType set) { m_validity |= set; }
+
+  [[nodiscard]] bool IsValid(RegisterSetType set) const {
+    return any(m_validity & set);
+  }
+
+  template <typename... Ts> void Invalidate(RegisterSetType first, Ts... rest) {
+    static_assert((std::is_same_v<Ts, RegisterSetType> && ...));
+    m_validity &= ~(first | ... | rest);
+  }
+
+  Status RestoreRegisters(void *buffer, const uint8_t **src, size_t len,
+                          const RegisterSetType set,
+                          std::function<Status()> writer);
+
   size_t m_tls_size = 0;
-  bool m_gcs_is_valid;
-  bool m_poe_is_valid;
 
   /// 64-bit general purpose registers.
   struct user_pt_regs m_gpr_arm64{};


        


More information about the lldb-commits mailing list