📄 gdb.exp
字号:
set expecting_action 1 lappend processed_code $subst_item if {$patterns != ""} { append patterns "; " } append patterns "\"$subst_item\"" } # Also purely cosmetic. regsub -all {\r} $patterns {\\r} patterns regsub -all {\n} $patterns {\\n} patterns if $verbose>2 then { send_user "Sending \"$command\" to gdb\n" send_user "Looking to match \"$patterns\"\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; } # since we're checking if each line of the multi-line # command are 'accepted' by GDB here, # we need to set -notransfer expect option so that # command output is not lost for pattern matching # - guo gdb_expect 2 { -notransfer -re "\[\r\n\]" { verbose "partial: match" 3 } timeout { verbose "partial: timeout" 3 } } 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 [target_info exists gdb,timeout] { set tmt [target_info gdb,timeout]; } else { if [info exists timeout] { set tmt $timeout; } else { global timeout; if [info exists timeout] { set tmt $timeout; } else { set tmt 60; } } } set code { -re ".*A problem internal to GDB has been detected" { fail "$message (GDB internal error)" gdb_internal_error_resync } -re "\\*\\*\\* DOSEXIT code.*" { if { $message != "" } { fail "$message"; } gdb_suppress_entire_file "GDB died"; set result -1; } -re "Ending remote debugging.*$gdb_prompt $" { if ![isnative] then { warning "Can`t communicate to remote target." } gdb_exit gdb_start set result -1 } } append code $processed_code append code { -re "Undefined\[a-z\]* command:.*$gdb_prompt $" { perror "Undefined command \"$command\"." fail "$message" set result 1 } -re "Ambiguous command.*$gdb_prompt $" { perror "\"$command\" is not a unique command name." fail "$message" set result 1 } -re "Program exited with code \[0-9\]+.*$gdb_prompt $" { if ![string match "" $message] then { set errmsg "$message (the program exited)" } else { set errmsg "$command (the program exited)" } fail "$errmsg" set result -1 } -re "EXIT code \[0-9\r\n\]+Program exited normally.*$gdb_prompt $" { if ![string match "" $message] then { set errmsg "$message (the program exited)" } else { set errmsg "$command (the program exited)" } fail "$errmsg" set result -1 } -re "The program is not being run.*$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" set result -1 } -re "\r\n$gdb_prompt $" { if ![string match "" $message] then { fail "$message" } set result 1 } "<return>" { send_gdb "\n" perror "Window too small." fail "$message" set result -1 } -re "\\(y or n\\) " { send_gdb "n\n" perror "Got interactive prompt." fail "$message" set result -1 } eof { perror "Process no longer exists" if { $message != "" } { fail "$message" } return -1 } full_buffer { perror "internal buffer is full." fail "$message" set result -1 } timeout { if ![string match "" $message] then { fail "$message (timeout)" } set result 1 } } set result 0 set code [catch {gdb_expect $tmt $code} string] if {$code == 1} { global errorInfo errorCode; return -code error -errorinfo $errorInfo -errorcode $errorCode $string } elseif {$code == 2} { return -code return $string } elseif {$code == 3} { return } elseif {$code > 4} { return -code $code $string } return $result}# gdb_test COMMAND PATTERN MESSAGE QUESTION RESPONSE# 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.)# QUESTION is a question GDB may ask in response to COMMAND, like# "are you sure?"# RESPONSE is the response to send if QUESTION appears.## Returns:# 1 if the test failed,# 0 if the test passes,# -1 if there was an internal error.# proc gdb_test { args } { global verbose global 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$" } return [gdb_test_multiple $command $message { -re "\[\r\n\]*($pattern)\[\r\n\]+$gdb_prompt $" { if ![string match "" $message] then { pass "$message" } } -re "(${question_string})$" { send_gdb "$response_string\n"; exp_continue; } }]}# Test that a command gives an error. For pass or fail, return# a 1 to indicate that more tests can proceed. However a timeout# is a serious error, generates a special fail message, and causes# a 0 to be returned to indicate that more tests are likely to fail# as well.proc test_print_reject { args } { global gdb_prompt global verbose if [llength $args]==2 then { set expectthis [lindex $args 1] } else { set expectthis "should never match this bogus string" } set sendthis [lindex $args 0] if $verbose>2 then { send_user "Sending \"$sendthis\" to gdb\n" send_user "Looking to match \"$expectthis\"\n" } send_gdb "$sendthis\n" #FIXME: Should add timeout as parameter. gdb_expect { -re "A .* in expression.*\\.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "Invalid syntax in expression.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "Junk after end of expression.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "Invalid number.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "Invalid character constant.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "No symbol table is loaded.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "No symbol .* in current context.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "Unmatched single quote.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "A character constant must contain at least one character.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re "$expectthis.*$gdb_prompt $" { pass "reject $sendthis" return 1 } -re ".*$gdb_prompt $" { fail "reject $sendthis" return 1 } default { fail "reject $sendthis (eof or timeout)" return 0 } }}# Given an input string, adds backslashes as needed to create a# regexp that will match the string.proc string_to_regexp {str} { set result $str regsub -all {[]*+.|()^$\[]} $str {\\&} result return $result}# Same as gdb_test, but the second parameter is not a regexp,# but a string that must match exactly.proc gdb_test_exact { args } { upvar timeout timeout set command [lindex $args 0] # This applies a special meaning to a null string pattern. Without # this, "$pattern\r\n$gdb_prompt $" will match anything, including error # messages from commands that should have no output except a new # prompt. With this, only results of a null string will match a null # string pattern. set pattern [lindex $args 1] if [string match $pattern ""] { set pattern [string_to_regexp [lindex $args 0]] } else { set pattern [string_to_regexp [lindex $args 1]] } # It is most natural to write the pattern argument with only # embedded \n's, especially if you are trying to avoid Tcl quoting # problems. But gdb_expect really wants to see \r\n in patterns. So # transform the pattern here. First transform \r\n back to \n, in # case some users of gdb_test_exact already do the right thing. regsub -all "\r\n" $pattern "\n" pattern regsub -all "\n" $pattern "\r\n" pattern if [llength $args]==3 then { set message [lindex $args 2] } else { set message $command } return [gdb_test $command $pattern $message]}proc gdb_reinitialize_dir { subdir } { global gdb_prompt if [is_remote host] { return ""; } send_gdb "dir\n" gdb_expect 60 { -re "Reinitialize source path to empty.*y or n. " { send_gdb "y\n" gdb_expect 60 { -re "Source directories searched.*$gdb_prompt $" { send_gdb "dir $subdir\n" gdb_expect 60 { -re "Source directories searched.*$gdb_prompt $" { verbose "Dir set to $subdir" } -re "$gdb_prompt $" { perror "Dir \"$subdir\" failed." } } } -re "$gdb_prompt $" { perror "Dir \"$subdir\" failed." } } } -re "$gdb_prompt $" { perror "Dir \"$subdir\" failed." } }}## gdb_exit -- exit the GDB, killing the target program if necessary#proc default_gdb_exit {} { global GDB global GDBFLAGS global verbose global gdb_spawn_id; gdb_stop_suppressing_tests; if ![info exists gdb_spawn_id] { return; } verbose "Quitting $GDB $GDBFLAGS" if { [is_remote host] && [board_info host exists fileid] } { send_gdb "quit\n"; gdb_expect 10 { -re "y or n" { send_gdb "y\n"; exp_continue; } -re "DOSEXIT code" { } default { } } } if ![is_remote host] { remote_close host; } unset gdb_spawn_id}# Load a file into the debugger.# The return value is 0 for success, -1 for failure.## This procedure also set the global variable GDB_FILE_CMD_DEBUG_INFO# to one of these values:## debug file was loaded successfully and has debug information# nodebug file was loaded successfully and has no debug information# fail file was not loaded## I tried returning this information as part of the return value,# but ran into a mess because of the many re-implementations of# gdb_load in config/*.exp.## TODO: gdb.base/sepdebug.exp and gdb.stabs/weird.exp might be able to use# this if they can get more information set.proc gdb_file_cmd { arg } { global gdb_prompt global verbose global GDB # Set whether debug info was found. # Default to "fail". global gdb_file_cmd_debug_info set gdb_file_cmd_debug_info "fail" if [is_remote host] { set arg [remote_download host $arg] if { $arg == "" } { perror "download failed" return -1 } } send_gdb "file $arg\n" gdb_expect 120 { -re "Reading symbols from.*no debugging symbols found.*done.*$gdb_prompt $" { verbose "\t\tLoaded $arg into the $GDB with no debugging symbols" set gdb_file_cmd_debug_info "nodebug" return 0 } -re "Reading symbols from.*done.*$gdb_prompt $" { verbose "\t\tLoaded $arg into the $GDB" set gdb_file_cmd_debug_info "debug" return 0 } -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.*$gdb_prompt $" { verbose "\t\tLoaded $arg with new symbol table into $GDB" set gdb_file_cmd_debug_info "debug" return 0 } timeout { perror "(timeout) Couldn't load $arg, other program already loaded." return -1 } } } -re "No such file or directory.*$gdb_prompt $" { perror "($arg) No such file or directory" return -1 } -re "$gdb_prompt $" { perror "couldn't load $arg into $GDB." return -1 } 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 } }}## start gdb -- start gdb running, default procedure#
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -