aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.dap
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/testsuite/gdb.dap')
-rw-r--r--gdb/testsuite/gdb.dap/attach.exp4
-rw-r--r--gdb/testsuite/gdb.dap/log-message.exp9
-rw-r--r--gdb/testsuite/gdb.dap/scopes.c2
-rw-r--r--gdb/testsuite/gdb.dap/scopes.exp247
-rw-r--r--gdb/testsuite/gdb.dap/threads.c67
-rw-r--r--gdb/testsuite/gdb.dap/threads.exp81
6 files changed, 306 insertions, 104 deletions
diff --git a/gdb/testsuite/gdb.dap/attach.exp b/gdb/testsuite/gdb.dap/attach.exp
index 37e867c..5e1f634 100644
--- a/gdb/testsuite/gdb.dap/attach.exp
+++ b/gdb/testsuite/gdb.dap/attach.exp
@@ -33,11 +33,11 @@ set attach_id [dap_attach $testpid $binfile]
dap_check_request_and_response "configurationDone" configurationDone
+dap_check_response "attach response" attach $attach_id
+
dap_wait_for_event_and_check "stopped" stopped \
"body reason" attach
-dap_check_response "attach response" attach $attach_id
-
dap_shutdown true
kill_wait_spawned_process $test_spawn_id
diff --git a/gdb/testsuite/gdb.dap/log-message.exp b/gdb/testsuite/gdb.dap/log-message.exp
index 421df14..cce367d 100644
--- a/gdb/testsuite/gdb.dap/log-message.exp
+++ b/gdb/testsuite/gdb.dap/log-message.exp
@@ -40,6 +40,15 @@ set obj [dap_check_request_and_response "set breakpoint" \
[list s $srcfile] $line]]
set fn_bpno [dap_get_breakpoint_number $obj]
+set eol {\n}
+dap_wait_for_event_and_check "set breakpoint output, part 1" output \
+ {body category} stdout \
+ {body output} "No source file named log-message.c.$eol"
+
+dap_wait_for_event_and_check "set breakpoint output, part 2" output \
+ {body category} stdout \
+ {body output} "Breakpoint 1 (-source log-message.c -line $line) pending.$eol"
+
dap_check_request_and_response "configurationDone" configurationDone
dap_check_response "launch response" launch $launch_id
diff --git a/gdb/testsuite/gdb.dap/scopes.c b/gdb/testsuite/gdb.dap/scopes.c
index d8929f1..2a1d76c 100644
--- a/gdb/testsuite/gdb.dap/scopes.c
+++ b/gdb/testsuite/gdb.dap/scopes.c
@@ -27,6 +27,8 @@ int main ()
static int scalar = 23;
+ void *ptr = (void *) &scalar;
+
{
const char *inner = "inner block";
diff --git a/gdb/testsuite/gdb.dap/scopes.exp b/gdb/testsuite/gdb.dap/scopes.exp
index 59d344b..e4e5c28 100644
--- a/gdb/testsuite/gdb.dap/scopes.exp
+++ b/gdb/testsuite/gdb.dap/scopes.exp
@@ -25,123 +25,166 @@ if {[build_executable ${testfile}.exp $testfile] == -1} {
return
}
-if {[dap_initialize] == ""} {
- return
-}
+save_vars { ::env(GLIBC_TUNABLES) } {
+
+ # If x86 shadow stack is supported we need to configure GLIBC_TUNABLES
+ # such that the feature is enabled and the register pl3_ssp is
+ # available. Otherwise the request to fetch all registers will fail
+ # with "message": "value is not available".
+ if { [allow_ssp_tests] } {
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+ }
-set launch_id [dap_launch $testfile]
+ if {[dap_initialize] == ""} {
+ return
+ }
-set line [gdb_get_line_number "BREAK"]
-set obj [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 line_bpno [dap_get_breakpoint_number $obj]
+ set launch_id [dap_launch $testfile]
-dap_check_request_and_response "configurationDone" configurationDone
+ set line [gdb_get_line_number "BREAK"]
+ set obj [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 line_bpno [dap_get_breakpoint_number $obj]
-dap_check_response "launch response" launch $launch_id
+ dap_check_request_and_response "configurationDone" configurationDone
-dap_wait_for_event_and_check "inferior started" thread "body reason" started
+ 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
+ dap_wait_for_event_and_check "inferior started" thread "body reason" started
-set bt [lindex [dap_check_request_and_response "backtrace" stackTrace \
- {o threadId [i 1]}] \
- 0]
-set frame_id [dict get [lindex [dict get $bt body stackFrames] 0] id]
+ dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
+ "body reason" breakpoint \
+ "body hitBreakpointIds" $line_bpno
-set scopes [dap_check_request_and_response "get scopes" scopes \
+ set bt [lindex [dap_check_request_and_response "backtrace" stackTrace \
+ {o threadId [i 1]}] \
+ 0]
+ set frame_id [dict get [lindex [dict get $bt body stackFrames] 0] id]
+
+ set scopes [dap_check_request_and_response "get scopes" scopes \
[format {o frameId [i %d]} $frame_id]]
-set scopes [dict get [lindex $scopes 0] body scopes]
+ set scopes [dict get [lindex $scopes 0] body scopes]
-# Request the scopes twice, and verify that the results are identical.
-# GDB previously had a bug where it would return new scopes each time.
-set scopes2 [dap_check_request_and_response "get scopes again" scopes \
+ # Request the scopes twice, and verify that the results are identical.
+ # GDB previously had a bug where it would return new scopes each time.
+ set scopes2 [dap_check_request_and_response "get scopes again" scopes \
[format {o frameId [i %d]} $frame_id]]
-set scopes2 [dict get [lindex $scopes2 0] body scopes]
-gdb_assert {$scopes2 == $scopes} "identical scopes requests yield same body"
-
-gdb_assert {[llength $scopes] == 2} "two scopes"
-
-lassign $scopes scope reg_scope
-gdb_assert {[dict get $scope name] == "Locals"} "scope is locals"
-gdb_assert {[dict get $scope presentationHint] == "locals"} \
- "locals presentation hint"
-gdb_assert {[dict get $scope namedVariables] == 3} "three vars in scope"
-
-gdb_assert {[dict get $reg_scope name] == "Registers"} \
- "second scope is registers"
-gdb_assert {[dict get $reg_scope presentationHint] == "registers"} \
- "registers presentation hint"
-gdb_assert {[dict get $reg_scope namedVariables] > 0} "at least one register"
-
-set num [dict get $scope variablesReference]
-# Send two requests and combine them, to verify that using a range
-# works.
-set refs1 [lindex [dap_check_request_and_response "fetch variables 0,1" \
- "variables" \
- [format {o variablesReference [i %d] count [i 2]} \
- $num]] \
- 0]
-set refs2 [lindex [dap_check_request_and_response "fetch variables 2" \
- "variables" \
- [format {o variablesReference [i %d] \
- start [i 2] count [i 1]} \
- $num]] \
- 0]
-
-set vars [concat [dict get $refs1 body variables] \
- [dict get $refs2 body variables]]
-foreach var $vars {
- set name [dict get $var name]
-
- if {$name != "dei"} {
- gdb_assert {[dict get $var variablesReference] == 0} \
- "$name has no structure"
- }
-
- switch $name {
- "inner" {
- gdb_assert {[string match "*inner block*" [dict get $var value]]} \
- "check value of inner"
+ set scopes2 [dict get [lindex $scopes2 0] body scopes]
+ gdb_assert {$scopes2 == $scopes} "identical scopes requests yield same body"
+
+ gdb_assert {[llength $scopes] == 2} "two scopes"
+
+ lassign $scopes scope reg_scope
+ gdb_assert {[dict get $scope name] == "Locals"} "scope is locals"
+ gdb_assert {[dict get $scope presentationHint] == "locals"} \
+ "locals presentation hint"
+ set count [dict get $scope namedVariables]
+ gdb_assert {$count == 4} "four vars in scope"
+
+ gdb_assert {[dict get $reg_scope name] == "Registers"} \
+ "second scope is registers"
+ gdb_assert {[dict get $reg_scope presentationHint] == "registers"} \
+ "registers presentation hint"
+ gdb_assert {[dict get $reg_scope namedVariables] > 0} "at least one register"
+
+ set num [dict get $scope variablesReference]
+ # Send two requests and combine them, to verify that using a range
+ # works.
+ set refs1 [lindex [dap_check_request_and_response "fetch variables 0,1" \
+ "variables" \
+ [format {o variablesReference [i %d] count [i 2]} \
+ $num]] \
+ 0]
+ set refs2 [lindex [dap_check_request_and_response "fetch variables 2" \
+ "variables" \
+ [format {o variablesReference [i %d] \
+ start [i 2] count [i %d]} \
+ $num [expr {$count - 2}]]] \
+ 0]
+
+ set vars [concat [dict get $refs1 body variables] \
+ [dict get $refs2 body variables]]
+ foreach var $vars {
+ set name [dict get $var name]
+
+ if {$name != "dei"} {
+ gdb_assert {[dict get $var variablesReference] == 0} \
+ "$name has no structure"
}
- "dei" {
- gdb_assert {[dict get $var value] == ""} "check value of dei"
- set dei_ref [dict get $var variablesReference]
- }
- "scalar" {
- gdb_assert {[dict get $var value] == 23} "check value of scalar"
+
+ switch $name {
+ "inner" {
+ gdb_assert {[string match "*inner block*" [dict get $var value]]} \
+ "check value of inner"
+ }
+ "dei" {
+ gdb_assert {[dict get $var value] == ""} "check value of dei"
+ set dei_ref [dict get $var variablesReference]
+ }
+ "scalar" {
+ gdb_assert {[dict get $var value] == 23} "check value of scalar"
+ }
+ "ptr" {
+ gdb_assert {[dict get $var memoryReference] != ""} \
+ "check memoryReference of ptr"
+ }
+ default {
+ fail "unknown variable $name"
+ }
}
- default {
- fail "unknown variable $name"
+ }
+
+ set refs [lindex [dap_check_request_and_response "fetch contents of dei" \
+ "variables" \
+ [format {o variablesReference [i %d]} $dei_ref]] \
+ 0]
+ set deivals [dict get $refs body variables]
+ gdb_assert {[llength $deivals] == 2} "dei has two members"
+
+ # Request more children than exist. See PR dap/33228.
+ set seq [dap_send_request variables \
+ [format {o variablesReference [i %d] count [i 100]} $dei_ref]]
+ lassign [dap_read_response variables $seq] response ignore
+ gdb_assert {[dict get $response success] == "false"} \
+ "variables with invalid count"
+
+ set num [dict get $reg_scope variablesReference]
+ lassign [dap_check_request_and_response "fetch all registers" \
+ "variables" \
+ [format {o variablesReference [i %d] count [i %d]} $num\
+ [dict get $reg_scope namedVariables]]] \
+ val events
+
+ # If any register has children, try to fetch those as well. This is a
+ # regression test for part of PR dap/33228.
+ foreach var [dict get $val body variables] {
+ set regvar [dict get $var variablesReference]
+ if {$regvar > 0} {
+ # If variablesReference is non-zero, then there must be either
+ # named or indexed children.
+ if {[dict exists $var namedVariables]} {
+ set n [dict get $var namedVariables]
+ } else {
+ set n [dict get $var indexedVariables]
+ }
+
+ dap_check_request_and_response "fetch register children for $regvar" \
+ "variables" \
+ [format {o variablesReference [i %d] count [i %d]} $regvar $n]
}
}
-}
-set refs [lindex [dap_check_request_and_response "fetch contents of dei" \
- "variables" \
- [format {o variablesReference [i %d]} $dei_ref]] \
- 0]
-set deivals [dict get $refs body variables]
-gdb_assert {[llength $deivals] == 2} "dei has two members"
-
-set num [dict get $reg_scope variablesReference]
-# The request succeeding is sufficient.
-set val [dap_check_request_and_response "fetch first register" \
- "variables" \
- [format {o variablesReference [i %d] count [i 1]} $num]]
-
-set num [dict get $scope variablesReference]
-set refs [lindex [dap_check_request_and_response "set variable scalar" \
- "setVariable" \
- [format {o variablesReference [i %d] name [s scalar] \
- value [s 32]} \
+ set num [dict get $scope variablesReference]
+ set refs [lindex [dap_check_request_and_response "set variable scalar" \
+ "setVariable" \
+ [format {o variablesReference [i %d] name [s scalar] \
+ value [s 32]} \
$num]] \
- 0]
-gdb_assert { [dict get $refs body value] == 32 } \
- "setting variable yields updated value"
+ 0]
+ gdb_assert { [dict get $refs body value] == 32 } \
+ "setting variable yields updated value"
-dap_shutdown
+ dap_shutdown
+}
diff --git a/gdb/testsuite/gdb.dap/threads.c b/gdb/testsuite/gdb.dap/threads.c
new file mode 100644
index 0000000..168f044
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/threads.c
@@ -0,0 +1,67 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019-2025 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/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define NUM 2
+
+static pthread_barrier_t threads_started_barrier;
+
+static void *
+thread_function (void *arg)
+{
+ pthread_barrier_wait (&threads_started_barrier);
+
+ while (1)
+ sleep (1);
+
+ pthread_exit (NULL);
+}
+
+static void
+all_started (void)
+{
+}
+
+int
+main ()
+{
+ pthread_t threads[NUM];
+ long i;
+
+ pthread_barrier_init (&threads_started_barrier, NULL, NUM + 1);
+
+ for (i = 1; i <= NUM; i++)
+ {
+ int res;
+
+ res = pthread_create (&threads[i - 1], NULL, thread_function, NULL);
+ }
+
+ pthread_barrier_wait (&threads_started_barrier);
+
+ all_started ();
+
+ printf ("sleeping\n");
+ fflush (stdout);
+ sleep (180);
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.dap/threads.exp b/gdb/testsuite/gdb.dap/threads.exp
new file mode 100644
index 0000000..c91d107
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/threads.exp
@@ -0,0 +1,81 @@
+# Copyright 2025 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 DAP "threads" request.
+
+require allow_shlib_tests allow_dap_tests
+
+load_lib dap-support.exp
+
+standard_testfile
+
+set libname $testfile-solib
+set srcfile_lib $srcdir/$subdir/$libname.c
+set binfile_lib [standard_output_file $libname.so]
+
+if {[build_executable "failed to prepare" $testfile $srcfile \
+ {debug pthreads}] == -1} {
+ return
+}
+
+if {[dap_initialize] == ""} {
+ return
+}
+
+set launch_id [dap_launch $testfile]
+
+set obj [dap_check_request_and_response "set breakpoint on all_started function" \
+ setFunctionBreakpoints \
+ {o breakpoints [a [o name [s all_started]]]}]
+set fn_bpno [dap_get_breakpoint_number $obj]
+
+dap_check_request_and_response "configurationDone" configurationDone
+
+dap_check_response "launch response" launch $launch_id
+
+lassign [dap_wait_for_event_and_check "stopped at function breakpoint" \
+ stopped \
+ "body reason" breakpoint \
+ "body hitBreakpointIds" $fn_bpno] \
+ ignore \
+ all_events
+
+# Verify that we saw the correct number of thread events.
+set count 0
+foreach event $all_events {
+ if {[dict get $event type] == "event"
+ && [dict get $event event] == "thread"
+ && [dict get $event body reason] == "started"} {
+ incr count
+ }
+}
+gdb_assert {$count == 3} "correct number of thread events"
+
+dap_check_request_and_response "continue" continue \
+ {o threadId [i 1]}
+
+# Make sure that the inferior has really re-started -- note that there
+# is no "continue" event, because the "continue" request suppresses
+# those.
+dap_wait_for_event_and_check "output from inferior" output \
+ {body output} "sleeping\\n"
+
+lassign [dap_check_request_and_response "threads request" threads] \
+ response ignore
+
+gdb_assert {[llength [dict get $response body threads]] == 3} \
+ "correct number of threads"
+
+dap_shutdown true