[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, ®set,
+ &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, ®set,
+ &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(),
+ ®set, &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(),
- ®set, &ioVec, ioVec.iov_len)
- .ToError();
+ ®set, &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, ®set,
- &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, ®set,
- &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(),
- ®set, &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