[Lldb-commits] [lldb] [lldb][Process/Linux] Introduce LoongArch64 hw break/watchpoint support (PR #118043)

Lu Weining via lldb-commits lldb-commits at lists.llvm.org
Mon Dec 2 17:38:22 PST 2024


================
@@ -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(
----------------
SixWeining wrote:

```suggestion
bool NativeRegisterContextLinux_loongarch64::HardwareBreakpointIsEnabled(
```

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


More information about the lldb-commits mailing list