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