diff options
Diffstat (limited to 'gdb/testsuite/gdb.multi/multi-term-settings.exp')
-rw-r--r-- | gdb/testsuite/gdb.multi/multi-term-settings.exp | 242 |
1 files changed, 242 insertions, 0 deletions
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 |