Skip to content

Commit 0e0b501

Browse files
authored
[lldb-dap] Take two at refactoring the startup sequence. (#140331)
This is more straight forward refactor of the startup sequence that reverts parts of ba29e60. Unlike my previous attempt, I ended up removing the pending request queue and not including an `AsyncReqeustHandler` because I don't think we actually need that at the moment. The key is that during the startup flow there are 2 parallel operations happening in the DAP that have different triggers. * The `initialize` request is sent and once the response is received the `launch` or `attach` is sent. * When the `initialized` event is recieved the `setBreakpionts` and other config requests are made followed by the `configurationDone` event. I moved the `initialized` event back to happen in the `PostRun` of the `launch` or `attach` request handlers. This ensures that we have a valid target by the time the configuration calls are made. I added also added a few extra validations that to the `configurationeDone` handler to ensure we're in an expected state. I've also fixed up the tests to match the new flow. With the other additional test fixes in 087a5d2 I think we've narrowed down the main source of test instability that motivated the startup sequence change.
1 parent 9178a17 commit 0e0b501

30 files changed

+151
-258
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ def __init__(
133133
self.output_condition = threading.Condition()
134134
self.output: dict[str, list[str]] = {}
135135
self.configuration_done_sent = False
136+
self.initialized = False
136137
self.frame_scopes = {}
137138
self.init_commands = init_commands
138139
self.disassembled_instructions = {}
@@ -235,6 +236,8 @@ def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool:
235236
self.output_condition.release()
236237
# no need to add 'output' event packets to our packets list
237238
return keepGoing
239+
elif event == "initialized":
240+
self.initialized = True
238241
elif event == "process":
239242
# When a new process is attached or launched, remember the
240243
# details that are available in the body of the event
@@ -602,7 +605,7 @@ def request_attach(
602605
exitCommands: Optional[list[str]] = None,
603606
terminateCommands: Optional[list[str]] = None,
604607
coreFile: Optional[str] = None,
605-
stopOnAttach=True,
608+
stopOnEntry=False,
606609
sourceMap: Optional[Union[list[tuple[str, str]], dict[str, str]]] = None,
607610
gdbRemotePort: Optional[int] = None,
608611
gdbRemoteHostname: Optional[str] = None,
@@ -629,8 +632,8 @@ def request_attach(
629632
args_dict["attachCommands"] = attachCommands
630633
if coreFile:
631634
args_dict["coreFile"] = coreFile
632-
if stopOnAttach:
633-
args_dict["stopOnEntry"] = stopOnAttach
635+
if stopOnEntry:
636+
args_dict["stopOnEntry"] = stopOnEntry
634637
if postRunCommands:
635638
args_dict["postRunCommands"] = postRunCommands
636639
if sourceMap:
@@ -640,11 +643,7 @@ def request_attach(
640643
if gdbRemoteHostname is not None:
641644
args_dict["gdb-remote-hostname"] = gdbRemoteHostname
642645
command_dict = {"command": "attach", "type": "request", "arguments": args_dict}
643-
response = self.send_recv(command_dict)
644-
645-
if response["success"]:
646-
self.wait_for_event("process")
647-
return response
646+
return self.send_recv(command_dict)
648647

649648
def request_breakpointLocations(
650649
self, file_path, line, end_line=None, column=None, end_column=None
@@ -677,6 +676,7 @@ def request_configurationDone(self):
677676
response = self.send_recv(command_dict)
678677
if response:
679678
self.configuration_done_sent = True
679+
self.request_threads()
680680
return response
681681

682682
def _process_stopped(self):
@@ -824,7 +824,7 @@ def request_launch(
824824
args: Optional[list[str]] = None,
825825
cwd: Optional[str] = None,
826826
env: Optional[dict[str, str]] = None,
827-
stopOnEntry=True,
827+
stopOnEntry=False,
828828
disableASLR=True,
829829
disableSTDIO=False,
830830
shellExpandArguments=False,
@@ -894,11 +894,7 @@ def request_launch(
894894
if commandEscapePrefix is not None:
895895
args_dict["commandEscapePrefix"] = commandEscapePrefix
896896
command_dict = {"command": "launch", "type": "request", "arguments": args_dict}
897-
response = self.send_recv(command_dict)
898-
899-
if response["success"]:
900-
self.wait_for_event("process")
901-
return response
897+
return self.send_recv(command_dict)
902898

903899
def request_next(self, threadId, granularity="statement"):
904900
if self.exit_status is not None:

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def set_source_breakpoints(self, source_path, lines, data=None):
5656
It contains optional location/hitCondition/logMessage parameters.
5757
"""
5858
response = self.dap_server.request_setBreakpoints(source_path, lines, data)
59-
if response is None:
59+
if response is None or not response["success"]:
6060
return []
6161
breakpoints = response["body"]["breakpoints"]
6262
breakpoint_ids = []
@@ -354,13 +354,9 @@ def disassemble(self, threadId=None, frameIndex=None):
354354
def attach(
355355
self,
356356
*,
357-
stopOnAttach=True,
358357
disconnectAutomatically=True,
359358
sourceInitFile=False,
360359
expectFailure=False,
361-
sourceBreakpoints=None,
362-
functionBreakpoints=None,
363-
timeout=DEFAULT_TIMEOUT,
364360
**kwargs,
365361
):
366362
"""Build the default Makefile target, create the DAP debug adapter,
@@ -378,49 +374,21 @@ def cleanup():
378374
self.addTearDownHook(cleanup)
379375
# Initialize and launch the program
380376
self.dap_server.request_initialize(sourceInitFile)
381-
self.dap_server.wait_for_event("initialized", timeout)
382-
383-
# Set source breakpoints as part of the launch sequence.
384-
if sourceBreakpoints:
385-
for source_path, lines in sourceBreakpoints:
386-
response = self.dap_server.request_setBreakpoints(source_path, lines)
387-
self.assertTrue(
388-
response["success"],
389-
"setBreakpoints failed (%s)" % (response),
390-
)
391-
392-
# Set function breakpoints as part of the launch sequence.
393-
if functionBreakpoints:
394-
response = self.dap_server.request_setFunctionBreakpoints(
395-
functionBreakpoints
396-
)
397-
self.assertTrue(
398-
response["success"],
399-
"setFunctionBreakpoint failed (%s)" % (response),
400-
)
401-
402-
self.dap_server.request_configurationDone()
403-
response = self.dap_server.request_attach(stopOnAttach=stopOnAttach, **kwargs)
377+
response = self.dap_server.request_attach(**kwargs)
404378
if expectFailure:
405379
return response
406380
if not (response and response["success"]):
407381
self.assertTrue(
408382
response["success"], "attach failed (%s)" % (response["message"])
409383
)
410-
if stopOnAttach:
411-
self.dap_server.wait_for_stopped(timeout)
412384

413385
def launch(
414386
self,
415387
program=None,
416388
*,
417389
sourceInitFile=False,
418390
disconnectAutomatically=True,
419-
sourceBreakpoints=None,
420-
functionBreakpoints=None,
421391
expectFailure=False,
422-
stopOnEntry=True,
423-
timeout=DEFAULT_TIMEOUT,
424392
**kwargs,
425393
):
426394
"""Sending launch request to dap"""
@@ -437,46 +405,14 @@ def cleanup():
437405

438406
# Initialize and launch the program
439407
self.dap_server.request_initialize(sourceInitFile)
440-
self.dap_server.wait_for_event("initialized", timeout)
441-
442-
# Set source breakpoints as part of the launch sequence.
443-
if sourceBreakpoints:
444-
for source_path, lines in sourceBreakpoints:
445-
response = self.dap_server.request_setBreakpoints(source_path, lines)
446-
self.assertTrue(
447-
response["success"],
448-
"setBreakpoints failed (%s)" % (response),
449-
)
450-
451-
# Set function breakpoints as part of the launch sequence.
452-
if functionBreakpoints:
453-
response = self.dap_server.request_setFunctionBreakpoints(
454-
functionBreakpoints
455-
)
456-
self.assertTrue(
457-
response["success"],
458-
"setFunctionBreakpoint failed (%s)" % (response),
459-
)
460-
461-
self.dap_server.request_configurationDone()
462-
463-
response = self.dap_server.request_launch(
464-
program,
465-
stopOnEntry=stopOnEntry,
466-
**kwargs,
467-
)
468-
408+
response = self.dap_server.request_launch(program, **kwargs)
469409
if expectFailure:
470410
return response
471411
if not (response and response["success"]):
472412
self.assertTrue(
473413
response["success"],
474414
"launch failed (%s)" % (response["body"]["error"]["format"]),
475415
)
476-
if stopOnEntry:
477-
self.dap_server.wait_for_stopped(timeout)
478-
479-
return response
480416

481417
def build_and_launch(
482418
self,

lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def test_breakpoint_events(self):
5252
# breakpoint events for these breakpoints but not for ones that are not
5353
# set via the command interpreter.
5454
bp_command = "breakpoint set --file foo.cpp --line %u" % (foo_bp2_line)
55-
self.build_and_launch(program, stopOnEntry=True, preRunCommands=[bp_command])
55+
self.build_and_launch(program, preRunCommands=[bp_command])
5656
main_bp_id = 0
5757
foo_bp_id = 0
5858
# Set breakpoints and verify that they got set correctly

lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def test_pending_request(self):
4444
Tests cancelling a pending request.
4545
"""
4646
program = self.getBuildArtifact("a.out")
47-
self.build_and_launch(program, stopOnEntry=True)
47+
self.build_and_launch(program)
4848

4949
# Use a relatively short timeout since this is only to ensure the
5050
# following request is queued.
@@ -76,7 +76,7 @@ def test_inflight_request(self):
7676
Tests cancelling an inflight request.
7777
"""
7878
program = self.getBuildArtifact("a.out")
79-
self.build_and_launch(program, stopOnEntry=True)
79+
self.build_and_launch(program)
8080

8181
blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2)
8282
# Wait for the sleep to start to cancel the inflight request.

lldb/test/API/tools/lldb-dap/completions/TestDAP_completions.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,12 @@ def verify_completions(self, actual_list, expected_list, not_expected_list=[]):
4646
def setup_debuggee(self):
4747
program = self.getBuildArtifact("a.out")
4848
source = "main.cpp"
49-
self.build_and_launch(
50-
program,
51-
stopOnEntry=True,
52-
sourceBreakpoints=[
53-
(
54-
source,
55-
[
56-
line_number(source, "// breakpoint 1"),
57-
line_number(source, "// breakpoint 2"),
58-
],
59-
),
49+
self.build_and_launch(program)
50+
self.set_source_breakpoints(
51+
source,
52+
[
53+
line_number(source, "// breakpoint 1"),
54+
line_number(source, "// breakpoint 2"),
6055
],
6156
)
6257

lldb/test/API/tools/lldb-dap/console/TestDAP_console.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def test_scopes_variables_setVariable_evaluate(self):
5353
character.
5454
"""
5555
program = self.getBuildArtifact("a.out")
56-
self.build_and_launch(program, stopOnEntry=True)
56+
self.build_and_launch(program)
5757
source = "main.cpp"
5858
breakpoint1_line = line_number(source, "// breakpoint 1")
5959
lines = [breakpoint1_line]
@@ -66,6 +66,7 @@ def test_scopes_variables_setVariable_evaluate(self):
6666
# Cause a "scopes" to be sent for frame zero which should update the
6767
# selected thread and frame to frame 0.
6868
self.dap_server.get_local_variables(frameIndex=0)
69+
6970
# Verify frame #0 is selected in the command interpreter by running
7071
# the "frame select" command with no frame index which will print the
7172
# currently selected frame.
@@ -74,15 +75,15 @@ def test_scopes_variables_setVariable_evaluate(self):
7475
# Cause a "scopes" to be sent for frame one which should update the
7576
# selected thread and frame to frame 1.
7677
self.dap_server.get_local_variables(frameIndex=1)
78+
7779
# Verify frame #1 is selected in the command interpreter by running
7880
# the "frame select" command with no frame index which will print the
7981
# currently selected frame.
80-
8182
self.check_lldb_command("frame select", "frame #1", "frame 1 is selected")
8283

8384
def test_custom_escape_prefix(self):
8485
program = self.getBuildArtifact("a.out")
85-
self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="::")
86+
self.build_and_launch(program, commandEscapePrefix="::")
8687
source = "main.cpp"
8788
breakpoint1_line = line_number(source, "// breakpoint 1")
8889
breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line])
@@ -97,7 +98,7 @@ def test_custom_escape_prefix(self):
9798

9899
def test_empty_escape_prefix(self):
99100
program = self.getBuildArtifact("a.out")
100-
self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="")
101+
self.build_and_launch(program, commandEscapePrefix="")
101102
source = "main.cpp"
102103
breakpoint1_line = line_number(source, "// breakpoint 1")
103104
breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line])
@@ -114,7 +115,7 @@ def test_empty_escape_prefix(self):
114115
def test_exit_status_message_sigterm(self):
115116
source = "main.cpp"
116117
program = self.getBuildArtifact("a.out")
117-
self.build_and_launch(program, stopOnEntry=True, commandEscapePrefix="")
118+
self.build_and_launch(program, commandEscapePrefix="")
118119
breakpoint1_line = line_number(source, "// breakpoint 1")
119120
breakpoint_ids = self.set_source_breakpoints(source, [breakpoint1_line])
120121
self.continue_to_breakpoints(breakpoint_ids)
@@ -168,7 +169,7 @@ def test_exit_status_message_ok(self):
168169

169170
def test_diagnositcs(self):
170171
program = self.getBuildArtifact("a.out")
171-
self.build_and_launch(program, stopOnEntry=True)
172+
self.build_and_launch(program)
172173

173174
core = self.getBuildArtifact("minidump.core")
174175
self.yaml2obj("minidump.yaml", core)

lldb/test/API/tools/lldb-dap/console/TestDAP_redirection_to_console.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ def test(self):
1616
"""
1717
program = self.getBuildArtifact("a.out")
1818
self.build_and_launch(
19-
program,
20-
stopOnEntry=True,
21-
lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""},
19+
program, lldbDAPEnv={"LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION": ""}
2220
)
2321

2422
source = "main.cpp"

lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def test_core_file(self):
1919

2020
self.create_debug_adapter()
2121
self.attach(program=exe_file, coreFile=core_file)
22+
self.dap_server.request_configurationDone()
2223

2324
expected_frames = [
2425
{

lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ def run_test_evaluate_expressions(
4343
self.build_and_launch(
4444
program,
4545
enableAutoVariableSummaries=enableAutoVariableSummaries,
46-
stopOnEntry=True,
4746
)
4847
source = "main.cpp"
4948
self.set_source_breakpoints(

lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ def test_stopOnEntry(self):
8787
"""
8888
program = self.getBuildArtifact("a.out")
8989
self.build_and_launch(program, stopOnEntry=True)
90-
90+
self.dap_server.request_configurationDone()
91+
self.dap_server.wait_for_stopped()
9192
self.assertTrue(
9293
len(self.dap_server.thread_stop_reasons) > 0,
9394
"expected stopped event during launch",
@@ -357,7 +358,6 @@ def test_commands(self):
357358
terminateCommands = ["expr 4+2"]
358359
self.build_and_launch(
359360
program,
360-
stopOnEntry=True,
361361
initCommands=initCommands,
362362
preRunCommands=preRunCommands,
363363
postRunCommands=postRunCommands,

lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase):
1010
@skipIfWindows
1111
def test_module_event(self):
1212
program = self.getBuildArtifact("a.out")
13-
self.build_and_launch(program, stopOnEntry=True)
13+
self.build_and_launch(program)
1414

1515
source = "main.cpp"
1616
breakpoint1_line = line_number(source, "// breakpoint 1")

lldb/test/API/tools/lldb-dap/module/TestDAP_module.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase):
1414
def run_test(self, symbol_basename, expect_debug_info_size):
1515
program_basename = "a.out.stripped"
1616
program = self.getBuildArtifact(program_basename)
17-
self.build_and_launch(program, stopOnEntry=True)
17+
self.build_and_launch(program)
1818
functions = ["foo"]
1919
breakpoint_ids = self.set_function_breakpoints(functions)
2020
self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint")
@@ -108,7 +108,7 @@ def test_modules_dsym(self):
108108
@skipIfWindows
109109
def test_compile_units(self):
110110
program = self.getBuildArtifact("a.out")
111-
self.build_and_launch(program, stopOnEntry=True)
111+
self.build_and_launch(program)
112112
source = "main.cpp"
113113
main_source_path = self.getSourcePath(source)
114114
breakpoint1_line = line_number(source, "// breakpoint 1")

lldb/test/API/tools/lldb-dap/repl-mode/TestDAP_repl_mode_detection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def assertEvaluate(self, expression, regex):
2020

2121
def test_completions(self):
2222
program = self.getBuildArtifact("a.out")
23-
self.build_and_launch(program, stopOnEntry=True)
23+
self.build_and_launch(program)
2424

2525
source = "main.cpp"
2626
breakpoint1_line = line_number(source, "// breakpoint 1")

0 commit comments

Comments
 (0)