diff options
Diffstat (limited to 'config/gdb_stub.exp')
-rw-r--r-- | config/gdb_stub.exp | 638 |
1 files changed, 638 insertions, 0 deletions
diff --git a/config/gdb_stub.exp b/config/gdb_stub.exp new file mode 100644 index 0000000..127c6eb --- /dev/null +++ b/config/gdb_stub.exp @@ -0,0 +1,638 @@ +# Copyright (C) 1996-98, 1999 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: +# DejaGnu@cygnus.com + +# This file was written by Michael Snyder <msnyder@cygnus.com>. + +# +# Stub remote run command. +# + +proc gdb_stub_init { dest args } { + global gdb_prompt + global GDB + global tool_root_dir + + if ![info exists GDB] then { + set GDB "[lookfor_file ${tool_root_dir} gdb/gdb]" + if { $GDB == "" } { + set GDB [transform gdb] + } + } + + if [board_info $dest exists gdb_prompt] { + set gdb_prompt [board_info $dest gdb_prompt]; + } else { + set gdb_prompt "\\(gdb\\)" + } + + return 1; +} + +proc gdb_stub_restart { dest } { + global gdb_prompt + global GDB + + gdb_stub_init $dest; + + for {set x 1;} { $x < 4 } {incr x} { + remote_close $dest; + sleep 2; + set command "$GDB -nw -nx"; + if [host_info exists gdb_opts] { + append command " [host_info gdb_opts]"; + } + set spawn_id [remote_spawn host $command]; + remote_expect host 30 { + -re "$gdb_prompt" { } + } + if { $spawn_id >= 0 } { + if [board_info $dest exists baud] { + remote_send host "set remotebaud [board_info $dest baud]\n"; + remote_expect host 5 { + -re "$gdb_prompt" { } + default { + warning "Error setting baud rate." + return -1; + } + } + } + + + set value [gdb_stub_startup $dest]; + if { $value > 0 } { + break; + } + verbose "got $value from gdb_stub_startup"; + remote_send host "quit\n"; + } + remote_reboot $dest; + } + if { ${x} < 4 } { + global board_info; + set name [board_info $dest name]; + + set board_info($name,gdb_is_running) 1; + return 1; + } else { + return 0; + } +} + +proc gdb_stub_remote_check { dest } { + global gdb_prompt + + if [board_info $dest exists gdb_serial] { + set serial [board_info $dest gdb_serial]; + } elseif [board_info $dest exists serial] { + set serial [board_info $dest serial]; + } else { + set serial [board_info $dest netport]; + } + remote_send host "target remote $serial\n"; + remote_expect host 10 { + -re "Couldn't establish connection.*$gdb_prompt" { + return 0; + } + -re "Remote debugging.*$gdb_prompt" { + verbose "stub is already running" + return 1; + } + -re "$gdb_prompt" { + return 0; + } + timeout { + remote_send host "\003"; + remote_expect host 10 { + -re "$gdb_prompt" { } + } + return 0; + } + default { + return 0; + } + } +} + +proc gdb_stub_startup { dest } { + global gdb_prompt + global GDB + + set is_running_stub 0; + + if [gdb_stub_remote_check $dest] { + set is_running_stub 1; + } + + if [board_info $dest exists serial] { + set serial [board_info $dest serial]; + } else { + set serial [board_info $dest netport]; + } + + if { ! $is_running_stub } { + set command "target [board_info $dest gdb_protocol] $serial\n"; + remote_send host $command; + remote_expect host 5 { + -re "already.*y or n." { + remote_send host "y\n"; + exp_continue; + } + -re "appears to be alive.*$gdb_prompt" { } + -re "Remote target.*connected to.*$gdb_prompt" { } + default { + return -1; + } + } + } + if { $is_running_stub == 0 } { + global libdir + + verbose "building loader"; + set loader "loader"; + if ![file exists $loader] { + if [board_info $dest exists gdb_stub_offset] { + set result [target_compile "${libdir}/stub-loader.c" $loader executable "libs=-Wl,-Ttext,[board_info $dest gdb_stub_offset]"]; + } else { + set result [target_compile "${libdir}/stub-loader.c" $loader executable "ldscript=[board_info $dest gdb_stub_ldscript]"]; + } + verbose "result is $result"; + if [is_remote host] { + set loader [remote_download host $loader]; + } + } + remote_send host "file $loader\n"; + remote_expect host 20 { + -re "A program is being debug.*Kill it.*y or n. $" { + remote_send host "y\n" + exp_continue + } + -re "Load new symbol table.*y or n. $" { + remote_send host "y\n" + exp_continue + } + -re "Reading symbols from.*done..*$gdb_prompt $" {} + -re "$gdb_prompt $" { warning "GDB couldn't find loader" } + timeout { + warning "(timeout) read symbol file" ; + return -1 + } + } + + if [board_info $dest exists serial] { + set serial [board_info $dest serial]; + } else { + set serial [board_info $dest netport]; + } + remote_send host "target [board_info $dest gdb_protocol] $serial\n"; + remote_expect host 60 { + -re "appears to be alive.*$gdb_prompt" { } + -re "Remote target.*connected to.*$gdb_prompt" { } + -re "$gdb_prompt" { + warning "Error reconnecting to stub."; + return -1; + } + default { + warning "Error reconnecting to stub."; + return -1; + } + } + + # We only send the offset if gdb_load_offset is set. Otherwise, we + # assume that sending the offset isn't needed. + if [board_info $dest exists gdb_load_offset] { + remote_send host "load $loader [board_info $dest gdb_stub_offset]\n" + } else { + remote_send host "load $loader\n"; + } + verbose "Loading $loader into $GDB" 2 + global verbose + set no_run_command 0; + # FIXME: The value 1200 below should be a parameter. + remote_expect host 1200 { + -re "Transfer rate:.*Switching to remote protocol.*Remote debugging" { + set no_run_command 1; + remote_send host ""; + sleep 2; + remote_send host ""; + sleep 1; + } + -re "Loading.*Starting.*at.*$gdb_prompt $" { + verbose "Loaded $loader into $GDB" 1 + set no_run_command 1; + } + -re "Loading.*$gdb_prompt $" { + verbose "Loaded $loader into $GDB" 1 + } + -re "$gdb_prompt $" { + if $verbose>1 then { + warning "GDB couldn't load." + } + } + timeout { + if $verbose>1 then { + warning "Timed out trying to load $arg." + } + } + } + + if { ! $no_run_command } { + remote_send host "run\n"; + remote_expect host 60 { + -re "A program is being debug.*Kill it.*y or n. $" { + remote_send host "y\n" + exp_continue + } + -re "The program being debugged .*y or n. $" { + remote_send host "y\n" + exp_continue + } + -re "Starting program:.*loader.*$" { + verbose "Starting loader succeeded" + } + timeout { + warning "(timeout) starting the loader" ; + return -1 + } + default { + warning "error starting the loader"; + } + } + sleep 2; + remote_send host "" + sleep 1; + remote_send host "" + verbose "Sent ^C^C" + remote_expect host 30 { + -re "Give up .and stop debugging it.*$" { + remote_send host "y\n" + exp_continue + } + -re "$gdb_prompt $" { + verbose "Running loader succeeded" + } + timeout { + warning "(timeout) interrupting the loader" ; + return -1 + } + default { + warning "error interrupting the loader"; + } + } + } + remote_send host "quit\n"; + return [gdb_stub_restart $dest]; + } + return 1; +} + +# +# Delete all breakpoints and verify that they were deleted. If anything +# goes wrong we just exit. +# +proc gdb_stub_delete_breakpoints {} { + global gdb_prompt + + remote_send host "delete breakpoints\n" + remote_expect host 10 { + -re "Delete all breakpoints.*y or n. $" { + remote_send host "y\n" + exp_continue + } + -re "$gdb_prompt $" { } + timeout { warning "Delete all breakpoints (timeout)" ; return -1} + } + remote_send host "info breakpoints\n" + remote_expect host 10 { + -re "No breakpoints or watchpoints..*$gdb_prompt $" {} + -re "$gdb_prompt $" { warning "breakpoints not deleted" ; return -1} + timeout { warning "info breakpoints (timeout)" ; return -1} + } + return 0; +} + +proc gdb_stub_go_idle { dest } { + gdb_stub_delete_breakpoints +} + +proc gdb_stub_add_breakpoint { function args } { + global gdb_prompt + + remote_send host "break $function\n" + remote_expect host 60 { + -re "Breakpoint (\[0-9\]+).*$gdb_prompt $" { return $expect_out(1,string) } + -re "Function.*not defined.*$gdb_prompt $" { return "undef" } + -re "No symbol table.*$gdb_prompt $" { return "undef" } + default { + return "undef" + } + } +} + +proc gdb_stub_start { dest } { + global gdb_prompt; + + set exit_brnum [gdb_stub_add_breakpoint _exit]; + if { $exit_brnum == "undef" || [board_info $dest exists always_break_exit] } { + set exit_brnum [gdb_stub_add_breakpoint exit]; + } + set abort_brnum [gdb_stub_add_breakpoint abort]; + + upvar #0 gdb_stub_info I + set I($dest,exit_brnum) $exit_brnum + set I($dest,abort_brnum) $abort_brnum + + remote_send host "set \$fp=0\n"; + remote_expect host 10 { + -re "$gdb_prompt" { } + } + # This is needed for the SparcLite. Whee. + if [board_info $dest exists gdb,start_symbol] { + set start_comm "jump *[board_info $dest gdb,start_symbol]\n"; + } else { + set start_comm "jump *start\n"; + } + remote_send host "break copyloop\n"; + remote_expect host 10 { + -re "Breakpoint.*$gdb_prompt $" { + set start_comm "continue\n"; + } + -re "Function.*not defined.*$gdb_prompt $" { } + default { } + } + remote_send host $start_comm; + remote_expect host 10 { + -re "y or n. $" { + remote_send host "y\n" + exp_continue; + } + -re "Breakpoint.*in copyloop.*$gdb_prompt $" { + remote_send host "jump relocd\n"; + exp_continue; + } + -re "Continuing at.*\[\r\n\]" { } + default { + return { "fail" "" }; + } + } + return { "pass" "" }; +} + +proc gdb_stub_spawn { dest prog args } { + for { set x 0; } { $x < 3 } { incr x } { + if { [remote_ld $dest $prog] != 1 } { + return [list "fail" "remote_ld failed"]; + } + + set result [gdb_stub_start $dest]; + if { [lindex $result 0] != "pass" } { + remote_reboot target; + } else { + return 666; # does anyone use this value? + } + } + return -1; +} + +proc gdb_stub_wait { dest timeout } { + global gdb_prompt + + + upvar #0 gdb_stub_info I + set exit_brnum $I($dest,exit_brnum) + set abort_brnum $I($dest,abort_brnum) + + remote_expect host $timeout { + -re "Breakpoint.*exit.*=0.*$gdb_prompt $" { + gdb_stub_go_idle $dest + return [list 0 ""]; + } + -re "Breakpoint.*exit.*=\[1-9\]\[0-9\]*.*$gdb_prompt $" { + gdb_stub_go_idle $dest + return [list 0 ""]; + } + -re "Breakpoint.*exit.*$gdb_prompt $" { + gdb_stub_go_idle $dest + return [list 0 ""]; + } + -re "Breakpoint.*abort.*$gdb_prompt $" { + gdb_stub_go_idle $dest + return [list 1 ""]; + } + -re " EXIT code 0.*$gdb_prompt $" { + gdb_stub_go_idle $dest; + return [list 0 ""]; + } + -re " EXIT code \[1-9]\[0-9]*.*$gdb_prompt $" { + gdb_stub_go_idle $dest; + return [list 0 ""]; + } + -re " EXIT code 4242.*$gdb_prompt $" { + gdb_stub_go_idle $dest; + return [list 1 ""]; + } + -re "Program received.*$gdb_prompt $" { + gdb_stub_go_idle $dest + return [list 1 ""]; + } + -re "Program exited.*$gdb_prompt $" { + gdb_stub_go_idle $dest + return [list 1 ""]; + } + -re "Breakpoint $exit_brnum.*$gdb_prompt $" { + gdb_stub_go_idle $dest; + return [list 0 ""]; + } + -re "Breakpoint $abort_brnum.*$gdb_prompt $" { + gdb_stub_go_idle $dest; + return [list 1 ""]; + } + default { + remote_close $dest; + remote_reboot $dest; + return [list -1 ""]; + } + } + return [list -1 ""]; +} + +proc gdb_stub_load { dest prog args } { + global gdb_prompt + set argnames { "command-line arguments" "input file" "output file" } + + for { set x 0; } { $x < [llength $args] } { incr x } { + if { [lindex $args $x] != "" } { + return [list "unsupported" "no support for [lindex $argnames $x] on this target"]; + } + } + + set result [remote_spawn $dest $prog]; + + if { $result < 0 } { + return [list "fail" "remote_spawn failed"]; + } + + # FIXME: The value 120 should be a parameter. + set result [remote_wait $dest 120]; + set status [lindex $result 0]; + set output [lindex $result 1]; + + if { $status == 0 } { + return [list "pass" $output]; + } elseif { $status > 0 } { + return [list "fail" $output]; + } else { + global gdb_stub_retry; + + if ![info exists gdb_stub_retry] { + set gdb_stub_retry 1; + + set result [eval gdb_stub_load \{$dest\} \{$prog\} $args]; + unset gdb_stub_retry; + return $result; + } else { + return [list "fail" $output]; + } + } +} + + +# +# gdb_stub_ld -- load PROG into the board; +# Returns a 0 if there was an error, +# 1 if it loaded successfully. +# +proc gdb_stub_ld { dest prog } { + global gdb_prompt + global GDB + + if ![board_info $dest exists gdb_is_running] { + if ![gdb_stub_restart $dest] { + return 0; + } + } + + set loadfile [file tail $prog] + set loadpath [file dirname $prog] + + remote_send host "file $prog\n" + remote_expect host 30 { + -re "A program is being debug.*Kill it.*y or n. $" { + remote_send host "y\n" + exp_continue + } + -re "Load new symbol table.*y or n. $" { + remote_send host "y\n" + exp_continue + } + -re "Reading symbols from.*done..*$gdb_prompt $" {} + -re "$gdb_prompt $" { + # Hmmm...is retrying going to help? I kinda doubt it. + warning "GDB couldn't read file" + return [gdb_stub_retry_ld "$dest" "$prog"]; + } + timeout { + warning "(timeout) read symbol file"; + return [gdb_stub_retry_ld "$dest" "$prog"]; + } + } + + # just in case there are old breakpoints lying around. + gdb_stub_delete_breakpoints + + if [board_info $dest exists gdb_serial] { + set serial [board_info $dest gdb_serial]; + } elseif [board_info $dest exists serial] { + set serial [board_info $dest serial]; + } else { + set serial [board_info $dest netport]; + } + + remote_send host "target remote $serial\n" + remote_expect host 60 { + -re "Kill it?.*y or n.*" { + remote_send host "y\n"; + exp_continue + } + -re "$gdb_prompt $" { + verbose "Set remote target to $serial" 2 + } + timeout { + warning "Couldn't set remote target." + return 0 + } + } + + if [board_info $dest exists gdb_load_offset] { + set offset "[board_info $dest gdb_load_offset]"; + } else { + set offset ""; + } + remote_send host "load $prog $offset\n" + verbose "Loading $prog into $GDB" 2 + global verbose; + remote_expect host 1200 { + -re "Loading.*$gdb_prompt $" { + verbose "Loaded $prog into $GDB" 1 + } + -re "$gdb_prompt $" { + if $verbose>1 then { + warning "GDB couldn't load." + } + } + timeout { + if $verbose>1 then { + perror "Timed out trying to load $prog." + } + } + } + return 1 +} + +# +# Retry the ld operation, but only once. +# + +proc gdb_stub_retry_ld { dest prog } { + global gdb_stub_retry_ld; + + remote_reboot $dest; + if [info exists gdb_stub_retry_ld] { + unset gdb_stub_retry_ld; + return 0; + } else { + set gdb_stub_retry_ld 1; + } + gdb_stub_restart $dest; + set status [gdb_stub_ld $dest $prog]; + if [info exists gdb_stub_retry_ld] { + unset gdb_stub_retry_ld; + } + return $status; +} + +proc gdb_stub_close { dest } { + global board_info + set name [board_info $dest name]; + if [info exists board_info($name,gdb_is_running)] { + unset board_info($name,gdb_is_running); + } + return [remote_close host]; +} + +set_board_info protocol "gdb_stub" |