xref: /illumos-gate/usr/src/test/util-tests/tests/dis/distest.ksh (revision 4c28a617e3922d92a58e813a5b955eb526b9c386)
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