https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/146602

>From 656beb2df5f39604454af0e3f4a9f4b1b7e9c5f8 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jo...@devlieghere.com>
Date: Tue, 1 Jul 2025 16:02:21 -0700
Subject: [PATCH 1/3] [lldb] Add SB API to make a breakpoint a hardware
 breakpoint
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This adds SBBreakpoint::SetIsHardware, allowing clients to mark an
existing breakpoint as a hardware breakpoint purely through the API.
This is safe to do after creation, as the hardware/software distinction
doesn't affect how breakpoint locations are selected.

In some cases (e.g. when writing a trap instruction would alter program
behavior), it's important to use hardware breakpoints. Ideally, we’d
extend the various Create methods to support this, but given their
number, this patch limits the scope to the post-creation API. As a
workaround, users can also rely on target.require-hardware-breakpoint or
use the breakpoint set command.

rdar://153528045
---
 lldb/include/lldb/API/SBBreakpoint.h          |  2 +
 lldb/include/lldb/Breakpoint/Breakpoint.h     |  1 +
 lldb/source/API/SBBreakpoint.cpp              | 11 +++++
 lldb/source/Breakpoint/Breakpoint.cpp         | 21 ++++++++++
 .../simple_hw_breakpoints/Makefile            |  7 ++++
 .../TestSimpleHWBreakpoints.py                | 40 +++++++++++++++++++
 .../simple_hw_breakpoints/main.c              |  7 ++++
 7 files changed, 89 insertions(+)
 create mode 100644 
lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/Makefile
 create mode 100644 
lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
 create mode 100644 
lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/main.c

diff --git a/lldb/include/lldb/API/SBBreakpoint.h 
b/lldb/include/lldb/API/SBBreakpoint.h
index e08df3b6d5ab0..307c9e13d7e39 100644
--- a/lldb/include/lldb/API/SBBreakpoint.h
+++ b/lldb/include/lldb/API/SBBreakpoint.h
@@ -148,6 +148,8 @@ class LLDB_API SBBreakpoint {
 
   bool IsHardware() const;
 
+  void SetIsHardware(bool is_hardware);
+
   // Can only be called from a ScriptedBreakpointResolver...
   SBError
   AddLocation(SBAddress &address);
diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h 
b/lldb/include/lldb/Breakpoint/Breakpoint.h
index f623a2e0c295b..8b1ab219832cc 100644
--- a/lldb/include/lldb/Breakpoint/Breakpoint.h
+++ b/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -518,6 +518,7 @@ class Breakpoint : public 
std::enable_shared_from_this<Breakpoint>,
                       lldb::break_id_t bp_loc_id);
 
   bool IsHardware() const { return m_hardware; }
+  void SetIsHardware(bool is_hardware);
 
   lldb::BreakpointResolverSP GetResolver() { return m_resolver_sp; }
 
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index 87fadbcec4f26..d790b3f4ca271 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -781,6 +781,17 @@ bool SBBreakpoint::IsHardware() const {
   return false;
 }
 
+void SBBreakpoint::SetIsHardware(bool is_hardware) {
+  LLDB_INSTRUMENT_VA(this, is_hardware);
+
+  BreakpointSP bkpt_sp = GetSP();
+  if (bkpt_sp) {
+    std::lock_guard<std::recursive_mutex> guard(
+        bkpt_sp->GetTarget().GetAPIMutex());
+    bkpt_sp->SetIsHardware(is_hardware);
+  }
+}
+
 BreakpointSP SBBreakpoint::GetSP() const { return m_opaque_wp.lock(); }
 
 // This is simple collection of breakpoint id's and their target.
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp 
b/lldb/source/Breakpoint/Breakpoint.cpp
index 2ed0c9314e3e1..d5845ebeeb08a 100644
--- a/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -251,6 +251,27 @@ const lldb::TargetSP Breakpoint::GetTargetSP() {
 
 bool Breakpoint::IsInternal() const { return LLDB_BREAK_ID_IS_INTERNAL(m_bid); 
}
 
+void Breakpoint::SetIsHardware(bool is_hardware) {
+  if (is_hardware == m_hardware)
+    return;
+
+  // Remember all the breakpoint locations we've disabled.
+  std::vector<BreakpointLocationSP> locations;
+  for (BreakpointLocationSP location : m_locations.BreakpointLocations()) {
+    if (location->IsEnabled()) {
+      locations.push_back(location);
+      location->SetEnabled(false);
+    }
+  }
+
+  // Toggle the hardware mode.
+  m_hardware = is_hardware;
+
+  // Re-enable the breakpoint locations.
+  for (BreakpointLocationSP location : locations)
+    location->SetEnabled(true);
+}
+
 BreakpointLocationSP Breakpoint::AddLocation(const Address &addr,
                                              bool *new_location) {
   return m_locations.AddLocation(addr, m_resolve_indirect_symbols,
diff --git 
a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/Makefile
 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/Makefile
new file mode 100644
index 0000000000000..304633c2dca1f
--- /dev/null
+++ 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/Makefile
@@ -0,0 +1,7 @@
+C_SOURCES := main.c
+
+ifeq ($(CC_TYPE), icc)
+    CFLAGS_EXTRAS := -debug inline-debug-info
+endif
+
+include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
new file mode 100644
index 0000000000000..abb5eef8f193f
--- /dev/null
+++ 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
@@ -0,0 +1,40 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+from functionalities.breakpoint.hardware_breakpoints.base import *
+
+
+class SimpleHWBreakpointTest(HardwareBreakpointTestBase):
+    def does_not_support_hw_breakpoints(self):
+        # FIXME: Use HardwareBreakpointTestBase.supports_hw_breakpoints
+        if super().supports_hw_breakpoints() is None:
+            return "Hardware breakpoints are unsupported"
+        return None
+
+    @skipTestIfFn(does_not_support_hw_breakpoints)
+    def test(self):
+        """Test SBBreakpoint::SetIsHardware"""
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        target = self.dbg.CreateTarget(exe)
+
+        breakpoint = target.BreakpointCreateByLocation("main.c", 1)
+        self.assertFalse(breakpoint.IsHardware())
+        breakpoint.SetIsHardware(True)
+        self.assertTrue(breakpoint.IsHardware())
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        self.expect(
+            "thread list",
+            STOPPED_DUE_TO_BREAKPOINT,
+            substrs=["stopped", "stop reason = breakpoint"],
+        )
+
+        # Check the breakpoint list.
+        self.expect(
+            "breakpoint list -v",
+            substrs=["file = 'main.c'", "hardware = true"],
+        )
diff --git 
a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/main.c
 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/main.c
new file mode 100644
index 0000000000000..4f1c9df56200a
--- /dev/null
+++ 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/main.c
@@ -0,0 +1,7 @@
+int break_on_me() {
+  int i = 10;
+  i++;
+  return i;
+}
+
+int main() { return break_on_me(); }

>From 00987591bd49a717bba36bbf1a4a1654d818d8b3 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jo...@devlieghere.com>
Date: Tue, 1 Jul 2025 20:42:26 -0700
Subject: [PATCH 2/3] Address Jim's feedback

---
 lldb/include/lldb/API/SBBreakpoint.h          |  2 +-
 lldb/include/lldb/Breakpoint/Breakpoint.h     |  3 +-
 .../lldb/Breakpoint/BreakpointLocation.h      |  2 +-
 lldb/source/API/SBBreakpoint.cpp              |  5 +--
 lldb/source/Breakpoint/Breakpoint.cpp         | 31 ++++++++++++-------
 lldb/source/Breakpoint/BreakpointLocation.cpp | 10 +++---
 .../TestSimpleHWBreakpoints.py                |  2 +-
 7 files changed, 32 insertions(+), 23 deletions(-)

diff --git a/lldb/include/lldb/API/SBBreakpoint.h 
b/lldb/include/lldb/API/SBBreakpoint.h
index 307c9e13d7e39..11f84034bd7b9 100644
--- a/lldb/include/lldb/API/SBBreakpoint.h
+++ b/lldb/include/lldb/API/SBBreakpoint.h
@@ -148,7 +148,7 @@ class LLDB_API SBBreakpoint {
 
   bool IsHardware() const;
 
-  void SetIsHardware(bool is_hardware);
+  bool SetIsHardware(bool is_hardware);
 
   // Can only be called from a ScriptedBreakpointResolver...
   SBError
diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h 
b/lldb/include/lldb/Breakpoint/Breakpoint.h
index 8b1ab219832cc..3f5c3a8b89a02 100644
--- a/lldb/include/lldb/Breakpoint/Breakpoint.h
+++ b/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -518,7 +518,8 @@ class Breakpoint : public 
std::enable_shared_from_this<Breakpoint>,
                       lldb::break_id_t bp_loc_id);
 
   bool IsHardware() const { return m_hardware; }
-  void SetIsHardware(bool is_hardware);
+
+  bool SetIsHardware(bool is_hardware);
 
   lldb::BreakpointResolverSP GetResolver() { return m_resolver_sp; }
 
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h 
b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
index 3592291bb2d06..f4fe2e9a9abfc 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
@@ -69,7 +69,7 @@ class BreakpointLocation
   // The next section deals with various breakpoint options.
 
   /// If \a enabled is \b true, enable the breakpoint, if \b false disable it.
-  void SetEnabled(bool enabled);
+  bool SetEnabled(bool enabled);
 
   /// Check the Enable/Disable state.
   ///
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index d790b3f4ca271..100f63f92ef4f 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -781,15 +781,16 @@ bool SBBreakpoint::IsHardware() const {
   return false;
 }
 
-void SBBreakpoint::SetIsHardware(bool is_hardware) {
+bool SBBreakpoint::SetIsHardware(bool is_hardware) {
   LLDB_INSTRUMENT_VA(this, is_hardware);
 
   BreakpointSP bkpt_sp = GetSP();
   if (bkpt_sp) {
     std::lock_guard<std::recursive_mutex> guard(
         bkpt_sp->GetTarget().GetAPIMutex());
-    bkpt_sp->SetIsHardware(is_hardware);
+    return bkpt_sp->SetIsHardware(is_hardware);
   }
+  return false;
 }
 
 BreakpointSP SBBreakpoint::GetSP() const { return m_opaque_wp.lock(); }
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp 
b/lldb/source/Breakpoint/Breakpoint.cpp
index d5845ebeeb08a..5d166e6888420 100644
--- a/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -251,25 +251,34 @@ const lldb::TargetSP Breakpoint::GetTargetSP() {
 
 bool Breakpoint::IsInternal() const { return LLDB_BREAK_ID_IS_INTERNAL(m_bid); 
}
 
-void Breakpoint::SetIsHardware(bool is_hardware) {
+bool Breakpoint::SetIsHardware(bool is_hardware) {
   if (is_hardware == m_hardware)
-    return;
+    return true;
 
-  // Remember all the breakpoint locations we've disabled.
+  // Disable all non-hardware breakpoint locations.
   std::vector<BreakpointLocationSP> locations;
-  for (BreakpointLocationSP location : m_locations.BreakpointLocations()) {
-    if (location->IsEnabled()) {
-      locations.push_back(location);
-      location->SetEnabled(false);
-    }
+  for (BreakpointLocationSP location_sp : m_locations.BreakpointLocations()) {
+    if (!location_sp || !location_sp->IsEnabled())
+      continue;
+
+    lldb::BreakpointSiteSP breakpoint_site_sp =
+        location_sp->GetBreakpointSite();
+    if (!breakpoint_site_sp ||
+        breakpoint_site_sp->GetType() == BreakpointSite::eHardware)
+      continue;
+
+    locations.push_back(location_sp);
+    location_sp->SetEnabled(false);
   }
 
   // Toggle the hardware mode.
   m_hardware = is_hardware;
 
-  // Re-enable the breakpoint locations.
-  for (BreakpointLocationSP location : locations)
-    location->SetEnabled(true);
+  // Re-enable all breakpoint locations.
+  bool success = true;
+  for (BreakpointLocationSP location_sp : locations)
+    success &= location_sp->SetEnabled(true);
+  return success;
 }
 
 BreakpointLocationSP Breakpoint::AddLocation(const Address &addr,
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp 
b/lldb/source/Breakpoint/BreakpointLocation.cpp
index c7ea50407ae1c..574f1f3fec19b 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -74,15 +74,13 @@ bool BreakpointLocation::IsEnabled() const {
     return true;
 }
 
-void BreakpointLocation::SetEnabled(bool enabled) {
+bool BreakpointLocation::SetEnabled(bool enabled) {
   GetLocationOptions().SetEnabled(enabled);
-  if (enabled) {
-    ResolveBreakpointSite();
-  } else {
-    ClearBreakpointSite();
-  }
+  const bool success =
+      enabled ? ResolveBreakpointSite() : ClearBreakpointSite();
   SendBreakpointLocationChangedEvent(enabled ? eBreakpointEventTypeEnabled
                                              : eBreakpointEventTypeDisabled);
+  return success;
 }
 
 bool BreakpointLocation::IsAutoContinue() const {
diff --git 
a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
index abb5eef8f193f..80ba8a6447d98 100644
--- 
a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
+++ 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
@@ -22,7 +22,7 @@ def test(self):
 
         breakpoint = target.BreakpointCreateByLocation("main.c", 1)
         self.assertFalse(breakpoint.IsHardware())
-        breakpoint.SetIsHardware(True)
+        self.assertTrue(breakpoint.SetIsHardware(True))
         self.assertTrue(breakpoint.IsHardware())
 
         self.runCmd("run", RUN_SUCCEEDED)

>From 9a9e8a3161697b24ba61c162bb742e43212b133d Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jo...@devlieghere.com>
Date: Wed, 2 Jul 2025 09:47:57 -0700
Subject: [PATCH 3/3] More logging to debug test failure

---
 lldb/include/lldb/API/SBBreakpoint.h                      | 2 ++
 lldb/source/Breakpoint/BreakpointLocation.cpp             | 8 ++++----
 .../simple_hw_breakpoints/TestSimpleHWBreakpoints.py      | 4 ++++
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/API/SBBreakpoint.h 
b/lldb/include/lldb/API/SBBreakpoint.h
index 11f84034bd7b9..945bdb8369253 100644
--- a/lldb/include/lldb/API/SBBreakpoint.h
+++ b/lldb/include/lldb/API/SBBreakpoint.h
@@ -148,6 +148,8 @@ class LLDB_API SBBreakpoint {
 
   bool IsHardware() const;
 
+  /// Turn this breakpoint into a hardware breakpoint. Returns true if all
+  /// existing breakpoint locations were replaced with hardware breakpoints.
   bool SetIsHardware(bool is_hardware);
 
   // Can only be called from a ScriptedBreakpointResolver...
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp 
b/lldb/source/Breakpoint/BreakpointLocation.cpp
index 574f1f3fec19b..ae1d933cac4ca 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -443,10 +443,10 @@ bool BreakpointLocation::ResolveBreakpointSite() {
       process->CreateBreakpointSite(shared_from_this(), m_owner.IsHardware());
 
   if (new_id == LLDB_INVALID_BREAK_ID) {
-    Log *log = GetLog(LLDBLog::Breakpoints);
-    if (log)
-      log->Warning("Failed to add breakpoint site at 0x%" PRIx64,
-                   m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()));
+    LLDB_LOGF(GetLog(LLDBLog::Breakpoints),
+              "Failed to add breakpoint site at 0x%" PRIx64 "(resolved=%s)",
+              m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()),
+              IsResolved() ? "yes" : "no");
   }
 
   return IsResolved();
diff --git 
a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
index 80ba8a6447d98..c43ccd1f164c7 100644
--- 
a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
+++ 
b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/simple_hw_breakpoints/TestSimpleHWBreakpoints.py
@@ -20,6 +20,10 @@ def test(self):
         exe = self.getBuildArtifact("a.out")
         target = self.dbg.CreateTarget(exe)
 
+        if self.TraceOn():
+            self.runCmd("log enable lldb break")
+            self.addTearDownHook(lambda: self.runCmd("log disable lldb break"))
+
         breakpoint = target.BreakpointCreateByLocation("main.c", 1)
         self.assertFalse(breakpoint.IsHardware())
         self.assertTrue(breakpoint.SetIsHardware(True))

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

Reply via email to