gdb: add inferior-specific breakpoints
[binutils-gdb.git] / gdb / testsuite / lib / mi-support.exp
index edfc07dba829928fb61c55d258468c340f3e222f..3cd94b03c15f1df21397b8abf37f02a5535fa492 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 1999-2016 Free Software Foundation, Inc.
+# Copyright 1999-2023 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@ load_lib gdb-utils.exp
 # The variable mi_gdb_prompt is a regexp which matches the gdb mi prompt.
 # Set it if it is not already set.
 global mi_gdb_prompt
-if ![info exists mi_gdb_prompt] then {
+if {![info exists mi_gdb_prompt]} {
     set mi_gdb_prompt "\[(\]gdb\[)\] \r\n"
 }
 
@@ -55,15 +55,12 @@ proc mi_gdb_exit {} {
 proc mi_uncatched_gdb_exit {} {
     global GDB
     global INTERNAL_GDBFLAGS GDBFLAGS
-    global verbose
     global gdb_spawn_id gdb_main_spawn_id
     global mi_spawn_id inferior_spawn_id
     global gdb_prompt
     global mi_gdb_prompt
     global MIFLAGS
 
-    gdb_stop_suppressing_tests
-
     if { [info procs sid_exit] != "" } {
        sid_exit
     }
@@ -86,10 +83,22 @@ proc mi_uncatched_gdb_exit {} {
                exp_continue
            }
            -re "DOSEXIT code" { }
-           default { }
+           -re "\r\n999\\^exit\r\n" { }
        }
     }
 
+    # Switch back to the main spawn id, so that remote_close below
+    # closes it, and not a secondary channel.  Closing a secondary
+    # channel does not make GDB exit.
+    if {$gdb_spawn_id != $gdb_main_spawn_id} {
+       switch_gdb_spawn_id $gdb_main_spawn_id
+    }
+
+    # Close secondary MI channel, if there's one.
+    if {$mi_spawn_id != $gdb_main_spawn_id} {
+       close -i $mi_spawn_id
+    }
+
     if ![is_remote host] {
        remote_close host
     }
@@ -122,19 +131,28 @@ proc mi_create_inferior_pty {} {
     }
 }
 
-# Switch the default spawn id to SPAWN_ID, so that mi_gdb_test
-# etc. default to using it.
+# Create a new pty, and reate a new MI UI (using the new-ui command) on it.
+#
+# Return a list with the spawn id for that pty and the pty file name.
 
-proc switch_gdb_spawn_id {spawn_id} {
-    global gdb_spawn_id
-    global board board_info
+proc create_mi_ui {} {
+    spawn -pty
+    set tty_name $spawn_out(slave,name)
+    gdb_test_multiple "new-ui mi $tty_name" "new-ui" {
+       -re "New UI allocated\r\n$::gdb_prompt $" {
+       }
+    }
 
-    set gdb_spawn_id $spawn_id
-    set board [host_info name]
-    set board_info($board,fileid) $spawn_id
+    return [list $spawn_id $tty_name]
 }
 
-proc mi_gdb_start_separate_mi_tty { args } {
+#
+# Like default_mi_gdb_start below, but the MI is created as a separate
+# ui in a new tty.  The global MI_SPAWN_ID is updated to point at the
+# new tty created for the MI interface.  The global GDB_MAIN_SPAWN_ID
+# is updated to the current value of the global GDB_SPAWN_ID.
+#
+proc mi_gdb_start_separate_mi_tty { { flags {} } } {
     global gdb_prompt mi_gdb_prompt
     global timeout
     global gdb_spawn_id gdb_main_spawn_id mi_spawn_id
@@ -142,8 +160,8 @@ proc mi_gdb_start_separate_mi_tty { args } {
 
     set separate_inferior_pty 0
 
-    foreach arg $args {
-       if {$arg == "separate-inferior-tty"} {
+    foreach flag $flags {
+       if {$flag == "separate-inferior-tty"} {
            set separate_inferior_pty 1
        }
     }
@@ -151,13 +169,7 @@ proc mi_gdb_start_separate_mi_tty { args } {
     gdb_start
 
     # Create the new PTY for the MI UI.
-    spawn -pty
-    set mi_spawn_id $spawn_id
-    set mi_tty_name $spawn_out(slave,name)
-    gdb_test_multiple "new-ui mi $mi_tty_name" "new-ui" {
-       -re "New UI allocated\r\n$gdb_prompt $" {
-       }
-    }
+    lassign [create_mi_ui] mi_spawn_id mi_tty_name
 
     # Switch to the MI channel.
     set gdb_main_spawn_id $gdb_spawn_id
@@ -186,8 +198,10 @@ proc mi_gdb_start_separate_mi_tty { args } {
 #
 # default_mi_gdb_start [FLAGS] -- start gdb running, default procedure
 #
+# FLAGS is a list of flags, each flag is a string.
+#
 # If "separate-inferior-tty" is specified, the inferior works with
-# it's own PTY.
+# its own PTY.
 #
 # If "separate-mi-tty" is specified, the gdb starts in CLI mode, with
 # MI running on a secondary UI, on its own tty.
@@ -196,8 +210,8 @@ proc mi_gdb_start_separate_mi_tty { args } {
 # tests on different hosts all using the same server, things can
 # get really slow.  Give gdb at least 3 minutes to start up.
 #
-proc default_mi_gdb_start { args } {
-    global verbose use_gdb_stub
+proc default_mi_gdb_start { { flags {} } } {
+    global use_gdb_stub
     global GDB
     global INTERNAL_GDBFLAGS GDBFLAGS
     global gdb_prompt
@@ -205,7 +219,13 @@ proc default_mi_gdb_start { args } {
     global timeout
     global gdb_spawn_id gdb_main_spawn_id inferior_spawn_id mi_spawn_id
     global MIFLAGS
-    global SEPARATE_MI_TTY
+    global FORCE_SEPARATE_MI_TTY
+
+    # Keep track of the number of times GDB has been launched.
+    global gdb_instances
+    incr gdb_instances
+
+    gdb_stdin_log_init
 
     if {[info exists FORCE_SEPARATE_MI_TTY]} {
        set separate_mi_pty $FORCE_SEPARATE_MI_TTY
@@ -215,21 +235,18 @@ proc default_mi_gdb_start { args } {
 
     set separate_inferior_pty 0
 
-    foreach arg $args {
-       if {$arg == "separate-mi-tty"} {
+    foreach flag $flags {
+       if {$flag == "separate-mi-tty"} {
            set separate_mi_pty 1
-       } elseif {$arg == "separate-inferior-tty"} {
+       } elseif {$flag == "separate-inferior-tty"} {
            set separate_inferior_pty 1
        }
     }
 
     if {$separate_mi_pty} {
-       return [eval mi_gdb_start_separate_mi_tty $args]
+       return [mi_gdb_start_separate_mi_tty $flags]
     }
 
-    gdb_stop_suppressing_tests
-    set inferior_pty no-tty
-
     # Set the default value, it may be overriden later by specific testfile.
     set use_gdb_stub [target_info exists use_gdb_stub]
 
@@ -239,66 +256,49 @@ proc default_mi_gdb_start { args } {
        sid_start
     }
 
-    verbose "Spawning $GDB $INTERNAL_GDBFLAGS $GDBFLAGS $MIFLAGS"
-
     if [info exists gdb_spawn_id] {
        return 0
     }
 
-    if ![is_remote host] {
-       if { [which $GDB] == 0 } then {
-           perror "$GDB does not exist."
-           exit 1
+    save_vars { GDBFLAGS } {
+       append GDBFLAGS " $MIFLAGS"
+
+       set res [gdb_spawn]
+       if { $res != 0} {
+           return $res
        }
     }
 
-    set res [remote_spawn host "$GDB $INTERNAL_GDBFLAGS $GDBFLAGS $MIFLAGS [host_info gdb_opts]"]
-    if { $res < 0 || $res == "" } {
-       perror "Spawning $GDB failed."
-       return 1
-    }
     gdb_expect {
        -re "~\"GNU.*\r\n~\".*$mi_gdb_prompt$" {
-           # We have a new format mi startup prompt.  If we are
-           # running mi1, then this is an error as we should be
-           # using the old-style prompt.
-           if { $MIFLAGS == "-i=mi1" } {
-               perror "(mi startup) Got unexpected new mi prompt."
-               remote_close host
-               return -1
-           }
+           # We have a new format mi startup prompt.
            verbose "GDB initialized."
        }
-       -re "\[^~\].*$mi_gdb_prompt$" {
-           # We have an old format mi startup prompt.  If we are
-           # not running mi1, then this is an error as we should be
-           # using the new-style prompt.
-           if { $MIFLAGS != "-i=mi1" } {
-               perror "(mi startup) Got unexpected old mi prompt."
-               remote_close host
-               return -1
-           }
+       -re "^(=\[^\r\n\]*\r\n)*$mi_gdb_prompt$" {
+           # Output with -q.
            verbose "GDB initialized."
        }
        -re ".*unrecognized option.*for a complete list of options." {
-           untested "Skip mi tests (not compiled with mi support)."
+           untested "skip mi tests (not compiled with mi support)."
            remote_close host
+           unset gdb_spawn_id
            return -1
        }
        -re ".*Interpreter `mi' unrecognized." {
-           untested "Skip mi tests (not compiled with mi support)."
+           untested "skip mi tests (not compiled with mi support)."
            remote_close host
+           unset gdb_spawn_id
            return -1
        }
        timeout {
            perror "(timeout) GDB never initialized after 10 seconds."
            remote_close host
+           unset gdb_spawn_id
            return -1
        }
     }
-    set gdb_spawn_id $res
-    set gdb_main_spawn_id $res
-    set mi_spawn_id $res
+    set gdb_main_spawn_id $gdb_spawn_id
+    set mi_spawn_id $gdb_spawn_id
 
     # FIXME: mi output does not go through pagers, so these can be removed.
     # force the height to "unlimited", so no pagers get used
@@ -386,36 +386,15 @@ proc mi_gdb_reinitialize_dir { subdir } {
     global mi_gdb_prompt
     global MIFLAGS
 
-    global suppress_flag
-    if { $suppress_flag } {
-       return
-    }
-
     if [is_remote host] {
        return ""
     }
 
-    if { $MIFLAGS == "-i=mi1" } {
-      send_gdb "104-environment-directory\n"
-      gdb_expect 60 {
-       -re ".*Reinitialize source path to empty.*y or n. " {
-           warning "Got confirmation prompt for dir reinitialization."
-           send_gdb "y\n"
-           gdb_expect 60 {
-               -re "$mi_gdb_prompt$" {}
-               timeout {error "Dir reinitialization failed (timeout)"}
-           }
-       }
+    send_gdb "104-environment-directory -r\n"
+    gdb_expect 60 {
+       -re "104\\\^done,source-path=.*\r\n$mi_gdb_prompt$" {}
        -re "$mi_gdb_prompt$" {}
-         timeout {error "Dir reinitialization failed (timeout)"}
-      }
-    } else {
-       send_gdb "104-environment-directory -r\n"
-       gdb_expect 60 {
-           -re "104\\\^done,source-path=.*\r\n$mi_gdb_prompt$" {}
-           -re "$mi_gdb_prompt$" {}
-           timeout {error "Dir reinitialization failed (timeout)"}
-      }
+       timeout {error "Dir reinitialization failed (timeout)"}
     }
 
     send_gdb "105-environment-directory $subdir\n"
@@ -474,7 +453,7 @@ proc mi_gdb_target_cmd { targetname serialport } {
                continue
            }
            -re "Non-stop mode requested, but remote does not support non-stop.*$mi_gdb_prompt" {
-               unsupported "Non-stop mode not supported"
+               unsupported "non-stop mode not supported"
                return 1
            }
            -re "Timeout reading from remote system.*$mi_gdb_prompt$" {
@@ -494,7 +473,6 @@ proc mi_gdb_target_cmd { targetname serialport } {
 # return a -1 if anything goes wrong.
 #
 proc mi_gdb_file_cmd { arg } {
-    global verbose
     global loadpath
     global loadfile
     global GDB
@@ -502,6 +480,11 @@ proc mi_gdb_file_cmd { arg } {
     global last_loaded_file
     upvar timeout timeout
 
+    # GCC for Windows target may create foo.exe given "-o foo".
+    if { ![file exists $arg] && [file exists "$arg.exe"] } {
+       set arg "$arg.exe"
+    }
+
     set last_loaded_file $arg
 
     if [is_remote host] {
@@ -516,7 +499,7 @@ proc mi_gdb_file_cmd { arg } {
 # output.  Queries are an error for mi.
     send_gdb "105-file-exec-and-symbols $arg\n"
     gdb_expect 120 {
-       -re "Reading symbols from.*done.*$mi_gdb_prompt$" {
+       -re "Reading symbols from.*$mi_gdb_prompt$" {
            verbose "\t\tLoaded $arg into the $GDB"
            return 0
        }
@@ -527,7 +510,7 @@ proc mi_gdb_file_cmd { arg } {
        -re "Load new symbol table from \".*\".*y or n. $" {
            send_gdb "y\n"
            gdb_expect 120 {
-               -re "Reading symbols from.*done.*$mi_gdb_prompt$" {
+               -re "Reading symbols from.*$mi_gdb_prompt$" {
                    verbose "\t\tLoaded $arg with new symbol table into $GDB"
                    # All OK
                }
@@ -565,7 +548,6 @@ proc mi_gdb_file_cmd { arg } {
 # return a -1 if anything goes wrong.
 #
 proc mi_gdb_target_load { } {
-    global verbose
     global loadpath
     global loadfile
     global GDB
@@ -614,8 +596,9 @@ proc mi_gdb_target_load { } {
            }
        }
     } elseif { [target_info protocol] == "sim" } {
+       set target_sim_options "[board_info target gdb,target_sim_options]"
        # For the simulator, just connect to it directly.
-       send_gdb "47-target-select sim\n"
+       send_gdb "47-target-select sim $target_sim_options\n"
        gdb_expect $loadtimeout {
            -re "47\\^connected.*$mi_gdb_prompt$" {
            }
@@ -663,16 +646,26 @@ proc mi_gdb_load { arg } {
     return 0
 }
 
-# mi_gdb_test COMMAND PATTERN MESSAGE [IPATTERN] -- send a command to gdb; 
+# Return true if symbols were read in using -readnow.  Otherwise,
+# return false.
+
+proc mi_readnow { args } {
+    # Just defer to gdb.exp.
+    return [readnow]
+}
+
+# mi_gdb_test COMMAND [PATTERN [MESSAGE [IPATTERN]]] -- send a command to gdb;
 #   test the result.
 #
 # COMMAND is the command to execute, send to GDB with send_gdb.  If
 #   this is the null string no command is sent.
 # PATTERN is the pattern to match for a PASS, and must NOT include
 #   the \r\n sequence immediately before the gdb prompt.
+#   If not specified, .* is used.
 # MESSAGE is the message to be printed.  (If this is the empty string,
 #   then sometimes we don't call pass or fail at all; I don't
 #   understand this at all.)
+#   If not specified, COMMAND is used.
 # IPATTERN is the pattern to match for the inferior's output.  This parameter
 #   is optional.  If present, it will produce a PASS if the match is
 #   successful, and a FAIL if unsuccessful.
@@ -689,9 +682,23 @@ proc mi_gdb_test { args } {
     global inferior_exited_re async
     upvar timeout timeout
 
-    set command [lindex $args 0]
-    set pattern [lindex $args 1]
-    set message [lindex $args 2]
+    if {[llength $args] >= 1} {
+       set command [lindex $args 0]
+    } else {
+       error "Not enough arguments in mi_gdb_test"
+    }
+
+    if {[llength $args] >= 2} {
+       set pattern [lindex $args 1]
+    } else {
+       set pattern ".*"
+    }
+
+    if {[llength $args] >= 3} {
+       set message [lindex $args 2]
+    } else {
+       set message $command
+    }
 
     if [llength $args]==4 {
        set ipattern [lindex $args 3]
@@ -704,7 +711,11 @@ proc mi_gdb_test { args } {
        set question_string "^FOOBAR$"
     }
 
-    if $verbose>2 then {
+    if { [llength $args] >= 6 } {
+       error "Too many arguments in mi_gdb_test"
+    }
+
+    if {$verbose > 2} {
        send_user "Sending \"$command\" to gdb\n"
        send_user "Looking to match \"$pattern\"\n"
        send_user "Message is \"$message\"\n"
@@ -721,13 +732,7 @@ proc mi_gdb_test { args } {
            if { $foo < [expr $len - 1] } {
                set str [string range "$string" 0 $foo]
                if { [send_gdb "$str"] != "" } {
-                   global suppress_flag
-
-                   if { ! $suppress_flag } {
-                       perror "Couldn't send $command to GDB."
-                   }
-                   fail "$message"
-                   return $result
+                   perror "Couldn't send $command to GDB."
                }
                gdb_expect 2 {
                    -re "\[\r\n\]" { }
@@ -740,13 +745,7 @@ proc mi_gdb_test { args } {
        }
        if { "$string" != "" } {
            if { [send_gdb "$string"] != "" } {
-               global suppress_flag
-
-               if { ! $suppress_flag } {
-                   perror "Couldn't send $command to GDB."
-               }
-               fail "$message"
-               return $result
+               perror "Couldn't send $command to GDB."
            }
        }
     }
@@ -772,11 +771,10 @@ proc mi_gdb_test { args } {
             if { $message != "" } {
                 fail "$message"
             }
-            gdb_suppress_entire_file "GDB died"
             return -1
         }
         -re "Ending remote debugging.*$mi_gdb_prompt\[ \]*$" {
-           if ![isnative] then {
+           if {![isnative]} {
                warning "Can`t communicate to remote target."
            }
            gdb_exit
@@ -796,7 +794,7 @@ proc mi_gdb_test { args } {
            # match a single mi output command.  If a second GDB/MI output 
            # response is sent, it will be in the buffer for the next 
            # time mi_gdb_test is called.
-           if ![string match "" $message] then {
+           if {![string match "" $message]} {
                pass "$message"
            }
            set result 0
@@ -816,7 +814,7 @@ proc mi_gdb_test { args } {
            set result 1
        }
         -re "$inferior_exited_re with code \[0-9\]+.*$mi_gdb_prompt\[ \]*$" {
-           if ![string match "" $message] then {
+           if {![string match "" $message]} {
                set errmsg "$message (the program exited)"
            } else {
                set errmsg "$command (the program exited)"
@@ -825,7 +823,7 @@ proc mi_gdb_test { args } {
            return -1
        }
         -re "The program is not being run.*$mi_gdb_prompt\[ \]*$" {
-           if ![string match "" $message] then {
+           if {![string match "" $message]} {
                set errmsg "$message (the program is no longer running)"
            } else {
                set errmsg "$command (the program is no longer running)"
@@ -833,9 +831,9 @@ proc mi_gdb_test { args } {
            fail "$errmsg"
            return -1
        }
-        -re ".*$mi_gdb_prompt\[ \]*$" {
-           if ![string match "" $message] then {
-               fail "$message"
+        -re "(.*$mi_gdb_prompt\[ \]*)$" {
+           if {![string match "" $message]} {
+               fail "$message (unexpected output)"
            }
            set result 1
        }
@@ -843,11 +841,6 @@ proc mi_gdb_test { args } {
            send_gdb "\n"
            perror "Window too small."
             fail "$message"
-       }
-        -re "\\(y or n\\) " {
-           send_gdb "n\n"
-           perror "Got interactive prompt."
-            fail "$message"
        }
         eof {
             perror "Process no longer exists"
@@ -861,7 +854,7 @@ proc mi_gdb_test { args } {
             fail "$message"
        }
        timeout {
-           if ![string match "" $message] then {
+           if {![string match "" $message]} {
                fail "$message (timeout)"
            }
            set result 1
@@ -937,10 +930,6 @@ proc mi_gdb_expect_cli_output {until message} {
 # If USE_MI_COMMAND is false, they are effectively arguments passed
 # to the test program.  If the global USE_GDB_STUB is true, ARGS is not used.
 proc mi_run_cmd_full {use_mi_command args} {
-    global suppress_flag
-    if { $suppress_flag } {
-       return -1
-    }
     global mi_gdb_prompt use_gdb_stub
     global thread_selected_re
     global library_loaded_re
@@ -958,7 +947,7 @@ proc mi_run_cmd_full {use_mi_command args} {
        gdb_expect 30 {
            -re "$mi_gdb_prompt$" { }
            default {
-               perror "gdb_init_command for target failed"
+               unresolved "gdb_init_command for target failed"
                return -1
            }
        }
@@ -990,7 +979,11 @@ proc mi_run_cmd_full {use_mi_command args} {
        send_gdb  "jump *$start\n"
        warning "Using CLI jump command, expect run-to-main FAIL"
        gdb_expect {
-           -re "${run_match}&\"jump \\*${start}\\n\"\[\r\n\]+~\"Continuing at 0x\[0-9A-Fa-f\]+\\n.\"\[\r\n\]+\^running\[\r\n\]+\\*running,thread-id=\"\[^\"\]+\"\r\n${mi_gdb_prompt}" {}
+           -re "&\"jump \\*${start}\\\\n\"\[\r\n\]+~\"Continuing at 0x\[0-9A-Fa-f\]+\.\\\\n\"\[\r\n\]+\\^running\[\r\n\]+\\*running,thread-id=\"\[^\"\]+\"\[\r\n\]+${mi_gdb_prompt}" {}
+           timeout {
+               unresolved "unable to start target"
+               return -1
+           }
        }
        return 0
     }
@@ -1000,11 +993,11 @@ proc mi_run_cmd_full {use_mi_command args} {
        -re "${run_match}\\^running\r\n(\\*running,thread-id=\"\[^\"\]+\"\r\n|=thread-created,id=\"1\",group-id=\"\[0-9\]+\"\r\n)*(${library_loaded_re})*(${thread_selected_re})?${mi_gdb_prompt}" {
        }
        -re "\\^error,msg=\"The target does not support running in non-stop mode.\"" {
-           unsupported "Non-stop mode not supported"
+           unsupported "non-stop mode not supported"
            return -1
        }
        timeout {
-           perror "Unable to start target"
+           unresolved "unable to start target"
            return -1
        }
     }
@@ -1027,28 +1020,36 @@ proc mi_run_with_cli {args} {
     return [eval mi_run_cmd_full 0 $args]
 }
 
-#
-# Just like run-to-main but works with the MI interface
-#
-
-proc mi_run_to_main { } {
-    global suppress_flag
-    if { $suppress_flag } {
-       return -1
-    }
+# Starts fresh GDB binary and loads an optional executable into GDB.
+# Usage: mi_clean_restart [EXECUTABLE]
+# EXECUTABLE is the basename of the binary.
+# Return -1 if starting gdb or loading the executable failed.
 
+proc mi_clean_restart {{executable ""} {flags {}}} {
     global srcdir
     global subdir
-    global binfile
-    global srcfile
+    global errcnt
+    global warncnt
+
+    gdb_exit
+
+    # This is a clean restart, so reset error and warning count.
+    set errcnt 0
+    set warncnt 0
+
+    if {[mi_gdb_start $flags]} {
+       return -1
+    }
 
-    mi_delete_breakpoints
     mi_gdb_reinitialize_dir $srcdir/$subdir
-    mi_gdb_load ${binfile}
 
-    mi_runto main
-}
+    if {$executable != ""} {
+       set binfile [standard_output_file ${executable}]
+       return [mi_gdb_load ${binfile}]
+    }
 
+    return 0
+}
 
 # Just like gdb's "runto" proc, it will run the target to a given
 # function.  The big difference here between mi_runto and mi_execute_to
@@ -1057,22 +1058,41 @@ proc mi_run_to_main { } {
 #
 # FUNC is the linespec of the place to stop (it inserts a breakpoint here).
 # It returns:
-#   -1  if test suppressed, failed, timedout
+#   -1  if failed, timedout
 #    0  if test passed
+#
+# Supported options:
+#
+#  -qualified -- pass --qualified to -break-insert
+#  -pending   -- pass -f to -break-insert to create a pending
+#                breakpoint.
 
-proc mi_runto_helper {func run_or_continue} {
-  global suppress_flag
-  if { $suppress_flag } {
-    return -1
-  }
-
+proc mi_runto_helper {func run_or_continue args} {
   global mi_gdb_prompt expect_out
   global hex decimal fullname_syntax
 
+  parse_args {{qualified} {pending}}
+
   set test "mi runto $func"
-  set bp [mi_make_breakpoint -type breakpoint -disp del \
-             -func $func\(\\\(.*\\\)\)?]
-  mi_gdb_test "200-break-insert -t $func" "200\\^done,$bp" \
+  if {$pending} {
+      set bp [mi_make_breakpoint_pending -type breakpoint -disp del]
+  } else {
+      set bp [mi_make_breakpoint -type breakpoint -disp del \
+                 -func $func\(\\\(.*\\\)\)?]
+  }
+  set extra_opts ""
+  set extra_output ""
+  if {$qualified} {
+      lappend extra_opts "--qualified"
+  }
+  if {$pending} {
+      lappend extra_opts "-f"
+      # MI prints "Function FUNC not defined", "No line NNN in current
+      # file.", etc. to the CLI stream.
+      set extra_output "&\"\[^\r\n\]+\"\r\n"
+  }
+
+  mi_gdb_test "200-break-insert [join $extra_opts " "] -t $func" "${extra_output}200\\^done,$bp" \
       "breakpoint at $func"
 
   if {$run_or_continue == "run"} {
@@ -1086,8 +1106,14 @@ proc mi_runto_helper {func run_or_continue} {
   mi_expect_stop "breakpoint-hit" $func ".*" ".*" "\[0-9\]+" { "" "disp=\"del\"" } $test
 }
 
-proc mi_runto {func} {
-    return [mi_runto_helper $func "run"]
+proc mi_runto {func args} {
+    return [mi_runto_helper $func "run" {*}$args]
+}
+
+# Just like runto_main but works with the MI interface.
+
+proc mi_runto_main {} {
+    return [mi_runto_helper "main" "run" -qualified]
 }
 
 # Next to the next statement
@@ -1133,11 +1159,11 @@ proc mi_detect_async {} {
 # filename of a file without debug info.  ARGS should not include [] the
 # list of argument is enclosed in, and other regular expressions should
 # not include quotes.
-# If EXTRA is a list of one element, it's the regular expression
+# EXTRA can be a list of one, two or three elements.
+# The first element is the regular expression
 # for output expected right after *stopped, and before GDB prompt.
-# If EXTRA is a list of two elements, the first element is for
-# output right after *stopped, and the second element is output
-# right after reason field.  The regex after reason should not include
+# The third element is the regular expression for the locno
+# right after bkptno field.  The locno regex should not include
 # the comma separating it from the following fields.
 #
 # When we fail to match output at all, -1 is returned.  If FILE does
@@ -1162,7 +1188,14 @@ proc mi_expect_stop { reason func args file line extra test } {
 
     set after_stopped ""
     set after_reason ""
-    if { [llength $extra] == 2 } {
+    set locno ""
+    if { [llength $extra] == 3 } {
+       set after_stopped [lindex $extra 0]
+       set after_reason [lindex $extra 1]
+       set after_reason "${after_reason},"
+       set locno [lindex $extra 2]
+       set locno "${locno},"
+    } elseif { [llength $extra] == 2 } {
        set after_stopped [lindex $extra 0]
        set after_reason [lindex $extra 1]
        set after_reason "${after_reason},"
@@ -1233,23 +1266,35 @@ proc mi_expect_stop { reason func args file line extra test } {
     set args "\\\[$args\\\]"
 
     set bn ""
+    set ebn ""
     if { $reason == "breakpoint-hit" } {
        set bn {bkptno="[0-9]+",}
+       set bn "${bn}${locno}"
     } elseif { $reason == "solib-event" } {
        set bn ".*"
+    } elseif { $reason == "exception-caught" } {
+       set ebn {bkptno="[0-9]+",}
+       set ebn "${ebn}${locno}"
+       set bn ".*"
+       set reason "breakpoint-hit"
     }
 
     set r ""
     if { $reason != "" } {
-       set r "reason=\"$reason\","
+       if { [regexp "\"" $reason] } {
+          set r "reason=$reason,"
+       } else {
+          set r "reason=\"$reason\","
+       }       
     }
 
 
     set a $after_reason
 
-    verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
+    verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
+
     gdb_expect {
-       -re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
+       -re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
            pass "$test"
            if {[array names expect_out "2,string"] != ""} {
                return $expect_out(2,string)
@@ -1257,7 +1302,7 @@ proc mi_expect_stop { reason func args file line extra test } {
            # No debug info available but $file does match.
            return 0
        }
-       -re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
+       -re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\",arch=\"$any\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
            verbose -log "got $expect_out(buffer)"
            fail "$test (stopped at wrong place)"
            return -1
@@ -1284,7 +1329,7 @@ proc mi_expect_interrupt { test } {
     if {$async} {
        set prompt_re ""
     } else {
-       set prompt_re "$mi_gdb_prompt$"
+       set prompt_re "$mi_gdb_prompt"
     }
 
     set r_nonstop "reason=\"signal-received\",signal-name=\"0\",signal-meaning=\"Signal 0\""
@@ -1299,7 +1344,7 @@ proc mi_expect_interrupt { test } {
            pass "$test"
            return 0
        }
-       -re ".*\r\n$mi_gdb_prompt$" {
+       -re ".*\r\n$mi_gdb_prompt" {
            verbose -log "got $expect_out(buffer)"
            fail "$test (unknown output after running)"
            return -1
@@ -1318,11 +1363,6 @@ proc mi_expect_interrupt { test } {
 # after the first prompt is printed.
 
 proc mi_execute_to { cmd reason func args file line extra test } {
-    global suppress_flag
-    if { $suppress_flag } {
-       return -1
-    }
-
     mi_send_resuming_command "$cmd" "$test"
     set r [mi_expect_stop $reason $func $args $file $line $extra $test]
     return $r
@@ -1349,33 +1389,6 @@ proc mi_continue_to {func} {
     mi_runto_helper $func "continue"
 }
 
-proc mi0_execute_to { cmd reason func args file line extra test } {
-    mi_execute_to_helper "$cmd" "$reason" "$func" "\{$args\}" \
-       "$file" "$line" "$extra" "$test"
-}
-
-proc mi0_next_to { func args file line test } {
-    mi0_execute_to "exec-next" "end-stepping-range" "$func" "$args" \
-       "$file" "$line" "" "$test"
-}
-
-proc mi0_step_to { func args file line test } {
-    mi0_execute_to "exec-step" "end-stepping-range" "$func" "$args" \
-       "$file" "$line" "" "$test"
-}
-
-proc mi0_finish_to { func args file line result ret test } {
-    mi0_execute_to "exec-finish" "function-finished" "$func" "$args" \
-       "$file" "$line" \
-       ",gdb-result-var=\"$result\",return-value=\"$ret\"" \
-       "$test"
-}
-
-proc mi0_continue_to { bkptno func args file line test } {
-    mi0_execute_to "exec-continue" "breakpoint-hit\",bkptno=\"$bkptno" \
-       "$func" "$args" "$file" "$line" "" "$test"
-}
-
 # Creates a breakpoint and checks the reported fields are as expected.
 # This procedure takes the same options as mi_make_breakpoint and
 # returns the breakpoint regexp from that procedure.
@@ -1386,6 +1399,23 @@ proc mi_create_breakpoint {location test args} {
     return $bp
 }
 
+# Like mi_create_breakpoint, but creates a breakpoint with multiple
+# locations using mi_make_breakpoint_multi instead.
+
+proc mi_create_breakpoint_multi {location test args} {
+    set bp [eval mi_make_breakpoint_multi $args]
+    mi_gdb_test "222-break-insert $location" "222\\^done,$bp" $test
+    return $bp
+}
+
+# Like mi_create_breakpoint, but creates a pending breakpoint.
+
+proc mi_create_breakpoint_pending {location test args} {
+    set bp [eval mi_make_breakpoint_pending $args]
+    mi_gdb_test "222-break-insert $location" ".*\r\n222\\^done,$bp" $test
+    return $bp
+}
+
 # Creates varobj named NAME for EXPRESSION.
 # Name cannot be "-".
 proc mi_create_varobj { name expression testname } {
@@ -1410,11 +1440,11 @@ proc mi_create_varobj_checked { name expression type testname } {
 }
 
 # Same as mi_create_floating_varobj, but assumes the test is creating
-# a dynamic varobj that has children, so the value must be "{...}".
-# The "has_more" attribute is checked.
-proc mi_create_dynamic_varobj {name expression has_more testname} {
+# a dynamic varobj that has children.  The "value" and "has_more"
+# attributes are checked.
+proc mi_create_dynamic_varobj {name expression value has_more testname} {
     mi_gdb_test "-var-create $name @ $expression" \
-       "\\^done,name=\"$name\",numchild=\"0\",value=\"{\\.\\.\\.}\",type=.*,has_more=\"${has_more}\"" \
+       "\\^done,name=\"$name\",numchild=\"0\",value=\"$value\",type=.*,has_more=\"${has_more}\"" \
        $testname
 }
 
@@ -1644,10 +1674,6 @@ set mi_autotest_data ""
 # The name of the source file for autotesting.
 set mi_autotest_source ""
 
-proc count_newlines { string } {
-    return [regexp -all "\n" $string]
-}
-
 # Prepares for running inline tests in FILENAME.
 # See comments for mi_run_inline_test for detailed
 # explanation of the idea and syntax.
@@ -1662,7 +1688,7 @@ proc mi_prepare_inline_tests { filename } {
 
     set mi_autotest_source $filename
 
-    if { ! [regexp "^/" "$filename"] } then {
+    if {![regexp "^/" "$filename"]} {
        set filename "$srcdir/$subdir/$filename"
     }
 
@@ -1739,13 +1765,13 @@ proc mi_get_inline_test {testcase} {
 }
 
 # Sets temporary breakpoint at LOCATION.
-proc mi_tbreak {location} {
+proc mi_tbreak {location test} {
 
     global mi_gdb_prompt
 
     mi_gdb_test "-break-insert -t $location" \
        {\^done,bkpt=.*} \
-       "run to $location (set breakpoint)"
+       $test
 }
 
 # Send COMMAND that must be a command that resumes
@@ -1801,15 +1827,16 @@ proc mi_send_resuming_command {command test} {
 # be determined.
 # Does not check that the line is the same as requested.
 # The caller can check itself if required.
-proc mi_continue_to_line {location test} {
-
-    mi_tbreak $location
-    mi_send_resuming_command "exec-continue" "run to $location (exec-continue)"
-    return [mi_get_stop_line $test]
+proc_with_prefix mi_continue_to_line {location test} {
+    with_test_prefix $test {
+       mi_tbreak $location "set temporary breakpoint"
+       mi_send_resuming_command "exec-continue" "continue to breakpoint"
+       return [mi_get_stop_line]
+    }
 }
 
 # Wait until gdb prints the current line.
-proc mi_get_stop_line {test} {
+proc mi_get_stop_line {} {
 
   global mi_gdb_prompt
   global async
@@ -1825,10 +1852,10 @@ proc mi_get_stop_line {test} {
          return $expect_out(1,string)
       }
       -re ".*$mi_gdb_prompt" {
-         fail "wait for stop ($test)"
+         fail "wait for stop (unexpected output)"
       }
       timeout {
-         fail "wait for stop ($test)"
+         fail "wait for stop (timeout)"
       }
   }
 }
@@ -1891,9 +1918,11 @@ proc mi_run_inline_test { testcase } {
 
        if {$first==1} {
            # Start the program afresh.
-           mi_tbreak "$mi_autotest_source:$line"
-           mi_run_cmd
-           set line_now [mi_get_stop_line "$testcase: step to $line"]
+           mi_tbreak "$mi_autotest_source:$line" "set temporary breakpoint"
+           if { [mi_run_cmd] < 0 } {
+               return -1
+           }
+           set line_now [mi_get_stop_line]
            set first 0
        } elseif {$line_now!=$line} {
            set line_now [mi_continue_to_line "$mi_autotest_source:$line" "continue to $line"]
@@ -1911,7 +1940,7 @@ proc mi_run_inline_test { testcase } {
        if { [mi_send_resuming_command "exec-next" "$testcase: step over $line"] != 0 } {
            return -1
        }
-       set line_now [mi_get_stop_line "$testcase: step over $line"]
+       set line_now [mi_get_stop_line]
 
        # We probably want to use 'uplevel' so that statements
        # have direct access to global variables that the
@@ -1919,6 +1948,8 @@ proc mi_run_inline_test { testcase } {
        # will need more experience to be sure.
        eval $statements
     }
+
+    return 0
 }
 
 proc get_mi_thread_list {name} {
@@ -2056,20 +2087,38 @@ proc check_mi_and_console_threads {name} {
   }
 }
 
+# Set solib-search-path to allow gdb to locate shlib FILE.
+proc mi_locate_shlib { file } {
+    global mi_spawn_id
+
+    if ![info exists mi_spawn_id] {
+       perror "mi_locate_shlib: GDB is not running"
+    }
+
+    # If the target is remote, we need to tell gdb where to find the
+    # libraries.
+    if { ![is_remote target] } {
+       return
+    }
+
+    # We could set this even when not testing remotely, but a user
+    # generally won't set it unless necessary.  In order to make the tests
+    # more like the real-life scenarios, we don't set it for local testing.
+    mi_gdb_test "set solib-search-path [file dirname $file]" "\^done" ""
+}
+
+# Copy shlib FILE to the target and set solib-search-path to allow gdb to
+# locate it.
+proc mi_load_shlib { file } {
+    set dest [gdb_download_shlib $file]
+    mi_locate_shlib $file
+    return $dest
+}
+
 # Download shared libraries to the target.
 proc mi_load_shlibs { args } {
     foreach file $args {
-       gdb_remote_download target [shlib_target_file $file]
-    }
-
-    if {[is_remote target]} {
-       # If the target is remote, we need to tell gdb where to find the
-       # libraries.
-       #
-       # We could set this even when not testing remotely, but a user
-       # generally won't set it unless necessary.  In order to make the tests
-       # more like the real-life scenarios, we don't set it for local testing.
-       mi_gdb_test "set solib-search-path [file dirname [lindex $args 0]]" "\^done" ""
+       mi_load_shlib $file
     }
 }
 
@@ -2487,40 +2536,61 @@ proc mi_build_kv_pairs {attr_list {joiner ,}} {
     return "[join $l $joiner]"
 }
 
-# Construct a breakpoint regexp.  This may be used to test the output of
-# -break-insert, -dprintf-insert, or -break-info.
+# Construct a breakpoint location regexp.  This may be used along with
+# mi_make_breakpoint_multi to test the output of -break-insert,
+# -dprintf-insert, or -break-info with breapoints with multiple
+# locations.
 #
-# All arguments for the breakpoint may be specified using the options
-# number, type, disp, enabled, addr, func, file, fullanme, line,
-# thread-groups, cond, evaluated-by, times, ignore, script,
-# and original-location.
+# All arguments for the breakpoint location may be specified using the
+# options: number, enabled, addr, func, file, fullname, line, inferior
+# thread-groups, and thread.
 #
-# Only if -script and -ignore are given will they appear in the output.
-# Otherwise, this procedure will skip them using ".*".
+# For the option -thread the corresponding output field is only added
+# if the option is present and not set to the empty string.
 #
-# Example: mi_make_breakpoint -number 2 -file ".*/myfile.c" -line 3
-# will return the breakpoint:
-# bkpt={number="2",type=".*",disp=".*",enabled=".*",addr=".*",func=".*",
-#       file=".*/myfile.c",fullname=".*",line="3",thread-groups=\[.*\],
-#       times="0".*original-location=".*"}
+# Example: mi_make_breakpoint_loc -number 2.1 -file ".*/myfile.c" -line 3
+# will return the breakpoint location:
+# {number="2.1",enabled=".*",addr=".*",func=".*",
+#       file=".*/myfile.c",fullname=".*",line="3",thread-groups=\[.*\]}
 
-proc mi_make_breakpoint {args} {
-    parse_args {{number .*} {type .*} {disp .*} {enabled .*} {addr .*}
+proc mi_make_breakpoint_loc {args} {
+    parse_args {{number .*} {enabled .*} {addr .*}
        {func .*} {file .*} {fullname .*} {line .*}
-       {thread-groups \\\[.*\\\]} {times .*} {ignore 0}
-       {script ""} {original-location .*} {cond ""} {evaluated-by ""}}
+       {thread-groups \\\[.*\\\]} {thread ""} {inferior ""}}
 
     set attr_list {}
-    foreach attr [list number type disp enabled addr func file \
-                     fullname line thread-groups] {
-       lappend attr_list $attr [set $attr]
+    foreach attr [list number enabled addr func file \
+                     fullname line thread-groups inferior] {
+       if {$attr ne "inferior" || [set $attr] ne ""} {
+           lappend attr_list $attr [set $attr]
+       }
     }
 
-    set result "bkpt={[mi_build_kv_pairs $attr_list]"
+    set result [mi_build_kv_pairs $attr_list]
+
+    if {[string length $thread] > 0} {
+       append result ","
+       append result [mi_build_kv_pairs [list "thread" $thread]]
+    }
+
+    return "{$result}"
+}
+
+# Bits shared between mi_make_breakpoint and mi_make_breakpoint_multi.
+
+proc mi_make_breakpoint_1 {attr_list thread cond evaluated-by times \
+                          ignore script original-location} {
+    set result "bkpt=\\\{[mi_build_kv_pairs $attr_list]"
 
     # There are always exceptions.
 
-    # If COND is not preset, do not output it.
+    # If THREAD is not present, do not output it.
+    if {[string length $thread] > 0} {
+       append result ","
+       append result [mi_build_kv_pairs [list "thread" $thread]]
+    }
+
+    # If COND is not present, do not output it.
     if {[string length $cond] > 0} {
        append result ","
        append result [mi_build_kv_pairs [list "cond" $cond]]
@@ -2556,7 +2626,143 @@ proc mi_make_breakpoint {args} {
     }
     append result [mi_build_kv_pairs \
                       [list "original-location" ${original-location}]]
-    append result "}"
+
+    return $result
+}
+
+
+# Construct a breakpoint regexp, for a breakpoint with multiple
+# locations.  This may be used to test the output of -break-insert,
+# -dprintf-insert, or -break-info with breakpoints with multiple
+# locations.
+#
+# All arguments for the breakpoint may be specified using the options:
+# number, type, disp, enabled, times, ignore, script, inferior,
+# original-location, cond, evaluated-by, locations, and thread.
+#
+# Only if -script and -ignore are given will they appear in the output.
+# Otherwise, this procedure will skip them using ".*".
+#
+# For the options -thread and -cond the corresponding output fields
+# are only added if the options are present and not set to the empty
+# string.
+#
+# Example: mi_make_breakpoint_multi -number 2 -locations "$loc"
+# will return the breakpoint:
+# bkpt={number="2",type=".*",disp=".*",enabled=".*",addr="<MULTIPLE>",
+#       times="0".*original-location=".*",locations=$loc}
+#
+# You can construct the list of locations with mi_make_breakpoint_loc.
+
+proc mi_make_breakpoint_multi {args} {
+    parse_args {{number .*} {type .*} {disp .*} {enabled .*}
+       {times .*} {ignore 0}
+       {script ""} {original-location .*} {cond ""} {evaluated-by ""}
+       {locations .*} {thread ""} {inferior ""}}
+
+    set attr_list {}
+    foreach attr [list number type disp enabled] {
+       lappend attr_list $attr [set $attr]
+    }
+
+    lappend attr_list "addr" "<MULTIPLE>"
+
+    # Only include the inferior field if it was set.  This field is
+    # optional in the MI output.
+    if {$inferior ne ""} {
+       lappend attr_list "inferior" $inferior
+    }
+
+    set result [mi_make_breakpoint_1 \
+                   $attr_list $thread $cond ${evaluated-by} $times \
+                   $ignore $script ${original-location}]
+
+    append result ","
+    append result [mi_build_kv_pairs [list "locations" $locations]]
+
+    append result "\\\}"
+    return $result
+}
+
+# Construct a breakpoint regexp, for a pending breakpoint.  This may
+# be used to test the output of -break-insert, -dprintf-insert, or
+# -break-info for pending breakpoints.
+#
+# Arguments for the breakpoint may be specified using the options:
+# number, type, disp, enabled, pending, original-location, thread, and
+# cond.
+#
+# For the options -thread and -cond the corresponding output fields
+# are only included if the options are present and not the empty
+# string.
+#
+# Example: mi_make_breakpoint_pending -number 2 -pending func
+# will return the breakpoint:
+# bkpt={number="2",type=".*",disp=".*",enabled=".*",addr="<PENDING>",
+#       pending="func", times="0".*original-location=".*"}
+
+proc mi_make_breakpoint_pending {args} {
+    parse_args {{number .*} {type .*} {disp .*} {enabled .*}
+       {pending .*} {original-location .*} {thread ""} {cond ""}
+       {script ""} {times .*}}
+
+    set attr_list {}
+    foreach attr [list number type disp enabled] {
+       lappend attr_list $attr [set $attr]
+    }
+
+    lappend attr_list "addr" "<PENDING>"
+
+    foreach attr [list pending] {
+       lappend attr_list $attr [set $attr]
+    }
+
+    set ignore 0
+    set evaluated-by ""
+
+    set result [mi_make_breakpoint_1 \
+                   $attr_list $thread $cond ${evaluated-by} $times \
+                   $ignore $script ${original-location}]
+
+    append result "\\\}"
+    return $result
+}
+
+# Construct a breakpoint regexp.  This may be used to test the output of
+# -break-insert, -dprintf-insert, or -break-info.
+#
+# All arguments for the breakpoint may be specified using the options
+# number, type, disp, enabled, addr, func, file, fullanme, line,
+# thread-groups, cond, evaluated-by, times, ignore, script,
+# and original-location.
+#
+# Only if -script and -ignore are given will they appear in the output.
+# Otherwise, this procedure will skip them using ".*".
+#
+# Example: mi_make_breakpoint -number 2 -file ".*/myfile.c" -line 3
+# will return the breakpoint:
+# bkpt={number="2",type=".*",disp=".*",enabled=".*",addr=".*",func=".*",
+#       file=".*/myfile.c",fullname=".*",line="3",thread-groups=\[.*\],
+#       times="0".*original-location=".*"}
+
+proc mi_make_breakpoint {args} {
+    parse_args {{number .*} {type .*} {disp .*} {enabled .*} {addr .*}
+       {func .*} {file .*} {fullname .*} {line .*}
+       {thread-groups \\\[.*\\\]} {times .*} {ignore 0}
+       {script ""} {original-location .*} {cond ""} {evaluated-by ""}
+       {thread ""}}
+
+    set attr_list {}
+    foreach attr [list number type disp enabled addr func file \
+                     fullname line thread-groups] {
+       lappend attr_list $attr [set $attr]
+    }
+
+    set result [mi_make_breakpoint_1 \
+                   $attr_list $thread $cond ${evaluated-by} $times \
+                   $ignore $script ${original-location}]
+
+    append result "\\\}"
     return $result
 }
 
@@ -2599,13 +2805,11 @@ proc mi_make_breakpoint_table {bp_list} {
     return "BreakpointTable={nr_rows=\"$nr\",nr_cols=\"$nc\",$header,$body}"
 }
 
-# Return a 1 for configurations that do not support Python scripting.
-# Note: This also sets various globals that specify which version of Python
-# is in use.  See skip_python_tests_prompt.
+# As skip_libstdcxx_probe_tests_prompt, with mi_gdb_prompt.
 
-proc mi_skip_python_tests {} {
+proc mi_skip_libstdcxx_probe_tests {} {
     global mi_gdb_prompt
-    return [skip_python_tests_prompt "$mi_gdb_prompt$"]
+    return [skip_libstdcxx_probe_tests_prompt "$mi_gdb_prompt$"]
 }
 
 # Check whether we're testing with the remote or extended-remote
@@ -2616,3 +2820,74 @@ proc mi_is_target_remote {} {
 
     return [gdb_is_target_remote_prompt "$mi_gdb_prompt"]
 }
+
+# Retrieve the value of EXP in the inferior, represented in format
+# specified in FMT (using "printFMT").  DEFAULT is used as fallback if
+# print fails.  TEST is the test message to use.  It can be omitted,
+# in which case a test message is built from EXP.
+#
+# This is an MI version of gdb_valueof.
+
+proc mi_get_valueof { fmt exp default {test ""} } {
+    global mi_gdb_prompt
+
+    if {$test == "" } {
+       set test "get valueof \"${exp}\""
+    }
+
+    set val ${default}
+    gdb_test_multiple "print${fmt} ${exp}" "$test" -prompt "$::mi_gdb_prompt$" {
+       -re "~\"\\$\[0-9\]* = (\[^\r\n\]*)\\\\n\"\r\n\\^done\r\n$mi_gdb_prompt$" {
+           set val $expect_out(1,string)
+           pass "$test"
+       }
+       timeout {
+           fail "$test (timeout)"
+       }
+    }
+    return ${val}
+}
+
+# Some MI tests should be run in the normal way, on the main UI, while
+# other tests should be run twice, once when the MI is on the main UI,
+# and once with the MI on a secondary UI, this proc facilitates that.
+#
+# Use as:
+#
+#   foreach_mi_ui_mode mode {
+#     # ... body ...
+#   }
+#
+# The BODY will then be run once with MODE set to 'main' and once with
+# MODE set to 'separate'.
+#
+# However, there are times when we know using the 'separate' UI will
+# not work.  This proc handles figuring that out, if the 'separate' UI
+# is known not to work then the 'separate' mode will be skipped and
+# BODY will be run just once with MODE set to 'main'.
+
+proc foreach_mi_ui_mode { var_name body } {
+    upvar 1 $var_name var
+
+    if [gdb_debug_enabled] {
+       # gdb debug doesn't work for separate-mi-tty.
+       set modes {"main"}
+    } else {
+       set modes {"main" "separate"}
+    }
+
+    foreach var $modes {
+       with_test_prefix "$var_name=$var" {
+           set code [catch {uplevel 1 $body} result]
+       }
+
+       if {$code == 1} {
+           global errorInfo errorCode
+           return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+       } elseif {$code == 3} {
+           break
+       } elseif {$code == 2} {
+           return -code $code $result
+       }
+    }
+}