[Lldb-commits] [lldb] 47c7e73 - Revert "[lldb-dap] Change the launch sequence (#138219)"

David Spickett via lldb-commits lldb-commits at lists.llvm.org
Wed May 7 02:12:48 PDT 2025


Author: David Spickett
Date: 2025-05-07T09:11:09Z
New Revision: 47c7e73e5763f81f218cc4e1eae306d0427aa42d

URL: https://github.com/llvm/llvm-project/commit/47c7e73e5763f81f218cc4e1eae306d0427aa42d
DIFF: https://github.com/llvm/llvm-project/commit/47c7e73e5763f81f218cc4e1eae306d0427aa42d.diff

LOG: Revert "[lldb-dap] Change the launch sequence (#138219)"

This reverts commit ba29e60f9a2222bd5e883579bb78db13fc5a7588.

As it broke tests on Windows on Arm: https://lab.llvm.org/buildbot/#/builders/141/builds/8500

********************
Unresolved Tests (2):
  lldb-api :: tools/lldb-dap/completions/TestDAP_completions.py
  lldb-api :: tools/lldb-dap/startDebugging/TestDAP_startDebugging.py
********************
Timed Out Tests (1):
  lldb-api :: tools/lldb-dap/send-event/TestDAP_sendEvent.py
********************
Failed Tests (6):
  lldb-api :: tools/lldb-dap/console/TestDAP_console.py
  lldb-api :: tools/lldb-dap/console/TestDAP_redirection_to_console.py
  lldb-api :: tools/lldb-dap/launch/TestDAP_launch.py
  lldb-api :: tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
  lldb-api :: tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py
  lldb-api :: tools/lldb-dap/variables/children/TestDAP_variables_children.py

Added: 
    

Modified: 
    lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
    lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
    lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
    lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
    lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
    lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py
    lldb/test/API/tools/lldb-dap/console/TestDAP_console.py
    lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
    lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
    lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
    lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py
    lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py
    lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py
    lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py
    lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py
    lldb/tools/lldb-dap/DAP.cpp
    lldb/tools/lldb-dap/DAP.h
    lldb/tools/lldb-dap/EventHelper.cpp
    lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/RequestHandler.cpp
    lldb/tools/lldb-dap/Handler/RequestHandler.h

Removed: 
    


################################################################################
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 e10342b72f4f0..6d9ab770684f1 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
@@ -132,6 +132,7 @@ def __init__(self, recv, send, init_commands, log_file=None):
         self.exit_status = None
         self.initialize_body = None
         self.thread_stop_reasons = {}
+        self.breakpoint_events = []
         self.progress_events = []
         self.reverse_requests = []
         self.module_events = []
@@ -243,6 +244,13 @@ def handle_recv_packet(self, packet):
                 self._process_stopped()
                 tid = body["threadId"]
                 self.thread_stop_reasons[tid] = body
+            elif event == "breakpoint":
+                # Breakpoint events come in when a breakpoint has locations
+                # added or removed. Keep track of them so we can look for them
+                # in tests.
+                self.breakpoint_events.append(packet)
+                # no need to add 'breakpoint' event packets to our packets list
+                return keepGoing
             elif event.startswith("progress"):
                 # Progress events come in as 'progressStart', 'progressUpdate',
                 # and 'progressEnd' events. Keep these around in case test
@@ -404,15 +412,6 @@ def wait_for_stopped(self, timeout=None):
             self.threads = []
         return stopped_events
 
-    def wait_for_breakpoint_events(self, timeout=None):
-        breakpoint_events = []
-        while True:
-            event = self.wait_for_event("breakpoint", timeout=timeout)
-            if not event:
-                break
-            breakpoint_events.append(event)
-        return breakpoint_events
-
     def wait_for_exited(self):
         event_dict = self.wait_for_event("exited")
         if event_dict is None:
@@ -592,7 +591,6 @@ def request_attach(
         attachCommands=None,
         terminateCommands=None,
         coreFile=None,
-        stopOnAttach=True,
         postRunCommands=None,
         sourceMap=None,
         gdbRemotePort=None,
@@ -622,8 +620,6 @@ def request_attach(
             args_dict["attachCommands"] = attachCommands
         if coreFile:
             args_dict["coreFile"] = coreFile
-        if stopOnAttach:
-            args_dict["stopOnEntry"] = stopOnAttach
         if postRunCommands:
             args_dict["postRunCommands"] = postRunCommands
         if sourceMap:
@@ -636,7 +632,7 @@ def request_attach(
         response = self.send_recv(command_dict)
 
         if response["success"]:
-            self.wait_for_event("process")
+            self.wait_for_events(["process", "initialized"])
         return response
 
     def request_breakpointLocations(
@@ -670,6 +666,10 @@ def request_configurationDone(self):
         response = self.send_recv(command_dict)
         if response:
             self.configuration_done_sent = True
+            # Client requests the baseline of currently existing threads after
+            # a successful launch or attach.
+            # Kick off the threads request that follows
+            self.request_threads()
         return response
 
     def _process_stopped(self):
@@ -887,7 +887,7 @@ def request_launch(
         response = self.send_recv(command_dict)
 
         if response["success"]:
-            self.wait_for_event("process")
+            self.wait_for_events(["process", "initialized"])
         return response
 
     def request_next(self, threadId, granularity="statement"):
@@ -1325,26 +1325,6 @@ def attach_options_specified(options):
 
 def run_vscode(dbg, args, options):
     dbg.request_initialize(options.sourceInitFile)
-
-    if options.sourceBreakpoints:
-        source_to_lines = {}
-        for file_line in options.sourceBreakpoints:
-            (path, line) = file_line.split(":")
-            if len(path) == 0 or len(line) == 0:
-                print('error: invalid source with line "%s"' % (file_line))
-
-            else:
-                if path in source_to_lines:
-                    source_to_lines[path].append(int(line))
-                else:
-                    source_to_lines[path] = [int(line)]
-        for source in source_to_lines:
-            dbg.request_setBreakpoints(source, source_to_lines[source])
-    if options.funcBreakpoints:
-        dbg.request_setFunctionBreakpoints(options.funcBreakpoints)
-
-    dbg.request_configurationDone()
-
     if attach_options_specified(options):
         response = dbg.request_attach(
             program=options.program,
@@ -1373,6 +1353,23 @@ def run_vscode(dbg, args, options):
         )
 
     if response["success"]:
+        if options.sourceBreakpoints:
+            source_to_lines = {}
+            for file_line in options.sourceBreakpoints:
+                (path, line) = file_line.split(":")
+                if len(path) == 0 or len(line) == 0:
+                    print('error: invalid source with line "%s"' % (file_line))
+
+                else:
+                    if path in source_to_lines:
+                        source_to_lines[path].append(int(line))
+                    else:
+                        source_to_lines[path] = [int(line)]
+            for source in source_to_lines:
+                dbg.request_setBreakpoints(source, source_to_lines[source])
+        if options.funcBreakpoints:
+            dbg.request_setFunctionBreakpoints(options.funcBreakpoints)
+        dbg.request_configurationDone()
         dbg.wait_for_stopped()
     else:
         if "message" in response:

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 958c7268c0c72..2c14bb35162b5 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
@@ -340,7 +340,6 @@ def attach(
         exitCommands=None,
         attachCommands=None,
         coreFile=None,
-        stopOnAttach=True,
         disconnectAutomatically=True,
         terminateCommands=None,
         postRunCommands=None,
@@ -365,8 +364,6 @@ def cleanup():
         self.addTearDownHook(cleanup)
         # Initialize and launch the program
         self.dap_server.request_initialize(sourceInitFile)
-        self.dap_server.wait_for_event("initialized")
-        self.dap_server.request_configurationDone()
         response = self.dap_server.request_attach(
             program=program,
             pid=pid,
@@ -379,7 +376,6 @@ def cleanup():
             attachCommands=attachCommands,
             terminateCommands=terminateCommands,
             coreFile=coreFile,
-            stopOnAttach=stopOnAttach,
             postRunCommands=postRunCommands,
             sourceMap=sourceMap,
             gdbRemotePort=gdbRemotePort,
@@ -438,9 +434,6 @@ def cleanup():
 
         # Initialize and launch the program
         self.dap_server.request_initialize(sourceInitFile)
-        self.dap_server.wait_for_event("initialized")
-        self.dap_server.request_configurationDone()
-
         response = self.dap_server.request_launch(
             program,
             args=args,

diff  --git a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
index 741c011a3d692..f48d5a7db3c50 100644
--- a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
+++ b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
@@ -27,8 +27,6 @@ def spawn_and_wait(program, delay):
 @skip
 class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase):
     def set_and_hit_breakpoint(self, continueToExit=True):
-        self.dap_server.wait_for_stopped()
-
         source = "main.c"
         breakpoint1_line = line_number(source, "// breakpoint 1")
         lines = [breakpoint1_line]

diff  --git a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
index 7250e67ebcd8c..7f93b9f2a3a22 100644
--- a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
+++ b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
@@ -18,17 +18,17 @@
 import socket
 
 
+ at skip
 class TestDAP_attachByPortNum(lldbdap_testcase.DAPTestCaseBase):
     default_timeout = 20
 
     def set_and_hit_breakpoint(self, continueToExit=True):
-        self.dap_server.wait_for_stopped()
-
         source = "main.c"
-        breakpoint1_line = line_number(source, "// breakpoint 1")
+        main_source_path = os.path.join(os.getcwd(), source)
+        breakpoint1_line = line_number(main_source_path, "// breakpoint 1")
         lines = [breakpoint1_line]
         # Set breakpoint in the thread function so we can step the threads
-        breakpoint_ids = self.set_source_breakpoints(source, lines)
+        breakpoint_ids = self.set_source_breakpoints(main_source_path, lines)
         self.assertEqual(
             len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
         )

diff  --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
index 8581f10cef22a..e5590e1b332a0 100644
--- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
+++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
@@ -81,27 +81,52 @@ def test_breakpoint_events(self):
                 breakpoint["verified"], "expect foo breakpoint to not be verified"
             )
 
-        # Make sure we're stopped.
-        self.dap_server.wait_for_stopped()
+        # Get the stop at the entry point
+        self.continue_to_next_stop()
 
-        # Flush the breakpoint events.
-        self.dap_server.wait_for_breakpoint_events(timeout=5)
+        # We are now stopped at the entry point to the program. Shared
+        # libraries are not loaded yet (at least on macOS they aren't) and only
+        # the breakpoint in the main executable should be resolved.
+        self.assertEqual(len(self.dap_server.breakpoint_events), 1)
+        event = self.dap_server.breakpoint_events[0]
+        body = event["body"]
+        self.assertEqual(
+            body["reason"], "changed", "breakpoint event should say changed"
+        )
+        breakpoint = body["breakpoint"]
+        self.assertEqual(breakpoint["id"], main_bp_id)
+        self.assertTrue(breakpoint["verified"], "main breakpoint should be resolved")
+
+        # Clear the list of breakpoint events so we don't see this one again.
+        self.dap_server.breakpoint_events.clear()
 
         # Continue to the breakpoint
         self.continue_to_breakpoints(dap_breakpoint_ids)
 
-        verified_breakpoint_ids = []
-        unverified_breakpoint_ids = []
-        for breakpoint_event in self.dap_server.wait_for_breakpoint_events(timeout=5):
-            breakpoint = breakpoint_event["body"]["breakpoint"]
-            id = breakpoint["id"]
-            if breakpoint["verified"]:
-                verified_breakpoint_ids.append(id)
-            else:
-                unverified_breakpoint_ids.append(id)
-
-        self.assertIn(main_bp_id, unverified_breakpoint_ids)
-        self.assertIn(foo_bp_id, unverified_breakpoint_ids)
+        # When the process launches, we first expect to see both the main and
+        # foo breakpoint as unresolved.
+        for event in self.dap_server.breakpoint_events[:2]:
+            body = event["body"]
+            self.assertEqual(
+                body["reason"], "changed", "breakpoint event should say changed"
+            )
+            breakpoint = body["breakpoint"]
+            self.assertIn(str(breakpoint["id"]), dap_breakpoint_ids)
+            self.assertFalse(breakpoint["verified"], "breakpoint should be unresolved")
 
-        self.assertIn(main_bp_id, verified_breakpoint_ids)
-        self.assertIn(foo_bp_id, verified_breakpoint_ids)
+        # Then, once the dynamic loader has given us a load address, they
+        # should show up as resolved again.
+        for event in self.dap_server.breakpoint_events[3:]:
+            body = event["body"]
+            self.assertEqual(
+                body["reason"], "changed", "breakpoint event should say changed"
+            )
+            breakpoint = body["breakpoint"]
+            self.assertIn(str(breakpoint["id"]), dap_breakpoint_ids)
+            self.assertTrue(breakpoint["verified"], "breakpoint should be resolved")
+            self.assertNotIn(
+                "source",
+                breakpoint,
+                "breakpoint event should not return a source object",
+            )
+            self.assertIn("line", breakpoint, "breakpoint event should have line")

diff  --git a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py
index 455ac84168baf..210e591bff426 100644
--- a/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py
+++ b/lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py
@@ -44,9 +44,9 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]):
             self.assertNotIn(not_expected_item, actual_list)
 
 
-    def setup_debugee(self, stopOnEntry=False):
+    def setup_debugee(self):
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program, stopOnEntry=stopOnEntry)
+        self.build_and_launch(program)
 
         source = "main.cpp"
         breakpoint1_line = line_number(source, "// breakpoint 1")
@@ -235,7 +235,7 @@ def test_auto_completions(self):
         """
         Tests completion requests in "repl-mode=auto"
         """
-        self.setup_debugee(stopOnEntry=True)
+        self.setup_debugee()
 
         res = self.dap_server.request_evaluate(
             "`lldb-dap repl-mode auto", context="repl"

diff  --git a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py
index 65a1bc04c7cd7..b07c4f871d73b 100644
--- a/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py
+++ b/lldb/test/API/tools/lldb-dap/console/TestDAP_console.py
@@ -167,7 +167,7 @@ def test_exit_status_message_ok(self):
 
     def test_diagnositcs(self):
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program, stopOnEntry=True)
+        self.build_and_launch(program)
 
         core = self.getBuildArtifact("minidump.core")
         self.yaml2obj("minidump.yaml", core)

diff  --git a/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py b/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
index 09e3f62f0eead..0cb792d662a80 100644
--- a/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
+++ b/lldb/test/API/tools/lldb-dap/disconnect/TestDAP_disconnect.py
@@ -31,7 +31,7 @@ def test_launch(self):
         created.
         """
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program, stopOnEntry=True, disconnectAutomatically=False)
+        self.build_and_launch(program, disconnectAutomatically=False)
 
         # We set a breakpoint right before the side effect file is created
         self.set_source_breakpoints(
@@ -39,11 +39,7 @@ def test_launch(self):
         )
         self.continue_to_next_stop()
 
-        # verify we haven't produced the side effect file yet
-        self.assertFalse(os.path.exists(program + ".side_effect"))
-
         self.dap_server.request_disconnect()
-
         # verify we didn't produce the side effect file
         time.sleep(1)
         self.assertFalse(os.path.exists(program + ".side_effect"))

diff  --git a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
index 19b682dfcd22d..d97fda730c46a 100644
--- a/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
+++ b/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py
@@ -10,7 +10,6 @@
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
 
-
 # DAP tests are flakey, see https://github.com/llvm/llvm-project/issues/137660.
 @skip
 class TestDAP_evaluate(lldbdap_testcase.DAPTestCaseBase):
@@ -43,9 +42,7 @@ def run_test_evaluate_expressions(
         self.context = context
         program = self.getBuildArtifact("a.out")
         self.build_and_launch(
-            program,
-            enableAutoVariableSummaries=enableAutoVariableSummaries,
-            stopOnEntry=True,
+            program, enableAutoVariableSummaries=enableAutoVariableSummaries
         )
         source = "main.cpp"
         self.set_source_breakpoints(

diff  --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
index 604a41678500c..931456299e03e 100644
--- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
+++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
@@ -88,8 +88,8 @@ def test_stopOnEntry(self):
         """
         program = self.getBuildArtifact("a.out")
         self.build_and_launch(program, stopOnEntry=True)
-
-        stopped_events = self.dap_server.wait_for_stopped()
+        self.set_function_breakpoints(["main"])
+        stopped_events = self.continue_to_next_stop()
         for stopped_event in stopped_events:
             if "body" in stopped_event:
                 body = stopped_event["body"]

diff  --git a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py
index 0f94b50c31fba..fee63655de0da 100755
--- a/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py
+++ b/lldb/test/API/tools/lldb-dap/progress/TestDAP_Progress.py
@@ -50,7 +50,7 @@ def verify_progress_events(
     @skipIfWindows
     def test(self):
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program, stopOnEntry=True)
+        self.build_and_launch(program)
         progress_emitter = os.path.join(os.getcwd(), "Progress_emitter.py")
         self.dap_server.request_evaluate(
             f"`command script import {progress_emitter}", context="repl"

diff  --git a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py
index 81edcdf4bd0f9..c6f59949d668e 100644
--- a/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py
+++ b/lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py
@@ -20,7 +20,7 @@ def assertEvaluate(self, expression, regex):
 
     def test_completions(self):
         program = self.getBuildArtifact("a.out")
-        self.build_and_launch(program, stopOnEntry=True)
+        self.build_and_launch(program)
 
         source = "main.cpp"
         breakpoint1_line = line_number(source, "// breakpoint 1")

diff  --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py
index 5f95c7bfb1556..36fa0bd40183f 100644
--- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py
+++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py
@@ -22,6 +22,7 @@ def test_basic_functionality(self):
         [bp_A, bp_B] = self.set_source_breakpoints("main.c", [line_A, line_B])
 
         # Verify we hit A, then B.
+        self.dap_server.request_configurationDone()
         self.verify_breakpoint_hit([bp_A])
         self.dap_server.request_continue()
         self.verify_breakpoint_hit([bp_B])

diff  --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py
index eed769a5a0cc6..a94c9860c1508 100644
--- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py
+++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py
@@ -74,6 +74,7 @@ def test_stopOnEntry(self):
         program = self.getBuildArtifact("a.out")
         self.build_and_launch(program, runInTerminal=True, stopOnEntry=True)
         [bp_main] = self.set_function_breakpoints(["main"])
+        self.dap_server.request_configurationDone()
 
         # When using stopOnEntry, configurationDone doesn't result in a running
         # process, we should immediately get a stopped event instead.

diff  --git a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py
index 7e28a5af4331c..70c11a63a79f7 100644
--- a/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py
+++ b/lldb/test/API/tools/lldb-dap/stop-hooks/TestDAP_stop_hooks.py
@@ -19,7 +19,7 @@ def test_stop_hooks_before_run(self):
         self.build_and_launch(program, stopOnEntry=True, preRunCommands=preRunCommands)
 
         # The first stop is on entry.
-        self.dap_server.wait_for_stopped()
+        self.continue_to_next_stop()
 
         breakpoint_ids = self.set_function_breakpoints(["main"])
         # This request hangs if the race happens, because, in that case, the

diff  --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 62c60cc3a9b3b..4b631484c9fab 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -84,8 +84,8 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode,
     : log(log), transport(transport), broadcaster("lldb-dap"),
       exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID),
       stop_at_entry(false), is_attach(false),
-      restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done(false),
-      waiting_for_run_in_terminal(false),
+      restarting_process_id(LLDB_INVALID_PROCESS_ID),
+      configuration_done_sent(false), waiting_for_run_in_terminal(false),
       progress_event_reporter(
           [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
       reverse_request_seq(0), repl_mode(default_repl_mode) {
@@ -893,19 +893,10 @@ llvm::Error DAP::Loop() {
             return errWrapper;
           }
 
-          // The launch sequence is special and we need to carefully handle
-          // packets in the right order. Until we've handled configurationDone,
-          bool add_to_pending_queue = false;
-
           if (const protocol::Request *req =
-                  std::get_if<protocol::Request>(&*next)) {
-            llvm::StringRef command = req->command;
-            if (command == "disconnect")
-              disconnecting = true;
-            if (!configuration_done)
-              add_to_pending_queue =
-                  command != "initialize" && command != "configurationDone" &&
-                  command != "disconnect" && !command.ends_with("Breakpoints");
+                  std::get_if<protocol::Request>(&*next);
+              req && req->command == "disconnect") {
+            disconnecting = true;
           }
 
           const std::optional<CancelArguments> cancel_args =
@@ -933,8 +924,7 @@ llvm::Error DAP::Loop() {
 
           {
             std::lock_guard<std::mutex> guard(m_queue_mutex);
-            auto &queue = add_to_pending_queue ? m_pending_queue : m_queue;
-            queue.push_back(std::move(*next));
+            m_queue.push_back(std::move(*next));
           }
           m_queue_cv.notify_one();
         }
@@ -948,19 +938,16 @@ llvm::Error DAP::Loop() {
     StopEventHandlers();
   });
 
-  while (true) {
+  while (!disconnecting || !m_queue.empty()) {
     std::unique_lock<std::mutex> lock(m_queue_mutex);
     m_queue_cv.wait(lock, [&] { return disconnecting || !m_queue.empty(); });
 
-    if (disconnecting && m_queue.empty())
+    if (m_queue.empty())
       break;
 
     Message next = m_queue.front();
     m_queue.pop_front();
 
-    // Unlock while we're processing the event.
-    lock.unlock();
-
     if (!HandleObject(next))
       return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                      "unhandled packet");
@@ -1232,16 +1219,6 @@ void DAP::SetConfiguration(const protocol::Configuration &config,
     SetThreadFormat(*configuration.customThreadFormat);
 }
 
-void DAP::SetConfigurationDone() {
-  {
-    std::lock_guard<std::mutex> guard(m_queue_mutex);
-    std::copy(m_pending_queue.begin(), m_pending_queue.end(),
-              std::front_inserter(m_queue));
-    configuration_done = true;
-  }
-  m_queue_cv.notify_all();
-}
-
 void DAP::SetFrameFormat(llvm::StringRef format) {
   if (format.empty())
     return;

diff  --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index b581ae759b1bc..88eedb0860cf1 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -188,7 +188,7 @@ struct DAP {
   // shutting down the entire adapter. When we're restarting, we keep the id of
   // the old process here so we can detect this case and keep running.
   lldb::pid_t restarting_process_id;
-  bool configuration_done;
+  bool configuration_done_sent;
   llvm::StringMap<std::unique_ptr<BaseRequestHandler>> request_handlers;
   bool waiting_for_run_in_terminal;
   ProgressEventReporter progress_event_reporter;
@@ -251,8 +251,6 @@ struct DAP {
   /// Configures the debug adapter for launching/attaching.
   void SetConfiguration(const protocol::Configuration &confing, bool is_attach);
 
-  void SetConfigurationDone();
-
   /// Configure source maps based on the current `DAPConfiguration`.
   void ConfigureSourceMaps();
 
@@ -419,10 +417,8 @@ struct DAP {
   lldb::SBMutex GetAPIMutex() const { return target.GetAPIMutex(); }
 
 private:
-  /// Queue for all incoming messages.
-  std::deque<protocol::Message> m_queue;
-  std::deque<protocol::Message> m_pending_queue;
   std::mutex m_queue_mutex;
+  std::deque<protocol::Message> m_queue;
   std::condition_variable m_queue_cv;
 
   std::mutex m_cancelled_requests_mutex;

diff  --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp
index ed2d8700c26b0..2c659f39f4b66 100644
--- a/lldb/tools/lldb-dap/EventHelper.cpp
+++ b/lldb/tools/lldb-dap/EventHelper.cpp
@@ -222,7 +222,7 @@ void SendContinuedEvent(DAP &dap) {
 
   // If the focus thread is not set then we haven't reported any thread status
   // to the client, so nothing to report.
-  if (!dap.configuration_done || dap.focus_tid == LLDB_INVALID_THREAD_ID) {
+  if (!dap.configuration_done_sent || dap.focus_tid == LLDB_INVALID_THREAD_ID) {
     return;
   }
 

diff  --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
index 5dc9c3f9772e3..7a0f091128e4a 100644
--- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
@@ -133,69 +133,60 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
     dap.SendOutput(OutputType::Console,
                    llvm::StringRef(attach_msg, attach_msg_len));
   }
+  if (attachCommands.empty()) {
+    // No "attachCommands", just attach normally.
 
-  {
-    // Perform the launch in synchronous mode so that we don't have to worry
-    // about process state changes during the launch.
+    // Disable async events so the attach will be successful when we return from
+    // the launch call and the launch will happen synchronously
     ScopeSyncMode scope_sync_mode(dap.debugger);
-    if (attachCommands.empty()) {
-      // No "attachCommands", just attach normally.
-      if (core_file.empty()) {
-        if ((pid != LLDB_INVALID_PROCESS_ID) &&
-            (gdb_remote_port != invalid_port)) {
-          // If both pid and port numbers are specified.
-          error.SetErrorString("The user can't specify both pid and port");
-        } else if (gdb_remote_port != invalid_port) {
-          // If port is specified and pid is not.
-          lldb::SBListener listener = dap.debugger.GetListener();
-
-          // If the user hasn't provided the hostname property, default
-          // localhost being used.
-          std::string connect_url =
-              llvm::formatv("connect://{0}:", gdb_remote_hostname);
-          connect_url += std::to_string(gdb_remote_port);
-          dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
-                                   error);
-        } else {
-          // Attach by pid or process name.
-          lldb::SBAttachInfo attach_info;
-          if (pid != LLDB_INVALID_PROCESS_ID)
-            attach_info.SetProcessID(pid);
-          else if (dap.configuration.program.has_value())
-            attach_info.SetExecutable(dap.configuration.program->data());
-          attach_info.SetWaitForLaunch(wait_for, false /*async*/);
-          dap.target.Attach(attach_info, error);
-        }
+
+    if (core_file.empty()) {
+      if ((pid != LLDB_INVALID_PROCESS_ID) &&
+          (gdb_remote_port != invalid_port)) {
+        // If both pid and port numbers are specified.
+        error.SetErrorString("The user can't specify both pid and port");
+      } else if (gdb_remote_port != invalid_port) {
+        // If port is specified and pid is not.
+        lldb::SBListener listener = dap.debugger.GetListener();
+
+        // If the user hasn't provided the hostname property, default localhost
+        // being used.
+        std::string connect_url =
+            llvm::formatv("connect://{0}:", gdb_remote_hostname);
+        connect_url += std::to_string(gdb_remote_port);
+        dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
+                                 error);
       } else {
-        dap.target.LoadCore(core_file.data(), error);
+        // Attach by pid or process name.
+        lldb::SBAttachInfo attach_info;
+        if (pid != LLDB_INVALID_PROCESS_ID)
+          attach_info.SetProcessID(pid);
+        else if (dap.configuration.program.has_value())
+          attach_info.SetExecutable(dap.configuration.program->data());
+        attach_info.SetWaitForLaunch(wait_for, false /*async*/);
+        dap.target.Attach(attach_info, error);
       }
     } else {
-      // We have "attachCommands" that are a set of commands that are expected
-      // to execute the commands after which a process should be created. If
-      // there is no valid process after running these commands, we have failed.
-      if (llvm::Error err = dap.RunAttachCommands(attachCommands)) {
-        response["success"] = false;
-        EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-        dap.SendJSON(llvm::json::Value(std::move(response)));
-        return;
-      }
-      // The custom commands might have created a new target so we should use
-      // the selected target after these commands are run.
-      dap.target = dap.debugger.GetSelectedTarget();
+      dap.target.LoadCore(core_file.data(), error);
     }
-  }
-
-  // Make sure the process is attached and stopped.
-  error = dap.WaitForProcessToStop(std::chrono::seconds(timeout_seconds));
+  } else {
+    // We have "attachCommands" that are a set of commands that are expected
+    // to execute the commands after which a process should be created. If there
+    // is no valid process after running these commands, we have failed.
+    if (llvm::Error err = dap.RunAttachCommands(attachCommands)) {
+      response["success"] = false;
+      EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
+      dap.SendJSON(llvm::json::Value(std::move(response)));
+      return;
+    }
+    // The custom commands might have created a new target so we should use the
+    // selected target after these commands are run.
+    dap.target = dap.debugger.GetSelectedTarget();
 
-  // Clients can request a baseline of currently existing threads after
-  // we acknowledge the configurationDone request.
-  // Client requests the baseline of currently existing threads after
-  // a successful or attach by sending a 'threads' request
-  // right after receiving the configurationDone response.
-  // Obtain the list of threads before we resume the process
-  dap.initial_thread_list =
-      GetThreads(dap.target.GetProcess(), dap.thread_format);
+    // Make sure the process is attached and stopped before proceeding as the
+    // the launch commands are not run using the synchronous mode.
+    error = dap.WaitForProcessToStop(std::chrono::seconds(timeout_seconds));
+  }
 
   if (error.Success() && core_file.empty()) {
     auto attached_pid = dap.target.GetProcess().GetProcessID();
@@ -215,17 +206,9 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
   }
 
   dap.SendJSON(llvm::json::Value(std::move(response)));
-
-  // FIXME: Move this into PostRun.
   if (error.Success()) {
-    if (dap.target.GetProcess().IsValid()) {
-      SendProcessEvent(dap, Attach);
-
-      if (dap.stop_at_entry)
-        SendThreadStoppedEvent(dap);
-      else
-        dap.target.GetProcess().Continue();
-    }
+    SendProcessEvent(dap, Attach);
+    dap.SendJSON(CreateEventObject("initialized"));
   }
 }
 

diff  --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
index 802c28d7b8904..f39bbdefdbb95 100644
--- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp
@@ -47,11 +47,21 @@ namespace lldb_dap {
 
 void ConfigurationDoneRequestHandler::operator()(
     const llvm::json::Object &request) const {
-  dap.SetConfigurationDone();
-
   llvm::json::Object response;
   FillResponse(request, response);
   dap.SendJSON(llvm::json::Value(std::move(response)));
+  dap.configuration_done_sent = true;
+  if (dap.stop_at_entry)
+    SendThreadStoppedEvent(dap);
+  else {
+    // Client requests the baseline of currently existing threads after
+    // a successful launch or attach by sending a 'threads' request
+    // right after receiving the configurationDone response.
+    // Obtain the list of threads before we resume the process
+    dap.initial_thread_list =
+        GetThreads(dap.target.GetProcess(), dap.thread_format);
+    dap.target.GetProcess().Continue();
+  }
 }
 
 } // namespace lldb_dap

diff  --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
index aa947d3cb5ab9..ce34c52bcc334 100644
--- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
@@ -140,28 +140,43 @@ static void EventThreadFunction(DAP &dap) {
         lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
         if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
           auto state = lldb::SBProcess::GetStateFromEvent(event);
-
-          DAP_LOG(dap.log, "State = {0}", state);
           switch (state) {
-          case lldb::eStateConnected:
-          case lldb::eStateDetached:
           case lldb::eStateInvalid:
+            // Not a state event
+            break;
           case lldb::eStateUnloaded:
             break;
+          case lldb::eStateConnected:
+            break;
           case lldb::eStateAttaching:
-          case lldb::eStateCrashed:
+            break;
           case lldb::eStateLaunching:
-          case lldb::eStateStopped:
+            break;
+          case lldb::eStateStepping:
+            break;
+          case lldb::eStateCrashed:
+            break;
+          case lldb::eStateDetached:
+            break;
           case lldb::eStateSuspended:
-            // Only report a stopped event if the process was not
-            // automatically restarted.
-            if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
-              SendStdOutStdErr(dap, process);
-              SendThreadStoppedEvent(dap);
+            break;
+          case lldb::eStateStopped:
+            // We launch and attach in synchronous mode then the first stop
+            // event will not be delivered. If we use "launchCommands" during a
+            // launch or "attachCommands" during an attach we might some process
+            // stop events which we do not want to send an event for. We will
+            // manually send a stopped event in request_configurationDone(...)
+            // so don't send any before then.
+            if (dap.configuration_done_sent) {
+              // Only report a stopped event if the process was not
+              // automatically restarted.
+              if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
+                SendStdOutStdErr(dap, process);
+                SendThreadStoppedEvent(dap);
+              }
             }
             break;
           case lldb::eStateRunning:
-          case lldb::eStateStepping:
             dap.WillContinue();
             SendContinuedEvent(dap);
             break;
@@ -269,7 +284,6 @@ llvm::Expected<InitializeResponseBody> InitializeRequestHandler::Run(
   // Do not source init files until in/out/err are configured.
   dap.debugger = lldb::SBDebugger::Create(false);
   dap.debugger.SetInputFile(dap.in);
-  dap.target = dap.debugger.GetDummyTarget();
 
   llvm::Expected<int> out_fd = dap.out.GetWriteFileDescriptor();
   if (!out_fd)
@@ -324,8 +338,4 @@ llvm::Expected<InitializeResponseBody> InitializeRequestHandler::Run(
   return dap.GetCapabilities();
 }
 
-void InitializeRequestHandler::PostRun() const {
-  dap.SendJSON(CreateEventObject("initialized"));
-}
-
 } // namespace lldb_dap

diff  --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
index 7e0e76935dd02..3e4532e754ec6 100644
--- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
@@ -71,12 +71,9 @@ void LaunchRequestHandler::PostRun() const {
   if (dap.target.GetProcess().IsValid()) {
     // Attach happens when launching with runInTerminal.
     SendProcessEvent(dap, dap.is_attach ? Attach : Launch);
-
-    if (dap.stop_at_entry)
-      SendThreadStoppedEvent(dap);
-    else
-      dap.target.GetProcess().Continue();
   }
+
+  dap.SendJSON(CreateEventObject("initialized"));
 }
 
 } // namespace lldb_dap

diff  --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 282c5f4ab15a5..7a75cd93abc19 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -8,7 +8,6 @@
 
 #include "Handler/RequestHandler.h"
 #include "DAP.h"
-#include "EventHelper.h"
 #include "Handler/ResponseHandler.h"
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
@@ -163,7 +162,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
   dap.target.GetProcess().Continue();
 
   // Now that the actual target is just starting (i.e. exec was just invoked),
-  // we return the debugger to its sync state.
+  // we return the debugger to its async state.
   scope_sync_mode.reset();
 
   // If sending the notification failed, the launcher should be dead by now and
@@ -239,47 +238,35 @@ llvm::Error BaseRequestHandler::LaunchProcess(
   launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug |
                              lldb::eLaunchFlagStopAtEntry);
 
-  {
-    // Perform the launch in synchronous mode so that we don't have to worry
-    // about process state changes during the launch.
+  if (arguments.runInTerminal) {
+    if (llvm::Error err = RunInTerminal(dap, arguments))
+      return err;
+  } else if (launchCommands.empty()) {
+    lldb::SBError error;
+    // Disable async events so the launch will be successful when we return from
+    // the launch call and the launch will happen synchronously
     ScopeSyncMode scope_sync_mode(dap.debugger);
-
-    if (arguments.runInTerminal) {
-      if (llvm::Error err = RunInTerminal(dap, arguments))
-        return err;
-    } else if (launchCommands.empty()) {
-      lldb::SBError error;
-      dap.target.Launch(launch_info, error);
-      if (error.Fail())
-        return llvm::make_error<DAPError>(error.GetCString());
-    } else {
-      // Set the launch info so that run commands can access the configured
-      // launch details.
-      dap.target.SetLaunchInfo(launch_info);
-      if (llvm::Error err = dap.RunLaunchCommands(launchCommands))
-        return err;
-
-      // The custom commands might have created a new target so we should use
-      // the selected target after these commands are run.
-      dap.target = dap.debugger.GetSelectedTarget();
-    }
+    dap.target.Launch(launch_info, error);
+    if (error.Fail())
+      return llvm::make_error<DAPError>(error.GetCString());
+  } else {
+    // Set the launch info so that run commands can access the configured
+    // launch details.
+    dap.target.SetLaunchInfo(launch_info);
+    if (llvm::Error err = dap.RunLaunchCommands(launchCommands))
+      return err;
+
+    // The custom commands might have created a new target so we should use the
+    // selected target after these commands are run.
+    dap.target = dap.debugger.GetSelectedTarget();
+    // Make sure the process is launched and stopped at the entry point before
+    // proceeding as the launch commands are not run using the synchronous
+    // mode.
+    lldb::SBError error = dap.WaitForProcessToStop(arguments.timeout);
+    if (error.Fail())
+      return llvm::make_error<DAPError>(error.GetCString());
   }
 
-  // Make sure the process is launched and stopped at the entry point before
-  // proceeding.
-  lldb::SBError error = dap.WaitForProcessToStop(arguments.timeout);
-  if (error.Fail())
-    return llvm::make_error<DAPError>(error.GetCString());
-
-  // Clients can request a baseline of currently existing threads after
-  // we acknowledge the configurationDone request.
-  // Client requests the baseline of currently existing threads after
-  // a successful or attach by sending a 'threads' request
-  // right after receiving the configurationDone response.
-  // Obtain the list of threads before we resume the process
-  dap.initial_thread_list =
-      GetThreads(dap.target.GetProcess(), dap.thread_format);
-
   return llvm::Error::success();
 }
 

diff  --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 9e9cfb13d77b8..37cc902e1c98e 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -282,7 +282,6 @@ class InitializeRequestHandler
   static llvm::StringLiteral GetCommand() { return "initialize"; }
   llvm::Expected<protocol::InitializeResponseBody>
   Run(const protocol::InitializeRequestArguments &args) const override;
-  void PostRun() const override;
 };
 
 class LaunchRequestHandler


        


More information about the lldb-commits mailing list