[Lldb-commits] [lldb] [lldb-dap] Add missing supportsSingleThreadExecutionRequests in capabilities (PR #200314)

via lldb-commits lldb-commits at lists.llvm.org
Mon Jun 1 12:53:35 PDT 2026


https://github.com/kusmour updated https://github.com/llvm/llvm-project/pull/200314

>From 646796d84d4b11d32a0a1df652010ca227a6bd35 Mon Sep 17 00:00:00 2001
From: Wanyi Ye <wanyi at meta.com>
Date: Mon, 1 Jun 2026 10:16:03 -0700
Subject: [PATCH 1/2] [lldb] Support single thread for step out

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:


Differential Revision: https://phabricator.intern.facebook.com/D107144940
---
 lldb/include/lldb/API/SBThread.h              |  4 ++
 .../test/tools/lldb-dap/dap_server.py         |  4 +-
 .../test/tools/lldb-dap/lldbdap_testcase.py   |  7 ++-
 lldb/source/API/SBThread.cpp                  | 39 ++++++++++++++++
 .../API/tools/lldb-dap/step/TestDAP_step.py   | 45 +++++++++++++++++++
 .../Handler/StepOutRequestHandler.cpp         |  4 +-
 6 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h
index 97d3b838492fb..5f43f2318d580 100644
--- a/lldb/include/lldb/API/SBThread.h
+++ b/lldb/include/lldb/API/SBThread.h
@@ -121,6 +121,10 @@ class LLDB_API SBThread {
 
   void StepOut(SBError &error);
 
+  void StepOut(lldb::RunMode stop_other_threads);
+
+  void StepOut(lldb::RunMode stop_other_threads, SBError &error);
+
   void StepOutOfFrame(SBFrame &frame);
 
   void StepOutOfFrame(SBFrame &frame, SBError &error);
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index c8acf67b23b99..b8d44d3822703 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -1294,10 +1294,12 @@ def request_stepInTargets(self, frameId):
         }
         return self._send_recv(command_dict)
 
-    def request_stepOut(self, threadId):
+    def request_stepOut(self, threadId, singleThread=None):
         if self.exit_status is not None:
             raise ValueError("request_stepOut called after process exited")
         args_dict = {"threadId": threadId}
+        if singleThread is not None:
+            args_dict["singleThread"] = singleThread
         command_dict = {"command": "stepOut", "type": "request", "arguments": args_dict}
         return self._send_recv(command_dict)
 
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index 714a8c228a76b..22562308614a2 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -443,8 +443,11 @@ def stepOver(
             return self.dap_server.wait_for_stopped()
         return None
 
-    def stepOut(self, threadId=None, waitForStop=True):
-        self.dap_server.request_stepOut(threadId=threadId)
+    def stepOut(self, threadId=None, waitForStop=True, singleThread=None):
+        response = self.dap_server.request_stepOut(
+            threadId=threadId, singleThread=singleThread
+        )
+        self.assertTrue(response["success"])
         if waitForStop:
             return self.dap_server.wait_for_stopped()
         return None
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index fafb533771e56..9e3e553a426f3 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -621,6 +621,45 @@ void SBThread::StepOut(SBError &error) {
     error = Status::FromErrorString(new_plan_status.AsCString());
 }
 
+void SBThread::StepOut(lldb::RunMode stop_other_threads) {
+  LLDB_INSTRUMENT_VA(this, stop_other_threads);
+
+  SBError error; // Ignored
+  StepOut(stop_other_threads, error);
+}
+
+void SBThread::StepOut(lldb::RunMode stop_other_threads, SBError &error) {
+  LLDB_INSTRUMENT_VA(this, stop_other_threads, error);
+
+  llvm::Expected<StoppedExecutionContext> exe_ctx =
+      GetStoppedExecutionContext(m_opaque_sp);
+  if (!exe_ctx) {
+    error = Status::FromError(exe_ctx.takeError());
+    return;
+  }
+
+  if (!exe_ctx->HasThreadScope()) {
+    error = Status::FromErrorString("this SBThread object is invalid");
+    return;
+  }
+
+  bool abort_other_plans = false;
+
+  Thread *thread = exe_ctx->GetThreadPtr();
+
+  const LazyBool avoid_no_debug = eLazyBoolCalculate;
+  Status new_plan_status;
+  ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut(
+      abort_other_plans, nullptr, false,
+      stop_other_threads == eOnlyThisThread, eVoteYes, eVoteNoOpinion, 0,
+      new_plan_status, avoid_no_debug));
+
+  if (new_plan_status.Success())
+    error = ResumeNewPlan(std::move(*exe_ctx), new_plan_sp.get());
+  else
+    error = Status::FromErrorString(new_plan_status.AsCString());
+}
+
 void SBThread::StepOutOfFrame(SBFrame &sb_frame) {
   LLDB_INSTRUMENT_VA(this, sb_frame);
 
diff --git a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
index 5c055f679aedc..31c0ea4ad1669 100644
--- a/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
+++ b/lldb/test/API/tools/lldb-dap/step/TestDAP_step.py
@@ -84,6 +84,51 @@ def test_step(self):
                     # only step one thread that is at the breakpoint and stop
                     break
 
+    @skipIfWindows
+    def test_step_out_single_thread(self):
+        """
+        Tests step out with singleThread=true correctly completes the step.
+        """
+        program = self.getBuildArtifact("a.out")
+        self.build_and_launch(program)
+        source = "main.cpp"
+        breakpoint1_line = line_number(source, "// breakpoint 1")
+        lines = [breakpoint1_line]
+        breakpoint_ids = self.set_source_breakpoints(source, lines)
+        self.assertEqual(
+            len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
+        )
+        self.continue_to_breakpoints(breakpoint_ids)
+        threads = self.dap_server.get_threads()
+        for thread in threads:
+            if "reason" in thread:
+                reason = thread["reason"]
+                if reason == "breakpoint":
+                    tid = thread["id"]
+                    x1 = self.get_local_as_int("x", threadId=tid)
+                    (src1, line1) = self.get_source_and_line(threadId=tid)
+
+                    # Step into the recursive call first so we have
+                    # a frame to step out of.
+                    self.stepIn(threadId=tid, waitForStop=True)
+                    x2 = self.get_local_as_int("x", threadId=tid)
+                    (src2, line2) = self.get_source_and_line(threadId=tid)
+                    self.assertEqual(x1, x2 + 1, "verify step in variable")
+
+                    # Now step out with singleThread and verify we
+                    # return to the caller frame.
+                    self.stepOut(
+                        threadId=tid, waitForStop=True, singleThread=True
+                    )
+                    x3 = self.get_local_as_int("x", threadId=tid)
+                    (src3, line3) = self.get_source_and_line(threadId=tid)
+                    self.assertEqual(x1, x3, "verify step out variable")
+                    self.assertGreaterEqual(
+                        line3, line1, "verify step out line"
+                    )
+                    self.assertEqual(src1, src3, "verify step out source")
+                    break
+
     def test_step_over_inlined_function(self):
         """
         Test stepping over when the program counter is in another file.
diff --git a/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
index 61bde76e08a3d..f573f2fe1e25b 100644
--- a/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp
@@ -41,7 +41,9 @@ Error StepOutRequestHandler::Run(const StepOutArguments &arguments) const {
   // "threadCausedFocus" boolean value in the "stopped" events.
   dap.focus_tid = thread.GetThreadID();
   lldb::SBError error;
-  thread.StepOut(error);
+  thread.StepOut(arguments.singleThread.value_or(false) ? eOnlyThisThread
+                                                        : eOnlyDuringStepping,
+                 error);
 
   return ToError(error);
 }

>From 6b82ac40d92960bd352a048c472dea097a345053 Mon Sep 17 00:00:00 2001
From: Wanyi Ye <wanyi at meta.com>
Date: Thu, 28 May 2026 16:50:57 -0700
Subject: [PATCH 2/2] [lldb-dap] Add missing
 supportsSingleThreadExecutionRequests in capabilities

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:


Differential Revision: https://phabricator.intern.facebook.com/D107144941
---
 lldb/docs/use/lldbdap.md    | 2 +-
 lldb/tools/lldb-dap/DAP.cpp | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/lldb/docs/use/lldbdap.md b/lldb/docs/use/lldbdap.md
index a4c151a2ff39c..a684b52afd31a 100644
--- a/lldb/docs/use/lldbdap.md
+++ b/lldb/docs/use/lldbdap.md
@@ -109,7 +109,7 @@ for more information.
 | supportsSteppingGranularity           | Y                       | The debug adapter supports stepping granularities (argument `granularity`) for the stepping requests.                                                                                                                                                                                                                 |
 | supportsInstructionBreakpoints        | Y                       | The debug adapter supports adding breakpoints based on instruction references.                                                                                                                                                                                                                                        |
 | supportsExceptionFilterOptions        | N                       | The debug adapter supports `filterOptions` as an argument on the `setExceptionBreakpoints` request.                                                                                                                                                                                                                   |
-| supportsSingleThreadExecutionRequests | N                       | The debug adapter supports the `singleThread` property on the execution requests (`continue`, `next`, `stepIn`, `stepOut`, `reverseContinue`, `stepBack`).                                                                                                                                                            |
+| supportsSingleThreadExecutionRequests | Y                       | The debug adapter supports the `singleThread` property on the execution requests (lldb-dap supported: `continue`, `next`, `stepIn`; lldb-dap not yet supported: `stepOut`, `reverseContinue`, `stepBack`).                                                                                                                                                            |
 | supportsDataBreakpointBytes           | Y                       | The debug adapter supports the `asAddress` and `bytes` fields in the `dataBreakpointInfo` request.                                                                                                                                                                                                                    |
 | breakpointModes                       | `[]`                    | Modes of breakpoints supported by the debug adapter, such as 'hardware' or 'software'. If present, the client may allow the user to select a mode and include it in its `setBreakpoints` request. Clients may present the first applicable mode in this array as the 'default' mode in gestures that set breakpoints. |
 | supportsANSIStyling                   | Y                       | The debug adapter supports ANSI escape sequences in styling of `OutputEvent.output` and `Variable.value` fields.                                                                                                                                                                                                      |
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index cb34c7b2fd1e8..81388eae2a275 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -1220,6 +1220,7 @@ protocol::Capabilities DAP::GetCapabilities() {
   // Supported capabilities that are not specific to a single request.
   capabilities.supportedFeatures = {
       protocol::eAdapterFeatureLogPoints,
+      protocol::eAdapterFeatureSingleThreadExecutionRequests,
       protocol::eAdapterFeatureSteppingGranularity,
       protocol::eAdapterFeatureValueFormattingOptions,
   };



More information about the lldb-commits mailing list