1# Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software 2# Foundation, Inc. 3# 4# This file is part of DejaGnu. 5# 6# DejaGnu is free software; you can redistribute it and/or modify it 7# under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# DejaGnu is distributed in the hope that it will be useful, but 12# WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14# General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with DejaGnu; if not, write to the Free Software Foundation, 18# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 20# This file was written by Michael Snyder <msnyder@cygnus.com>. 21 22# 23# Stub remote run command. 24# 25 26proc gdb_stub_init { dest args } { 27 global gdb_prompt 28 global GDB 29 global tool_root_dir 30 31 if ![info exists GDB] then { 32 set GDB "[lookfor_file ${tool_root_dir} gdb/gdb]" 33 if { $GDB == "" } { 34 set GDB [transform gdb] 35 } 36 } 37 38 if [board_info $dest exists gdb_prompt] { 39 set gdb_prompt [board_info $dest gdb_prompt] 40 } else { 41 set gdb_prompt "\\(gdb\\)" 42 } 43 44 return 1 45} 46 47proc gdb_stub_restart { dest } { 48 global gdb_prompt 49 global GDB 50 51 gdb_stub_init $dest 52 53 for { set x 1 } { $x < 4 } {incr x} { 54 remote_close $dest 55 sleep 2 56 set command "$GDB -nw -nx" 57 if [host_info exists gdb_opts] { 58 append command " [host_info gdb_opts]" 59 } 60 set spawn_id [remote_spawn host $command] 61 remote_expect host 30 { 62 -re "$gdb_prompt" { } 63 } 64 if { $spawn_id >= 0 } { 65 if [board_info $dest exists baud] { 66 remote_send host "set remotebaud [board_info $dest baud]\n" 67 remote_expect host 5 { 68 -re "$gdb_prompt" { } 69 default { 70 warning "Error setting baud rate." 71 return -1 72 } 73 } 74 } 75 76 77 set value [gdb_stub_startup $dest] 78 if { $value > 0 } { 79 break 80 } 81 verbose "got $value from gdb_stub_startup" 82 remote_send host "quit\n" 83 } 84 remote_reboot $dest 85 } 86 if { ${x} < 4 } { 87 global board_info 88 set name [board_info $dest name] 89 90 set board_info($name,gdb_is_running) 1 91 return 1 92 } else { 93 return 0 94 } 95} 96 97proc gdb_stub_remote_check { dest } { 98 global gdb_prompt 99 100 if [board_info $dest exists gdb_serial] { 101 set serial [board_info $dest gdb_serial] 102 } elseif [board_info $dest exists serial] { 103 set serial [board_info $dest serial] 104 } else { 105 set serial [board_info $dest netport] 106 } 107 remote_send host "target remote $serial\n" 108 remote_expect host 10 { 109 -re "Couldn't establish connection.*$gdb_prompt" { 110 return 0 111 } 112 -re "Remote debugging.*$gdb_prompt" { 113 verbose "stub is already running" 114 return 1 115 } 116 -re "$gdb_prompt" { 117 return 0 118 } 119 timeout { 120 remote_send host "\003" 121 remote_expect host 10 { 122 -re "$gdb_prompt" { } 123 } 124 return 0 125 } 126 default { 127 return 0 128 } 129 } 130} 131 132proc gdb_stub_startup { dest } { 133 global gdb_prompt 134 global GDB 135 136 set is_running_stub 0 137 138 if [gdb_stub_remote_check $dest] { 139 set is_running_stub 1 140 } 141 142 if [board_info $dest exists serial] { 143 set serial [board_info $dest serial] 144 } else { 145 set serial [board_info $dest netport] 146 } 147 148 if { ! $is_running_stub } { 149 set command "target [board_info $dest gdb_protocol] $serial\n" 150 remote_send host $command 151 remote_expect host 5 { 152 -re "already.*y or n." { 153 remote_send host "y\n" 154 exp_continue 155 } 156 -re "appears to be alive.*$gdb_prompt" { } 157 -re "Remote target.*connected to.*$gdb_prompt" { } 158 default { 159 return -1 160 } 161 } 162 } 163 if { $is_running_stub == 0 } { 164 global libdir 165 166 verbose "building loader" 167 set loader "loader" 168 if ![file exists $loader] { 169 if [board_info $dest exists gdb_stub_offset] { 170 set result [target_compile "${libdir}/stub-loader.c" $loader executable "libs=-Wl,-Ttext,[board_info $dest gdb_stub_offset]"] 171 } else { 172 set result [target_compile "${libdir}/stub-loader.c" $loader executable "ldscript=[board_info $dest gdb_stub_ldscript]"] 173 } 174 verbose "result is $result" 175 if [is_remote host] { 176 set loader [remote_download host $loader] 177 } 178 } 179 remote_send host "file $loader\n" 180 remote_expect host 20 { 181 -re "A program is being debug.*Kill it.*y or n. $" { 182 remote_send host "y\n" 183 exp_continue 184 } 185 -re "Load new symbol table.*y or n. $" { 186 remote_send host "y\n" 187 exp_continue 188 } 189 -re "Reading symbols from.*done..*$gdb_prompt $" {} 190 -re "$gdb_prompt $" { warning "GDB couldn't find loader" } 191 timeout { 192 warning "(timeout) read symbol file" 193 return -1 194 } 195 } 196 197 if [board_info $dest exists serial] { 198 set serial [board_info $dest serial] 199 } else { 200 set serial [board_info $dest netport] 201 } 202 remote_send host "target [board_info $dest gdb_protocol] $serial\n" 203 remote_expect host 60 { 204 -re "appears to be alive.*$gdb_prompt" { } 205 -re "Remote target.*connected to.*$gdb_prompt" { } 206 -re "$gdb_prompt" { 207 warning "Error reconnecting to stub." 208 return -1 209 } 210 default { 211 warning "Error reconnecting to stub." 212 return -1 213 } 214 } 215 216 # We only send the offset if gdb_load_offset is set. Otherwise, we 217 # assume that sending the offset isn't needed. 218 if [board_info $dest exists gdb_load_offset] { 219 remote_send host "load $loader [board_info $dest gdb_stub_offset]\n" 220 } else { 221 remote_send host "load $loader\n" 222 } 223 verbose "Loading $loader into $GDB" 2 224 global verbose 225 set no_run_command 0 226 # FIXME: The value 1200 below should be a parameter. 227 remote_expect host 1200 { 228 -re "Transfer rate:.*Switching to remote protocol.*Remote debugging" { 229 set no_run_command 1 230 remote_send host "" 231 sleep 2 232 remote_send host "" 233 sleep 1 234 } 235 -re "Loading.*Starting.*at.*$gdb_prompt $" { 236 verbose "Loaded $loader into $GDB" 1 237 set no_run_command 1 238 } 239 -re "Loading.*$gdb_prompt $" { 240 verbose "Loaded $loader into $GDB" 1 241 } 242 -re "$gdb_prompt $" { 243 if $verbose>1 then { 244 warning "GDB couldn't load." 245 } 246 } 247 timeout { 248 if $verbose>1 then { 249 warning "Timed out trying to load $arg." 250 } 251 } 252 } 253 254 if { ! $no_run_command } { 255 remote_send host "run\n" 256 remote_expect host 60 { 257 -re "A program is being debug.*Kill it.*y or n. $" { 258 remote_send host "y\n" 259 exp_continue 260 } 261 -re "The program being debugged .*y or n. $" { 262 remote_send host "y\n" 263 exp_continue 264 } 265 -re "Starting program:.*loader.*$" { 266 verbose "Starting loader succeeded" 267 } 268 timeout { 269 warning "(timeout) starting the loader" 270 return -1 271 } 272 default { 273 warning "error starting the loader" 274 } 275 } 276 sleep 2 277 remote_send host "" 278 sleep 1 279 remote_send host "" 280 verbose "Sent ^C^C" 281 remote_expect host 30 { 282 -re "Give up .and stop debugging it.*$" { 283 remote_send host "y\n" 284 exp_continue 285 } 286 -re "$gdb_prompt $" { 287 verbose "Running loader succeeded" 288 } 289 timeout { 290 warning "(timeout) interrupting the loader" 291 return -1 292 } 293 default { 294 warning "error interrupting the loader" 295 } 296 } 297 } 298 remote_send host "quit\n" 299 return [gdb_stub_restart $dest] 300 } 301 return 1 302} 303 304# 305# Delete all breakpoints and verify that they were deleted. If anything 306# goes wrong we just exit. 307# 308proc gdb_stub_delete_breakpoints {} { 309 global gdb_prompt 310 311 remote_send host "delete breakpoints\n" 312 remote_expect host 10 { 313 -re "Delete all breakpoints.*y or n. $" { 314 remote_send host "y\n" 315 exp_continue 316 } 317 -re "$gdb_prompt $" { } 318 timeout { warning "Delete all breakpoints (timeout)" ; return -1} 319 } 320 remote_send host "info breakpoints\n" 321 remote_expect host 10 { 322 -re "No breakpoints or watchpoints..*$gdb_prompt $" {} 323 -re "$gdb_prompt $" { warning "breakpoints not deleted" ; return -1} 324 timeout { warning "info breakpoints (timeout)" ; return -1} 325 } 326 return 0 327} 328 329proc gdb_stub_go_idle { dest } { 330 gdb_stub_delete_breakpoints 331} 332 333proc gdb_stub_add_breakpoint { function args } { 334 global gdb_prompt 335 336 remote_send host "break $function\n" 337 remote_expect host 60 { 338 -re "Breakpoint (\[0-9\]+).*$gdb_prompt $" { return $expect_out(1,string) } 339 -re "Function.*not defined.*$gdb_prompt $" { return "undef" } 340 -re "No symbol table.*$gdb_prompt $" { return "undef" } 341 default { 342 return "undef" 343 } 344 } 345} 346 347proc gdb_stub_start { dest } { 348 global gdb_prompt 349 350 set exit_brnum [gdb_stub_add_breakpoint _exit] 351 if { $exit_brnum == "undef" || [board_info $dest exists always_break_exit] } { 352 set exit_brnum [gdb_stub_add_breakpoint exit] 353 } 354 set abort_brnum [gdb_stub_add_breakpoint abort] 355 356 upvar #0 gdb_stub_info I 357 set I($dest,exit_brnum) $exit_brnum 358 set I($dest,abort_brnum) $abort_brnum 359 360 remote_send host "set \$fp=0\n" 361 remote_expect host 10 { 362 -re "$gdb_prompt" { } 363 } 364 # This is needed for the SparcLite. Whee. 365 if [board_info $dest exists gdb,start_symbol] { 366 set start_comm "jump *[board_info $dest gdb,start_symbol]\n" 367 } else { 368 set start_comm "jump *start\n" 369 } 370 remote_send host "break copyloop\n" 371 remote_expect host 10 { 372 -re "Breakpoint.*$gdb_prompt $" { 373 set start_comm "continue\n" 374 } 375 -re "Function.*not defined.*$gdb_prompt $" { } 376 default { } 377 } 378 remote_send host $start_comm 379 remote_expect host 10 { 380 -re "y or n. $" { 381 remote_send host "y\n" 382 exp_continue 383 } 384 -re "Breakpoint.*in copyloop.*$gdb_prompt $" { 385 remote_send host "jump relocd\n" 386 exp_continue 387 } 388 -re "Continuing at.*\[\r\n\]" { } 389 default { 390 return { "fail" "" } 391 } 392 } 393 return { "pass" "" } 394} 395 396proc gdb_stub_spawn { dest prog args } { 397 for { set x 0 } { $x < 3 } { incr x } { 398 if { [remote_ld $dest $prog] != 1 } { 399 return [list "fail" "remote_ld failed"] 400 } 401 402 set result [gdb_stub_start $dest] 403 if { [lindex $result 0] != "pass" } { 404 remote_reboot target 405 } else { 406 return 666; # does anyone use this value? 407 } 408 } 409 return -1 410} 411 412proc gdb_stub_wait { dest timeout } { 413 global gdb_prompt 414 415 416 upvar #0 gdb_stub_info I 417 set exit_brnum $I($dest,exit_brnum) 418 set abort_brnum $I($dest,abort_brnum) 419 420 remote_expect host $timeout { 421 -re "Breakpoint.*exit.*=0.*$gdb_prompt $" { 422 gdb_stub_go_idle $dest 423 return [list 0 ""] 424 } 425 -re "Breakpoint.*exit.*=\[1-9\]\[0-9\]*.*$gdb_prompt $" { 426 gdb_stub_go_idle $dest 427 return [list 0 ""] 428 } 429 -re "Breakpoint.*exit.*$gdb_prompt $" { 430 gdb_stub_go_idle $dest 431 return [list 0 ""] 432 } 433 -re "Breakpoint.*abort.*$gdb_prompt $" { 434 gdb_stub_go_idle $dest 435 return [list 1 ""] 436 } 437 -re " EXIT code 0.*$gdb_prompt $" { 438 gdb_stub_go_idle $dest 439 return [list 0 ""] 440 } 441 -re " EXIT code \[1-9]\[0-9]*.*$gdb_prompt $" { 442 gdb_stub_go_idle $dest 443 return [list 0 ""] 444 } 445 -re " EXIT code 4242.*$gdb_prompt $" { 446 gdb_stub_go_idle $dest 447 return [list 1 ""] 448 } 449 -re "Program received.*$gdb_prompt $" { 450 gdb_stub_go_idle $dest 451 return [list 1 ""] 452 } 453 -re "Program exited.*$gdb_prompt $" { 454 gdb_stub_go_idle $dest 455 return [list 1 ""] 456 } 457 -re "Breakpoint $exit_brnum.*$gdb_prompt $" { 458 gdb_stub_go_idle $dest 459 return [list 0 ""] 460 } 461 -re "Breakpoint $abort_brnum.*$gdb_prompt $" { 462 gdb_stub_go_idle $dest 463 return [list 1 ""] 464 } 465 default { 466 remote_close $dest 467 remote_reboot $dest 468 return [list -1 ""] 469 } 470 } 471 return [list -1 ""] 472} 473 474proc gdb_stub_load { dest prog args } { 475 global gdb_prompt 476 set argnames { "command-line arguments" "input file" "output file" } 477 478 for { set x 0 } { $x < [llength $args] } { incr x } { 479 if { [lindex $args $x] != "" } { 480 return [list "unsupported" "no support for [lindex $argnames $x] on this target"] 481 } 482 } 483 484 set result [remote_spawn $dest $prog] 485 486 if { $result < 0 } { 487 return [list "fail" "remote_spawn failed"] 488 } 489 490 # FIXME: The value 120 should be a parameter. 491 set result [remote_wait $dest 120] 492 set status [lindex $result 0] 493 set output [lindex $result 1] 494 495 if { $status == 0 } { 496 return [list "pass" $output] 497 } else if { $status > 0 } { 498 return [list "fail" $output] 499 } else { 500 global gdb_stub_retry 501 502 if ![info exists gdb_stub_retry] { 503 set gdb_stub_retry 1 504 505 set result [eval gdb_stub_load \{$dest\} \{$prog\} $args] 506 unset gdb_stub_retry 507 return $result 508 } else { 509 return [list "fail" $output] 510 } 511 } 512} 513 514 515# 516# gdb_stub_ld -- load PROG into the board 517# Returns a 0 if there was an error, 518# 1 if it loaded successfully. 519# 520proc gdb_stub_ld { dest prog } { 521 global gdb_prompt 522 global GDB 523 524 if ![board_info $dest exists gdb_is_running] { 525 if ![gdb_stub_restart $dest] { 526 return 0 527 } 528 } 529 530 set loadfile [file tail $prog] 531 set loadpath [file dirname $prog] 532 533 remote_send host "file $prog\n" 534 remote_expect host 30 { 535 -re "A program is being debug.*Kill it.*y or n. $" { 536 remote_send host "y\n" 537 exp_continue 538 } 539 -re "Load new symbol table.*y or n. $" { 540 remote_send host "y\n" 541 exp_continue 542 } 543 -re "Reading symbols from.*done..*$gdb_prompt $" {} 544 -re "$gdb_prompt $" { 545 # Hmmm...is retrying going to help? I kinda doubt it. 546 warning "GDB couldn't read file" 547 return [gdb_stub_retry_ld "$dest" "$prog"] 548 } 549 timeout { 550 warning "(timeout) read symbol file" 551 return [gdb_stub_retry_ld "$dest" "$prog"] 552 } 553 } 554 555 # just in case there are old breakpoints lying around. 556 gdb_stub_delete_breakpoints 557 558 if [board_info $dest exists gdb_serial] { 559 set serial [board_info $dest gdb_serial] 560 } elseif [board_info $dest exists serial] { 561 set serial [board_info $dest serial] 562 } else { 563 set serial [board_info $dest netport] 564 } 565 566 remote_send host "target remote $serial\n" 567 remote_expect host 60 { 568 -re "Kill it?.*y or n.*" { 569 remote_send host "y\n" 570 exp_continue 571 } 572 -re "$gdb_prompt $" { 573 verbose "Set remote target to $serial" 2 574 } 575 timeout { 576 warning "Couldn't set remote target." 577 return 0 578 } 579 } 580 581 if [board_info $dest exists gdb_load_offset] { 582 set offset "[board_info $dest gdb_load_offset]" 583 } else { 584 set offset "" 585 } 586 remote_send host "load $prog $offset\n" 587 verbose "Loading $prog into $GDB" 2 588 global verbose 589 remote_expect host 1200 { 590 -re "Loading.*$gdb_prompt $" { 591 verbose "Loaded $prog into $GDB" 1 592 } 593 -re "$gdb_prompt $" { 594 if $verbose>1 then { 595 warning "GDB couldn't load." 596 } 597 } 598 timeout { 599 if $verbose>1 then { 600 perror "Timed out trying to load $prog." 601 } 602 } 603 } 604 return 1 605} 606 607# 608# Retry the ld operation, but only once. 609# 610 611proc gdb_stub_retry_ld { dest prog } { 612 global gdb_stub_retry_ld 613 614 remote_reboot $dest 615 if [info exists gdb_stub_retry_ld] { 616 unset gdb_stub_retry_ld 617 return 0 618 } else { 619 set gdb_stub_retry_ld 1 620 } 621 gdb_stub_restart $dest 622 set status [gdb_stub_ld $dest $prog] 623 if [info exists gdb_stub_retry_ld] { 624 unset gdb_stub_retry_ld 625 } 626 return $status 627} 628 629proc gdb_stub_close { dest } { 630 global board_info 631 set name [board_info $dest name] 632 if [info exists board_info($name,gdb_is_running)] { 633 unset board_info($name,gdb_is_running) 634 } 635 return [remote_close host] 636} 637 638set_board_info protocol "gdb_stub" 639