diff options
Diffstat (limited to 'gdb/testsuite')
-rw-r--r-- | gdb/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/interrupt-daemon.c | 67 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/interrupt-daemon.exp | 89 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/multi-term-settings.c | 52 | ||||
-rw-r--r-- | gdb/testsuite/gdb.multi/multi-term-settings.exp | 242 |
5 files changed, 458 insertions, 0 deletions
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 52a689f..19b3eda 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2018-01-30 Pedro Alves <palves@redhat.com> + + PR gdb/13211 + * gdb.base/interrupt-daemon.c: New. + * gdb.base/interrupt-daemon.exp: New. + * gdb.multi/multi-term-settings.c: New. + * gdb.multi/multi-term-settings.exp: New. + 2018-01-30 Joel Brobecker <brobecker@adacore.com> * gdb.base/break.exp: Save the location where the breakpoint diff --git a/gdb/testsuite/gdb.base/interrupt-daemon.c b/gdb/testsuite/gdb.base/interrupt-daemon.c new file mode 100644 index 0000000..5074d7b --- /dev/null +++ b/gdb/testsuite/gdb.base/interrupt-daemon.c @@ -0,0 +1,67 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2017 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 <unistd.h> +#include <stdlib.h> +#include <assert.h> + +static void +daemon_main (void) +{ +} + +int +main () +{ + pid_t child; + + alarm (60); + + /* Normally we're a progress group leader at this point, so can't + create a session. Fork so the child can create a new + session. */ + child = fork (); + if (child == -1) + return 1; + else if (child != 0) + return 0; + else + { + /* In child. Switch to a new session. */ + pid_t session = setsid (); + if (session == -1) + return 1; + + /* Fork again, so that the grand child (what we want to debug) + can't accidentally acquire a controlling terminal, because + it's not a session leader. We're not opening any file here, + but this is representative of what daemons do. */ + child = fork (); + if (child == -1) + return 1; + else if (child != 0) + return 0; + + /* In grandchild. */ + daemon_main (); + + while (1) + sleep (1); + } + + return 0; +} diff --git a/gdb/testsuite/gdb.base/interrupt-daemon.exp b/gdb/testsuite/gdb.base/interrupt-daemon.exp new file mode 100644 index 0000000..ca3eecb --- /dev/null +++ b/gdb/testsuite/gdb.base/interrupt-daemon.exp @@ -0,0 +1,89 @@ +# Copyright 2017 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/>. + +# Make sure that we can interrupt an inferior that forks and moves to +# its own session. + +standard_testfile + +if {[build_executable "failed to build" $testfile $srcfile {debug}]} { + return -1 +} + +# The test proper. + +proc do_test {} { + global binfile + global gdb_prompt + + clean_restart $binfile + + gdb_test "set follow-fork-mode child" ".*" + + if ![runto "daemon_main"] { + fail "can't run to daemon_main function" + return + } + + with_test_prefix "fg" { + global gdb_prompt + + set test "continue" + gdb_test_multiple $test $test { + -re "Continuing" { + pass $test + } + } + + after 200 + + send_gdb "\003" + + set test "ctrl-c stops process" + gdb_test_multiple "" $test { + -re "received signal SIGINT.*\r\n$gdb_prompt $" { + pass $test + } + } + } + + with_test_prefix "bg" { + + set test "continue&" + gdb_test_multiple "continue&" $test { + -re "Continuing\\.\r\n$gdb_prompt " { + pass $test + } + } + + after 200 + + set test "interrupt" + gdb_test_multiple $test $test { + -re "$gdb_prompt " { + pass $test + } + } + + set test "interrupt cmd stops process" + gdb_test_multiple "" $test { + -re "received signal SIGINT" { + pass $test + } + } + } +} + +do_test diff --git a/gdb/testsuite/gdb.multi/multi-term-settings.c b/gdb/testsuite/gdb.multi/multi-term-settings.c new file mode 100644 index 0000000..c96779e --- /dev/null +++ b/gdb/testsuite/gdb.multi/multi-term-settings.c @@ -0,0 +1,52 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2017 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/>. */ + +/* This program is intended to be started outside of gdb, and then + attached to by gdb. It loops for a while, but not forever. */ + +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> +#include <termios.h> +#include <unistd.h> +#include <signal.h> + +int +main () +{ + /* In case we inherit SIG_IGN. */ + signal (SIGTTOU, SIG_DFL); + + alarm (30); + + int count = 0; + while (1) + { + struct termios termios; + + printf ("pid=%ld, count=%d\n", (long) getpid (), count++); + + /* This generates a SIGTTOU if our progress group is not in the + foreground. */ + tcgetattr (0, &termios); + tcsetattr (0, TCSANOW, &termios); + + usleep (100000); + } + + return 0; +} diff --git a/gdb/testsuite/gdb.multi/multi-term-settings.exp b/gdb/testsuite/gdb.multi/multi-term-settings.exp new file mode 100644 index 0000000..7245b84 --- /dev/null +++ b/gdb/testsuite/gdb.multi/multi-term-settings.exp @@ -0,0 +1,242 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2017 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/>. + +# This testcase exercises GDB's terminal ownership management +# (terminal_ours/terminal_inferior, etc.) when debugging multiple +# inferiors. It tests debugging multiple inferiors started with +# different combinations of 'run'/'run+tty'/'attach', and ensures that +# the process that is sharing GDB's terminal/session is properly made +# the GDB terminal's foregound process group (i.e., "given the +# terminal"). + +standard_testfile + +if ![can_spawn_for_attach] { + return 0 +} + +if [build_executable "failed to prepare" $testfile $srcfile {debug}] { + return -1 +} + +# Start the programs running and then wait for a bit, to be sure that +# they can be attached to. We start these processes upfront in order +# to reuse them for the different iterations. This makes the testcase +# faster, compared to calling spawn_wait_for_attach for each iteration +# in the testing matrix. + +set spawn_id_list [spawn_wait_for_attach [list $binfile $binfile]] +set attach_spawn_id1 [lindex $spawn_id_list 0] +set attach_spawn_id2 [lindex $spawn_id_list 1] +set attach_pid1 [spawn_id_get_pid $attach_spawn_id1] +set attach_pid2 [spawn_id_get_pid $attach_spawn_id2] + +# Create inferior WHICH_INF. INF_HOW is how to create it. This can +# be one of: +# +# - "run" - for "run" command. +# - "tty" - for "run" + "tty TTY". +# - "attach" - for attaching to an existing process. +proc create_inferior {which_inf inf_how} { + global binfile + + # Run to main and delete breakpoints. + proc my_runto_main {} { + if ![runto_main] { + fail "run to main" + return 0 + } else { + # Delete breakpoints otherwise GDB would try to step over + # the breakpoint at 'main' without resuming the other + # inferior, possibly masking the issue we're trying to + # test. + delete_breakpoints + return 1 + } + } + + if {$inf_how == "run"} { + if [my_runto_main] { + global inferior_spawn_id + return $inferior_spawn_id + } + } elseif {$inf_how == "tty"} { + # Create the new PTY for the inferior. + spawn -pty + set inf_spawn_id $spawn_id + set inf_tty_name $spawn_out(slave,name) + gdb_test_no_output "tty $inf_tty_name" "tty TTY" + + if [my_runto_main] { + return $inf_spawn_id + } + } elseif {$inf_how == "attach"} { + + # Reuse the inferiors spawned at the start of the testcase (to + # avoid having to wait the delay imposed by + # spawn_wait_for_attach). + global attach_spawn_id$which_inf + set test_spawn_id [set attach_spawn_id$which_inf] + set testpid [spawn_id_get_pid $test_spawn_id] + if {[gdb_test "attach $testpid" \ + "Attaching to program: .*, process $testpid.*(in|at).*" \ + "attach"] == 0} { + return $test_spawn_id + } + } else { + error "unhandled inf_how: $inf_how" + } + + return "" +} + +# Print debug output. + +proc send_debug {str} { + # Uncomment for debugging. + #send_user $str +} + +# The core of the testcase. See intro. Creates two inferiors that +# both loop changing their terminal's settings and printing output, +# and checks whether they receive SIGTTOU. INF1_HOW and INF2_HOW +# indicate how inferiors 1 and 2 should be created, respectively. See +# 'create_inferior' above for what arguments these parameters accept. + +proc coretest {inf1_how inf2_how} { + global binfile + global inferior_spawn_id + global gdb_spawn_id + global decimal + + clean_restart $binfile + + set inf1_spawn_id [create_inferior 1 $inf1_how] + + set num 2 + gdb_test "add-inferior" "Added inferior $num.*" \ + "add empty inferior $num" + gdb_test "inferior $num" "Switching to inferior $num.*" \ + "switch to inferior $num" + gdb_file_cmd ${binfile} + + set inf2_spawn_id [create_inferior 2 $inf2_how] + + gdb_test_no_output "set schedule-multiple on" + + # "run" makes each inferior be a process group leader. When we + # run both inferiors in GDB's terminal/session, only one can end + # up as the terminal's foreground process group, so it's expected + # that the other receives a SIGTTOU. + set expect_ttou [expr {$inf1_how == "run" && $inf2_how == "run"}] + + global gdb_prompt + + set any "\[^\r\n\]*" + + set pid1 -1 + set pid2 -1 + + set test "info inferiors" + gdb_test_multiple $test $test { + -re "1${any}process ($decimal)${any}\r\n" { + set pid1 $expect_out(1,string) + send_debug "pid1=$pid1\n" + exp_continue + } + -re "2${any}process ($decimal)${any}\r\n" { + set pid2 $expect_out(1,string) + send_debug "pid2=$pid2\n" + exp_continue + } + -re "$gdb_prompt $" { + pass $test + } + } + + # Helper for the gdb_test_multiple call below. Issues a PASS if + # we've seen each inferior print at least 3 times, otherwise + # continues waiting for inferior output. + proc pass_or_exp_continue {} { + uplevel 1 { + if {$count1 >= 3 && $count2 >= 3} { + if $expect_ttou { + fail "$test (expected SIGTTOU)" + } else { + pass $test + } + } else { + exp_continue + } + } + } + + set infs_spawn_ids [list $inf1_spawn_id $inf2_spawn_id] + send_debug "infs_spawn_ids=$infs_spawn_ids\n" + + set count1 0 + set count2 0 + + set test "continue" + gdb_test_multiple $test $test { + -i $infs_spawn_ids -re "pid=$pid1, count=" { + incr count1 + pass_or_exp_continue + } + -i $infs_spawn_ids -re "pid=$pid2, count=" { + incr count2 + pass_or_exp_continue + } + -i $gdb_spawn_id -re "received signal SIGTTOU.*$gdb_prompt " { + if $expect_ttou { + pass "$test (expected SIGTTOU)" + } else { + fail "$test (SIGTTOU)" + } + } + } + + send_gdb "\003" + if {$expect_ttou} { + gdb_test "" "Quit" "stop with control-c" + } else { + gdb_test "" "received signal SIGINT.*" "stop with control-c" + } + + # Useful for debugging in case the Ctrl-C above fails. + gdb_test "info inferiors" + gdb_test "info threads" +} + +set how_modes {"run" "attach" "tty"} + +foreach_with_prefix inf1_how $how_modes { + foreach_with_prefix inf2_how $how_modes { + if {($inf1_how == "tty" || $inf2_how == "tty") + && [target_info gdb_protocol] == "extended-remote"} { + # No way to specify the inferior's tty in the remote + # protocol. + unsupported "no support for \"tty\" in the RSP" + continue + } + + coretest $inf1_how $inf2_how + } +} + +kill_wait_spawned_process $attach_spawn_id1 +kill_wait_spawned_process $attach_spawn_id2 |