📄 mi-support.exp
字号:
# 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 expect_out 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 "\[\r\n\]*($pattern)\[\r\n\]+$mi_gdb_prompt\[ \]*$" { if ![string match "" $message] then { pass "$message" } set result 0 } -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 "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 "000\\^running\[\r\n\]+$mi_gdb_prompt$" {} default {} } return; } if [target_info exists gdb,start_symbol] { set start [target_info gdb,start_symbol]; } else { set start "start"; } # HACK: Should either use 000-jump or fix the target code # to better handle RUN. send_gdb "jump *$start\n" warning "Using CLI jump command, expect run-to-main FAIL" 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 srcdir global subdir global binfile global srcfile mi_delete_breakpoints mi_gdb_reinitialize_dir $srcdir/$subdir mi_gdb_load ${binfile} mi_runto main}# Just like gdb's "runto" proc, it will run the target to a given# function. The big difference here between mi_runto and mi_execute_to# is that mi_execute_to must have the inferior running already. This# proc will (like gdb's runto) (re)start the inferior, too.## FUNC is the linespec of the place to stop (it inserts a breakpoint here).# It returns:# -1 if test suppressed, failed, timedout# 0 if test passedproc mi_runto {func} { global suppress_flag if { $suppress_flag } { return -1 } global mi_gdb_prompt expect_out global hex decimal set test "mi runto $func" mi_gdb_test "200-break-insert $func" \ "200\\^done,bkpt=\{number=\"\[0-9\]+\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\",addr=\"$hex\",func=\"$func\",file=\".*\",line=\"\[0-9\]*\",times=\"0\"\}" \ "breakpoint at $func" if {![regexp {number="[0-9]+"} $expect_out(buffer) str] || ![scan $str {number="%d"} bkptno]} { set bkptno {[0-9]+} } mi_run_cmd gdb_expect { -re ".*000\\*stopped,reason=\"breakpoint-hit\",bkptno=\"$bkptno\",thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=\(\\\[.*\\\]\|\{.*\}\),file=\".*\",line=\"\[0-9\]*\"\}\r\n$mi_gdb_prompt$" { pass "$test" return 0 } -re ".*$mi_gdb_prompt$" { fail "$test (2)" } timeout { fail "$test (timeout)" return -1 } }}# Next to the next statement# For return values, see mi_execute_to_helperproc mi_next { test } { return [mi_next_to {.*} {.*} {.*} {.*} $test]}# Step to the next statement# For return values, see mi_execute_to_helperproc mi_step { test } { return [mi_step_to {.*} {.*} {.*} {.*} $test]}# cmd should not include the number or newline (i.e. "exec-step 3", not# "220-exec-step 3\n"# Can not match -re ".*\r\n${mi_gdb_prompt}", because of false positives# after the first prompt is printed.proc mi_execute_to_helper { cmd reason func args file line extra test } { global suppress_flag if { $suppress_flag } { return -1 } global mi_gdb_prompt global hex global decimal send_gdb "220-$cmd\n" gdb_expect { -re ".*220\\^running\r\n${mi_gdb_prompt}.*220\\*stopped,reason=\"$reason\",thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",line=\"$line\"\}$extra\r\n$mi_gdb_prompt$" { pass "$test" return 0 } -re ".*220\\^running\r\n${mi_gdb_prompt}.*220\\*stopped,reason=\"$reason\",thread-id=\"$decimal\",frame=\{addr=\"$hex\",func=\".*\",args=\[\\\[\{\].*\[\\\]\}\],file=\".*\",line=\"\[0-9\]*\"\}.*\r\n$mi_gdb_prompt$" { fail "$test (stopped at wrong place)" return -1 } -re "220\\^running\r\n${mi_gdb_prompt}.*\r\n${mi_gdb_prompt}$" { fail "$test (unknown output after running)" return -1 } timeout { fail "$test (timeout)" return -1 } }}proc mi_execute_to { cmd reason func args file line extra test } { mi_execute_to_helper "$cmd" "$reason" "$func" "\\\[$args\\\]" \ "$file" "$line" "$extra" "$test"}proc mi_next_to { func args file line test } { mi_execute_to "exec-next" "end-stepping-range" "$func" "$args" \ "$file" "$line" "" "$test"}proc mi_step_to { func args file line test } { mi_execute_to "exec-step" "end-stepping-range" "$func" "$args" \ "$file" "$line" "" "$test"}proc mi_finish_to { func args file line result ret test } { mi_execute_to "exec-finish" "function-finished" "$func" "$args" \ "$file" "$line" \ ",gdb-result-var=\"$result\",return-value=\"$ret\"" \ "$test"}proc mi_continue_to { bkptno func args file line test } { mi_execute_to "exec-continue" "breakpoint-hit\",bkptno=\"$bkptno" \ "$func" "$args" "$file" "$line" "" "$test"}proc mi0_execute_to { cmd reason func args file line extra test } { mi_execute_to_helper "$cmd" "$reason" "$func" "\{$args\}" \ "$file" "$line" "$extra" "$test"}proc mi0_next_to { func args file line test } { mi0_execute_to "exec-next" "end-stepping-range" "$func" "$args" \ "$file" "$line" "" "$test"}proc mi0_step_to { func args file line test } { mi0_execute_to "exec-step" "end-stepping-range" "$func" "$args" \ "$file" "$line" "" "$test"}proc mi0_finish_to { func args file line result ret test } { mi0_execute_to "exec-finish" "function-finished" "$func" "$args" \ "$file" "$line" \ ",gdb-result-var=\"$result\",return-value=\"$ret\"" \ "$test"}proc mi0_continue_to { bkptno func args file line test } { mi0_execute_to "exec-continue" "breakpoint-hit\",bkptno=\"$bkptno" \ "$func" "$args" "$file" "$line" "" "$test"}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -