[Lldb-commits] [lldb] 6c4e70f - [lldb][Process] Introduce LoongArch64 hw break/watchpoint support

via lldb-commits lldb-commits at lists.llvm.org
Thu Dec 12 18:06:58 PST 2024


Author: wanglei
Date: 2024-12-13T10:06:55+08:00
New Revision: 6c4e70fcbbb62f38a5aab085634de5faaa5cf729

URL: https://github.com/llvm/llvm-project/commit/6c4e70fcbbb62f38a5aab085634de5faaa5cf729
DIFF: https://github.com/llvm/llvm-project/commit/6c4e70fcbbb62f38a5aab085634de5faaa5cf729.diff

LOG: [lldb][Process] Introduce LoongArch64 hw break/watchpoint support

This patch adds support for setting/clearing hardware watchpoints and
breakpoints on LoongArch 64-bit hardware.

Refer to the following document for the hw break/watchpoint:
https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#control-and-status-registers-related-to-watchpoints

Fix Failed Tests:
  lldb-shell :: Subprocess/clone-follow-child-wp.test
  lldb-shell :: Subprocess/clone-follow-parent-wp.test
  lldb-shell :: Subprocess/fork-follow-child-wp.test
  lldb-shell :: Subprocess/fork-follow-parent-wp.test
  lldb-shell :: Subprocess/vfork-follow-child-wp.test
  lldb-shell :: Subprocess/vfork-follow-parent-wp.test
  lldb-shell :: Watchpoint/ExpressionLanguage.test

Depends on: #118043

Reviewed By: SixWeining

Pull Request: https://github.com/llvm/llvm-project/pull/118770

Added: 
    lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp
    lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h

Modified: 
    lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
    lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
    lldb/source/Plugins/Process/Utility/CMakeLists.txt
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
    lldb/source/Target/Process.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
index f4d1bb297049da..9ffc8ada920cb8 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.cpp
@@ -11,6 +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/Log.h"
 #include "lldb/Utility/RegisterValue.h"
@@ -62,6 +63,16 @@ NativeRegisterContextLinux_loongarch64::NativeRegisterContextLinux_loongarch64(
   ::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));
+
+  // 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.
+  m_max_hwp_supported = 14;
+  m_max_hbp_supported = 14;
+  m_refresh_hwdebug_info = true;
+
   m_gpr_is_valid = false;
   m_fpu_is_valid = false;
 }
@@ -337,4 +348,73 @@ NativeRegisterContextLinux_loongarch64::GetExpeditedRegisters(
   return expedited_reg_nums;
 }
 
+llvm::Error NativeRegisterContextLinux_loongarch64::ReadHardwareDebugInfo() {
+  if (!m_refresh_hwdebug_info)
+    return llvm::Error::success();
+
+  ::pid_t tid = m_thread.GetID();
+
+  int regset = NT_LOONGARCH_HW_WATCH;
+  struct iovec ioVec;
+  struct user_watch_state dreg_state;
+  Status error;
+
+  ioVec.iov_base = &dreg_state;
+  ioVec.iov_len = sizeof(dreg_state);
+  error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
+                                            &ioVec, ioVec.iov_len);
+  if (error.Fail())
+    return error.ToError();
+
+  m_max_hwp_supported = dreg_state.dbg_info & 0x3f;
+
+  regset = NT_LOONGARCH_HW_BREAK;
+  error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, &regset,
+                                            &ioVec, ioVec.iov_len);
+  if (error.Fail())
+    return error.ToError();
+
+  m_max_hbp_supported = dreg_state.dbg_info & 0x3f;
+
+  m_refresh_hwdebug_info = false;
+
+  return llvm::Error::success();
+}
+
+llvm::Error NativeRegisterContextLinux_loongarch64::WriteHardwareDebugRegs(
+    DREGType hwbType) {
+  struct iovec ioVec;
+  struct user_watch_state dreg_state;
+  int regset;
+
+  memset(&dreg_state, 0, sizeof(dreg_state));
+  ioVec.iov_base = &dreg_state;
+
+  switch (hwbType) {
+  case eDREGTypeWATCH:
+    regset = NT_LOONGARCH_HW_WATCH;
+    ioVec.iov_len = sizeof(dreg_state.dbg_info) +
+                    (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported);
+
+    for (uint32_t i = 0; i < m_max_hwp_supported; i++) {
+      dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address;
+      dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control;
+    }
+    break;
+  case eDREGTypeBREAK:
+    regset = NT_LOONGARCH_HW_BREAK;
+    ioVec.iov_len = sizeof(dreg_state.dbg_info) +
+                    (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported);
+
+    for (uint32_t i = 0; i < m_max_hbp_supported; i++) {
+      dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address;
+      dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control;
+    }
+    break;
+  }
+
+  return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
+                                           &regset, &ioVec, ioVec.iov_len)
+      .ToError();
+}
 #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..633b26fa970de1 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_loongarch64.h
@@ -12,6 +12,7 @@
 #define lldb_NativeRegisterContextLinux_loongarch64_h
 
 #include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_loongarch64.h"
 
 #include <asm/ptrace.h>
@@ -22,7 +23,8 @@ namespace process_linux {
 class NativeProcessLinux;
 
 class NativeRegisterContextLinux_loongarch64
-    : public NativeRegisterContextLinux {
+    : public NativeRegisterContextLinux,
+      public NativeRegisterContextDBReg_loongarch {
 public:
   NativeRegisterContextLinux_loongarch64(
       const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
@@ -71,6 +73,7 @@ class NativeRegisterContextLinux_loongarch64
 private:
   bool m_gpr_is_valid;
   bool m_fpu_is_valid;
+  bool m_refresh_hwdebug_info;
 
   RegisterInfoPOSIX_loongarch64::GPR m_gpr;
 
@@ -83,6 +86,10 @@ class NativeRegisterContextLinux_loongarch64
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
 
   const RegisterInfoPOSIX_loongarch64 &GetRegisterInfo() const;
+
+  llvm::Error ReadHardwareDebugInfo() override;
+
+  llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override;
 };
 
 } // namespace process_linux

diff  --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 0526c95503175e..0e1a5069d4409e 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -11,6 +11,7 @@ add_lldb_library(lldbPluginProcessUtility
   NativeProcessSoftwareSingleStep.cpp
   NativeRegisterContextDBReg.cpp
   NativeRegisterContextDBReg_arm64.cpp
+  NativeRegisterContextDBReg_loongarch.cpp
   NativeRegisterContextDBReg_x86.cpp
   NativeRegisterContextRegisterInfo.cpp
   NetBSDSignals.cpp

diff  --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp
new file mode 100644
index 00000000000000..b3b5e6b4d4139b
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.cpp
@@ -0,0 +1,65 @@
+//===-- NativeRegisterContextDBReg_loongarch.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_loongarch.h"
+
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+using namespace lldb_private;
+
+uint32_t
+NativeRegisterContextDBReg_loongarch::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;
+  }
+}
+
+std::optional<NativeRegisterContextDBReg::WatchpointDetails>
+NativeRegisterContextDBReg_loongarch::AdjustWatchpoint(
+    const WatchpointDetails &details) {
+  // LoongArch only needs to check the size; it does not need to check the
+  // address.
+  size_t size = details.size;
+  if (size != 1 && size != 2 && size != 4 && size != 8)
+    return std::nullopt;
+
+  return details;
+}
+
+uint32_t
+NativeRegisterContextDBReg_loongarch::MakeBreakControlValue(size_t size) {
+  // Return encoded hardware breakpoint control value.
+  return m_hw_dbg_enable_bit;
+}
+
+uint32_t NativeRegisterContextDBReg_loongarch::MakeWatchControlValue(
+    size_t size, uint32_t watch_flags) {
+  // Encoding hardware watchpoint control value.
+  // Size encoded:
+  // case 1 : 0b11
+  // case 2 : 0b10
+  // case 4 : 0b01
+  // case 8 : 0b00
+  size_t encoded_size = (3 - llvm::Log2_32(size)) << 10;
+
+  return m_hw_dbg_enable_bit | encoded_size | (watch_flags << 8);
+}

diff  --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h
new file mode 100644
index 00000000000000..19c5e4cdea2635
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_loongarch.h
@@ -0,0 +1,34 @@
+//===-- NativeRegisterContextDBReg_loongarch.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_loongarch_h
+#define lldb_NativeRegisterContextDBReg_loongarch_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h"
+
+namespace lldb_private {
+
+class NativeRegisterContextDBReg_loongarch : public NativeRegisterContextDBReg {
+public:
+  NativeRegisterContextDBReg_loongarch()
+      : NativeRegisterContextDBReg(/*enable_bit=*/0x10U) {}
+
+private:
+  uint32_t GetWatchpointSize(uint32_t wp_index) override;
+
+  std::optional<WatchpointDetails>
+  AdjustWatchpoint(const WatchpointDetails &details) override;
+
+  uint32_t MakeBreakControlValue(size_t size) override;
+
+  uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextDBReg_loongarch_h

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;


        


More information about the lldb-commits mailing list