Skip to content

Commit 5446eb9

Browse files
authored
[Dexter] Adjust launch sequencing to align closer with DAP spec (#170523)
Following PR #169744 the DAP launch sequencing of Dexter was changed to complete a launch request/response before performing configuration steps. This matches LLDB's current behaviour, but is not compatible with the DAP specification and causes issues interfacing with other debuggers. This patch tries to bridge the gap by using a sequencing that is mostly DAP-compliant while still interfacing correctly with lldb-dap: we send a launch request first, then perform all configuration steps and send configurationDone, and then await the launch response. For lldb-dap, we do not wait for the launch response and may send configuration requests before it is received, but lldb-dap appears to handle this without issue. For other debug adapters, the launch request will be ignored until the configurationDone request is received and responded to, at which point the launch request will be acted upon and responded to. As an additional note, the initialized event should be sent after the initialize response and before the launch request according to the spec, but as LLDB currently sends it after the launch response Dexter has avoided checking for it. Since the initialized event is now being sent after the launch response by LLDB, we can start checking for it earlier in the sequence as well (though technically the client should receive the initialized event before it sends the launch request).
1 parent 9bfb3be commit 5446eb9

File tree

1 file changed

+25
-9
lines changed
  • cross-project-tests/debuginfo-tests/dexter/dex/debugger

1 file changed

+25
-9
lines changed

cross-project-tests/debuginfo-tests/dexter/dex/debugger/DAP.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -763,23 +763,39 @@ def launch(self, cmdline):
763763

764764
launch_request = self._get_launch_params(cmdline)
765765

766-
# Per DAP protocol, the correct sequence is:
766+
# Per DAP protocol, we follow the sequence:
767767
# 1. Send launch request
768-
# 2. Wait for launch response and "initialized" event
769-
# 3. Set breakpoints
770-
# 4. Send configurationDone to start the process
768+
# 2. Set breakpoints
769+
# 3. Send configurationDone to start the process
770+
# 4. Wait for launch and configurationDone responses, and a "process" event, to confirm successful launch
771+
# NB: Technically, we should also wait for the "initialized" event before sending the launch request, but in
772+
# practice there are DAP implementations that do not send the initialized event until post-launch, and all
773+
# adapters seem to accept us not waiting for the initialized event, so ignoring it gives maximum compatibility.
771774
launch_req_id = self.send_message(self.make_request("launch", launch_request))
772-
launch_response = self._await_response(launch_req_id)
773-
if not launch_response["success"]:
774-
raise DebuggerException(
775-
f"failure launching debugger: \"{launch_response['body']['error']['format']}\""
776-
)
775+
776+
# Wait for the initialized event; for LLDB, this will be sent after the launch request has been processed;
777+
# for other debuggers, it will have been sent some time after the initialize response was sent.
778+
# NB: In all current cases this timeout is never hit because the initialized event is received almost
779+
# immediately after either the initialize response or the launch request/response; if this starts being hit, we
780+
# probably need to parameterize this.
781+
initialize_timeout = Timeout(3)
782+
while not self._debugger_state.initialized:
783+
if initialize_timeout.timed_out():
784+
raise TimeoutError(
785+
f"Timed out while waiting for initialized event from DAP"
786+
)
787+
time.sleep(0.001)
777788

778789
# Set breakpoints after receiving launch response but before configurationDone.
779790
self._flush_breakpoints()
780791

781792
# Send configurationDone to allow the process to start running.
782793
config_done_req_id = self.send_message(self.make_request("configurationDone"))
794+
launch_response = self._await_response(launch_req_id)
795+
if not launch_response["success"]:
796+
raise DebuggerException(
797+
f"failure launching debugger: \"{launch_response['body']['error']['format']}\""
798+
)
783799
config_done_response = self._await_response(config_done_req_id)
784800
assert config_done_response["success"]
785801

0 commit comments

Comments
 (0)