xref: /illumos-gate/usr/src/test/util-tests/tests/ctf/ctftest.ksh (revision 8b184c19c5f61fa8890900f7bab686bf19b543d3)
1#!/usr/bin/ksh
2#
3#
4# This file and its contents are supplied under the terms of the
5# Common Development and Distribution License ("CDDL"), version 1.0.
6# You may only use this file in accordance with the terms of version
7# 1.0 of the CDDL.
8#
9# A full copy of the text of the CDDL should have accompanied this
10# source.  A copy of the CDDL is also available via the Internet at
11# http://www.illumos.org/license/CDDL.
12#
13
14#
15# Copyright (c) 2019, Joyent, Inc.
16# Copyright 2025 Oxide Computer Company
17#
18
19#
20# Run all of the various CTF tests
21#
22
23unalias -a
24#set -o xtrace
25
26if [[ -z "$TMPDIR" ]]; then
27	TMPDIR="/tmp"
28fi
29
30
31ctf_arg0=$(basename $0)
32ctf_root=$(cd $(dirname $0) && echo $PWD)
33ctf_tests=
34ctf_cc="gcc"
35ctf_cxx="g++"
36ctf_as="gas"
37ctf_convert="ctfconvert"
38ctf_merge="ctfmerge"
39ctf_debugdef="-gdwarf-2"
40ctf_debugflags=
41ctf_mach32="-m32"
42ctf_mach64="-m64"
43ctf_temp="$TMPDIR/ctftest.$$.o"
44ctf_makefile="Makefile.ctftest"
45ctf_nerrs=0
46ctf_cc_type=
47ctf_cc_vers=
48
49usage()
50{
51	typeset msg="$*"
52	[[ -z "$msg" ]] || echo "$msg" >&2
53	cat <<USAGE >&2
54Usage: $ctf_arg0 [-a as] [-c cc] [-C CC] [-g flags] [-m ctfmerge] [-t ctfconvert]
55
56	Runs the CTF test suite
57
58	-a assembler		Use the specified assembler, defaults to 'as'
59	-c compiler		Use the specified C compiler, defaults to 'gcc'
60	-C compiler		Use the specified C++ compiler, defaults to 'g++'
61	-g flags		Use flags to generate debug info. Defaults to
62				"-gdwarf-2".
63	-m ctfmerge		Use the specified ctfmerge, defaults to
64				'ctfmerge'
65	-t ctfconvert		Use the specified ctfconvert, defaults to
66				'ctfconvert'
67USAGE
68	exit 2
69}
70
71
72test_fail()
73{
74	typeset msg="$*"
75	[[ -z "$msg" ]] && msg="failed"
76	echo "TEST FAILED: $msg" >&2
77	((ctf_nerrs++))
78}
79
80warn()
81{
82	typeset msg="$*"
83	echo "$ctf_arg0: $msg" >&2
84}
85
86fatal()
87{
88	typeset msg="$*"
89	[[ -z "$msg" ]] && msg="failed"
90	echo "$ctf_arg0: $msg" >&2
91	rm -f "$ctf_temp"
92	exit 1
93}
94
95#
96# Attempt to try and figure out what class and version of compiler we
97# are dealing with so we can try and skip known failures due to existing
98# bugs in the compiler.
99#
100determine_compiler()
101{
102	typeset name=$($ctf_cc --version | awk '{ print $1; exit; }')
103	typeset version
104
105	if [[ "$name" == "gcc" ]]; then
106		version=$($ctf_cc --version | awk '{ print $NF; exit; }')
107	elif [[ "$name" == "clang" ]]; then
108		version=$($ctf_cc --version | awk '{ print $NF; exit; }')
109	else
110		warn "failed to parse compiler name from $ctf_cc, will " \
111		    "not make any assumptions about expected failures"
112		name="unknown"
113		version="unknown"
114	fi
115
116	ctf_cc_type="$name"
117	ctf_cc_version="$version"
118}
119
120announce()
121{
122	cat << EOF
123Beginning CTF tests with the following settings:
124cc:		$(which $ctf_cc)
125detected:	$ctf_cc_type $ctf_cc_version
126CC:		$(which $ctf_cxx)
127as:		$(which $ctf_as)
128ctfconvert:	$(which $ctf_convert)
129ctfmerge:	$(which $ctf_merge)
13032-bit CFLAGS:	$ctf_32cflags
13164-bit CFLAGS:	$ctf_64cflags
132
133EOF
134}
135
136run_one()
137{
138	typeset source=$1 checker=$2 flags=$3
139
140	if ! "$ctf_cc" $flags -o "$ctf_temp" -c "$source"; then
141		test_fail "failed to compile $source with flags: $flags"
142		return
143	fi
144
145	if ! "$ctf_convert" "$ctf_temp"; then
146		test_fail "failed to convert CTF in $source"
147		return
148	fi
149
150	if ! "$checker" "$ctf_temp"; then
151		test_fail "check for $source, $checker, failed"
152		return
153	fi
154
155	rm -f "$ctf_temp"
156	echo "TEST PASSED: $source $flags"
157}
158
159#
160# Perform a more complex build. The Makefile present will drive the
161# building of the artifacts and the running of the tests based on the
162# variables that we pass to it.
163#
164run_dir()
165{
166	typeset dir outdir check32 check64 flags32 flags64
167
168	dir=$1
169	outdir="$TMPDIR/ctftest.$$-$(basename $d)"
170	check32=$2
171	flags32=$3
172	check64=$4
173	flags64=$5
174
175	if ! mkdir $outdir; then
176		fatal "failed to make temporary directory '$outdir'"
177	fi
178
179	if ! make -C $dir -f Makefile.ctftest \
180	    BUILDDIR="$outdir" \
181	    CC="$ctf_cc" \
182	    CFLAGS32="$ctf_mach32" \
183	    CFLAGS64="$ctf_mach64" \
184	    DEBUGFLAGS="$ctf_debugflags" \
185	    CTFCONVERT="$ctf_convert" \
186	    CTFMERGE="$ctf_merge" \
187	    build 1>/dev/null; then
188		rm -rf $outdir
189		test_fail "failed to build $dir"
190		return
191	fi
192
193	if ! make -C $dir -f Makefile.ctftest \
194	    BUILDDIR="$outdir" \
195	    CHECK32="$check32" \
196	    CHECK64="$check64" \
197	    run-test 1>/dev/null; then
198		rm -rf $outdir
199		test_fail "failed to run tests for $dir"
200		return
201	fi
202
203	rm -rf $outdir
204	echo "TEST PASSED: $dir (dir)"
205}
206
207#
208# Find all of the tests that exist and then try to run them all. Tests
209# may either be a single file or a directory.
210#
211run_tests()
212{
213	typeset t base check
214	ctf_tests=$(ls "$ctf_root"/*.c)
215	for t in $ctf_tests; do
216		base=$(basename "$t" .c)
217		check=$(echo "$base" | sed s/test-/check-/)
218		if [[ -f "$ctf_root/$check" ]]; then
219			run_one $t "$ctf_root/$check" "$ctf_32cflags"
220			run_one $t "$ctf_root/$check" "$ctf_64cflags"
221		elif [[ -f "$ctf_root/$check-32" && \
222		    -f "$ctf_root/$check-64" ]]; then
223			run_one $t "$ctf_root/$check-32" "$ctf_32cflags"
224			run_one $t "$ctf_root/$check-64" "$ctf_64cflags"
225		else
226			test_fail "missing checker for $t"
227		fi
228	done
229
230	for d in $(find "$ctf_root" -maxdepth 1 -type d -name 'test-*'); do
231		[[ ! -f "$d/$ctf_makefile" ]] && continue
232		base=$(basename "$d")
233		check=$(echo "$base" | sed s/test-/check-/)
234		if [[ -f "$ctf_root/$check" ]]; then
235			run_dir $d "$ctf_root/$check" "$ctf_32cflags" \
236			    "$ctf_root/$check" "$ctf_64cflags"
237		elif [[ -f "$ctf_root/$check-32" && \
238		    -f "$ctf_root/$check-64" ]]; then
239			run_dir $d "$ctf_root/$check-32" "$ctf_32cflags" \
240			    "$ctf_root/$check-64" "$ctf_64cflags"
241		else
242			test_fail "missing checker for $t"
243		fi
244	done
245
246	outdir="$TMPDIR/ctftest.$$"
247
248	for f in $(find "$ctf_root" -maxdepth 1 -type f -name 'ctftest-*'); do
249		if ! mkdir $outdir; then
250			fatal "failed to make temporary directory '$outdir'"
251		fi
252
253		echo "Running $f in $outdir"
254
255		(cd $outdir && $f)
256
257		if (( $? != 0 )); then
258			test_fail "$f failed"
259		else
260			echo "TEST PASSED: $f"
261		fi
262
263		rm -rf $outdir
264	done
265}
266
267while getopts ":a:C:c:g:m:t:" c $@; do
268	case "$c" in
269	a)
270		ctf_as=$OPTARG
271		;;
272	C)
273		ctf_cxx=$OPTARG
274		;;
275	c)
276		ctf_cc=$OPTARG
277		;;
278	g)
279		ctf_debugflags+=" -g$OPTARG"
280		;;
281	m)
282		ctf_merge=$OPTARG
283		;;
284	t)
285		ctf_convert=$OPTARG
286		;;
287	:)
288		usage "option requires an argument -- $OPTARG"
289		;;
290	*)
291		usage "invalid option -- $OPTARG"
292		;;
293	esac
294done
295
296if [[ -z "$ctf_debugflags" ]]; then
297	ctf_debugflags=$ctf_debugdef
298fi
299
300ctf_32cflags="$ctf_mach32 $ctf_debugflags"
301ctf_64cflags="$ctf_mach64 $ctf_debugflags"
302
303determine_compiler
304
305export ctf_as ctf_cc ctf_cxx ctf_debugflags ctf_merge ctf_convert
306export ctf_cc_type ctf_cc_version
307
308announce
309
310run_tests
311
312if (( ctf_nerrs != 0 )); then
313	if (( ctf_nerrs == 1 )); then
314		printf "\n%s: %u test failed\n" "$ctf_arg0" "$ctf_nerrs"
315	else
316		printf "\n%s: %u tests failed\n" "$ctf_arg0" "$ctf_nerrs"
317	fi
318	exit 1
319else
320	printf "\n%s: All tests passed successfully\n" "$ctf_arg0"
321	exit 0
322fi
323