# Support routines for libctf testsuite. # Copyright (C) 1994-2021 Free Software Foundation, Inc. # # This file is part of the GNU Binutils. # # This file 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 3 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., 51 Franklin Street - Fifth Floor, Boston, # MA 02110-1301, USA. proc load_common_lib { name } { global srcdir load_file $srcdir/../../binutils/testsuite/lib/$name } load_common_lib binutils-common.exp proc run_native_host_cmd { command } { global link_output global ld verbose -log "$command" set run_output "" try { set run_output [exec "sh" "-c" "$command" "2>@1"] set status 0 } trap CHILDSTATUS {results options} { set status [lindex [dict get $options -errorcode] 2] set run_output $results } regsub "\n$" $run_output "" run_output if { [lindex $status 0] != 0 && [string match "" $run_output] } then { append run_output "child process exited abnormally" } if [string match "" $run_output] then { return "" } verbose -log "$run_output" return "$run_output" } proc run_host_cmd { prog command } { global link_output global gcc_B_opt global gcc_ld_B_opt_tested global ld if { ![is_remote host] && [which "$prog"] == 0 } then { perror "$prog does not exist" return 0 } # If we are compiling with gcc, we want to add gcc_B_opt to flags. However, # if $prog already has -B options, which might be the case when running gcc # out of a build directory, we want our -B options to come first. set gccexe $prog set gccparm [string first " " $gccexe] set gccflags "" if { $gccparm > 0 } then { set gccflags [string range $gccexe $gccparm end] set gccexe [string range $gccexe 0 $gccparm] set prog $gccexe } set gccexe [string replace $gccexe 0 [string last "/" $gccexe] ""] if {[string match "*cc*" $gccexe] || [string match "*++*" $gccexe]} then { set gccflags "$gcc_B_opt $gccflags" if {![info exists gcc_ld_B_opt_tested]} { set gcc_ld_B_opt_tested 1 set ld_version_message [run_host_cmd "$ld" "--version"] set gcc_ld_version_message [run_host_cmd "$prog" "$gccflags -Wl,--version"] if {[string first $ld_version_message $gcc_ld_version_message] < 0} { perror "************************************************************************" perror "Your compiler driver ignores -B when choosing ld." perror "You will not be testing the new ld in many of the following tests." set gcc_ld_version [run_host_cmd "$prog" "$gccflags --print-prog-name=ld"] if {![string match "" $gcc_ld_version] && ![string match "ld" $gcc_ld_version]} { perror "It seems you will be testing $gcc_ld_version instead." } perror "************************************************************************" } } } verbose -log "$prog $gccflags $command" set status [remote_exec host [concat sh -c [list "$prog $gccflags $command 2>&1"]] "" "/dev/null" "libctf.tmp"] remote_upload host "libctf.tmp" set run_output [file_contents "libctf.tmp"] regsub "\n$" $run_output "" run_output if { [lindex $status 0] != 0 && [string match "" $run_output] } then { append run_output "child process exited abnormally" } remote_file build delete libctf.tmp remote_file host delete libctf.tmp if [string match "" $run_output] then { return "" } verbose -log "$run_output" return "$run_output" } proc run_host_cmd_yesno { prog command } { global exec_output global errcnt warncnt set exec_output [prune_warnings [run_host_cmd "$prog" "$command"]] # Ignore error and warning. set errcnt 0 set warncnt 0 if [string match "" $exec_output] then { return 1; } return 0; } # Return true if we can build a program with the compiler. # On some targets, CC might be defined, but libraries and startup # code might be missing or require special options that the ld test # harness doesn't know about. proc check_compiler_available { } { global compiler_available_saved global CC if {![info exists compiler_available_saved]} { if { [which $CC] == 0 } { set compiler_available_saved 0 return 0 } set flags "" if [board_info [target_info name] exists cflags] { append flags " [board_info [target_info name] cflags]" } if [board_info [target_info name] exists ldflags] { append flags " [board_info [target_info name] ldflags]" } set basename "tmpdir/compiler[pid]" set src ${basename}.c set output ${basename}.out set f [open $src "w"] puts $f "int main (void)" puts $f "{" puts $f " return 0; " puts $f "}" close $f if [is_remote host] { set src [remote_download host $src] } set compiler_available_saved [run_host_cmd_yesno "$CC" "$flags $src -o $output"] remote_file host delete $src remote_file host delete $output file delete $src } return $compiler_available_saved } # Compile and link a C source file for execution on the host. proc compile_link_one_host_cc { src output additional_args } { global CC_FOR_HOST global CFLAGS return [run_native_host_cmd "./libtool --quiet --tag=CC --mode=link $CC_FOR_HOST $CFLAGS $src -o $output $additional_args" ] } # Compile a C source file, with the specified additional_flags. proc compile_one_cc { src output additional_flags } { global CC global CFLAGS set flags "" if [board_info [target_info name] exists cflags] { append flags " [board_info [target_info name] cflags]" } if [board_info [target_info name] exists ldflags] { append flags " [board_info [target_info name] ldflags]" } if [is_remote host] { set src [remote_download host $src] } return [run_host_cmd "$CC" "$flags $CFLAGS $additional_flags $src -o $output"] } # run_lookup_test FILE # # Compile with the host compiler and link a .c file into a "lookup" binary, then # compile and optionally link together a bunch of .s or .c files with CTF info # and pass the name of the resulting binary to the "lookup" binary and check the # output. (If none is specified, the binary is expected to generate its own CTF # for testing purposes.) # # As with run_dump_test, this is all driven by a file (in this case, a .lk file) # beginning with zero or more option lines, which specify the names of the # lookup binary's source file, the source file(s) with CTF info to compile # together, and whether to link them. The optional lines have the syntax: # # # OPTION: VALUE # # OPTION is the name of some option, like "name" or "lookup", and # VALUE is OPTION's value. The valid options are described below. # Whitespace is ignored everywhere, except within VALUE. The option # list ends with the first line that doesn't match the above syntax. # However, a line within the options that begins with a #, but doesn't # have a recognizable option name followed by a colon, is considered a # comment and entirely ignored. # # The interesting options are: # # name: TEST-NAME # The name of this test, passed to DejaGNU's `pass' and `fail' # commands. If omitted, this defaults to FILE, the root of the # lookup .c file's name. # # lookup: SOURCE # Compile the file SOURCE.c. If omitted, the lookup source defaults # to FILE.c. # # source: SOURCE # Assemble the file SOURCE.c and pass it to the LOOKUP program. # # nonshared: # If set, do not link with -shared. # # link: # If set, link the SOURCE together even if only one file is specified. # # link_flags: # If set, extra flags to pass to the linker. # # xfail: GLOB|PROC ... # This test is expected to fail on a specified list of targets. # # Each option may occur at most once unless otherwise mentioned. # # After the option lines come regexp lines. run_lookup_test calls # regexp_diff to compare the output of the lookup program against the # regexps in FILE.d. # proc run_lookup_test { name } { global CC CFLAGS LIBS global copyfile env runtests srcdir subdir verbose if ![runtest_file_p $runtests $name] then { return } if [string match "*/*" $name] { set file $name set name [file tail $name] } else { set file "$srcdir/$subdir/$name" } set opt_array [slurp_options "${file}.lk"] if { $opt_array == -1 } { perror "error reading options from $file.lk" unresolved $subdir/$name return } set run_ld 0 set shared "-shared" set opts(link) {} set opts(link_flags) {} set opts(nonshared) {} set opts(lookup) {} set opts(name) {} set opts(source) {} set opts(xfail) {} foreach i $opt_array { set opt_name [lindex $i 0] set opt_val [lindex $i 1] if { $opt_name == "" } { set in_extra 1 continue } if ![info exists opts($opt_name)] { perror "unknown option $opt_name in file $file.lk" unresolved $subdir/$name return } set opts($opt_name) [concat $opts($opt_name) $opt_val] } if { [llength $opts(lookup)] == 0 } { set opts(lookup) "$file.c" } else { set opts(lookup) "[file dirname $file]/$opts(lookup)" } if { [llength $opts(name)] == 0 } { set opts(name) $opts(lookup) } if { [llength $opts(link)] != 0 || [llength $opts(source)] > 1 } { set run_ld 1 } if { [llength $opts(nonshared)] != 0 } { set shared "" } set testname $opts(name) if { $opts(name) == "" } { set testname "$subdir/$name" } # Compile and link the lookup program. set comp_output [compile_link_one_host_cc $opts(lookup) "tmpdir/lookup" "libctf.la"] if { $comp_output != ""} { send_log "compilation of lookup program $opts(lookup) failed with <$comp_output>" perror "compilation of lookup program $opts(lookup) failed" fail $testname return 0 } # Compile the inputs and posibly link them together. set lookup_output "" if { [llength $opts(source)] > 0 } { set lookup_flags "" if { $run_ld } { set lookup_output "tmpdir/out.so" set lookup_flags "-gt -fPIC $shared $opts(link_flags)" } else { set lookup_output "tmpdir/out.o" set lookup_flags "-gt -fPIC -c" } if [board_info [target_info name] exists cflags] { append lookup_flags " [board_info [target_info name] cflags]" } if [board_info [target_info name] exists ldflags] { append lookup_flags " [board_info [target_info name] ldflags]" } set src {} foreach sfile $opts(source) { if [is_remote host] { lappend src [remote_download host [file join [file dirname $file] $sfile]] } else { lappend src [file join [file dirname $file] $sfile] } } set comp_output [run_host_cmd "$CC" "$CFLAGS $lookup_flags [concat $src] -o $lookup_output"] if { $comp_output != ""} { send_log "compilation of CTF program [concat $src] failed with <$comp_output>" fail $testname return 0 } } # Time to setup xfailures. foreach targ $opts(xfail) { if [match_target $targ] { setup_xfail "*-*-*" break } } # Invoke the lookup program on the outputs. set results [run_host_cmd tmpdir/lookup $lookup_output] set f [open "tmpdir/lookup.out" "w"] puts $f $results close $f if { [regexp_diff "tmpdir/lookup.out" "${file}.lk"] } then { fail $testname if { $verbose == 2 } then { verbose "output is [file_contents tmpdir/lookup.out]" 2 } return 0 } pass $testname return 0 } # Returns true if the target compiler supports -gt proc check_ctf_available { } { global ctf_available_saved if {![info exists ctf_available_saved]} { if { ![check_compiler_available] } { set ctf_available_saved 0 } else { set basename "tmpdir/ctf_available[pid]" set src ${basename}.c set output ${basename}.o set f [open $src "w"] puts $f "int main() { return 0; }" close $f set comp_output [compile_one_cc $src $output "-gt -c"] if { $comp_output == ""} { set ctf_available_saved 1 } else { set ctf_available_saved 0 } remote_file host delete $src remote_file host delete $output file delete $src } } return $ctf_available_saved }