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