[Lldb-commits] [lldb] [lldb] Interpret breakpoint-id "." as the location(s) of the current stop (PR #194272)

Dave Lee via lldb-commits lldb-commits at lists.llvm.org
Tue Apr 28 13:03:25 PDT 2026


https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/194272

>From a4cce4cabe507c26a015e11aa860c603a7794889 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Sun, 26 Apr 2026 16:26:02 -0700
Subject: [PATCH 1/7] [lldb] Interpret breakpoint-id "." as meaning the
 locations of the current stop

---
 .../lldb/Breakpoint/BreakpointIDList.h        |  3 +-
 lldb/source/Breakpoint/BreakpointIDList.cpp   | 38 ++++++++++++++-
 .../Commands/CommandObjectBreakpoint.cpp      | 23 ++++-----
 .../source/Commands/CommandObjectBreakpoint.h | 13 ++---
 .../CommandObjectBreakpointCommand.cpp        |  6 +--
 lldb/source/Commands/CommandObjectProcess.cpp |  2 +-
 .../test/API/commands/breakpoint/dot/Makefile |  3 ++
 .../breakpoint/dot/TestBreakpointDot.py       | 48 +++++++++++++++++++
 lldb/test/API/commands/breakpoint/dot/main.c  |  4 ++
 9 files changed, 117 insertions(+), 23 deletions(-)
 create mode 100644 lldb/test/API/commands/breakpoint/dot/Makefile
 create mode 100644 lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
 create mode 100644 lldb/test/API/commands/breakpoint/dot/main.c

diff --git a/lldb/include/lldb/Breakpoint/BreakpointIDList.h b/lldb/include/lldb/Breakpoint/BreakpointIDList.h
index f2eaa60d95413..d361208c08164 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointIDList.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointIDList.h
@@ -51,7 +51,8 @@ class BreakpointIDList {
   SplitIDRangeExpression(llvm::StringRef in_string);
 
   static llvm::Error
-  FindAndReplaceIDRanges(Args &old_args, Target *target, bool allow_locations,
+  FindAndReplaceIDRanges(Args &old_args, ExecutionContext &exe_ctx,
+                         bool allow_locations,
                          BreakpointName::Permissions ::PermissionKinds purpose,
                          Args &new_args);
 
diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp
index 8c46b39c02a9e..16f3616bca88a 100644
--- a/lldb/source/Breakpoint/BreakpointIDList.cpp
+++ b/lldb/source/Breakpoint/BreakpointIDList.cpp
@@ -11,9 +11,13 @@
 
 #include "lldb/Breakpoint/Breakpoint.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/StopInfo.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
 #include "lldb/Utility/Args.h"
 #include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-forward.h"
 
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -55,6 +59,15 @@ bool BreakpointIDList::Contains(BreakpointID bp_id) const {
   return llvm::is_contained(m_breakpoint_ids, bp_id);
 }
 
+static std::string_view BreakpointIDForStop(StopInfoSP stop_info_sp,
+                                            uint32_t idx) {
+  break_id_t bp_id = stop_info_sp->GetStopReasonDataAtIndex(idx);
+  break_id_t loc_id = stop_info_sp->GetStopReasonDataAtIndex(idx + 1);
+  StreamString stream;
+  BreakpointID::GetCanonicalReference(&stream, bp_id, loc_id);
+  return stream.GetString();
+}
+
 //  This function takes OLD_ARGS, which is usually the result of breaking the
 //  command string arguments into
 //  an array of space-separated strings, and searches through the arguments for
@@ -69,8 +82,9 @@ bool BreakpointIDList::Contains(BreakpointID bp_id) const {
 //  by the members of the range.
 
 llvm::Error BreakpointIDList::FindAndReplaceIDRanges(
-    Args &old_args, Target *target, bool allow_locations,
+    Args &old_args, ExecutionContext &exe_ctx, bool allow_locations,
     BreakpointName::Permissions ::PermissionKinds purpose, Args &new_args) {
+  Target *target = exe_ctx.GetTargetPtr();
   llvm::StringRef range_from;
   llvm::StringRef range_to;
   llvm::StringRef current_arg;
@@ -80,6 +94,28 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges(
     bool is_range = false;
 
     current_arg = old_args[i].ref();
+
+    if (current_arg == ".") {
+      Thread *thread = exe_ctx.GetThreadPtr();
+      if (!thread) {
+        new_args.Clear();
+        return llvm::createStringError("no current thread");
+      }
+      StopInfoSP stop_info_sp = thread->GetStopInfo();
+      if (!stop_info_sp ||
+          stop_info_sp->GetStopReason() != eStopReasonBreakpoint) {
+        new_args.Clear();
+        return llvm::createStringError(
+            "current thread is not stopped at a breakpoint.");
+      }
+
+      uint32_t data_count = stop_info_sp->GetStopReasonDataCount();
+      for (uint32_t j = 0; j < data_count; j += 2)
+        new_args.AppendArgument(BreakpointIDForStop(stop_info_sp, j));
+
+      continue;
+    }
+
     if (!allow_locations && current_arg.contains('.')) {
       new_args.Clear();
       return llvm::createStringError(
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
index 02ddb8aa5b4b3..bb71055ebb3cb 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -2073,7 +2073,7 @@ class CommandObjectBreakpointModify : public CommandObjectParsed {
     BreakpointIDList valid_bp_ids;
 
     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-        command, target, result, &valid_bp_ids,
+        command, m_exe_ctx, result, &valid_bp_ids,
         BreakpointName::Permissions::PermissionKinds::disablePerm);
 
     if (result.Succeeded()) {
@@ -2153,7 +2153,7 @@ class CommandObjectBreakpointEnable : public CommandObjectParsed {
       // Particular breakpoint selected; enable that breakpoint.
       BreakpointIDList valid_bp_ids;
       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-          command, target, result, &valid_bp_ids,
+          command, m_exe_ctx, result, &valid_bp_ids,
           BreakpointName::Permissions::PermissionKinds::disablePerm);
 
       if (result.Succeeded()) {
@@ -2261,7 +2261,7 @@ the second re-enables the first location.");
       BreakpointIDList valid_bp_ids;
 
       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-          command, target, result, &valid_bp_ids,
+          command, m_exe_ctx, result, &valid_bp_ids,
           BreakpointName::Permissions::PermissionKinds::disablePerm);
 
       if (result.Succeeded()) {
@@ -2406,7 +2406,7 @@ class CommandObjectBreakpointList : public CommandObjectParsed {
       // Particular breakpoints selected; show info about that breakpoint.
       BreakpointIDList valid_bp_ids;
       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-          command, target, result, &valid_bp_ids,
+          command, m_exe_ctx, result, &valid_bp_ids,
           BreakpointName::Permissions::PermissionKinds::listPerm);
 
       if (result.Succeeded()) {
@@ -2685,7 +2685,7 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed {
 
       if (!command.empty()) {
         CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-            command, target, result, &excluded_bp_ids,
+            command, m_exe_ctx, result, &excluded_bp_ids,
             BreakpointName::Permissions::PermissionKinds::deletePerm);
         if (!result.Succeeded())
           return;
@@ -2704,7 +2704,7 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed {
       }
     } else {
       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-          command, target, result, &valid_bp_ids,
+          command, m_exe_ctx, result, &valid_bp_ids,
           BreakpointName::Permissions::PermissionKinds::deletePerm);
       if (!result.Succeeded())
         return;
@@ -3015,7 +3015,7 @@ class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
     // Particular breakpoint selected; disable that breakpoint.
     BreakpointIDList valid_bp_ids;
     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
-        command, target, result, &valid_bp_ids,
+        command, m_exe_ctx, result, &valid_bp_ids,
         BreakpointName::Permissions::PermissionKinds::listPerm);
 
     if (result.Succeeded()) {
@@ -3089,7 +3089,7 @@ class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
     // Particular breakpoint selected; disable that breakpoint.
     BreakpointIDList valid_bp_ids;
     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
-        command, target, result, &valid_bp_ids,
+        command, m_exe_ctx, result, &valid_bp_ids,
         BreakpointName::Permissions::PermissionKinds::deletePerm);
 
     if (result.Succeeded()) {
@@ -3562,7 +3562,7 @@ class CommandObjectBreakpointWrite : public CommandObjectParsed {
     BreakpointIDList valid_bp_ids;
     if (!command.empty()) {
       CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
-          command, target, result, &valid_bp_ids,
+          command, m_exe_ctx, result, &valid_bp_ids,
           BreakpointName::Permissions::PermissionKinds::listPerm);
 
       if (!result.Succeeded()) {
@@ -3648,7 +3648,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
 
 void CommandObjectMultiwordBreakpoint::VerifyIDs(
-    Args &args, Target &target, bool allow_locations,
+    Args &args, ExecutionContext &exe_ctx, bool allow_locations,
     CommandReturnObject &result, BreakpointIDList *valid_ids,
     BreakpointName::Permissions ::PermissionKinds purpose) {
   // args can be strings representing 1). integers (for breakpoint ids)
@@ -3662,6 +3662,7 @@ void CommandObjectMultiwordBreakpoint::VerifyIDs(
   // If args is empty, we will use the last created breakpoint (if there is
   // one.)
 
+  Target &target = exe_ctx.GetTargetRef();
   Args temp_args;
 
   if (args.empty()) {
@@ -3683,7 +3684,7 @@ void CommandObjectMultiwordBreakpoint::VerifyIDs(
   // into TEMP_ARGS.
 
   if (llvm::Error err = BreakpointIDList::FindAndReplaceIDRanges(
-          args, &target, allow_locations, purpose, temp_args)) {
+          args, exe_ctx, allow_locations, purpose, temp_args)) {
     result.SetError(std::move(err));
     return;
   }
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.h b/lldb/source/Commands/CommandObjectBreakpoint.h
index 40c67157e07c4..eaee254e0079f 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.h
+++ b/lldb/source/Commands/CommandObjectBreakpoint.h
@@ -23,22 +23,23 @@ class CommandObjectMultiwordBreakpoint : public CommandObjectMultiword {
   ~CommandObjectMultiwordBreakpoint() override;
 
   static void VerifyBreakpointOrLocationIDs(
-      Args &args, Target &target, CommandReturnObject &result,
+      Args &args, ExecutionContext &exe_ctx, CommandReturnObject &result,
       BreakpointIDList *valid_ids,
       BreakpointName::Permissions ::PermissionKinds purpose) {
-    VerifyIDs(args, target, true, result, valid_ids, purpose);
+    VerifyIDs(args, exe_ctx, true, result, valid_ids, purpose);
   }
 
   static void
-  VerifyBreakpointIDs(Args &args, Target &target, CommandReturnObject &result,
+  VerifyBreakpointIDs(Args &args, ExecutionContext &exe_ctx,
+                      CommandReturnObject &result,
                       BreakpointIDList *valid_ids,
                       BreakpointName::Permissions::PermissionKinds purpose) {
-    VerifyIDs(args, target, false, result, valid_ids, purpose);
+    VerifyIDs(args, exe_ctx, false, result, valid_ids, purpose);
   }
 
 private:
-  static void VerifyIDs(Args &args, Target &target, bool allow_locations,
-                        CommandReturnObject &result,
+  static void VerifyIDs(Args &args, ExecutionContext &exe_ctx,
+                        bool allow_locations, CommandReturnObject &result,
                         BreakpointIDList *valid_ids,
                         BreakpointName::Permissions::PermissionKinds purpose);
 };
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
index f9110d23042d5..03ca1e3e87748 100644
--- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -344,7 +344,7 @@ are no syntax errors may indicate that a function was declared but never called.
 
     BreakpointIDList valid_bp_ids;
     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-        command, target, result, &valid_bp_ids,
+        command, m_exe_ctx, result, &valid_bp_ids,
         BreakpointName::Permissions::PermissionKinds::listPerm);
 
     m_bp_options_vec.clear();
@@ -500,7 +500,7 @@ class CommandObjectBreakpointCommandDelete : public CommandObjectParsed {
 
     BreakpointIDList valid_bp_ids;
     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-        command, target, result, &valid_bp_ids,
+        command, m_exe_ctx, result, &valid_bp_ids,
         BreakpointName::Permissions::PermissionKinds::listPerm);
 
     if (result.Succeeded()) {
@@ -567,7 +567,7 @@ class CommandObjectBreakpointCommandList : public CommandObjectParsed {
 
     BreakpointIDList valid_bp_ids;
     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-        command, target, result, &valid_bp_ids,
+        command, m_exe_ctx, result, &valid_bp_ids,
         BreakpointName::Permissions::PermissionKinds::listPerm);
 
     if (result.Succeeded()) {
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 32a2b32f294b2..e4ce38eea2ebb 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -533,7 +533,7 @@ class CommandObjectProcessContinue : public CommandObjectParsed {
       // default breakpoint.
       if (m_options.m_run_to_bkpt_args.GetArgumentCount() > 0)
         CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
-            m_options.m_run_to_bkpt_args, target, result, &run_to_bkpt_ids,
+            m_options.m_run_to_bkpt_args, m_exe_ctx, result, &run_to_bkpt_ids,
             BreakpointName::Permissions::disablePerm);
       if (!result.Succeeded()) {
         return;
diff --git a/lldb/test/API/commands/breakpoint/dot/Makefile b/lldb/test/API/commands/breakpoint/dot/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/commands/breakpoint/dot/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
new file mode 100644
index 0000000000000..2bc53963fdc36
--- /dev/null
+++ b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
@@ -0,0 +1,48 @@
+"""Test breakpoint '.' ID - the current stopped breakpoint."""
+
+import lldb
+from lldbsuite.test.lldbtest import TestBase
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    def test_disable(self):
+        self.build()
+        _, _, _, bp = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.c")
+        )
+
+        self.assertTrue(bp.FindLocationByID(1).IsEnabled())
+        self.expect("breakpoint disable .", startstr="1 breakpoints disabled.")
+        self.assertFalse(bp.FindLocationByID(1).IsEnabled())
+
+    def test_enable(self):
+        self.build()
+        _, _, _, bp = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.c")
+        )
+
+        bp.FindLocationByID(1).SetEnabled(False)
+        self.assertFalse(bp.FindLocationByID(1).IsEnabled())
+        self.expect("breakpoint enable .", startstr="1 breakpoints enabled.")
+        self.assertTrue(bp.FindLocationByID(1).IsEnabled())
+
+    def test_delete(self):
+        self.build()
+        _, _, _, bp = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.c")
+        )
+
+        self.expect(
+            "breakpoint delete .",
+            startstr="0 breakpoints deleted; 1 breakpoint locations disabled",
+        )
+        self.assertFalse(bp.FindLocationByID(1).IsEnabled())
+
+    def test_error_no_process(self):
+        self.build()
+        target = self.createTestTarget()
+        target.BreakpointCreateByLocation("main.c", 2)
+        self.expect(
+            "breakpoint disable .", error=True, substrs=["no current thread"]
+        )
diff --git a/lldb/test/API/commands/breakpoint/dot/main.c b/lldb/test/API/commands/breakpoint/dot/main.c
new file mode 100644
index 0000000000000..51083e9c9bac6
--- /dev/null
+++ b/lldb/test/API/commands/breakpoint/dot/main.c
@@ -0,0 +1,4 @@
+int main() {
+  int x = 1; // break here
+  return x;
+}

>From 60ade547b2cef667943784c9f4215a046c238db5 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Sun, 26 Apr 2026 16:39:32 -0700
Subject: [PATCH 2/7] formatting

---
 lldb/include/lldb/Breakpoint/BreakpointIDList.h           | 8 +++-----
 lldb/source/Commands/CommandObjectBreakpoint.h            | 3 +--
 .../test/API/commands/breakpoint/dot/TestBreakpointDot.py | 4 +---
 3 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/lldb/include/lldb/Breakpoint/BreakpointIDList.h b/lldb/include/lldb/Breakpoint/BreakpointIDList.h
index d361208c08164..3354a3a24893a 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointIDList.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointIDList.h
@@ -50,11 +50,9 @@ class BreakpointIDList {
   static std::pair<llvm::StringRef, llvm::StringRef>
   SplitIDRangeExpression(llvm::StringRef in_string);
 
-  static llvm::Error
-  FindAndReplaceIDRanges(Args &old_args, ExecutionContext &exe_ctx,
-                         bool allow_locations,
-                         BreakpointName::Permissions ::PermissionKinds purpose,
-                         Args &new_args);
+  static llvm::Error FindAndReplaceIDRanges(
+      Args &old_args, ExecutionContext &exe_ctx, bool allow_locations,
+      BreakpointName::Permissions ::PermissionKinds purpose, Args &new_args);
 
 private:
   BreakpointIDArray m_breakpoint_ids;
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.h b/lldb/source/Commands/CommandObjectBreakpoint.h
index eaee254e0079f..7e2fa045eb744 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.h
+++ b/lldb/source/Commands/CommandObjectBreakpoint.h
@@ -31,8 +31,7 @@ class CommandObjectMultiwordBreakpoint : public CommandObjectMultiword {
 
   static void
   VerifyBreakpointIDs(Args &args, ExecutionContext &exe_ctx,
-                      CommandReturnObject &result,
-                      BreakpointIDList *valid_ids,
+                      CommandReturnObject &result, BreakpointIDList *valid_ids,
                       BreakpointName::Permissions::PermissionKinds purpose) {
     VerifyIDs(args, exe_ctx, false, result, valid_ids, purpose);
   }
diff --git a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
index 2bc53963fdc36..7bc2104961010 100644
--- a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
+++ b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
@@ -43,6 +43,4 @@ def test_error_no_process(self):
         self.build()
         target = self.createTestTarget()
         target.BreakpointCreateByLocation("main.c", 2)
-        self.expect(
-            "breakpoint disable .", error=True, substrs=["no current thread"]
-        )
+        self.expect("breakpoint disable .", error=True, substrs=["no current thread"])

>From b081f4311630d4488fa29989cbb89bf6bbcc6d47 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Mon, 27 Apr 2026 07:39:11 -0700
Subject: [PATCH 3/7] Update breakpt-id help text

---
 lldb/source/Commands/CommandOptionArgumentTable.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Commands/CommandOptionArgumentTable.cpp b/lldb/source/Commands/CommandOptionArgumentTable.cpp
index e8e9307b62919..2af9e544e43de 100644
--- a/lldb/source/Commands/CommandOptionArgumentTable.cpp
+++ b/lldb/source/Commands/CommandOptionArgumentTable.cpp
@@ -49,7 +49,10 @@ llvm::StringRef BreakpointIDHelpTextCallback() {
          "major "
          "number, or the major number followed by a dot and the location "
          "number (e.g. "
-         "3 or 3.2 could both be valid breakpoint IDs.)";
+         "3 or 3.2 could both be valid breakpoint IDs.)\n"
+         "\n"
+         "You can use . to refer to the breakpoint location(s) on which the "
+         "process is currently stopped.";
 }
 
 llvm::StringRef BreakpointIDRangeHelpTextCallback() {

>From d1d7a690b8e6c8d16bee301f02db78976361a8ca Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Mon, 27 Apr 2026 08:19:58 -0700
Subject: [PATCH 4/7] remove full stop from error string

---
 lldb/source/Breakpoint/BreakpointIDList.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp
index 16f3616bca88a..9311e6716295f 100644
--- a/lldb/source/Breakpoint/BreakpointIDList.cpp
+++ b/lldb/source/Breakpoint/BreakpointIDList.cpp
@@ -106,7 +106,7 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges(
           stop_info_sp->GetStopReason() != eStopReasonBreakpoint) {
         new_args.Clear();
         return llvm::createStringError(
-            "current thread is not stopped at a breakpoint.");
+            "current thread is not stopped at a breakpoint");
       }
 
       uint32_t data_count = stop_info_sp->GetStopReasonDataCount();

>From 3802f7b6b268fcab6866369c18e4f5b496e19710 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Mon, 27 Apr 2026 08:27:42 -0700
Subject: [PATCH 5/7] Add test for non-breakpoint stop

---
 .../commands/breakpoint/dot/TestBreakpointDot.py | 16 ++++++++++++++++
 lldb/test/API/commands/breakpoint/dot/main.c     |  3 ++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
index 7bc2104961010..42e688b7858f6 100644
--- a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
+++ b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
@@ -39,6 +39,22 @@ def test_delete(self):
         )
         self.assertFalse(bp.FindLocationByID(1).IsEnabled())
 
+    def test_error_not_breakpoint_stop(self):
+        self.build()
+        _, _, thread, bp = lldbutil.run_to_source_breakpoint(
+            self, "break here", lldb.SBFileSpec("main.c")
+        )
+
+        self.assertTrue(bp.FindLocationByID(1).IsEnabled())
+        thread.StepOver()
+        self.assertNotEqual(thread.stop_reason, lldb.eStopReasonBreakpoint)
+        self.expect(
+            "breakpoint disable .",
+            error=True,
+            startstr="error: current thread is not stopped at a breakpoint",
+        )
+        self.assertTrue(bp.FindLocationByID(1).IsEnabled())
+
     def test_error_no_process(self):
         self.build()
         target = self.createTestTarget()
diff --git a/lldb/test/API/commands/breakpoint/dot/main.c b/lldb/test/API/commands/breakpoint/dot/main.c
index 51083e9c9bac6..f4a494dd4bc25 100644
--- a/lldb/test/API/commands/breakpoint/dot/main.c
+++ b/lldb/test/API/commands/breakpoint/dot/main.c
@@ -1,4 +1,5 @@
 int main() {
   int x = 1; // break here
-  return x;
+  int y = 2;
+  return x + y;
 }

>From 7f598d2592d8d2e370214bddd9d5d02acac1cef8 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Tue, 28 Apr 2026 12:16:05 -0700
Subject: [PATCH 6/7] Location . fine tuning

---
 lldb/source/Breakpoint/BreakpointIDList.cpp         | 13 +++++++------
 lldb/source/Commands/CommandOptionArgumentTable.cpp |  4 ++--
 .../commands/breakpoint/dot/TestBreakpointDot.py    | 12 ++----------
 3 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp
index 9311e6716295f..ef987abe13bb2 100644
--- a/lldb/source/Breakpoint/BreakpointIDList.cpp
+++ b/lldb/source/Breakpoint/BreakpointIDList.cpp
@@ -59,13 +59,12 @@ bool BreakpointIDList::Contains(BreakpointID bp_id) const {
   return llvm::is_contained(m_breakpoint_ids, bp_id);
 }
 
-static std::string_view BreakpointIDForStop(StopInfoSP stop_info_sp,
-                                            uint32_t idx) {
+static std::string LocationIDForStop(StopInfoSP stop_info_sp, uint32_t idx) {
   break_id_t bp_id = stop_info_sp->GetStopReasonDataAtIndex(idx);
   break_id_t loc_id = stop_info_sp->GetStopReasonDataAtIndex(idx + 1);
   StreamString stream;
   BreakpointID::GetCanonicalReference(&stream, bp_id, loc_id);
-  return stream.GetString();
+  return stream.GetString().str();
 }
 
 //  This function takes OLD_ARGS, which is usually the result of breaking the
@@ -95,7 +94,7 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges(
 
     current_arg = old_args[i].ref();
 
-    if (current_arg == ".") {
+    if (allow_locations && current_arg == ".") {
       Thread *thread = exe_ctx.GetThreadPtr();
       if (!thread) {
         new_args.Clear();
@@ -110,8 +109,10 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges(
       }
 
       uint32_t data_count = stop_info_sp->GetStopReasonDataCount();
-      for (uint32_t j = 0; j < data_count; j += 2)
-        new_args.AppendArgument(BreakpointIDForStop(stop_info_sp, j));
+      for (uint32_t j = 0; j < data_count; j += 2) {
+        std::string location_id = LocationIDForStop(stop_info_sp, j);
+        new_args.AppendArgument(location_id);
+      }
 
       continue;
     }
diff --git a/lldb/source/Commands/CommandOptionArgumentTable.cpp b/lldb/source/Commands/CommandOptionArgumentTable.cpp
index 2af9e544e43de..4d267ba111e16 100644
--- a/lldb/source/Commands/CommandOptionArgumentTable.cpp
+++ b/lldb/source/Commands/CommandOptionArgumentTable.cpp
@@ -51,8 +51,8 @@ llvm::StringRef BreakpointIDHelpTextCallback() {
          "number (e.g. "
          "3 or 3.2 could both be valid breakpoint IDs.)\n"
          "\n"
-         "You can use . to refer to the breakpoint location(s) on which the "
-         "process is currently stopped.";
+         "You can use . to refer to the breakpoint location(s) at which the "
+         "current thread is stopped.";
 }
 
 llvm::StringRef BreakpointIDRangeHelpTextCallback() {
diff --git a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
index 42e688b7858f6..5370372aaf220 100644
--- a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
+++ b/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
@@ -6,7 +6,8 @@
 
 
 class TestCase(TestBase):
-    def test_disable(self):
+
+    def test_disable_enable(self):
         self.build()
         _, _, _, bp = lldbutil.run_to_source_breakpoint(
             self, "break here", lldb.SBFileSpec("main.c")
@@ -15,15 +16,6 @@ def test_disable(self):
         self.assertTrue(bp.FindLocationByID(1).IsEnabled())
         self.expect("breakpoint disable .", startstr="1 breakpoints disabled.")
         self.assertFalse(bp.FindLocationByID(1).IsEnabled())
-
-    def test_enable(self):
-        self.build()
-        _, _, _, bp = lldbutil.run_to_source_breakpoint(
-            self, "break here", lldb.SBFileSpec("main.c")
-        )
-
-        bp.FindLocationByID(1).SetEnabled(False)
-        self.assertFalse(bp.FindLocationByID(1).IsEnabled())
         self.expect("breakpoint enable .", startstr="1 breakpoints enabled.")
         self.assertTrue(bp.FindLocationByID(1).IsEnabled())
 

>From c8fefdbda8344d7e13fbdf7b10ef70fde98fd836 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Tue, 28 Apr 2026 12:22:30 -0700
Subject: [PATCH 7/7] Rename tests

---
 lldb/test/API/commands/breakpoint/{dot => location-dot}/Makefile  | 0
 .../TestBreakpointLocationDot.py}                                 | 0
 lldb/test/API/commands/breakpoint/{dot => location-dot}/main.c    | 0
 3 files changed, 0 insertions(+), 0 deletions(-)
 rename lldb/test/API/commands/breakpoint/{dot => location-dot}/Makefile (100%)
 rename lldb/test/API/commands/breakpoint/{dot/TestBreakpointDot.py => location-dot/TestBreakpointLocationDot.py} (100%)
 rename lldb/test/API/commands/breakpoint/{dot => location-dot}/main.c (100%)

diff --git a/lldb/test/API/commands/breakpoint/dot/Makefile b/lldb/test/API/commands/breakpoint/location-dot/Makefile
similarity index 100%
rename from lldb/test/API/commands/breakpoint/dot/Makefile
rename to lldb/test/API/commands/breakpoint/location-dot/Makefile
diff --git a/lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py b/lldb/test/API/commands/breakpoint/location-dot/TestBreakpointLocationDot.py
similarity index 100%
rename from lldb/test/API/commands/breakpoint/dot/TestBreakpointDot.py
rename to lldb/test/API/commands/breakpoint/location-dot/TestBreakpointLocationDot.py
diff --git a/lldb/test/API/commands/breakpoint/dot/main.c b/lldb/test/API/commands/breakpoint/location-dot/main.c
similarity index 100%
rename from lldb/test/API/commands/breakpoint/dot/main.c
rename to lldb/test/API/commands/breakpoint/location-dot/main.c



More information about the lldb-commits mailing list