blob: df5ab40970bdda8f1bfc0d31616ea38798134caf [file] [log] [blame]
xf.libdd93d52023-05-12 07:10:14 -07001#!/bin/bash
2# test-wrapper script for NaCl.
3
4# Copyright (C) 2015-2016 Free Software Foundation, Inc.
5# This file is part of the GNU C Library.
6
7# The GNU C Library is free software; you can redistribute it and/or
8# modify it under the terms of the GNU Lesser General Public
9# License as published by the Free Software Foundation; either
10# version 2.1 of the License, or (at your option) any later version.
11
12# The GNU C Library is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15# Lesser General Public License for more details.
16
17# You should have received a copy of the GNU Lesser General Public
18# License along with the GNU C Library; if not, see
19# <http://www.gnu.org/licenses/>.
20
21progname="$(basename "$0")"
22
23usage="usage: ${progname} --arch=ARCH [VAR=VAL...] COMMAND ..."
24help="
25"
26
27use_bootstrap=true
28arch=
29env=()
30envi=0
31while [ $# -gt 0 ]; do
32 case "$1" in
33
34 --help)
35 echo "$usage"
36 echo "$help"
37 exit 0
38 ;;
39
40 --arch=*)
41 arch="${1#--arch=}"
42 shift
43 ;;
44
45 *=*)
46 env[envi++]='-E'
47 env[envi++]="$1"
48 shift
49 ;;
50
51 --)
52 shift
53 break
54 ;;
55
56 *)
57 break
58 ;;
59 esac
60done
61
62if [ $# -lt 1 -o -z "$arch" ]; then
63 echo "$usage" >&2
64 echo "Type '${progname} --help' for more detailed help." >&2
65 exit 1
66fi
67
68test_args=("$@")
69
70if [ -z "$NACL_SDK_ROOT" ]; then
71 echo >&2 "$0: NACL_SDK_ROOT must be set in the environment"
72 exit 77
73fi
74
75# We use a handful of things from the NaCl SDK, or at least
76# from a directory matching the layout of the NaCl SDK.
77sdk_tools="${NACL_SDK_ROOT}/tools"
78
79NACL_BOOTSTRAP="${sdk_tools}/nacl_helper_bootstrap_${arch}"
80NACL_SEL_LDR="${sdk_tools}/sel_ldr_${arch}"
81NACL_IRT="${sdk_tools}/irt_core_${arch}.nexe"
82NACL_LOADER="${sdk_tools}/elf_loader_${arch}.nexe"
83
84if [ ! -x "$NACL_BOOTSTRAP" -o ! -x "$NACL_SEL_LDR" ]; then
85 echo >&2 "$0: sel_ldr_${arch} and/or nacl_helper_bootstrap_${arch} missing"
86 echo >&2 "$0: from directory $sdk_tools"
87 exit 77
88fi
89
90if [ ! -r "$NACL_IRT" -o ! -r "$NACL_LOADER" ]; then
91 echo >&2 "$0: irt_core_${arch}.nexe and/or loader_${arch}.nexe missing"
92 echo >&2 "$0: from directory $sdk_tools"
93 exit 77
94fi
95
96# Figure out if we are building for the native machine or not.
97# If not, we'll run sel_ldr under qemu.
98decide_use_emulator()
99{
100 local arg
101 for arg; do
102 if [[ "$(uname -m)" = "$1" ]]; then
103 return
104 fi
105 done
106 use_emulator=true
107}
108
109use_emulator=false
110case "$arch" in
111arm)
112 decide_use_emulator 'arm*'
113 emulator=(qemu-arm -cpu cortex-a15 -L "${sdk_tools}/arm_trusted")
114 ;;
115x86_32)
116 decide_use_emulator 'i?86' 'x86_64*'
117 emulator=(qemu-i386)
118 ;;
119x86_64)
120 decide_use_emulator 'x86_64*'
121 emulator=(qemu-x86_64)
122 ;;
123esac
124
125if $use_emulator; then
126 ldr_args=('-Q')
127 emulator_factor=10
128else
129 emulator=()
130 ldr_args=()
131 emulator_factor=1
132fi
133
134if $use_bootstrap; then
135 ldr=(
136 "${NACL_BOOTSTRAP}"
137 "${NACL_SEL_LDR}"
138 '--r_debug=0xXXXXXXXXXXXXXXXX'
139 '--reserved_at_zero=0xXXXXXXXXXXXXXXXX'
140 )
141else
142 ldr=("${NACL_SEL_LDR}")
143fi
144
145static=true
146case "$1" in
147*/ld-nacl*) static=false ;;
148esac
149
150if $static; then
151 loader=()
152else
153 loader=(-f "${NACL_LOADER}")
154fi
155
156run_test()
157{
158 local test_fifo="$1"
159 local cmd=(
160 "${emulator[@]}" "${ldr[@]}" -q -S -a "${ldr_args[@]}" -B "${NACL_IRT}"
161 "${loader[@]}" "${env[@]}" -E TEST_DIRECT="$test_fifo" -- "${test_args[@]}"
162 )
163 if [ "${NACLVERBOSITY:+set}" = set ]; then
164 "${cmd[@]}"
165 else
166 NACLLOG=/dev/null "${cmd[@]}"
167 fi
168}
169
170temp_files=()
171test_fifo=
172do_cleanup()
173{
174 rm -rf "$test_fifo" "${temp_files[@]}"
175}
176trap do_cleanup EXIT HUP INT TERM
177
178# Create a named pipe to receive the TEST_DIRECT information from the test
179# program.
180test_fifo=${TMPDIR:-/tmp}/libc-test-fifo.$$
181rm -f "$test_fifo"
182mkfifo "$test_fifo" || {
183 echo "Cannot create test FIFO '$test_fifo'"
184 exit 1
185}
186
187# Run the test in the background, so we can implement a timeout.
188# The no-op redirection defeats the default behavior of "< /dev/null"
189# for a background command.
190run_test "$test_fifo" <&0 & test_pid=$!
191
192# Set up a short timeout before we read from the FIFO, in case
193# the program doesn't actually write to the FIFO at all (it is
194# not a test-skeleton.c program, or it dies very early).
195no_skeleton=false
196script_pid=$$
197trap 'no_skeleton=true' USR1
198(sleep 2; kill -USR1 $script_pid) 2> /dev/null &
199
200# The test should first write into the FIFO to describe its expectations.
201# Our open-for-reading of the FIFO will block until the test starts up and
202# opens it for writing. Then our reads will block until the test finishes
203# writing out info and closes the FIFO. At that point we will have
204# collected (and evaluated) what it emitted. It sets these variables:
205# timeout=%u
206# timeoutfactor=%u
207# exit=%u
208# signal=%s
209unset exit signal
210. "$test_fifo" 2> /dev/null
211
212# If we got this far, either the 'no_skeleton=true' watchdog already
213# fired, or else we don't want it to.
214trap '' USR1
215
216if $no_skeleton; then
217 # We hit the timeout, so we didn't get full information about test
218 # expectations. Reset any partial results we may have gotten.
219 unset exit signal
220else
221 # Now we know the expected timeout, so we can start the timer running.
222 ((sleep_time = timeout * timeoutfactor * emulator_factor))
223
224 # Now start a background subshell to enforce the timeout.
225 (sleep "$sleep_time"; kill -ALRM $test_pid) 2> /dev/null &
226fi
227
228# This corresponds to '#ifdef EXPECTED_STATUS' in test-skeleton.c.
229expected_status()
230{
231 test "${exit+yes}" = yes
232}
233# This corresponds to '#ifdef EXPECTED_SIGNAL' in test-skeleton.c.
234expected_signal()
235{
236 test "${signal+yes}" = yes
237}
238# This corresponds to 'if (WIFEXITED (status))' in test-skeleton.c.
239wifexited()
240{
241 test $test_rc -lt 128
242}
243
244# Now wait for the test process to finish.
245wait $test_pid
246test_rc=$?
247
248# This exactly duplicates the logic in test-skeleton.c.
249if wifexited; then
250 if ! expected_status; then
251 if ! expected_signal; then
252 # Simply exit with the return value of the test. */
253 exit $test_rc
254 else
255 echo "Expected signal '${signal}' from child, got none"
256 exit 1
257 fi
258 else
259 if [ $test_rc -ne $exit ]; then
260 echo "Expected status $exit, got $test_rc"
261 exit 1
262 fi
263 exit 0
264 fi
265else
266 # Process was killed by timer or other signal.
267 ((test_signal = test_rc > 192 ? 256 - test_rc : test_rc - 128 ))
268 test_signame=$(kill -l "$test_signal")
269 if ! expected_signal; then
270 echo "Didn't expect signal from child; got '${test_signame}'"
271 exit 1
272 else
273 if [ "$test_signame" != "$signal" ]; then
274 echo "\
275Incorrect signal from child: got '${test_signame}', need '${signal}'"
276 exit 1
277 fi
278 exit 0
279 fi
280fi