mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
281 lines
6.6 KiB
Bash
Executable File
281 lines
6.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# test-wrapper script for NaCl.
|
|
|
|
# Copyright (C) 2015-2016 Free Software Foundation, Inc.
|
|
# This file is part of the GNU C Library.
|
|
|
|
# The GNU C Library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
|
|
# The GNU C Library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with the GNU C Library; if not, see
|
|
# <http://www.gnu.org/licenses/>.
|
|
|
|
progname="$(basename "$0")"
|
|
|
|
usage="usage: ${progname} --arch=ARCH [VAR=VAL...] COMMAND ..."
|
|
help="
|
|
"
|
|
|
|
use_bootstrap=true
|
|
arch=
|
|
env=()
|
|
envi=0
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
|
|
--help)
|
|
echo "$usage"
|
|
echo "$help"
|
|
exit 0
|
|
;;
|
|
|
|
--arch=*)
|
|
arch="${1#--arch=}"
|
|
shift
|
|
;;
|
|
|
|
*=*)
|
|
env[envi++]='-E'
|
|
env[envi++]="$1"
|
|
shift
|
|
;;
|
|
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ $# -lt 1 -o -z "$arch" ]; then
|
|
echo "$usage" >&2
|
|
echo "Type '${progname} --help' for more detailed help." >&2
|
|
exit 1
|
|
fi
|
|
|
|
test_args=("$@")
|
|
|
|
if [ -z "$NACL_SDK_ROOT" ]; then
|
|
echo >&2 "$0: NACL_SDK_ROOT must be set in the environment"
|
|
exit 77
|
|
fi
|
|
|
|
# We use a handful of things from the NaCl SDK, or at least
|
|
# from a directory matching the layout of the NaCl SDK.
|
|
sdk_tools="${NACL_SDK_ROOT}/tools"
|
|
|
|
NACL_BOOTSTRAP="${sdk_tools}/nacl_helper_bootstrap_${arch}"
|
|
NACL_SEL_LDR="${sdk_tools}/sel_ldr_${arch}"
|
|
NACL_IRT="${sdk_tools}/irt_core_${arch}.nexe"
|
|
NACL_LOADER="${sdk_tools}/elf_loader_${arch}.nexe"
|
|
|
|
if [ ! -x "$NACL_BOOTSTRAP" -o ! -x "$NACL_SEL_LDR" ]; then
|
|
echo >&2 "$0: sel_ldr_${arch} and/or nacl_helper_bootstrap_${arch} missing"
|
|
echo >&2 "$0: from directory $sdk_tools"
|
|
exit 77
|
|
fi
|
|
|
|
if [ ! -r "$NACL_IRT" -o ! -r "$NACL_LOADER" ]; then
|
|
echo >&2 "$0: irt_core_${arch}.nexe and/or loader_${arch}.nexe missing"
|
|
echo >&2 "$0: from directory $sdk_tools"
|
|
exit 77
|
|
fi
|
|
|
|
# Figure out if we are building for the native machine or not.
|
|
# If not, we'll run sel_ldr under qemu.
|
|
decide_use_emulator()
|
|
{
|
|
local arg
|
|
for arg; do
|
|
if [[ "$(uname -m)" = "$1" ]]; then
|
|
return
|
|
fi
|
|
done
|
|
use_emulator=true
|
|
}
|
|
|
|
use_emulator=false
|
|
case "$arch" in
|
|
arm)
|
|
decide_use_emulator 'arm*'
|
|
emulator=(qemu-arm -cpu cortex-a15 -L "${sdk_tools}/arm_trusted")
|
|
;;
|
|
x86_32)
|
|
decide_use_emulator 'i?86' 'x86_64*'
|
|
emulator=(qemu-i386)
|
|
;;
|
|
x86_64)
|
|
decide_use_emulator 'x86_64*'
|
|
emulator=(qemu-x86_64)
|
|
;;
|
|
esac
|
|
|
|
if $use_emulator; then
|
|
ldr_args=('-Q')
|
|
emulator_factor=10
|
|
else
|
|
emulator=()
|
|
ldr_args=()
|
|
emulator_factor=1
|
|
fi
|
|
|
|
if $use_bootstrap; then
|
|
ldr=(
|
|
"${NACL_BOOTSTRAP}"
|
|
"${NACL_SEL_LDR}"
|
|
'--r_debug=0xXXXXXXXXXXXXXXXX'
|
|
'--reserved_at_zero=0xXXXXXXXXXXXXXXXX'
|
|
)
|
|
else
|
|
ldr=("${NACL_SEL_LDR}")
|
|
fi
|
|
|
|
static=true
|
|
case "$1" in
|
|
*/ld-nacl*) static=false ;;
|
|
esac
|
|
|
|
if $static; then
|
|
loader=()
|
|
else
|
|
loader=(-f "${NACL_LOADER}")
|
|
fi
|
|
|
|
run_test()
|
|
{
|
|
local test_fifo="$1"
|
|
local cmd=(
|
|
"${emulator[@]}" "${ldr[@]}" -q -S -a "${ldr_args[@]}" -B "${NACL_IRT}"
|
|
"${loader[@]}" "${env[@]}" -E TEST_DIRECT="$test_fifo" -- "${test_args[@]}"
|
|
)
|
|
if [ "${NACLVERBOSITY:+set}" = set ]; then
|
|
"${cmd[@]}"
|
|
else
|
|
NACLLOG=/dev/null "${cmd[@]}"
|
|
fi
|
|
}
|
|
|
|
temp_files=()
|
|
test_fifo=
|
|
do_cleanup()
|
|
{
|
|
rm -rf "$test_fifo" "${temp_files[@]}"
|
|
}
|
|
trap do_cleanup EXIT HUP INT TERM
|
|
|
|
# Create a named pipe to receive the TEST_DIRECT information from the test
|
|
# program.
|
|
test_fifo=${TMPDIR:-/tmp}/libc-test-fifo.$$
|
|
rm -f "$test_fifo"
|
|
mkfifo "$test_fifo" || {
|
|
echo "Cannot create test FIFO '$test_fifo'"
|
|
exit 1
|
|
}
|
|
|
|
# Run the test in the background, so we can implement a timeout.
|
|
# The no-op redirection defeats the default behavior of "< /dev/null"
|
|
# for a background command.
|
|
run_test "$test_fifo" <&0 & test_pid=$!
|
|
|
|
# Set up a short timeout before we read from the FIFO, in case
|
|
# the program doesn't actually write to the FIFO at all (it is
|
|
# not a test-skeleton.c program, or it dies very early).
|
|
no_skeleton=false
|
|
script_pid=$$
|
|
trap 'no_skeleton=true' USR1
|
|
(sleep 2; kill -USR1 $script_pid) 2> /dev/null &
|
|
|
|
# The test should first write into the FIFO to describe its expectations.
|
|
# Our open-for-reading of the FIFO will block until the test starts up and
|
|
# opens it for writing. Then our reads will block until the test finishes
|
|
# writing out info and closes the FIFO. At that point we will have
|
|
# collected (and evaluated) what it emitted. It sets these variables:
|
|
# timeout=%u
|
|
# timeoutfactor=%u
|
|
# exit=%u
|
|
# signal=%s
|
|
unset exit signal
|
|
. "$test_fifo" 2> /dev/null
|
|
|
|
# If we got this far, either the 'no_skeleton=true' watchdog already
|
|
# fired, or else we don't want it to.
|
|
trap '' USR1
|
|
|
|
if $no_skeleton; then
|
|
# We hit the timeout, so we didn't get full information about test
|
|
# expectations. Reset any partial results we may have gotten.
|
|
unset exit signal
|
|
else
|
|
# Now we know the expected timeout, so we can start the timer running.
|
|
((sleep_time = timeout * timeoutfactor * emulator_factor))
|
|
|
|
# Now start a background subshell to enforce the timeout.
|
|
(sleep "$sleep_time"; kill -ALRM $test_pid) 2> /dev/null &
|
|
fi
|
|
|
|
# This corresponds to '#ifdef EXPECTED_STATUS' in test-skeleton.c.
|
|
expected_status()
|
|
{
|
|
test "${exit+yes}" = yes
|
|
}
|
|
# This corresponds to '#ifdef EXPECTED_SIGNAL' in test-skeleton.c.
|
|
expected_signal()
|
|
{
|
|
test "${signal+yes}" = yes
|
|
}
|
|
# This corresponds to 'if (WIFEXITED (status))' in test-skeleton.c.
|
|
wifexited()
|
|
{
|
|
test $test_rc -lt 128
|
|
}
|
|
|
|
# Now wait for the test process to finish.
|
|
wait $test_pid
|
|
test_rc=$?
|
|
|
|
# This exactly duplicates the logic in test-skeleton.c.
|
|
if wifexited; then
|
|
if ! expected_status; then
|
|
if ! expected_signal; then
|
|
# Simply exit with the return value of the test. */
|
|
exit $test_rc
|
|
else
|
|
echo "Expected signal '${signal}' from child, got none"
|
|
exit 1
|
|
fi
|
|
else
|
|
if [ $test_rc -ne $exit ]; then
|
|
echo "Expected status $exit, got $test_rc"
|
|
exit 1
|
|
fi
|
|
exit 0
|
|
fi
|
|
else
|
|
# Process was killed by timer or other signal.
|
|
((test_signal = test_rc > 192 ? 256 - test_rc : test_rc - 128 ))
|
|
test_signame=$(kill -l "$test_signal")
|
|
if ! expected_signal; then
|
|
echo "Didn't expect signal from child; got '${test_signame}'"
|
|
exit 1
|
|
else
|
|
if [ "$test_signame" != "$signal" ]; then
|
|
echo "\
|
|
Incorrect signal from child: got '${test_signame}', need '${signal}'"
|
|
exit 1
|
|
fi
|
|
exit 0
|
|
fi
|
|
fi
|