xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.multi/multi-term-settings.exp (revision ae082add65442546470c0ba499a860ee89eed305)
1# This testcase is part of GDB, the GNU debugger.
2
3# Copyright 2017-2019 Free Software Foundation, Inc.
4
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18# This testcase exercises GDB's terminal ownership management
19# (terminal_ours/terminal_inferior, etc.) when debugging multiple
20# inferiors.  It tests debugging multiple inferiors started with
21# different combinations of 'run'/'run+tty'/'attach', and ensures that
22# the process that is sharing GDB's terminal/session is properly made
23# the GDB terminal's foregound process group (i.e., "given the
24# terminal").
25
26standard_testfile
27
28if ![can_spawn_for_attach] {
29    return 0
30}
31
32if [build_executable "failed to prepare" $testfile $srcfile {debug}] {
33    return -1
34}
35
36# Start the programs running and then wait for a bit, to be sure that
37# they can be attached to.  We start these processes upfront in order
38# to reuse them for the different iterations.  This makes the testcase
39# faster, compared to calling spawn_wait_for_attach for each iteration
40# in the testing matrix.
41
42set spawn_id_list [spawn_wait_for_attach [list $binfile $binfile]]
43set attach_spawn_id1 [lindex $spawn_id_list 0]
44set attach_spawn_id2 [lindex $spawn_id_list 1]
45set attach_pid1 [spawn_id_get_pid $attach_spawn_id1]
46set attach_pid2 [spawn_id_get_pid $attach_spawn_id2]
47
48# Create inferior WHICH_INF.  INF_HOW is how to create it.  This can
49# be one of:
50#
51#  - "run" - for "run" command.
52#  - "tty" - for "run" + "tty TTY".
53#  - "attach" - for attaching to an existing process.
54proc create_inferior {which_inf inf_how} {
55    global binfile
56
57    # Run to main and delete breakpoints.
58    proc my_runto_main {} {
59	if ![runto_main] {
60	    fail "run to main"
61	    return 0
62	} else {
63	    # Delete breakpoints otherwise GDB would try to step over
64	    # the breakpoint at 'main' without resuming the other
65	    # inferior, possibly masking the issue we're trying to
66	    # test.
67	    delete_breakpoints
68	    return 1
69	}
70    }
71
72    if {$inf_how == "run"} {
73	if [my_runto_main] {
74	    global inferior_spawn_id
75	    return $inferior_spawn_id
76	}
77    } elseif {$inf_how == "tty"} {
78	# Create the new PTY for the inferior.
79	spawn -pty
80	set inf_spawn_id $spawn_id
81	set inf_tty_name $spawn_out(slave,name)
82	gdb_test_no_output "tty $inf_tty_name" "tty TTY"
83
84	if [my_runto_main] {
85	    return $inf_spawn_id
86	}
87    } elseif {$inf_how == "attach"} {
88
89	# Reuse the inferiors spawned at the start of the testcase (to
90	# avoid having to wait the delay imposed by
91	# spawn_wait_for_attach).
92	global attach_spawn_id$which_inf
93	set test_spawn_id [set attach_spawn_id$which_inf]
94	set testpid [spawn_id_get_pid $test_spawn_id]
95	if {[gdb_test "attach $testpid" \
96		 "Attaching to program: .*, process $testpid.*(in|at).*" \
97		 "attach"] == 0} {
98	    return $test_spawn_id
99	}
100    } else {
101	error "unhandled inf_how: $inf_how"
102    }
103
104    return ""
105}
106
107# Print debug output.
108
109proc send_debug {str} {
110    # Uncomment for debugging.
111    #send_user $str
112}
113
114# The core of the testcase.  See intro.  Creates two inferiors that
115# both loop changing their terminal's settings and printing output,
116# and checks whether they receive SIGTTOU.  INF1_HOW and INF2_HOW
117# indicate how inferiors 1 and 2 should be created, respectively.  See
118# 'create_inferior' above for what arguments these parameters accept.
119
120proc coretest {inf1_how inf2_how} {
121    global binfile
122    global inferior_spawn_id
123    global gdb_spawn_id
124    global decimal
125
126    clean_restart $binfile
127
128    set inf1_spawn_id [create_inferior 1 $inf1_how]
129
130    set num 2
131    gdb_test "add-inferior" "Added inferior $num.*" \
132	"add empty inferior $num"
133    gdb_test "inferior $num" "Switching to inferior $num.*" \
134	"switch to inferior $num"
135    gdb_file_cmd ${binfile}
136
137    set inf2_spawn_id [create_inferior 2 $inf2_how]
138
139    gdb_test_no_output "set schedule-multiple on"
140
141    # "run" makes each inferior be a process group leader.  When we
142    # run both inferiors in GDB's terminal/session, only one can end
143    # up as the terminal's foreground process group, so it's expected
144    # that the other receives a SIGTTOU.
145    set expect_ttou [expr {$inf1_how == "run" && $inf2_how == "run"}]
146
147    global gdb_prompt
148
149    set any "\[^\r\n\]*"
150
151    set pid1 -1
152    set pid2 -1
153
154    set test "info inferiors"
155    gdb_test_multiple $test $test {
156	-re "1${any}process ($decimal)${any}\r\n" {
157	    set pid1 $expect_out(1,string)
158	    send_debug "pid1=$pid1\n"
159	    exp_continue
160	}
161	-re "2${any}process ($decimal)${any}\r\n" {
162	    set pid2 $expect_out(1,string)
163	    send_debug "pid2=$pid2\n"
164	    exp_continue
165	}
166	-re "$gdb_prompt $" {
167	    pass $test
168	}
169    }
170
171    # Helper for the gdb_test_multiple call below.  Issues a PASS if
172    # we've seen each inferior print at least 3 times, otherwise
173    # continues waiting for inferior output.
174    proc pass_or_exp_continue {} {
175	uplevel 1 {
176	    if {$count1 >= 3 && $count2 >= 3} {
177		if $expect_ttou {
178		    fail "$test (expected SIGTTOU)"
179		} else {
180		    pass $test
181		}
182	    } else {
183		exp_continue
184	    }
185	}
186    }
187
188    set infs_spawn_ids [list $inf1_spawn_id $inf2_spawn_id]
189    send_debug "infs_spawn_ids=$infs_spawn_ids\n"
190
191    set count1 0
192    set count2 0
193
194    set test "continue"
195    gdb_test_multiple $test $test {
196	-i $infs_spawn_ids -re "pid=$pid1, count=" {
197	    incr count1
198	    pass_or_exp_continue
199	}
200	-i $infs_spawn_ids -re "pid=$pid2, count=" {
201	    incr count2
202	    pass_or_exp_continue
203	}
204	-i $gdb_spawn_id -re "received signal SIGTTOU.*$gdb_prompt " {
205	    if $expect_ttou {
206		pass "$test (expected SIGTTOU)"
207	    } else {
208		fail "$test (SIGTTOU)"
209	    }
210	}
211    }
212
213    send_gdb "\003"
214    if {$expect_ttou} {
215	gdb_test "" "Quit" "stop with control-c"
216    } else {
217	gdb_test "" "received signal SIGINT.*" "stop with control-c"
218    }
219
220    # Useful for debugging in case the Ctrl-C above fails.
221    gdb_test "info inferiors"
222    gdb_test "info threads"
223}
224
225set how_modes {"run" "attach" "tty"}
226
227foreach_with_prefix inf1_how $how_modes {
228    foreach_with_prefix inf2_how $how_modes {
229	if {($inf1_how == "tty" || $inf2_how == "tty")
230	    && [target_info gdb_protocol] == "extended-remote"} {
231	    # No way to specify the inferior's tty in the remote
232	    # protocol.
233	    unsupported "no support for \"tty\" in the RSP"
234	    continue
235	}
236
237	coretest $inf1_how $inf2_how
238    }
239}
240
241kill_wait_spawned_process $attach_spawn_id1
242kill_wait_spawned_process $attach_spawn_id2
243