| # Copyright (C) 92, 93, 94, 95, 1996 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., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| # Please email any bugs, comments, and/or additions to this file to: |
| # bug-dejagnu@prep.ai.mit.edu |
| |
| # This file was written by Rob Savoye. (rob@welcomehome.org) |
| |
| # a hairy pattern to recognize text |
| set text "\[- A-Za-z0-9\.\;\"\_\:\'\`\(\)\!\#\=\+\?\&\*]" |
| |
| # |
| # this is a collection of support procs for the target data |
| # structures. We use a named array, since Tcl has no real data |
| # structures. Here's the special index words for the array: |
| # Required fields are: |
| # name - the name of the target. (mostly for error messages) This |
| # should also be the string used for this target's array. |
| # It should also be the same as the linker script so we |
| # can find them dynamically. |
| # Optional fields are: |
| # ldflags - the flags required to produce a fully linked executable. |
| # config - the target canonical for this target. This is a regexp |
| # as passed to istarget or isnative. |
| # cflags - the flags required to produce an object file from a |
| # source file. |
| # connect - the connectmode for this target. This is for both IP and |
| # serial connections. |
| # target - the hostname of the target. This is for TCP/IP based connections, |
| # and is also used for version of tip that use /etc/remote. |
| # serial - the serial port. This is typically /dev/tty? or com?:. |
| # netport - the IP port. |
| # baud - the baud rate for a serial port connection. |
| # x10 - parameters for the x10 controller (used to reboot) |
| # fileid - the fileid or spawn id of of the connection. |
| # prompt - a regexp for matching the prompt. |
| # abbrev - abbreviation for tool init files. |
| # ioport - the port for I/O on dual port systems. |
| # |
| # there are three main arrays, indexed in with "target", "build", and "host". |
| # all other targets are indexed with a name usually based on the linker script |
| # like "idp", or "ex93x.ld". |
| # |
| |
| # |
| # Set the elements of the target data structure |
| # The order of the values is name, ldflags, config, cflags, connect, target, serial, |
| # netport, baud, x10, fileid, prompt, abbrev, ioport. |
| # FIXME: I'm not entirely sure this proc is a good idea... |
| proc set_target_info { args } { |
| global target_info |
| |
| set name [lindex $args 0] |
| |
| # process the linker arguments |
| if { [llength $args] > 0 } { |
| set target_info($name,ldflags) [lindex $args 1] |
| } else { |
| set target_info($name,ldflags) "" |
| } |
| |
| # process the config string |
| if { [llength $args] > 1 } { |
| set target_info($name,config) [lindex $args 2] |
| } else { |
| set target_info($name,config) "" |
| } |
| |
| # process the compiler arguments |
| if { [llength $args] > 2 } { |
| set target_info($name,cflags) [lindex $args 3] |
| } else { |
| set target_info($name,cflags) "" |
| } |
| |
| # process the connection mode |
| if { [llength $args] > 3 } { |
| set target_info($name,connect) [lindex $args 3] |
| } else { |
| set target_info($name,connect) "" |
| } |
| |
| # process the target's hostname |
| if { [llength $args] > 4 } { |
| set target_info($name,target) [lindex $args 3] |
| } else { |
| set target_info($name,target) "" |
| } |
| |
| # process the serial port |
| if { [llength $args] > 5 } { |
| set target_info($name,serial) [lindex $args 3] |
| } else { |
| set target_info($name,serial) "" |
| } |
| |
| # process the netport |
| if { [llength $args] > 6 } { |
| set target_info($name,netport) [lindex $args 3] |
| } else { |
| set target_info($name,netport) "" |
| } |
| |
| # process the baud |
| if { [llength $args] > 7 } { |
| set target_info($name,baud) [lindex $args 3] |
| } else { |
| set target_info($name,baud) "" |
| } |
| |
| # process the x10 unit number. |
| if { [llength $args] > 8 } { |
| set target_info($name,x10) [lindex $args 3] |
| } else { |
| set target_info($name,x10) "" |
| } |
| |
| # process the fileid |
| if { [llength $args] > 9 } { |
| set target_info($name,fileid) [lindex $args 3] |
| } else { |
| set target_info($name,fileid) "" |
| } |
| |
| # process the prompt |
| if { [llength $args] > 10 } { |
| set target_info($name,prompt) [lindex $args 3] |
| } else { |
| set target_info($name,prompt) "" |
| } |
| |
| # process the abbrev |
| if { [llength $args] > 10 } { |
| set target_info($name,connect) [lindex $args 3] |
| } else { |
| set target_info($name,connect) "" |
| } |
| |
| # process the ioport |
| if { [llength $args] > 11 } { |
| set target_info($name,ioport) [lindex $args 3] |
| } else { |
| set target_info($name,ioport) "" |
| } |
| } |
| |
| # |
| # Set the target connection. |
| # |
| proc push_target { name } { |
| pop_config target |
| push_config target $name |
| } |
| |
| # |
| # Set the host connnection. |
| # |
| proc push_host { name } { |
| pop_config host |
| push_config host $name |
| } |
| |
| # |
| # Set the config for the current host or target connection. |
| # |
| proc push_config { type name } { |
| global target_info |
| |
| if [info exists target_info(${name},name)] { |
| set target_info($type,name) $name |
| } |
| if [info exists target_info(${name},ldflags)] { |
| set target_info($type,ldflags) $target_info(${name},ldflags) |
| } |
| if [info exists target_info(${name},config)] { |
| set target_info($type,config) $target_info(${name},config) |
| } |
| if [info exists target_info(${name},cflags)] { |
| set target_info($type,cflags) $target_info(${name},cflags) |
| } |
| if [info exists target_info(${name},connect)] { |
| set target_info($type,connect) $target_info(${name},connect) |
| } |
| if [info exists target_info(${name},target)] { |
| set target_info($type,target) $target_info(${name},target) |
| } |
| if [info exists target_info(${name},serial)] { |
| set target_info($type,serial) $target_info(${name},serial) |
| } |
| if [info exists target_info(${name},netport)] { |
| set target_info($type,netport) $target_info(${name},netport) |
| } |
| if [info exists target_info(${name},baud)] { |
| set target_info($type,baud) $target_info(${name},baud) |
| } |
| if [info exists target_info(${name},x10)] { |
| set target_info($type,x10) $target_info(${name},x10) |
| } |
| if [info exists target_info(${name},fileid)] { |
| set target_info($type,fileid) $target_info(${name},fileid) |
| } |
| if [info exists target_info(${name},prompt)] { |
| set target_info($type,prompt) $target_info(${name},prompt) |
| } |
| if [info exists target_info(${name},abbrev)] { |
| set target_info($type,abbrev) $target_info(${name},abbrev) |
| } |
| if [info exists target_info(${name},ioport)] { |
| set target_info($type,ioport) $target_info(${name},ioport) |
| } |
| } |
| |
| # |
| # Set the current connection for target or host. |
| # |
| proc pop_config { type } { |
| global target_info |
| |
| set target_info(${type},name) "" |
| set target_info(${type},ldflags) "" |
| set target_info(${type},config) "" |
| set target_info(${type},cflags) "" |
| set target_info(${type},connect) "" |
| set target_info(${type},target) "" |
| set target_info(${type},serial) "" |
| set target_info(${type},netport) "" |
| set target_info(${type},baud) "" |
| set target_info(${type},x10) "" |
| set target_info(${type},fileid) "" |
| set target_info(${type},prompt) "" |
| set target_info(${type},abbrev) "" |
| set target_info(${type},ioport) "" |
| } |
| |
| # |
| # Unset the target connection. |
| # |
| proc pop_target { } { |
| pop_config target |
| } |
| |
| |
| # |
| # Unset the host connection. |
| # |
| proc pop_host { } { |
| pop_config host |
| } |
| |
| # |
| # list all the configured targets. |
| # returns: |
| # "" if there are no targets. |
| # else it returns a list of unique names. |
| # |
| proc list_targets { } { |
| global target_info |
| |
| if ![info exists target_info] { |
| return "" |
| } |
| |
| set j "" |
| set targs "" |
| foreach i "[lsort [array names target_info]]" { |
| set i "[lindex [split $i ","] 0]" |
| if { $i == $j } { |
| continue |
| } else { |
| lappend targs "[lindex [split $i ","] 0]" |
| set j $i |
| } |
| } |
| return $targs |
| } |
| |
| # |
| # Remove extraneous warnings we don't care about |
| # |
| proc prune_warnings { text } { |
| # remove the \r part of "\r\n" so we don't break all the patterns |
| # we want to match. |
| regsub -all -- "\r" $text "" text |
| |
| # This is from sun4's. Do it for all machines for now. |
| # The "\\1" is to try to preserve a "\n" but only if necessary. |
| if [ishost "sparc-*-sunos"] { |
| regsub -all "(^|\n)(ld.so: warning:\[^\n\]*\n?)+" $text "\\1" text |
| } |
| |
| # See Brendan for the raison d'etre of this one. |
| if [ishost "alpha*-*-*"] { |
| regsub -all "(^|\n)(/usr/(ucb|bin)/ld.*without exceptions was\[^\n\]+\n?)" $text "\\1" text |
| } |
| |
| |
| # Ignore these. |
| regsub -all "(^|\n)\[^\n\]*linker input file unused since linking not done" $text "" text |
| regsub -all "(^|\n)\[^\n\]*file path prefix \[^\n\]* never used" $text "" text |
| |
| # It might be tempting to get carried away and delete blank lines, etc. |
| # Just delete *exactly* what we're ask to, and that's it. |
| return $text |
| } |
| |
| # |
| # Invoke the compiler. This gets interesting cause the compiler may |
| # not be on the same machine we're running DejaGnu on. |
| # |
| proc compile { arg } { |
| global target_info |
| global comp_output |
| global CC |
| |
| if [info exists target_info(target,cflags)] { |
| lappend options "$target_info(target,cflags)" |
| } |
| |
| append options " $arg" |
| |
| verbose "Invoking the compiler as $CC $options" |
| set comp_output [prune_warnings [execute_anywhere "$CC $options"]] |
| return ${comp_output} |
| } |
| |
| # |
| # Invoke the archiver. |
| # |
| proc archive { arg } { |
| global target_info |
| global comp_output |
| global AR |
| |
| if [info exists target_info(target,arflags)] { |
| lappend options "$target_info(target,arflags)" |
| } |
| append options "$arg" |
| |
| verbose "Invoking the archiver as $AR $options" |
| set comp_output [prune_warnings [execute_anywhere "$AR $options"]] |
| return ${comp_output} |
| } |
| |
| proc ranlib { arg } { |
| global target_info |
| global comp_output |
| global RANLIB |
| |
| append options "$arg" |
| |
| verbose "Invoking the archiver as $RANLIB $options" |
| set comp_output [prune_warnings [execute_anywhere "$RANLIB $options"]] |
| return ${comp_output} |
| } |
| |
| # |
| # Link a few objects together. This gets interesting cause the |
| # objects may not be on the same machine we're running DejaGnu on. |
| # |
| proc link_objects { arg } { |
| global target_info |
| global comp_output |
| global LD |
| |
| set options "$arg" |
| if [info exists target_info(target,ldlags)] { |
| lappend options "$target_info(target,ldlags)" |
| } |
| |
| set comp_output [execute_anywhere "$LD $args"] |
| return [ prune_warnings $comp_output] |
| } |
| |
| # |
| # Remotely execute something. This gets fun cause we can't expect an |
| # Unix machine on the other end. We'll use expect instead so we can |
| # connect using $connectmode. This is really designed for executing |
| # the tools to be tested, rather than the test cases. |
| # |
| proc execute_anywhere { cmdline } { |
| global exec_output |
| global target_info |
| |
| if ![info exists target_info(current,prompt)] { |
| set prompt "" |
| } else { |
| set prompt $target_info(current,prompt) |
| } |
| |
| # if we're running stuff that's hosted on the same machine |
| if ![is3way] { |
| verbose -log "Executing on local host: ${cmdline}" 2 |
| set status [catch "exec ${cmdline}" exec_output] |
| if ![string match "" ${exec_output}] { |
| # FIXME: This should be done below, after `else'. |
| verbose -log -- "${exec_output}" 2 |
| } |
| return ${exec_output} |
| } else { |
| verbose -log "Executing on remote host: ${cmdline}" 2 |
| # open the connection |
| verbose "Connecting to remote host" 2 |
| set shellid [remote_open "host"] |
| if { $shellid < 0 } { |
| perror "Can't open connection to remote host" |
| return REMOTERROR |
| } |
| # stty -echo |
| send -i $shellid "echo START ; $cmdline ; echo END\r\n" |
| expect { |
| -i $shellid "echo START \; $cmdline \; echo END" { |
| } |
| default { |
| warning "Never got command echo" |
| } |
| } |
| expect { |
| -i $shellid "START" { |
| exp_continue |
| } |
| -i $shellid "END" { |
| regsub -all "\]" $expect_out(buffer) "" exec_output |
| regsub "END" $exec_output "" exec_output |
| } default { |
| set exec_output $i |
| } |
| } |
| } |
| |
| if [info exists exec_output] { |
| verbose "EXEC_OUTPUT = \"$exec_output\"" 2 |
| } |
| |
| |
| # stty echo |
| # close the connection |
| remote_close $shellid |
| |
| if [info exists exec_output] { |
| return $exec_output |
| } else { |
| return REMOTERROR |
| } |
| } |
| |
| # |
| # Get something resembling a prompt We can't grab more |
| # than the last word cause we have no real idea how long |
| # the prompt is. We also get the full prompt, but it's |
| # kinda useless as it might contain command numbers or |
| # paths that change. If we can't return a prompt, return |
| # null. so at least other patterns won't break. |
| # |
| proc getprompt { shellid } { |
| global spawn_id |
| |
| if { $shellid < 0 } { |
| perror "Invalid spawn id" |
| return "" |
| } |
| |
| set tries 0 |
| set text "" |
| |
| while { $tries <=3 } { |
| verbose "Trying to get the remote host's prompt" |
| send -i $shellid "ACK\r\n" |
| expect { |
| -i $shellid -re "Kerberos rcmd failed.*$" { |
| perror "Need to kinit" |
| return "" |
| } |
| -i $shellid -re "$text*\[\r\n\]*" { |
| return [lindex [split $expect_out(buffer) "\r\n"] 5] |
| break |
| } |
| -i $shellid -re "Terminal type is.*tty.*\>" { |
| return [lindex [split $expect_out(buffer) "\r\n"] 5] |
| break |
| } |
| -i $shellid "" { |
| warning "No prompt" |
| } |
| -i $shellid timeout { |
| perror "Couldn't sync with the remote system" |
| } |
| -i $shellid eof { |
| perror "Got EOF instead of a prompt" |
| } |
| } |
| incr tries |
| } |
| |
| # see if we maxed out on errors |
| if { $tries >= 3 } { |
| warning "Couldn't get the prompt" |
| return "" |
| } |
| } |
| |
| |
| # |
| # |
| # |
| proc make { args } { |
| perror "Unimplemented" |
| } |