X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Ftestsuite%2Flib%2Fbinutils-common.exp;h=b9e3c6d8174168226a044d532b760e22ef8f7d8f;hb=8a8a1171237d45e20b2ebb18ee2d3f8686e01b82;hp=dbbbc792243235b39bd544db7a4c59499f1cf885;hpb=b3066ae8259d3adb4e00ee8145c55df16c3d7261;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp index dbbbc79224..b9e3c6d817 100644 --- a/binutils/testsuite/lib/binutils-common.exp +++ b/binutils/testsuite/lib/binutils-common.exp @@ -1,4 +1,4 @@ -# Copyright (C) 1993-2016 Free Software Foundation, Inc. +# Copyright (C) 1993-2020 Free Software Foundation, Inc. # # This file is part of the GNU Binutils. # @@ -23,65 +23,54 @@ 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-*] } { + if { [istarget m68hc1*-*] || [istarget s12z*-*] || [istarget xgate-*] } { return 1; } +# vxworks (and windiss) excluded due to number of ELF tests that need +# modifying to pass on those targets. +# && ![istarget *-*-vxworks*] +# && ![istarget *-*-windiss*] - if { ![istarget *-*-sysv4*] - && ![istarget *-*-unixware*] - && ![istarget *-*-elf*] + if { ![istarget *-*-chorus*] + && ![istarget *-*-cloudabi*] && ![istarget *-*-eabi*] - && ![istarget *-*-rtems*] - && ![istarget hppa*64*-*-hpux*] - && ![istarget ia64-*-hpux*] - && ![istarget *-*-linux*] + && ![istarget *-*-*elf*] + && ![istarget *-*-*freebsd*] + && ![istarget *-*-fuchsia*] && ![istarget *-*-gnu*] - && ![istarget *-*-nacl*] - && ![istarget frv-*-uclinux*] - && ![istarget bfin-*-uclinux] - && ![istarget sh*-*-uclinux*] - && ![istarget tic6x*-*-uclinux*] && ![istarget *-*-irix5*] && ![istarget *-*-irix6*] - && ![istarget *-*-freebsd*] + && ![istarget *-*-kaos*] + && ![istarget *-*-*linux*] + && ![istarget *-*-lynxos*] + && ![istarget *-*-nacl*] && ![istarget *-*-netbsd*] + && ![istarget *-*-nto*] && ![istarget *-*-openbsd*] - && ![istarget *-*-solaris2*] } { + && ![istarget *-*-rtems*] + && ![istarget *-*-solaris2*] + && ![istarget *-*-sysv4*] + && ![istarget *-*-unixware*] + && ![istarget *-*-wasm32*] + && ![istarget avr-*-*] + && ![istarget hppa*64*-*-hpux*] + && ![istarget ia64-*-hpux*] } { return 0 } - if { [istarget i?86-*-freebsd\[12\].*] } { - return 0 - } - - if { [istarget *-*-linux*aout*] - || [istarget *-*-linux*ecoff*] - || [istarget *-*-linux*oldld*] - || [istarget h8500-*-rtems*] - || [istarget i960-*-rtems*] + if { [istarget *-*-linux*ecoff*] || [istarget *-*-rtemscoff*] } { 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 vax-*-netbsd*] || [istarget ns32k-*-netbsd*]) } { return 0 } - if { [istarget arm-*-openbsd*] - || [istarget i386-*-openbsd\[0-2\].*] - || [istarget i386-*-openbsd3.\[0-2\]] - || [istarget m68*-*-openbsd*] + if { [istarget arm-*-openbsd*] || [istarget ns32k-*-openbsd*] - || [istarget sparc-*-openbsd\[0-2\].*] - || [istarget sparc-*-openbsd3.\[0-1\]] || [istarget vax-*-openbsd*] } { return 0 } @@ -92,34 +81,11 @@ proc is_elf_format {} { # 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*] + if { [istarget *-*-*aout*] || [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 } @@ -129,14 +95,30 @@ proc is_aout_format {} { # 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 + if { [istarget *-*-beospe*] + || [istarget *-*-cegcc*] + || [istarget *-*-cygwin*] + || [istarget *-*-interix*] + || [istarget *-*-mingw*] + || [istarget *-*-netbsdpe*] + || [istarget *-*-pe*] + || [istarget *-*-winnt*] } { + return 1 } + return 0 +} - return 1 +proc is_som_format {} { + if { ![istarget hppa*-*-*] || [istarget hppa*64*-*-*] } { + return 0; + } + if { [istarget *-*-osf*] \ + || [istarget {*-*-h[ip]ux*}] \ + || [istarget *-*-mpeix*] \ + || [istarget *-*-bsd*] } { + return 1; + } + return 0; } # True if the object format is known to be 64-bit ELF. @@ -145,15 +127,16 @@ proc is_elf64 { binary_file } { global READELF global READELFFLAGS + set tmpfile [file dirname $binary_file]/readelf.out set readelf_size "" - catch "exec $READELF $READELFFLAGS -h $binary_file > readelf.out" got + catch "exec $READELF $READELFFLAGS -h $binary_file > $tmpfile" got if ![string match "" $got] then { return 0 } if { ![regexp "\n\[ \]*Class:\[ \]*ELF(\[0-9\]+)\n" \ - [file_contents readelf.out] nil readelf_size] } { + [file_contents $tmpfile] nil readelf_size] } { return 0 } @@ -164,6 +147,167 @@ proc is_elf64 { binary_file } { return 0 } +# True if the object format is known to use RELA relocations. +# +proc is_rela { binary_file } { + global READELF + global READELFFLAGS + + set tmpfile [file dirname $binary_file]/readelf.out + catch "exec $READELF $READELFFLAGS -S $binary_file > $tmpfile" got + + if ![string match "" $got] then { + return 0 + } + + if { ![regexp "RELA" [file_contents $tmpfile]] } { + return 0 + } + + return 1 +} + +# True if the target matches TARGET, specified as a TCL procedure if +# in square brackets or as machine triplet otherwise. +# +proc match_target { target } { + if [regexp {^!?\[.*\]$} $target] { + return $target + } else { + return [istarget $target] + } +} + +# True if the ELF target supports setting the ELF header OSABI field +# to ELFOSABI_GNU or ELFOSABI_FREEBSD, a requirement for STT_GNU_IFUNC +# symbol and SHF_GNU_MBIND section support. +# +# 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. Likewise +# non-EABI ARM targets set OSABI to ELFOSABI_ARM +# +# Note that some TI C6X targets use ELFOSABI_C6000_* but one doesn't, +# so we don't try to sort out tic6x here. (The effect is that linker +# testcases will generally need to exclude tic6x or use a -m option.) +# +proc supports_gnu_osabi {} { + if { [istarget *-*-gnu*] + || [istarget *-*-linux*] + || [istarget *-*-nacl*] + || ( [istarget *-*-*bsd*] && ![istarget arm*-*-netbsd*] ) + || [istarget *-*-symbianelf] + || [istarget *-*-lynxos] + || ( [istarget *-*-nto*] && ![istarget arm*-*-*] ) + || [istarget *-*-irix*] + || [istarget *-*-*eabi*] + || [istarget *-*-rtems*] } { + return 1 + } + if { [istarget "wasm32*-*-*"] } { + return 1 + } + if { ![istarget "*-*-elf*"] } { + return 0 + } + if { [istarget "arm*-*-*"] + || [istarget "msp430-*-*"] + || [istarget "visium-*-*"] } { + return 0 + } + return 1 +} + +# Return true if target uses the generic_link_hash_table linker. +proc is_generic { } { + if { [istarget "d30v-*-*"] + || [istarget "dlx-*-*"] + || [istarget "pj*-*-*"] + || [istarget "s12z-*-*"] + || [istarget "xgate-*-*"] } { + return 1 + } + return 0 +} + +# True if the ELF target supports STB_GNU_UNIQUE. +# +# This require ELFOSABI_GNU, and `bfd_elf_final_link'. +# +proc supports_gnu_unique {} { + if { [istarget *-*-freebsd*] } { + return 0 + } + if { [supports_gnu_osabi] && ![is_generic] } { + return 1 + } + return 0 +} + +# 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; +} + +# Returns true if -shared is supported on the target + +proc check_shared_lib_support { } { + global shared_available_saved + global ld + + if {![info exists shared_available_saved]} { + set ld_output [remote_exec host $ld "-shared"] + if { [ string first "not supported" $ld_output ] >= 0 } { + set shared_available_saved 0 + } else { + set shared_available_saved 1 + } + } + return $shared_available_saved +} + +# Returns true if -pie is supported on the target + +proc check_pie_support { } { + global pie_available_saved + global ld + + if {![info exists pie_available_saved]} { + set ld_output [remote_exec host $ld "-pie"] + if { [ string first "not supported" $ld_output ] >= 0 } { + set pie_available_saved 0 + } else { + set pie_available_saved 1 + } + } + return $pie_available_saved +} + # 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. # @@ -181,6 +325,10 @@ proc is_elf64 { binary_file } { # REGEXP # Skip all lines in FILE_1 until the first that matches REGEXP. # +# #?REGEXP +# Optionally match REGEXP against line from FILE_1. If the REGEXP +# does not match then the next line from FILE_2 is tried. +# # 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. @@ -267,6 +415,21 @@ proc regexp_diff { file_1 file_2 args } { } } break + } elseif { [string match "#\\?*" $line_b] } { + if { ! $end_1 } { + set line_b [string replace $line_b 0 1] + 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 "optional match for $n\"^$line_bx$\"" 3 + if { [expr [regexp "^$line_bx$" "$line_a"] != $negated] } { + break + } + } } if { [gets $file_b line_b] == $eof } { set end_2 1 @@ -326,3 +489,992 @@ proc regexp_diff { file_1 file_2 args } { return $differences } + +# prune_warnings_extra -- delete extra warnings from TEXT. +# +# An example is: +# ld: warning: /lib64/ld-linux-x86-64.so.2: unsupported GNU_PROPERTY_TYPE (5) type : 0xc0010001 +proc prune_warnings_extra { text } { + global experimental + # Warnings are only pruned from non-experimental code (ie code not + # on a release branch). For experimental code we want the warnings + # as they indicate that the sources need to be updated to recognise + # the new properties. + if { "$experimental" == "false" } { + # The "\\1" is to try to preserve a "\n" but only if necessary. + regsub -all "(^|\n)(\[^\n\]*: warning:\[^\n\]*unsupported GNU_PROPERTY_TYPE\[^\n\]*\n?)+" $text "\\1" text + } + # PR binutils/23898: It is OK to have gaps in build notes. + regsub -all "(^|\n)(\[^\n\]*: Warning: Gap in build notes detected from\[^\n\]*\n?)+" $text "\\1" text + return $text +} + +# This definition is taken from an unreleased version of DejaGnu. Once +# that version gets released, and has been out in the world for a few +# months at least, it may be safe to delete this copy. +if ![string length [info proc prune_warnings]] { + # + # prune_warnings -- delete various system verbosities from TEXT + # + # An example is: + # ld.so: warning: /usr/lib/libc.so.1.8.1 has older revision than expected 9 + # + # Sites with particular verbose os's may wish to override this in site.exp. + # + proc prune_warnings { 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. + regsub -all "(^|\n)(ld.so: warning:\[^\n\]*\n?)+" $text "\\1" 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. + set text [prune_warnings_extra $text] + return $text + } +} elseif { [info procs saved-prune_warnings] == [list] } { + rename prune_warnings saved-prune_warnings + proc prune_warnings { text } { + set text [saved-prune_warnings $text] + set text [prune_warnings_extra $text] + return $text + } +} + +# run_dump_test FILE (optional:) EXTRA_OPTIONS +# +# Assemble a .s file, then run some utility on it and check the output. +# +# There should be an assembly language file named FILE.s in the test +# suite directory, and a pattern file called FILE.d. run_dump_test +# will assemble FILE.s, optionally run objcopy on the object file, +# optionally run ld, optionally run another objcopy, optionally run +# another tool under test specified by PROG, then run a dump tool like +# addr2line, nm, objdump, readelf or size on the object file to produce +# textual output, and then analyze that with regexps. +# The FILE.d file specifies what program to run, and what to expect in +# its output. +# +# The FILE.d file begins with zero or more option lines, which specify +# flags to pass to the assembler, the program to run to dump the +# assembler's output, and the options it wants. The option lines have +# the syntax: +# +# # OPTION: VALUE +# +# OPTION is the name of some option, like "name" or "objdump", 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 optional EXTRA_OPTIONS argument to `run_dump_test' is a list of +# two-element lists. The first element of each is an option name, and +# the second additional arguments to be added on to the end of the +# option list as given in FILE.d. (If omitted, no additional options +# are added.) +# +# 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 +# .s and .d files' names. +# +# as: FLAGS +# When assembling, pass FLAGS to the assembler. +# If assembling several files, you can pass different assembler +# options in the "source" directives. See below. +# Multiple instances of this directive tells run_dump_test to run the test +# multiple times -- one time with each set of flags provided. +# Each instance will run exactly as a file with a single "as" line, it is +# not possible to condition any behaviour on which set of "as" flags is +# used. That means that the "source" specific options are appended to +# the "as" flags for their corresponding files, and any extra processing +# (e.g. with "ld" and "objcopy") is repeated for each test. +# +# ld: FLAGS +# Link assembled files using FLAGS, in the order of the "source" +# directives, when using multiple files. +# +# ld_after_inputfiles: FLAGS +# Similar to "ld", but put FLAGS after all input files. +# +# objcopy_objects: FLAGS +# Run objcopy with the specified flags after assembling any source +# that has the special marker RUN_OBJCOPY in the source specific +# flags. +# +# objcopy_linked_file: FLAGS +# Run objcopy on the linked file with the specified flags. +# This lets you transform the linked file using objcopy, before the +# result is analyzed by an analyzer program specified below. +# +# PROG: PROGRAM-NAME +# The name of a program under test, to run to modify or analyze the +# .o file produced by the assembler. Recognised names are: ar, +# elfedit, nm, objcopy, ranlib, strings, and strip. +# +# DUMPPROG: PROGRAM-NAME +# The name of the program to run to analyze the file produced +# by the assembler or the linker. This can be omitted; +# run_dump_test will guess which program to run from which of +# the flags options below is present. +# +# addr2line: FLAGS +# nm: FLAGS +# objdump: FLAGS +# readelf: FLAGS +# size: FLAGS +# Use the specified program to analyze the output file, and pass it +# FLAGS, in addition to the output name. Note that they are run +# with LC_ALL=C in the environment to give consistent sorting of +# symbols. If no FLAGS are needed then you can use: +# DUMPPROG: [nm objdump readelf addr2line] +# instead, or just pass a flag that happens to be the default. +# If objdump is the dump tool and we're not dumping binary, nor +# have run ld, then the standard section names (.text, .data and +# .bss) are replaced by target ones if any (eg. rx-elf uses "P" +# instead of .text). The substition is done for both the +# objdump options (eg: "-j .text" is replaced by "-j P") and the +# reference file. +# +# source: SOURCE [FLAGS] +# Assemble the file SOURCE.s using the flags in the "as" directive +# and the (optional) FLAGS. If omitted, the source defaults to +# FILE.s. +# This is useful if several .d files want to share a .s file. +# More than one "source" directive can be given, which is useful +# when testing linking. +# +# dump: DUMP +# Match against DUMP.d. If omitted, this defaults to FILE.d. This +# is useful if several .d files differ by options only. Options are +# always read from FILE.d. +# +# target: GLOB|PROC ... +# Run this test only on a specified list of targets. More precisely, +# in the space-separated list each glob is passed to "istarget" and +# each proc is called as a TCL procedure. List items are interpreted +# such that procs are denoted by surrounding square brackets, and any +# other items are consired globs. If the call evaluates true for any +# of them, the test will be run, otherwise it will be marked +# unsupported. +# +# notarget: GLOB|PROC ... +# Do not run this test on a specified list of targets. Again, each +# glob in the space-separated list is passed to "istarget" and each +# proc is called as a TCL procedure, and the test is run if it +# evaluates *false* for *all* of them. Otherwise it will be marked +# unsupported. +# +# alltargets: GLOB|PROC ... +# Run this test on a specified list of targets. Again, each +# glob in the space-separated list is passed to "istarget" and each +# proc is called as a TCL procedure, and the test is run if it +# evaluates *true* for *all* of them. Otherwise it will be marked +# unsupported. +# +# skip: GLOB|PROC ... +# anyskip: GLOB|PROC ... +# noskip: GLOB|PROC ... +# These are exactly the same as "notarget", "alltargets" and +# "target" respectively, except that they do nothing at all if the +# check fails. They should only be used in groups, to construct a +# single test which is run on all targets but with variant options +# or expected output on some targets. (For example, see +# gas/arm/inst.d and gas/arm/wince_inst.d.) +# +# xfail: GLOB|PROC ... +# Run this test and it is is expected to fail on a specified list +# of targets. +# +# error: REGEX +# An error with message matching REGEX must be emitted for the test +# to pass. The DUMPPROG, addr2line, nm, objdump, readelf and size +# options have no meaning and need not supplied if this is present. +# Multiple "error" directives append to the expected error message. +# +# error_output: FILE +# Means the same as 'error', except the regular expression lines +# are contains in FILE. +# +# warning: REGEX +# Expect a warning matching REGEX. It is an error to issue +# both "error" and "warning". Multiple "warning" directives +# append to the expected warning message. +# +# warning_output: FILE +# Means the same as 'warning', except the regular expression +# lines are contains in FILE. +# +# map: FILE +# Adding this option will cause the linker to generate a linker +# map file, using the -Map=MAPFILE command line option. If +# there is no -Map=MAPFILE in the 'ld: FLAGS' then one will be +# added to the linker command line. The contents of the +# generated MAPFILE are then compared against the regexp lines +# in FILE using `regexp_diff' (see below for details). +# +# section_subst: no +# Means that the section substitution for objdump is disabled. +# +# Each option may occur at most once unless otherwise mentioned. +# +# After the option lines come regexp lines. run_dump_test calls +# regexp_diff to compare the output of the dumping tool against the +# regexps in FILE.d. +# +proc run_dump_test { name {extra_options {}} } { + global ADDR2LINE ADDR2LINEFLAGS AS ASFLAGS ELFEDIT ELFEDITFLAGS LD LDFLAGS + global NM NMFLAGS OBJCOPY OBJCOPYFLAGS OBJDUMP OBJDUMPFLAGS + global READELF READELFFLAGS STRIP STRIPFLAGS + global copyfile env ld_elf_shared_opt runtests srcdir subdir verbose + + if [string match "*/*" $name] { + set file $name + set name [file tail $name] + } else { + set file "$srcdir/$subdir/$name" + } + + if ![runtest_file_p $runtests $name] then { + return + } + + set opt_array [slurp_options "${file}.d"] + if { $opt_array == -1 } { + perror "error reading options from $file.d" + unresolved $subdir/$name + return + } + set dumpfile tmpdir/dump.out + set run_ld 0 + set run_objcopy 0 + set objfile_names {} + set opts(PROG) {} + set opts(DUMPPROG) {} + set opts(addr2line) {} + set opts(alltargets) {} + set opts(anyskip) {} + set opts(ar) {} + set opts(as) {} + set as_final_flags {} + set as_additional_flags {} + set opts(dump) {} + set opts(elfedit) {} + set opts(error) {} + set opts(error_output) {} + set opts(ld) {} + set opts(ld_after_inputfiles) {} + set opts(map) {} + set opts(name) {} + set opts(nm) {} + set opts(noskip) {} + set opts(notarget) {} + set opts(objcopy) {} + set opts(objcopy_linked_file) {} + set opts(objcopy_objects) {} + set opts(objdump) {} + set opts(ranlib) {} + set opts(readelf) {} + set opts(section_subst) {} + set opts(size) {} + set opts(strings) {} + set opts(strip) {} + set opts(skip) {} + set opts(source) {} + set opts(strip) {} + set opts(target) {} + set opts(warning) {} + set opts(warning_output) {} + set opts(xfail) {} + + set in_extra 0 + foreach i [concat $opt_array {{} {}} $extra_options] { + 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.d" + unresolved $subdir/$name + return + } + + # Allow more substitutions, including tcl functions, for as and ld. + # Not done in general because extra quoting is needed for glob + # args used for example in binutils-all/remove-relocs-04.d. + if { $opt_name == "as" || $opt_name == "ld" } { + set opt_val [subst $opt_val] + } else { + # Just substitute $srcdir and $subdir + regsub -all {\$srcdir} "$opt_val" "$srcdir" opt_val + regsub -all {\$subdir} "$opt_val" "$subdir" opt_val + } + + switch -- $opt_name { + xfail {} + target {} + alltargets {} + notarget {} + skip {} + anyskip {} + noskip {} + warning {} + error {} + source { + # Move any source-specific as-flags to a separate list to + # simplify processing. + if { [llength $opt_val] > 1 } { + lappend asflags [lrange $opt_val 1 end] + set opt_val [lindex $opt_val 0] + } else { + lappend asflags {} + } + + # Create the object file name based on nothing but the source + # file name. + set new_objfile \ + [concat tmpdir/[file rootname [file tail [lindex $opt_val 0]]].o] + # But, sometimes, we have the exact same source filename in + # different directories (foo/src.s bar/src.s) which would lead + # us to try and create two src.o files. We detect this + # conflict here, and instead create src.o and src1.o. + set j 0 + while { [lsearch $objfile_names $new_objfile] != -1 } { + incr j + set new_objfile \ + [concat tmpdir/[file rootname [file tail [lindex $opt_val 0]]]${j}.o] + } + lappend objfile_names $new_objfile + } + default { + if { !$in_extra + && [string length $opts($opt_name)] + && $opt_name != "as" } { + perror "option $opt_name multiply set in $file.d" + unresolved $subdir/$name + return + } + + # A single "#ld:" with no options should do the right thing. + if { $opt_name == "ld" } { + set run_ld 1 + } + # Likewise objcopy_linked_file. + if { $opt_name == "objcopy_linked_file" } { + set run_objcopy 1 + } + } + } + + # Append differently whether it's a message (without space) or + # an option or list (with space). + switch -- $opt_name { + warning - + error { + append opts($opt_name) $opt_val + } + as { + if { $in_extra } { + set as_additional_flags [concat $as_additional_flags $opt_val] + } else { + lappend opts(as) $opt_val + } + } + default { + set opts($opt_name) [concat $opts($opt_name) $opt_val] + } + } + } + + # Ensure there is something in $opts(as) for the foreach loop below. + if { [llength $opts(as)] == 0 } { + set opts(as) [list " "] + } + foreach x $opts(as) { + if { [string length $x] && [string length $as_additional_flags] } { + append x " " + } + append x $as_additional_flags + regsub {\[big_or_little_endian\]} $x \ + [big_or_little_endian] x + lappend as_final_flags $x + } + + regsub {\[big_or_little_endian\]} $opts(ld) \ + [big_or_little_endian] opts(ld) + + if { $opts(name) == "" } { + set testname "$subdir/$name" + } else { + set testname $opts(name) + } + + set err_warn 0 + foreach opt { warning error warning_output error_output } { + if { $opts($opt) != "" } { + if { $err_warn } { + perror "$testname: bad mix of warning and error test directives" + unresolved $testname + return + } + set err_warn 1 + } + } + + # Decide early whether we should run the test for this target. + if { [llength $opts(noskip)] > 0 } { + set targmatch 0 + foreach targ $opts(noskip) { + if [match_target $targ] { + set targmatch 1 + break + } + } + if { $targmatch == 0 } { + return + } + } + foreach targ $opts(anyskip) { + if ![match_target $targ] { + return + } + } + foreach targ $opts(skip) { + if [match_target $targ] { + return + } + } + if { [llength $opts(target)] > 0 } { + set targmatch 0 + foreach targ $opts(target) { + if [match_target $targ] { + set targmatch 1 + break + } + } + if { $targmatch == 0 } { + unsupported $testname + return + } + } + foreach targ $opts(alltargets) { + if ![match_target $targ] { + unsupported $testname + return + } + } + foreach targ $opts(notarget) { + if [match_target $targ] { + unsupported $testname + return + } + } + + set dumpprogram "" + # It's meaningless to require an output-testing method when we + # expect an error. + if { $opts(error) == "" && $opts(error_output) == "" } { + if { $opts(DUMPPROG) != "" } { + switch -- $opts(DUMPPROG) { + addr2line { set dumpprogram addr2line } + nm { set dumpprogram nm } + objdump { set dumpprogram objdump } + readelf { set dumpprogram readelf } + size { set dumpprogram size } + default { + perror "unrecognized DUMPPROG option $opts(DUMPPROG) in $file.d" + unresolved $testname + return + } + } + } else { + # Guess which program to run, by seeing which option was specified. + foreach p {addr2line nm objdump readelf size} { + if {$opts($p) != ""} { + if {$dumpprogram != ""} { + perror "ambiguous dump program in $file.d" + unresolved $testname + return + } else { + set dumpprogram $p + } + } + } + } + if { $dumpprogram == "" && $opts(map) == "" && !$err_warn } { + perror "dump program unspecified in $file.d" + unresolved $testname + return + } + } + + if { $opts(source) == "" } { + set sourcefiles [list ${file}.s] + set asflags [list ""] + set objfile_names [list tmpdir/[file tail ${file}].o] + } else { + set sourcefiles {} + foreach sf $opts(source) { + if { [string match "./*" $sf] } { + lappend sourcefiles "$sf" + } else { + lappend sourcefiles "$srcdir/$subdir/$sf" + } + } + } + + if { $opts(dump) == "" } { + set dfile ${file}.d + } else { + set dfile $srcdir/$subdir/$opts(dump) + } + + # Time to setup xfailures. + foreach targ $opts(xfail) { + if [match_target $targ] { + setup_xfail "*-*-*" + break + } + } + + foreach as_flags $as_final_flags { + # Assemble each file. + set objfiles {} + for { set i 0 } { $i < [llength $sourcefiles] } { incr i } { + set sourcefile [lindex $sourcefiles $i] + set sourceasflags [lindex $asflags $i] + set run_objcopy_objects 0 + + if { [string match "*RUN_OBJCOPY*" $sourceasflags] } { + set run_objcopy_objects 1 + } + regsub "RUN_OBJCOPY" $sourceasflags "" sourceasflags + + set objfile [lindex $objfile_names $i] + catch "exec rm -f $objfile" exec_output + lappend objfiles $objfile + + if { $as_flags == "binary" } { + while {[file type $sourcefile] eq "link"} { + set newfile [file readlink $sourcefile] + if {[string index $newfile 0] ne "/"} { + set newfile [file dirname $sourcefile]/$newfile + } + set sourcefile $newfile + } + set newfile [remote_download host $sourcefile $objfile] + set cmdret 0 + if { $newfile == "" } { + set cmdret 1 + } + } else { + if { [istarget "hppa*-*-*"] \ + && ![istarget "*-*-linux*"] \ + && ![istarget "*-*-netbsd*" ] } { + set cmd "sed -e 's/^\[ \]*\.comm \\(\[^,\]*\\),\\(.*\\)/\\1 .comm \\2/' < $sourcefile > tmpdir/asm.s" + send_log "$cmd\n" + set cmdret [remote_exec host [concat sh -c [list "$cmd"]]] + set cmdret [lindex $cmdret 0] + if { $cmdret != 0 } { + perror "sed failure" + unresolved $testname + continue + } + set sourcefile tmpdir/asm.s + } + set cmd "$AS $ASFLAGS $as_flags $sourceasflags -o $objfile $sourcefile" + + send_log "$cmd\n" + set cmdret [remote_exec host [concat sh -c [list "$cmd 2>&1"]] "" "/dev/null" "dump.tmp"] + remote_upload host "dump.tmp" + set comp_output [prune_warnings [file_contents "dump.tmp"]] + remote_file host delete "dump.tmp" + remote_file build delete "dump.tmp" + set cmdret [lindex $cmdret 0] + } + if { $cmdret == 0 && $run_objcopy_objects } { + set cmd "$OBJCOPY $opts(objcopy_objects) $objfile" + + send_log "$cmd\n" + set cmdret [remote_exec host [concat sh -c [list "$cmd 2>&1"]] \ + "" "/dev/null" "dump.tmp"] + remote_upload host "dump.tmp" + append comp_output [prune_warnings [file_contents "dump.tmp"]] + remote_file host delete "dump.tmp" + remote_file build delete "dump.tmp" + set cmdret [lindex $cmdret 0] + } + } + + # Perhaps link the file(s). + if { $cmdret == 0 && $run_ld } { + set objfile "tmpdir/dump" + catch "exec rm -f $objfile" exec_output + + set ld_extra_opt "" + global ld + set ld "$LD" + if { [is_elf_format] && [check_shared_lib_support] } { + set ld_extra_opt "$ld_elf_shared_opt" + } + + # Add -L$srcdir/$subdir so that the linker command can use + # linker scripts in the source directory. + set cmd "$LD $ld_extra_opt $LDFLAGS -L$srcdir/$subdir \ + $opts(ld) -o $objfile $objfiles $opts(ld_after_inputfiles)" + + # If needed then check for, or add a -Map option. + set mapfile "" + if { $opts(map) != "" } then { + if { [regexp -- "-Map=(\[^ \]+)" $cmd all mapfile] } then { + # Found existing mapfile option + verbose -log "Existing mapfile '$mapfile' found" + } else { + # No mapfile option. + set mapfile "tmpdir/dump.map" + verbose -log "Adding mapfile '$mapfile'" + set cmd "$cmd -Map=$mapfile" + } + } + + send_log "$cmd\n" + set cmdret [remote_exec host [concat sh -c [list "$cmd 2>&1"]] "" "/dev/null" "dump.tmp"] + remote_upload host "dump.tmp" + append comp_output [file_contents "dump.tmp"] + remote_file host delete "dump.tmp" + remote_file build delete "dump.tmp" + set cmdret [lindex $cmdret 0] + + if { $cmdret == 0 && $run_objcopy } { + set infile $objfile + set objfile "tmpdir/dump1" + remote_file host delete $objfile + + # Note that we don't use OBJCOPYFLAGS here; any flags must be + # explicitly specified. + set cmd "$OBJCOPY $opts(objcopy_linked_file) $infile $objfile" + + send_log "$cmd\n" + set cmdret [remote_exec host [concat sh -c [list "$cmd 2>&1"]] "" "/dev/null" "dump.tmp"] + remote_upload host "dump.tmp" + append comp_output [file_contents "dump.tmp"] + remote_file host delete "dump.tmp" + remote_file build delete "dump.tmp" + set cmdret [lindex $cmdret 0] + } + } else { + set objfile [lindex $objfiles 0] + } + + if { $cmdret == 0 && $opts(PROG) != "" } { + set destopt ${copyfile}.o + switch -- $opts(PROG) { + ar { set program ar } + elfedit { + set program elfedit + set destopt "" + } + nm { set program nm } + objcopy { set program objcopy } + ranlib { set program ranlib } + strings { set program strings } + strip { + set program strip + set destopt "-o $destopt" + } + default { + perror "unrecognized PROG option $opts(PROG) in $file.d" + unresolved $testname + continue + } + } + + set progopts1 $opts($program) + eval set progopts \$[string toupper $program]FLAGS + eval set binary \$[string toupper $program] + + if { ![is_remote host] && [which $binary] == 0 } { + untested $testname + continue + } + + verbose "running $binary $progopts $progopts1" 3 + set cmd "$binary $progopts $progopts1 $objfile $destopt" + + # Ensure consistent sorting of symbols + if {[info exists env(LC_ALL)]} { + set old_lc_all $env(LC_ALL) + } + set env(LC_ALL) "C" + send_log "$cmd\n" + set cmdret [remote_exec host [concat sh -c [list "$cmd 2>dump.tmp"]] "" "/dev/null"] + set cmdret [lindex $cmdret 0] + remote_upload host "dump.tmp" + append comp_output [prune_warnings [file_contents "dump.tmp"]] + remote_file host delete "dump.tmp" + remote_file build delete "dump.tmp" + if {[info exists old_lc_all]} { + set env(LC_ALL) $old_lc_all + } else { + unset env(LC_ALL) + } + if { $destopt != "" } { + set objfile ${copyfile}.o + } + } + + set want_out(source) "" + set want_out(terminal) 0 + if { $err_warn } { + if { $opts(error) != "" || $opts(error_output) != "" } { + set want_out(terminal) 1 + } + + if { $opts(error) != "" || $opts(warning) != "" } { + set want_out(source) "regex" + if { $opts(error) != "" } { + set want_out(regex) $opts(error) + } else { + set want_out(regex) $opts(warning) + } + } else { + set want_out(source) "file" + if { $opts(error_output) != "" } { + set want_out(file) $opts(error_output) + } else { + set want_out(file) $opts(warning_output) + } + } + } + + regsub "\n$" $comp_output "" comp_output + if { $cmdret != 0 || $comp_output != "" || $want_out(source) != "" } { + set exitstat "succeeded" + if { $cmdret != 0 } { set exitstat "failed" } + + if { $want_out(source) == "regex" } { + verbose -log "$exitstat with: <$comp_output>, expected: <$want_out(regex)>" + } elseif { $want_out(source) == "file" } { + verbose -log "$exitstat with: <$comp_output>, expected in file $want_out(file)" + set_file_contents "tmpdir/ld.messages" "$comp_output" + } else { + verbose -log "$exitstat with: <$comp_output>, no expected output" + } + + if { (($want_out(source) == "") == ($comp_output == "")) \ + && (($cmdret == 0) == ($want_out(terminal) == 0)) \ + && ((($want_out(source) == "regex") \ + && [regexp -- $want_out(regex) $comp_output]) \ + || (($want_out(source) == "file") \ + && (![regexp_diff "tmpdir/ld.messages" "$srcdir/$subdir/$want_out(file)"]))) } { + # We have the expected output. + if { $want_out(terminal) || $dumpprogram == "" } { + pass $testname + continue + } + } else { + fail $testname + continue + } + } + + # We must not have expected failure if we get here. + if { $opts(error) != "" } { + fail $testname + continue + } + + if { $opts(map) != "" } then { + # Check the map file matches. + set map_pattern_file $srcdir/$subdir/$opts(map) + verbose -log "Compare '$mapfile' against '$map_pattern_file'" + if { [regexp_diff $mapfile $map_pattern_file] } then { + fail "$testname (map file check)" + } else { + pass "$testname (map file check)" + } + + if { $dumpprogram == "" } then { + continue + } + } + + set progopts1 $opts($dumpprogram) + eval set progopts \$[string toupper $dumpprogram]FLAGS + eval set binary \$[string toupper $dumpprogram] + + if { ![is_remote host] && [which $binary] == 0 } { + untested $testname + continue + } + + # For objdump of gas output, automatically translate standard section names + set sect_names "" + if { !$run_ld && $dumpprogram == "objdump" \ + && $opts(section_subst) != "no" \ + && ![string match "*-b binary*" $progopts1] } { + set sect_names [get_standard_section_names] + if { $sect_names != ""} { + regsub -- "\\.text" $progopts1 "[lindex $sect_names 0]" progopts1 + regsub -- "\\.data" $progopts1 "[lindex $sect_names 1]" progopts1 + regsub -- "\\.bss" $progopts1 "[lindex $sect_names 2]" progopts1 + } + } + + if { $progopts1 == "" } { set $progopts1 "-r" } + verbose "running $binary $progopts $progopts1" 3 + + set cmd "$binary $progopts $progopts1 $objfile > $dumpfile" + + # Ensure consistent sorting of symbols + if {[info exists env(LC_ALL)]} { + set old_lc_all $env(LC_ALL) + } + set env(LC_ALL) "C" + send_log "$cmd\n" + set cmdret [remote_exec host [concat sh -c [list "$cmd 2>dump.tmp"]] "" "/dev/null"] + set cmdret [lindex $cmdret 0] + remote_upload host "dump.tmp" + set comp_output [prune_warnings [file_contents "dump.tmp"]] + remote_file host delete "dump.tmp" + remote_file build delete "dump.tmp" + if {[info exists old_lc_all]} { + set env(LC_ALL) $old_lc_all + } else { + unset env(LC_ALL) + } + if { $cmdret != 0 || $comp_output != "" } { + send_log "exited abnormally with $cmdret, output:$comp_output\n" + fail $testname + continue + } + + if { $verbose > 2 } then { verbose "output is [file_contents $dumpfile]" 3 } + + # Create the substition list for objdump output. + set regexp_subst "" + if { $sect_names != "" } { + set regexp_subst [list "\\\\?\\.text" [lindex $sect_names 0] \ + "\\\\?\\.data" [lindex $sect_names 1] \ + "\\\\?\\.bss" [lindex $sect_names 2] ] + } + + if { [regexp_diff $dumpfile "${dfile}" $regexp_subst] } then { + fail $testname + if { $verbose == 2 } then { verbose "output is [file_contents $dumpfile]" 2 } + continue + } + + pass $testname + } +} + +proc slurp_options { file } { + # If options_regsub(foo) is set to {a b}, then the contents of a + # "#foo:" line will have regsub -all applied to replace a with b. + global options_regsub + + if [catch { set f [open $file r] } x] { + #perror "couldn't open `$file': $x" + perror "$x" + return -1 + } + set opt_array {} + # whitespace expression + set ws {[ ]*} + set nws {[^ ]*} + # whitespace is ignored anywhere except within the options list; + # option names are alphanumeric plus underscore. + set pat "^#${ws}(\[a-zA-Z0-9_\]*)$ws:${ws}(.*)$ws\$" + while { [gets $f line] != -1 } { + set line [string trim $line] + # Whitespace here is space-tab. + if [regexp $pat $line xxx opt_name opt_val] { + # match! + if [info exists options_regsub($opt_name)] { + set subst $options_regsub($opt_name) + regsub -all -- [lindex $subst 0] $opt_val [lindex $subst 1] \ + opt_val + } + lappend opt_array [list $opt_name $opt_val] + } elseif {![regexp "^#" $line ]} { + break + } + } + close $f + return $opt_array +} + +proc file_contents { filename } { + set file [open $filename r] + set contents [read $file] + close $file + return $contents +} + +proc set_file_contents { filename contents } { + set file [open $filename w] + puts $file "$contents" + close $file +} + +# Look for big-endian or little-endian switches in the multlib +# options and translate these into a -EB or -EL switch. Note +# we cannot rely upon proc process_multilib_options to do this +# for us because for some targets the compiler does not support +# -EB/-EL but it does support -mbig-endian/-mlittle-endian, and +# the site.exp file will include the switch "-mbig-endian" +# (rather than "big-endian") which is not detected by proc +# process_multilib_options. +# +proc big_or_little_endian {} { + + if [board_info [target_info name] exists multilib_flags] { + set tmp_flags " [board_info [target_info name] multilib_flags]" + + foreach x $tmp_flags { + switch -glob $x { + *big*endian - + eb - + EB - + -eb - + -EB - + -mb - + -meb { + set flags " -EB" + return $flags + } + *little*endian - + el - + EL - + -el - + -EL - + -ml - + -mel { + set flags " -EL" + return $flags + } + } + } + } + + set flags "" + return $flags +} + +# Internal procedure: return the names of the standard sections +# +proc get_standard_section_names {} { + if [istarget "rx-*-elf"] { + return { "P" "D_1" "B_1" } + } + if { [istarget "alpha*-*-*vms*"] || [is_som_format] } { + return { {\$CODE\$} {\$DATA\$} {\$BSS\$} } + } + return +}