1 # Copyright 2016-2024 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 # This test checks that the "thread", "select-frame", "frame" and "inferior" 17 # CLI commands, as well as the "-thread-select" and "-stack-select-frame" MI 18 # commands send the appropriate user-selection-change events to all UIs. 19 # 20 # This test considers the case where console and MI are two different UIs, 21 # and MI is created with the new-ui command. 22 # 23 # It also considers the case where the console commands are sent directly in 24 # the MI channel as described in PR 20487. 25 # 26 # It does so by starting 2 inferiors with 3 threads each. 27 # - Thread 1 of each inferior is the main thread, starting the others. 28 # - Thread 2 of each inferior is stopped at /* thread loop line */. 29 # - Thread 3 of each inferior is either stopped at /* thread loop line */, if we 30 # are using all-stop, or running, if we are using non-stop. 31 32 # Do not run if gdb debug is enabled as it doesn't work for separate-mi-tty. 33 require !gdb_debug_enabled 34 35 load_lib mi-support.exp 36 37 standard_testfile 38 39 # Multiple inferiors are needed, therefore only native gdb and extended 40 # gdbserver modes are supported. 41 require !use_gdb_stub 42 43 set compile_options "debug pthreads" 44 if {[build_executable $testfile.exp $testfile ${srcfile} ${compile_options}] == -1} { 45 untested "failed to compile" 46 return -1 47 } 48 49 set main_break_line [gdb_get_line_number "main break line"] 50 set thread_loop_line [gdb_get_line_number "thread loop line"] 51 set thread_caller_line [gdb_get_line_number "thread caller line"] 52 53 # Return whether we expect thread THREAD to be running in mode MODE. 54 # 55 # MODE can be either "all-stop" or "non-stop". 56 # THREAD can be either a CLI thread id (e.g. 2.3) or an MI thread id (e.g. 6). 57 58 proc thread_is_running { mode thread } { 59 if { $mode != "non-stop" } { 60 return 0 61 } 62 63 return [expr { 64 $thread == 1.3 65 || $thread == 2.3 66 || $thread == 3 67 || $thread == 6 68 }] 69 } 70 71 # Make a regular expression to match the various inferior/thread/frame selection 72 # events for CLI. 73 # 74 # MODE can be either "all-stop" or "non-stop", indicating which one is currently 75 # in use. 76 # INF is the inferior number we are expecting GDB to switch to, or -1 if we are 77 # not expecting GDB to announce an inferior switch. 78 # THREAD is the thread number we are expecting GDB to switch to, or -1 if we are 79 # not expecting GDB to announce a thread switch. 80 # FRAME is the frame number we are expecting GDB to switch to, or -1 if we are 81 # not expecting GDB to announce a frame switch. See the FRAME_RE variable for 82 # details. 83 84 proc make_cli_re { mode inf thread frame } { 85 global srcfile 86 global thread_caller_line 87 global thread_loop_line 88 global main_break_line 89 global decimal 90 91 set any "\[^\r\n\]*" 92 93 set cli_re "" 94 95 set inf_re "\\\[Switching to inferior $inf${any}\\\]" 96 set all_stop_thread_re "\\\[Switching to thread [string_to_regexp $thread]${any}\\\]" 97 98 set frame_re(0) "#0${any}child_sub_function$any$srcfile:$thread_loop_line\r\n${any}thread loop line \\\*/" 99 set frame_re(1) "#1${any}child_function \\\(args=0x0\\\) at ${any}$srcfile:$thread_caller_line\r\n$thread_caller_line${any}/\\\* thread caller line \\\*/" 100 101 # Special frame for main thread. 102 set frame_re(2) "#0${any}\r\n${main_break_line}${any}" 103 104 if { $inf != -1 } { 105 append cli_re $inf_re 106 } 107 108 if { $thread != -1 } { 109 if { $inf != -1 } { 110 append cli_re "\r\n" 111 } 112 set thread_re $all_stop_thread_re 113 114 if [thread_is_running $mode $thread] { 115 set thread_re "$thread_re\\\(running\\\)" 116 } 117 118 append cli_re $thread_re 119 } 120 121 if { $frame != -1 } { 122 if { $thread != -1 } { 123 append cli_re "\r\n" 124 } 125 append cli_re $frame_re($frame) 126 } 127 128 return $cli_re 129 } 130 131 # Make a regular expression to match the various inferior/thread/frame selection 132 # events for MI. 133 # 134 # MODE can be either "all-stop" or "non-stop", indicating which one is currently 135 # in use. 136 # THREAD is the thread number we are expecting GDB to switch to, or -1 if we are 137 # not expecting GDB to announce a thread switch. 138 # If EVENT is 1, build a regex for an "=thread-selected" async event. 139 # Otherwise, build a regex for a response to a command. 140 # FRAME is the frame number we are expecting GDB to switch to, or -1 if we are 141 # not expecting GDB to announce a frame switch. See the FRAME_RE variable for 142 # details. 143 144 proc make_mi_re { mode thread frame type } { 145 global srcfile 146 global hex 147 global decimal 148 global thread_loop_line 149 global main_break_line 150 global thread_caller_line 151 152 set any "\[^\r\n\]*" 153 154 set mi_re "" 155 156 set thread_event_re "=thread-selected,id=\"$thread\"" 157 set thread_answer_re "\\^done,new-thread-id=\"$thread\"" 158 159 set frame_re(0) ",frame=\{level=\"0\",addr=\"$hex\",func=\"child_sub_function\",args=\\\[\\\],file=\"${any}${srcfile}\",fullname=\"${any}${srcfile}\",line=\"$thread_loop_line\",arch=\"$any\"\}" 160 set frame_re(1) ",frame=\{level=\"1\",addr=\"$hex\",func=\"child_function\",args=\\\[\{name=\"args\",value=\"0x0\"\}\\\],file=\"${any}${srcfile}\",fullname=\"${any}${srcfile}\",line=\"$thread_caller_line\",arch=\"$any\"\}" 161 162 # Special frame for main thread. 163 set frame_re(2) ",frame=\{level=\"0\",addr=\"$hex\",func=\"main\",args=\\\[\\\],file=\"${any}${srcfile}\",fullname=\"${any}${srcfile}\",line=\"${main_break_line}\",arch=\"$any\"\}" 164 165 if { $thread != -1 } { 166 if { $type == "event" } { 167 append mi_re $thread_event_re 168 } elseif { $type == "response" } { 169 append mi_re $thread_answer_re 170 } else { 171 error "Invalid value for EVENT." 172 } 173 } 174 175 if { $frame != -1 } { 176 append mi_re $frame_re($frame) 177 } 178 179 if { $type == "event" } { 180 append mi_re "\r\n" 181 } 182 183 return $mi_re 184 } 185 186 # Make a regular expression to match the various inferior/thread/frame selection 187 # events when issuing CLI commands inside MI. 188 # 189 # COMMAND is the CLI command that was sent to GDB, which will be output in the 190 # console output stream. 191 # CLI_IN_MI_MODE indicates which method of CLI-in-MI command is used. It can be 192 # either "direct" of "interpreter-exec". 193 # MODE can be either "all-stop" or "non-stop", indicating which one is currently 194 # in use. 195 # If EVENT is 1, expect a =thread-select MI event. 196 # INF is the inferior number we are expecting GDB to switch to, or -1 if we are 197 # not expecting GDB to announce an inferior switch. 198 # CLI_THREAD is the thread number as seen in the CLI (inferior-qualified) we are 199 # expecting GDB to switch to, or -1 if we are not expecting GDB to announce a 200 # thread switch. 201 # MI_THREAD is the thread number as seen in the MI (global number) we are 202 # expecting GDB to switch to, or -1 if we are not expecting GDB to announce a 203 # thread switch. 204 # FRAME is the frame number we are expecting GDB to switch to, or -1 if we are 205 # not expecting GDB to announce a frame switch. See the FRAME_RE variable for 206 # details. 207 208 proc make_cli_in_mi_re { command cli_in_mi_mode mode event inf cli_thread 209 mi_thread frame } { 210 global srcfile 211 global thread_loop_line 212 global main_break_line 213 global thread_caller_line 214 215 set any "\[^\r\n\]*" 216 217 set command_re [string_to_regexp $command] 218 set cli_in_mi_re "$command_re\r\n" 219 220 if { $cli_in_mi_mode == "direct" } { 221 append cli_in_mi_re "&\"$command_re\\\\n\"\r\n" 222 } 223 224 set frame_re(0) "~\"#0${any}child_sub_function${any}$srcfile:$thread_loop_line\\\\n\"\r\n~\"${thread_loop_line}${any}thread loop line \\\*/\\\\n\"\r\n" 225 set frame_re(1) "~\"#1${any}child_function \\\(args=0x0\\\) at ${any}$srcfile:$thread_caller_line\\\\n\"\r\n~\"$thread_caller_line${any}thread caller line \\\*/\\\\n\"\r\n" 226 227 # Special frame for main thread. 228 set frame_re(2) "~\"#0${any}main${any}\\\\n\"\r\n~\"${main_break_line}${any}\"\r\n" 229 230 if { $inf != -1 } { 231 append cli_in_mi_re "~\"" 232 append cli_in_mi_re [make_cli_re $mode $inf -1 -1] 233 append cli_in_mi_re "\\\\n\"\r\n" 234 } 235 236 if { $cli_thread != "-1" } { 237 append cli_in_mi_re "~\"" 238 append cli_in_mi_re [make_cli_re $mode -1 $cli_thread -1] 239 append cli_in_mi_re "\\\\n\"\r\n" 240 } 241 242 if { $frame != -1 } { 243 append cli_in_mi_re $frame_re($frame) 244 } 245 246 if { $event == 1 } { 247 append cli_in_mi_re [make_mi_re $mode $mi_thread $frame event] 248 } 249 250 append cli_in_mi_re "\\^done" 251 252 return $cli_in_mi_re 253 } 254 255 # Return the current value of the "scheduler-locking" parameter. 256 257 proc show_scheduler_locking { } { 258 global gdb_prompt 259 global expect_out 260 261 set any "\[^\r\n\]*" 262 263 set test "show scheduler-locking" 264 gdb_test_multiple $test $test { 265 -re ".*Mode for locking scheduler during execution is \"(${any})\".\r\n$gdb_prompt " { 266 pass $test 267 return $expect_out(1,string) 268 } 269 } 270 271 error "Couldn't get current scheduler-locking value." 272 } 273 274 # Prepare inferior INF so it is in the state we expect (see comment at the top). 275 276 proc test_continue_to_start { mode inf } { 277 global gdb_spawn_id 278 global mi_spawn_id 279 global gdb_main_spawn_id 280 global srcfile 281 global main_break_line 282 global thread_loop_line 283 global decimal 284 global gdb_prompt 285 286 set any "\[^\r\n\]*" 287 288 if { $gdb_spawn_id != $gdb_main_spawn_id } { 289 error "This should not happen." 290 } 291 292 with_test_prefix "inferior $inf" { 293 with_spawn_id $gdb_main_spawn_id { 294 # Continue to the point where we know for sure the threads are 295 # started. 296 gdb_test "tbreak $srcfile:$main_break_line" \ 297 "Temporary breakpoint ${any}" \ 298 "set breakpoint in main" 299 300 gdb_continue_to_breakpoint "main breakpoint" 301 302 # Consume MI event output. 303 with_spawn_id $mi_spawn_id { 304 if { $inf == 1 } { 305 mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \ 306 "$decimal" {"" "disp=\"del\""} "stop at breakpoint in main" 307 } else { 308 mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" \ 309 "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} "stop at breakpoint in main" 310 } 311 } 312 313 if { $mode == "all-stop" } { 314 set previous_schedlock_val [show_scheduler_locking] 315 316 # Set scheduler-locking on, so that we can control threads 317 # independently. 318 gdb_test_no_output "set scheduler-locking on" 319 320 # Continue each child thread to the point we want them to be. 321 foreach thread { 2 3 } { 322 gdb_test "thread $inf.$thread" ".*" "select child thread $inf.$thread" 323 324 gdb_test "tbreak $srcfile:$thread_loop_line" \ 325 "Temporary breakpoint ${any}" \ 326 "set breakpoint for thread $inf.$thread" 327 328 gdb_continue_to_breakpoint "continue thread $inf.$thread to infinite loop breakpoint" 329 330 # Consume MI output. 331 with_spawn_id $mi_spawn_id { 332 if { $inf == 1} { 333 mi_expect_stop "breakpoint-hit" "child_sub_function" \ 334 "" "$srcfile" "$decimal" {"" "disp=\"del\""} \ 335 "thread $inf.$thread stops MI" 336 } else { 337 mi_expect_stop "breakpoint-hit" "child_sub_function" \ 338 "" "$srcfile" "$decimal" {"" "disp=\"del\"" "locno=\"[0-9]+\""} \ 339 "thread $inf.$thread stops MI" 340 } 341 } 342 } 343 344 # Restore scheduler-locking to its original value. 345 gdb_test_no_output "set scheduler-locking $previous_schedlock_val" 346 } else { # $mode == "non-stop" 347 # Put a thread-specific breakpoint for thread 2 of the current 348 # inferior. We don't put a breakpoint for thread 3, since we 349 # want to let it run. 350 set test "set thread-specific breakpoint, thread $inf.2" 351 gdb_test_multiple "tbreak $srcfile:$thread_loop_line thread $inf.2" $test { 352 -re "Temporary breakpoint ${any}\r\n$gdb_prompt " { 353 pass $test 354 } 355 } 356 357 # Confirm the stop of thread $inf.2. 358 set test "thread $inf.2 stops CLI" 359 gdb_test_multiple "" $test { 360 -re "Thread $inf.2 ${any} hit Temporary breakpoint ${any}\r\n$thread_loop_line${any}\r\n" { 361 pass $test 362 } 363 } 364 365 # Consume MI output. 366 with_spawn_id $mi_spawn_id { 367 mi_expect_stop "breakpoint-hit" "child_sub_function" \ 368 "" "$srcfile" "$decimal" {"" "disp=\"del\""} \ 369 "thread $inf.2 stops MI" 370 } 371 } 372 } 373 } 374 } 375 376 # Prepare the test environment. 377 # 378 # MODE can be either "all-stop" or "non-stop". 379 380 proc_with_prefix test_setup { mode } { 381 global srcfile 382 global srcdir 383 global subdir 384 global gdb_main_spawn_id 385 global mi_spawn_id 386 global decimal 387 global binfile 388 global GDBFLAGS 389 global async 390 391 set any "\[^\r\n\]*" 392 393 save_vars { GDBFLAGS } { 394 if { $mode == "non-stop" } { 395 set GDBFLAGS [concat $GDBFLAGS " -ex \"set non-stop 1\""] 396 } 397 398 if { [mi_clean_restart $binfile "separate-mi-tty"] != 0 } { 399 return -1 400 } 401 } 402 403 if { [mi_runto_main] < 0 } { 404 return -1 405 } 406 407 # When using mi_expect_stop, we don't expect a prompt after the *stopped 408 # event, since the blocking commands are done from the CLI. Setting async 409 # to 1 makes it not expect the prompt. 410 set async 1 411 412 with_spawn_id $gdb_main_spawn_id { 413 # Add the second inferior now. While this is not mandatory, it allows 414 # us to assume that per-inferior thread numbering will be used, 415 # simplifying test_continue_to_start a bit (Thread 1.2 and not Thread 2). 416 gdb_test "add-inferior" "Added inferior 2 on connection .*" "add inferior 2" 417 418 # Prepare the first inferior for the test. 419 test_continue_to_start $mode 1 420 421 # Switch to and start the second inferior. 422 gdb_test "inferior 2" "\\\[Switching to inferior 2${any}\\\]" "switch to inferior 2" 423 gdb_load ${binfile} 424 425 # Doing "start" on the CLI generates a ton of MI output. At some point, 426 # if we don't consume/match it, the buffer between GDB's MI channel and 427 # Expect will get full, GDB will block on a write system call and we'll 428 # deadlock, waiting for CLI output that will never arrive. And then 429 # we're sad. So instead of using gdb_test and expect CLI output, send 430 # the start command first, then consume MI output, and finally consume 431 # CLI output. 432 send_gdb "start\n" 433 434 with_spawn_id $mi_spawn_id { 435 mi_expect_stop "breakpoint-hit" "main" "" "$srcfile" "$decimal" \ 436 {"" "disp=\"del\""} "main stop" 437 } 438 439 # Consume CLI output. 440 gdb_test "" "Temporary breakpoint.*Starting program.*" 441 442 # Prepare the second inferior for the test. 443 test_continue_to_start $mode 2 444 } 445 446 return 0 447 } 448 449 # Reset the selection to frame #0 of thread THREAD. 450 451 proc reset_selection { thread } { 452 global gdb_main_spawn_id 453 454 set any "\[^\r\n\]*" 455 456 with_spawn_id $gdb_main_spawn_id { 457 gdb_test "thread $thread" \ 458 "\\\[Switching to thread $thread ${any}\\\].*" \ 459 "reset selection to thread $thread" 460 gdb_test "frame 0" ".*" "reset selection to frame 0" 461 } 462 } 463 464 # Flush Expect's internal buffers for both CLI and MI. 465 # 466 # The idea here is to send a command, and to consume all the characters that we 467 # expect that command to output, including the following prompt. Using gdb_test 468 # and mi_gdb_test should do that. 469 470 proc flush_buffers { } { 471 global gdb_main_spawn_id mi_spawn_id 472 473 with_spawn_id $gdb_main_spawn_id { 474 gdb_test "print 444" "= 444" "flush CLI" 475 } 476 477 with_spawn_id $mi_spawn_id { 478 mi_gdb_test "555-data-evaluate-expression 666" ".*done,value=\"666\"" "flush MI" 479 } 480 } 481 482 # Run a command on the current spawn id, to confirm that no output is pending 483 # in Expect's internal buffer. This is used to ensure that nothing was output 484 # on the spawn id since the call to gdb_test/mi_gdb_test/flush_buffers. 485 # 486 # The key here is that the regexes use start-of-buffer anchors (^), ensuring 487 # that they match the entire buffer, confirming that there was nothing in it 488 # before. 489 490 proc ensure_no_output { test } { 491 global gdb_spawn_id gdb_main_spawn_id mi_spawn_id 492 global decimal 493 494 if { $gdb_spawn_id == $gdb_main_spawn_id } { 495 # CLI 496 gdb_test "print 666" \ 497 "^\\\$$decimal = 666" \ 498 "$test, ensure no output CLI" 499 } elseif { $gdb_spawn_id == $mi_spawn_id } { 500 # MI 501 mi_gdb_test "777-data-evaluate-expression 888" \ 502 "^777-data-evaluate-expression 888\r\n777\\^done,value=\"888\"" \ 503 "$test, ensure no output MI" 504 } else { 505 error "Unexpected gdb_spawn_id value." 506 } 507 } 508 509 # Match a regular expression, or ensure that there was no output. 510 # 511 # If RE is non-empty, try to match the content of the program output (using the 512 # current spawn_id) and pass/fail TEST accordingly. 513 # If RE is empty, ensure that the program did not output anything. 514 515 proc match_re_or_ensure_no_output { re test } { 516 if { $re != "" } { 517 gdb_expect { 518 -re "$re" { 519 pass $test 520 } 521 522 default { 523 fail $test 524 } 525 } 526 } else { 527 ensure_no_output $test 528 } 529 } 530 531 # Test selecting an inferior from CLI. 532 533 proc_with_prefix test_cli_inferior { mode } { 534 global gdb_main_spawn_id mi_spawn_id 535 536 reset_selection "1.1" 537 538 set mi_re [make_mi_re $mode 4 2 event] 539 set cli_re [make_cli_re $mode 2 2.1 2] 540 541 flush_buffers 542 543 # Do the 'inferior' command. 544 with_spawn_id $gdb_main_spawn_id { 545 gdb_test "inferior 2" $cli_re "CLI select inferior" 546 } 547 548 with_spawn_id $mi_spawn_id { 549 match_re_or_ensure_no_output $mi_re "event on MI" 550 } 551 552 # Do the 'inferior' command on the currently selected inferior. For now, 553 # GDB naively re-outputs everything. 554 with_spawn_id $gdb_main_spawn_id { 555 gdb_test "inferior 2" $cli_re "CLI select inferior again" 556 } 557 558 with_spawn_id $mi_spawn_id { 559 match_re_or_ensure_no_output $mi_re "event on MI again" 560 } 561 } 562 563 # Test thread selection from CLI. 564 565 proc_with_prefix test_cli_thread { mode } { 566 global gdb_main_spawn_id 567 global mi_spawn_id 568 569 set any "\[^\r\n\]*" 570 571 reset_selection "1.1" 572 flush_buffers 573 574 with_test_prefix "thread 1.2" { 575 # Do the 'thread' command to select a stopped thread. 576 577 set mi_re [make_mi_re $mode 2 0 event] 578 set cli_re [make_cli_re $mode -1 1.2 0] 579 580 with_spawn_id $gdb_main_spawn_id { 581 gdb_test "thread 1.2" $cli_re "select thread" 582 } 583 584 with_spawn_id $mi_spawn_id { 585 match_re_or_ensure_no_output $mi_re "select thread, event on MI " 586 } 587 588 # Do the 'thread' command to select the same thread. We shouldn't receive 589 # an event on MI, since we won't actually switch thread. 590 591 set mi_re "" 592 593 with_spawn_id $gdb_main_spawn_id { 594 gdb_test "thread 1.2" $cli_re "select thread again" 595 } 596 597 with_spawn_id $mi_spawn_id { 598 match_re_or_ensure_no_output $mi_re "select thread, event on MI again" 599 } 600 601 # Try the 'thread' command without arguments. 602 603 set cli_re "\\\[Current thread is 1\\.2.*\\\]" 604 set mi_re "" 605 606 with_spawn_id $gdb_main_spawn_id { 607 gdb_test "thread" $cli_re "thread without args" 608 } 609 610 with_spawn_id $mi_spawn_id { 611 match_re_or_ensure_no_output $mi_re "thread without args, event on MI" 612 } 613 } 614 615 with_test_prefix "thread 1.3" { 616 # Do the 'thread' command to select the third thread, stopped on all-stop, 617 # running on non-stop. 618 619 if { $mode == "all-stop" } { 620 set cli_re [make_cli_re $mode -1 1.3 0] 621 set mi_re [make_mi_re $mode 3 0 event] 622 } else { 623 set cli_re [make_cli_re $mode -1 1.3 -1] 624 set mi_re [make_mi_re $mode 3 -1 event] 625 } 626 627 with_spawn_id $gdb_main_spawn_id { 628 gdb_test "thread 1.3" $cli_re "select thread" 629 } 630 631 with_spawn_id $mi_spawn_id { 632 match_re_or_ensure_no_output $mi_re "select thread, event on MI" 633 } 634 635 # Do the 'thread' command to select the third thread again. Again, we 636 # shouldn't receive an event on MI. 637 638 set mi_re "" 639 640 with_spawn_id $gdb_main_spawn_id { 641 gdb_test "thread 1.3" $cli_re "select thread again" 642 } 643 644 with_spawn_id $mi_spawn_id { 645 match_re_or_ensure_no_output $mi_re "select thread again, event on MI" 646 } 647 648 # Try the 'thread' command without arguments. 649 650 set cli_re "\\\[Current thread is 1\\.3 ${any}\\\]" 651 set mi_re "" 652 653 with_spawn_id $gdb_main_spawn_id { 654 gdb_test "thread" $cli_re "thread without args" 655 } 656 657 with_spawn_id $mi_spawn_id { 658 match_re_or_ensure_no_output $mi_re "thread without args, event on MI" 659 } 660 } 661 662 # Idea for the future: selecting a thread in a different inferior. For now, 663 # GDB doesn't show an inferior switch, but if it did, it would be a nice 664 # place to test it. 665 } 666 667 # Test frame selection from CLI. 668 669 proc_with_prefix test_cli_frame { mode } { 670 global gdb_main_spawn_id mi_spawn_id 671 672 with_test_prefix "thread 1.2" { 673 reset_selection "1.2" 674 flush_buffers 675 676 # Do the 'frame' command to select frame 1. 677 678 set mi_re [make_mi_re $mode 2 1 event] 679 set cli_re [make_cli_re $mode -1 -1 1] 680 681 with_spawn_id $gdb_main_spawn_id { 682 gdb_test "frame 1" $cli_re "select frame 1" 683 } 684 685 with_spawn_id $mi_spawn_id { 686 match_re_or_ensure_no_output $mi_re "select frame 1, event on MI" 687 } 688 689 # Do the 'frame' command to select the same frame. This time we don't 690 # expect an event on MI, since we won't actually change frame. 691 692 set mi_re "" 693 694 with_spawn_id $gdb_main_spawn_id { 695 gdb_test "frame 1" $cli_re "select frame 1 again" 696 } 697 698 with_spawn_id $mi_spawn_id { 699 match_re_or_ensure_no_output $mi_re "select frame 1 again, event on MI" 700 } 701 702 # Do the 'frame' command without arguments. We shouldn't see anything on MI. 703 704 with_spawn_id $gdb_main_spawn_id { 705 gdb_test "frame" $cli_re "frame without args" 706 } 707 708 with_spawn_id $mi_spawn_id { 709 match_re_or_ensure_no_output $mi_re "frame without args, event on MI" 710 } 711 } 712 713 with_test_prefix "thread 1.3" { 714 # Now, try the 'frame' command on thread 3, which is running if we are in 715 # non-stop mode. 716 reset_selection "1.3" 717 flush_buffers 718 719 if {$mode == "all-stop"} { 720 set mi_re [make_mi_re $mode 3 1 event] 721 set cli_re [make_cli_re $mode -1 -1 1] 722 } elseif {$mode == "non-stop"} { 723 set mi_re "" 724 set cli_re "Selected thread is running\\." 725 } 726 727 with_spawn_id $gdb_main_spawn_id { 728 gdb_test "frame 1" $cli_re "select frame 1" 729 } 730 731 with_spawn_id $mi_spawn_id { 732 match_re_or_ensure_no_output $mi_re "select frame 1, event on MI" 733 } 734 735 # Do the 'frame' command without arguments. 736 737 if { $mode == "non-stop" } { 738 set cli_re "No stack\\." 739 } 740 set mi_re "" 741 742 with_spawn_id $gdb_main_spawn_id { 743 gdb_test "frame" $cli_re "frame without args" 744 } 745 746 with_spawn_id $mi_spawn_id { 747 match_re_or_ensure_no_output $mi_re "frame without args, event on MI" 748 } 749 } 750 } 751 752 # Test frame selection from CLI with the select-frame command. 753 754 proc_with_prefix test_cli_select_frame { mode } { 755 global gdb_main_spawn_id mi_spawn_id expect_out 756 757 with_test_prefix "thread 1.2" { 758 reset_selection "1.2" 759 flush_buffers 760 761 # Do the 'select-frame' command to select frame 1. 762 763 set mi_re [make_mi_re $mode 2 1 event] 764 765 with_spawn_id $gdb_main_spawn_id { 766 gdb_test_no_output "select-frame 1" "select frame 1" 767 } 768 769 with_spawn_id $mi_spawn_id { 770 match_re_or_ensure_no_output $mi_re "select frame 1, event on MI" 771 } 772 773 # Do the 'select-frame' command to select the same frame. This time we expect to 774 # event on MI, since we won't actually change frame. 775 776 set mi_re "" 777 778 with_spawn_id $gdb_main_spawn_id { 779 gdb_test_no_output "select-frame 1" "select frame 1 again" 780 } 781 782 with_spawn_id $mi_spawn_id { 783 match_re_or_ensure_no_output $mi_re "select frame 1 again, event on MI" 784 } 785 } 786 787 with_test_prefix "thread 1.3" { 788 # Now, try the 'select-frame' command on thread 3, which is running if we are in 789 # non-stop mode. 790 reset_selection "1.3" 791 flush_buffers 792 793 if {$mode == "all-stop"} { 794 set mi_re [make_mi_re $mode 3 1 event] 795 } elseif {$mode == "non-stop"} { 796 set mi-re "" 797 set cli_re "Selected thread is running\\." 798 } 799 800 with_spawn_id $gdb_main_spawn_id { 801 if { $mode == "all-stop" } { 802 gdb_test_no_output "select-frame 1" "select frame 1" 803 } else { 804 gdb_test "select-frame 1" $cli_re "select frame 1" 805 } 806 } 807 808 with_spawn_id $mi_spawn_id { 809 match_re_or_ensure_no_output $mi_re "select frame 1, event on MI" 810 } 811 } 812 } 813 814 # Test doing an up and then down command from CLI. 815 816 proc_with_prefix test_cli_up_down { mode } { 817 global gdb_main_spawn_id mi_spawn_id 818 819 reset_selection "1.2" 820 flush_buffers 821 822 # Try doing an 'up'. 823 824 set mi_re [make_mi_re $mode 2 1 event] 825 set cli_re [make_cli_re $mode -1 -1 1] 826 827 with_spawn_id $gdb_main_spawn_id { 828 gdb_test "up" $cli_re "frame up" 829 } 830 831 with_spawn_id $mi_spawn_id { 832 match_re_or_ensure_no_output $mi_re "frame up, event on MI" 833 } 834 835 # Try doing a 'down'. 836 837 set mi_re [make_mi_re $mode 2 0 event] 838 set cli_re [make_cli_re $mode -1 -1 0] 839 840 with_spawn_id $gdb_main_spawn_id { 841 gdb_test "down" $cli_re "frame down" 842 } 843 844 with_spawn_id $mi_spawn_id { 845 match_re_or_ensure_no_output $mi_re "frame down, event on MI" 846 } 847 } 848 849 # Test selecting a thread from MI. 850 851 proc_with_prefix test_mi_thread_select { mode } { 852 global gdb_main_spawn_id mi_spawn_id 853 854 reset_selection "1.1" 855 flush_buffers 856 857 with_test_prefix "thread 1.2" { 858 # Do the '-thread-select' command to select a stopped thread. 859 860 set mi_re [make_mi_re $mode 2 0 response] 861 set cli_re [make_cli_re $mode -1 1.2 0] 862 863 with_spawn_id $mi_spawn_id { 864 mi_gdb_test "-thread-select 2" $mi_re "-thread-select" 865 } 866 867 with_spawn_id $gdb_main_spawn_id { 868 match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI" 869 } 870 871 # Do the '-thread-select' command to select the same thread. We 872 # shouldn't receive an event on CLI, since we won't actually switch 873 # thread. 874 875 set cli_re "" 876 877 with_spawn_id $mi_spawn_id { 878 mi_gdb_test "-thread-select 2" $mi_re "-thread-select again" 879 } 880 881 with_spawn_id $gdb_main_spawn_id { 882 match_re_or_ensure_no_output $cli_re "-thread-select again, event on CLI" 883 } 884 } 885 886 with_test_prefix "thread 1.3" { 887 # Do the '-thread-select' command to select the third thread, stopped on all-stop, 888 # running on non-stop. 889 890 if { $mode == "all-stop" } { 891 set mi_re [make_mi_re $mode 3 0 response] 892 set cli_re [make_cli_re $mode -1 1.3 0] 893 } else { 894 set mi_re [make_mi_re $mode 3 -1 response] 895 set cli_re [make_cli_re $mode -1 1.3 -1] 896 } 897 898 with_spawn_id $mi_spawn_id { 899 mi_gdb_test "-thread-select 3" $mi_re "-thread-select" 900 } 901 902 with_spawn_id $gdb_main_spawn_id { 903 match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on CLI" 904 } 905 906 # Do the 'thread' command to select the third thread again. Again, we 907 # shouldn't receive an event on MI. 908 909 set cli_re "" 910 911 with_spawn_id $mi_spawn_id { 912 mi_gdb_test "-thread-select 3" $mi_re "-thread-select again" 913 } 914 915 with_spawn_id $gdb_main_spawn_id { 916 match_re_or_ensure_no_output $cli_re "-thread-select again, event on CLI" 917 } 918 } 919 920 with_test_prefix "thread 1.2 with --thread 2" { 921 # Test selecting a thread from MI with a --thread option. This test 922 # verifies that even if the thread GDB would switch to is the same as 923 # the thread specified with --thread, an event is still sent to CLI. 924 # In this case this is thread 1.2 925 926 set mi_re [make_mi_re $mode 2 0 response] 927 set cli_re [make_cli_re $mode -1 1.2 0] 928 929 with_spawn_id $mi_spawn_id { 930 mi_gdb_test "-thread-select --thread 2 2" $mi_re "-thread-select" 931 } 932 933 with_spawn_id $gdb_main_spawn_id { 934 match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on cli" 935 } 936 } 937 938 with_test_prefix "thread 1.2 with --thread 3" { 939 # Test selecting a thread from MI with a --thread option. 940 # This test verifies that when different thread numbers are 941 # passed to the --thread option and the underlying 942 # -thread-select command, the correct thread is selected. 943 # In this case this is thread 1.2 944 945 reset_selection "1.1" 946 947 set mi_re [make_mi_re $mode 2 0 response] 948 set cli_re [make_cli_re $mode -1 1.2 0] 949 950 with_spawn_id $mi_spawn_id { 951 mi_gdb_test "-thread-select --thread 3 2" $mi_re "-thread-select" 952 } 953 954 with_spawn_id $gdb_main_spawn_id { 955 match_re_or_ensure_no_output "$cli_re\r\n" "-thread-select, event on cli" 956 } 957 } 958 959 # Idea for the future: selecting a thread in a different inferior. For now, 960 # GDB doesn't show an inferior switch, but if it did, it would be a nice 961 # place to test it. 962 } 963 964 proc_with_prefix test_mi_stack_select_frame { mode } { 965 global gdb_main_spawn_id mi_spawn_id 966 967 with_test_prefix "thread 1.2" { 968 reset_selection "1.2" 969 flush_buffers 970 971 # Do the '-stack-select-frame' command to select frame 1. 972 973 set mi_re "\\^done" 974 set cli_re [make_cli_re $mode -1 -1 1] 975 976 with_spawn_id $mi_spawn_id { 977 mi_gdb_test "-stack-select-frame 1" $mi_re "-stack-select-frame" 978 } 979 980 with_spawn_id $gdb_main_spawn_id { 981 match_re_or_ensure_no_output "$cli_re\r\n" "-stack-select-frame, event on CLI" 982 } 983 984 # Do the '-stack-select-frame' command to select the same frame. This time we don't 985 # expect an event on CLI, since we won't actually change frame. 986 987 set cli_re "" 988 989 with_spawn_id $mi_spawn_id { 990 mi_gdb_test "-stack-select-frame 1" $mi_re "-stack-select-frame again" 991 } 992 993 with_spawn_id $gdb_main_spawn_id { 994 match_re_or_ensure_no_output $cli_re "-stack-select-frame again, event on CLI" 995 } 996 997 # Now use the '-stack-select-frame' command with the --frame 998 # option, this verifies that even when the frame GDB would 999 # swith to is the same as the frame specified with --frame, an 1000 # event is still sent to the CLI. 1001 1002 set cli_re [make_cli_re $mode -1 -1 0] 1003 1004 with_spawn_id $mi_spawn_id { 1005 mi_gdb_test "-stack-select-frame --thread 2 --frame 0 0" $mi_re 1006 } 1007 1008 with_spawn_id $gdb_main_spawn_id { 1009 match_re_or_ensure_no_output "$cli_re\r\n" "-stack-select-frame with --frame 0, event on CLI" 1010 } 1011 1012 # Now use the '-stack-select-frame' command with the --frame 1013 # option, this verifies that the correct event is sent to the 1014 # CLI when the frame specified with --frame is different to 1015 # the actual frame selected. 1016 1017 set cli_re [make_cli_re $mode -1 -1 1] 1018 1019 with_spawn_id $mi_spawn_id { 1020 mi_gdb_test "-stack-select-frame --thread 2 --frame 2 1" $mi_re 1021 } 1022 1023 with_spawn_id $gdb_main_spawn_id { 1024 match_re_or_ensure_no_output "$cli_re\r\n" "-stack-select-frame with --frame 2, event on CLI" 1025 } 1026 } 1027 1028 with_test_prefix "thread 1.3" { 1029 # Now, try the '-stack-select-frame' command on thread 3, which is 1030 # running if we are in non-stop mode. 1031 reset_selection "1.3" 1032 flush_buffers 1033 1034 if {$mode == "all-stop"} { 1035 set mi_re "\\^done" 1036 set cli_re [make_cli_re $mode -1 -1 1] 1037 append cli_re "\r\n" 1038 } elseif {$mode == "non-stop"} { 1039 set cli_re "" 1040 set mi_re "\\^error,msg=\"Selected thread is running\\.\"" 1041 } 1042 1043 with_spawn_id $mi_spawn_id { 1044 mi_gdb_test "-stack-select-frame 1" $mi_re "-stack-select-frame" 1045 } 1046 1047 with_spawn_id $gdb_main_spawn_id { 1048 match_re_or_ensure_no_output $cli_re "-stack-select-frame, event on CLI" 1049 } 1050 } 1051 } 1052 1053 proc make_cli_in_mi_command { cli_in_mi_mode command } { 1054 if { $cli_in_mi_mode == "direct" } { 1055 return $command 1056 } elseif { $cli_in_mi_mode == "interpreter-exec" } { 1057 return "-interpreter-exec console \"$command\"" 1058 } else { 1059 error "Invalid value for CLI_IN_MI_MODE." 1060 } 1061 } 1062 1063 # Test selecting the inferior using a CLI command in the MI channel. 1064 1065 proc_with_prefix test_cli_in_mi_inferior { mode cli_in_mi_mode } { 1066 global gdb_main_spawn_id mi_spawn_id 1067 1068 reset_selection "1.1" 1069 flush_buffers 1070 1071 set command [make_cli_in_mi_command $cli_in_mi_mode "inferior 2"] 1072 1073 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 2 2.1 4 2] 1074 set cli_re [make_cli_re $mode 2 "2.1" 2] 1075 1076 with_spawn_id $mi_spawn_id { 1077 mi_gdb_test $command $mi_re "select inferior" 1078 } 1079 1080 with_spawn_id $gdb_main_spawn_id { 1081 match_re_or_ensure_no_output "$cli_re\r\n" "select inferior, event on CLI" 1082 } 1083 1084 # Do the 'inferior' command on the currently selected inferior. For now, 1085 # GDB naively re-outputs everything. 1086 with_spawn_id $mi_spawn_id { 1087 mi_gdb_test $command $mi_re "select inferior again" 1088 } 1089 1090 with_spawn_id $gdb_main_spawn_id { 1091 match_re_or_ensure_no_output $cli_re "select inferior again, event on CLI" 1092 } 1093 } 1094 1095 # Test selecting the thread using a CLI command in the MI channel. 1096 1097 proc_with_prefix test_cli_in_mi_thread { mode cli_in_mi_mode } { 1098 global gdb_main_spawn_id mi_spawn_id 1099 1100 reset_selection "1.1" 1101 flush_buffers 1102 1103 with_test_prefix "thread 1.2" { 1104 # Do the 'thread' command to select a stopped thread. 1105 1106 set command [make_cli_in_mi_command $cli_in_mi_mode "thread 1.2"] 1107 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 -1 1.2 2 0] 1108 set cli_re [make_cli_re $mode -1 1.2 0] 1109 1110 with_spawn_id $mi_spawn_id { 1111 mi_gdb_test $command $mi_re "select thread" 1112 } 1113 1114 with_spawn_id $gdb_main_spawn_id { 1115 match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI" 1116 } 1117 1118 # Do the 'thread' command to select the same thread. We shouldn't 1119 # receive an event on CLI, since we won't actually switch thread. 1120 1121 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 0 -1 1.2 2 0] 1122 set cli_re "" 1123 1124 with_spawn_id $mi_spawn_id { 1125 mi_gdb_test $command $mi_re "select thread again" 1126 } 1127 1128 with_spawn_id $gdb_main_spawn_id { 1129 match_re_or_ensure_no_output $cli_re "select thread again, event on CLI" 1130 } 1131 1132 # Try the 'thread' command without arguments. 1133 1134 set command [make_cli_in_mi_command $cli_in_mi_mode "thread"] 1135 1136 set mi_re "${command}.*~\"\\\[Current thread is 1\\.2.*\\\]\\\\n\".*\\^done" 1137 set cli_re "" 1138 1139 with_spawn_id $mi_spawn_id { 1140 mi_gdb_test $command $mi_re "thread without args" 1141 } 1142 1143 with_spawn_id $gdb_main_spawn_id { 1144 match_re_or_ensure_no_output $cli_re "thread without args, event on CLI" 1145 } 1146 } 1147 1148 with_test_prefix "thread 1.3" { 1149 # Do the 'thread' command to select the third thread, stopped on 1150 # all-stop, running on non-stop. 1151 1152 set command [make_cli_in_mi_command $cli_in_mi_mode "thread 1.3"] 1153 if { $mode == "all-stop" } { 1154 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 -1 1.3 3 0] 1155 set cli_re [make_cli_re $mode -1 "1.3" 0] 1156 } else { 1157 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 -1 1.3 3 -1] 1158 set cli_re [make_cli_re $mode -1 "1.3" -1] 1159 } 1160 1161 with_spawn_id $mi_spawn_id { 1162 mi_gdb_test $command $mi_re "select thread" 1163 } 1164 1165 with_spawn_id $gdb_main_spawn_id { 1166 match_re_or_ensure_no_output "$cli_re\r\n" "select thread, event on CLI" 1167 } 1168 1169 # Do the 'thread' command to select the third thread again. Again, we 1170 # shouldn't receive an event on MI. 1171 1172 if { $mode == "all-stop" } { 1173 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 0 -1 1.3 3 0] 1174 } else { 1175 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 0 -1 1.3 3 -1] 1176 } 1177 set cli_re "" 1178 1179 with_spawn_id $mi_spawn_id { 1180 mi_gdb_test $command $mi_re "select thread again" 1181 } 1182 1183 with_spawn_id $gdb_main_spawn_id { 1184 match_re_or_ensure_no_output $cli_re "select thread again, event on CLI" 1185 } 1186 1187 # Try the 'thread' command without arguments. 1188 1189 set command [make_cli_in_mi_command $cli_in_mi_mode "thread"] 1190 1191 set mi_re "${command}.*~\"\\\[Current thread is 1\\.3.*\\\]\\\\n\".*\\^done" 1192 set cli_re "" 1193 1194 with_spawn_id $mi_spawn_id { 1195 mi_gdb_test $command $mi_re "thread without args" 1196 } 1197 1198 with_spawn_id $gdb_main_spawn_id { 1199 match_re_or_ensure_no_output $cli_re "thread without args, event on CLI" 1200 } 1201 } 1202 1203 # Idea for the future: selecting a thread in a different inferior. For now, 1204 # GDB doesn't show an inferior switch, but if it did, it would be a nice 1205 # place to test it. 1206 } 1207 1208 # Test selecting the frame using a CLI command in the MI channel. 1209 1210 proc_with_prefix test_cli_in_mi_frame { mode cli_in_mi_mode } { 1211 global gdb_main_spawn_id mi_spawn_id 1212 1213 with_test_prefix "thread 1.2" { 1214 reset_selection "1.2" 1215 flush_buffers 1216 1217 # Do the 'frame' command to select frame 1. 1218 1219 set command [make_cli_in_mi_command $cli_in_mi_mode "frame 1"] 1220 set cli_re [make_cli_re $mode -1 -1 1] 1221 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 -1 -1 2 1] 1222 1223 with_spawn_id $mi_spawn_id { 1224 mi_gdb_test $command $mi_re "select frame 1" 1225 } 1226 1227 with_spawn_id $gdb_main_spawn_id { 1228 match_re_or_ensure_no_output "$cli_re\r\n" "select frame 1, event on CLI" 1229 } 1230 1231 # Do the 'frame' command to select the same frame. This time we don't 1232 # expect an event on MI, since we won't actually change frame. 1233 1234 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 0 -1 -1 2 1] 1235 set cli_re "" 1236 1237 with_spawn_id $mi_spawn_id { 1238 mi_gdb_test $command $mi_re "select frame 1 again" 1239 } 1240 1241 with_spawn_id $gdb_main_spawn_id { 1242 match_re_or_ensure_no_output $cli_re "select frame 1 again, event on CLI" 1243 } 1244 1245 # Do the 'frame' command without arguments. We shouldn't see anything on MI. 1246 1247 set command [make_cli_in_mi_command $cli_in_mi_mode "frame"] 1248 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 0 -1 -1 2 1] 1249 1250 with_spawn_id $mi_spawn_id { 1251 mi_gdb_test $command $mi_re "frame without args" 1252 } 1253 1254 with_spawn_id $gdb_main_spawn_id { 1255 match_re_or_ensure_no_output $cli_re "frame without args, event on CLI" 1256 } 1257 } 1258 1259 with_test_prefix "thread 1.3" { 1260 # Now, try the 'frame' command on thread 3, which is running if we are in 1261 # non-stop mode. 1262 reset_selection "1.3" 1263 flush_buffers 1264 1265 set command [make_cli_in_mi_command $cli_in_mi_mode "frame 1"] 1266 if {$mode == "all-stop"} { 1267 set cli_re [make_cli_re $mode -1 -1 1] 1268 append cli_re "\r\n" 1269 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 1 -1 -1 3 1] 1270 } elseif {$mode == "non-stop"} { 1271 set cli_re "" 1272 set mi_re "\\^error,msg=\"Selected thread is running\\.\".*" 1273 } 1274 1275 with_spawn_id $mi_spawn_id { 1276 mi_gdb_test $command $mi_re "select frame 1" 1277 } 1278 1279 with_spawn_id $gdb_main_spawn_id { 1280 match_re_or_ensure_no_output $cli_re "select frame 1, event on CLI" 1281 } 1282 1283 # Do the 'frame' command without arguments. 1284 1285 set command [make_cli_in_mi_command $cli_in_mi_mode "frame"] 1286 if { $mode == "all-stop" } { 1287 set mi_re [make_cli_in_mi_re $command $cli_in_mi_mode $mode 0 -1 -1 -1 1] 1288 } else { 1289 set mi_re "\\^error,msg=\"No stack\\.\"" 1290 } 1291 set cli_re "" 1292 1293 with_spawn_id $mi_spawn_id { 1294 mi_gdb_test $command $mi_re "frame without args" 1295 } 1296 1297 with_spawn_id $gdb_main_spawn_id { 1298 match_re_or_ensure_no_output $cli_re "frame without args, event on CLI" 1299 } 1300 } 1301 } 1302 1303 foreach_with_prefix mode { "all-stop" "non-stop" } { 1304 set test "setup done" 1305 if { [test_setup $mode] == -1 } { 1306 fail $test 1307 continue 1308 } 1309 pass $test 1310 1311 # Test selecting inferior, thread and frame from CLI 1312 1313 test_cli_inferior $mode 1314 test_cli_thread $mode 1315 test_cli_frame $mode 1316 test_cli_select_frame $mode 1317 test_cli_up_down $mode 1318 1319 # Test selecting thread and frame from MI 1320 1321 test_mi_thread_select $mode 1322 test_mi_stack_select_frame $mode 1323 1324 # Test some CLI commands sent through MI, both with a "direct" command, 1325 # such as "thread 1", and with -interpreter-exec, such as 1326 # '-interpreter-exec console "thread 1"'. 1327 1328 foreach_with_prefix exec_mode {"direct" "interpreter-exec"} { 1329 test_cli_in_mi_inferior $mode $exec_mode 1330 test_cli_in_mi_thread $mode $exec_mode 1331 test_cli_in_mi_frame $mode $exec_mode 1332 } 1333 } 1334