GNU Binutils with patches for OS216
Révision | cc70f1f4d1e2a61c4d4d69830e00ef872934cf55 (tree) |
---|---|
l'heure | 2020-01-06 23:11:21 |
Auteur | Pedro Alves <palves@redh...> |
Commiter | Pedro Alves |
Add multi-target tests
This adds a testcase exercising multi-target features. It spawns 6
inferiors, like this:
and then tests various details, including:
This testcase caught a _lot_ of bugs in development.
gdb/testsuite/ChangeLog:
yyyy-mm-dd Pedro Alves <palves@redhat.com>
* gdb.multi/multi-target.c: New file.
* gdb.multi/multi-target.exp: New file.
* lib/gdbserver-support.exp (gdb_target_cmd): Handle "Non-stop
mode requested, but remote does not support non-stop".
@@ -0,0 +1,100 @@ | ||
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 | +#include <stdlib.h> | |
19 | +#include <stdio.h> | |
20 | +#include <unistd.h> | |
21 | +#include <limits.h> | |
22 | +#include <string.h> | |
23 | +#include <pthread.h> | |
24 | + | |
25 | +#define NUM_THREADS 1 | |
26 | + | |
27 | +static pthread_barrier_t barrier; | |
28 | + | |
29 | +static void * | |
30 | +thread_start (void *arg) | |
31 | +{ | |
32 | + pthread_barrier_wait (&barrier); | |
33 | + | |
34 | + while (1) | |
35 | + sleep (1); | |
36 | + return NULL; | |
37 | +} | |
38 | + | |
39 | +static void | |
40 | +all_started (void) | |
41 | +{ | |
42 | +} | |
43 | + | |
44 | +int wait_for_gdb; | |
45 | + | |
46 | +static void | |
47 | +function1 (void) | |
48 | +{ | |
49 | + while (wait_for_gdb) | |
50 | + sleep (1); | |
51 | +} | |
52 | + | |
53 | +static void | |
54 | +function2 (void) | |
55 | +{ | |
56 | + while (wait_for_gdb) | |
57 | + sleep (1); | |
58 | +} | |
59 | + | |
60 | +static void | |
61 | +function3 (void) | |
62 | +{ | |
63 | +} | |
64 | + | |
65 | +static void | |
66 | +function4 (void) | |
67 | +{ | |
68 | +} | |
69 | + | |
70 | +static void | |
71 | +function5 (void) | |
72 | +{ | |
73 | +} | |
74 | + | |
75 | +int | |
76 | +main (int argc, char ** argv) | |
77 | +{ | |
78 | + pthread_t thread; | |
79 | + int len; | |
80 | + | |
81 | + alarm (360); | |
82 | + | |
83 | + pthread_barrier_init (&barrier, NULL, NUM_THREADS + 1); | |
84 | + pthread_create (&thread, NULL, thread_start, NULL); | |
85 | + | |
86 | + pthread_barrier_wait (&barrier); | |
87 | + all_started (); | |
88 | + | |
89 | + while (1) | |
90 | + { | |
91 | + function1 (); /* set break 1 here */ | |
92 | + function2 (); /* set break 2 here */ | |
93 | + function3 (); | |
94 | + function4 (); | |
95 | + function5 (); | |
96 | + sleep (1); | |
97 | + } | |
98 | + | |
99 | + return 0; | |
100 | +} |
@@ -0,0 +1,361 @@ | ||
1 | +# Copyright 2017-2019 Free Software Foundation, Inc. | |
2 | + | |
3 | +# This program is free software; you can redistribute it and/or modify | |
4 | +# it under the terms of the GNU General Public License as published by | |
5 | +# the Free Software Foundation; either version 3 of the License, or | |
6 | +# (at your option) any later version. | |
7 | +# | |
8 | +# This program is distributed in the hope that it will be useful, | |
9 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | +# GNU General Public License for more details. | |
12 | +# | |
13 | +# You should have received a copy of the GNU General Public License | |
14 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | + | |
16 | +# Test multi-target features. | |
17 | + | |
18 | +load_lib gdbserver-support.exp | |
19 | + | |
20 | +standard_testfile | |
21 | + | |
22 | +# The plain remote target can't do multiple inferiors. | |
23 | +if {[target_info gdb_protocol] != ""} { | |
24 | + return | |
25 | +} | |
26 | + | |
27 | +if { [prepare_for_testing "failed to prepare" ${binfile} "${srcfile}" \ | |
28 | + {debug pthreads}] } { | |
29 | + return | |
30 | +} | |
31 | + | |
32 | +proc connect_target_extended_remote {binfile} { | |
33 | + set res [gdbserver_start "--multi" ""] | |
34 | + set gdbserver_gdbport [lindex $res 1] | |
35 | + return [gdb_target_cmd "extended-remote" $gdbserver_gdbport] | |
36 | +} | |
37 | + | |
38 | +# Add and start inferior number NUM. Returns true on success, false | |
39 | +# otherwise. | |
40 | +proc add_inferior {num target binfile {gcorefile ""}} { | |
41 | + # Start another inferior. | |
42 | + gdb_test "add-inferior -no-connection" "Added inferior $num" \ | |
43 | + "add empty inferior $num" | |
44 | + gdb_test "inferior $num" "Switching to inferior $num.*" \ | |
45 | + "switch to inferior $num" | |
46 | + gdb_test "file ${binfile}" ".*" "load file in inferior $num" | |
47 | + gdb_test_no_output "set remote exec-file ${binfile}" \ | |
48 | + "set remote-exec file in inferior $num" | |
49 | + | |
50 | + if {$target == "core"} { | |
51 | + gdb_test "core $gcorefile" "Core was generated by.*" \ | |
52 | + "core [file tail $gcorefile], inf $num" | |
53 | + return 1 | |
54 | + } | |
55 | + | |
56 | + if {$target == "extended-remote"} { | |
57 | + if {[connect_target_extended_remote $binfile]} { | |
58 | + return 0 | |
59 | + } | |
60 | + } | |
61 | + if ![runto "all_started"] then { | |
62 | + return 0 | |
63 | + } | |
64 | + delete_breakpoints | |
65 | + | |
66 | + return 1 | |
67 | +} | |
68 | + | |
69 | +proc prepare_core {} { | |
70 | + global gcorefile gcore_created | |
71 | + global binfile | |
72 | + | |
73 | + clean_restart ${binfile} | |
74 | + | |
75 | + if ![runto all_started] then { | |
76 | + return -1 | |
77 | + } | |
78 | + | |
79 | + global testfile | |
80 | + set gcorefile [standard_output_file $testfile.gcore] | |
81 | + set gcore_created [gdb_gcore_cmd $gcorefile "save a core file"] | |
82 | +} | |
83 | + | |
84 | +proc next_live_inferior {inf} { | |
85 | + incr inf | |
86 | + if {$inf == 3} { | |
87 | + # 3 is a core. | |
88 | + return 4 | |
89 | + } | |
90 | + if {$inf > 5} { | |
91 | + # 6 is a core. | |
92 | + return 1 | |
93 | + } | |
94 | + | |
95 | + return $inf | |
96 | +} | |
97 | + | |
98 | +# Return true on success, false otherwise. | |
99 | + | |
100 | +proc setup {non-stop} { | |
101 | + global gcorefile gcore_created | |
102 | + global binfile | |
103 | + | |
104 | + clean_restart ${binfile} | |
105 | + | |
106 | + # multi-target depends on target running in non-stop mode. Force | |
107 | + # it on for remote targets, until this is the default. | |
108 | + gdb_test_no_output "maint set target-non-stop on" | |
109 | + | |
110 | + gdb_test_no_output "set non-stop ${non-stop}" | |
111 | + | |
112 | + if ![runto all_started] then { | |
113 | + return 0 | |
114 | + } | |
115 | + | |
116 | + delete_breakpoints | |
117 | + | |
118 | + # inferior 1 -> native | |
119 | + # inferior 2 -> extended-remote | |
120 | + # inferior 3 -> core | |
121 | + # inferior 4 -> native | |
122 | + # inferior 5 -> extended-remote | |
123 | + # inferior 6 -> core | |
124 | + if {![add_inferior 2 "extended-remote" $binfile]} { | |
125 | + return 0 | |
126 | + } | |
127 | + if {![add_inferior 3 "core" $binfile $gcorefile]} { | |
128 | + return 0 | |
129 | + } | |
130 | + if {![add_inferior 4 "native" $binfile]} { | |
131 | + return 0 | |
132 | + } | |
133 | + if {![add_inferior 5 "extended-remote" $binfile]} { | |
134 | + return 0 | |
135 | + } | |
136 | + if {![add_inferior 6 "core" $binfile $gcorefile]} { | |
137 | + return 0 | |
138 | + } | |
139 | + | |
140 | + # For debugging. | |
141 | + gdb_test "info inferiors" ".*" | |
142 | + gdb_test "info threads" ".*" | |
143 | + | |
144 | + # Make "continue" resume all inferiors. | |
145 | + if {${non-stop} == "off"} { | |
146 | + gdb_test_no_output "set schedule-multiple on" | |
147 | + } | |
148 | + | |
149 | + return 1 | |
150 | +} | |
151 | + | |
152 | +# Test "continue" to breakpoints in different targets. In non-stop | |
153 | +# mode, also tests "interrupt -a". | |
154 | +proc test_continue {non-stop} { | |
155 | + if {![setup ${non-stop}]} { | |
156 | + untested "setup failed" | |
157 | + return | |
158 | + } | |
159 | + | |
160 | + proc set_break {inf} { | |
161 | + gdb_test "break function${inf} thread ${inf}.1" \ | |
162 | + "Breakpoint .* function${inf}\\..*" | |
163 | + } | |
164 | + | |
165 | + # Select inferior INF, and then run to a breakpoint on inferior | |
166 | + # INF+1. | |
167 | + proc test_continue_inf {inf} { | |
168 | + upvar 1 non-stop non-stop | |
169 | + | |
170 | + global gdb_prompt | |
171 | + delete_breakpoints | |
172 | + | |
173 | + set next_inf [next_live_inferior $inf] | |
174 | + | |
175 | + gdb_test "inferior $inf" "Switching to inferior $inf.*" | |
176 | + set_break $next_inf | |
177 | + | |
178 | + if {${non-stop} == "off"} { | |
179 | + gdb_test "continue" "hit Breakpoint .* function${next_inf}.*" | |
180 | + } else { | |
181 | + set msg "continue" | |
182 | + gdb_test_multiple "continue -a&" $msg { | |
183 | + -re "Continuing.*$gdb_prompt " { | |
184 | + pass $msg | |
185 | + } | |
186 | + } | |
187 | + | |
188 | + set msg "hit bp" | |
189 | + gdb_test_multiple "" $msg { | |
190 | + -re "hit Breakpoint .* function${next_inf}" { | |
191 | + pass $msg | |
192 | + } | |
193 | + } | |
194 | + | |
195 | + set msg "stop all threads" | |
196 | + gdb_test_multiple "interrupt -a" $msg { | |
197 | + -re "$gdb_prompt " { | |
198 | + for {set i 0} {$i < 7} {incr i} { | |
199 | + set ok 0 | |
200 | + gdb_test_multiple "" $msg { | |
201 | + -re "Thread\[^\r\n\]*stopped\\." { | |
202 | + set ok 1 | |
203 | + } | |
204 | + } | |
205 | + if {!$ok} { | |
206 | + break | |
207 | + } | |
208 | + } | |
209 | + gdb_assert $ok $msg | |
210 | + } | |
211 | + } | |
212 | + } | |
213 | + } | |
214 | + | |
215 | + for {set i 1} {$i <= 5} {incr i} { | |
216 | + if {$i == 3} { | |
217 | + # This is a core inferior. | |
218 | + continue | |
219 | + } | |
220 | + | |
221 | + with_test_prefix "inf$i" { | |
222 | + test_continue_inf $i | |
223 | + } | |
224 | + } | |
225 | +} | |
226 | + | |
227 | +# Test interrupting multiple targets with Ctrl-C. | |
228 | + | |
229 | +proc test_ctrlc {} { | |
230 | + if {![setup "off"]} { | |
231 | + untested "setup failed" | |
232 | + return | |
233 | + } | |
234 | + | |
235 | + delete_breakpoints | |
236 | + | |
237 | + # Select inferior INF, continue all inferiors, and then Ctrl-C. | |
238 | + proc test_ctrlc_inf {inf} { | |
239 | + global gdb_prompt | |
240 | + | |
241 | + gdb_test "inferior $inf" "Switching to inferior $inf.*" | |
242 | + | |
243 | + set msg "continue" | |
244 | + gdb_test_multiple "continue" $msg { | |
245 | + -re "Continuing" { | |
246 | + pass $msg | |
247 | + } | |
248 | + } | |
249 | + | |
250 | + after 200 { send_gdb "\003" } | |
251 | + | |
252 | + set msg "send_gdb control C" | |
253 | + gdb_test_multiple "" $msg { | |
254 | + -re "received signal SIGINT.*$gdb_prompt $" { | |
255 | + pass $msg | |
256 | + } | |
257 | + } | |
258 | + | |
259 | + set msg "all threads stopped" | |
260 | + gdb_test_multiple "info threads" "$msg" { | |
261 | + -re "\\\(running\\\).*$gdb_prompt $" { | |
262 | + fail $msg | |
263 | + } | |
264 | + -re "$gdb_prompt $" { | |
265 | + pass $msg | |
266 | + } | |
267 | + } | |
268 | + } | |
269 | + | |
270 | + for {set i 1} {$i <= 5} {incr i} { | |
271 | + if {$i == 3} { | |
272 | + # This is a core inferior. | |
273 | + continue | |
274 | + } | |
275 | + | |
276 | + with_test_prefix "inf$i" { | |
277 | + test_ctrlc_inf $i | |
278 | + } | |
279 | + } | |
280 | +} | |
281 | + | |
282 | +# Test "next" bouncing between two breakpoints in two threads running | |
283 | +# in different targets. | |
284 | +proc test_ping_pong_next {} { | |
285 | + global srcfile | |
286 | + | |
287 | + if {![setup "off"]} { | |
288 | + untested "setup failed" | |
289 | + return | |
290 | + } | |
291 | + | |
292 | + # block/unblock inferiors 1 and 2 according to INF1 and INF2. | |
293 | + proc block {inf1 inf2} { | |
294 | + gdb_test "thread apply 1.1 p wait_for_gdb = $inf1" " = $inf1" | |
295 | + gdb_test "thread apply 2.1 p wait_for_gdb = $inf2" " = $inf2" | |
296 | + } | |
297 | + | |
298 | + # We're use inferiors 1 and 2. Make sure they're really connected | |
299 | + # to different targets. | |
300 | + gdb_test "thread apply 1.1 maint print target-stack" \ | |
301 | + "- native.*" | |
302 | + gdb_test "thread apply 2.1 maint print target-stack" \ | |
303 | + "- extended-remote.*" | |
304 | + | |
305 | + # Set two breakpoints, one for each of inferior 1 and 2. Inferior | |
306 | + # 1 is running on the native target, and inferior 2 is running on | |
307 | + # extended-gdbserver. Run to breakpoint 1 to gets things started. | |
308 | + set line1 [gdb_get_line_number "set break 1 here"] | |
309 | + set line2 [gdb_get_line_number "set break 2 here"] | |
310 | + | |
311 | + gdb_test "thread 1.1" "Switching to thread 1.1 .*" | |
312 | + | |
313 | + gdb_test "break $srcfile:$line1 thread 1.1" \ | |
314 | + "Breakpoint .*$srcfile:$line1\\..*" | |
315 | + | |
316 | + gdb_test "continue" "hit Breakpoint .*" | |
317 | + | |
318 | + gdb_test "break $srcfile:$line2 thread 2.1" \ | |
319 | + "Breakpoint .*$srcfile:$line2\\..*" | |
320 | + | |
321 | + # Now block inferior 1 and issue "next". We should stop at the | |
322 | + # breakpoint for inferior 2, given schedlock off. | |
323 | + with_test_prefix "next inf 1" { | |
324 | + block 1 0 | |
325 | + gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*" | |
326 | + } | |
327 | + | |
328 | + # Now unblock inferior 2 and block inferior 1. "next" should run | |
329 | + # into the breakpoint in inferior 1. | |
330 | + with_test_prefix "next inf 2" { | |
331 | + block 0 1 | |
332 | + gdb_test "next" "Thread 1.1 .*hit Breakpoint .*$srcfile:$line1.*" | |
333 | + } | |
334 | + | |
335 | + # Try nexting inferior 1 again. | |
336 | + with_test_prefix "next inf 1 again" { | |
337 | + block 1 0 | |
338 | + gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*" | |
339 | + } | |
340 | +} | |
341 | + | |
342 | +# Make a core file with two threads upfront. Several tests load the | |
343 | +# same core file. | |
344 | +prepare_core | |
345 | + | |
346 | +# Some basic "continue" + breakpoints tests. | |
347 | +with_test_prefix "continue" { | |
348 | + foreach_with_prefix non-stop {"off" "on"} { | |
349 | + test_continue ${non-stop} | |
350 | + } | |
351 | +} | |
352 | + | |
353 | +# Some basic all-stop Ctrl-C tests. | |
354 | +with_test_prefix "interrupt" { | |
355 | + test_ctrlc | |
356 | +} | |
357 | + | |
358 | +# Test ping-ponging between two targets with "next". | |
359 | +with_test_prefix "ping-pong" { | |
360 | + test_ping_pong_next | |
361 | +} |
@@ -64,6 +64,10 @@ proc gdb_target_cmd_ext { targetname serialport {additional_text ""} } { | ||
64 | 64 | -re "Couldn't establish connection to remote.*$gdb_prompt $" { |
65 | 65 | verbose "Connection failed" |
66 | 66 | } |
67 | + -re "Non-stop mode requested, but remote does not support non-stop.*$gdb_prompt $" { | |
68 | + verbose "remote does not support non-stop" | |
69 | + return 1 | |
70 | + } | |
67 | 71 | -re "Remote MIPS debugging.*$additional_text.*$gdb_prompt" { |
68 | 72 | verbose "Set target to $targetname" |
69 | 73 | return 0 |