kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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