https://github.com/DavidSpickett created 
https://github.com/llvm/llvm-project/pull/152284

Which is also used by AArch64 and LoongArch.

To do this I had to make some adjustments to NativeRegisterContextDBReg:
* New method AdjustBreakpoint. This is like AdjustWatchpoint, but 
  only Arm needs to adjust breakpoints. For Arm this method removes the 
  bottom address bits according to the mode.
* MakeWatchControlValue now takes the address too. Arm uses this to
  generate the byte mask.

To test this, I ran the test suite as usual on Arm and found no new 
failures, then ran it again with all test programs compiled with
`-mthumb`. This means the binaries will be entirely Thumb code.

Finally I tested it on AArch64, but this is mostly a build test,
as I did not run the entire test suite compiled to AArch32.

Prior to this change, these tests failed with `-mthumb`:
```
Failed Tests (14):
  lldb-api :: commands/process/reverse-continue/TestReverseContinue.py
  lldb-api :: 
functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py
  lldb-api :: 
functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py
  lldb-api :: 
functionalities/reverse-execution/TestReverseContinueBreakpoints.py
  lldb-api :: 
functionalities/reverse-execution/TestReverseContinueWatchpoints.py
  lldb-api :: 
functionalities/tail_call_frames/disambiguate_call_site/TestDisambiguateCallSite.py
  lldb-api :: 
functionalities/tail_call_frames/disambiguate_paths_to_common_sink/TestDisambiguatePathsToCommonSink.py
  lldb-api :: 
functionalities/tail_call_frames/disambiguate_tail_call_seq/TestDisambiguateTailCallSeq.py
  lldb-api :: 
functionalities/tail_call_frames/inlining_and_tail_calls/TestInliningAndTailCalls.py
  lldb-api :: 
functionalities/tail_call_frames/sbapi_support/TestTailCallFrameSBAPI.py
  lldb-api :: 
functionalities/tail_call_frames/thread_step_out_message/TestArtificialFrameStepOutMessage.py
  lldb-api :: functionalities/thread/jump/TestThreadJump.py
  lldb-api :: lang/c/vla/TestVLA.py
  lldb-api :: linux/sepdebugsymlink/TestTargetSymbolsSepDebugSymlink.py
```

After this change, no new failures occurred. So I am confident it is
correct.

Looking at those failures, it's a few things:
* Something in the reverse execution wrapper that I can't figure out, but is
  likely nothing to do with the real breakpoints.
* The inability to tail call when building thumb code, because the call goes
  via. a veneer that might do a mode switch.
* Assumptions about source locations being in specific places.

None of which are massive issues I feel like need fixing before doing this port.

>From 6753d9b62e599dac57d8ba710cedf0640e5b43cd Mon Sep 17 00:00:00 2001
From: David Spickett <david.spick...@linaro.org>
Date: Mon, 16 Dec 2024 16:02:33 +0000
Subject: [PATCH 1/2] [lldb][ARM] Port Arm Linux to use
 NativeRegisterContextDBReg

Which is also used by AArch64 and LoongArch.

To do this I had to make some adjustments to NativeRegisterContextDBReg:
* New method AdjustBreakpoint. This is like AdjustWatchpoint, but
  only Arm needs to adjust breakpoints. For Arm this method removes the
  bottom address bits according to the mode.
* MakeWatchControlValue now takes the address too. Arm uses this to
  generate the byte mask.

To test this, I ran the test suite as usual on Arm and found no new
failures, then ran it again with all test programs compiled with
`-mthumb`. This means the binaries will be entirely Thumb code.

Finally I tested it on AArch64, but this is mostly a build test,
as I did not run the entire test suite compiled to AArch32 mode.

Prior to this change, these tests failed with `-mthumb`:
```
Failed Tests (14):
  lldb-api :: commands/process/reverse-continue/TestReverseContinue.py
  lldb-api :: 
functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py
  lldb-api :: 
functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py
  lldb-api :: 
functionalities/reverse-execution/TestReverseContinueBreakpoints.py
  lldb-api :: 
functionalities/reverse-execution/TestReverseContinueWatchpoints.py
  lldb-api :: 
functionalities/tail_call_frames/disambiguate_call_site/TestDisambiguateCallSite.py
  lldb-api :: 
functionalities/tail_call_frames/disambiguate_paths_to_common_sink/TestDisambiguatePathsToCommonSink.py
  lldb-api :: 
functionalities/tail_call_frames/disambiguate_tail_call_seq/TestDisambiguateTailCallSeq.py
  lldb-api :: 
functionalities/tail_call_frames/inlining_and_tail_calls/TestInliningAndTailCalls.py
  lldb-api :: 
functionalities/tail_call_frames/sbapi_support/TestTailCallFrameSBAPI.py
  lldb-api :: 
functionalities/tail_call_frames/thread_step_out_message/TestArtificialFrameStepOutMessage.py
  lldb-api :: functionalities/thread/jump/TestThreadJump.py
  lldb-api :: lang/c/vla/TestVLA.py
  lldb-api :: linux/sepdebugsymlink/TestTargetSymbolsSepDebugSymlink.py
```

After this change, no new failures occured. So I am confident it is
correct.

Looking into those failures, it's a few things:
* Something in the reverse execution wrapper that I can't figure out, but is
  likely nothing to do with the real breakpoints.
* The inability to tail call when building thumb code, because the call goes
  via. a veneer that might do a mode switch.
* Assumptions about source locations being in speciifc places.

None of which are massive issues I feel like need fixing before doing this port.
---
 .../Linux/NativeRegisterContextLinux_arm.cpp  | 529 ++----------------
 .../Linux/NativeRegisterContextLinux_arm.h    |  51 +-
 .../Plugins/Process/Utility/CMakeLists.txt    |   1 +
 .../Utility/NativeRegisterContextDBReg.cpp    |   4 +-
 .../Utility/NativeRegisterContextDBReg.h      |  14 +-
 .../NativeRegisterContextDBReg_arm.cpp        | 116 ++++
 .../Utility/NativeRegisterContextDBReg_arm.h  |  46 ++
 .../NativeRegisterContextDBReg_arm64.cpp      |   7 +-
 .../NativeRegisterContextDBReg_arm64.h        |   3 +-
 .../NativeRegisterContextDBReg_loongarch.cpp  |   3 +-
 .../NativeRegisterContextDBReg_loongarch.h    |   3 +-
 11 files changed, 243 insertions(+), 534 deletions(-)
 create mode 100644 
lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
 create mode 100644 
lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h

diff --git 
a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp 
b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index fdafacf410d64..25e91c84ec584 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -76,7 +76,7 @@ 
NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm(
   ::memset(&m_fpr, 0, sizeof(m_fpr));
   ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm));
   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
-  ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
+  ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs));
 
   // 16 is just a maximum value, query hardware for actual watchpoint count
   m_max_hwp_supported = 16;
@@ -283,484 +283,60 @@ bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) 
const {
   return false;
 }
 
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() {
-  Log *log = GetLog(POSIXLog::Breakpoints);
-
-  LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
-  Status error;
-
-  // Read hardware breakpoint and watchpoint information.
-  error = ReadHardwareDebugInfo();
-
-  if (error.Fail())
-    return 0;
-
-  LLDB_LOG(log, "{0}", m_max_hbp_supported);
-  return m_max_hbp_supported;
-}
-
-uint32_t
-NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr,
-                                                      size_t size) {
-  Log *log = GetLog(POSIXLog::Breakpoints);
-  LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail())
-    return LLDB_INVALID_INDEX32;
-
-  uint32_t control_value = 0, bp_index = 0;
-
-  // Setup address and control values.
-  // Use size to get a hint of arm vs thumb modes.
-  switch (size) {
-  case 2:
-    control_value = (0x3 << 5) | 7;
-    addr &= ~1;
-    break;
-  case 4:
-    control_value = (0xfu << 5) | 7;
-    addr &= ~3;
-    break;
-  default:
-    return LLDB_INVALID_INDEX32;
-  }
-
-  // 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 ((m_hbr_regs[i].control & 1) == 0) {
-      bp_index = i; // Mark last free slot
-    } else if (m_hbr_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_hbr_regs[bp_index].real_addr = addr;
-  m_hbr_regs[bp_index].address = addr;
-  m_hbr_regs[bp_index].control = control_value;
-
-  // PTRACE call to set corresponding hardware breakpoint register.
-  error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
-                                 bp_index);
-
-  if (error.Fail()) {
-    m_hbr_regs[bp_index].address = 0;
-    m_hbr_regs[bp_index].control &= ~1;
-
-    return LLDB_INVALID_INDEX32;
-  }
-
-  return bp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) {
-  Log *log = GetLog(POSIXLog::Breakpoints);
-  LLDB_LOG(log, "hw_idx: {0}", hw_idx);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail())
-    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_hbr_regs[hw_idx].address;
-  uint32_t tempControl = m_hbr_regs[hw_idx].control;
-
-  m_hbr_regs[hw_idx].control &= ~1;
-  m_hbr_regs[hw_idx].address = 0;
-
-  // PTRACE call to clear corresponding hardware breakpoint register.
-  error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK,
-                                 hw_idx);
-
-  if (error.Fail()) {
-    m_hbr_regs[hw_idx].control = tempControl;
-    m_hbr_regs[hw_idx].address = tempAddr;
-
-    return false;
-  }
-
-  return true;
-}
-
-Status NativeRegisterContextLinux_arm::GetHardwareBreakHitIndex(
-    uint32_t &bp_index, lldb::addr_t trap_addr) {
-  Log *log = GetLog(POSIXLog::Breakpoints);
-
-  LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
-  lldb::addr_t break_addr;
-
-  for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {
-    break_addr = m_hbr_regs[bp_index].address;
-
-    if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) {
-      m_hbr_regs[bp_index].hit_addr = trap_addr;
-      return Status();
-    }
-  }
-
-  bp_index = LLDB_INVALID_INDEX32;
-  return Status();
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() {
-  Log *log = GetLog(POSIXLog::Breakpoints);
-
-  LLDB_LOGF(log, "NativeRegisterContextLinux_arm::%s()", __FUNCTION__);
-
-  Status error;
-
-  // Read hardware breakpoint and watchpoint information.
-  error = ReadHardwareDebugInfo();
-
-  if (error.Fail())
-    return error;
-
-  lldb::addr_t tempAddr = 0;
-  uint32_t tempControl = 0;
-
-  for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
-    if (m_hbr_regs[i].control & 0x01) {
-      // Create a backup we can revert to in case of failure.
-      tempAddr = m_hbr_regs[i].address;
-      tempControl = m_hbr_regs[i].control;
-
-      // Clear breakpoints in local cache
-      m_hbr_regs[i].control &= ~1;
-      m_hbr_regs[i].address = 0;
-
-      // Ptrace call to update hardware debug registers
-      error =
-          WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, 
i);
-
-      if (error.Fail()) {
-        m_hbr_regs[i].control = tempControl;
-        m_hbr_regs[i].address = tempAddr;
-
-        return error;
-      }
-    }
-  }
-
-  return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareWatchpoints() {
-  Log *log = GetLog(POSIXLog::Watchpoints);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail())
-    return 0;
-
-  LLDB_LOG(log, "{0}", m_max_hwp_supported);
-  return m_max_hwp_supported;
-}
-
-uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint(
-    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
-  Log *log = GetLog(POSIXLog::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())
-    return LLDB_INVALID_INDEX32;
-
-  uint32_t control_value = 0, wp_index = 0, addr_word_offset = 0, byte_mask = 
0;
-  lldb::addr_t real_addr = addr;
-
-  // Check if we are setting watchpoint other than read/write/access Also
-  // update watchpoint flag to match Arm write-read bit configuration.
-  switch (watch_flags) {
-  case 1:
-    watch_flags = 2;
-    break;
-  case 2:
-    watch_flags = 1;
-    break;
-  case 3:
-    break;
-  default:
-    return LLDB_INVALID_INDEX32;
-  }
-
-  // Can't watch zero bytes
-  // Can't watch more than 4 bytes per WVR/WCR pair
-
-  if (size == 0 || size > 4)
-    return LLDB_INVALID_INDEX32;
-
-  // Check 4-byte alignment for hardware watchpoint target address. Below is a
-  // hack to recalculate address and size in order to make sure we can watch
-  // non 4-byte aligned addresses as well.
-  if (addr & 0x03) {
-    uint8_t watch_mask = (addr & 0x03) + size;
-
-    if (watch_mask > 0x04)
-      return LLDB_INVALID_INDEX32;
-    else if (watch_mask <= 0x02)
-      size = 2;
-    else
-      size = 4;
-
-    addr = addr & (~0x03);
-  }
-
-  // We can only watch up to four bytes that follow a 4 byte aligned address
-  // per watchpoint register pair, so make sure we can properly encode this.
-  addr_word_offset = addr % 4;
-  byte_mask = ((1u << size) - 1u) << addr_word_offset;
-
-  // Check if we need multiple watchpoint register
-  if (byte_mask > 0xfu)
-    return LLDB_INVALID_INDEX32;
-
-  // Setup control value
-  // Make the byte_mask into a valid Byte Address Select mask
-  control_value = byte_mask << 5;
-
-  // Turn on appropriate watchpoint flags read or write
-  control_value |= (watch_flags << 3);
-
-  // Enable this watchpoint and make it stop in privileged or user mode;
-  control_value |= 7;
-
-  // Make sure bits 1:0 are clear in our address
-  addr &= ~((lldb::addr_t)3);
-
-  // 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 ((m_hwp_regs[i].control & 1) == 0) {
-      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].real_addr = real_addr;
-  m_hwp_regs[wp_index].address = addr;
-  m_hwp_regs[wp_index].control = control_value;
-
-  // PTRACE call to set corresponding watchpoint register.
-  error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
-                                 wp_index);
-
-  if (error.Fail()) {
-    m_hwp_regs[wp_index].address = 0;
-    m_hwp_regs[wp_index].control &= ~1;
-
-    return LLDB_INVALID_INDEX32;
-  }
-
-  return wp_index;
-}
-
-bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint(
-    uint32_t wp_index) {
-  Log *log = GetLog(POSIXLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail())
-    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 &= ~1;
-  m_hwp_regs[wp_index].address = 0;
-
-  // Ptrace call to update hardware debug registers
-  error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH,
-                                 wp_index);
-
-  if (error.Fail()) {
-    m_hwp_regs[wp_index].control = tempControl;
-    m_hwp_regs[wp_index].address = tempAddr;
-
-    return false;
-  }
-
-  return true;
-}
-
-Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() {
-  // Read hardware breakpoint and watchpoint information.
-  Status error = ReadHardwareDebugInfo();
-
-  if (error.Fail())
-    return error;
-
-  lldb::addr_t tempAddr = 0;
-  uint32_t tempControl = 0;
-
-  for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
-    if (m_hwp_regs[i].control & 0x01) {
-      // Create a backup we can revert to in case of failure.
-      tempAddr = m_hwp_regs[i].address;
-      tempControl = m_hwp_regs[i].control;
-
-      // Clear watchpoints in local cache
-      m_hwp_regs[i].control &= ~1;
-      m_hwp_regs[i].address = 0;
-
-      // Ptrace call to update hardware debug registers
-      error =
-          WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, 
i);
-
-      if (error.Fail()) {
-        m_hwp_regs[i].control = tempControl;
-        m_hwp_regs[i].address = tempAddr;
-
-        return error;
-      }
-    }
-  }
-
-  return Status();
-}
-
-uint32_t NativeRegisterContextLinux_arm::GetWatchpointSize(uint32_t wp_index) {
-  Log *log = GetLog(POSIXLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) {
-  case 0x01:
-    return 1;
-  case 0x03:
-    return 2;
-  case 0x07:
-    return 3;
-  case 0x0f:
-    return 4;
-  default:
-    return 0;
-  }
-}
-bool NativeRegisterContextLinux_arm::WatchpointIsEnabled(uint32_t wp_index) {
-  Log *log = GetLog(POSIXLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}", wp_index);
-
-  if ((m_hwp_regs[wp_index].control & 0x1) == 0x1)
-    return true;
-  else
-    return false;
-}
-
-Status
-NativeRegisterContextLinux_arm::GetWatchpointHitIndex(uint32_t &wp_index,
-                                                      lldb::addr_t trap_addr) {
-  Log *log = GetLog(POSIXLog::Watchpoints);
-  LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, 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
-NativeRegisterContextLinux_arm::GetWatchpointAddress(uint32_t wp_index) {
-  Log *log = GetLog(POSIXLog::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;
-  else
-    return LLDB_INVALID_ADDRESS;
-}
-
-lldb::addr_t
-NativeRegisterContextLinux_arm::GetWatchpointHitAddress(uint32_t wp_index) {
-  Log *log = GetLog(POSIXLog::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;
-  else
-    return LLDB_INVALID_ADDRESS;
-}
-
-Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
-  Status error;
-
-  if (!m_refresh_hwdebug_info) {
-    return Status();
-  }
+llvm::Error NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() {
+  if (!m_refresh_hwdebug_info)
+    return llvm::Error::success();
 
 #ifdef __arm__
   unsigned int cap_val;
-
-  error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, 
m_thread.GetID(),
-                                            nullptr, &cap_val,
-                                            sizeof(unsigned int));
+  Status error = NativeProcessLinux::PtraceWrapper(
+      PTRACE_GETHBPREGS, m_thread.GetID(), nullptr, &cap_val,
+      sizeof(unsigned int));
 
   if (error.Fail())
-    return error;
+    return error.ToError();
 
   m_max_hwp_supported = (cap_val >> 8) & 0xff;
   m_max_hbp_supported = cap_val & 0xff;
   m_refresh_hwdebug_info = false;
 
-  return error;
+  return error.ToError();
 #else  // __aarch64__
   return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported,
-                                      m_max_hbp_supported);
+                                      m_max_hbp_supported)
+      .ToError();
 #endif // ifdef __arm__
 }
 
-Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
-    NativeRegisterContextDBReg::DREGType hwbType, int hwb_index) {
-  Status error;
-
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
 #ifdef __arm__
+  uint32_t max_index = m_max_hbp_supported;
+  if (hwbType == eDREGTypeWATCH)
+    max_index = m_max_hwp_supported;
+
+  for (uint32_t idx = 0; idx < max_index; ++idx)
+    if (auto error = WriteHardwareDebugReg(hwbType, idx))
+      return error;
+
+  return llvm::Error::success();
+#else  // __aarch64__
+  uint32_t max_supported =
+      (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
+          ? m_max_hwp_supported
+          : m_max_hbp_supported;
+  auto &regs = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
+                   ? m_hwp_regs
+                   : m_hbp_regs;
+  return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), 
max_supported,
+                                       regs).ToError();
+#endif // ifdef __arm__
+}
+
+llvm::Error
+NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
+                                                      int hwb_index) {
+  Status error;
   lldb::addr_t *addr_buf;
   uint32_t *ctrl_buf;
 
@@ -774,15 +350,18 @@ Status 
NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
         sizeof(unsigned int));
 
     if (error.Fail())
-      return error;
+      return error.ToError();
 
     error = NativeProcessLinux::PtraceWrapper(
         PTRACE_SETHBPREGS, m_thread.GetID(),
         (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
         sizeof(unsigned int));
+
+    if (error.Fail())
+      return error.ToError();
   } else {
-    addr_buf = &m_hbr_regs[hwb_index].address;
-    ctrl_buf = &m_hbr_regs[hwb_index].control;
+    addr_buf = &m_hbp_regs[hwb_index].address;
+    ctrl_buf = &m_hbp_regs[hwb_index].control;
 
     error = NativeProcessLinux::PtraceWrapper(
         PTRACE_SETHBPREGS, m_thread.GetID(),
@@ -790,26 +369,18 @@ Status 
NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(
         sizeof(unsigned int));
 
     if (error.Fail())
-      return error;
+      return error.ToError();
 
     error = NativeProcessLinux::PtraceWrapper(
         PTRACE_SETHBPREGS, m_thread.GetID(),
         (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
         sizeof(unsigned int));
+
+    if (error.Fail())
+      return error.ToError();
   }
 
-  return error;
-#else  // __aarch64__
-  uint32_t max_supported =
-      (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
-          ? m_max_hwp_supported
-          : m_max_hbp_supported;
-  auto &regs = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH)
-                   ? m_hwp_regs
-                   : m_hbr_regs;
-  return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), 
max_supported,
-                                       regs);
-#endif // ifdef __arm__
+  return error.ToError();
 }
 
 uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h 
b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
index 3a31d68d7a3c4..6ac19e45f1069 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -12,7 +12,7 @@
 #define lldb_NativeRegisterContextLinux_arm_h
 
 #include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
-#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"
 #include "Plugins/Process/Utility/lldb-arm-register-enums.h"
 
@@ -21,7 +21,8 @@ namespace process_linux {
 
 class NativeProcessLinux;
 
-class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux {
+class NativeRegisterContextLinux_arm : public NativeRegisterContextLinux,
+                                       public NativeRegisterContextDBReg_arm {
 public:
   NativeRegisterContextLinux_arm(const ArchSpec &target_arch,
                                  NativeThreadProtocol &native_thread);
@@ -42,39 +43,6 @@ class NativeRegisterContextLinux_arm : public 
NativeRegisterContextLinux {
 
   Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
 
-  // Hardware breakpoints/watchpoint 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;
-
-  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 DoReadRegisterValue(uint32_t offset, const char *reg_name,
                              uint32_t size, RegisterValue &value) override;
@@ -100,23 +68,16 @@ class NativeRegisterContextLinux_arm : public 
NativeRegisterContextLinux {
   uint32_t m_gpr_arm[k_num_gpr_registers_arm];
   RegisterInfoPOSIX_arm::FPU m_fpr;
 
-  std::array<NativeRegisterContextDBReg::DREG, 16>
-      m_hbr_regs; // Arm native linux hardware breakpoints
-  std::array<NativeRegisterContextDBReg::DREG, 16>
-      m_hwp_regs; // Arm native linux hardware watchpoints
-
-  uint32_t m_max_hwp_supported;
-  uint32_t m_max_hbp_supported;
   bool m_refresh_hwdebug_info;
 
   bool IsGPR(unsigned reg) const;
 
   bool IsFPR(unsigned reg) const;
 
-  Status ReadHardwareDebugInfo();
+  llvm::Error ReadHardwareDebugInfo() override;
 
-  Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType,
-                                int hwb_index);
+  llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
+  llvm::Error WriteHardwareDebugReg(DREGType hwbType, int hwb_index) override;
 
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
 
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt 
b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 5d99c22dafe15..b1e326ec064e4 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -13,6 +13,7 @@ add_lldb_library(lldbPluginProcessUtility
   MemoryTagManagerAArch64MTE.cpp
   NativeProcessSoftwareSingleStep.cpp
   NativeRegisterContextDBReg.cpp
+  NativeRegisterContextDBReg_arm.cpp
   NativeRegisterContextDBReg_arm64.cpp
   NativeRegisterContextDBReg_loongarch.cpp
   NativeRegisterContextDBReg_x86.cpp
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
index 19601b7f35d47..a79adb8858635 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
@@ -222,7 +222,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
   addr = adjusted->addr;
 
   // Check if we are setting watchpoint other than read/write/access Also
-  // update watchpoint flag to match AArch64/LoongArch write-read bit
+  // update watchpoint flag to match ARM/AArch64/LoongArch write-read bit
   // configuration.
   switch (watch_flags) {
   case lldb::eWatchpointKindWrite:
@@ -237,7 +237,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(
     return LLDB_INVALID_INDEX32;
   }
 
-  control_value = MakeWatchControlValue(size, watch_flags);
+  control_value = MakeWatchControlValue(addr, size, watch_flags);
 
   // Iterate over stored watchpoints and find a free wp_index
   wp_index = LLDB_INVALID_INDEX32;
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
index 9b6ecd382c3f3..97e40ab14eaaf 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h
@@ -12,6 +12,7 @@
 #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
 
 #include <array>
+#include <optional>
 
 // Common utilities for hardware breakpoints and hardware watchpoints on 
AArch64
 // and LoongArch.
@@ -76,17 +77,26 @@ class NativeRegisterContextDBReg
 
   // On AArch64 and Loongarch the hardware breakpoint length size is 4, and the
   // target address must 4-byte alignment.
-  bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
+  virtual bool ValidateBreakpoint(size_t size, lldb::addr_t addr) {
     return (size == 4) && !(addr & 0x3);
   }
+
   struct WatchpointDetails {
     size_t size;
     lldb::addr_t addr;
   };
   virtual std::optional<WatchpointDetails>
   AdjustWatchpoint(const WatchpointDetails &details) = 0;
+
+  using BreakpointDetails = WatchpointDetails;
+  virtual std::optional<BreakpointDetails>
+  AdjustBreakpoint(const BreakpointDetails &details) {
+    return details;
+  }
+
   virtual uint32_t MakeBreakControlValue(size_t size) = 0;
-  virtual uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) = 
0;
+  virtual uint32_t MakeWatchControlValue(lldb::addr_t addr, size_t size,
+                                         uint32_t watch_flags) = 0;
   virtual uint32_t GetWatchpointSize(uint32_t wp_index) = 0;
 
   virtual llvm::Error ReadHardwareDebugInfo() = 0;
diff --git 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
new file mode 100644
index 0000000000000..e3b9a49253d0c
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp
@@ -0,0 +1,116 @@
+//===-- NativeRegisterContextDBReg_arm.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_arm.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+uint32_t NativeRegisterContextDBReg_arm::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) & 0x0f) {
+  case 0x01:
+    return 1;
+  case 0x03:
+    return 2;
+  case 0x07:
+    return 3;
+  case 0x0f:
+    return 4;
+  default:
+    return 0;
+  }
+}
+
+std::optional<NativeRegisterContextDBReg::BreakpointDetails>
+NativeRegisterContextDBReg_arm::AdjustBreakpoint(
+    const BreakpointDetails &details) {
+  BreakpointDetails bd = details;
+  // Use size to get a hint of arm vs thumb modes.
+  switch (bd.size) {
+  case 2:
+    bd.addr &= ~1;
+    break;
+  case 4:
+    bd.addr &= ~3;
+    break;
+  default:
+    return {};
+  }
+
+  return bd;
+}
+
+std::optional<NativeRegisterContextDBReg::WatchpointDetails>
+NativeRegisterContextDBReg_arm::AdjustWatchpoint(
+    const WatchpointDetails &details) {
+  auto [size, addr] = details;
+
+  if (size == 0 || size > 4)
+    return {};
+
+  // Check 4-byte alignment for hardware watchpoint target address. Below is a
+  // hack to recalculate address and size in order to make sure we can watch
+  // non 4-byte aligned addresses as well.
+  if (addr & 0x03) {
+    uint8_t watch_mask = (addr & 0x03) + size;
+    if (watch_mask > 0x04)
+      return {};
+    else if (watch_mask <= 0x02)
+      size = 2;
+    else
+      size = 4;
+
+    addr = addr & (~0x03);
+  }
+
+  return WatchpointDetails{size, addr};
+}
+
+uint32_t NativeRegisterContextDBReg_arm::MakeBreakControlValue(size_t size) {
+  switch (size) {
+  case 2:
+    return (0x3 << 5) | 7;
+  case 4:
+    return (0xfu << 5) | 7;
+  default:
+    // We assume that AdjustBreakpoint would have caught this earlier.
+    llvm_unreachable("Invalid breakpoint size.");
+  }
+}
+
+uint32_t NativeRegisterContextDBReg_arm::MakeWatchControlValue(
+    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+  uint32_t addr_word_offset = 0, byte_mask = 0;
+
+  // We can only watch up to four bytes that follow a 4 byte aligned address
+  // per watchpoint register pair, so make sure we can properly encode this.
+  addr_word_offset = addr % 4;
+  byte_mask = ((1u << size) - 1u) << addr_word_offset;
+
+  // Check if we need multiple watchpoint register
+  if (byte_mask > 0xfu)
+    return LLDB_INVALID_INDEX32;
+
+  // Setup control value
+  // Make the byte_mask into a valid Byte Address Select mask
+  uint32_t control_value = byte_mask << 5;
+
+  // Turn on appropriate watchpoint flags read or write
+  control_value |= (watch_flags << 3);
+
+  // Enable this watchpoint and make it stop in privileged or user mode;
+  control_value |= 7;
+
+  return control_value;
+}
diff --git 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
new file mode 100644
index 0000000000000..0af590d1be002
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
@@ -0,0 +1,46 @@
+//===-- NativeRegisterContextDBReg_arm.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_arm_h
+#define lldb_NativeRegisterContextDBReg_arm_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg_arm : public NativeRegisterContextDBReg {
+public:
+  NativeRegisterContextDBReg_arm()
+      : NativeRegisterContextDBReg(/*enable_bit=*/0x1U) {}
+
+private:
+  uint32_t GetWatchpointSize(uint32_t wp_index) override;
+
+  std::optional<WatchpointDetails>
+  AdjustWatchpoint(const WatchpointDetails &details) override;
+
+  std::optional<BreakpointDetails>
+  AdjustBreakpoint(const BreakpointDetails &details) override;
+
+  uint32_t MakeBreakControlValue(size_t size) override;
+
+  uint32_t MakeWatchControlValue(lldb::addr_t addr, size_t size,
+                                 uint32_t watch_flags) override;
+
+  bool ValidateBreakpoint(size_t size, lldb::addr_t addr) override {
+    // Break on 4 or 2 byte instructions.
+    return size == 4 || size == 2;
+  }
+
+  virtual llvm::Error WriteHardwareDebugReg(DREGType hwbType,
+                                            int hwb_index) = 0;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_arm_h
diff --git 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
index f2f772ad615c9..c134d2f5d5ce2 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp
@@ -78,9 +78,10 @@ uint32_t 
NativeRegisterContextDBReg_arm64::MakeBreakControlValue(size_t size) {
   return m_hw_dbg_enable_bit | pac_bits | encoded_size;
 }
 
-uint32_t
-NativeRegisterContextDBReg_arm64::MakeWatchControlValue(size_t size,
-                                                        uint32_t watch_flags) {
+uint32_t NativeRegisterContextDBReg_arm64::MakeWatchControlValue(
+    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+  (void)addr;
+
   // PAC (bits 2:1): 0b10
   const uint32_t pac_bits = 2 << 1;
 
diff --git 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
index 42d6bacf64861..b88efd67ad45a 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h
@@ -26,7 +26,8 @@ class NativeRegisterContextDBReg_arm64 : public 
NativeRegisterContextDBReg {
 
   uint32_t MakeBreakControlValue(size_t size) override;
 
-  uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override;
+  uint32_t MakeWatchControlValue(lldb::addr_t addr, size_t size,
+                                 uint32_t watch_flags) override;
 };
 
 } // namespace lldb_private
diff --git 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp
index b3b5e6b4d4139..e5beca468b74e 100644
--- 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp
+++ 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp
@@ -52,7 +52,8 @@ 
NativeRegisterContextDBReg_loongarch::MakeBreakControlValue(size_t size) {
 }
 
 uint32_t NativeRegisterContextDBReg_loongarch::MakeWatchControlValue(
-    size_t size, uint32_t watch_flags) {
+    lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+  (void)addr;
   // Encoding hardware watchpoint control value.
   // Size encoded:
   // case 1 : 0b11
diff --git 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h
index 19c5e4cdea263..6582371cf1a11 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h
@@ -26,7 +26,8 @@ class NativeRegisterContextDBReg_loongarch : public 
NativeRegisterContextDBReg {
 
   uint32_t MakeBreakControlValue(size_t size) override;
 
-  uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override;
+  uint32_t MakeWatchControlValue(lldb::addr_t addr, size_t size,
+                                 uint32_t watch_flags) override;
 };
 
 } // namespace lldb_private

>From abc7017284cf07b80d739a5356b7ff5413838ddf Mon Sep 17 00:00:00 2001
From: David Spickett <david.spick...@linaro.org>
Date: Tue, 5 Aug 2025 12:37:48 +0000
Subject: [PATCH 2/2] refactor write registers

---
 .../Linux/NativeRegisterContextLinux_arm.cpp  | 45 +++++++------------
 .../Linux/NativeRegisterContextLinux_arm.h    |  4 +-
 .../Utility/NativeRegisterContextDBReg_arm.h  |  3 --
 3 files changed, 18 insertions(+), 34 deletions(-)

diff --git 
a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp 
b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
index 25e91c84ec584..85395f1c15125 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp
@@ -333,55 +333,40 @@ 
NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(DREGType hwbType) {
 #endif // ifdef __arm__
 }
 
+#ifdef __arm__
 llvm::Error
 NativeRegisterContextLinux_arm::WriteHardwareDebugReg(DREGType hwbType,
                                                       int hwb_index) {
   Status error;
   lldb::addr_t *addr_buf;
   uint32_t *ctrl_buf;
+  int addr_idx = (hwb_index << 1) + 1;
+  int ctrl_idx = addr_idx + 1;
 
   if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) {
+    addr_idx *= -1;
     addr_buf = &m_hwp_regs[hwb_index].address;
+    ctrl_idx *= -1;
     ctrl_buf = &m_hwp_regs[hwb_index].control;
-
-    error = NativeProcessLinux::PtraceWrapper(
-        PTRACE_SETHBPREGS, m_thread.GetID(),
-        (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 1), addr_buf,
-        sizeof(unsigned int));
-
-    if (error.Fail())
-      return error.ToError();
-
-    error = NativeProcessLinux::PtraceWrapper(
-        PTRACE_SETHBPREGS, m_thread.GetID(),
-        (PTRACE_TYPE_ARG3)(intptr_t) - ((hwb_index << 1) + 2), ctrl_buf,
-        sizeof(unsigned int));
-
-    if (error.Fail())
-      return error.ToError();
   } else {
     addr_buf = &m_hbp_regs[hwb_index].address;
     ctrl_buf = &m_hbp_regs[hwb_index].control;
+  }
 
-    error = NativeProcessLinux::PtraceWrapper(
-        PTRACE_SETHBPREGS, m_thread.GetID(),
-        (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 1), addr_buf,
-        sizeof(unsigned int));
-
-    if (error.Fail())
-      return error.ToError();
+  error = NativeProcessLinux::PtraceWrapper(
+      PTRACE_SETHBPREGS, m_thread.GetID(), 
(PTRACE_TYPE_ARG3)(intptr_t)addr_idx,
+      addr_buf, sizeof(unsigned int));
 
-    error = NativeProcessLinux::PtraceWrapper(
-        PTRACE_SETHBPREGS, m_thread.GetID(),
-        (PTRACE_TYPE_ARG3)(intptr_t)((hwb_index << 1) + 2), ctrl_buf,
-        sizeof(unsigned int));
+  if (error.Fail())
+    return error.ToError();
 
-    if (error.Fail())
-      return error.ToError();
-  }
+  error = NativeProcessLinux::PtraceWrapper(
+      PTRACE_SETHBPREGS, m_thread.GetID(), 
(PTRACE_TYPE_ARG3)(intptr_t)ctrl_idx,
+      ctrl_buf, sizeof(unsigned int));
 
   return error.ToError();
 }
+#endif // ifdef __arm__
 
 uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset(
     const RegisterInfo *reg_info) const {
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h 
b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
index 6ac19e45f1069..cf36859b16ad4 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h
@@ -77,7 +77,9 @@ class NativeRegisterContextLinux_arm : public 
NativeRegisterContextLinux,
   llvm::Error ReadHardwareDebugInfo() override;
 
   llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
-  llvm::Error WriteHardwareDebugReg(DREGType hwbType, int hwb_index) override;
+#ifdef __arm__
+  llvm::Error WriteHardwareDebugReg(DREGType hwbType, int hwb_index);
+#endif
 
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
 
diff --git 
a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h 
b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
index 0af590d1be002..92cc6bb654e7e 100644
--- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h
@@ -36,9 +36,6 @@ class NativeRegisterContextDBReg_arm : public 
NativeRegisterContextDBReg {
     // Break on 4 or 2 byte instructions.
     return size == 4 || size == 2;
   }
-
-  virtual llvm::Error WriteHardwareDebugReg(DREGType hwbType,
-                                            int hwb_index) = 0;
 };
 
 } // namespace lldb_private

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to