From d0c99a23b21aff9107a4cf49ee626b7db0824a04 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Sun, 24 Jan 2021 23:57:28 -0500 Subject: [PATCH] gdb/testsuite: add test for run/attach while program is running A WIP patch series broke the use case of doing "run" or "attach" while the program is running, but it wasn't caught by the testsuite, which means it's not covered. Add a test for that. gdb/testsuite/ChangeLog: * gdb.base/run-attach-while-running.exp: New. * gdb.base/run-attach-while-running.c: New. Change-Id: I77f098ec0b28dc2d4575ea80e941f6a75273e431 --- gdb/testsuite/ChangeLog | 6 + .../gdb.base/run-attach-while-running.c | 69 ++++++++++ .../gdb.base/run-attach-while-running.exp | 120 ++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 gdb/testsuite/gdb.base/run-attach-while-running.c create mode 100644 gdb/testsuite/gdb.base/run-attach-while-running.exp diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 1e23b91d9a..c1d7fec6cc 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2021-03-17 Simon Marchi + Pedro Alves + + * gdb.base/run-attach-while-running.exp: New. + * gdb.base/run-attach-while-running.c: New. + 2021-03-16 Andrew Burgess * gdb.python/py-framefilter-addr.c: New file. diff --git a/gdb/testsuite/gdb.base/run-attach-while-running.c b/gdb/testsuite/gdb.base/run-attach-while-running.c new file mode 100644 index 0000000000..57bebbe645 --- /dev/null +++ b/gdb/testsuite/gdb.base/run-attach-while-running.c @@ -0,0 +1,69 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021 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 . */ + +#include +#include + +#ifndef WITH_THREADS +# error "WITH_THREADS must be defined." +#endif + +#if WITH_THREADS +# include + +static pthread_barrier_t barrier; + +static void * +thread_func (void *p) +{ + pthread_barrier_wait (&barrier); + + for (int i = 0; i < 30; i++) + sleep (1); + + return NULL; +} + +#endif /* WITH_THREADS */ + +static void +all_started (void) +{} + +int +main (void) +{ + alarm (30); + +#if WITH_THREADS + int ret = pthread_barrier_init (&barrier, NULL, 2); + assert (ret == 0); + + pthread_t thread; + ret = pthread_create (&thread, NULL, thread_func, NULL); + assert (ret == 0); + + pthread_barrier_wait (&barrier); +#endif /* WITH_THREADS */ + + all_started (); + + for (int i = 0; i < 30; i++) + sleep (1); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/run-attach-while-running.exp b/gdb/testsuite/gdb.base/run-attach-while-running.exp new file mode 100644 index 0000000000..7c16aa6f5c --- /dev/null +++ b/gdb/testsuite/gdb.base/run-attach-while-running.exp @@ -0,0 +1,120 @@ +# Copyright 2021 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 . + +# Test doing a "run" or an "attach" while the program is running. +# +# We test a non-threaded and a threaded configuration, so that targets +# that don't support threads get some testing, but we also test with +# threads when possible in case that triggers some +# multi-thread-specific bugs. + +standard_testfile + +set binfile_threads ${binfile}-threads +set binfile_nothreads ${binfile}-nothreads +unset binfile + +# Valid parameter / axis values: +# +# - non-stop: "off" of "on" +# - threaded: 0 or 1 +# - run-or-attach: "run" or "attach" + +proc_with_prefix test { non-stop threaded run-or-attach } { + if { ${run-or-attach} == "attach" && ![can_spawn_for_attach] } { + unsupported "attach not supported" + return + } + + save_vars ::GDBFLAGS { + set ::GDBFLAGS "$::GDBFLAGS -ex \"set non-stop ${non-stop}\"" + + # The test doesn't work when the remote target uses the + # synchronous remote protocol, because GDB can't kill the + # remote inferior while it is running, when we "run" or + # "attach" again. When aswering "yes" to the "Start it from + # the beginning?" question, we otherwise get: + # + # Cannot execute this command while the target is running. Use the + # "interrupt" command to stop the target and then try again. + # + # Interrupting the target would defeat the purpose of the + # test. So when non-stop is off and using the remote target, + # force the target to use the async / non-stop version of the + # protocol. + if { [target_info exists gdb_protocol] && ${non-stop} == "off" } { + set ::GDBFLAGS "$::GDBFLAGS -ex \"maint set target-non-stop on\"" + } + + clean_restart $::binfile + } + + if { ![runto_main] } { + untested "could not run to main" + return + } + + gdb_breakpoint "all_started" "temporary" + gdb_continue_to_breakpoint "continue to all_started" + + # If all-stop, everything stopped when we hit the all_started + # breakpoint, so resume execution in background. If running the + # non-threaded version, our only thread is stopped in any case, so + # resume as well. But if we are in non-stop with two threads, we + # have one running and one stopped, leave it like this, it makes + # an interesting test case. + if { ${non-stop} == "off" || !${threaded} } { + gdb_test "continue &" "Continuing." + } + + gdb_test_no_output "set confirm off" + + # Run again (or, connect to a new stub if using a stub), take + # advantage of the fact that runto_main leaves the breakpoint on + # main in place. + if { ${run-or-attach} == "run" } { + gdb_run_cmd + gdb_test "" "Breakpoint $::decimal, .*main.*" "hit main breakpoint after re-run" + } elseif { ${run-or-attach} == "attach" } { + set test_spawn_id [spawn_wait_for_attach $::binfile] + set test_pid [spawn_id_get_pid $test_spawn_id] + + gdb_test "attach $test_pid" "Attaching to program: .*" "attach to process" + + gdb_exit + kill_wait_spawned_process $test_spawn_id + } else { + error "Invalid value for run-or-attach" + } +} + +foreach_with_prefix threaded {0 1} { + set options [list debug additional_flags=-DWITH_THREADS=$threaded] + if { $threaded } { + set binfile $binfile_threads + lappend options pthreads + } else { + set binfile $binfile_nothreads + } + if { [build_executable "failed to prepare" ${binfile} ${srcfile} $options] } { + continue + } + + foreach_with_prefix run-or-attach {run attach} { + foreach_with_prefix non-stop {off on} { + test ${non-stop} ${threaded} ${run-or-attach} + } + } +} -- 2.34.1