mgorny created this revision.
mgorny added reviewers: labath, krytarowski, emaste.
Herald added a subscriber: arichardson.
mgorny requested review of this revision.

// This is work-in-progress, submitted to get proposed API reviewed. No actual 
caching is done yet.
// I am planning to use this for NetBSD and FreeBSD. It will also result in 
some of the code being deduplicated.

Introduce a new API for caching register set reads and writes
in the generic NativeRegisterContextRegisterInfo class.  Use it
in the NetBSD plugin for initial testing.

The implementation provides a generic caching version of ReadRegister()
and WriteRegister() that call virtual methods implemented in actual
NativeRegisterContext* classes.  This should not affect existing
implementations since they override ReadRegister() and WriteRegister()
already.

The hook API consists of five methods that need to be implemented
in NativeRegisterContext* classes:

- GetRegisterSetForRegNum() to map register number to a register set number 
(the latter being opaque to NativeRegisterContextRegisterInfo).

- ReadRegisterSet() and WriteRegisterSet() to respectively read regset into 
cache and write it back.  The actual cache storage is provided by final classes 
(m_gpr, m_fpr...).

- GetRegisterFromCache() and SetRegisterInCache() to respectively get and 
update individual register values inside the cache. The implementation of both 
methods can assume that ReadRegisterSet() has been called to fill the cache, 
and must not call either ReadRegisterSet() or WriteRegisterSet().

Optionally, the classes can also override:

- FlushRegisterSet() method to control how register sets are flushed, in 
particular handling overlapping regsets.

The NativeRegisterContextRegisterInfo class maintains state map of cache
for individual regsets, and issues appropriate ReadRegisterSet()
and WriteRegisterSet() calls to maintain it.  It includes
a FlushRegisterSets() method that needs to be called whenever the thread
is about to resume execution.


https://reviews.llvm.org/D89335

Files:
  lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
  lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
  lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
  lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h

Index: lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h
===================================================================
--- lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h
+++ lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h
@@ -9,11 +9,21 @@
 #ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NATIVEREGISTERCONTEXTREGISTERINFO_H
 #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_NATIVEREGISTERCONTEXTREGISTERINFO_H
 
+#include <cstdint>
+#include <map>
 #include <memory>
 
 #include "RegisterInfoInterface.h"
 #include "lldb/Host/common/NativeRegisterContext.h"
 
+enum class RegSetCacheStatus {
+  Empty,
+  Read,
+  Written,
+};
+
+#define LLDB_INVALID_REGSET UINT32_MAX
+
 namespace lldb_private {
 class NativeRegisterContextRegisterInfo : public NativeRegisterContext {
 public:
@@ -33,8 +43,50 @@
 
   const RegisterInfoInterface &GetRegisterInfoInterface() const;
 
+  Status ReadRegister(const RegisterInfo *reg_info,
+                      RegisterValue &reg_value) override;
+
+  Status WriteRegister(const RegisterInfo *reg_info,
+                       const RegisterValue &reg_value) override;
+
+  Status FlushRegisterSets();
+
 protected:
   std::unique_ptr<RegisterInfoInterface> m_register_info_interface_up;
+
+  // APIs used to implement cached register access, they need to be defined
+  // only if ReadRegister() and WriteRegister() are not overriden
+
+  virtual uint32_t GetRegisterSetForRegNum(uint32_t reg_index) const {
+    return LLDB_INVALID_REGSET;
+  }
+
+  virtual Status ReadRegisterSet(uint32_t set) {
+    return Status("not implemented");
+  }
+
+  virtual Status WriteRegisterSet(uint32_t set) {
+    return Status("not implemented");
+  }
+
+  virtual Status GetRegisterFromCache(const RegisterInfo *reg_info,
+                                      RegisterValue &reg_value, uint32_t set) {
+    return Status("not implemented");
+  }
+
+  virtual Status SetRegisterInCache(const RegisterInfo *reg_info,
+                                    const RegisterValue &reg_value,
+                                    uint32_t set) {
+    return Status("not implemented");
+  }
+
+  virtual Status FlushRegisterSet(uint32_t set);
+
+  // ---------------------------------------------------------------------------
+
+private:
+  std::map<int, RegSetCacheStatus> m_regset_cache_status;
 };
-}
+
+} // namespace lldb_private
 #endif
Index: lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
+++ lldb/source/Plugins/Process/Utility/NativeRegisterContextRegisterInfo.cpp
@@ -40,3 +40,98 @@
 NativeRegisterContextRegisterInfo::GetRegisterInfoInterface() const {
   return *m_register_info_interface_up;
 }
+
+Status
+NativeRegisterContextRegisterInfo::ReadRegister(const RegisterInfo *reg_info,
+                                                RegisterValue &reg_value) {
+  Status error;
+
+  if (!reg_info) {
+    error.SetErrorString("reg_info NULL");
+    return error;
+  }
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  if (reg == LLDB_INVALID_REGNUM) {
+    // This is likely an internal register for lldb use only and should not be
+    // directly queried.
+    error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+                                   "register, cannot read directly",
+                                   reg_info->name);
+    return error;
+  }
+
+  uint32_t set = GetRegisterSetForRegNum(reg);
+  if (set == LLDB_INVALID_REGSET) {
+    // This is likely an internal register for lldb use only and should not be
+    // directly queried.
+    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+                                   reg_info->name);
+    return error;
+  }
+
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  return GetRegisterFromCache(reg_info, reg_value, set);
+}
+
+Status NativeRegisterContextRegisterInfo::WriteRegister(
+    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+
+  Status error;
+
+  if (!reg_info) {
+    error.SetErrorString("reg_info NULL");
+    return error;
+  }
+
+  uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+  if (reg == LLDB_INVALID_REGNUM) {
+    // This is likely an internal register for lldb use only and should not be
+    // directly queried.
+    error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+                                   "register, cannot read directly",
+                                   reg_info->name);
+    return error;
+  }
+
+  uint32_t set = GetRegisterSetForRegNum(reg);
+  if (set == LLDB_INVALID_REGSET) {
+    // This is likely an internal register for lldb use only and should not be
+    // directly queried.
+    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+                                   reg_info->name);
+    return error;
+  }
+
+  error = ReadRegisterSet(set);
+  if (error.Fail())
+    return error;
+
+  error = SetRegisterInCache(reg_info, reg_value, set);
+  if (error.Fail())
+    return error;
+
+  return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextRegisterInfo::FlushRegisterSets() {
+  Status error;
+
+  for (auto kv : m_regset_cache_status) {
+    if (kv.second == RegSetCacheStatus::Empty)
+      continue;
+    error = FlushRegisterSet(kv.first);
+    if (error.Fail())
+      break;
+  }
+
+  return error;
+}
+
+Status NativeRegisterContextRegisterInfo::FlushRegisterSet(uint32_t set) {
+  m_regset_cache_status[set] = RegSetCacheStatus::Empty;
+  return Status();
+}
Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
+++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
@@ -39,12 +39,6 @@
 
   const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
 
-  Status ReadRegister(const RegisterInfo *reg_info,
-                      RegisterValue &reg_value) override;
-
-  Status WriteRegister(const RegisterInfo *reg_info,
-                       const RegisterValue &reg_value) override;
-
   Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
 
   Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
@@ -76,6 +70,19 @@
   Status
   CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override;
 
+protected:
+  uint32_t GetRegisterSetForRegNum(uint32_t reg_index) const override;
+
+  Status ReadRegisterSet(uint32_t set) override;
+  Status WriteRegisterSet(uint32_t set) override;
+
+  Status GetRegisterFromCache(const RegisterInfo *reg_info,
+                              RegisterValue &reg_value,
+                              uint32_t set) override;
+  Status SetRegisterInCache(const RegisterInfo *reg_info,
+                            const RegisterValue &reg_value,
+                            uint32_t set) override;
+
 private:
   // Private member types.
   enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet };
@@ -92,11 +99,7 @@
   struct xstate m_xstate;
 #endif
 
-  int GetSetForNativeRegNum(int reg_num) const;
   int GetDR(int num) const;
-
-  Status ReadRegisterSet(uint32_t set);
-  Status WriteRegisterSet(uint32_t set);
 };
 
 } // namespace process_netbsd
Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
+++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
@@ -263,7 +263,7 @@
 uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
   uint32_t sets = 0;
   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
-    if (GetSetForNativeRegNum(set_index) != -1)
+    if (GetRegisterSetForRegNum(set_index) != LLDB_INVALID_REGNUM)
       ++sets;
   }
 
@@ -395,8 +395,8 @@
   }
 }
 
-int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
-    int reg_num) const {
+uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetForRegNum(
+    uint32_t reg_num) const {
   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
   case llvm::Triple::x86:
     if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386)
@@ -406,9 +406,9 @@
     if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
       return XStateRegSet; // AVX
     if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
-      return -1; // MPXR
+      return LLDB_INVALID_REGSET; // MPXR
     if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
-      return -1; // MPXC
+      return LLDB_INVALID_REGSET; // MPXC
     if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386)
       return DBRegSet; // DBR
     break;
@@ -420,9 +420,9 @@
     if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
       return XStateRegSet; // AVX
     if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
-      return -1; // MPXR
+      return LLDB_INVALID_REGSET; // MPXR
     if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
-      return -1; // MPXC
+      return LLDB_INVALID_REGSET; // MPXC
     if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64)
       return DBRegSet; // DBR
     break;
@@ -484,33 +484,14 @@
 }
 
 Status
-NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
-                                                 RegisterValue &reg_value) {
-  Status error;
+NativeRegisterContextNetBSD_x86_64::GetRegisterFromCache(
+    const RegisterInfo *reg_info, RegisterValue &reg_value, uint32_t set) {
 
-  if (!reg_info) {
-    error.SetErrorString("reg_info NULL");
-    return error;
-  }
+  assert(reg_info);
+  assert(set != LLDB_INVALID_REGSET);
 
+  Status error;
   uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
-  if (reg == LLDB_INVALID_REGNUM) {
-    // This is likely an internal register for lldb use only and should not be
-    // directly queried.
-    error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
-                                   "register, cannot read directly",
-                                   reg_info->name);
-    return error;
-  }
-
-  int set = GetSetForNativeRegNum(reg);
-  if (set == -1) {
-    // This is likely an internal register for lldb use only and should not be
-    // directly queried.
-    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
-                                   reg_info->name);
-    return error;
-  }
 
   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
   case llvm::Triple::x86_64:
@@ -522,10 +503,6 @@
     llvm_unreachable("Unhandled target architecture.");
   }
 
-  error = ReadRegisterSet(set);
-  if (error.Fail())
-    return error;
-
   switch (reg) {
 #if defined(__x86_64__)
   case lldb_rax_x86_64:
@@ -771,34 +748,16 @@
   return error;
 }
 
-Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
-    const RegisterInfo *reg_info, const RegisterValue &reg_value) {
-
-  Status error;
+Status NativeRegisterContextNetBSD_x86_64::SetRegisterInCache(
+    const RegisterInfo *reg_info,
+    const RegisterValue &reg_value,
+    uint32_t set) {
 
-  if (!reg_info) {
-    error.SetErrorString("reg_info NULL");
-    return error;
-  }
+  assert(reg_info);
+  assert(set != LLDB_INVALID_REGSET);
 
+  Status error;
   uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
-  if (reg == LLDB_INVALID_REGNUM) {
-    // This is likely an internal register for lldb use only and should not be
-    // directly queried.
-    error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
-                                   "register, cannot read directly",
-                                   reg_info->name);
-    return error;
-  }
-
-  int set = GetSetForNativeRegNum(reg);
-  if (set == -1) {
-    // This is likely an internal register for lldb use only and should not be
-    // directly queried.
-    error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
-                                   reg_info->name);
-    return error;
-  }
 
   switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
   case llvm::Triple::x86_64:
@@ -810,10 +769,6 @@
     llvm_unreachable("Unhandled target architecture.");
   }
 
-  error = ReadRegisterSet(set);
-  if (error.Fail())
-    return error;
-
   switch (reg) {
 #if defined(__x86_64__)
   case lldb_rax_x86_64:
@@ -1057,7 +1012,7 @@
     llvm_unreachable("Reading unknown/unsupported register");
   }
 
-  return WriteRegisterSet(set);
+  return Status();
 }
 
 Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to