diff options
author | Andrew Cagney <cagney@redhat.com> | 2000-02-23 00:25:43 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2000-02-23 00:25:43 +0000 |
commit | fb40c20903110ed8af9701ce7c2635abd3770d52 (patch) | |
tree | 9f99a85a7d64fa61cfa9a167e006e2f747716d42 /gdb/testsuite/lib | |
parent | e6c6b6fe2d24c8be4909c7e3c0dd1a937819ffe9 (diff) | |
download | gdb-fb40c20903110ed8af9701ce7c2635abd3770d52.zip gdb-fb40c20903110ed8af9701ce7c2635abd3770d52.tar.gz gdb-fb40c20903110ed8af9701ce7c2635abd3770d52.tar.bz2 |
Add mi/ and testsuite/gdb.mi/ subdirectories.
Add --enable-gdbmi option to configury.
Add mi rules to Makefile.in
Add mi conditional output to event-top.c infrun.c main.c top.c.
Add -i=mi option.
Diffstat (limited to 'gdb/testsuite/lib')
-rw-r--r-- | gdb/testsuite/lib/mi-support.exp | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp new file mode 100644 index 0000000..7d207df --- /dev/null +++ b/gdb/testsuite/lib/mi-support.exp @@ -0,0 +1,683 @@ +# Copyright (C) 1999, 2000 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was based on a file written by Fred Fish. (fnf@cygnus.com) + +# Test setup routines that work with the MI interpreter. + +# 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 { + set mi_gdb_prompt "\[(\]gdb\[)\] \r\n" +} + +set MIFLAGS "-i=mi" + +# +# mi_gdb_exit -- exit the GDB, killing the target program if necessary +# +proc mi_gdb_exit {} { + catch mi_uncatched_gdb_exit +} + +proc mi_uncatched_gdb_exit {} { + global GDB + global GDBFLAGS + global verbose + global gdb_spawn_id; + global gdb_prompt + global mi_gdb_prompt + global MIFLAGS + + gdb_stop_suppressing_tests; + + if { [info procs sid_exit] != "" } { + sid_exit + } + + if ![info exists gdb_spawn_id] { + return; + } + + verbose "Quitting $GDB $GDBFLAGS $MIFLAGS" + + if { [is_remote host] && [board_info host exists fileid] } { + send_gdb "999-gdb-exit\n"; + gdb_expect 10 { + -re "y or n" { + send_gdb "y\n"; + exp_continue; + } + -re "Undefined command.*$gdb_prompt $" { + send_gdb "quit\n" + exp_continue; + } + -re "DOSEXIT code" { } + default { } + } + } + + if ![is_remote host] { + remote_close host; + } + unset gdb_spawn_id +} + +# +# start gdb -- start gdb running, default procedure +# +# 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. +# +proc mi_gdb_start { } { + global verbose + global GDB + global GDBFLAGS + global gdb_prompt + global mi_gdb_prompt + global timeout + global gdb_spawn_id; + global MIFLAGS + + gdb_stop_suppressing_tests; + + verbose "Spawning $GDB -nw $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 + } + } + set res [remote_spawn host "$GDB -nw $GDBFLAGS $MIFLAGS [host_info gdb_opts]"]; + if { $res < 0 || $res == "" } { + perror "Spawning $GDB failed." + return 1; + } + gdb_expect { + -re ".*UI_OUT.*$mi_gdb_prompt$" { + verbose "GDB initialized." + } + -re ".*$mi_gdb_prompt$" { + untested "Skip mi tests (output not in headless format)." + remote_close host; + return -1; + } + -re ".*$gdb_prompt $" { + untested "Skip mi tests (got non-mi prompt)." + remote_close host; + return -1; + } + timeout { + perror "(timeout) GDB never initialized after 10 seconds." + remote_close host; + return -1 + } + } + set gdb_spawn_id -1; + + # FIXME: mi output does not go through pagers, so these can be removed. + # force the height to "unlimited", so no pagers get used + send_gdb "100-gdb-set height 0\n" + gdb_expect 10 { + -re ".*100-gdb-set height 0\r\n100\\\^done\r\n$mi_gdb_prompt$" { + verbose "Setting height to 0." 2 + } + timeout { + warning "Couldn't set the height to 0" + } + } + # force the width to "unlimited", so no wraparound occurs + send_gdb "101-gdb-set width 0\n" + gdb_expect 10 { + -re ".*101-gdb-set width 0\r\n101\\\^done\r\n$mi_gdb_prompt$" { + verbose "Setting width to 0." 2 + } + timeout { + warning "Couldn't set the width to 0." + } + } + + # Finally start SID. + if { [info procs sid_start] != "" } { + verbose "Spawning SID" + sid_start + } + + return 0; +} + +# Many of the tests depend on setting breakpoints at various places and +# running until that breakpoint is reached. At times, we want to start +# with a clean-slate with respect to breakpoints, so this utility proc +# lets us do this without duplicating this code everywhere. +# + +proc mi_delete_breakpoints {} { + global mi_gdb_prompt + +# FIXME: The mi operation won't accept a prompt back and will use the 'all' arg + send_gdb "102-break-delete\n" + gdb_expect 30 { + -re "Delete all breakpoints.*y or n.*$" { + send_gdb "y\n"; + exp_continue + } + -re ".*102-break-delete\r\n102\\\^done\r\n$mi_gdb_prompt$" { + # This happens if there were no breakpoints + } + timeout { perror "Delete all breakpoints in delete_breakpoints (timeout)" ; return } + } + +# The correct output is not "No breakpoints or watchpoints." but an +# empty BreakpointTable. Also, a query is not acceptable with mi. + send_gdb "103-break-list\n" + gdb_expect 30 { + -re "103-break-list\r\n103\\\^done,BreakpointTable=\{\}\r\n$mi_gdb_prompt$" {} + -re "103-break-list\r\n103\\\^doneNo breakpoints or watchpoints.\r\n\r\n$mi_gdb_prompt$" {warning "Unexpected console text received"} + -re "$mi_gdb_prompt$" { perror "Breakpoints not deleted" ; return } + -re "Delete all breakpoints.*or n.*$" { + warning "Unexpected prompt for breakpoints deletion"; + send_gdb "y\n"; + exp_continue + } + timeout { perror "-break-list (timeout)" ; return } + } +} + +proc mi_gdb_reinitialize_dir { subdir } { + global mi_gdb_prompt + + global suppress_flag + if { $suppress_flag } { + return + } + + if [is_remote host] { + return ""; + } + + 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)"} + } + } + -re "$mi_gdb_prompt$" {} + timeout {error "Dir reinitialization failed (timeout)"} + } + + send_gdb "105-environment-directory $subdir\n" + gdb_expect 60 { + -re "Source directories searched.*$mi_gdb_prompt$" { + verbose "Dir set to $subdir" + } + -re "105\\\^done\r\n$mi_gdb_prompt$" { + # FIXME: We return just the prompt for now. + verbose "Dir set to $subdir" + # perror "Dir \"$subdir\" failed." + } + } +} + +# +# load a file into the debugger. +# return a -1 if anything goes wrong. +# +proc mi_gdb_load { arg } { + global verbose + global loadpath + global loadfile + global GDB + global mi_gdb_prompt + upvar timeout timeout + + # ``gdb_unload'' + + # ``gdb_file_cmd'' +# FIXME: Several of these patterns are only acceptable for console +# 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$" { + verbose "\t\tLoaded $arg into the $GDB" + # All OK + } + -re "has no symbol-table.*$mi_gdb_prompt$" { + perror "$arg wasn't compiled with \"-g\"" + return -1 + } + -re "A program is being debugged already.*Kill it.*y or n. $" { + send_gdb "y\n" + verbose "\t\tKilling previous program being debugged" + exp_continue + } + -re "Load new symbol table from \".*\".*y or n. $" { + send_gdb "y\n" + gdb_expect 120 { + -re "Reading symbols from.*done.*$mi_gdb_prompt$" { + verbose "\t\tLoaded $arg with new symbol table into $GDB" + # All OK + } + timeout { + perror "(timeout) Couldn't load $arg, other program already loaded." + return -1 + } + } + } + -re "No such file or directory.*$mi_gdb_prompt$" { + perror "($arg) No such file or directory\n" + return -1 + } + -re "105-file-exec-and-symbols .*\r\n105\\\^done\r\n$mi_gdb_prompt$" { + # We are just giving the prompt back for now + # All OK + } + timeout { + perror "couldn't load $arg into $GDB (timed out)." + return -1 + } + eof { + # This is an attempt to detect a core dump, but seems not to + # work. Perhaps we need to match .* followed by eof, in which + # gdb_expect does not seem to have a way to do that. + perror "couldn't load $arg into $GDB (end of file)." + return -1 + } + } + + # ``load'' + if { [info procs send_target_sid] != "" } { + # For SID, things get complex + send_target_sid + gdb_expect 60 { + -re "\\^done,.*$mi_gdb_prompt$" { + } + timeout { + perror "Unable to connect to SID target" + return -1 + } + } + send_gdb "48-target-download\n" + gdb_expect 10 { + -re "48\\^done.*$mi_gdb_prompt$" { + } + timeout { + perror "Unable to download to SID target" + return -1 + } + } + } elseif { [target_info protocol] == "sim" } { + # For the simulator, just connect to it directly. + send_gdb "47-target-select sim\n" + gdb_expect 10 { + -re "47\\^connected.*$mi_gdb_prompt$" { + } + timeout { + perror "Unable to select sim target" + return -1 + } + } + send_gdb "48-target-download\n" + gdb_expect 10 { + -re "48\\^done.*$mi_gdb_prompt$" { + } + timeout { + perror "Unable to download to sim target" + return -1 + } + } + } + return 0 +} + +# mi_gdb_test COMMAND PATTERN MESSAGE -- 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. +# 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 +# call pass or fail at all; I don't understand this at all.) +# +# Returns: +# 1 if the test failed, +# 0 if the test passes, +# -1 if there was an internal error. +# +proc mi_gdb_test { args } { + global verbose + global mi_gdb_prompt + global GDB + upvar timeout timeout + + if [llength $args]>2 then { + set message [lindex $args 2] + } else { + set message [lindex $args 0] + } + set command [lindex $args 0] + set pattern [lindex $args 1] + + if [llength $args]==5 { + set question_string [lindex $args 3]; + set response_string [lindex $args 4]; + } else { + set question_string "^FOOBAR$" + } + + if $verbose>2 then { + send_user "Sending \"$command\" to gdb\n" + send_user "Looking to match \"$pattern\"\n" + send_user "Message is \"$message\"\n" + } + + set result -1 + set string "${command}\n"; + if { $command != "" } { + while { "$string" != "" } { + set foo [string first "\n" "$string"]; + set len [string length "$string"]; + 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; + } + gdb_expect 2 { + -re "\[\r\n\]" { } + timeout { } + } + set string [string range "$string" [expr $foo + 1] end]; + } else { + break; + } + } + if { "$string" != "" } { + if { [send_gdb "$string"] != "" } { + global suppress_flag; + + if { ! $suppress_flag } { + perror "Couldn't send $command to GDB."; + } + fail "$message"; + return $result; + } + } + } + + if [info exists timeout] { + set tmt $timeout; + } else { + global timeout; + if [info exists timeout] { + set tmt $timeout; + } else { + set tmt 60; + } + } + gdb_expect $tmt { + -re "\\*\\*\\* DOSEXIT code.*" { + if { $message != "" } { + fail "$message"; + } + gdb_suppress_entire_file "GDB died"; + return -1; + } + -re "Ending remote debugging.*$mi_gdb_prompt\[ \]*$" { + if ![isnative] then { + warning "Can`t communicate to remote target." + } + gdb_exit + gdb_start + set result -1 + } + -re "(${question_string})$" { + send_gdb "$response_string\n"; + exp_continue; + } + -re "Undefined.* command:.*$mi_gdb_prompt\[ \]*$" { + perror "Undefined command \"$command\"." + fail "$message" + set result 1 + } + -re "Ambiguous command.*$mi_gdb_prompt\[ \]*$" { + perror "\"$command\" is not a unique command name." + fail "$message" + set result 1 + } + -re "\[\r\n\]*($pattern)\[\r\n\]+$mi_gdb_prompt\[ \]*$" { + if ![string match "" $message] then { + pass "$message" + } + set result 0 + } + -re "Program exited with code \[0-9\]+.*$mi_gdb_prompt\[ \]*$" { + if ![string match "" $message] then { + set errmsg "$message: the program exited" + } else { + set errmsg "$command: the program exited" + } + fail "$errmsg" + return -1 + } + -re "The program is not being run.*$mi_gdb_prompt\[ \]*$" { + if ![string match "" $message] then { + set errmsg "$message: the program is no longer running" + } else { + set errmsg "$command: the program is no longer running" + } + fail "$errmsg" + return -1 + } + -re ".*$mi_gdb_prompt\[ \]*$" { + if ![string match "" $message] then { + fail "$message" + } + set result 1 + } + "<return>" { + 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" + if { $message != "" } { + fail "$message" + } + return -1 + } + full_buffer { + perror "internal buffer is full." + fail "$message" + } + timeout { + if ![string match "" $message] then { + fail "$message (timeout)" + } + set result 1 + } + } + return $result +} + +# +# MI run command. (A modified version of gdb_run_cmd) +# + +# In patterns, the newline sequence ``\r\n'' is matched explicitly as +# ``.*$'' could swallow up output that we attempt to match elsewhere. + +proc mi_run_cmd {args} { + global suppress_flag + if { $suppress_flag } { + return -1 + } + global mi_gdb_prompt + + if [target_info exists gdb_init_command] { + send_gdb "[target_info gdb_init_command]\n"; + gdb_expect 30 { + -re "$mi_gdb_prompt$" { } + default { + perror "gdb_init_command for target failed"; + return; + } + } + } + + if [target_info exists use_gdb_stub] { + if [target_info exists gdb,do_reload_on_run] { + # Specifying no file, defaults to the executable + # currently being debugged. + if { [mi_gdb_load ""] < 0 } { + return; + } + send_gdb "000-exec-continue\n"; + gdb_expect 60 { + -re "Continu\[^\r\n\]*\[\r\n\]" {} + default {} + } + return; + } + } + + send_gdb "000-exec-run $args\n" + gdb_expect { + -re "000\\^running\r\n${mi_gdb_prompt}" { + } + timeout { + perror "Unable to start target" + return + } + } + # NOTE: Shortly after this there will be a ``000*stopping,...(gdb)'' +} + +# +# Just like run-to-main but works with the MI interface +# + +proc mi_run_to_main { } { + global suppress_flag + if { $suppress_flag } { + return -1 + } + + global mi_gdb_prompt + global hex + global decimal + global srcdir + global subdir + global binfile + global srcfile + + set test "mi run-to-main" + mi_delete_breakpoints + mi_gdb_reinitialize_dir $srcdir/$subdir + mi_gdb_load ${binfile} + + mi_gdb_test "200-break-insert main" \ + "200\\^done,bkpt=\{number=\"1\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"$hex\",func=\"main\",file=\".*\",line=\"\[0-9\]*\",times=\"0\"\}" \ + "breakpoint at main" + + mi_run_cmd + gdb_expect { + -re "000\\*stopped,reason=\"breakpoint-hit\",bkptno=\"1\",thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"main\",args=\{\},file=\".*\",line=\"\[0-9\]*\"\}\r\n$mi_gdb_prompt$" { + pass "$test" + return 0 + } + timeout { + fail "$test (timeout)" + return -1 + } + } +} + + +# Next to the next statement + +proc mi_next { test } { + global suppress_flag + if { $suppress_flag } { + return -1 + } + global mi_gdb_prompt + send_gdb "220-exec-next\n" + gdb_expect { + -re "220\\^running\r\n${mi_gdb_prompt}220\\*stopped,reason=\"end-stepping-range\",thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\{.*\},,file=\".*\",line=\"\[0-9\]*\"\}\r\n$mi_gdb_prompt$" { + pass "$test" + return 0 + } + timeout { + fail "$test" + return -1 + } + } +} + + +# Step to the next statement + +proc mi_step { test } { + global suppress_flag + if { $suppress_flag } { + return -1 + } + global mi_gdb_prompt + send_gdb "220-exec-step\n" + gdb_expect { + -re "220\\^running\r\n${mi_gdb_prompt}220\\*stopped,reason=\"end-stepping-range\",thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\{.*\},,file=\".*\",line=\"\[0-9\]*\"\}\r\n$mi_gdb_prompt$" { + pass "$test" + return 0 + } + timeout { + fail "$test" + return -1 + } + } +} + + +# Local variables: +# change-log-default-name: "../gdb.mi/ChangeLog-mi" +# End: |