1#!/usr/bin/ksh 2# 3# This file and its contents are supplied under the terms of the 4# Common Development and Distribution License ("CDDL"), version 1.0. 5# You may only use this file in accordance with the terms of version 6# 1.0 of the CDDL. 7# 8# A full copy of the text of the CDDL should have accompanied this 9# source. A copy of the CDDL is also available via the Internet at 10# http://www.illumos.org/license/CDDL. 11# 12 13# 14# Copyright 2016 Joyent, Inc. 15# 16 17# 18# libdis test driver 19# 20# Tests are arranged by architecture. By default we'll run all of the 21# dis tests on our current architecture only. If the -p option is passed 22# to point to other correctly built gas instances, then we'll run those 23# tests, verifying that the cross-dis works. 24# 25# Each test should begin with one of the following three keywords: 26# 27# tst - Run both the 32-bit and 64-bit versions 28# 32 - Only run this with the gas 32-bit flag 29# 64 - Only run this with the gas 64-bit flag 30# 31# For example, tst.smap.s, would be built both 32-bit and 64-bit and compared to 32# its output file. 33# 34# Each input file should consist of a series of instructions in a function named 35# 'libdis_test'. The test suite will compile this file into an object file, 36# disassemble it, and compare it to the output file. 37# 38# For each input file, there should be a corresponding output file with the .out 39# suffix instead of the .s suffix. So, if you had tst.smap.s, you should have 40# tst.smap.out. 41# 42 43unalias -a 44dt_arg0=$(basename $0) 45dt_dis="/usr/bin/dis -qF libdis_test" 46dt_diff="/usr/bin/cmp -s" 47dt_defas="gas" 48dt_defarch= 49dt_nodefault= 50dt_tests= 51dt_tnum=0 52dt_tfail=0 53dt_tsuc=0 54dt_origwd= 55dt_root= 56dt_faildir=0 57typeset -A dt_platforms 58 59fatal() 60{ 61 typeset msg="$*" 62 [[ -z "$msg" ]] && msg="failed" 63 echo "$dt_arg0: $msg" >&2 64 exit 1 65} 66 67usage() 68{ 69 typeset msg="$*" 70 [[ -z "$msg" ]] || echo "$msg" 2>&1 71 cat <<USAGE >&2 72Usage: $dt_arg0 [-n] [ -p platform=pathtoas ]... [ test ]... 73 74 Runs all dis for the current platform or only specified tests if listed. 75 76 -n Don't run default platform tests 77 -p platform=pathtoas Run tests for platform using assembler. Should 78 either be an absolute path or a command on the 79 path. 80USAGE 81} 82 83# 84# By default, tests only run for the current platform. In other words, 85# running on an x86 system only assumes that the tests in the i386 86# directory should be run. If the -p option is specified, then other 87# platforms will be run. 88# 89# Right now, we only support running this on x86 natively; however, you 90# can run tests for other platforms with the -p option. 91# 92determine_arch() 93{ 94 typeset arch 95 96 arch=$(uname -p) 97 [[ $? -eq 0 ]] || fatal "failed to determine host architecture" 98 [[ "$arch" != "i386" ]] && fatal "dis tests are only supported on x86" 99 [[ -n "$dt_nodefault" ]] && return 100 dt_defarch="i386" 101 dt_platforms[$dt_defarch]=$dt_defas 102} 103 104# 105# Iterate over the set of platforms and verify that we both know about them and 106# we can find the assembler for them. 107# 108check_platforms() 109{ 110 typeset key 111 112 for key in ${!dt_platforms[@]}; do 113 typeset bin 114 [[ -d $dt_root/$key ]] || fatal "encountered unknown platform: $key" 115 116 # 117 # This may be a path or something else. 118 # 119 bin=${dt_platforms[$key]} 120 [[ -x $bin ]] && continue 121 which $bin >/dev/null 2>&1 && continue 122 fatal "failed to find command as absolute path or file: $bin" 123 done 124} 125 126handle_failure() 127{ 128 typeset dir reason source out 129 dir=$1 130 reason=$2 131 source=$3 132 out=$4 133 faildir= 134 135 while [[ -d failure.$dt_faildir ]]; do 136 ((dt_faildir++)) 137 done 138 139 faildir="failure.$dt_faildir" 140 mv $dir $faildir 141 cp $source $faildir/ 142 cp $out $faildir/ 143 printf "%s " "failed " 144 [[ -n $reason ]] && printf "%s " $reason 145 printf "%s\n" "$faildir" 146 ((dt_tfail++)) 147} 148 149# 150# Check 151# 152test_one() 153{ 154 typeset gflags source cmp disfile outfile extra aserr diserr 155 dir="dis.$$" 156 gflags=$1 157 source=$2 158 cmp=$3 159 extra=$4 160 161 outfile=$dir/dis.o 162 aserr=$dir/as.stderr 163 disfile=$dir/libdis.out 164 diserr=$dir/dis.stderr 165 166 ((dt_tnum++)) 167 mkdir -p $dir || fatal "failed to make directory $dir" 168 169 printf "testing %s " $source 170 [[ -n $extra ]] && printf "%s " $extra 171 printf "... " 172 if ! $gas $gflags -o $outfile $source 2>$aserr >/dev/null; then 173 handle_failure $dir "(assembling)" $source $cmp 174 return 175 fi 176 177 if ! $dt_dis $outfile >$disfile 2>$diserr; then 178 handle_failure $dir "(disassembling)" $source $cmp 179 return 180 fi 181 182 if ! $dt_diff $disfile $cmp; then 183 handle_failure $dir "(comparing)" $source $cmp 184 return 185 fi 186 187 ((dt_tsuc++)) 188 print "passed" 189 rm -rf $dir || fatal "failed to remove directory $dir" 190} 191 192# 193# Run a single test. This may result in two actual tests (one 32-bit and one 194# 64-bit) being run. 195# 196run_single_file() 197{ 198 typeset sfile base cmpfile prefix arch gas p flags 199 sfile=$1 200 201 base=${sfile##*/} 202 cmpfile=${sfile%.*}.out 203 prefix=${base%%.*} 204 arch=${sfile%/*} 205 arch=${arch##*/} 206 [[ -f $cmpfile ]] || fatal "missing output file $cmpfile" 207 gas=${dt_platforms[$arch]} 208 [[ -n $gas ]] || fatal "encountered test $sfile, but missing assembler" 209 210 case "$prefix" in 211 32) 212 test_one "-32" $sfile $cmpfile 213 ;; 214 64) 215 test_one "-64" $sfile $cmpfile 216 ;; 217 tst) 218 test_one "-32" $sfile $cmpfile "(32-bit)" 219 test_one "-64" $sfile $cmpfile "(64-bit)" 220 ;; 221 esac 222} 223 224# 225# Iterate over all the test directories and run the specified tests 226# 227run_tests() 228{ 229 typeset t 230 if [[ $# -ne 0 ]]; then 231 for t in $@; do 232 run_single_file $t 233 done 234 else 235 typeset k tests tests32 tests64 236 for k in ${!dt_platforms[@]}; do 237 tests=$(find $dt_root/$k -type f -name 'tst.*.s') 238 tests32=$(find $dt_root/$k -type f -name '32.*.s') 239 tests64=$(find $dt_root/$k -type f -name '64.*.s') 240 for t in $tests $tests32 $tests64; do 241 run_single_file $t 242 done 243 done 244 fi 245} 246 247goodbye() 248{ 249 cat <<EOF 250 251-------------- 252libdis Results 253-------------- 254 255Tests passed: $dt_tsuc 256Tests failed: $dt_tfail 257Tests ran: $dt_tnum 258EOF 259} 260 261 262dt_origwd=$PWD 263cd $(dirname $0) || fatal "failed to cd to test root" 264dt_root=$PWD 265cd $dt_origwd || fatal "failed to return to original dir" 266 267while getopts ":np:" c $@; do 268 case "$c" in 269 n) 270 dt_nodefault="y" 271 ;; 272 p) 273 IFS="=" 274 set -A split $OPTARG 275 IFS=" " 276 [[ ${#split[@]} -eq 2 ]] || usage "malformed -p option: $OPTARG" 277 dt_platforms[${split[0]}]=${split[1]} 278 ;; 279 :) 280 usage "option requires an argument -- $OPTARG" 281 ;; 282 *) 283 usage "invalid option -- $OPTARG" 284 ;; 285 esac 286done 287 288[[ -n $dt_nodefault && ${#dt_platforms[@]} -eq 0 ]] && fatal \ 289 "no platforms specified to run tests for" 290 291shift $((OPTIND-1)) 292 293determine_arch 294check_platforms 295run_tests 296goodbye 297 298[[ $dt_tfail -eq 0 ]] 299