Home | History | Annotate | Download | only in tests-m32
      1 #!/bin/sh
      2 #
      3 # Copyright (c) 2011-2016 Dmitry V. Levin <ldv (at] altlinux.org>
      4 # Copyright (c) 2011-2018 The strace developers.
      5 # All rights reserved.
      6 #
      7 # Redistribution and use in source and binary forms, with or without
      8 # modification, are permitted provided that the following conditions
      9 # are met:
     10 # 1. Redistributions of source code must retain the above copyright
     11 #    notice, this list of conditions and the following disclaimer.
     12 # 2. Redistributions in binary form must reproduce the above copyright
     13 #    notice, this list of conditions and the following disclaimer in the
     14 #    documentation and/or other materials provided with the distribution.
     15 # 3. The name of the author may not be used to endorse or promote products
     16 #    derived from this software without specific prior written permission.
     17 #
     18 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19 # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20 # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23 # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 export LC_ALL=C
     30 ME_="${0##*/}"
     31 LOG="log"
     32 OUT="out"
     33 EXP="exp"
     34 
     35 warn_() { printf >&2 '%s\n' "$*"; }
     36 fail_() { warn_ "$ME_: failed test: $*"; exit 1; }
     37 skip_() { warn_ "$ME_: skipped test: $*"; exit 77; }
     38 framework_failure_() { warn_ "$ME_: framework failure: $*"; exit 99; }
     39 framework_skip_() { warn_ "$ME_: framework skip: $*"; exit 77; }
     40 
     41 check_prog()
     42 {
     43 	type "$@" > /dev/null 2>&1 ||
     44 		framework_skip_ "$* is not available"
     45 }
     46 
     47 dump_log_and_fail_with()
     48 {
     49 	cat < "$LOG" >&2
     50 	fail_ "$*"
     51 }
     52 
     53 run_prog()
     54 {
     55 	if [ $# -eq 0 ]; then
     56 		set -- "../$NAME"
     57 	fi
     58 	args="$*"
     59 	"$@" || {
     60 		rc=$?
     61 		if [ $rc -eq 77 ]; then
     62 			skip_ "$args exited with code 77"
     63 		else
     64 			fail_ "$args failed with code $rc"
     65 		fi
     66 	}
     67 }
     68 
     69 
     70 run_prog_skip_if_failed()
     71 {
     72 	args="$*"
     73 	"$@" || framework_skip_ "$args failed with code $?"
     74 }
     75 
     76 try_run_prog()
     77 {
     78 	local rc
     79 
     80 	"$@" > /dev/null || {
     81 		rc=$?
     82 		if [ $rc -eq 77 ]; then
     83 			return 1
     84 		else
     85 			fail_ "$* failed with code $rc"
     86 		fi
     87 	}
     88 }
     89 
     90 run_strace()
     91 {
     92 	> "$LOG" || fail_ "failed to write $LOG"
     93 	args="$*"
     94 	$STRACE -o "$LOG" "$@" ||
     95 		dump_log_and_fail_with "$STRACE $args failed with code $?"
     96 }
     97 
     98 run_strace_merge()
     99 {
    100 	rm -f -- "$LOG".[0-9]*
    101 	run_strace -ff -tt "$@"
    102 	"$srcdir"/../strace-log-merge "$LOG" > "$LOG" ||
    103 		dump_log_and_fail_with 'strace-log-merge failed with code $?'
    104 	rm -f -- "$LOG".[0-9]*
    105 }
    106 
    107 check_gawk()
    108 {
    109 	check_prog gawk
    110 	check_prog grep
    111 
    112 	local program="$1"; shift
    113 	if grep '^@include[[:space:]]' < "$program" > /dev/null; then
    114 		gawk '@include "/dev/null"' < /dev/null ||
    115 			framework_skip_ 'gawk does not support @include'
    116 	fi
    117 }
    118 
    119 # Usage: [FILE_TO_CHECK [AWK_PROGRAM [ERROR_MESSAGE [EXTRA_AWK_OPTIONS...]]]]
    120 # Check whether AWK_PROGRAM matches FILE_TO_CHECK using gawk.
    121 # If it doesn't, dump FILE_TO_CHECK and fail with ERROR_MESSAGE.
    122 match_awk()
    123 {
    124 	local output program error
    125 	if [ $# -eq 0 ]; then
    126 		output="$LOG"
    127 	else
    128 		output="$1"; shift
    129 	fi
    130 	if [ $# -eq 0 ]; then
    131 		program="$srcdir/$NAME.awk"
    132 	else
    133 		program="$1"; shift
    134 	fi
    135 	if [ $# -eq 0 ]; then
    136 		error="$STRACE $args output mismatch"
    137 	else
    138 		error="$1"; shift
    139 	fi
    140 
    141 	check_gawk "$program"
    142 
    143 	AWKPATH="$srcdir" gawk -f "$program" "$@" < "$output" || {
    144 		cat < "$output"
    145 		fail_ "$error"
    146 	}
    147 }
    148 
    149 # Usage: [FILE_TO_CHECK [FILE_TO_COMPATE_WITH [ERROR_MESSAGE]]]
    150 # Check whether FILE_TO_CHECK differs from FILE_TO_COMPATE_WITH.
    151 # If it does, dump the difference and fail with ERROR_MESSAGE.
    152 match_diff()
    153 {
    154 	local output expected error
    155 	if [ $# -eq 0 ]; then
    156 		output="$LOG"
    157 	else
    158 		output="$1"; shift
    159 	fi
    160 	if [ $# -eq 0 ]; then
    161 		expected="$srcdir/$NAME.expected"
    162 	else
    163 		expected="$1"; shift
    164 	fi
    165 	if [ $# -eq 0 ]; then
    166 		error="$STRACE $args output mismatch"
    167 	else
    168 		error="$1"; shift
    169 	fi
    170 
    171 	check_prog diff
    172 
    173 	diff -u -- "$expected" "$output" ||
    174 		fail_ "$error"
    175 }
    176 
    177 # Usage: [FILE_TO_CHECK [FILE_WITH_PATTERNS [ERROR_MESSAGE]]]
    178 # Check whether all patterns listed in FILE_WITH_PATTERNS
    179 # match FILE_TO_CHECK using egrep.
    180 # If at least one of these patterns does not match,
    181 # dump both files and fail with ERROR_MESSAGE.
    182 match_grep()
    183 {
    184 	local output patterns error pattern cnt failed=
    185 	if [ $# -eq 0 ]; then
    186 		output="$LOG"
    187 	else
    188 		output="$1"; shift
    189 	fi
    190 	if [ $# -eq 0 ]; then
    191 		patterns="$srcdir/$NAME.expected"
    192 	else
    193 		patterns="$1"; shift
    194 	fi
    195 	if [ $# -eq 0 ]; then
    196 		error="$STRACE $args output mismatch"
    197 	else
    198 		error="$1"; shift
    199 	fi
    200 
    201 	check_prog wc
    202 	check_prog grep
    203 
    204 	cnt=1
    205 	while read -r pattern; do
    206 		LC_ALL=C grep -E -x -e "$pattern" < "$output" > /dev/null || {
    207 			test -n "$failed" || {
    208 				echo 'Failed patterns of expected output:'
    209 				failed=1
    210 			}
    211 			printf '#%d: %s\n' "$cnt" "$pattern"
    212 		}
    213 		cnt=$(($cnt + 1))
    214 	done < "$patterns"
    215 	test -z "$failed" || {
    216 		echo 'Actual output:'
    217 		cat < "$output"
    218 		fail_ "$error"
    219 	}
    220 }
    221 
    222 # Usage: run_strace_match_diff [args to run_strace]
    223 run_strace_match_diff()
    224 {
    225 	args="$*"
    226 	[ -n "$args" -a -z "${args##*-e trace=*}" ] ||
    227 		set -- -e trace="$NAME" "$@"
    228 	run_prog > /dev/null
    229 	run_strace "$@" $args > "$EXP"
    230 	match_diff "$LOG" "$EXP"
    231 }
    232 
    233 # Usage: run_strace_match_grep [args to run_strace]
    234 run_strace_match_grep()
    235 {
    236 	args="$*"
    237 	[ -n "$args" -a -z "${args##*-e trace=*}" ] ||
    238 		set -- -e trace="$NAME" "$@"
    239 	run_prog > /dev/null
    240 	run_strace "$@" $args > "$EXP"
    241 	match_grep "$LOG" "$EXP"
    242 }
    243 
    244 # Print kernel version code.
    245 # usage: kernel_version_code $(uname -r)
    246 kernel_version_code()
    247 {
    248 	(
    249 		set -f
    250 		IFS=.
    251 		set -- $1 0 0
    252 		v1="${1%%[!0-9]*}" && [ -n "$v1" ] || v1=0
    253 		v2="${2%%[!0-9]*}" && [ -n "$v2" ] || v2=0
    254 		v3="${3%%[!0-9]*}" && [ -n "$v3" ] || v3=0
    255 		echo "$(($v1 * 65536 + $v2 * 256 + $v3))"
    256 	)
    257 }
    258 
    259 # Usage: require_min_kernel_version_or_skip 3.0
    260 require_min_kernel_version_or_skip()
    261 {
    262 	local uname_r
    263 	uname_r="$(uname -r)"
    264 
    265 	[ "$(kernel_version_code "$uname_r")" -ge \
    266 	  "$(kernel_version_code "$1")" ] ||
    267 		skip_ "the kernel release $uname_r is not $1 or newer"
    268 }
    269 
    270 # Usage: grep_pid_status $pid GREP-OPTIONS...
    271 grep_pid_status()
    272 {
    273 	local pid
    274 	pid=$1; shift
    275 	cat < "/proc/$pid/status" | grep "$@"
    276 }
    277 
    278 # Subtracts one program set from another.
    279 # If an optional regular expression is specified, the lines in the minuend file
    280 # that match this regular expression are elso excluded from the output.
    281 #
    282 # Usage: prog_set_subtract minuend_file subtrahend_file [subtrahend_regexp]
    283 prog_set_subtract()
    284 {
    285 	local min sub re pat
    286 	min="$1"; shift
    287 	sub="$1"; shift
    288 	re="${1-}"
    289 	pat="$re|$(sed 's/[[:space:]].*//' < "$sub" | tr -s '\n' '|')"
    290 	grep -E -v -x -e "$pat" < "$min"
    291 }
    292 
    293 # Usage: test_pure_prog_set [--expfile FILE] COMMON_ARGS < tests_file
    294 # stdin should consist of lines in "test_name strace_args..." format.
    295 test_pure_prog_set()
    296 {
    297 	local expfile
    298 
    299 	expfile="$EXP"
    300 
    301 	while [ -n "$1" ]; do
    302 		case "$1" in
    303 		--expfile)
    304 			shift
    305 			expfile="$1"
    306 			shift
    307 			;;
    308 		*)
    309 			break
    310 			;;
    311 		esac
    312 	done
    313 
    314 	while read -r t prog_args; do {
    315 		# skip lines beginning with "#" symbol
    316 		[ "${t###}" = "$t" ] || continue
    317 
    318 		try_run_prog "../$t" || continue
    319 		run_strace $prog_args "$@" "../$t" > "$expfile"
    320 		match_diff "$LOG" "$expfile"
    321 	} < /dev/null; done
    322 }
    323 
    324 # Run strace against list of programs put in "$NAME.in" and then against the
    325 # rest of pure_executables.list with the expectation of empty output in the
    326 # latter case.
    327 #
    328 # Usage: source this file after init.sh and call:
    329 #   test_trace_expr subtrahend_regexp strace_args
    330 # Environment:
    331 #   $NAME:	test name, used for "$NAME.in" file containing list of tests
    332 #		for positive trace expression match;
    333 #   $srcdir:	used to find pure_executables.list and "$NAME.in" files.
    334 # Files created:
    335 #   negative.list: File containing list of tests for negative match.
    336 test_trace_expr()
    337 {
    338 	local subtrahend_regexp
    339 	subtrahend_regexp="$1"; shift
    340 	test_pure_prog_set "$@" < "$srcdir/$NAME.in"
    341 	prog_set_subtract "$srcdir/pure_executables.list" "$srcdir/$NAME.in" \
    342 		"$subtrahend_regexp" > negative.list
    343 	test_pure_prog_set --expfile /dev/null -qq -esignal=none "$@" \
    344 		< negative.list
    345 }
    346 
    347 check_prog cat
    348 check_prog rm
    349 
    350 case "$ME_" in
    351 	*.gen.test) NAME="${ME_%.gen.test}" ;;
    352 	*.test) NAME="${ME_%.test}" ;;
    353 	*) NAME=
    354 esac
    355 
    356 STRACE_EXE=
    357 if [ -n "$NAME" ]; then
    358 	TESTDIR="$NAME.dir"
    359 	rm -rf -- "$TESTDIR"
    360 	mkdir -- "$TESTDIR"
    361 	cd "$TESTDIR"
    362 
    363 	case "$srcdir" in
    364 		/*) ;;
    365 		*) srcdir="../$srcdir" ;;
    366 	esac
    367 
    368 	[ -n "${STRACE-}" ] || {
    369 		STRACE=../../strace
    370 		case "${LOG_COMPILER-} ${LOG_FLAGS-}" in
    371 			*--suppressions=*--error-exitcode=*--tool=*)
    372 			STRACE_EXE="$STRACE"
    373 			# add valgrind command prefix
    374 			STRACE="${LOG_COMPILER-} ${LOG_FLAGS-} $STRACE"
    375 			;;
    376 		esac
    377 	}
    378 
    379 	trap 'dump_log_and_fail_with "time limit ($TIMEOUT_DURATION) exceeded"' XCPU
    380 else
    381 	: "${STRACE:=../strace}"
    382 fi
    383 
    384 # Export $STRACE_EXE to check_PROGRAMS.
    385 : "${STRACE_EXE:=$STRACE}"
    386 export STRACE_EXE
    387 
    388 : "${TIMEOUT_DURATION:=600}"
    389 : "${SLEEP_A_BIT:=sleep 1}"
    390 
    391 [ -z "${VERBOSE-}" ] ||
    392 	set -x
    393