[Lldb-commits] [lldb] [LLDB][Process/Utility] Introduce NativeRegisterContextDBReg class (PR #118043)

via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 10 22:22:32 PST 2024


https://github.com/wangleiat updated https://github.com/llvm/llvm-project/pull/118043

>From a7cba7ef089a6f2004b1879d30675652729370e5 Mon Sep 17 00:00:00 2001
From: wanglei <wanglei at loongson.cn>
Date: Fri, 29 Nov 2024 10:43:31 +0800
Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.5-bogner
---
 ...NativeRegisterContextLinux_loongarch64.cpp | 484 ++++++++++++++++++
 .../NativeRegisterContextLinux_loongarch64.h  |  60 +++
 .../GDBRemoteCommunicationServerCommon.cpp    |   3 +-
 lldb/source/Target/Process.cpp                |   3 +-
 4 files changed, 548 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
index f4d1bb297049da..1f73bd0467962d 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
@@ -11,7 +11,9 @@
 #include "NativeRegisterContextLinux_loongarch64.h"
 
 #include "lldb/Host/HostInfo.h"
+#include "lldb/Host/linux/Ptrace.h"
 #include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/Status.h"
@@ -32,6 +34,19 @@ using namespace lldb;
 using namespace lldb_private;
 using namespace lldb_private::process_linux;
 
+// CTRL_PLV3_ENABLE, used to enable breakpoint/watchpoint
+constexpr uint32_t g_enable_bit = 0x10;
+
+// Returns appropriate control register bits for the specified size
+// size encoded:
+// case 1 : 0b11
+// case 2 : 0b10
+// case 4 : 0b01
+// case 8 : 0b00
+static inline uint64_t GetSizeBits(int size) {
+  return (3 - llvm::Log2_32(size)) << 10;
+}
+
 std::unique_ptr<NativeRegisterContextLinux>
 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
@@ -61,6 +76,8 @@ NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64(
       NativeRegisterContextLinux(native_thread) {
   ::memset(&m_fpr, 0, sizeof(m_fpr));
   ::memset(&m_gpr, 0, sizeof(m_gpr));
+  ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
+  ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
 
   m_gpr_is_valid = false;
   m_fpu_is_valid = false;
@@ -337,4 +354,471 @@ NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
   return expedited_reg_nums;
 }
 
+uint32_t
+NativeRegisterContextLinux_loongarch64::NumSupportedHardwareBreakpoints() {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+
+  if (error.Fail()) {
+    LLDB_LOG(log, "failed to read debug registers");
+    return 0;
+  }
+
+  LLDB_LOG(log, "{0}", m_max_hbp_supported);
+  return m_max_hbp_supported;
+}
+
+uint32_t
+NativeRegisterContextLinux_loongarch64::SetHardwareBreakpoint(lldb::addr_t addr,
+                                                              size_t size) {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+  LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log, "unable to set breakpoint: failed to read debug registers");
+    return LLDB_INVALID_INDEX32;
+  }
+
+  uint32_t bp_index = 0;
+
+  // Check if size has a valid hardware breakpoint length.
+  if (size != 4)
+    return LLDB_INVALID_INDEX32; // Invalid size for a LoongArch hardware
+                                 // breakpoint
+
+  // Check 4-byte alignment for hardware breakpoint target address.
+  if (addr & 0x03)
+    return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
+
+  // Iterate over stored breakpoints and find a free bp_index
+  bp_index = LLDB_INVALID_INDEX32;
+  for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+    if (!BreakpointIsEnabled(i))
+      bp_index = i; // Mark last free slot
+    else if (m_hbp_regs[i].address == addr)
+      return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
+  }
+
+  if (bp_index == LLDB_INVALID_INDEX32)
+    return LLDB_INVALID_INDEX32;
+
+  // Update breakpoint in local cache
+  m_hbp_regs[bp_index].address = addr;
+  m_hbp_regs[bp_index].control = g_enable_bit;
+
+  // PTRACE call to set corresponding hardware breakpoint register.
+  error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+  if (error.Fail()) {
+    m_hbp_regs[bp_index].address = 0;
+    m_hbp_regs[bp_index].control = 0;
+
+    LLDB_LOG(log, "unable to set breakpoint: failed to write debug registers");
+    return LLDB_INVALID_INDEX32;
+  }
+
+  return bp_index;
+}
+bool NativeRegisterContextLinux_loongarch64::ClearHardwareBreakpoint(
+    uint32_t hw_idx) {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+  LLDB_LOG(log, "hw_idx: {0}", hw_idx);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log, "unable to clear breakpoint: failed to read debug registers");
+    return false;
+  }
+
+  if (hw_idx >= m_max_hbp_supported)
+    return false;
+
+  // Create a backup we can revert to in case of failure.
+  lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;
+  uint32_t tempControl = m_hbp_regs[hw_idx].control;
+
+  m_hbp_regs[hw_idx].control = 0;
+  m_hbp_regs[hw_idx].address = 0;
+
+  // PTRACE call to clear corresponding hardware breakpoint register.
+  error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+  if (error.Fail()) {
+    m_hbp_regs[hw_idx].control = tempControl;
+    m_hbp_regs[hw_idx].address = tempAddr;
+
+    LLDB_LOG(log,
+             "unable to clear breakpoint: failed to write debug registers");
+    return false;
+  }
+
+  return true;
+}
+Status NativeRegisterContextLinux_loongarch64::GetHardwareBreakHitIndex(
+    uint32_t &bp_index, lldb::addr_t trap_addr) {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+
+  LLDB_LOGF(log, "NativeRegisterContextLinux_loongarch64::%s()", __FUNCTION__);
+
+  lldb::addr_t break_addr;
+
+  for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
+    break_addr = m_hbp_regs[bp_index].address;
+
+    if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {
+      m_hbp_regs[bp_index].hit_addr = trap_addr;
+      return Status();
+    }
+  }
+
+  bp_index = LLDB_INVALID_INDEX32;
+  return Status();
+}
+Status NativeRegisterContextLinux_loongarch64::ClearAllHardwareBreakpoints() {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+
+  LLDB_LOGF(log, "NativeRegisterContextLinux_loongarch64::%s()", __FUNCTION__);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail())
+    return error;
+
+  for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+    if (!BreakpointIsEnabled(i))
+      continue;
+    // Create a backup we can revert to in case of failure.
+    lldb::addr_t tempAddr = m_hbp_regs[i].address;
+    uint32_t tempControl = m_hbp_regs[i].control;
+
+    // Clear watchpoints in local cache
+    m_hbp_regs[i].control = 0;
+    m_hbp_regs[i].address = 0;
+
+    // Ptrace call to update hardware debug registers
+    error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+    if (error.Fail()) {
+      m_hbp_regs[i].control = tempControl;
+      m_hbp_regs[i].address = tempAddr;
+
+      return error;
+    }
+  }
+
+  return Status();
+}
+bool NativeRegisterContextLinux_loongarch64::BreakpointIsEnabled(
+    uint32_t bp_index) {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+  LLDB_LOG(log, "bp_index: {0}", bp_index);
+  return ((m_hbp_regs[bp_index].control & g_enable_bit) != 0);
+}
+
+uint32_t
+NativeRegisterContextLinux_loongarch64::NumSupportedHardwareWatchpoints() {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log, "failed to read debug registers");
+    return 0;
+  }
+
+  return m_max_hwp_supported;
+}
+
+uint32_t NativeRegisterContextLinux_loongarch64::SetHardwareWatchpoint(
+    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
+           watch_flags);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+
+  if (error.Fail()) {
+    LLDB_LOG(log, "unable to set watchpoint: failed to read debug registers");
+    return LLDB_INVALID_INDEX32;
+  }
+
+  uint32_t control_value = 0, wp_index = 0;
+
+  // Check if we are setting watchpoint other than read/write/access Update
+  // watchpoint flag to match loongarch64 write-read bit configuration.
+  switch (watch_flags) {
+  case eWatchpointKindWrite:
+    watch_flags = 2;
+    break;
+  case eWatchpointKindRead:
+    watch_flags = 1;
+    break;
+  case (eWatchpointKindRead | eWatchpointKindWrite):
+    break;
+  default:
+    return LLDB_INVALID_INDEX32;
+  }
+
+  // Check if size has a valid hardware watchpoint length.
+  if (size != 1 && size != 2 && size != 4 && size != 8)
+    return LLDB_INVALID_INDEX32;
+
+  // Setup control value
+  control_value = g_enable_bit | GetSizeBits(size);
+  control_value |= watch_flags << 8;
+
+  // Iterate over stored watchpoints and find a free wp_index
+  wp_index = LLDB_INVALID_INDEX32;
+  for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+    if (!WatchpointIsEnabled(i)) {
+      wp_index = i; // Mark last free slot
+    } else if (m_hwp_regs[i].address == addr) {
+      return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
+    }
+  }
+
+  if (wp_index == LLDB_INVALID_INDEX32)
+    return LLDB_INVALID_INDEX32;
+
+  // Update watchpoint in local cache
+  m_hwp_regs[wp_index].address = addr;
+  m_hwp_regs[wp_index].control = control_value;
+
+  // PTRACE call to set corresponding watchpoint register.
+  error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+  if (error.Fail()) {
+    m_hwp_regs[wp_index].address = 0;
+    m_hwp_regs[wp_index].control = 0;
+
+    LLDB_LOG(log, "unable to set watchpoint: failed to write debug registers");
+    return LLDB_INVALID_INDEX32;
+  }
+
+  return wp_index;
+}
+
+bool NativeRegisterContextLinux_loongarch64::ClearHardwareWatchpoint(
+    uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+
+  if (error.Fail()) {
+    LLDB_LOG(log, "unable to clear watchpoint: failed to read debug registers");
+    return false;
+  }
+
+  if (wp_index >= m_max_hwp_supported)
+    return false;
+
+  // Create a backup we can revert to in case of failure.
+  lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
+  uint32_t tempControl = m_hwp_regs[wp_index].control;
+
+  // Update watchpoint in local cache
+  m_hwp_regs[wp_index].control = 0;
+  m_hwp_regs[wp_index].address = 0;
+
+  // Ptrace call to update hardware debug registers
+  error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+  if (error.Fail()) {
+    m_hwp_regs[wp_index].control = tempControl;
+    m_hwp_regs[wp_index].address = tempAddr;
+
+    LLDB_LOG(log, "unable to clear watchpoint: failed to read debug registers");
+    return false;
+  }
+
+  return true;
+}
+
+Status NativeRegisterContextLinux_loongarch64::ClearAllHardwareWatchpoints() {
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail())
+    return error;
+
+  for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+    if (!WatchpointIsEnabled(i))
+      continue;
+    // Create a backup we can revert to in case of failure.
+    lldb::addr_t tempAddr = m_hwp_regs[i].address;
+    uint32_t tempControl = m_hwp_regs[i].control;
+
+    // Clear watchpoints in local cache
+    m_hwp_regs[i].control = 0;
+    m_hwp_regs[i].address = 0;
+
+    // Ptrace call to update hardware debug registers
+    error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+    if (error.Fail()) {
+      m_hwp_regs[i].control = tempControl;
+      m_hwp_regs[i].address = tempAddr;
+
+      return error;
+    }
+  }
+
+  return Status();
+}
+
+uint32_t
+NativeRegisterContextLinux_loongarch64::GetWatchpointSize(uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  switch ((m_hwp_regs[wp_index].control >> 10) & 0x3) {
+  case 0x0:
+    return 8;
+  case 0x1:
+    return 4;
+  case 0x2:
+    return 2;
+  case 0x3:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+bool NativeRegisterContextLinux_loongarch64::WatchpointIsEnabled(
+    uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+  return ((m_hwp_regs[wp_index].control & g_enable_bit) != 0);
+}
+
+Status NativeRegisterContextLinux_loongarch64::GetWatchpointHitIndex(
+    uint32_t &wp_index, lldb::addr_t trap_addr) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail())
+    return error;
+
+  uint32_t watch_size;
+  lldb::addr_t watch_addr;
+
+  for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
+    watch_size = GetWatchpointSize(wp_index);
+    watch_addr = m_hwp_regs[wp_index].address;
+
+    if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
+        trap_addr <= watch_addr + watch_size) {
+      m_hwp_regs[wp_index].hit_addr = trap_addr;
+      return Status();
+    }
+  }
+
+  wp_index = LLDB_INVALID_INDEX32;
+  return Status();
+}
+
+lldb::addr_t NativeRegisterContextLinux_loongarch64::GetWatchpointAddress(
+    uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  if (wp_index >= m_max_hwp_supported)
+    return LLDB_INVALID_ADDRESS;
+
+  if (WatchpointIsEnabled(wp_index))
+    return m_hwp_regs[wp_index].address;
+
+  return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t NativeRegisterContextLinux_loongarch64::GetWatchpointHitAddress(
+    uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  if (wp_index >= m_max_hwp_supported)
+    return LLDB_INVALID_ADDRESS;
+
+  if (WatchpointIsEnabled(wp_index))
+    return m_hwp_regs[wp_index].hit_addr;
+
+  return LLDB_INVALID_ADDRESS;
+}
+
+Status NativeRegisterContextLinux_loongarch64::ReadHardwareDebugInfo() {
+  if (!m_refresh_hwdebug_info)
+    return Status();
+
+  ::pid_t tid = m_thread.GetID();
+
+  int regset = NT_LOONGARCH_HW_WATCH;
+  struct iovec ioVec;
+  struct user_watch_state dreg_state;
+  Status error;
+
+  ioVec.iov_base = &dreg_state;
+  ioVec.iov_len = sizeof(dreg_state);
+  error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
+                                            &ioVec, ioVec.iov_len);
+  if (error.Fail())
+    return error;
+
+  m_max_hwp_supported = dreg_state.dbg_info & 0x3f;
+
+  regset = NT_LOONGARCH_HW_BREAK;
+  error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
+                                            &ioVec, ioVec.iov_len);
+  if (error.Fail())
+    return error;
+
+  m_max_hbp_supported = dreg_state.dbg_info & 0x3f;
+
+  m_refresh_hwdebug_info = false;
+
+  return error;
+}
+
+Status NativeRegisterContextLinux_loongarch64::WriteHardwareDebugRegs(
+    DREGType hwbType) {
+  struct iovec ioVec;
+  struct user_watch_state dreg_state;
+  int regset;
+
+  memset(&dreg_state, 0, sizeof(dreg_state));
+  ioVec.iov_base = &dreg_state;
+
+  switch (hwbType) {
+  case eDREGTypeWATCH:
+    regset = NT_LOONGARCH_HW_WATCH;
+    ioVec.iov_len = sizeof(dreg_state.dbg_info) +
+                    (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
+
+    for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+      dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
+      dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
+    }
+    break;
+  case eDREGTypeBREAK:
+    regset = NT_LOONGARCH_HW_BREAK;
+    ioVec.iov_len = sizeof(dreg_state.dbg_info) +
+                    (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
+
+    for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+      dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
+      dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
+    }
+    break;
+  }
+
+  return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
+                                           &regset, &ioVec, ioVec.iov_len);
+}
 #endif // defined(__loongarch__) && __loongarch_grlen == 64
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
index 0a6084ff4206db..6599677924d41d 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
@@ -51,6 +51,42 @@ class NativeRegisterContextLinux_loongarch64
 
   bool RegisterOffsetIsDynamic() const override { return true; }
 
+  // Hardware breakpoints management functions
+
+  uint32_t NumSupportedHardwareBreakpoints() override;
+
+  uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+  bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
+
+  Status ClearAllHardwareBreakpoints() override;
+
+  Status GetHardwareBreakHitIndex(uint32_t &bp_index,
+                                  lldb::addr_t trap_addr) override;
+
+  bool BreakpointIsEnabled(uint32_t bp_index);
+
+  // Hardware watchpoints management functions
+  uint32_t NumSupportedHardwareWatchpoints() override;
+
+  uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+                                 uint32_t watch_flags) override;
+
+  bool ClearHardwareWatchpoint(uint32_t hw_index) override;
+
+  Status ClearAllHardwareWatchpoints() override;
+
+  Status GetWatchpointHitIndex(uint32_t &wp_index,
+                               lldb::addr_t trap_addr) override;
+
+  lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
+
+  lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
+
+  uint32_t GetWatchpointSize(uint32_t wp_index);
+
+  bool WatchpointIsEnabled(uint32_t wp_index);
+
 protected:
   Status ReadGPR() override;
 
@@ -83,6 +119,30 @@ class NativeRegisterContextLinux_loongarch64
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
 
   const RegisterInfoPOSIX_loongarch64 &GetRegisterInfo() const;
+
+  // Debug register type select
+  enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
+
+  Status ReadHardwareDebugInfo();
+  Status WriteHardwareDebugRegs(DREGType hwbType);
+
+  // Debug register info for hardware watchpoints management.
+  struct DREG {
+    lldb::addr_t address;  // Breakpoint/watchpoint address value.
+    lldb::addr_t hit_addr; // Address at which last watchpoint trigger
+                           // exception occurred.
+    uint32_t control;      // Breakpoint/watchpoint control value.
+  };
+
+  std::array<struct DREG, 14> m_hbp_regs; // hardware breakpoints
+  std::array<struct DREG, 14> m_hwp_regs; // hardware watchpoints
+
+  // Refer to:
+  // https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#control-and-status-registers-related-to-watchpoints
+  // 14 is just a maximum value, query hardware for actual watchpoint count.
+  uint32_t m_max_hwp_supported = 14;
+  uint32_t m_max_hbp_supported = 14;
+  bool m_refresh_hwdebug_info = true;
 };
 
 } // namespace process_linux
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index 324db3db7eb4c7..c2fe05cad566ef 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -231,7 +231,8 @@ GDBRemoteCommunicationServerCommon::Handle_qHostInfo(
       host_arch.GetMachine() == llvm::Triple::aarch64_32 ||
       host_arch.GetMachine() == llvm::Triple::aarch64_be ||
       host_arch.GetMachine() == llvm::Triple::arm ||
-      host_arch.GetMachine() == llvm::Triple::armeb || host_arch.IsMIPS())
+      host_arch.GetMachine() == llvm::Triple::armeb || host_arch.IsMIPS() ||
+      host_arch.GetTriple().isLoongArch())
     response.Printf("watchpoint_exceptions_received:before;");
   else
     response.Printf("watchpoint_exceptions_received:after;");
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index db33525978a16a..68485a40a3fcce 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2517,7 +2517,8 @@ bool Process::GetWatchpointReportedAfter() {
   llvm::Triple triple = arch.GetTriple();
 
   if (triple.isMIPS() || triple.isPPC64() || triple.isRISCV() ||
-      triple.isAArch64() || triple.isArmMClass() || triple.isARM())
+      triple.isAArch64() || triple.isArmMClass() || triple.isARM() ||
+      triple.isLoongArch())
     reported_after = false;
 
   return reported_after;

>From 94596521121634dcfe5e357e1444c0fbe725ef63 Mon Sep 17 00:00:00 2001
From: wanglei <wanglei at loongson.cn>
Date: Thu, 5 Dec 2024 17:11:56 +0800
Subject: [PATCH 2/2] Introduce NativeRegisterContextDBReg class

Created using spr 1.3.5-bogner
---
 .../NativeRegisterContextLinux_arm64.cpp      |  21 +-
 .../Linux/NativeRegisterContextLinux_arm64.h  |   4 +-
 ...NativeRegisterContextLinux_loongarch64.cpp | 484 ------------------
 .../NativeRegisterContextLinux_loongarch64.h  |  60 ---
 .../Plugins/Process/Utility/CMakeLists.txt    |   1 +
 .../Utility/NativeRegisterContextDBReg.cpp    | 271 ++++++++++
 .../Utility/NativeRegisterContextDBReg.h      |  76 +++
 .../NativeRegisterContextDBReg_arm64.cpp      | 342 ++-----------
 .../NativeRegisterContextDBReg_arm64.h        |  68 +--
 .../GDBRemoteCommunicationServerCommon.cpp    |   3 +-
 lldb/source/Target/Process.cpp                |   3 +-
 11 files changed, 402 insertions(+), 931 deletions(-)
 create mode 100644 lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
 create mode 100644 lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h

diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index 6056f3001fed6e..55dd0583890403 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -202,6 +202,9 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
   m_max_hwp_supported = 16;
   m_max_hbp_supported = 16;
 
+  // E (bit 0), used to enable breakpoint/watchpoint
+  m_hw_dbg_enable_bit = 1;
+
   m_refresh_hwdebug_info = true;
 
   m_gpr_is_valid = false;
@@ -1067,10 +1070,9 @@ bool NativeRegisterContextLinux_arm64::IsFPMR(unsigned reg) const {
   return GetRegisterInfo().IsFPMRReg(reg);
 }
 
-llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
-  if (!m_refresh_hwdebug_info) {
-    return llvm::Error::success();
-  }
+Status NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
+  if (!m_refresh_hwdebug_info)
+    return Status();
 
   ::pid_t tid = m_thread.GetID();
 
@@ -1085,7 +1087,7 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
                                             &ioVec, ioVec.iov_len);
 
   if (error.Fail())
-    return error.ToError();
+    return error;
 
   m_max_hwp_supported = dreg_state.dbg_info & 0xff;
 
@@ -1094,15 +1096,15 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
                                             &ioVec, ioVec.iov_len);
 
   if (error.Fail())
-    return error.ToError();
+    return error;
 
   m_max_hbp_supported = dreg_state.dbg_info & 0xff;
   m_refresh_hwdebug_info = false;
 
-  return llvm::Error::success();
+  return Status();
 }
 
-llvm::Error
+Status
 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) {
   struct iovec ioVec;
   struct user_hwdebug_state dreg_state;
@@ -1135,8 +1137,7 @@ NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) {
   }
 
   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
-                                           &regset, &ioVec, ioVec.iov_len)
-      .ToError();
+                                           &regset, &ioVec, ioVec.iov_len);
 }
 
 Status NativeRegisterContextLinux_arm64::ReadGPR() {
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
index 16190b5492582b..2730a61df8bcf8 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -234,9 +234,9 @@ class NativeRegisterContextLinux_arm64
 
   size_t GetFPMRBufferSize() { return sizeof(m_fpmr_reg); }
 
-  llvm::Error ReadHardwareDebugInfo() override;
+  Status ReadHardwareDebugInfo() override;
 
-  llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
+  Status WriteHardwareDebugRegs(DREGType hwbType) override;
 
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
 
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
index 1f73bd0467962d..f4d1bb297049da 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
@@ -11,9 +11,7 @@
 #include "NativeRegisterContextLinux_loongarch64.h"
 
 #include "lldb/Host/HostInfo.h"
-#include "lldb/Host/linux/Ptrace.h"
 #include "lldb/Utility/DataBufferHeap.h"
-#include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/Status.h"
@@ -34,19 +32,6 @@ using namespace lldb;
 using namespace lldb_private;
 using namespace lldb_private::process_linux;
 
-// CTRL_PLV3_ENABLE, used to enable breakpoint/watchpoint
-constexpr uint32_t g_enable_bit = 0x10;
-
-// Returns appropriate control register bits for the specified size
-// size encoded:
-// case 1 : 0b11
-// case 2 : 0b10
-// case 4 : 0b01
-// case 8 : 0b00
-static inline uint64_t GetSizeBits(int size) {
-  return (3 - llvm::Log2_32(size)) << 10;
-}
-
 std::unique_ptr<NativeRegisterContextLinux>
 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
     const ArchSpec &target_arch, NativeThreadLinux &native_thread) {
@@ -76,8 +61,6 @@ NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64(
       NativeRegisterContextLinux(native_thread) {
   ::memset(&m_fpr, 0, sizeof(m_fpr));
   ::memset(&m_gpr, 0, sizeof(m_gpr));
-  ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
-  ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
 
   m_gpr_is_valid = false;
   m_fpu_is_valid = false;
@@ -354,471 +337,4 @@ NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
   return expedited_reg_nums;
 }
 
-uint32_t
-NativeRegisterContextLinux_loongarch64::NumSupportedHardwareBreakpoints() {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail()) {
-    LLDB_LOG(log, "failed to read debug registers");
-    return 0;
-  }
-
-  LLDB_LOG(log, "{0}", m_max_hbp_supported);
-  return m_max_hbp_supported;
-}
-
-uint32_t
-NativeRegisterContextLinux_loongarch64::SetHardwareBreakpoint(lldb::addr_t addr,
-                                                              size_t size) {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-  LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-  if (error.Fail()) {
-    LLDB_LOG(log, "unable to set breakpoint: failed to read debug registers");
-    return LLDB_INVALID_INDEX32;
-  }
-
-  uint32_t bp_index = 0;
-
-  // Check if size has a valid hardware breakpoint length.
-  if (size != 4)
-    return LLDB_INVALID_INDEX32; // Invalid size for a LoongArch hardware
-                                 // breakpoint
-
-  // Check 4-byte alignment for hardware breakpoint target address.
-  if (addr & 0x03)
-    return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
-
-  // Iterate over stored breakpoints and find a free bp_index
-  bp_index = LLDB_INVALID_INDEX32;
-  for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
-    if (!BreakpointIsEnabled(i))
-      bp_index = i; // Mark last free slot
-    else if (m_hbp_regs[i].address == addr)
-      return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.
-  }
-
-  if (bp_index == LLDB_INVALID_INDEX32)
-    return LLDB_INVALID_INDEX32;
-
-  // Update breakpoint in local cache
-  m_hbp_regs[bp_index].address = addr;
-  m_hbp_regs[bp_index].control = g_enable_bit;
-
-  // PTRACE call to set corresponding hardware breakpoint register.
-  error = WriteHardwareDebugRegs(eDREGTypeBREAK);
-
-  if (error.Fail()) {
-    m_hbp_regs[bp_index].address = 0;
-    m_hbp_regs[bp_index].control = 0;
-
-    LLDB_LOG(log, "unable to set breakpoint: failed to write debug registers");
-    return LLDB_INVALID_INDEX32;
-  }
-
-  return bp_index;
-}
-bool NativeRegisterContextLinux_loongarch64::ClearHardwareBreakpoint(
-    uint32_t hw_idx) {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-  LLDB_LOG(log, "hw_idx: {0}", hw_idx);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-  if (error.Fail()) {
-    LLDB_LOG(log, "unable to clear breakpoint: failed to read debug registers");
-    return false;
-  }
-
-  if (hw_idx >= m_max_hbp_supported)
-    return false;
-
-  // Create a backup we can revert to in case of failure.
-  lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;
-  uint32_t tempControl = m_hbp_regs[hw_idx].control;
-
-  m_hbp_regs[hw_idx].control = 0;
-  m_hbp_regs[hw_idx].address = 0;
-
-  // PTRACE call to clear corresponding hardware breakpoint register.
-  error = WriteHardwareDebugRegs(eDREGTypeBREAK);
-
-  if (error.Fail()) {
-    m_hbp_regs[hw_idx].control = tempControl;
-    m_hbp_regs[hw_idx].address = tempAddr;
-
-    LLDB_LOG(log,
-             "unable to clear breakpoint: failed to write debug registers");
-    return false;
-  }
-
-  return true;
-}
-Status NativeRegisterContextLinux_loongarch64::GetHardwareBreakHitIndex(
-    uint32_t &bp_index, lldb::addr_t trap_addr) {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-
-  LLDB_LOGF(log, "NativeRegisterContextLinux_loongarch64::%s()", __FUNCTION__);
-
-  lldb::addr_t break_addr;
-
-  for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
-    break_addr = m_hbp_regs[bp_index].address;
-
-    if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {
-      m_hbp_regs[bp_index].hit_addr = trap_addr;
-      return Status();
-    }
-  }
-
-  bp_index = LLDB_INVALID_INDEX32;
-  return Status();
-}
-Status NativeRegisterContextLinux_loongarch64::ClearAllHardwareBreakpoints() {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-
-  LLDB_LOGF(log, "NativeRegisterContextLinux_loongarch64::%s()", __FUNCTION__);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-  if (error.Fail())
-    return error;
-
-  for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
-    if (!BreakpointIsEnabled(i))
-      continue;
-    // Create a backup we can revert to in case of failure.
-    lldb::addr_t tempAddr = m_hbp_regs[i].address;
-    uint32_t tempControl = m_hbp_regs[i].control;
-
-    // Clear watchpoints in local cache
-    m_hbp_regs[i].control = 0;
-    m_hbp_regs[i].address = 0;
-
-    // Ptrace call to update hardware debug registers
-    error = WriteHardwareDebugRegs(eDREGTypeBREAK);
-
-    if (error.Fail()) {
-      m_hbp_regs[i].control = tempControl;
-      m_hbp_regs[i].address = tempAddr;
-
-      return error;
-    }
-  }
-
-  return Status();
-}
-bool NativeRegisterContextLinux_loongarch64::BreakpointIsEnabled(
-    uint32_t bp_index) {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-  LLDB_LOG(log, "bp_index: {0}", bp_index);
-  return ((m_hbp_regs[bp_index].control & g_enable_bit) != 0);
-}
-
-uint32_t
-NativeRegisterContextLinux_loongarch64::NumSupportedHardwareWatchpoints() {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  Status error = ReadHardwareDebugInfo();
-  if (error.Fail()) {
-    LLDB_LOG(log, "failed to read debug registers");
-    return 0;
-  }
-
-  return m_max_hwp_supported;
-}
-
-uint32_t NativeRegisterContextLinux_loongarch64::SetHardwareWatchpoint(
-    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,
-           watch_flags);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail()) {
-    LLDB_LOG(log, "unable to set watchpoint: failed to read debug registers");
-    return LLDB_INVALID_INDEX32;
-  }
-
-  uint32_t control_value = 0, wp_index = 0;
-
-  // Check if we are setting watchpoint other than read/write/access Update
-  // watchpoint flag to match loongarch64 write-read bit configuration.
-  switch (watch_flags) {
-  case eWatchpointKindWrite:
-    watch_flags = 2;
-    break;
-  case eWatchpointKindRead:
-    watch_flags = 1;
-    break;
-  case (eWatchpointKindRead | eWatchpointKindWrite):
-    break;
-  default:
-    return LLDB_INVALID_INDEX32;
-  }
-
-  // Check if size has a valid hardware watchpoint length.
-  if (size != 1 && size != 2 && size != 4 && size != 8)
-    return LLDB_INVALID_INDEX32;
-
-  // Setup control value
-  control_value = g_enable_bit | GetSizeBits(size);
-  control_value |= watch_flags << 8;
-
-  // Iterate over stored watchpoints and find a free wp_index
-  wp_index = LLDB_INVALID_INDEX32;
-  for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
-    if (!WatchpointIsEnabled(i)) {
-      wp_index = i; // Mark last free slot
-    } else if (m_hwp_regs[i].address == addr) {
-      return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.
-    }
-  }
-
-  if (wp_index == LLDB_INVALID_INDEX32)
-    return LLDB_INVALID_INDEX32;
-
-  // Update watchpoint in local cache
-  m_hwp_regs[wp_index].address = addr;
-  m_hwp_regs[wp_index].control = control_value;
-
-  // PTRACE call to set corresponding watchpoint register.
-  error = WriteHardwareDebugRegs(eDREGTypeWATCH);
-
-  if (error.Fail()) {
-    m_hwp_regs[wp_index].address = 0;
-    m_hwp_regs[wp_index].control = 0;
-
-    LLDB_LOG(log, "unable to set watchpoint: failed to write debug registers");
-    return LLDB_INVALID_INDEX32;
-  }
-
-  return wp_index;
-}
-
-bool NativeRegisterContextLinux_loongarch64::ClearHardwareWatchpoint(
-    uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail()) {
-    LLDB_LOG(log, "unable to clear watchpoint: failed to read debug registers");
-    return false;
-  }
-
-  if (wp_index >= m_max_hwp_supported)
-    return false;
-
-  // Create a backup we can revert to in case of failure.
-  lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
-  uint32_t tempControl = m_hwp_regs[wp_index].control;
-
-  // Update watchpoint in local cache
-  m_hwp_regs[wp_index].control = 0;
-  m_hwp_regs[wp_index].address = 0;
-
-  // Ptrace call to update hardware debug registers
-  error = WriteHardwareDebugRegs(eDREGTypeWATCH);
-
-  if (error.Fail()) {
-    m_hwp_regs[wp_index].control = tempControl;
-    m_hwp_regs[wp_index].address = tempAddr;
-
-    LLDB_LOG(log, "unable to clear watchpoint: failed to read debug registers");
-    return false;
-  }
-
-  return true;
-}
-
-Status NativeRegisterContextLinux_loongarch64::ClearAllHardwareWatchpoints() {
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-  if (error.Fail())
-    return error;
-
-  for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
-    if (!WatchpointIsEnabled(i))
-      continue;
-    // Create a backup we can revert to in case of failure.
-    lldb::addr_t tempAddr = m_hwp_regs[i].address;
-    uint32_t tempControl = m_hwp_regs[i].control;
-
-    // Clear watchpoints in local cache
-    m_hwp_regs[i].control = 0;
-    m_hwp_regs[i].address = 0;
-
-    // Ptrace call to update hardware debug registers
-    error = WriteHardwareDebugRegs(eDREGTypeWATCH);
-
-    if (error.Fail()) {
-      m_hwp_regs[i].control = tempControl;
-      m_hwp_regs[i].address = tempAddr;
-
-      return error;
-    }
-  }
-
-  return Status();
-}
-
-uint32_t
-NativeRegisterContextLinux_loongarch64::GetWatchpointSize(uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  switch ((m_hwp_regs[wp_index].control >> 10) & 0x3) {
-  case 0x0:
-    return 8;
-  case 0x1:
-    return 4;
-  case 0x2:
-    return 2;
-  case 0x3:
-    return 1;
-  default:
-    return 0;
-  }
-}
-
-bool NativeRegisterContextLinux_loongarch64::WatchpointIsEnabled(
-    uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-  return ((m_hwp_regs[wp_index].control & g_enable_bit) != 0);
-}
-
-Status NativeRegisterContextLinux_loongarch64::GetWatchpointHitIndex(
-    uint32_t &wp_index, lldb::addr_t trap_addr) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-  if (error.Fail())
-    return error;
-
-  uint32_t watch_size;
-  lldb::addr_t watch_addr;
-
-  for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
-    watch_size = GetWatchpointSize(wp_index);
-    watch_addr = m_hwp_regs[wp_index].address;
-
-    if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
-        trap_addr <= watch_addr + watch_size) {
-      m_hwp_regs[wp_index].hit_addr = trap_addr;
-      return Status();
-    }
-  }
-
-  wp_index = LLDB_INVALID_INDEX32;
-  return Status();
-}
-
-lldb::addr_t NativeRegisterContextLinux_loongarch64::GetWatchpointAddress(
-    uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  if (wp_index >= m_max_hwp_supported)
-    return LLDB_INVALID_ADDRESS;
-
-  if (WatchpointIsEnabled(wp_index))
-    return m_hwp_regs[wp_index].address;
-
-  return LLDB_INVALID_ADDRESS;
-}
-
-lldb::addr_t NativeRegisterContextLinux_loongarch64::GetWatchpointHitAddress(
-    uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  if (wp_index >= m_max_hwp_supported)
-    return LLDB_INVALID_ADDRESS;
-
-  if (WatchpointIsEnabled(wp_index))
-    return m_hwp_regs[wp_index].hit_addr;
-
-  return LLDB_INVALID_ADDRESS;
-}
-
-Status NativeRegisterContextLinux_loongarch64::ReadHardwareDebugInfo() {
-  if (!m_refresh_hwdebug_info)
-    return Status();
-
-  ::pid_t tid = m_thread.GetID();
-
-  int regset = NT_LOONGARCH_HW_WATCH;
-  struct iovec ioVec;
-  struct user_watch_state dreg_state;
-  Status error;
-
-  ioVec.iov_base = &dreg_state;
-  ioVec.iov_len = sizeof(dreg_state);
-  error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
-                                            &ioVec, ioVec.iov_len);
-  if (error.Fail())
-    return error;
-
-  m_max_hwp_supported = dreg_state.dbg_info & 0x3f;
-
-  regset = NT_LOONGARCH_HW_BREAK;
-  error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
-                                            &ioVec, ioVec.iov_len);
-  if (error.Fail())
-    return error;
-
-  m_max_hbp_supported = dreg_state.dbg_info & 0x3f;
-
-  m_refresh_hwdebug_info = false;
-
-  return error;
-}
-
-Status NativeRegisterContextLinux_loongarch64::WriteHardwareDebugRegs(
-    DREGType hwbType) {
-  struct iovec ioVec;
-  struct user_watch_state dreg_state;
-  int regset;
-
-  memset(&dreg_state, 0, sizeof(dreg_state));
-  ioVec.iov_base = &dreg_state;
-
-  switch (hwbType) {
-  case eDREGTypeWATCH:
-    regset = NT_LOONGARCH_HW_WATCH;
-    ioVec.iov_len = sizeof(dreg_state.dbg_info) +
-                    (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
-
-    for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
-      dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
-      dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
-    }
-    break;
-  case eDREGTypeBREAK:
-    regset = NT_LOONGARCH_HW_BREAK;
-    ioVec.iov_len = sizeof(dreg_state.dbg_info) +
-                    (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
-
-    for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
-      dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
-      dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
-    }
-    break;
-  }
-
-  return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
-                                           &regset, &ioVec, ioVec.iov_len);
-}
 #endif // defined(__loongarch__) && __loongarch_grlen == 64
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
index 6599677924d41d..0a6084ff4206db 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
@@ -51,42 +51,6 @@ class NativeRegisterContextLinux_loongarch64
 
   bool RegisterOffsetIsDynamic() const override { return true; }
 
-  // Hardware breakpoints management functions
-
-  uint32_t NumSupportedHardwareBreakpoints() override;
-
-  uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
-
-  bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
-
-  Status ClearAllHardwareBreakpoints() override;
-
-  Status GetHardwareBreakHitIndex(uint32_t &bp_index,
-                                  lldb::addr_t trap_addr) override;
-
-  bool BreakpointIsEnabled(uint32_t bp_index);
-
-  // Hardware watchpoints management functions
-  uint32_t NumSupportedHardwareWatchpoints() override;
-
-  uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
-                                 uint32_t watch_flags) override;
-
-  bool ClearHardwareWatchpoint(uint32_t hw_index) override;
-
-  Status ClearAllHardwareWatchpoints() override;
-
-  Status GetWatchpointHitIndex(uint32_t &wp_index,
-                               lldb::addr_t trap_addr) override;
-
-  lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
-
-  lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
-
-  uint32_t GetWatchpointSize(uint32_t wp_index);
-
-  bool WatchpointIsEnabled(uint32_t wp_index);
-
 protected:
   Status ReadGPR() override;
 
@@ -119,30 +83,6 @@ class NativeRegisterContextLinux_loongarch64
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
 
   const RegisterInfoPOSIX_loongarch64 &GetRegisterInfo() const;
-
-  // Debug register type select
-  enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
-
-  Status ReadHardwareDebugInfo();
-  Status WriteHardwareDebugRegs(DREGType hwbType);
-
-  // Debug register info for hardware watchpoints management.
-  struct DREG {
-    lldb::addr_t address;  // Breakpoint/watchpoint address value.
-    lldb::addr_t hit_addr; // Address at which last watchpoint trigger
-                           // exception occurred.
-    uint32_t control;      // Breakpoint/watchpoint control value.
-  };
-
-  std::array<struct DREG, 14> m_hbp_regs; // hardware breakpoints
-  std::array<struct DREG, 14> m_hwp_regs; // hardware watchpoints
-
-  // Refer to:
-  // https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#control-and-status-registers-related-to-watchpoints
-  // 14 is just a maximum value, query hardware for actual watchpoint count.
-  uint32_t m_max_hwp_supported = 14;
-  uint32_t m_max_hbp_supported = 14;
-  bool m_refresh_hwdebug_info = true;
 };
 
 } // namespace process_linux
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 308ea29e31ad77..0526c95503175e 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -9,6 +9,7 @@ add_lldb_library(lldbPluginProcessUtility
   LinuxSignals.cpp
   MemoryTagManagerAArch64MTE.cpp
   NativeProcessSoftwareSingleStep.cpp
+  NativeRegisterContextDBReg.cpp
   NativeRegisterContextDBReg_arm64.cpp
   NativeRegisterContextDBReg_x86.cpp
   NativeRegisterContextRegisterInfo.cpp
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
new file mode 100644
index 00000000000000..9a0f17ba57bdfa
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
@@ -0,0 +1,271 @@
+//===-- NativeRegisterContextDBReg.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextDBReg.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+uint32_t NativeRegisterContextDBReg::NumSupportedHardwareBreakpoints() {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+
+  if (error.Fail()) {
+    LLDB_LOG(log, "failed to read debug registers");
+    return 0;
+  }
+
+  LLDB_LOG(log, "{0}", m_max_hbp_supported);
+  return m_max_hbp_supported;
+}
+
+bool NativeRegisterContextDBReg::ClearHardwareBreakpoint(uint32_t hw_idx) {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+  LLDB_LOG(log, "hw_idx: {0}", hw_idx);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log,
+             "unable to clear breakpoint: failed to read debug registers: {0}");
+    return false;
+  }
+
+  if (hw_idx >= m_max_hbp_supported)
+    return false;
+
+  // Create a backup we can revert to in case of failure.
+  lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;
+  uint32_t tempControl = m_hbp_regs[hw_idx].control;
+
+  m_hbp_regs[hw_idx].control &= ~m_hw_dbg_enable_bit;
+  m_hbp_regs[hw_idx].address = 0;
+
+  // PTRACE call to clear corresponding hardware breakpoint register.
+  error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+  if (error.Fail()) {
+    m_hbp_regs[hw_idx].control = tempControl;
+    m_hbp_regs[hw_idx].address = tempAddr;
+
+    LLDB_LOG(log,
+             "unable to clear breakpoint: failed to write debug registers");
+    return false;
+  }
+
+  return true;
+}
+
+Status
+NativeRegisterContextDBReg::GetHardwareBreakHitIndex(uint32_t &bp_index,
+                                                     lldb::addr_t trap_addr) {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+
+  LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);
+
+  lldb::addr_t break_addr;
+
+  for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
+    break_addr = m_hbp_regs[bp_index].address;
+
+    if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {
+      m_hbp_regs[bp_index].hit_addr = trap_addr;
+      return Status();
+    }
+  }
+
+  bp_index = LLDB_INVALID_INDEX32;
+  return Status();
+}
+
+Status NativeRegisterContextDBReg::ClearAllHardwareBreakpoints() {
+  Log *log = GetLog(LLDBLog::Breakpoints);
+
+  LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail())
+    return error;
+
+  for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+    if (!BreakpointIsEnabled(i))
+      continue;
+    // Create a backup we can revert to in case of failure.
+    lldb::addr_t tempAddr = m_hbp_regs[i].address;
+    uint32_t tempControl = m_hbp_regs[i].control;
+
+    // Clear watchpoints in local cache
+    m_hbp_regs[i].control &= ~m_hw_dbg_enable_bit;
+    m_hbp_regs[i].address = 0;
+
+    // Ptrace call to update hardware debug registers
+    error = WriteHardwareDebugRegs(eDREGTypeBREAK);
+
+    if (error.Fail()) {
+      m_hbp_regs[i].control = tempControl;
+      m_hbp_regs[i].address = tempAddr;
+
+      return error;
+    }
+  }
+
+  return Status();
+}
+
+bool NativeRegisterContextDBReg::BreakpointIsEnabled(uint32_t bp_index) {
+  return ((m_hbp_regs[bp_index].control & m_hw_dbg_enable_bit) != 0);
+}
+
+uint32_t NativeRegisterContextDBReg::NumSupportedHardwareWatchpoints() {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log, "failed to read debug registers");
+    return 0;
+  }
+
+  return m_max_hwp_supported;
+}
+
+bool NativeRegisterContextDBReg::ClearHardwareWatchpoint(uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log, "unable to set watchpoint: failed to read debug registers");
+    return LLDB_INVALID_INDEX32;
+  }
+
+  if (wp_index >= m_max_hwp_supported)
+    return false;
+
+  // Create a backup we can revert to in case of failure.
+  lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
+  uint32_t tempControl = m_hwp_regs[wp_index].control;
+
+  // Update watchpoint in local cache
+  m_hwp_regs[wp_index].control &= ~m_hw_dbg_enable_bit;
+  m_hwp_regs[wp_index].address = 0;
+
+  // Ptrace call to update hardware debug registers
+  error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+  if (error.Fail()) {
+    m_hwp_regs[wp_index].control = tempControl;
+    m_hwp_regs[wp_index].address = tempAddr;
+
+    LLDB_LOG(log, "unable to clear watchpoint: failed to read debug registers");
+    return false;
+  }
+
+  return true;
+}
+
+Status NativeRegisterContextDBReg::ClearAllHardwareWatchpoints() {
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail())
+    return error;
+
+  for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+    if (!WatchpointIsEnabled(i))
+      continue;
+    // Create a backup we can revert to in case of failure.
+    lldb::addr_t tempAddr = m_hwp_regs[i].address;
+    uint32_t tempControl = m_hwp_regs[i].control;
+
+    // Clear watchpoints in local cache
+    m_hwp_regs[i].control = 0;
+    m_hwp_regs[i].address = 0;
+
+    // Ptrace call to update hardware debug registers
+    error = WriteHardwareDebugRegs(eDREGTypeWATCH);
+
+    if (error.Fail()) {
+      m_hwp_regs[i].control = tempControl;
+      m_hwp_regs[i].address = tempAddr;
+
+      return error;
+    }
+  }
+
+  return Status();
+}
+
+Status
+NativeRegisterContextDBReg::GetWatchpointHitIndex(uint32_t &wp_index,
+                                                  lldb::addr_t trap_addr) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
+
+  // Read hardware breakpoint and watchpoint information.
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail())
+    return error;
+
+  // Mask off ignored bits from watchpoint trap address.
+  // aarch64
+  trap_addr = FixWatchpointHitAddress(trap_addr);
+
+  uint32_t watch_size;
+  lldb::addr_t watch_addr;
+
+  for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
+    watch_size = GetWatchpointSize(wp_index);
+    watch_addr = m_hwp_regs[wp_index].address;
+
+    if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
+        trap_addr < watch_addr + watch_size) {
+      m_hwp_regs[wp_index].hit_addr = trap_addr;
+      return Status();
+    }
+  }
+
+  wp_index = LLDB_INVALID_INDEX32;
+  return Status();
+}
+
+bool NativeRegisterContextDBReg::WatchpointIsEnabled(uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+  return ((m_hwp_regs[wp_index].control & m_hw_dbg_enable_bit) != 0);
+}
+
+lldb::addr_t
+NativeRegisterContextDBReg::GetWatchpointAddress(uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  if (wp_index >= m_max_hwp_supported)
+    return LLDB_INVALID_ADDRESS;
+
+  if (WatchpointIsEnabled(wp_index))
+    return m_hwp_regs[wp_index].real_addr;
+  return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
+NativeRegisterContextDBReg::GetWatchpointHitAddress(uint32_t wp_index) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  if (wp_index >= m_max_hwp_supported)
+    return LLDB_INVALID_ADDRESS;
+
+  if (WatchpointIsEnabled(wp_index))
+    return m_hwp_regs[wp_index].hit_addr;
+  return LLDB_INVALID_ADDRESS;
+}
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
new file mode 100644
index 00000000000000..bbd23bddbea25d
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
@@ -0,0 +1,76 @@
+//===-- NativeRegisterContextDBReg.h ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextDBReg_h
+#define lldb_NativeRegisterContextDBReg_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+#include <array>
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg
+    : public virtual NativeRegisterContextRegisterInfo {
+public:
+  uint32_t NumSupportedHardwareBreakpoints() override;
+
+  bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
+
+  Status ClearAllHardwareBreakpoints() override;
+
+  Status GetHardwareBreakHitIndex(uint32_t &bp_index,
+                                  lldb::addr_t trap_addr) override;
+
+  uint32_t NumSupportedHardwareWatchpoints() override;
+
+  bool ClearHardwareWatchpoint(uint32_t hw_index) override;
+
+  Status ClearAllHardwareWatchpoints() override;
+
+  Status GetWatchpointHitIndex(uint32_t &wp_index,
+                               lldb::addr_t trap_addr) override;
+
+  lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
+
+  lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
+
+protected:
+  // Debug register type select
+  enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
+
+  /// Debug register info for hardware breakpoints and watchpoints management.
+  struct DREG {
+    lldb::addr_t address;  // Breakpoint/watchpoint address value.
+    lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception
+                           // occurred.
+    lldb::addr_t real_addr; // Address value that should cause target to stop.
+    uint32_t control;       // Breakpoint/watchpoint control value.
+  };
+
+  std::array<struct DREG, 16> m_hbp_regs; // hardware breakpoints
+  std::array<struct DREG, 16> m_hwp_regs; // hardware watchpoints
+
+  uint32_t m_max_hbp_supported;
+  uint32_t m_max_hwp_supported;
+  uint32_t m_hw_dbg_enable_bit;
+
+  bool WatchpointIsEnabled(uint32_t wp_index);
+  bool BreakpointIsEnabled(uint32_t bp_index);
+
+  virtual uint32_t GetWatchpointSize(uint32_t wp_index) = 0;
+  virtual Status ReadHardwareDebugInfo() = 0;
+  virtual Status WriteHardwareDebugRegs(DREGType hwbType) = 0;
+  virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) {
+    return hit_addr;
+  }
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_h
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
index f1d0756b3ed9c5..101fbe692a2b09 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
@@ -14,8 +14,6 @@
 
 using namespace lldb_private;
 
-// E (bit 0), used to enable breakpoint/watchpoint
-constexpr uint32_t g_enable_bit = 1;
 // PAC (bits 2:1): 0b10
 constexpr uint32_t g_pac_bits = (2 << 1);
 
@@ -29,18 +27,6 @@ static constexpr inline uint64_t GetSizeBits(int size) {
   return ((1 << size) - 1) << 5;
 }
 
-uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareBreakpoints() {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error) {
-    LLDB_LOG_ERROR(log, std::move(error),
-                   "failed to read debug registers: {0}");
-    return 0;
-  }
-
-  return m_max_hbp_supported;
-}
-
 uint32_t
 NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
                                                         size_t size) {
@@ -48,11 +34,10 @@ NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
   LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
 
   // Read hardware breakpoint and watchpoint information.
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error) {
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to set breakpoint: failed to read debug registers: {0}");
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log,
+             "unable to set breakpoint: failed to read debug registers: {0}");
     return LLDB_INVALID_INDEX32;
   }
 
@@ -68,7 +53,7 @@ NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
     return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned.
 
   // Setup control value
-  control_value = g_enable_bit | g_pac_bits | GetSizeBits(size);
+  control_value = m_hw_dbg_enable_bit | g_pac_bits | GetSizeBits(size);
 
   // Iterate over stored breakpoints and find a free bp_index
   bp_index = LLDB_INVALID_INDEX32;
@@ -90,132 +75,35 @@ NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr,
   // PTRACE call to set corresponding hardware breakpoint register.
   error = WriteHardwareDebugRegs(eDREGTypeBREAK);
 
-  if (error) {
+  if (error.Fail()) {
     m_hbp_regs[bp_index].address = 0;
-    m_hbp_regs[bp_index].control &= ~1;
+    m_hbp_regs[bp_index].control &= ~m_hw_dbg_enable_bit;
 
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to set breakpoint: failed to write debug registers: {0}");
+    LLDB_LOG(log,
+             "unable to set breakpoint: failed to write debug registers: {0}");
     return LLDB_INVALID_INDEX32;
   }
 
   return bp_index;
 }
 
-bool NativeRegisterContextDBReg_arm64::ClearHardwareBreakpoint(
-    uint32_t hw_idx) {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-  LLDB_LOG(log, "hw_idx: {0}", hw_idx);
-
-  // Read hardware breakpoint and watchpoint information.
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error) {
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to clear breakpoint: failed to read debug registers: {0}");
-    return false;
-  }
-
-  if (hw_idx >= m_max_hbp_supported)
-    return false;
-
-  // Create a backup we can revert to in case of failure.
-  lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;
-  uint32_t tempControl = m_hbp_regs[hw_idx].control;
-
-  m_hbp_regs[hw_idx].control &= ~g_enable_bit;
-  m_hbp_regs[hw_idx].address = 0;
-
-  // PTRACE call to clear corresponding hardware breakpoint register.
-  error = WriteHardwareDebugRegs(eDREGTypeBREAK);
-
-  if (error) {
-    m_hbp_regs[hw_idx].control = tempControl;
-    m_hbp_regs[hw_idx].address = tempAddr;
-
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to clear breakpoint: failed to write debug registers: {0}");
-    return false;
-  }
-
-  return true;
-}
-
-Status NativeRegisterContextDBReg_arm64::GetHardwareBreakHitIndex(
-    uint32_t &bp_index, lldb::addr_t trap_addr) {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-
-  LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__);
-
-  lldb::addr_t break_addr;
-
-  for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
-    break_addr = m_hbp_regs[bp_index].address;
-
-    if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {
-      m_hbp_regs[bp_index].hit_addr = trap_addr;
-      return Status();
-    }
-  }
-
-  bp_index = LLDB_INVALID_INDEX32;
-  return Status();
-}
-
-Status NativeRegisterContextDBReg_arm64::ClearAllHardwareBreakpoints() {
-  Log *log = GetLog(LLDBLog::Breakpoints);
-
-  LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__);
-
-  // Read hardware breakpoint and watchpoint information.
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error)
-    return Status::FromError(std::move(error));
-
-  for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
-    if (BreakpointIsEnabled(i)) {
-      // Create a backup we can revert to in case of failure.
-      lldb::addr_t tempAddr = m_hbp_regs[i].address;
-      uint32_t tempControl = m_hbp_regs[i].control;
-
-      // Clear watchpoints in local cache
-      m_hbp_regs[i].control &= ~g_enable_bit;
-      m_hbp_regs[i].address = 0;
-
-      // Ptrace call to update hardware debug registers
-      error = WriteHardwareDebugRegs(eDREGTypeBREAK);
-
-      if (error) {
-        m_hbp_regs[i].control = tempControl;
-        m_hbp_regs[i].address = tempAddr;
-
-        return Status::FromError(std::move(error));
-      }
-    }
-  }
-
-  return Status();
-}
-
-bool NativeRegisterContextDBReg_arm64::BreakpointIsEnabled(uint32_t bp_index) {
-  if ((m_hbp_regs[bp_index].control & g_enable_bit) != 0)
-    return true;
-  else
-    return false;
-}
-
-uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareWatchpoints() {
+uint32_t
+NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) {
   Log *log = GetLog(LLDBLog::Watchpoints);
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error) {
-    LLDB_LOG_ERROR(log, std::move(error),
-                   "failed to read debug registers: {0}");
+  LLDB_LOG(log, "wp_index: {0}", wp_index);
+
+  switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
+  case 0x01:
+    return 1;
+  case 0x03:
+    return 2;
+  case 0x0f:
+    return 4;
+  case 0xff:
+    return 8;
+  default:
     return 0;
   }
-
-  return m_max_hwp_supported;
 }
 
 uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint(
@@ -225,11 +113,10 @@ uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint(
            watch_flags);
 
   // Read hardware breakpoint and watchpoint information.
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error) {
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to set watchpoint: failed to read debug registers: {0}");
+  Status error = ReadHardwareDebugInfo();
+  if (error.Fail()) {
+    LLDB_LOG(log,
+             "unable to set watchpoint: failed to read debug registers: {0}");
     return LLDB_INVALID_INDEX32;
   }
 
@@ -239,13 +126,13 @@ uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint(
   // Check if we are setting watchpoint other than read/write/access Also
   // update watchpoint flag to match AArch64 write-read bit configuration.
   switch (watch_flags) {
-  case 1:
+  case lldb::eWatchpointKindWrite:
     watch_flags = 2;
     break;
-  case 2:
+  case lldb::eWatchpointKindRead:
     watch_flags = 1;
     break;
-  case 3:
+  case (lldb::eWatchpointKindRead | lldb::eWatchpointKindWrite):
     break;
   default:
     return LLDB_INVALID_INDEX32;
@@ -274,7 +161,7 @@ uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint(
   }
 
   // Setup control value
-  control_value = g_enable_bit | g_pac_bits | GetSizeBits(size);
+  control_value = m_hw_dbg_enable_bit | g_pac_bits | GetSizeBits(size);
   control_value |= watch_flags << 3;
 
   // Iterate over stored watchpoints and find a free wp_index
@@ -298,173 +185,14 @@ uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint(
   // PTRACE call to set corresponding watchpoint register.
   error = WriteHardwareDebugRegs(eDREGTypeWATCH);
 
-  if (error) {
+  if (error.Fail()) {
     m_hwp_regs[wp_index].address = 0;
-    m_hwp_regs[wp_index].control &= ~g_enable_bit;
+    m_hwp_regs[wp_index].control &= ~m_hw_dbg_enable_bit;
 
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to set watchpoint: failed to write debug registers: {0}");
+    LLDB_LOG(log,
+             "unable to set watchpoint: failed to write debug registers: {0}");
     return LLDB_INVALID_INDEX32;
   }
 
   return wp_index;
 }
-
-bool NativeRegisterContextDBReg_arm64::ClearHardwareWatchpoint(
-    uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  // Read hardware breakpoint and watchpoint information.
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error) {
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to clear watchpoint: failed to read debug registers: {0}");
-    return false;
-  }
-
-  if (wp_index >= m_max_hwp_supported)
-    return false;
-
-  // Create a backup we can revert to in case of failure.
-  lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;
-  uint32_t tempControl = m_hwp_regs[wp_index].control;
-
-  // Update watchpoint in local cache
-  m_hwp_regs[wp_index].control &= ~g_enable_bit;
-  m_hwp_regs[wp_index].address = 0;
-
-  // Ptrace call to update hardware debug registers
-  error = WriteHardwareDebugRegs(eDREGTypeWATCH);
-
-  if (error) {
-    m_hwp_regs[wp_index].control = tempControl;
-    m_hwp_regs[wp_index].address = tempAddr;
-
-    LLDB_LOG_ERROR(
-        log, std::move(error),
-        "unable to clear watchpoint: failed to write debug registers: {0}");
-    return false;
-  }
-
-  return true;
-}
-
-Status NativeRegisterContextDBReg_arm64::ClearAllHardwareWatchpoints() {
-  // Read hardware breakpoint and watchpoint information.
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error)
-    return Status::FromError(std::move(error));
-
-  for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
-    if (WatchpointIsEnabled(i)) {
-      // Create a backup we can revert to in case of failure.
-      lldb::addr_t tempAddr = m_hwp_regs[i].address;
-      uint32_t tempControl = m_hwp_regs[i].control;
-
-      // Clear watchpoints in local cache
-      m_hwp_regs[i].control &= ~g_enable_bit;
-      m_hwp_regs[i].address = 0;
-
-      // Ptrace call to update hardware debug registers
-      error = WriteHardwareDebugRegs(eDREGTypeWATCH);
-
-      if (error) {
-        m_hwp_regs[i].control = tempControl;
-        m_hwp_regs[i].address = tempAddr;
-
-        return Status::FromError(std::move(error));
-      }
-    }
-  }
-
-  return Status();
-}
-
-uint32_t
-NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) {
-  case 0x01:
-    return 1;
-  case 0x03:
-    return 2;
-  case 0x0f:
-    return 4;
-  case 0xff:
-    return 8;
-  default:
-    return 0;
-  }
-}
-
-bool NativeRegisterContextDBReg_arm64::WatchpointIsEnabled(uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  if ((m_hwp_regs[wp_index].control & g_enable_bit) != 0)
-    return true;
-  else
-    return false;
-}
-
-Status NativeRegisterContextDBReg_arm64::GetWatchpointHitIndex(
-    uint32_t &wp_index, lldb::addr_t trap_addr) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);
-
-  // Read hardware breakpoint and watchpoint information.
-  llvm::Error error = ReadHardwareDebugInfo();
-  if (error)
-    return Status::FromError(std::move(error));
-
-  // Mask off ignored bits from watchpoint trap address.
-  trap_addr = FixWatchpointHitAddress(trap_addr);
-
-  uint32_t watch_size;
-  lldb::addr_t watch_addr;
-
-  for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {
-    watch_size = GetWatchpointSize(wp_index);
-    watch_addr = m_hwp_regs[wp_index].address;
-
-    if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&
-        trap_addr < watch_addr + watch_size) {
-      m_hwp_regs[wp_index].hit_addr = trap_addr;
-      return Status();
-    }
-  }
-
-  wp_index = LLDB_INVALID_INDEX32;
-  return Status();
-}
-
-lldb::addr_t
-NativeRegisterContextDBReg_arm64::GetWatchpointAddress(uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  if (wp_index >= m_max_hwp_supported)
-    return LLDB_INVALID_ADDRESS;
-
-  if (WatchpointIsEnabled(wp_index))
-    return m_hwp_regs[wp_index].real_addr;
-  return LLDB_INVALID_ADDRESS;
-}
-
-lldb::addr_t
-NativeRegisterContextDBReg_arm64::GetWatchpointHitAddress(uint32_t wp_index) {
-  Log *log = GetLog(LLDBLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  if (wp_index >= m_max_hwp_supported)
-    return LLDB_INVALID_ADDRESS;
-
-  if (WatchpointIsEnabled(wp_index))
-    return m_hwp_regs[wp_index].hit_addr;
-  return LLDB_INVALID_ADDRESS;
-}
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
index f8246ff4d71873..9142a0a685bea3 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
@@ -9,79 +9,19 @@
 #ifndef lldb_NativeRegisterContextDBReg_arm64_h
 #define lldb_NativeRegisterContextDBReg_arm64_h
 
-#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
-
-#include <array>
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
 
 namespace lldb_private {
 
-class NativeRegisterContextDBReg_arm64
-    : public virtual NativeRegisterContextRegisterInfo {
+class NativeRegisterContextDBReg_arm64 : public NativeRegisterContextDBReg {
 public:
-  uint32_t NumSupportedHardwareBreakpoints() override;
-
   uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
 
-  bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
-
-  Status ClearAllHardwareBreakpoints() override;
-
-  Status GetHardwareBreakHitIndex(uint32_t &bp_index,
-                                  lldb::addr_t trap_addr) override;
-
-  bool BreakpointIsEnabled(uint32_t bp_index);
-
-  uint32_t NumSupportedHardwareWatchpoints() override;
-
   uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
                                  uint32_t watch_flags) override;
 
-  bool ClearHardwareWatchpoint(uint32_t hw_index) override;
-
-  Status ClearAllHardwareWatchpoints() override;
-
-  Status GetWatchpointHitIndex(uint32_t &wp_index,
-                               lldb::addr_t trap_addr) override;
-
-  lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;
-
-  lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
-
-  uint32_t GetWatchpointSize(uint32_t wp_index);
-
-  bool WatchpointIsEnabled(uint32_t wp_index);
-
-  // Debug register type select
-  enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK };
-
-protected:
-  /// Debug register info for hardware breakpoints and watchpoints management.
-  /// Watchpoints: For a user requested size 4 at addr 0x1004, where BAS
-  /// watchpoints are at doubleword (8-byte) alignment.
-  ///   \a real_addr is 0x1004
-  ///   \a address is 0x1000
-  ///   size is 8
-  ///   If a one-byte write to 0x1006 is the most recent watchpoint trap,
-  ///   \a hit_addr is 0x1006
-  struct DREG {
-    lldb::addr_t address;  // Breakpoint/watchpoint address value.
-    lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception
-                           // occurred.
-    lldb::addr_t real_addr; // Address value that should cause target to stop.
-    uint32_t control;       // Breakpoint/watchpoint control value.
-  };
-
-  std::array<struct DREG, 16> m_hbp_regs; // hardware breakpoints
-  std::array<struct DREG, 16> m_hwp_regs; // hardware watchpoints
-
-  uint32_t m_max_hbp_supported;
-  uint32_t m_max_hwp_supported;
-
-  virtual llvm::Error ReadHardwareDebugInfo() = 0;
-  virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0;
-  virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) {
-    return hit_addr;
-  }
+private:
+  uint32_t GetWatchpointSize(uint32_t wp_index) override;
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index c2fe05cad566ef..324db3db7eb4c7 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -231,8 +231,7 @@ GDBRemoteCommunicationServerCommon::Handle_qHostInfo(
       host_arch.GetMachine() == llvm::Triple::aarch64_32 ||
       host_arch.GetMachine() == llvm::Triple::aarch64_be ||
       host_arch.GetMachine() == llvm::Triple::arm ||
-      host_arch.GetMachine() == llvm::Triple::armeb || host_arch.IsMIPS() ||
-      host_arch.GetTriple().isLoongArch())
+      host_arch.GetMachine() == llvm::Triple::armeb || host_arch.IsMIPS())
     response.Printf("watchpoint_exceptions_received:before;");
   else
     response.Printf("watchpoint_exceptions_received:after;");
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 68485a40a3fcce..db33525978a16a 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -2517,8 +2517,7 @@ bool Process::GetWatchpointReportedAfter() {
   llvm::Triple triple = arch.GetTriple();
 
   if (triple.isMIPS() || triple.isPPC64() || triple.isRISCV() ||
-      triple.isAArch64() || triple.isArmMClass() || triple.isARM() ||
-      triple.isLoongArch())
+      triple.isAArch64() || triple.isArmMClass() || triple.isARM())
     reported_after = false;
 
   return reported_after;



More information about the lldb-commits mailing list