| 1 | # Copyright 2017-2020 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 | set ws "\[ \t\]+" |
| 141 | global decimal |
| 142 | |
| 143 | # Test "info connections" and "info inferior"'s "Connection" |
| 144 | # column, while at it. |
| 145 | |
| 146 | gdb_test "info connections" \ |
| 147 | [multi_line \ |
| 148 | "Num${ws}What${ws}Description${ws}" \ |
| 149 | " 1${ws}native${ws}Native process${ws}" \ |
| 150 | " 2${ws}extended-remote localhost:$decimal${ws}Extended remote serial target in gdb-specific protocol${ws}" \ |
| 151 | " 3${ws}core${ws}Local core dump file${ws}" \ |
| 152 | " 4${ws}extended-remote localhost:$decimal${ws}Extended remote serial target in gdb-specific protocol${ws}" \ |
| 153 | "\\* 5${ws}core${ws}Local core dump file${ws}" \ |
| 154 | ] |
| 155 | |
| 156 | gdb_test "info inferiors" \ |
| 157 | [multi_line \ |
| 158 | "Num${ws}Description${ws}Connection${ws}Executable${ws}" \ |
| 159 | " 1${ws}process ${decimal}${ws}1 \\(native\\)${ws}${binfile}${ws}" \ |
| 160 | " 2${ws}process ${decimal}${ws}2 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \ |
| 161 | " 3${ws}process ${decimal}${ws}3 \\(core\\)${ws}${binfile}${ws}" \ |
| 162 | " 4${ws}process ${decimal}${ws}1 \\(native\\)${ws}${binfile}${ws}" \ |
| 163 | " 5${ws}process ${decimal}${ws}4 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \ |
| 164 | "\\* 6${ws}process ${decimal}${ws}5 \\(core\\)${ws}${binfile}${ws}" \ |
| 165 | ] |
| 166 | |
| 167 | # For debugging. |
| 168 | gdb_test "info threads" ".*" |
| 169 | |
| 170 | # Make "continue" resume all inferiors. |
| 171 | if {${non-stop} == "off"} { |
| 172 | gdb_test_no_output "set schedule-multiple on" |
| 173 | } |
| 174 | |
| 175 | return 1 |
| 176 | } |
| 177 | |
| 178 | # Test "continue" to breakpoints in different targets. In non-stop |
| 179 | # mode, also tests "interrupt -a". |
| 180 | proc test_continue {non-stop} { |
| 181 | if {![setup ${non-stop}]} { |
| 182 | untested "setup failed" |
| 183 | return |
| 184 | } |
| 185 | |
| 186 | proc set_break {inf} { |
| 187 | gdb_test "break function${inf} thread ${inf}.1" \ |
| 188 | "Breakpoint .* function${inf}\\..*" |
| 189 | } |
| 190 | |
| 191 | # Select inferior INF, and then run to a breakpoint on inferior |
| 192 | # INF+1. |
| 193 | proc test_continue_inf {inf} { |
| 194 | upvar 1 non-stop non-stop |
| 195 | |
| 196 | global gdb_prompt |
| 197 | delete_breakpoints |
| 198 | |
| 199 | set next_inf [next_live_inferior $inf] |
| 200 | |
| 201 | gdb_test "inferior $inf" "Switching to inferior $inf.*" |
| 202 | set_break $next_inf |
| 203 | |
| 204 | if {${non-stop} == "off"} { |
| 205 | gdb_test "continue" "hit Breakpoint .* function${next_inf}.*" |
| 206 | } else { |
| 207 | set msg "continue" |
| 208 | gdb_test_multiple "continue -a&" $msg { |
| 209 | -re "Continuing.*$gdb_prompt " { |
| 210 | pass $msg |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | set msg "hit bp" |
| 215 | gdb_test_multiple "" $msg { |
| 216 | -re "hit Breakpoint .* function${next_inf}" { |
| 217 | pass $msg |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | set msg "stop all threads" |
| 222 | gdb_test_multiple "interrupt -a" $msg { |
| 223 | -re "$gdb_prompt " { |
| 224 | for {set i 0} {$i < 7} {incr i} { |
| 225 | set ok 0 |
| 226 | gdb_test_multiple "" $msg { |
| 227 | -re "Thread\[^\r\n\]*stopped\\." { |
| 228 | set ok 1 |
| 229 | } |
| 230 | } |
| 231 | if {!$ok} { |
| 232 | break |
| 233 | } |
| 234 | } |
| 235 | gdb_assert $ok $msg |
| 236 | } |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | for {set i 1} {$i <= 5} {incr i} { |
| 242 | if {$i == 3} { |
| 243 | # This is a core inferior. |
| 244 | continue |
| 245 | } |
| 246 | |
| 247 | with_test_prefix "inf$i" { |
| 248 | test_continue_inf $i |
| 249 | } |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | # Test interrupting multiple targets with Ctrl-C. |
| 254 | |
| 255 | proc test_ctrlc {} { |
| 256 | if {![setup "off"]} { |
| 257 | untested "setup failed" |
| 258 | return |
| 259 | } |
| 260 | |
| 261 | delete_breakpoints |
| 262 | |
| 263 | # Select inferior INF, continue all inferiors, and then Ctrl-C. |
| 264 | proc test_ctrlc_inf {inf} { |
| 265 | global gdb_prompt |
| 266 | |
| 267 | gdb_test "inferior $inf" "Switching to inferior $inf.*" |
| 268 | |
| 269 | set msg "continue" |
| 270 | gdb_test_multiple "continue" $msg { |
| 271 | -re "Continuing" { |
| 272 | pass $msg |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | after 200 { send_gdb "\003" } |
| 277 | |
| 278 | set msg "send_gdb control C" |
| 279 | gdb_test_multiple "" $msg { |
| 280 | -re "received signal SIGINT.*$gdb_prompt $" { |
| 281 | pass $msg |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | set msg "all threads stopped" |
| 286 | gdb_test_multiple "info threads" "$msg" { |
| 287 | -re "\\\(running\\\).*$gdb_prompt $" { |
| 288 | fail $msg |
| 289 | } |
| 290 | -re "$gdb_prompt $" { |
| 291 | pass $msg |
| 292 | } |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | for {set i 1} {$i <= 5} {incr i} { |
| 297 | if {$i == 3} { |
| 298 | # This is a core inferior. |
| 299 | continue |
| 300 | } |
| 301 | |
| 302 | with_test_prefix "inf$i" { |
| 303 | test_ctrlc_inf $i |
| 304 | } |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | # Test "next" bouncing between two breakpoints in two threads running |
| 309 | # in different targets. |
| 310 | proc test_ping_pong_next {} { |
| 311 | global srcfile |
| 312 | |
| 313 | if {![setup "off"]} { |
| 314 | untested "setup failed" |
| 315 | return |
| 316 | } |
| 317 | |
| 318 | # block/unblock inferiors 1 and 2 according to INF1 and INF2. |
| 319 | proc block {inf1 inf2} { |
| 320 | gdb_test "thread apply 1.1 p wait_for_gdb = $inf1" " = $inf1" |
| 321 | gdb_test "thread apply 2.1 p wait_for_gdb = $inf2" " = $inf2" |
| 322 | } |
| 323 | |
| 324 | # We're use inferiors 1 and 2. Make sure they're really connected |
| 325 | # to different targets. |
| 326 | gdb_test "thread apply 1.1 maint print target-stack" \ |
| 327 | "- native.*" |
| 328 | gdb_test "thread apply 2.1 maint print target-stack" \ |
| 329 | "- extended-remote.*" |
| 330 | |
| 331 | # Set two breakpoints, one for each of inferior 1 and 2. Inferior |
| 332 | # 1 is running on the native target, and inferior 2 is running on |
| 333 | # extended-gdbserver. Run to breakpoint 1 to gets things started. |
| 334 | set line1 [gdb_get_line_number "set break 1 here"] |
| 335 | set line2 [gdb_get_line_number "set break 2 here"] |
| 336 | |
| 337 | gdb_test "thread 1.1" "Switching to thread 1.1 .*" |
| 338 | |
| 339 | gdb_test "break $srcfile:$line1 thread 1.1" \ |
| 340 | "Breakpoint .*$srcfile:$line1\\..*" |
| 341 | |
| 342 | gdb_test "continue" "hit Breakpoint .*" |
| 343 | |
| 344 | gdb_test "break $srcfile:$line2 thread 2.1" \ |
| 345 | "Breakpoint .*$srcfile:$line2\\..*" |
| 346 | |
| 347 | # Now block inferior 1 and issue "next". We should stop at the |
| 348 | # breakpoint for inferior 2, given schedlock off. |
| 349 | with_test_prefix "next inf 1" { |
| 350 | block 1 0 |
| 351 | gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*" |
| 352 | } |
| 353 | |
| 354 | # Now unblock inferior 2 and block inferior 1. "next" should run |
| 355 | # into the breakpoint in inferior 1. |
| 356 | with_test_prefix "next inf 2" { |
| 357 | block 0 1 |
| 358 | gdb_test "next" "Thread 1.1 .*hit Breakpoint .*$srcfile:$line1.*" |
| 359 | } |
| 360 | |
| 361 | # Try nexting inferior 1 again. |
| 362 | with_test_prefix "next inf 1 again" { |
| 363 | block 1 0 |
| 364 | gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*" |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | # Make a core file with two threads upfront. Several tests load the |
| 369 | # same core file. |
| 370 | prepare_core |
| 371 | |
| 372 | # Some basic "continue" + breakpoints tests. |
| 373 | with_test_prefix "continue" { |
| 374 | foreach_with_prefix non-stop {"off" "on"} { |
| 375 | test_continue ${non-stop} |
| 376 | } |
| 377 | } |
| 378 | |
| 379 | # Some basic all-stop Ctrl-C tests. |
| 380 | with_test_prefix "interrupt" { |
| 381 | test_ctrlc |
| 382 | } |
| 383 | |
| 384 | # Test ping-ponging between two targets with "next". |
| 385 | with_test_prefix "ping-pong" { |
| 386 | test_ping_pong_next |
| 387 | } |