# Copyright (C) 1993-2016 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. # True if the object format is known to be ELF. # proc is_elf_format {} { # config.sub for these targets curiously transforms a target doublet # ending in -elf to -none. eg. m68hc12-elf to m68hc12-unknown-none # They are always elf. if { [istarget m68hc1*-*] || [istarget xgate-*] } { return 1; } if { ![istarget *-*-eabi*] && ![istarget *-*-elf*] && ![istarget *-*-freebsd*] && ![istarget *-*-gnu*] && ![istarget *-*-irix5*] && ![istarget *-*-irix6*] && ![istarget *-*-linux*] && ![istarget *-*-nacl*] && ![istarget *-*-netbsd*] && ![istarget *-*-openbsd*] && ![istarget *-*-rtems*] && ![istarget *-*-solaris2*] && ![istarget *-*-sysv4*] && ![istarget *-*-unixware*] && ![istarget avr-*-*] && ![istarget bfin-*-uclinux] && ![istarget frv-*-uclinux*] && ![istarget hppa*64*-*-hpux*] && ![istarget ia64-*-hpux*] && ![istarget sh*-*-uclinux*] && ![istarget tic6x*-*-uclinux*] } { return 0 } if { [istarget *-*-linux*aout*] || [istarget *-*-linux*ecoff*] || [istarget *-*-linux*oldld*] || [istarget *-*-rtemscoff*] || [istarget h8500-*-rtems*] || [istarget i?86-*-freebsd\[12\].*] || [istarget i960-*-rtems*] } { return 0 } if { ![istarget *-*-netbsdelf*] && ( [istarget *-*-netbsd*aout*] || [istarget *-*-netbsdpe*] || [istarget arm*-*-netbsd*] || [istarget sparc-*-netbsd*] || [istarget i*86-*-netbsd*] || [istarget m68*-*-netbsd*] || [istarget vax-*-netbsd*] || [istarget ns32k-*-netbsd*]) } { return 0 } if { [istarget arm-*-openbsd*] || [istarget i386-*-openbsd\[0-2\].*] || [istarget i386-*-openbsd3.\[0-2\]] || [istarget m68*-*-openbsd*] || [istarget ns32k-*-openbsd*] || [istarget sparc-*-openbsd\[0-2\].*] || [istarget sparc-*-openbsd3.\[0-1\]] || [istarget vax-*-openbsd*] } { return 0 } return 1 } # True if the object format is known to be a.out. # proc is_aout_format {} { if { [istarget *-*-netbsdelf] || [istarget sparc64-*-netbsd*] || [istarget sparc64-*-openbsd*] } { return 0 } if { [istarget *-*-*\[ab\]out*] || [istarget *-*-linux*oldld*] || [istarget *-*-bsd*] || [istarget *-*-msdos*] || [istarget arm-*-netbsd*] || [istarget arm-*-openbsd*] || [istarget arm-*-riscix*] || [istarget i?86-*-freebsd\[12\].*] || [istarget i?86-*-netbsd*] || [istarget i?86-*-openbsd\[0-2\]*] || [istarget i?86-*-openbsd3.\[0-2\]*] || [istarget i?86-*-vsta] || [istarget i?86-*-mach*] || [istarget m68*-*-netbsd*] || [istarget m68*-*-openbsd*] || [istarget ns32k-*-*] || [istarget pdp11-*-*] || [istarget sparc*-*-sunos4*] || [istarget sparc*-*-netbsd*] || [istarget sparc*-*-openbsd\[0-2\]*] || [istarget sparc*-*-openbsd3.\[0-1\]*] || [istarget sparc*-fujitsu-none] || [istarget vax-dec-ultrix*] || [istarget vax-*-netbsd] } { return 1 } return 0 } # True if the object format is known to be PE COFF. # proc is_pecoff_format {} { if { ![istarget *-*-mingw*] && ![istarget *-*-cygwin*] && ![istarget *-*-cegcc*] && ![istarget *-*-pe*] } { return 0 } return 1 } # True if the object format is known to be 64-bit ELF. # proc is_elf64 { binary_file } { global READELF global READELFFLAGS set readelf_size "" catch "exec $READELF $READELFFLAGS -h $binary_file > readelf.out" got if ![string match "" $got] then { return 0 } if { ![regexp "\n\[ \]*Class:\[ \]*ELF(\[0-9\]+)\n" \ [file_contents readelf.out] nil readelf_size] } { return 0 } if { $readelf_size == "64" } { return 1 } return 0 } # True if the ELF target supports STB_GNU_UNIQUE with the ELF header's # OSABI field set to ELFOSABI_GNU. # # This generally depends on the target OS only, however there are a # number of exceptions for bare metal targets as follows. The MSP430 # and Visium targets set OSABI to ELFOSABI_STANDALONE and cannot # support STB_GNU_UNIQUE. Likewise non-EABI ARM targets set OSABI to # ELFOSABI_ARM, and TI C6X targets to ELFOSABI_C6000_*. Finally # rather than `bfd_elf_final_link' AM33/2.0, D30V, DLX, i960, and # picoJava targets use `_bfd_generic_final_link', which does not # support STB_GNU_UNIQUE symbol binding causing assertion failures. # proc supports_gnu_unique {} { if { [istarget *-*-gnu*] || [istarget *-*-linux*] || [istarget *-*-nacl*] } { return 1 } if { [istarget "arm*-*-*eabi*"] } { return 1 } if { ![istarget "*-*-elf*"] } { return 0 } if { [istarget "arm*-*-*"] || [istarget "msp430-*-*"] || [istarget "tic6x-*-*"] || [istarget "visium-*-*"] } { return 0 } if { [istarget "am33_2.0-*-*"] || [istarget "d30v-*-*"] || [istarget "dlx-*-*"] || [istarget "i960-*-*"] || [istarget "pj*-*-*"] } { return 0 } return 1 } # True for targets that do not sort .symtab as per the ELF standard. # ie. any that have mips_elf32_be_vec, mips_elf32_le_vec, # mips_elf32_n_be_vec or mips_elf32_n_le_vec as the primary bfd target # vector in config.bfd. When syncing with config.bfd, don't forget that # earlier case-matches trump later ones. proc is_bad_symtab {} { if { ![istarget "mips*-*-*"] } { return 0; } if { [istarget "*-*-chorus*"] || [istarget "*-*-irix5*"] || [istarget "*-*-irix6*"] || [istarget "*-*-none"] || [istarget "*-*-rtems*"] || [istarget "*-*-windiss"] } { return 1; } if { [istarget "*-*-elf*"] && ![istarget "*-sde-*"] && ![istarget "*-mti-*"] && ![istarget "*-img-*"] } { return 1; } if { [istarget "*-*-openbsd*"] && ![istarget "mips64*-*-*"] } { return 1; } return 0; } # Compare two files line-by-line. FILE_1 is the actual output and FILE_2 # is the expected output. Ignore blank lines in either file. # # FILE_2 is a series of regexps, comments and # directives. The directives # are: # # #pass # Treat the test as a PASS if everything up till this point has # matched. Ignore any remaining lines in either FILE_1 or FILE_2. # # #failif # Reverse the sense of the test: expect differences to exist. # # #... # REGEXP # Skip all lines in FILE_1 until the first that matches REGEXP. # # Other # lines are comments. Regexp lines starting with the `!' character # specify inverse matching (use `\!' for literal matching against a leading # `!'). Skip empty lines in both files. # # The first optional argument is a list of regexp substitutions of the form: # # EXP1 SUBSPEC1 EXP2 SUBSPEC2 ... # # This tells the function to apply each regexp substitution EXPi->SUBSPECi # in order to every line of FILE_2. # # Return nonzero if differences exist. proc regexp_diff { file_1 file_2 args } { set eof -1 set end_1 0 set end_2 0 set differences 0 set diff_pass 0 set fail_if_match 0 set ref_subst "" if { [llength $args] > 0 } { set ref_subst [lindex $args 0] } if { [llength $args] > 1 } { perror "Too many arguments to regexp_diff" return 1 } if [file exists $file_1] then { set file_a [open $file_1 r] } else { perror "$file_1 doesn't exist" return 1 } if [file exists $file_2] then { set file_b [open $file_2 r] } else { perror "$file_2 doesn't exist" close $file_a return 1 } verbose " Regexp-diff'ing: $file_1 $file_2" 2 while { 1 } { set line_a "" set line_b "" while { [string length $line_a] == 0 } { # Ignore blank line in FILE_1. if { [gets $file_a line_a] == $eof } { set end_1 1 break } } while { [string length $line_b] == 0 || [string match "#*" $line_b] } { if { [string match "#pass" $line_b] } { set end_2 1 set diff_pass 1 break } elseif { [string match "#failif" $line_b] } { send_log "fail if no difference\n" verbose "fail if no difference" 3 set fail_if_match 1 } elseif { [string match "#..." $line_b] } { if { [gets $file_b line_b] == $eof } { set end_2 1 set diff_pass 1 break } set negated [expr { [string index $line_b 0] == "!" }] set line_bx [string range $line_b $negated end] set n [expr { $negated ? "! " : "" }] # Substitute on the reference. foreach {name value} $ref_subst { regsub -- $name $line_bx $value line_bx } verbose "looking for $n\"^$line_bx$\"" 3 while { [expr [regexp "^$line_bx$" "$line_a"] == $negated] } { verbose "skipping \"$line_a\"" 3 if { [gets $file_a line_a] == $eof } { set end_1 1 break } } break } if { [gets $file_b line_b] == $eof } { set end_2 1 break } } if { $diff_pass } { break } elseif { $end_1 && $end_2 } { break } elseif { $end_1 } { send_log "extra regexps in $file_2 starting with \"^$line_b$\"\nEOF from $file_1\n" verbose "extra regexps in $file_2 starting with \"^$line_b$\"\nEOF from $file_1" 3 set differences 1 break } elseif { $end_2 } { send_log "extra lines in $file_1 starting with \"^$line_a$\"\nEOF from $file_2\n" verbose "extra lines in $file_1 starting with \"^$line_a$\"\nEOF from $file_2\n" 3 set differences 1 break } else { set negated [expr { [string index $line_b 0] == "!" }] set line_bx [string range $line_b $negated end] set n [expr { $negated ? "! " : "" }] set s [expr { $negated ? " " : "" }] # Substitute on the reference. foreach {name value} $ref_subst { regsub -- $name $line_bx $value line_bx } verbose "regexp $n\"^$line_bx$\"\nline \"$line_a\"" 3 if { [expr [regexp "^$line_bx$" "$line_a"] == $negated] } { send_log "regexp_diff match failure\n" send_log "regexp $n\"^$line_bx$\"\nline $s\"$line_a\"\n" verbose "regexp_diff match failure\n" 3 set differences 1 } } } if { $differences == 0 && !$diff_pass && [eof $file_a] != [eof $file_b] } { send_log "$file_1 and $file_2 are different lengths\n" verbose "$file_1 and $file_2 are different lengths" 3 set differences 1 } if { $fail_if_match } { if { $differences == 0 } { set differences 1 } else { set differences 0 } } close $file_a close $file_b return $differences }