]>
Commit | Line | Data |
---|---|---|
e671cd59 PA |
1 | # This testcase is part of GDB, the GNU debugger. |
2 | ||
b811d2c2 | 3 | # Copyright 2017-2020 Free Software Foundation, Inc. |
e671cd59 PA |
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 | ||
26 | standard_testfile | |
27 | ||
28 | if ![can_spawn_for_attach] { | |
29 | return 0 | |
30 | } | |
31 | ||
32 | if [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 | ||
42 | set spawn_id_list [spawn_wait_for_attach [list $binfile $binfile]] | |
43 | set attach_spawn_id1 [lindex $spawn_id_list 0] | |
44 | set attach_spawn_id2 [lindex $spawn_id_list 1] | |
45 | set attach_pid1 [spawn_id_get_pid $attach_spawn_id1] | |
46 | set 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. | |
54 | proc 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 | ||
109 | proc 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 | ||
120 | proc 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} { | |
395fad09 | 215 | gdb_test "" "Quit" "stop with control-c (Quit)" |
e671cd59 | 216 | } else { |
395fad09 | 217 | gdb_test "" "received signal SIGINT.*" "stop with control-c (SIGINT)" |
e671cd59 PA |
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 | ||
225 | set how_modes {"run" "attach" "tty"} | |
226 | ||
227 | foreach_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 | ||
241 | kill_wait_spawned_process $attach_spawn_id1 | |
242 | kill_wait_spawned_process $attach_spawn_id2 |