run.sh (7825B)
1 #!/usr/bin/env bash 2 # FreeBSD hosted-link smoke (static and/or dynamic). 3 # 4 # Cross-compiles a tiny libc program with kit for all three supported FreeBSD 5 # targets and validates the linked ELF. Sysroots come from 6 # scripts/freebsd_sysroot.sh (cached base.txz extracts under ~/.cache/kit). 7 # 8 # KIT_FREEBSD_LINK=static|dynamic|both which lane(s) to build (default: both) 9 # KIT_FREEBSD_RUN_VM=1 also boot the cached FreeBSD VMs and 10 # execute each binary under real FreeBSD 11 # KIT_FREEBSD_ARCHES="amd64 aarch64 riscv64" restrict the arch set 12 # 13 # The default lane validates ELF metadata only; the VM lane is the real 14 # end-to-end check (program prints "freebsd <mode>" and exits 7). 15 16 set -u 17 18 ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" 19 KIT="${KIT:-$ROOT/build/kit}" 20 BUILD_DIR="${KIT_FREEBSD_BUILD_DIR:-$ROOT/build/freebsd-link}" 21 ARCHES="${KIT_FREEBSD_ARCHES:-amd64 aarch64 riscv64}" 22 RUN_VM="${KIT_FREEBSD_RUN_VM:-0}" 23 LINK="${KIT_FREEBSD_LINK:-both}" 24 25 . "$ROOT/test/lib/kit_sh_report.sh" 26 27 mkdir -p "$BUILD_DIR" 28 29 if [ ! -x "$KIT" ]; then 30 echo "kit driver missing at $KIT -- run 'make bin' first" >&2 31 exit 2 32 fi 33 34 READELF="$(command -v llvm-readelf 2>/dev/null || command -v readelf 2>/dev/null || true)" 35 if [ -z "$READELF" ]; then 36 echo "llvm-readelf/readelf missing" >&2 37 exit 2 38 fi 39 40 case "$LINK" in 41 static) MODES="static" ;; 42 dynamic) MODES="dynamic" ;; 43 both) MODES="static dynamic" ;; 44 *) echo "KIT_FREEBSD_LINK must be static|dynamic|both (got '$LINK')" >&2; exit 2 ;; 45 esac 46 47 arch_target() { 48 case "$1" in 49 amd64) echo "x86_64-freebsd" ;; 50 aarch64) echo "aarch64-freebsd" ;; 51 riscv64) echo "riscv64-freebsd" ;; 52 *) echo "" ;; 53 esac 54 } 55 56 arch_sysroot() { 57 case "$1" in 58 amd64) [ -n "${KIT_FREEBSD_AMD64_SYSROOT:-}" ] && { echo "$KIT_FREEBSD_AMD64_SYSROOT"; return; } ;; 59 aarch64) [ -n "${KIT_FREEBSD_AARCH64_SYSROOT:-}" ] && { echo "$KIT_FREEBSD_AARCH64_SYSROOT"; return; } ;; 60 riscv64) [ -n "${KIT_FREEBSD_RISCV64_SYSROOT:-}" ] && { echo "$KIT_FREEBSD_RISCV64_SYSROOT"; return; } ;; 61 esac 62 if [ -x "$ROOT/scripts/freebsd_sysroot.sh" ]; then 63 "$ROOT/scripts/freebsd_sysroot.sh" path "$1" 64 else 65 echo "$ROOT/build/freebsd-sysroot/$1" 66 fi 67 } 68 69 exe_path() { echo "$BUILD_DIR/$2-$1"; } # <arch> <mode> 70 71 # compile_arch <arch> <mode> 72 compile_arch() { 73 local arch="$1" mode="$2" target sysroot exe log meta 74 target="$(arch_target "$arch")" 75 sysroot="$(arch_sysroot "$arch")" 76 exe="$(exe_path "$arch" "$mode")" 77 log="$BUILD_DIR/cc-$mode-$arch.log" 78 meta="$BUILD_DIR/readelf-$mode-$arch.txt" 79 rm -f "$exe" 80 81 if [ -z "$target" ]; then 82 kit_skip_na "$arch/freebsd-$mode" 83 return 1 84 fi 85 if [ ! -d "$sysroot/usr/include" ]; then 86 kit_skip "$arch/freebsd-$mode" "missing sysroot $sysroot (run scripts/freebsd_sysroot.sh $arch)" 87 return 1 88 fi 89 if [ "$mode" = static ] && [ ! -f "$sysroot/usr/lib/libc.a" ]; then 90 kit_skip "$arch/freebsd-$mode" "missing $sysroot/usr/lib/libc.a" 91 return 1 92 fi 93 if [ "$mode" = dynamic ] && [ ! -f "$sysroot/lib/libc.so.7" ]; then 94 kit_skip "$arch/freebsd-$mode" "missing $sysroot/lib/libc.so.7" 95 return 1 96 fi 97 98 local flags=(-target "$target" --sysroot "$sysroot") 99 [ "$mode" = static ] && flags+=(-static) 100 101 if ! printf '#include <stdio.h>\nint main(void){puts("freebsd %s");return 7;}\n' "$mode" | 102 "$KIT" cc "${flags[@]}" -x c - -o "$exe" >"$log" 2>&1; then 103 kit_fail "$arch/freebsd-$mode link" 104 sed 's/^/ cc| /' "$log" | head -20 105 return 1 106 fi 107 108 if ! "$READELF" -h -l -d -r --dyn-symbols "$exe" >"$meta" 2>&1; then 109 kit_fail "$arch/freebsd-$mode readelf" 110 return 1 111 fi 112 113 if ! grep -qi 'OS/ABI:.*FreeBSD' "$meta"; then 114 kit_fail "$arch/freebsd-$mode metadata (OS/ABI not FreeBSD)" 115 sed 's/^/ elf| /' "$meta" | head -20 116 return 1 117 fi 118 if grep -Eq 'R_[A-Z0-9_]+_NONE' "$meta"; then 119 kit_fail "$arch/freebsd-$mode metadata (R_*_NONE reloc)" 120 sed 's/^/ elf| /' "$meta" | head -40 121 return 1 122 fi 123 124 if [ "$mode" = static ]; then 125 if grep -q 'Requesting program interpreter' "$meta"; then 126 kit_fail "$arch/freebsd-static metadata (unexpected PT_INTERP)" 127 return 1 128 fi 129 else 130 if ! grep -q "Requesting program interpreter: /libexec/ld-elf.so.1" "$meta" || 131 ! grep -q "Shared library: \\[libc.so.7\\]" "$meta" || 132 ! grep -q "Shared library: \\[libsys.so.7\\]" "$meta" || 133 ! grep -q "[[:space:]]environ$" "$meta" || 134 ! grep -q "[[:space:]]__progname$" "$meta" || 135 ! grep -q "JUMP_SLOT.*puts" "$meta"; then 136 kit_fail "$arch/freebsd-dynamic metadata" 137 sed 's/^/ elf| /' "$meta" | head -80 138 return 1 139 fi 140 fi 141 142 kit_pass "$arch/freebsd-$mode metadata" 143 return 0 144 } 145 146 shutdown_vm() { 147 local arch="$1" pid_file="$BUILD_DIR/vm-$arch.pid" pid 148 "$ROOT/scripts/freebsd_vm.sh" ssh "$arch" 'sync' >"$BUILD_DIR/shutdown-$arch.log" 2>&1 || true 149 [ -f "$pid_file" ] || return 0 150 pid="$(cat "$pid_file")" 151 for _ in $(seq 1 5); do kill -0 "$pid" 2>/dev/null || return 0; sleep 1; done 152 kill "$pid" 2>/dev/null || true; sleep 1 153 kill -0 "$pid" 2>/dev/null && kill -9 "$pid" 2>/dev/null || true 154 wait "$pid" 2>/dev/null || true 155 } 156 157 # Boot an arch's VM once, run every built mode's binary in it, then shut down. 158 run_vm_arch() { 159 local arch="$1" port pid_file started_vm=0 qemu mode exe out 160 port="$(arch_port "$arch")" 161 pid_file="$BUILD_DIR/vm-$arch.pid" 162 qemu="qemu-system-$(case "$arch" in amd64) echo x86_64 ;; *) echo "$arch" ;; esac)" 163 164 if ! command -v "$qemu" >/dev/null 2>&1; then 165 kit_skip "$arch/freebsd vm" "$qemu missing"; return 166 fi 167 if [ ! -f "$ROOT/build/freebsd-vm/images/freebsd-$arch.provisioned" ]; then 168 kit_skip "$arch/freebsd vm" "FreeBSD VM is not provisioned (scripts/freebsd_vm.sh prepare $arch)"; return 169 fi 170 171 if "$ROOT/scripts/freebsd_vm.sh" ssh "$arch" 'true' >"$BUILD_DIR/reuse-$arch.log" 2>&1; then 172 : # reuse a guest the caller already has running 173 else 174 "$ROOT/scripts/freebsd_vm.sh" run "$arch" >"$BUILD_DIR/vm-$arch.log" 2>&1 & 175 echo "$!" >"$pid_file"; started_vm=1; sleep 2 176 if ! kill -0 "$(cat "$pid_file")" 2>/dev/null; then 177 kit_fail "$arch/freebsd vm start" 178 sed 's/^/ qemu| /' "$BUILD_DIR/vm-$arch.log" | head -20; return 179 fi 180 fi 181 if ! "$ROOT/scripts/freebsd_vm.sh" wait-ssh "$arch" >"$BUILD_DIR/wait-$arch.log" 2>&1; then 182 kit_fail "$arch/freebsd vm wait" 183 sed 's/^/ wait| /' "$BUILD_DIR/wait-$arch.log" | head -20 184 [ "$started_vm" = 1 ] && shutdown_vm "$arch"; return 185 fi 186 187 for mode in $MODES; do 188 exe="$(exe_path "$arch" "$mode")" 189 [ -x "$exe" ] || continue 190 if ! "$ROOT/scripts/freebsd_vm.sh" ssh "$arch" 'cat > /tmp/kit-fb' <"$exe" \ 191 >"$BUILD_DIR/copy-$mode-$arch.log" 2>&1; then 192 kit_fail "$arch/freebsd-$mode vm copy"; continue 193 fi 194 out="$BUILD_DIR/run-$mode-$arch.log" 195 "$ROOT/scripts/freebsd_vm.sh" ssh "$arch" \ 196 'chmod +x /tmp/kit-fb; /tmp/kit-fb; printf "rc=%s\n" "$?"' >"$out" 2>&1 || true 197 if grep -q "^freebsd $mode\$" "$out" && grep -q '^rc=7$' "$out"; then 198 kit_pass "$arch/freebsd-$mode vm" 199 else 200 kit_fail "$arch/freebsd-$mode vm output" 201 sed 's/^/ run| /' "$out" | head -20 202 fi 203 done 204 205 [ "$started_vm" = 1 ] && shutdown_vm "$arch" 206 } 207 208 arch_port() { 209 case "$1" in 210 amd64) echo "${KIT_FREEBSD_AMD64_SSH_PORT:-2222}" ;; 211 aarch64) echo "${KIT_FREEBSD_AARCH64_SSH_PORT:-2223}" ;; 212 riscv64) echo "${KIT_FREEBSD_RISCV64_SSH_PORT:-2224}" ;; 213 *) echo "" ;; 214 esac 215 } 216 217 printf 'test-freebsd link=%s arches=%s run_vm=%s\n' "$LINK" "$ARCHES" "$RUN_VM" 218 219 for arch in $ARCHES; do 220 for mode in $MODES; do 221 compile_arch "$arch" "$mode" 222 done 223 done 224 225 if [ "$RUN_VM" = "1" ]; then 226 for arch in $ARCHES; do 227 run_vm_arch "$arch" 228 done 229 fi 230 231 kit_summary test-freebsd 232 kit_exit