@@ -92,6 +92,12 @@
the return value from the latest "stepOut" command, when
appropriate.
+ ** The "launch" and "attach" requests were rewritten in accordance
+ with some clarifications to the spec. Now they can be sent at
+ any time after the "initialized" event, but will not take effect
+ (or send a response) until after the "configurationDone" request
+ has been sent.
+
* New commands
set style line-number foreground COLOR
@@ -21,8 +21,42 @@ from typing import Mapping, Optional, Sequence
import gdb
from .events import exec_and_expect_stop, expect_process, expect_stop
-from .server import capability, request
-from .startup import DAPException, exec_and_log, in_gdb_thread
+from .server import (
+ DeferredRequest,
+ call_function_later,
+ capability,
+ request,
+ send_gdb,
+ send_gdb_with_response,
+)
+from .startup import DAPException, exec_and_log, in_dap_thread, in_gdb_thread
+
+# A launch or attach promise that that will be fulfilled after a
+# configurationDone request has been processed.
+_launch_or_attach_promise = None
+
+
+# A DeferredRequest that handles either a "launch" or "attach"
+# request.
+class _LaunchOrAttachDeferredRequest(DeferredRequest):
+ def __init__(self, callback):
+ self._callback = callback
+ global _launch_or_attach_promise
+ if _launch_or_attach_promise is not None:
+ raise DAPException("launch or attach already specified")
+ _launch_or_attach_promise = self
+
+ # Invoke the callback and return the result.
+ @in_dap_thread
+ def invoke(self):
+ return self._callback()
+
+ # Override this so we can clear the global when rescheduling.
+ @in_dap_thread
+ def reschedule(self):
+ global _launch_or_attach_promise
+ _launch_or_attach_promise = None
+ super().reschedule()
# A wrapper for the 'file' command that correctly quotes its argument.
@@ -37,7 +71,7 @@ def file_command(program):
# Any parameters here are necessarily extensions -- DAP requires this
# from implementations. Any additions or changes here should be
# documented in the gdb manual.
-@request("launch", response=False)
+@request("launch", on_dap_thread=True)
def launch(
*,
program: Optional[str] = None,
@@ -48,27 +82,51 @@ def launch(
stopOnEntry: bool = False,
**extra,
):
- if cwd is not None:
- exec_and_log("cd " + cwd)
- if program is not None:
- file_command(program)
- inf = gdb.selected_inferior()
- inf.arguments = args
- if env is not None:
- inf.clear_env()
- for name, value in env.items():
- inf.set_env(name, value)
- expect_process("process")
- if stopAtBeginningOfMainSubprogram:
- cmd = "start"
- elif stopOnEntry:
- cmd = "starti"
- else:
- cmd = "run"
- exec_and_expect_stop(cmd)
-
-
-@request("attach")
+ # Launch setup is handled here. This is done synchronously so
+ # that errors can be reported in a natural way.
+ @in_gdb_thread
+ def _setup_launch():
+ if cwd is not None:
+ exec_and_log("cd " + cwd)
+ if program is not None:
+ file_command(program)
+ inf = gdb.selected_inferior()
+ inf.arguments = args
+ if env is not None:
+ inf.clear_env()
+ for name, value in env.items():
+ inf.set_env(name, value)
+
+ # Actual launching done here. See below for more info.
+ @in_gdb_thread
+ def _do_launch():
+ expect_process("process")
+ if stopAtBeginningOfMainSubprogram:
+ cmd = "start"
+ elif stopOnEntry:
+ cmd = "starti"
+ else:
+ cmd = "run"
+ exec_and_expect_stop(cmd)
+
+ @in_dap_thread
+ def _launch_impl():
+ send_gdb_with_response(_setup_launch)
+ # We do not wait for the result here. It might be a little
+ # nicer if we did -- perhaps the various thread events would
+ # occur in a more logical sequence -- but if the inferior does
+ # not stop, then the launch response will not be seen either,
+ # which seems worse.
+ send_gdb(_do_launch)
+ # Launch response does not have a body.
+ return None
+
+ # The launch itself is deferred until the configurationDone
+ # request.
+ return _LaunchOrAttachDeferredRequest(_launch_impl)
+
+
+@request("attach", on_dap_thread=True)
def attach(
*,
program: Optional[str] = None,
@@ -76,21 +134,39 @@ def attach(
target: Optional[str] = None,
**args,
):
- if program is not None:
- file_command(program)
- if pid is not None:
- cmd = "attach " + str(pid)
- elif target is not None:
- cmd = "target remote " + target
- else:
- raise DAPException("attach requires either 'pid' or 'target'")
- expect_process("attach")
- expect_stop("attach")
- exec_and_log(cmd)
+ # The actual attach is handled by this function.
+ @in_gdb_thread
+ def _do_attach():
+ if program is not None:
+ file_command(program)
+ if pid is not None:
+ cmd = "attach " + str(pid)
+ elif target is not None:
+ cmd = "target remote " + target
+ else:
+ raise DAPException("attach requires either 'pid' or 'target'")
+ expect_process("attach")
+ expect_stop("attach")
+ exec_and_log(cmd)
+ # Attach response does not have a body.
+ return None
+
+ @in_dap_thread
+ def _attach_impl():
+ return send_gdb_with_response(_do_attach)
+
+ # The attach itself is deferred until the configurationDone
+ # request.
+ return _LaunchOrAttachDeferredRequest(_attach_impl)
@capability("supportsConfigurationDoneRequest")
-@request("configurationDone")
+@request("configurationDone", on_dap_thread=True)
def config_done(**args):
- # Nothing to do.
- return None
+ # Handle the launch or attach.
+ global _launch_or_attach_promise
+ if _launch_or_attach_promise is None:
+ raise DAPException("launch or attach not specified")
+ # Resolve the launch or attach, but only after the
+ # configurationDone response has been sent.
+ call_function_later(_launch_or_attach_promise.reschedule)
@@ -33,6 +33,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
# Stop in a C frame, but examine values in an Ada frame, to make sure
# cross-language scenarios work correctly.
set line [gdb_get_line_number "STOP" $testdir/cstuff.c]
@@ -44,9 +46,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -31,6 +31,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "STOP"]
set obj [dap_check_request_and_response "set breakpoint" \
setBreakpoints \
@@ -41,9 +43,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $binfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $fn_bpno
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "STOP"]
set obj [dap_check_request_and_response "set breakpoint" \
setBreakpoints \
@@ -39,9 +41,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $binfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $fn_bpno
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile arguments {a "b c"} env {{DEI something}}]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -38,9 +40,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile arguments {a "b c"} env {{DEI something}}] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -36,6 +36,8 @@ save_vars GDBFLAGS {
}
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "STOP"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -45,9 +47,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $line_bpno
@@ -29,17 +29,14 @@ set test_spawn_id [spawn_wait_for_attach $binfile]
set testpid [spawn_id_get_pid $test_spawn_id]
# Test that attaching works at all.
-set result [dap_attach $testpid $binfile]
-
-set found 0
-foreach ev [lindex $result 1] {
- if {[dict get $ev type] == "event"
- && [dict get $ev event] == "stopped"
- && [dict get $ev body reason] == "attach"} {
- set found 1
- }
-}
-gdb_assert {$found} "saw stopped event for attach"
+set attach_id [dap_attach $testpid $binfile]
+
+dap_check_request_and_response "configurationDone" configurationDone
+
+dap_wait_for_event_and_check "stopped" stopped \
+ "body reason" attach
+
+dap_check_response "attach response" attach $attach_id
dap_shutdown true
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set breakpoint on two functions" \
setFunctionBreakpoints \
{o breakpoints [a [o name [s function_breakpoint_here]] \
@@ -86,9 +88,8 @@ gdb_assert {$new_line_bpno == $line_bpno} "re-setting kept same breakpoint numbe
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
# While waiting for the stopped event, we might receive breakpoint changed
@@ -31,6 +31,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set breakpoint on inner" \
setFunctionBreakpoints \
{o breakpoints [a [o name [s function_breakpoint_here]]]}]
@@ -38,9 +40,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
lassign [dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
new file mode 100644
@@ -0,0 +1,56 @@
+# Copyright 2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Test cancellation of a "launch" command.
+
+require allow_dap_tests
+
+load_lib dap-support.exp
+
+# Anything will work, we aren't going to run it.
+standard_testfile sources.c
+
+if {[build_executable ${testfile}.exp $testfile $srcfile] == -1} {
+ return
+}
+
+if {[dap_initialize] == ""} {
+ return
+}
+
+set launch_id [dap_launch $testfile]
+
+# Set a breakpoint. This is done to ensure that the launch request is
+# definitely in the deferred state when we try to cancel it.
+set line [gdb_get_line_number "Distinguishing comment"]
+dap_check_request_and_response "set breakpoint by line number" \
+ setBreakpoints \
+ [format {o source [o path [%s]] breakpoints [a [o line [i %d]]]} \
+ [list s $srcfile] $line]
+
+set cancel_id [dap_send_request cancel \
+ [format {o requestId [i %d]} $launch_id]]
+
+dap_read_response cancel $cancel_id
+
+# The cancellation isn't actually processed until configurationDone is
+# sent. While this seems fine, it's unclear if gdb should be more
+# eager here and try to cancel a deferred task before it is
+# rescheduled.
+dap_check_request_and_response "configurationDone" configurationDone
+
+dap_read_response launch $launch_id
+
+dap_shutdown
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set exception catchpoints" \
setExceptionBreakpoints \
{o filters [a [s nosuchfilter] [s assert]] \
@@ -69,9 +71,8 @@ foreach spec $bps {
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $binfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at first raise" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" 2
@@ -36,6 +36,8 @@ save_vars GDBFLAGS {
}
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "STOP"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -45,9 +47,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $line_bpno
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "STOP"]
# Test some breakpoint-setting failure modes.
@@ -65,9 +67,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $fn_bpno
@@ -29,14 +29,14 @@ if {[dap_initialize] == ""} {
return
}
-dap_check_request_and_response "configurationDone" configurationDone
-
# Starting the inferior will fail if the change of cwd does not work.
set the_dir [file dirname $testfile]
set the_file [file tail $testfile]
-if {[dap_launch $the_file cwd $the_dir stop_at_main 1] == ""} {
- return
-}
+set launch_id [dap_launch $the_file cwd $the_dir stop_at_main 1]
+
+dap_check_request_and_response "configurationDone" configurationDone
+
+dap_check_response "launch response" launch $launch_id
# We didn't explicitly set a breakpoint, so if we hit one, it worked.
dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
@@ -28,6 +28,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set exception catchpoints" \
setExceptionBreakpoints \
{o filters [a [s throw] [s rethrow] [s catch]]}]
@@ -49,9 +51,8 @@ foreach bp $bps {
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at throw" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" 1
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set breakpoint" \
setFunctionBreakpoints \
{o breakpoints [a [o name [s main]]]}]
@@ -36,9 +38,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -38,9 +40,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
"body reason" breakpoint \
@@ -27,6 +27,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -36,9 +38,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -38,9 +40,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at breakpoint" stopped \
@@ -39,6 +39,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set breakpoint on main" \
setFunctionBreakpoints \
{o breakpoints [a [o name [s main]]]}]
@@ -56,14 +58,12 @@ gdb_assert {[dict get $bp verified] == "false"} \
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
-
# The event we're looking for should occur during startup, but we want
# to leave open the possibility that it occurs when waiting for the
-# stopped event. So, keep both event lists around and search them
+# stopped event. So, keep all event lists around and search them
# once below.
+lassign [dap_check_response "launch response" launch $launch_id] \
+ unused objs0
lassign [dap_wait_for_event_and_check "inferior started" \
thread "body reason" started] \
unused objs1
@@ -72,7 +72,7 @@ lassign [dap_wait_for_event_and_check "stopped at breakpoint" stopped \
"body hitBreakpointIds" $fn_bpno] unused objs2
set found_bp_event 0
-foreach obj [concat $objs1 $objs2] {
+foreach obj [concat $objs0 $objs1 $objs2] {
if { [dict get $obj "type"] != "event" } {
continue
}
@@ -36,6 +36,8 @@ save_vars GDBFLAGS {
}
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "STOP"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -45,9 +47,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $line_bpno
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "HERE"]
set obj [dap_check_request_and_response "set breakpoint" \
setBreakpoints \
@@ -40,9 +42,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "logging output" output \
@@ -37,6 +37,8 @@ save_vars { env(ASAN_OPTIONS) env(TSAN_OPTIONS) } {
}
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -46,9 +48,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -42,6 +42,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set breakpoint on stop function" \
setFunctionBreakpoints \
{o breakpoints [a [o name [s stop]]]}]
@@ -49,9 +51,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $fn_bpno
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
# Set a conditional breakpoint that will never fire. This is done to
# test the state-tracking in events -- an inferior call from a
# breakpoint condition should not cause any sort of stop or continue
@@ -43,9 +45,8 @@ dap_check_request_and_response "set conditional breakpoint" \
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "process event generated" process \
"body startMethod" process
dap_wait_for_event_and_check "inferior started" thread "body reason" started
@@ -27,6 +27,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -36,9 +38,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -42,8 +42,12 @@ lassign [gdbserver_start "" $target_exec] protocol port
gdb_assert {$protocol == "remote"}
# We just want to test that attaching works at all.
-if {[dap_target_remote $port] != ""} {
- dap_shutdown true
-}
+set attach_id [dap_target_remote $port]
+
+dap_check_request_and_response "configurationDone" configurationDone
+
+dap_check_response "attach response" attach $attach_id
+
+dap_shutdown true
close_gdbserver
@@ -32,6 +32,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "STOP"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -41,9 +43,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -38,9 +40,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
@@ -29,14 +29,16 @@ if {[dap_initialize] == ""} {
return
}
-if {[dap_launch $testfile stop_at_main 1] == ""} {
- return
-}
+set launch_id [dap_launch $testfile stop_at_main 1]
-proc do_tests {} {
- dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
- "body reason" breakpoint
+dap_check_request_and_response "configurationDone" configurationDone
+dap_check_response "launch response" launch $launch_id
+
+dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
+ "body reason" breakpoint
+
+proc do_tests {} {
set obj [dap_check_request_and_response loadedSources loadedSources]
if { $obj == "" } {
return
@@ -36,6 +36,8 @@ save_vars GDBFLAGS {
}
}
+set launch_id [dap_launch $testfile]
+
set line [gdb_get_line_number "BREAK"]
set obj [dap_check_request_and_response "set breakpoint by line number" \
setBreakpoints \
@@ -45,9 +47,8 @@ set line_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
"body reason" breakpoint \
"body hitBreakpointIds" $line_bpno
@@ -29,6 +29,8 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
set obj [dap_check_request_and_response "set breakpoint on function" \
setFunctionBreakpoints \
{o breakpoints [a [o name [s function_breakpoint_here]]]}]
@@ -36,9 +38,8 @@ set fn_bpno [dap_get_breakpoint_number $obj]
dap_check_request_and_response "configurationDone" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
@@ -29,11 +29,12 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile stop_at_main 1]
+
dap_check_request_and_response "start inferior" configurationDone
-if {[dap_launch $testfile stop_at_main 1] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
# We didn't explicitly set a breakpoint, so if we hit one, it worked.
dap_wait_for_event_and_check "stopped at function breakpoint" stopped \
"body reason" breakpoint
@@ -31,11 +31,12 @@ if {[dap_initialize] == ""} {
return
}
+set launch_id [dap_launch $testfile]
+
dap_check_request_and_response "start inferior" configurationDone
-if {[dap_launch $testfile] == ""} {
- return
-}
+dap_check_response "launch response" launch $launch_id
+
dap_wait_for_event_and_check "inferior started" thread "body reason" started
dap_wait_for_event_and_check "terminated event" terminated
@@ -248,10 +248,10 @@ proc dap_request_and_response {command {obj {}}} {
return [dap_read_response $command $seq]
}
-# Like dap_request_and_response, but also checks that the response
-# indicates success. NAME is used to issue a test result.
-proc dap_check_request_and_response {name command {obj {}}} {
- set response_and_events [dap_request_and_response $command $obj]
+# Wait for a response to the given request, and issue a pass/fail.
+# Returns the response and events like dap_request_and_response.
+proc dap_check_response {name cmd request} {
+ set response_and_events [dap_read_response $cmd $request]
set response [lindex $response_and_events 0]
if {[dict get $response success] != "true"} {
verbose "request failure: $response"
@@ -262,6 +262,13 @@ proc dap_check_request_and_response {name command {obj {}}} {
return $response_and_events
}
+# Like dap_request_and_response, but also checks that the response
+# indicates success. NAME is used to issue a test result.
+proc dap_check_request_and_response {name command {obj {}}} {
+ set seq [dap_send_request $command $obj]
+ return [dap_check_response $name $command $seq]
+}
+
# Start gdb, send a DAP initialization request and return the
# response. This approach lets the caller check the feature list, if
# desired. Returns the empty string on failure. NAME is used as the
@@ -278,10 +285,9 @@ proc dap_initialize {{name "initialize"}} {
}
# Send a launch request specifying FILE as the program to use for the
-# inferior. Returns the empty string on failure, or the response
-# object from the launch request. If specified, ARGS is a dictionary
-# of key-value pairs, each passed to the launch request. Valid keys
-# are:
+# inferior. Returns the request ID. If specified, ARGS is a
+# dictionary of key-value pairs, each passed to the launch request.
+# Valid keys are:
#
# * arguments - value is a list of strings passed as command-line
# arguments to the inferior
@@ -334,12 +340,12 @@ proc dap_launch {file {args {}}} {
}
}
- return [dap_check_request_and_response "startup - launch" launch $params]
+ return [dap_send_request launch $params]
}
# Start gdb, send a DAP initialize request, and then an attach request
# specifying PID as the inferior process ID. Returns the empty string
-# on failure, or the response object from the attach request.
+# on failure, or the attach request sequence ID.
proc dap_attach {pid {prog ""}} {
if {[dap_initialize "startup - initialize"] == ""} {
return ""
@@ -350,18 +356,17 @@ proc dap_attach {pid {prog ""}} {
append args [format { program [s %s]} $prog]
}
- return [dap_check_request_and_response "startup - attach" attach $args]
+ return [dap_send_request attach $args]
}
# Start gdb, send a DAP initialize request, and then an attach request
# specifying TARGET as the remote target. Returns the empty string on
-# failure, or the response object from the attach request.
+# failure, or the attach request sequence ID.
proc dap_target_remote {target} {
if {[dap_initialize "startup - initialize"] == ""} {
return ""
}
- return [dap_check_request_and_response "startup - target" attach \
- [format {o target [s %s]} $target]]
+ return [dap_send_request attach [format {o target [s %s]} $target]]
}
# Read the most recent DAP log file and check it for exceptions.