#!/usr/bin/ksh93 # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2016 Joyent, Inc. # # # libdis test driver # # Tests are arranged by architecture. By default we'll run all of the # dis tests on our current architecture only. If the -p option is passed # to point to other correctly built gas instances, then we'll run those # tests, verifying that the cross-dis works. # # Each test should begin with one of the following three keywords: # # tst - Run both the 32-bit and 64-bit versions # 32 - Only run this with the gas 32-bit flag # 64 - Only run this with the gas 64-bit flag # # For example, tst.smap.s, would be built both 32-bit and 64-bit and compared to # its output file. # # Each input file should consist of a series of instructions in a function named # 'libdis_test'. The test suite will compile this file into an object file, # disassemble it, and compare it to the output file. # # For each input file, there should be a corresponding output file with the .out # suffix instead of the .s suffix. So, if you had tst.smap.s, you should have # tst.smap.out. # unalias -a typeset -r dt_dis='/usr/bin/dis -qF libdis_test' \ dt_diff='/usr/bin/cmp -s' \ dt_defas='gas' function showUsage { [[ -n $1 ]] && X='-?' || X='--man' getopts -a ${dt_arg0} "${ print ${USAGE} ; }" OPT $X } function fatal { typeset msg="$*" [[ -z ${msg} ]] && msg='failed' print -u2 "${dt_arg0}: ${msg}" exit 1 } # # By default, tests only run for the current platform. In other words, # running on an x86 system only assumes that the tests in the i386 # directory should be run. If the -p option is specified, then other # platforms will be run. # # Right now, we only support running this on x86 natively; however, you # can run tests for other platforms with the -p option. # function determine_arch { typeset arch=${ uname -p ; } [[ -z ${arch} ]] && fatal 'failed to determine host architecture' [[ ${arch} != 'i386' ]] && fatal 'dis tests are only supported on x86' (( dt_nodefault )) && return dt_platforms['i386']="${dt_defas}" } # # Iterate over the set of platforms and verify that we both know about them and # we can find the assembler for them. # function check_platforms { typeset key bin for key in ${!dt_platforms[@]}; do [[ -d ${dt_root}/${key} ]] || fatal "encountered unknown platform: ${key}" # # This may be a path or something else. # bin=${dt_platforms[${key}]} [[ -x ${bin} ]] && continue whence -p ${bin} >/dev/null && continue fatal "failed to find command as absolute path or file: ${bin}" done } function handle_failure { typeset dir=$1 reason=$2 source=$3 out=$4 faildir while [[ -d failure.${dt_faildir} ]]; do ((dt_faildir++)) done faildir="failure.${dt_faildir}" mv "${dir}" "${faildir}" cp "${source}" "${faildir}/" cp "${out}" "${faildir}/" [[ -n ${reason} ]] && reason+=' ' print "failed ${reason}${faildir}" ((dt_tfail++)) } # # Check # function test_one { typeset dir="dis.$$" gflags=$1 source=$2 cmp=$3 extra=$4 \ outfile="${dir}/dis.o" aserr="${dir}/as.stderr" \ disfile="${dir}/libdis.out" diserr="${dir}/dis.stderr" ((dt_tnum++)) mkdir -p ${dir} || fatal "failed to make directory '${dir}'" [[ -n ${extra} ]] && extra+=' ' print -n "testing ${source} ${extra}... " if ! "${gas}" ${gflags} -o ${outfile} "${source}" 2>${aserr} >/dev/null then handle_failure ${dir} '(assembling)' "${source}" "${cmp}" return fi if ! "${dt_dis}" ${outfile} >${disfile} 2>${diserr}; then handle_failure ${dir} '(disassembling)' "${source}" "${cmp}" return fi if ! "${dt_diff}" ${disfile} "${cmp}"; then handle_failure ${dir} '(comparing)' "${source}" "${cmp}" return fi ((dt_tsuc++)) print 'passed' rm -rf ${dir} || fatal "failed to remove directory '${dir}'" } # # Run a single test. This may result in two actual tests (one 32-bit and one # 64-bit) being run. # function run_single_file { typeset sfile=$1 base cmpfile prefix arch gas p flags base=${sfile##*/} arch=${sfile:0:${#base}-1} arch=${arch##*/} cmpfile=${sfile%.*}.out [[ -f ${cmpfile} ]] || fatal "missing output file '${cmpfile}'" prefix=${base%%.*} gas=${dt_platforms[${arch}]} [[ -n ${gas} ]] || fatal "encountered test '${sfile}', but missing assembler" case "${prefix}" in 32) test_one '-32' "${sfile}" "${cmpfile}" ;; 64) test_one '-64' "${sfile}" "${cmpfile}" ;; tst) test_one '-32' "${sfile}" "${cmpfile}" '(32-bit)' test_one '-64' "${sfile}" "${cmpfile}" '(64-bit)' ;; esac } # # Iterate over all the test directories and run the specified tests # function run_tests { typeset t if (( $# )); then for t in $@; do run_single_file "$t" done return $? fi typeset k tests tests32 tests64 for k in ${!dt_platforms[@]}; do tests=${ find ${dt_root}/$k -type f -name 'tst.*.s' ; } tests32=${ find ${dt_root}/$k -type f -name '32.*.s' ; } tests64=${ find ${dt_root}/$k -type f -name '64.*.s' ; } for t in ${tests} ${tests32} ${tests64}; do run_single_file "$t" done done } function goodbye { cat <