GDB copyright headers update after running GDB's copyright.py script.
[deliverable/binutils-gdb.git] / gdb / testsuite / lib / gdb.exp
index dcc2f942975c1d91ad5fe50b1acb8aef0c6fe319..015e20225dc3b8b80cd76c1bd0230784cf6ad31a 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 1992-2015 Free Software Foundation, Inc.
+# Copyright 1992-2016 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
@@ -31,6 +31,14 @@ load_lib gdb-utils.exp
 
 global GDB
 
+# The spawn ID used for I/O interaction with the inferior.  For native
+# targets, or remote targets that can do I/O through GDB
+# (semi-hosting) this will be the same as the host/GDB's spawn ID.
+# Otherwise, the board may set this to some other spawn ID.  E.g.,
+# when debugging with GDBserver, this is set to GDBserver's spawn ID,
+# so input/output is done on gdbserver's tty.
+global inferior_spawn_id
+
 if [info exists TOOL_EXECUTABLE] {
     set GDB $TOOL_EXECUTABLE
 }
@@ -181,25 +189,35 @@ proc delete_breakpoints {} {
     # we need a larger timeout value here or this thing just confuses
     # itself.  May need a better implementation if possible. - guo
     #
-    send_gdb "delete breakpoints\n"
-    gdb_expect 100 {
-        -re "Delete all breakpoints.*y or n.*$" {
+    set timeout 100
+
+    set msg "delete all breakpoints in delete_breakpoints"
+    set deleted 0
+    gdb_test_multiple "delete breakpoints" "$msg" {
+       -re "Delete all breakpoints.*y or n.*$" {
            send_gdb "y\n"
            exp_continue
        }
-        -re "$gdb_prompt $" { # This happens if there were no breakpoints
-           }
-        timeout { perror "Delete all breakpoints in delete_breakpoints (timeout)" ; return }
+       -re "$gdb_prompt $" {
+           set deleted 1
+       }
     }
-    send_gdb "info breakpoints\n"
-    gdb_expect 100 {
-        -re "No breakpoints or watchpoints..*$gdb_prompt $" {}
-        -re "$gdb_prompt $" { perror "breakpoints not deleted" ; return }
-        -re "Delete all breakpoints.*or n.*$" {
-           send_gdb "y\n"
-           exp_continue
+
+    if {$deleted} {
+       # Confirm with "info breakpoints".
+       set deleted 0
+       set msg "info breakpoints"
+       gdb_test_multiple $msg $msg {
+           -re "No breakpoints or watchpoints..*$gdb_prompt $" {
+               set deleted 1
+           }
+           -re "$gdb_prompt $" {
+           }
        }
-        timeout { perror "info breakpoints (timeout)" ; return }
+    }
+
+    if {!$deleted} {
+       perror "breakpoints not deleted"
     }
 }
 
@@ -646,16 +664,35 @@ proc gdb_internal_error_resync {} {
 #    }
 # }
 #
+# Like with "expect", you can also specify the spawn id to match with
+# -i "$id".  Interesting spawn ids are $inferior_spawn_id and
+# $gdb_spawn_id.  The former matches inferior I/O, while the latter
+# matches GDB I/O.  E.g.:
+#
+# send_inferior "hello\n"
+# gdb_test_multiple "continue" "test echo" {
+#    -i "$inferior_spawn_id" -re "^hello\r\nhello\r\n$" {
+#        pass "got echo"
+#    }
+#    -i "$gdb_spawn_id" -re "Breakpoint.*$gdb_prompt $" {
+#        fail "hit breakpoint"
+#    }
+# }
+#
 # The standard patterns, such as "Inferior exited..." and "A problem
-# ...", all being implicitly appended to that list.
+# ...", all being implicitly appended to that list.  These are always
+# expected from $gdb_spawn_id.  IOW, callers do not need to worry
+# about resetting "-i" back to $gdb_spawn_id explicitly.
 #
 proc gdb_test_multiple { command message user_code } {
     global verbose use_gdb_stub
     global gdb_prompt pagination_prompt
     global GDB
+    global gdb_spawn_id
     global inferior_exited_re
     upvar timeout timeout
     upvar expect_out expect_out
+    global any_spawn_id
 
     if { $message == "" } {
        set message $command
@@ -713,14 +750,14 @@ proc gdb_test_multiple { command message user_code } {
            lappend processed_code $item
            continue
        }
-       if { $item == "-timeout" } {
+       if { $item == "-timeout" || $item == "-i" } {
            set expecting_arg 1
            lappend processed_code $item
            continue
        }
        if { $expecting_arg } {
            set expecting_arg 0
-           lappend processed_code $item
+           lappend processed_code $subst_item
            continue
        }
        if { $expecting_action } {
@@ -798,6 +835,7 @@ proc gdb_test_multiple { command message user_code } {
        -re ".*A problem internal to GDB has been detected" {
            fail "$message (GDB internal error)"
            gdb_internal_error_resync
+           set result -1
        }
        -re "\\*\\*\\* DOSEXIT code.*" {
            if { $message != "" } {
@@ -809,6 +847,9 @@ proc gdb_test_multiple { command message user_code } {
     }
     append code $processed_code
     append code {
+       # Reset the spawn id, in case the processed code used -i.
+       -i "$gdb_spawn_id"
+
        -re "Ending remote debugging.*$gdb_prompt $" {
            if ![isnative] then {
                warning "Can`t communicate to remote target."
@@ -878,6 +919,9 @@ proc gdb_test_multiple { command message user_code } {
            fail "$message (got breakpoint menu)"
            set result -1
        }
+
+       # Patterns below apply to any spawn id specified.
+       -i $any_spawn_id
        eof {
            perror "Process no longer exists"
            if { $message != "" } {
@@ -915,7 +959,9 @@ proc gdb_test_multiple { command message user_code } {
 # 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.
+#   the \r\n sequence immediately before the gdb prompt.  This argument
+#   may be omitted to just match the prompt, ignoring whatever output 
+#   precedes it.
 # MESSAGE is an optional message to be printed.  If this is
 #   omitted, then the pass/fail messages use the command string as the
 #   message.  (If this is the empty string, then sometimes we don't
@@ -1186,6 +1232,73 @@ proc gdb_test_list_exact { cmd name elm_find_regexp elm_extract_regexp result_ma
        }
     }
 }
+
+# gdb_test_stdio COMMAND INFERIOR_PATTERN GDB_PATTERN MESSAGE
+# Send a command to gdb; expect inferior and gdb output.
+#
+# See gdb_test_multiple for a description of the COMMAND and MESSAGE
+# parameters.
+#
+# INFERIOR_PATTERN is the pattern to match against inferior output.
+#
+# GDB_PATTERN is the pattern to match against gdb output, and must NOT
+# include the \r\n sequence immediately before the gdb prompt, nor the
+# prompt.  The default is empty.
+#
+# Both inferior and gdb patterns must match for a PASS.
+#
+# If MESSAGE is ommitted, then COMMAND will be used as the message.
+#
+# Returns:
+#    1 if the test failed,
+#    0 if the test passes,
+#   -1 if there was an internal error.
+#
+
+proc gdb_test_stdio {command inferior_pattern {gdb_pattern ""} {message ""}} {
+    global inferior_spawn_id gdb_spawn_id
+    global gdb_prompt
+
+    if {$message == ""} {
+       set message $command
+    }
+
+    set inferior_matched 0
+    set gdb_matched 0
+
+    # Use an indirect spawn id list, and remove the inferior spawn id
+    # from the expected output as soon as it matches, in case
+    # $inferior_pattern happens to be a prefix of the resulting full
+    # gdb pattern below (e.g., "\r\n").
+    global gdb_test_stdio_spawn_id_list
+    set gdb_test_stdio_spawn_id_list "$inferior_spawn_id"
+
+    # Note that if $inferior_spawn_id and $gdb_spawn_id are different,
+    # then we may see gdb's output arriving before the inferior's
+    # output.
+    set res [gdb_test_multiple $command $message {
+       -i gdb_test_stdio_spawn_id_list -re "$inferior_pattern" {
+           set inferior_matched 1
+           if {!$gdb_matched} {
+               set gdb_test_stdio_spawn_id_list ""
+               exp_continue
+           }
+       }
+       -i $gdb_spawn_id -re "$gdb_pattern\r\n$gdb_prompt $" {
+           set gdb_matched 1
+           if {!$inferior_matched} {
+               exp_continue
+           }
+       }
+    }]
+    if {$res == 0} {
+       pass $message
+    } else {
+       verbose -log "inferior_matched=$inferior_matched, gdb_matched=$gdb_matched"
+    }
+    return $res
+}
+
 \f
 
 # Issue a PASS and return true if evaluating CONDITION in the caller's
@@ -1444,7 +1557,8 @@ proc default_gdb_spawn { } {
        perror "Spawning $GDB failed."
        return 1
     }
-    set gdb_spawn_id -1
+
+    set gdb_spawn_id $res
     return 0
 }
 
@@ -1453,6 +1567,7 @@ proc default_gdb_spawn { } {
 proc default_gdb_start { } {
     global gdb_prompt pagination_prompt
     global gdb_spawn_id
+    global inferior_spawn_id
 
     if [info exists gdb_spawn_id] {
        return 0
@@ -1463,6 +1578,11 @@ proc default_gdb_start { } {
        return $res
     }
 
+    # Default to assuming inferior I/O is done on GDB's terminal.
+    if {![info exists inferior_spawn_id]} {
+       set inferior_spawn_id $gdb_spawn_id
+    }
+
     # When running over NFS, particularly if running many simultaneous
     # tests on different hosts all using the same server, things can
     # get really slow.  Give gdb at least 3 minutes to start up.
@@ -1516,6 +1636,24 @@ proc default_gdb_start { } {
     return 0
 }
 
+# Utility procedure to give user control of the gdb prompt in a script. It is
+# meant to be used for debugging test cases, and should not be left in the
+# test cases code.
+
+proc gdb_interact { } {
+    global gdb_spawn_id
+    set spawn_id $gdb_spawn_id
+
+    send_user "+------------------------------------------+\n"
+    send_user "| Script interrupted, you can now interact |\n"
+    send_user "| with by gdb. Type >>> to continue.       |\n"
+    send_user "+------------------------------------------+\n"
+
+    interact {
+       ">>>" return
+    }
+}
+
 # Examine the output of compilation to determine whether compilation
 # failed or not.  If it failed determine whether it is due to missing
 # compiler or due to compiler error.  Report pass, fail or unsupported
@@ -1598,35 +1736,35 @@ proc skip_d_tests {} {
 }
 
 # Return a 1 for configurations that do not support Python scripting.
+# PROMPT_REGEXP is the expected prompt.
 
-proc skip_python_tests {} {
-    global gdb_prompt
+proc skip_python_tests_prompt { prompt_regexp } {
     global gdb_py_is_py3k
     global gdb_py_is_py24
 
     gdb_test_multiple "python print ('test')" "verify python support" {
-       -re "not supported.*$gdb_prompt $"      {
+       -re "not supported.*$prompt_regexp" {
            unsupported "Python support is disabled."
            return 1
        }
-       -re "$gdb_prompt $"     {}
+       -re "$prompt_regexp" {}
     }
 
     set gdb_py_is_py24 0
     gdb_test_multiple "python print (sys.version_info\[0\])" "check if python 3" {
-       -re "3.*$gdb_prompt $"  {
+       -re "3.*$prompt_regexp" {
             set gdb_py_is_py3k 1
         }
-       -re ".*$gdb_prompt $"   {
+       -re ".*$prompt_regexp" {
             set gdb_py_is_py3k 0
         }
     }
     if { $gdb_py_is_py3k == 0 } {
         gdb_test_multiple "python print (sys.version_info\[1\])" "check if python 2.4" {
-           -re "\[45\].*$gdb_prompt $" {
+           -re "\[45\].*$prompt_regexp" {
                 set gdb_py_is_py24 1
             }
-           -re ".*$gdb_prompt $" {
+           -re ".*$prompt_regexp" {
                 set gdb_py_is_py24 0
             }
         }
@@ -1635,6 +1773,15 @@ proc skip_python_tests {} {
     return 0
 }
 
+# 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.
+
+proc skip_python_tests {} {
+    global gdb_prompt
+    return [skip_python_tests_prompt "$gdb_prompt $"]
+}
+
 # Return a 1 if we should skip shared library tests.
 
 proc skip_shlib_tests {} {
@@ -1658,6 +1805,22 @@ proc skip_shlib_tests {} {
     return 1
 }
 
+# Return 1 if we should skip tui related tests.
+
+proc skip_tui_tests {} {
+    global gdb_prompt
+
+    gdb_test_multiple "help layout" "verify tui support" {
+       -re "Undefined command: \"layout\".*$gdb_prompt $" {
+           return 1
+       }
+       -re "$gdb_prompt $" {
+       }
+    }
+
+    return 0
+}
+
 # Test files shall make sure all the test result lines in gdb.sum are
 # unique in a test run, so that comparing the gdb.sum files of two
 # test runs gives correct results.  Test files that exercise
@@ -1745,6 +1908,73 @@ proc with_test_prefix { prefix body } {
   }
 }
 
+# Run BODY in the context of the caller.  After BODY is run, the variables
+# listed in VARS will be reset to the values they had before BODY was run.
+#
+# This is useful for providing a scope in which it is safe to temporarily
+# modify global variables, e.g.
+#
+#   global INTERNAL_GDBFLAGS
+#   global env
+#
+#   set foo GDBHISTSIZE
+#
+#   save_vars { INTERNAL_GDBFLAGS env($foo) env(HOME) } {
+#       append INTERNAL_GDBFLAGS " -nx"
+#       unset -nocomplain env(GDBHISTSIZE)
+#       gdb_start
+#       gdb_test ...
+#   }
+#
+# Here, although INTERNAL_GDBFLAGS, env(GDBHISTSIZE) and env(HOME) may be
+# modified inside BODY, this proc guarantees that the modifications will be
+# undone after BODY finishes executing.
+
+proc save_vars { vars body } {
+    array set saved_scalars { }
+    array set saved_arrays { }
+    set unset_vars { }
+
+    foreach var $vars {
+       # First evaluate VAR in the context of the caller in case the variable
+       # name may be a not-yet-interpolated string like env($foo)
+       set var [uplevel 1 list $var]
+
+       if [uplevel 1 [list info exists $var]] {
+           if [uplevel 1 [list array exists $var]] {
+               set saved_arrays($var) [uplevel 1 [list array get $var]]
+           } else {
+               set saved_scalars($var) [uplevel 1 [list set $var]]
+           }
+       } else {
+           lappend unset_vars $var
+       }
+    }
+
+    set code [catch {uplevel 1 $body} result]
+
+    foreach {var value} [array get saved_scalars] {
+       uplevel 1 [list set $var $value]
+    }
+
+    foreach {var value} [array get saved_arrays] {
+       uplevel 1 [list unset $var]
+       uplevel 1 [list array set $var $value]
+    }
+
+    foreach var $unset_vars {
+       uplevel 1 [list unset -nocomplain $var]
+    }
+
+    if {$code == 1} {
+       global errorInfo errorCode
+       return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+    } else {
+       return -code $code $result
+    }
+}
+
+
 # Run tests in BODY with GDB prompt and variable $gdb_prompt set to
 # PROMPT.  When BODY is finished, restore GDB prompt and variable
 # $gdb_prompt.
@@ -1829,6 +2059,54 @@ proc with_target_charset { target_charset body } {
     }
 }
 
+# Select the largest timeout from all the timeouts:
+# - the local "timeout" variable of the scope two levels above,
+# - the global "timeout" variable,
+# - the board variable "gdb,timeout".
+
+proc get_largest_timeout {} {
+    upvar #0 timeout gtimeout
+    upvar 2 timeout timeout
+
+    set tmt 0
+    if [info exists timeout] {
+      set tmt $timeout
+    }
+    if { [info exists gtimeout] && $gtimeout > $tmt } {
+       set tmt $gtimeout
+    }
+    if { [target_info exists gdb,timeout]
+        && [target_info gdb,timeout] > $tmt } {
+       set tmt [target_info gdb,timeout]
+    }
+    if { $tmt == 0 } {
+       # Eeeeew.
+       set tmt 60
+    }
+
+    return $tmt
+}
+
+# Run tests in BODY with timeout increased by factor of FACTOR.  When
+# BODY is finished, restore timeout.
+
+proc with_timeout_factor { factor body } {
+    global timeout
+
+    set savedtimeout $timeout
+
+    set timeout [expr [get_largest_timeout] * $factor]
+    set code [catch {uplevel 1 $body} result]
+
+    set timeout $savedtimeout
+    if {$code == 1} {
+       global errorInfo errorCode
+       return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
+    } else {
+       return -code $code $result
+    }
+}
+
 # Return 1 if _Complex types are supported, otherwise, return 0.
 
 gdb_caching_proc support_complex_tests {
@@ -1863,15 +2141,21 @@ gdb_caching_proc support_complex_tests {
     return $result
 }
 
-# Return 1 if target hardware or OS supports single stepping to signal
-# handler, otherwise, return 0.
+# Return 1 if GDB can get a type for siginfo from the target, otherwise
+# return 0.
 
-proc can_single_step_to_signal_handler {} {
+proc supports_get_siginfo_type {} {
+    if { [istarget "*-*-linux*"] } {
+       return 1
+    } else {
+       return 0
+    }
+}
+
+# Return 1 if the target supports hardware single stepping.
+
+proc can_hardware_single_step {} {
 
-    # Targets don't have hardware single step.  On these targets, when
-    # a signal is delivered during software single step, gdb is unable
-    # to determine the next instruction addresses, because start of signal
-    # handler is one of them.
     if { [istarget "arm*-*-*"] || [istarget "mips*-*-*"]
         || [istarget "tic6x-*-*"] || [istarget "sparc*-*-linux*"]
         || [istarget "nios2-*-*"] } {
@@ -1881,6 +2165,17 @@ proc can_single_step_to_signal_handler {} {
     return 1
 }
 
+# Return 1 if target hardware or OS supports single stepping to signal
+# handler, otherwise, return 0.
+
+proc can_single_step_to_signal_handler {} {
+    # Targets don't have hardware single step.  On these targets, when
+    # a signal is delivered during software single step, gdb is unable
+    # to determine the next instruction addresses, because start of signal
+    # handler is one of them.
+    return [can_hardware_single_step]
+}
+
 # Return 1 if target supports process record, otherwise return 0.
 
 proc supports_process_record {} {
@@ -1890,7 +2185,10 @@ proc supports_process_record {} {
     }
 
     if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
-         || [istarget "i\[34567\]86-*-linux*"] } {
+         || [istarget "i\[34567\]86-*-linux*"]
+         || [istarget "aarch64*-*-linux*"]
+         || [istarget "powerpc*-*-linux*"]
+         || [istarget "s390*-*-linux*"] } {
        return 1
     }
 
@@ -1906,7 +2204,10 @@ proc supports_reverse {} {
     }
 
     if { [istarget "arm*-*-linux*"] || [istarget "x86_64-*-linux*"]
-         || [istarget "i\[34567\]86-*-linux*"] } {
+         || [istarget "i\[34567\]86-*-linux*"]
+         || [istarget "aarch64*-*-linux*"]
+         || [istarget "powerpc*-*-linux*"]
+         || [istarget "s390*-*-linux*"] } {
        return 1
     }
 
@@ -2123,12 +2424,60 @@ proc is_x86_like_target {} {
     return [expr [is_ilp32_target] && ![is_amd64_regs_target]]
 }
 
+# Return 1 if this target is an arm or aarch32 on aarch64.
+
+gdb_caching_proc is_aarch32_target {
+    if { [istarget "arm*-*-*"] } {
+       return 1
+    }
+
+    if { ![istarget "aarch64*-*-*"] } {
+       return 0
+    }
+
+    set me "is_aarch32_target"
+
+    set src [standard_temp_file aarch32[pid].s]
+    set obj [standard_temp_file aarch32[pid].o]
+
+    set list {}
+    foreach reg \
+       {r0 r1 r2 r3} {
+           lappend list "\tmov $reg, $reg"
+       }
+    gdb_produce_source $src [join $list \n]
+
+    verbose "$me:  compiling testfile $src" 2
+    set lines [gdb_compile $src $obj object {quiet}]
+    file delete $src
+    file delete $obj
+
+    if ![string match "" $lines] then {
+       verbose "$me:  testfile compilation failed, returning 0" 2
+       return 0
+    }
+
+    verbose "$me:  returning 1" 2
+    return 1
+}
+
+# Return 1 if this target is an aarch64, either lp64 or ilp32.
+
+proc is_aarch64_target {} {
+    if { ![istarget "aarch64*-*-*"] } {
+       return 0
+    }
+
+    return [expr ![is_aarch32_target]]
+}
+
 # Return 1 if displaced stepping is supported on target, otherwise, return 0.
 proc support_displaced_stepping {} {
 
     if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"]
         || [istarget "arm*-*-linux*"] || [istarget "powerpc-*-linux*"]
-        || [istarget "powerpc64-*-linux*"] || [istarget "s390*-*-*"] } {
+        || [istarget "powerpc64-*-linux*"] || [istarget "s390*-*-*"]
+        || [istarget "aarch64*-*-linux*"] } {
        return 1
     }
 
@@ -2300,6 +2649,63 @@ gdb_caching_proc skip_vsx_tests {
     return $skip_vsx_tests
 }
 
+# Run a test on the target to see if it supports TSX hardware.  Return 0 if so,
+# 1 if it does not.  Based on 'check_vmx_hw_available' from the GCC testsuite.
+
+gdb_caching_proc skip_tsx_tests {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "skip_tsx_tests"
+
+    set src [standard_temp_file tsx[pid].c]
+    set exe [standard_temp_file tsx[pid].x]
+
+    gdb_produce_source $src {
+    int main() {
+        asm volatile ("xbegin .L0");
+        asm volatile ("xend");
+        asm volatile (".L0: nop");
+        return 0;
+    }
+    }
+
+    verbose "$me:  compiling testfile $src" 2
+    set lines [gdb_compile $src $exe executable {nowarnings quiet}]
+    file delete $src
+
+    if ![string match "" $lines] then {
+        verbose "$me:  testfile compilation failed." 2
+        return 1
+    }
+
+    # No error message, compilation succeeded so now run it via gdb.
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load "$exe"
+    gdb_run_cmd
+    gdb_expect {
+        -re ".*Illegal instruction.*${gdb_prompt} $" {
+            verbose -log "$me:  TSX hardware not detected."
+            set skip_tsx_tests 1
+        }
+        -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+            verbose -log "$me:  TSX hardware detected."
+            set skip_tsx_tests 0
+        }
+        default {
+            warning "\n$me:  default case taken."
+            set skip_tsx_tests 1
+        }
+    }
+    gdb_exit
+    remote_file build delete $exe
+
+    verbose "$me:  returning $skip_tsx_tests" 2
+    return $skip_tsx_tests
+}
+
 # Run a test on the target to see if it supports btrace hardware.  Return 0 if so,
 # 1 if it does not.  Based on 'check_vmx_hw_available' from the GCC testsuite.
 
@@ -2366,13 +2772,74 @@ gdb_caching_proc skip_btrace_tests {
     return $skip_btrace_tests
 }
 
-# Skip all the tests in the file if you are not on an hppa running
-# hpux target.
+# Run a test on the target to see if it supports btrace pt hardware.
+# Return 0 if so, 1 if it does not.  Based on 'check_vmx_hw_available'
+# from the GCC testsuite.
+
+gdb_caching_proc skip_btrace_pt_tests {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "skip_btrace_tests"
+    if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } {
+        verbose "$me:  target does not support btrace, returning 1" 2
+        return 1
+    }
+
+    # Set up, compile, and execute a test program.
+    # Include the current process ID in the file names to prevent conflicts
+    # with invocations for multiple testsuites.
+    set src [standard_temp_file btrace[pid].c]
+    set exe [standard_temp_file btrace[pid].x]
+
+    gdb_produce_source $src {
+       int main(void) { return 0; }
+    }
+
+    verbose "$me:  compiling testfile $src" 2
+    set compile_flags {debug nowarnings quiet}
+    set lines [gdb_compile $src $exe executable $compile_flags]
+
+    if ![string match "" $lines] then {
+        verbose "$me:  testfile compilation failed, returning 1" 2
+       file delete $src
+        return 1
+    }
+
+    # No error message, compilation succeeded so now run it via gdb.
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load $exe
+    if ![runto_main] {
+       file delete $src
+        return 1
+    }
+    file delete $src
+    # In case of an unexpected output, we return 2 as a fail value.
+    set skip_btrace_tests 2
+    gdb_test_multiple "record btrace pt" "check btrace support" {
+        -re "You can't do that when your target is.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "Target does not support branch tracing.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "Could not enable branch tracing.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "GDB does not support.*\r\n$gdb_prompt $" {
+            set skip_btrace_tests 1
+        }
+        -re "^record btrace pt\r\n$gdb_prompt $" {
+            set skip_btrace_tests 0
+        }
+    }
+    gdb_exit
+    remote_file build delete $exe
 
-proc skip_hp_tests {} {
-    eval set skip_hp [ expr ![isnative] || ![istarget "hppa*-*-hpux*"] ]
-    verbose "Skip hp tests is $skip_hp"
-    return $skip_hp
+    verbose "$me:  returning $skip_btrace_tests" 2
+    return $skip_btrace_tests
 }
 
 # Return whether we should skip tests for showing inlined functions in
@@ -2419,7 +2886,8 @@ proc skip_hw_breakpoint_tests {} {
     if { [istarget "i?86-*-*"] 
         || [istarget "x86_64-*-*"]
         || [istarget "ia64-*-*"] 
-        || [istarget "arm*-*-*"]} {
+        || [istarget "arm*-*-*"]
+        || [istarget "aarch64*-*-*"]} {
        return 0
     }
 
@@ -2439,6 +2907,7 @@ proc skip_hw_watchpoint_tests {} {
         || [istarget "x86_64-*-*"]
         || [istarget "ia64-*-*"] 
         || [istarget "arm*-*-*"]
+        || [istarget "aarch64*-*-*"]
         || [istarget "powerpc*-*-linux*"]
         || [istarget "s390*-*-*"] } {
        return 0
@@ -2547,25 +3016,33 @@ proc skip_compile_feature_tests {} {
     return $result
 }
 
-# Check whether we're testing with the remote or extended-remote
-# targets.
+# Helper for gdb_is_target_remote.  PROMPT_REGEXP is the expected
+# prompt.
 
-proc gdb_is_target_remote {} {
-    global gdb_prompt
+proc gdb_is_target_remote_prompt { prompt_regexp } {
 
     set test "probe for target remote"
     gdb_test_multiple "maint print target-stack" $test {
-       -re ".*emote serial target in gdb-specific protocol.*$gdb_prompt $" {
+       -re ".*emote serial target in gdb-specific protocol.*$prompt_regexp" {
            pass $test
            return 1
        }
-       -re "$gdb_prompt $" {
+       -re "$prompt_regexp" {
            pass $test
        }
     }
     return 0
 }
 
+# Check whether we're testing with the remote or extended-remote
+# targets.
+
+proc gdb_is_target_remote {} {
+    global gdb_prompt
+
+    return [gdb_is_target_remote_prompt "$gdb_prompt $"]
+}
+
 # Return 1 if the current remote target is an instance of our GDBserver, 0
 # otherwise.  Return -1 if there was an error and we can't tell.
 
@@ -2591,12 +3068,18 @@ gdb_caching_proc target_is_gdbserver {
     return $is_gdbserver
 }
 
-set compiler_info              "unknown"
+# N.B. compiler_info is intended to be local to this file.
+# Call test_compiler_info with no arguments to fetch its value.
+# Yes, this is counterintuitive when there's get_compiler_info,
+# but that's the current API.
+if [info exists compiler_info] {
+    unset compiler_info
+}
+
 set gcc_compiled               0
-set hp_cc_compiler             0
-set hp_aCC_compiler            0
 
 # Figure out what compiler I am using.
+# The result is cached so only the first invocation runs the compiler.
 #
 # ARG can be empty or "C++".  If empty, "C" is assumed.
 #
@@ -2660,8 +3143,11 @@ proc get_compiler_info {{arg ""}} {
 
     # Legacy global data symbols.
     global gcc_compiled
-    global hp_cc_compiler
-    global hp_aCC_compiler
+
+    if [info exists compiler_info] {
+       # Already computed.
+       return 0
+    }
 
     # Choose which file to preprocess.
     set ifile "${srcdir}/lib/compiler.c"
@@ -2704,22 +3190,24 @@ proc get_compiler_info {{arg ""}} {
        }
     }
 
-    # Reset to unknown compiler if any diagnostics happened.
+    # Set to unknown if for some reason compiler_info didn't get defined.
+    if ![info exists compiler_info] {
+       verbose -log "get_compiler_info: compiler_info not provided"
+       set compiler_info "unknown"
+    }
+    # Also set to unknown compiler if any diagnostics happened.
     if { $unknown } {
+       verbose -log "get_compiler_info: got unexpected diagnostics"
        set compiler_info "unknown"
     }
 
     # Set the legacy symbols.
     set gcc_compiled     0
-    set hp_cc_compiler   0
-    set hp_aCC_compiler  0
     if { [regexp "^gcc-1-" "$compiler_info" ] } { set gcc_compiled 1 }
     if { [regexp "^gcc-2-" "$compiler_info" ] } { set gcc_compiled 2 }
     if { [regexp "^gcc-3-" "$compiler_info" ] } { set gcc_compiled 3 }
     if { [regexp "^gcc-4-" "$compiler_info" ] } { set gcc_compiled 4 }
     if { [regexp "^gcc-5-" "$compiler_info" ] } { set gcc_compiled 5 }
-    if { [regexp "^hpcc-"  "$compiler_info" ] } { set hp_cc_compiler 1 }
-    if { [regexp "^hpacc-" "$compiler_info" ] } { set hp_aCC_compiler 1 }
 
     # Log what happened.
     verbose -log "get_compiler_info: $compiler_info"
@@ -2729,28 +3217,21 @@ proc get_compiler_info {{arg ""}} {
     uplevel \#0 { set true 1 }
     uplevel \#0 { set false 0 }
 
-    # Use of aCC results in boolean results being displayed as
-    # "true" or "false"
-    if { $hp_aCC_compiler } {
-      uplevel \#0 { set true true }
-      uplevel \#0 { set false false }
-    }
-
     return 0
 }
 
+# Return the compiler_info string if no arg is provided.
+# Otherwise the argument is a glob-style expression to match against
+# compiler_info.
+
 proc test_compiler_info { {compiler ""} } {
     global compiler_info
+    get_compiler_info
 
-     # if no arg, return the compiler_info string
-
-     if [string match "" $compiler] {
-         if [info exists compiler_info] {
-             return $compiler_info
-         } else {
-             perror "No compiler info found."
-         }
-     }
+    # If no arg, return the compiler_info string.
+    if [string match "" $compiler] {
+       return $compiler_info
+    }
 
     return [string match $compiler $compiler_info]
 }
@@ -2794,6 +3275,40 @@ proc gdb_wrapper_init { args } {
 global gdb_saved_set_unbuffered_mode_obj
 set gdb_saved_set_unbuffered_mode_obj ""
 
+# Compile source files specified by SOURCE into a binary of type TYPE at path
+# DEST.  gdb_compile is implemented using DejaGnu's target_compile, so the type
+# parameter and most options are passed directly to it.
+#
+# The type can be one of the following:
+#
+#   - object: Compile into an object file.
+#   - executable: Compile and link into an executable.
+#   - preprocess: Preprocess the source files.
+#   - assembly: Generate assembly listing.
+#
+# The following options are understood and processed by gdb_compile:
+#
+#   - shlib=so_path: Add SO_PATH to the sources, and enable some target-specific
+#     quirks to be able to use shared libraries.
+#   - shlib_load: Link with appropriate libraries to allow the test to
+#     dynamically load libraries at runtime.  For example, on Linux, this adds
+#     -ldl so that the test can use dlopen.
+#   - nowarnings:  Inhibit all compiler warnings.
+#
+# And here are some of the not too obscure options understood by DejaGnu that
+# influence the compilation:
+#
+#   - additional_flags=flag: Add FLAG to the compiler flags.
+#   - libs=library: Add LIBRARY to the libraries passed to the linker.  The
+#     argument can be a file, in which case it's added to the sources, or a
+#     linker flag.
+#   - ldflags=flag: Add FLAG to the linker flags.
+#   - incdir=path: Add PATH to the searched include directories.
+#   - libdir=path: Add PATH to the linker searched directories.
+#   - ada, c++, f77: Compile the file as Ada, C++ or Fortran.
+#   - debug: Build with debug information.
+#   - optimize: Build with optimization.
+
 proc gdb_compile {source dest type options} {
     global GDB_TESTCASE_OPTIONS
     global gdb_wrapper_file
@@ -2829,6 +3344,13 @@ proc gdb_compile {source dest type options} {
                      || [istarget *-*-cygwin*]) } {
                    lappend new_options "additional_flags=-Wl,--enable-auto-import"
                }
+               if { [test_compiler_info "gcc-*"] || [test_compiler_info "clang-*"] } {
+                   # Undo debian's change in the default.
+                   # Put it at the front to not override any user-provided
+                   # value, and to make sure it appears in front of all the
+                   # shlibs!
+                   lappend new_options "early_flags=-Wl,--no-as-needed"
+               }
             }
        } elseif { $opt == "shlib_load" } {
            set shlib_load 1
@@ -2845,8 +3367,7 @@ proc gdb_compile {source dest type options} {
     if { $shlib_load || ($shlib_found && [is_remote target]) } {
        if { ([istarget "*-*-mingw*"]
              || [istarget *-*-cygwin*]
-             || [istarget *-*-pe*]
-             || [istarget hppa*-*-hpux*])} {
+             || [istarget *-*-pe*]) } {
            # Do not need anything.
        } elseif { [istarget *-*-freebsd*] || [istarget *-*-openbsd*] } {
            lappend new_options "ldflags=-Wl,-rpath,${outdir}"
@@ -3025,14 +3546,7 @@ proc gdb_compile_shlib {sources dest options} {
             }
         }
         default {
-            switch -glob [istarget] {
-                "hppa*-hp-hpux*" {
-                    lappend obj_options "additional_flags=+z"
-                }
-                default {
-                    # don't know what the compiler is...
-                }
-            }
+           # don't know what the compiler is...
         }
     }
 
@@ -3046,49 +3560,46 @@ proc gdb_compile_shlib {sources dest options} {
        lappend objects ${outdir}/${sourcebase}.o
     }
 
-    if [istarget "hppa*-*-hpux*"] {
-       remote_exec build "ld -b ${objects} -o ${dest}"
+    set link_options $options
+    if [test_compiler_info "xlc-*"] {
+       lappend link_options "additional_flags=-qmkshrobj"
     } else {
-       set link_options $options
-       if [test_compiler_info "xlc-*"] {
-          lappend link_options "additional_flags=-qmkshrobj"
-       } else {
-          lappend link_options "additional_flags=-shared"
-
-          if { ([istarget "*-*-mingw*"]
-                || [istarget *-*-cygwin*]
-                || [istarget *-*-pe*]) } {
-              if { [is_remote host] } {
-                  set name [file tail ${dest}]
-              } else {
-                  set name ${dest}
-              }
-              lappend link_options "additional_flags=-Wl,--out-implib,${name}.a"
-          } elseif [is_remote target] {
-            # By default, we do not set the soname.  This causes the linker
-            # on ELF systems to create a DT_NEEDED entry in the executable
-            # refering to the full path name of the library.  This is a
-            # problem in remote testing if the library is in a different
-            # directory there.  To fix this, we set a soname of just the
-            # base filename for the library, and add an appropriate -rpath
-            # to the main executable (in gdb_compile).
-             set destbase [file tail $dest]
-             lappend link_options "additional_flags=-Wl,-soname,$destbase"
-           }
-       }
-       if {[gdb_compile "${objects}" "${dest}" executable $link_options] != ""} {
-           return -1
-       }
-       if { [is_remote host]
-            && ([istarget "*-*-mingw*"]
-                || [istarget *-*-cygwin*]
-                || [istarget *-*-pe*]) } {
-           set dest_tail_name [file tail ${dest}]
-           remote_upload host $dest_tail_name.a ${dest}.a
-           remote_file host delete $dest_tail_name.a
-       }
+       lappend link_options "additional_flags=-shared"
+
+       if { ([istarget "*-*-mingw*"]
+             || [istarget *-*-cygwin*]
+             || [istarget *-*-pe*]) } {
+           if { [is_remote host] } {
+               set name [file tail ${dest}]
+           } else {
+               set name ${dest}
+           }
+           lappend link_options "additional_flags=-Wl,--out-implib,${name}.a"
+       } elseif [is_remote target] {
+           # By default, we do not set the soname.  This causes the linker
+           # on ELF systems to create a DT_NEEDED entry in the executable
+           # refering to the full path name of the library.  This is a
+           # problem in remote testing if the library is in a different
+           # directory there.  To fix this, we set a soname of just the
+           # base filename for the library, and add an appropriate -rpath
+           # to the main executable (in gdb_compile).
+           set destbase [file tail $dest]
+           lappend link_options "additional_flags=-Wl,-soname,$destbase"
+       }
+    }
+    if {[gdb_compile "${objects}" "${dest}" executable $link_options] != ""} {
+       return -1
+    }
+    if { [is_remote host]
+        && ([istarget "*-*-mingw*"]
+            || [istarget *-*-cygwin*]
+            || [istarget *-*-pe*]) } {
+       set dest_tail_name [file tail ${dest}]
+       remote_upload host $dest_tail_name.a ${dest}.a
+       remote_file host delete $dest_tail_name.a
     }
-  return ""
+
+    return ""
 }
 
 # This is just like gdb_compile_shlib, above, except that it tries compiling
@@ -3174,6 +3685,18 @@ proc send_gdb { string } {
     return [remote_send host "$string"]
 }
 
+# Send STRING to the inferior's terminal.
+
+proc send_inferior { string } {
+    global inferior_spawn_id
+
+    if {[catch "send -i $inferior_spawn_id -- \$string" errorInfo]} {
+       return "$errorInfo"
+    } else {
+       return ""
+    }
+}
+
 #
 #
 
@@ -3187,26 +3710,10 @@ proc gdb_expect { args } {
 
     # A timeout argument takes precedence, otherwise of all the timeouts
     # select the largest.
-    upvar #0 timeout gtimeout
-    upvar timeout timeout
     if [info exists atimeout] {
        set tmt $atimeout
     } else {
-       set tmt 0
-       if [info exists timeout] {
-           set tmt $timeout
-       }
-       if { [info exists gtimeout] && $gtimeout > $tmt } {
-           set tmt $gtimeout
-       }
-       if { [target_info exists gdb,timeout]
-            && [target_info gdb,timeout] > $tmt } {
-           set tmt [target_info gdb,timeout]
-       }
-       if { $tmt == 0 } {
-           # Eeeeew.
-           set tmt 60
-       }
+       set tmt [get_largest_timeout]
     }
 
     global suppress_flag
@@ -3391,6 +3898,9 @@ proc gdb_spawn_with_cmdline_opts { cmdline_flags } {
 
     set saved_gdbflags $GDBFLAGS
 
+    if {$GDBFLAGS != ""} {
+       append GDBFLAGS " "
+    }
     append GDBFLAGS $cmdline_flags
 
     set res [gdb_spawn]
@@ -3413,29 +3923,90 @@ proc gdb_exit { } {
     catch default_gdb_exit
 }
 
+# Return true if we can spawn a program on the target and attach to
+# it.
+
+proc can_spawn_for_attach { } {
+    # We use exp_pid to get the inferior's pid, assuming that gives
+    # back the pid of the program.  On remote boards, that would give
+    # us instead the PID of e.g., the ssh client, etc.
+    if [is_remote target] then {
+       return 0
+    }
+
+    # The "attach" command doesn't make sense when the target is
+    # stub-like, where GDB finds the program already started on
+    # initial connection.
+    if {[target_info exists use_gdb_stub]} {
+       return 0
+    }
+
+    # Assume yes.
+    return 1
+}
+
+# Kill a progress previously started with spawn_wait_for_attach, and
+# reap its wait status.  PROC_SPAWN_ID is the spawn id associated with
+# the process.
+
+proc kill_wait_spawned_process { proc_spawn_id } {
+    set pid [exp_pid -i $proc_spawn_id]
+
+    verbose -log "killing ${pid}"
+    remote_exec build "kill -9 ${pid}"
+
+    verbose -log "closing ${proc_spawn_id}"
+    catch "close -i $proc_spawn_id"
+    verbose -log "waiting for ${proc_spawn_id}"
+
+    # If somehow GDB ends up still attached to the process here, a
+    # blocking wait hangs until gdb is killed (or until gdb / the
+    # ptracer reaps the exit status too, but that won't happen because
+    # something went wrong.)  Passing -nowait makes expect tell Tcl to
+    # wait for the PID in the background.  That's fine because we
+    # don't care about the exit status.  */
+    wait -nowait -i $proc_spawn_id
+}
+
+# Returns the process id corresponding to the given spawn id.
+
+proc spawn_id_get_pid { spawn_id } {
+    set testpid [exp_pid -i $spawn_id]
+
+    if { [istarget "*-*-cygwin*"] } {
+       # testpid is the Cygwin PID, GDB uses the Windows PID, which
+       # might be different due to the way fork/exec works.
+       set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ]
+    }
+
+    return $testpid
+}
+
 # Start a set of programs running and then wait for a bit, to be sure
-# that they can be attached to.  Return a list of the processes' PIDs.
+# that they can be attached to.  Return a list of processes spawn IDs,
+# one element for each process spawned.  It's a test error to call
+# this when [can_spawn_for_attach] is false.
 
 proc spawn_wait_for_attach { executable_list } {
-    set pid_list {}
+    set spawn_id_list {}
+
+    if ![can_spawn_for_attach] {
+       # The caller should have checked can_spawn_for_attach itself
+       # before getting here.
+       error "can't spawn for attach with this target/board"
+    }
 
     foreach {executable} $executable_list {
-       lappend pid_list [eval exec $executable &]
+       # Note we use Expect's spawn, not Tcl's exec, because with
+       # spawn we control when to wait for/reap the process.  That
+       # allows killing the process by PID without being subject to
+       # pid-reuse races.
+       lappend spawn_id_list [remote_spawn target $executable]
     }
 
     sleep 2
 
-    if { [istarget "*-*-cygwin*"] } {
-       for {set i 0} {$i < [llength $pid_list]} {incr i} {
-           # testpid is the Cygwin PID, GDB uses the Windows PID,
-           # which might be different due to the way fork/exec works.
-           set testpid [lindex $pid_list $i]
-           set testpid [ exec ps -e | gawk "{ if (\$1 == $testpid) print \$4; }" ]
-           set pid_list [lreplace $pid_list $i $i $testpid]
-       }
-    }
-
-    return $pid_list
+    return $spawn_id_list
 }
 
 #
@@ -3653,12 +4224,14 @@ proc gdb_load_shlibs { args } {
 #
 # gdb_load -- load a file into the debugger.  Specifying no file
 # defaults to the executable currently being debugged.
+# The return value is 0 for success, -1 for failure.
 # Many files in config/*.exp override this procedure.
 #
 proc gdb_load { arg } {
     if { $arg != "" } {
        return [gdb_file_cmd $arg]
     }
+    return 0
 }
 
 # gdb_reload -- load a file into the target.  Called before "running",
@@ -3721,6 +4294,26 @@ proc default_gdb_init { test_file_name } {
     }
 }
 
+# Return a path using GDB_PARALLEL.
+# ARGS is a list of path elements to append to "$objdir/$GDB_PARALLEL".
+# GDB_PARALLEL must be defined, the caller must check.
+#
+# The default value for GDB_PARALLEL is, canonically, ".".
+# The catch is that tests don't expect an additional "./" in file paths so
+# omit any directory for the default case.
+# GDB_PARALLEL is written as "yes" for the default case in Makefile.in to mark
+# its special handling.
+
+proc make_gdb_parallel_path { args } {
+    global GDB_PARALLEL objdir
+    set joiner [list "file" "join" $objdir]
+    if { $GDB_PARALLEL != "yes" } {
+       lappend joiner $GDB_PARALLEL
+    }
+    set joiner [concat $joiner $args]
+    return [eval $joiner]
+}
+
 # Turn BASENAME into a full file name in the standard output
 # directory.  It is ok if BASENAME is the empty string; in this case
 # the directory is returned.
@@ -3729,7 +4322,7 @@ proc standard_output_file {basename} {
     global objdir subdir gdb_test_file_name GDB_PARALLEL
 
     if {[info exists GDB_PARALLEL]} {
-       set dir [file join $objdir outputs $subdir $gdb_test_file_name]
+       set dir [make_gdb_parallel_path outputs $subdir $gdb_test_file_name]
        file mkdir $dir
        return [file join $dir $basename]
     } else {
@@ -3743,7 +4336,7 @@ proc standard_temp_file {basename} {
     global objdir GDB_PARALLEL
 
     if {[info exists GDB_PARALLEL]} {
-       return [file join $objdir temp $basename]
+       return [make_gdb_parallel_path temp $basename]
     } else {
        return $basename
     }
@@ -3936,20 +4529,6 @@ proc gdb_finish { } {
     global gdb_prompt
     global cleanfiles
 
-    # Give persistent gdbserver a chance to terminate before GDB is killed.
-    if {[info exists gdbserver_reconnect_p] && $gdbserver_reconnect_p
-       && [info exists gdb_spawn_id]} {
-       send_gdb "kill\n";
-       gdb_expect 10 {
-           -re "y or n" {
-               send_gdb "y\n";
-               exp_continue;
-           }
-           -re "$gdb_prompt $" {
-           }
-       }
-    }
-
     # Exit first, so that the files are no longer in use.
     gdb_exit
 
@@ -4357,7 +4936,6 @@ gdb_caching_proc gdb_has_argv0 {
          || [istarget *-wince-pe] || [istarget *-*-mingw32ce*]
          || [istarget *-*-symbianelf*]
          || [istarget *-*-osf*]
-         || [istarget *-*-hpux*]
          || [istarget *-*-dicos*]
          || [istarget *-*-nto*]
          || [istarget *-*-*vms*]
@@ -4388,28 +4966,39 @@ gdb_caching_proc gdb_has_argv0 {
 # Returns "" if there is none.
 
 proc get_build_id { filename } {
-    set tmp [standard_output_file "${filename}-tmp"]
-    set objcopy_program [gdb_find_objcopy]
-
-    set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output]
-    verbose "result is $result"
-    verbose "output is $output"
-    if {$result == 1} {
-       return ""
-    }
-    set fi [open $tmp]
-    fconfigure $fi -translation binary
-    # Skip the NOTE header.
-    read $fi 16
-    set data [read $fi]
-    close $fi
-    file delete $tmp
-    if ![string compare $data ""] then {
-       return ""
+    if { ([istarget "*-*-mingw*"]
+         || [istarget *-*-cygwin*]) } {
+       set objdump_program [gdb_find_objdump]
+       set result [catch {set data [exec $objdump_program -p $filename | grep signature | cut "-d " -f4]} output]
+       verbose "result is $result"
+       verbose "output is $output"
+       if {$result == 1} {
+           return ""
+       }
+       return $data
+    } else {
+       set tmp [standard_output_file "${filename}-tmp"]
+       set objcopy_program [gdb_find_objcopy]
+       set result [catch "exec $objcopy_program -j .note.gnu.build-id -O binary $filename $tmp" output]
+       verbose "result is $result"
+       verbose "output is $output"
+       if {$result == 1} {
+           return ""
+       }
+       set fi [open $tmp]
+       fconfigure $fi -translation binary
+       # Skip the NOTE header.
+       read $fi 16
+       set data [read $fi]
+       close $fi
+       file delete $tmp
+       if ![string compare $data ""] then {
+           return ""
+       }
+       # Convert it to hex.
+       binary scan $data H* data
+       return $data
     }
-    # Convert it to hex.
-    binary scan $data H* data
-    return $data
 }
 
 # Return the build-id hex string (usually 160 bits as 40 hex characters)
@@ -4519,11 +5108,13 @@ proc help_test_raw { gdb_command expected_lines args } {
 # are regular expressions that should match the beginning of output,
 # before the list of commands in that class.  The presence of 
 # command list and standard epilogue will be tested automatically.
+# Notice that the '[' and ']' characters don't need to be escaped for strings
+# wrapped in {} braces.
 proc test_class_help { command_class expected_initial_lines args } {
     set l_stock_body {
-        "List of commands\:.*\[\r\n\]+"
-        "Type \"help\" followed by command name for full documentation\.\[\r\n\]+"
-        "Type \"apropos word\" to search for commands related to \"word\"\.[\r\n\]+"
+        "List of commands\:.*[\r\n]+"
+        "Type \"help\" followed by command name for full documentation\.[\r\n]+"
+        "Type \"apropos word\" to search for commands related to \"word\"\.[\r\n]+"
         "Command name abbreviations are allowed if unambiguous\." 
     }
     set l_entire_body [concat $expected_initial_lines $l_stock_body]
@@ -4645,17 +5236,27 @@ proc build_executable { testname executable {sources ""} {options {debug}} } {
     return [eval build_executable_from_specs $arglist]
 }
 
-# Starts fresh GDB binary and loads EXECUTABLE into GDB. EXECUTABLE is
-# the basename of the binary.
-proc clean_restart { executable } {
+# Starts fresh GDB binary and loads an optional executable into GDB.
+# Usage: clean_restart [executable]
+# EXECUTABLE is the basename of the binary.
+
+proc clean_restart { args } {
     global srcdir
     global subdir
-    set binfile [standard_output_file ${executable}]
+
+    if { [llength $args] > 1 } {
+       error "bad number of args: [llength $args]"
+    }
 
     gdb_exit
     gdb_start
     gdb_reinitialize_dir $srcdir/$subdir
-    gdb_load ${binfile}
+
+    if { [llength $args] >= 1 } {
+       set executable [lindex $args 0]
+       set binfile [standard_output_file ${executable}]
+       gdb_load ${binfile}
+    }
 }
 
 # Prepares for testing by calling build_executable_full, then
@@ -4859,7 +5460,10 @@ if {[info exists GDB_PARALLEL]} {
     if {[is_remote host]} {
        unset GDB_PARALLEL
     } else {
-       file mkdir outputs temp cache
+       file mkdir \
+           [make_gdb_parallel_path outputs] \
+           [make_gdb_parallel_path temp] \
+           [make_gdb_parallel_path cache]
     }
 }
 
@@ -4930,18 +5534,96 @@ proc core_find {binfile {deletefiles {}} {arg ""}} {
     return $destcore
 }
 
-# gdb_target_symbol_prefix_flags returns a string that can be added
-# to gdb_compile options to define SYMBOL_PREFIX macro value
-# symbol_prefix_flags returns a string that can be added
-# for targets that use underscore as symbol prefix.
-# TODO: find out automatically if the target needs this.
+# gdb_target_symbol_prefix compiles a test program and then examines
+# the output from objdump to determine the prefix (such as underscore)
+# for linker symbol prefixes.
+
+gdb_caching_proc gdb_target_symbol_prefix {
+    # Set up and compile a simple test program...
+    set src [standard_temp_file main[pid].c]
+    set exe [standard_temp_file main[pid].x]
+
+    gdb_produce_source $src {
+       int main() {
+           return 0;
+       }
+    }
+
+    verbose "compiling testfile $src" 2
+    set compile_flags {debug nowarnings quiet}
+    set lines [gdb_compile $src $exe executable $compile_flags]
+
+    set prefix ""
+
+    if ![string match "" $lines] then {
+        verbose "gdb_target_symbol_prefix: testfile compilation failed, returning null prefix" 2
+    } else {
+       set objdump_program [gdb_find_objdump]
+       set result [catch "exec $objdump_program --syms $exe" output]
+
+       if { $result == 0 \
+            && ![regexp -lineanchor \
+                 { ([^ a-zA-Z0-9]*)main$} $output dummy prefix] } {
+           verbose "gdb_target_symbol_prefix: Could not find main in objdump output; returning null prefix" 2
+       }
+    }
+
+    file delete $src
+    file delete $exe
+
+    return $prefix
+}
+
+# gdb_target_symbol returns the provided symbol with the correct prefix
+# prepended.  (See gdb_target_symbol_prefix, above.)
+
+proc gdb_target_symbol { symbol } {
+  set prefix [gdb_target_symbol_prefix]
+  return "${prefix}${symbol}"
+}
+
+# gdb_target_symbol_prefix_flags_asm returns a string that can be
+# added to gdb_compile options to define the C-preprocessor macro
+# SYMBOL_PREFIX with a value that can be prepended to symbols
+# for targets which require a prefix, such as underscore.
+#
+# This version (_asm) defines the prefix without double quotes
+# surrounding the prefix.  It is used to define the macro
+# SYMBOL_PREFIX for assembly language files.  Another version, below,
+# is used for symbols in inline assembler in C/C++ files.
+# 
+# The lack of quotes in this version (_asm) makes it possible to
+# define supporting macros in the .S file.  (The version which
+# uses quotes for the prefix won't work for such files since it's
+# impossible to define a quote-stripping macro in C.)
+#
+# It's possible to use this version (_asm) for C/C++ source files too,
+# but a string is usually required in such files; providing a version
+# (no _asm) which encloses the prefix with double quotes makes it
+# somewhat easier to define the supporting macros in the test case.
+
+proc gdb_target_symbol_prefix_flags_asm {} {
+    set prefix [gdb_target_symbol_prefix]
+    if {$prefix ne ""} {
+       return "additional_flags=-DSYMBOL_PREFIX=$prefix"
+    } else {
+       return "";
+    }
+}
+
+# gdb_target_symbol_prefix_flags returns the same string as
+# gdb_target_symbol_prefix_flags_asm, above, but with the prefix
+# enclosed in double quotes if there is a prefix.
+#
+# See the comment for gdb_target_symbol_prefix_flags_asm for an
+# extended discussion.
 
 proc gdb_target_symbol_prefix_flags {} {
-    if { [istarget "*-*-cygwin*"] || [istarget "i?86-*-mingw*"]
-        || [istarget "*-*-msdosdjgpp*"] || [istarget "*-*-go32*"] } {
-       return "additional_flags=-DSYMBOL_PREFIX=\"_\""
+    set prefix [gdb_target_symbol_prefix]
+    if {$prefix ne ""} {
+       return "additional_flags=-DSYMBOL_PREFIX=\"$prefix\""
     } else {
-       return ""
+       return "";
     }
 }
 
@@ -5044,19 +5726,32 @@ proc parse_args { argset } {
     # number of items expected to be passed into the procedure...
 }
 
-# Capture the output of COMMAND in a string ignoring PREFIX; return that string.
+# Capture the output of COMMAND in a string ignoring PREFIX (a regexp);
+# return that string.
+
 proc capture_command_output { command prefix } {
     global gdb_prompt
     global expect_out
 
     set output_string ""
     gdb_test_multiple "$command" "capture_command_output for $command" {
-       -re "${command}\[\r\n\]+${prefix}(.*)\[\r\n\]+$gdb_prompt $" {
+       -re "[string_to_regexp ${command}]\[\r\n\]+${prefix}(.*)\[\r\n\]+$gdb_prompt $" {
            set output_string $expect_out(1,string)
        }
     }
     return $output_string
 }
 
+# A convenience function that joins all the arguments together, with a
+# regexp that matches exactly one end of line in between each argument.
+# This function is ideal to write the expected output of a GDB command
+# that generates more than a couple of lines, as this allows us to write
+# each line as a separate string, which is easier to read by a human
+# being.
+
+proc multi_line { args } {
+    return [join $args "\r\n"]
+}
+
 # Always load compatibility stuff.
 load_lib future.exp
This page took 0.041626 seconds and 4 git commands to generate.