+# Test the output of "help COMMNAD_CLASS". EXPECTED_INITIAL_LINES
+# 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.
+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\]+"
+ "Command name abbreviations are allowed if unambiguous\."
+ }
+ set l_entire_body [concat $expected_initial_lines $l_stock_body]
+
+ eval [list help_test_raw "help ${command_class}" $l_entire_body] $args
+}
+
+# COMMAND_LIST should have either one element -- command to test, or
+# two elements -- abbreviated command to test, and full command the first
+# element is abbreviation of.
+# The command must be a prefix command. EXPECTED_INITIAL_LINES
+# are regular expressions that should match the beginning of output,
+# before the list of subcommands. The presence of
+# subcommand list and standard epilogue will be tested automatically.
+proc test_prefix_command_help { command_list expected_initial_lines args } {
+ set command [lindex $command_list 0]
+ if {[llength $command_list]>1} {
+ set full_command [lindex $command_list 1]
+ } else {
+ set full_command $command
+ }
+ # Use 'list' and not just {} because we want variables to
+ # be expanded in this list.
+ set l_stock_body [list\
+ "List of $full_command subcommands\:.*\[\r\n\]+"\
+ "Type \"help $full_command\" followed by $full_command subcommand 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]
+ if {[llength $args]>0} {
+ help_test_raw "help ${command}" $l_entire_body [lindex $args 0]
+ } else {
+ help_test_raw "help ${command}" $l_entire_body
+ }
+}
+
+# Build executable named EXECUTABLE, from SOURCES. If SOURCES are not
+# provided, uses $EXECUTABLE.c. The TESTNAME paramer is the name of test
+# to pass to untested, if something is wrong. OPTIONS are passed
+# to gdb_compile directly.
+proc build_executable { testname executable {sources ""} {options {debug}} } {
+
+ global objdir
+ global subdir
+ global srcdir
+ if {[llength $sources]==0} {
+ set sources ${executable}.c
+ }
+
+ set binfile ${objdir}/${subdir}/${executable}
+
+ set objects {}
+ for {set i 0} "\$i<[llength $sources]" {incr i} {
+ set s [lindex $sources $i]
+ if { [gdb_compile "${srcdir}/${subdir}/${s}" "${binfile}${i}.o" object $options] != "" } {
+ untested $testname
+ return -1
+ }
+ lappend objects "${binfile}${i}.o"
+ }
+
+ if { [gdb_compile $objects "${binfile}" executable $options] != "" } {
+ untested $testname
+ return -1
+ }
+
+ if [get_compiler_info ${binfile}] {
+ return -1
+ }
+ return 0
+}
+
+# Starts fresh GDB binary and loads EXECUTABLE into GDB. EXECUTABLE is
+# the name of binary in ${objdir}/${subdir}.
+proc clean_restart { executable } {
+ global srcdir
+ global objdir
+ global subdir
+ set binfile ${objdir}/${subdir}/${executable}
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ if [target_info exists gdb_stub] {
+ gdb_step_for_stub;
+ }
+}
+
+# Prepares for testing, by calling build_executable, and then clean_restart.
+# Please refer to build_executable for parameter description.
+proc prepare_for_testing { testname executable {sources ""} {options {debug}}} {
+
+ if {[build_executable $testname $executable $sources $options] == -1} {
+ return -1
+ }
+ clean_restart $executable
+
+ return 0
+}
+
+proc get_valueof { fmt exp default } {
+ global gdb_prompt
+
+ set test "get valueof \"${exp}\""
+ set val ${default}
+ gdb_test_multiple "print${fmt} ${exp}" "$test" {
+ -re "\\$\[0-9\]* = (.*)\[\r\n\]*$gdb_prompt $" {
+ set val $expect_out(1,string)
+ pass "$test ($val)"
+ }
+ timeout {
+ fail "$test (timeout)"
+ }
+ }
+ return ${val}
+}
+
+proc get_integer_valueof { exp default } {
+ global gdb_prompt
+
+ set test "get integer valueof \"${exp}\""
+ set val ${default}
+ gdb_test_multiple "print /d ${exp}" "$test" {
+ -re "\\$\[0-9\]* = (\[-\]*\[0-9\]*).*$gdb_prompt $" {
+ set val $expect_out(1,string)
+ pass "$test ($val)"
+ }
+ timeout {
+ fail "$test (timeout)"
+ }
+ }
+ return ${val}
+}
+
+proc get_hexadecimal_valueof { exp default } {
+ global gdb_prompt
+ send_gdb "print /x ${exp}\n"
+ set test "get hexadecimal valueof \"${exp}\""
+ gdb_expect {
+ -re "\\$\[0-9\]* = (0x\[0-9a-zA-Z\]+).*$gdb_prompt $" {
+ set val $expect_out(1,string)
+ pass "$test"
+ }
+ timeout {
+ set val ${default}
+ fail "$test (timeout)"
+ }
+ }
+ return ${val}
+}
+
+proc get_sizeof { type default } {
+ return [get_integer_valueof "sizeof (${type})" $default]
+}
+
+# Log gdb command line and script if requested.
+if {[info exists TRANSCRIPT]} {
+ rename send_gdb real_send_gdb
+ rename remote_spawn real_remote_spawn
+ rename remote_close real_remote_close
+
+ global gdb_transcript
+ set gdb_transcript ""
+
+ global gdb_trans_count
+ set gdb_trans_count 1
+
+ proc remote_spawn {args} {
+ global gdb_transcript gdb_trans_count outdir
+
+ if {$gdb_transcript != ""} {
+ close $gdb_transcript
+ }
+ set gdb_transcript [open [file join $outdir transcript.$gdb_trans_count] w]
+ puts $gdb_transcript [lindex $args 1]
+ incr gdb_trans_count
+
+ return [uplevel real_remote_spawn $args]
+ }
+
+ proc remote_close {args} {
+ global gdb_transcript
+
+ if {$gdb_transcript != ""} {
+ close $gdb_transcript
+ set gdb_transcript ""
+ }
+
+ return [uplevel real_remote_close $args]
+ }
+
+ proc send_gdb {args} {
+ global gdb_transcript
+
+ if {$gdb_transcript != ""} {
+ puts -nonewline $gdb_transcript [lindex $args 0]
+ }
+
+ return [uplevel real_send_gdb $args]
+ }
+}
+
+proc core_find {binfile {deletefiles {}} {arg ""}} {
+ global objdir subdir
+
+ set destcore "$binfile.core"
+ file delete $destcore
+
+ # Create a core file named "$destcore" rather than just "core", to
+ # avoid problems with sys admin types that like to regularly prune all
+ # files named "core" from the system.
+ #
+ # Arbitrarily try setting the core size limit to "unlimited" since
+ # this does not hurt on systems where the command does not work and
+ # allows us to generate a core on systems where it does.
+ #
+ # Some systems append "core" to the name of the program; others append
+ # the name of the program to "core"; still others (like Linux, as of
+ # May 2003) create cores named "core.PID". In the latter case, we
+ # could have many core files lying around, and it may be difficult to
+ # tell which one is ours, so let's run the program in a subdirectory.
+ set found 0
+ set coredir "${objdir}/${subdir}/coredir.[getpid]"
+ file mkdir $coredir
+ catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile} ${arg}; true) >/dev/null 2>&1\""
+ # remote_exec host "${binfile}"
+ foreach i "${coredir}/core ${coredir}/core.coremaker.c ${binfile}.core" {
+ if [remote_file build exists $i] {
+ remote_exec build "mv $i $destcore"
+ set found 1
+ }
+ }
+ # Check for "core.PID".
+ if { $found == 0 } {
+ set names [glob -nocomplain -directory $coredir core.*]
+ if {[llength $names] == 1} {
+ set corefile [file join $coredir [lindex $names 0]]
+ remote_exec build "mv $corefile $destcore"
+ set found 1
+ }
+ }
+ if { $found == 0 } {
+ # The braindamaged HPUX shell quits after the ulimit -c above
+ # without executing ${binfile}. So we try again without the
+ # ulimit here if we didn't find a core file above.
+ # Oh, I should mention that any "braindamaged" non-Unix system has
+ # the same problem. I like the cd bit too, it's really neat'n stuff.
+ catch "system \"(cd ${objdir}/${subdir}; ${binfile}; true) >/dev/null 2>&1\""
+ foreach i "${objdir}/${subdir}/core ${objdir}/${subdir}/core.coremaker.c ${binfile}.core" {
+ if [remote_file build exists $i] {
+ remote_exec build "mv $i $destcore"
+ set found 1
+ }
+ }
+ }
+
+ # Try to clean up after ourselves.
+ foreach deletefile $deletefiles {
+ remote_file build delete [file join $coredir $deletefile]
+ }
+ remote_exec build "rmdir $coredir"
+
+ if { $found == 0 } {
+ warning "can't generate a core file - core tests suppressed - check ulimit -c"
+ return ""
+ }
+ return $destcore
+}