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 2018 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 exit 2 82} 83 84# 85# By default, tests only run for the current platform. In other words, 86# running on an x86 system only assumes that the tests in the i386 87# directory should be run. If the -p option is specified, then other 88# platforms will be run. 89# 90# Right now, we only support running this on x86 natively; however, you 91# can run tests for other platforms with the -p option. 92# 93determine_arch() 94{ 95 typeset arch 96 97 arch=$(uname -p) 98 [[ $? -eq 0 ]] || fatal "failed to determine host architecture" 99 [[ "$arch" != "i386" ]] && fatal "dis tests are only supported on x86" 100 [[ -n "$dt_nodefault" ]] && return 101 dt_defarch="i386" 102 dt_platforms[$dt_defarch]=$dt_defas 103} 104 105# 106# Iterate over the set of platforms and verify that we both know about them and 107# we can find the assembler for them. 108# 109check_platforms() 110{ 111 typeset key 112 113 for key in ${!dt_platforms[@]}; do 114 typeset bin 115 [[ -d $dt_root/$key ]] || fatal "encountered unknown platform: $key" 116 117 # 118 # This may be a path or something else. 119 # 120 bin=${dt_platforms[$key]} 121 [[ -x $bin ]] && continue 122 which $bin >/dev/null 2>&1 && continue 123 fatal "failed to find command as absolute path or file: $bin" 124 done 125} 126 127handle_failure() 128{ 129 typeset dir reason source out 130 dir=$1 131 reason=$2 132 source=$3 133 out=$4 134 faildir= 135 136 while [[ -d failure.$dt_faildir ]]; do 137 ((dt_faildir++)) 138 done 139 140 faildir="failure.$dt_faildir" 141 mv $dir $faildir 142 cp $source $faildir/ 143 cp $out $faildir/ 144 printf "%s " "failed " 145 [[ -n $reason ]] && printf "%s " $reason 146 printf "%s\n" "$faildir" 147 ((dt_tfail++)) 148} 149 150# 151# Check 152# 153test_one() 154{ 155 typeset gflags source cmp disfile outfile extra aserr diserr 156 dir="dis.$$" 157 gflags=$1 158 source=$2 159 cmp=$3 160 extra=$4 161 162 outfile=$dir/dis.o 163 aserr=$dir/as.stderr 164 disfile=$dir/libdis.out 165 diserr=$dir/dis.stderr 166 167 ((dt_tnum++)) 168 mkdir -p $dir || fatal "failed to make directory $dir" 169 170 printf "testing %s " $source 171 [[ -n $extra ]] && printf "%s " $extra 172 printf "... " 173 if ! $gas $gflags -o $outfile $source 2>$aserr >/dev/null; then 174 handle_failure $dir "(assembling)" $source $cmp 175 return 176 fi 177 178 if ! $dt_dis $outfile >$disfile 2>$diserr; then 179 handle_failure $dir "(disassembling)" $source $cmp 180 return 181 fi 182 183 if ! $dt_diff $disfile $cmp; then 184 handle_failure $dir "(comparing)" $source $cmp 185 return 186 fi 187 188 ((dt_tsuc++)) 189 print "passed" 190 rm -rf $dir || fatal "failed to remove directory $dir" 191} 192 193# 194# Run a single test. This may result in two actual tests (one 32-bit and one 195# 64-bit) being run. 196# 197run_single_file() 198{ 199 typeset sfile base cmpfile prefix arch gas p flags 200 typeset asflags32 asflags64 201 sfile=$1 202 203 base=${sfile##*/} 204 cmpfile=${sfile%.*}.out 205 prefix=${base%%.*} 206 arch=${sfile%/*} 207 arch=${arch##*/} 208 [[ -f $cmpfile ]] || fatal "missing output file $cmpfile" 209 gas=${dt_platforms[$arch]} 210 [[ -n $gas ]] || fatal "encountered test $sfile, but missing assembler" 211 212 case "$arch" in 213 "risc-v") 214 asflags32="-march=rv32g" 215 asflags64="-march=rv64g" 216 ;; 217 "risc-v-c") 218 asflags32="-march=rv32gc" 219 asflags64="-march=rv64gc" 220 ;; 221 *) 222 asflags32="-32" 223 asflags64="-64" 224 ;; 225 esac 226 227 case "$prefix" in 228 32) 229 test_one $asflags32 $sfile $cmpfile 230 ;; 231 64) 232 test_one $asflags64 $sfile $cmpfile 233 ;; 234 tst) 235 test_one $asflags32 $sfile $cmpfile "(32-bit)" 236 test_one $asflags64 $sfile $cmpfile "(64-bit)" 237 ;; 238 esac 239} 240 241# 242# Iterate over all the test directories and run the specified tests 243# 244run_tests() 245{ 246 typeset t 247 if [[ $# -ne 0 ]]; then 248 for t in $@; do 249 run_single_file $t 250 done 251 else 252 typeset k tests tests32 tests64 253 for k in ${!dt_platforms[@]}; do 254 tests=$(find $dt_root/$k -type f -name 'tst.*.s') 255 tests32=$(find $dt_root/$k -type f -name '32.*.s') 256 tests64=$(find $dt_root/$k -type f -name '64.*.s') 257 for t in $tests $tests32 $tests64; do 258 run_single_file $t 259 done 260 done 261 fi 262} 263 264goodbye() 265{ 266 cat <<EOF 267 268-------------- 269libdis Results 270-------------- 271 272Tests passed: $dt_tsuc 273Tests failed: $dt_tfail 274Tests ran: $dt_tnum 275EOF 276} 277 278 279dt_origwd=$PWD 280cd $(dirname $0) || fatal "failed to cd to test root" 281dt_root=$PWD 282cd $dt_origwd || fatal "failed to return to original dir" 283 284while getopts ":np:" c $@; do 285 case "$c" in 286 n) 287 dt_nodefault="y" 288 ;; 289 p) 290 OLDIFS=$IFS 291 IFS="=" 292 set -A split $OPTARG 293 IFS=$OLDIFS 294 [[ ${#split[@]} -eq 2 ]] || usage "malformed -p option: $OPTARG" 295 dt_platforms[${split[0]}]=${split[1]} 296 ;; 297 :) 298 usage "option requires an argument -- $OPTARG" 299 ;; 300 *) 301 usage "invalid option -- $OPTARG" 302 ;; 303 esac 304done 305 306[[ -n $dt_nodefault && ${#dt_platforms[@]} -eq 0 ]] && fatal \ 307 "no platforms specified to run tests for" 308 309shift $((OPTIND-1)) 310 311determine_arch 312check_platforms 313run_tests 314goodbye 315 316[[ $dt_tfail -eq 0 ]] 317