run.sh (18910B)
1 #!/usr/bin/env bash 2 # test/link/elf-dso-aa64/run.sh — ELF shared-library harness, aarch64 target. 3 # 4 # Kit lanes: kit cc compiles PIC objects, kit ld links DSOs, kit cc links the 5 # consumers, then readelf and podman verify the result. Lane B links a produced 6 # DSO against libc.so so the loader must resolve a dependency of a dependency. 7 # 8 # Prerequisites (checked at runtime; missing prereqs produce SKIP, not FAIL): 9 # build/kit — built kit binary 10 # readelf — llvm-readelf or GNU readelf (structural checks) 11 # podman — for runtime execution inside an aarch64 container 12 # images: alpine (musl) and/or debian:bookworm-slim (glibc) 13 # 14 # Usage: 15 # bash test/link/elf-dso-aa64/run.sh # all structural + runtime 16 # KIT_TEST_ALLOW_SKIP=1 bash ... # allow skips (CI-friendly) 17 # 18 # Output: structured pass/fail via kit_sh_report.sh; exit 0 = all pass. 19 20 set -u 21 22 ROOT="$(cd "$(dirname "$0")/../../.." && pwd)" 23 BUILD_DIR="$ROOT/build/test/link/elf-dso-aa64" 24 mkdir -p "$BUILD_DIR" 25 26 KIT_KIT_DIR="$ROOT/test/lib" 27 . "$ROOT/test/lib/kit_sh_kit.sh" 28 kit_report_init 29 30 KIT_SKIP_IS_FAILURE="${KIT_SKIP_IS_FAILURE:-0}" 31 32 KIT="$ROOT/build/kit" 33 KIT_TARGET="-target aarch64-linux" 34 work="$BUILD_DIR" 35 36 # ---- tool detection ----------------------------------------------------------- 37 38 have_readelf=0 39 READELF_BIN="" 40 if command -v llvm-readelf >/dev/null 2>&1; then 41 READELF_BIN="$(command -v llvm-readelf)"; have_readelf=1 42 elif command -v readelf >/dev/null 2>&1; then 43 READELF_BIN="$(command -v readelf)"; have_readelf=1 44 fi 45 46 # exec_target.sh requirements 47 have_qemu=0 48 QEMU_BIN="" 49 have_podman=0 50 is_aarch64=0 51 arch_raw="$(uname -m 2>/dev/null || true)" 52 { [ "$arch_raw" = "aarch64" ] || [ "$arch_raw" = "arm64" ]; } && is_aarch64=1 53 command -v podman >/dev/null 2>&1 && have_podman=1 54 55 EXEC_TARGET_MOUNT_ROOT="$BUILD_DIR" 56 export have_qemu QEMU_BIN have_podman is_aarch64 EXEC_TARGET_MOUNT_ROOT 57 58 # shellcheck source=../../lib/exec_target.sh 59 . "$ROOT/test/lib/exec_target.sh" 60 61 # ---- exec_dso_podman ---------------------------------------------------------- 62 # Like exec_target_run but podman-only. Dynamically linked DSO consumers need a 63 # full OS environment (dynamic linker + libc); qemu-user alone cannot satisfy 64 # that without a sysroot. Both files (libfoo.so + consumer) must live in the 65 # same directory; the consumer's RPATH $ORIGIN then resolves to /work inside the 66 # container (exec_target_run mounts the directory as /work). 67 # 68 # Sets RUN_RC to the container exit code, or 127 when podman is unavailable / 69 # the image is not provisioned. 70 exec_dso_podman() { 71 local tag="$1" exe="$2" out="$3" err="$4" 72 RUN_RC=127 73 [ "${have_podman:-0}" -eq 1 ] || return 0 74 _exec_target_image_present "$tag" || return 0 75 local dir base platform image platform_flag=() 76 dir="$(cd "$(dirname "$exe")" && pwd)" 77 base="$(basename "$exe")" 78 platform="$(_exec_target_platform "$tag")" 79 image="$(_exec_target_image "$tag")" 80 if ! _exec_target_podman_native "$tag"; then 81 platform_flag=(--platform "$platform") 82 fi 83 # Mount the directory as /work so both the consumer and libfoo.so are 84 # accessible at the same relative paths ($ORIGIN expands to /work). 85 podman run --rm --pull=never \ 86 ${platform_flag[@]+"${platform_flag[@]}"} \ 87 --net=none \ 88 -v "$dir":/work:Z -w /work \ 89 "$image" "./$base" \ 90 >"$out" 2>"$err" 91 RUN_RC=$? 92 } 93 94 # ---- kit shared-library path ------------------------------------------------- 95 # 96 # Structural checks (require build/kit + readelf): 97 # A/build-lib compile lib_foo.c -fPIC and link libfoo.so 98 # A/header-dyn ET_DYN, e_entry = 0 99 # A/no-interp no PT_INTERP in program headers 100 # A/has-dynamic PT_DYNAMIC present 101 # A/soname DT_SONAME = libfoo.so 102 # A/export-foo-add foo_add in .dynsym as GLOBAL defined 103 # A/export-foo-ctr foo_counter in .dynsym as GLOBAL defined 104 # A/export-foo-get foo_get_counter in .dynsym as GLOBAL defined 105 # A/hidden-absent foo_hidden NOT in .dynsym as a GLOBAL defined symbol 106 # A/import-bar bar_external in .dynsym as UND 107 # 108 # Runtime checks (require podman + provisioned image; SKIP if unavailable): 109 # A/run-musl consumer-musl exits 0 inside alpine (musl) container 110 # A/run-glibc consumer-glibc exits 0 inside debian (glibc) container 111 # 112 # Libc-dependency checks (require extracted aarch64 musl sysroot): 113 # B/build-libc-lib compile lib_foo_libc.c and link libfoo_libc.so with libc.so 114 # B/libc-needed libfoo_libc.so has a libc DT_NEEDED entry 115 # B/import-malloc malloc is UND in libfoo_libc.so .dynsym 116 # B/run-musl consumer-libc-musl exits 0 inside alpine container 117 118 # ---- A: prerequisites -------------------------------------------------------- 119 120 if [ ! -x "$KIT" ]; then 121 skip_test "A" "build/kit unavailable (run: make bin)" 122 kit_summary test-link-dso-aa64; kit_exit 123 fi 124 if [ $have_readelf -eq 0 ]; then 125 skip_test "A" "readelf / llvm-readelf unavailable (needed for structural checks)" 126 kit_summary test-link-dso-aa64; kit_exit 127 fi 128 129 LIBFOO_O="$work/lib_foo.o" 130 LIBFOO_SO="$work/libfoo.so" 131 CONSUMER_O="$work/consumer.o" 132 CONSUMER_MUSL="$work/consumer-musl" 133 CONSUMER_GLIBC="$work/consumer-glibc" 134 LIBFOO_LIBC_O="$work/lib_foo_libc.o" 135 LIBFOO_LIBC_SO="$work/libfoo_libc.so" 136 CONSUMER_LIBC_MUSL="$work/consumer-libc-musl" 137 MUSL_SYSROOT="${KIT_MUSL_SYSROOT:-${XDG_CACHE_HOME:-$HOME/.cache}/kit/sysroots/linux-musl}" 138 139 SRC_DIR="$(cd "$(dirname "$0")" && pwd)" 140 141 # ---- A/build-lib: compile lib_foo.c + link libfoo.so ------------------------- 142 143 if ! "$KIT" cc $KIT_TARGET \ 144 -O1 -fPIC \ 145 -c "$SRC_DIR/lib_foo.c" -o "$LIBFOO_O" \ 146 >"$work/compile-lib.out" 2>"$work/compile-lib.err"; then 147 not_ok "A/build-lib" "$work/compile-lib.err" 148 kit_summary test-link-dso-aa64; kit_exit 149 fi 150 151 # bar_external is intentionally unresolved in the DSO; it will appear as UND 152 # in .dynsym and be satisfied at runtime by the consumer. 153 if ! "$KIT" ld \ 154 -shared \ 155 -soname libfoo.so \ 156 "$LIBFOO_O" -o "$LIBFOO_SO" \ 157 >"$work/link-lib.out" 2>"$work/link-lib.err"; then 158 not_ok "A/build-lib" "$work/link-lib.err" 159 kit_summary test-link-dso-aa64; kit_exit 160 fi 161 ok "A/build-lib" 162 163 # ---- A: structural checks on libfoo.so --------------------------------------- 164 165 # Dump ELF header, program headers, dynamic section, and dynamic symbol table 166 # once each into per-check files; all grep/awk checks read those cached files. 167 DUMP_HDR="$work/readelf-hdr.txt" 168 DUMP_PHDR="$work/readelf-phdr.txt" 169 DUMP_DYN="$work/readelf-dyn.txt" 170 DUMP_DYNSYM="$work/readelf-dynsym.txt" 171 172 "$READELF_BIN" -h "$LIBFOO_SO" >"$DUMP_HDR" 2>/dev/null 173 "$READELF_BIN" -l "$LIBFOO_SO" >"$DUMP_PHDR" 2>/dev/null 174 "$READELF_BIN" -d "$LIBFOO_SO" >"$DUMP_DYN" 2>/dev/null 175 "$READELF_BIN" --dyn-syms "$LIBFOO_SO" >"$DUMP_DYNSYM" 2>/dev/null 176 177 # A/header-dyn: ELF type must be DYN, entry address must be 0x0 178 if grep -q "Type:.*DYN" "$DUMP_HDR" && \ 179 grep -qE "Entry point address:\s+0x0\b" "$DUMP_HDR"; then 180 ok "A/header-dyn" 181 else 182 printf 'FAIL: expected Type: DYN and entry 0x0\n' >"$work/A-header-dyn.diag" 183 grep "Type:\|Entry point" "$DUMP_HDR" >>"$work/A-header-dyn.diag" 184 not_ok "A/header-dyn" "$work/A-header-dyn.diag" 185 fi 186 187 # A/no-interp: PT_INTERP must be absent (DSOs are loaded by another program's 188 # interpreter, not their own) 189 if grep -q "INTERP" "$DUMP_PHDR"; then 190 printf 'FAIL: unexpected PT_INTERP in DSO program headers\n' >"$work/A-no-interp.diag" 191 grep "INTERP" "$DUMP_PHDR" >>"$work/A-no-interp.diag" 192 not_ok "A/no-interp" "$work/A-no-interp.diag" 193 else 194 ok "A/no-interp" 195 fi 196 197 # A/has-dynamic: PT_DYNAMIC must be present 198 if grep -q "DYNAMIC" "$DUMP_PHDR"; then 199 ok "A/has-dynamic" 200 else 201 printf 'FAIL: PT_DYNAMIC absent from DSO program headers\n' >"$work/A-has-dynamic.diag" 202 cat "$DUMP_PHDR" >>"$work/A-has-dynamic.diag" 203 not_ok "A/has-dynamic" "$work/A-has-dynamic.diag" 204 fi 205 206 # A/soname: DT_SONAME must be present and match libfoo.so 207 if grep -q "(SONAME)" "$DUMP_DYN" && grep -q "libfoo.so" "$DUMP_DYN"; then 208 ok "A/soname" 209 else 210 printf 'FAIL: DT_SONAME absent or wrong\n' >"$work/A-soname.diag" 211 grep "SONAME\|soname\|libfoo" "$DUMP_DYN" >>"$work/A-soname.diag" 212 not_ok "A/soname" "$work/A-soname.diag" 213 fi 214 215 # A/export-foo-add: foo_add must be in .dynsym as a GLOBAL defined symbol 216 if grep -q "GLOBAL\|WEAK" "$DUMP_DYNSYM" && grep "foo_add" "$DUMP_DYNSYM" | grep -qv "UND"; then 217 ok "A/export-foo-add" 218 else 219 printf 'FAIL: foo_add not exported in .dynsym\n' >"$work/A-export-foo-add.diag" 220 grep "foo_add" "$DUMP_DYNSYM" >>"$work/A-export-foo-add.diag" || true 221 not_ok "A/export-foo-add" "$work/A-export-foo-add.diag" 222 fi 223 224 # A/export-foo-ctr: foo_counter must be in .dynsym as a GLOBAL defined symbol 225 if grep "foo_counter" "$DUMP_DYNSYM" | grep -qv "UND"; then 226 ok "A/export-foo-ctr" 227 else 228 printf 'FAIL: foo_counter not exported in .dynsym\n' >"$work/A-export-foo-ctr.diag" 229 grep "foo_counter" "$DUMP_DYNSYM" >>"$work/A-export-foo-ctr.diag" || true 230 not_ok "A/export-foo-ctr" "$work/A-export-foo-ctr.diag" 231 fi 232 233 # A/export-foo-get: foo_get_counter must be in .dynsym as a GLOBAL defined symbol 234 if grep "foo_get_counter" "$DUMP_DYNSYM" | grep -qv "UND"; then 235 ok "A/export-foo-get" 236 else 237 printf 'FAIL: foo_get_counter not exported in .dynsym\n' >"$work/A-export-foo-get.diag" 238 grep "foo_get_counter" "$DUMP_DYNSYM" >>"$work/A-export-foo-get.diag" || true 239 not_ok "A/export-foo-get" "$work/A-export-foo-get.diag" 240 fi 241 242 # A/hidden-absent: foo_hidden must NOT appear as a GLOBAL/WEAK defined symbol 243 # in .dynsym. Hidden symbols stay in .symtab only; they must not be preemptible. 244 # If it appears at all in .dynsym it must be STV_HIDDEN (Vis == HIDDEN) and not 245 # GLOBAL-or-WEAK DEFAULT, so check that no GLOBAL DEFAULT line mentions it. 246 if grep "foo_hidden" "$DUMP_DYNSYM" | grep -q "GLOBAL.*DEFAULT.*[0-9]"; then 247 printf 'FAIL: foo_hidden appears as GLOBAL DEFAULT in .dynsym\n' >"$work/A-hidden-absent.diag" 248 grep "foo_hidden" "$DUMP_DYNSYM" >>"$work/A-hidden-absent.diag" 249 not_ok "A/hidden-absent" "$work/A-hidden-absent.diag" 250 else 251 ok "A/hidden-absent" 252 fi 253 254 # A/import-bar: bar_external must be in .dynsym as UND (undefined import) 255 if grep "bar_external" "$DUMP_DYNSYM" | grep -q "UND"; then 256 ok "A/import-bar" 257 else 258 printf 'FAIL: bar_external not in .dynsym as UND\n' >"$work/A-import-bar.diag" 259 grep "bar_external" "$DUMP_DYNSYM" >>"$work/A-import-bar.diag" || true 260 not_ok "A/import-bar" "$work/A-import-bar.diag" 261 fi 262 263 # ---- A: build consumers for runtime execution -------------------------------- 264 # Two variants, one per libc ABI, so each can run in its matching container. 265 # Both are freestanding (no libc calls, no sysroot required at compile time). 266 # --export-dynamic exports bar_external to the executable's .dynsym so that 267 # libfoo.so's dynamic reference to it is resolved by the loader at startup. 268 269 # Musl interpreter (alpine linux/arm64) 270 MUSL_INTERP="/lib/ld-musl-aarch64.so.1" 271 if ! "$KIT" cc $KIT_TARGET \ 272 -O1 -ffreestanding \ 273 -nostdlib -rdynamic \ 274 -e _start \ 275 -Wl,-dynamic-linker,"$MUSL_INTERP" \ 276 -Wl,-rpath,\$ORIGIN \ 277 "$SRC_DIR/consumer.c" \ 278 -L"$work" -lfoo \ 279 -o "$CONSUMER_MUSL" \ 280 >"$work/build-consumer-musl.out" 2>"$work/build-consumer-musl.err"; then 281 skip_test "A/run-musl" "consumer-musl build failed; see $work/build-consumer-musl.err" 282 have_consumer_musl=0 283 else 284 have_consumer_musl=1 285 fi 286 287 # Glibc interpreter (debian:bookworm-slim linux/arm64) 288 GLIBC_INTERP="/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1" 289 if ! "$KIT" cc $KIT_TARGET \ 290 -O1 -ffreestanding \ 291 -nostdlib -rdynamic \ 292 -e _start \ 293 -Wl,-dynamic-linker,"$GLIBC_INTERP" \ 294 -Wl,-rpath,\$ORIGIN \ 295 "$SRC_DIR/consumer.c" \ 296 -L"$work" -lfoo \ 297 -o "$CONSUMER_GLIBC" \ 298 >"$work/build-consumer-glibc.out" 2>"$work/build-consumer-glibc.err"; then 299 skip_test "A/run-glibc" "consumer-glibc build failed; see $work/build-consumer-glibc.err" 300 have_consumer_glibc=0 301 else 302 have_consumer_glibc=1 303 fi 304 305 # ---- A: check consumer DT_NEEDED and RPATH (structural, glibc variant) ------- 306 # Only if the glibc consumer built successfully. The musl and glibc consumers 307 # have identical dynamic metadata (same NEEDED/RPATH) — check once. 308 if [ $have_consumer_glibc -eq 1 ]; then 309 DUMP_CON_DYN="$work/readelf-consumer-dyn.txt" 310 "$READELF_BIN" -d "$CONSUMER_GLIBC" >"$DUMP_CON_DYN" 2>/dev/null 311 312 # DT_NEEDED must reference libfoo.so (matching the soname we embedded) 313 if grep -q "(NEEDED)" "$DUMP_CON_DYN" && grep "(NEEDED)" "$DUMP_CON_DYN" | grep -q "libfoo.so"; then 314 ok "A/consumer-needed" 315 else 316 printf 'FAIL: consumer missing DT_NEEDED libfoo.so\n' >"$work/A-consumer-needed.diag" 317 grep "NEEDED\|libfoo" "$DUMP_CON_DYN" >>"$work/A-consumer-needed.diag" || true 318 not_ok "A/consumer-needed" "$work/A-consumer-needed.diag" 319 fi 320 321 # RPATH or RUNPATH must contain $ORIGIN 322 if grep -E "(RPATH|RUNPATH)" "$DUMP_CON_DYN" | grep -q 'ORIGIN'; then 323 ok "A/consumer-rpath" 324 else 325 printf 'FAIL: consumer missing RPATH/RUNPATH with \$ORIGIN\n' >"$work/A-consumer-rpath.diag" 326 grep -E "RPATH|RUNPATH" "$DUMP_CON_DYN" >>"$work/A-consumer-rpath.diag" || true 327 not_ok "A/consumer-rpath" "$work/A-consumer-rpath.diag" 328 fi 329 fi 330 331 # ---- A/run-musl: runtime execution in alpine (musl) container ---------------- 332 if [ $have_consumer_musl -eq 1 ]; then 333 if [ "${have_podman:-0}" -ne 1 ]; then 334 skip_test "A/run-musl" "podman unavailable" 335 elif ! _exec_target_image_present "aarch64-linux"; then 336 skip_test "A/run-musl" "aarch64 musl image not provisioned (run: make test-images)" 337 else 338 exec_dso_podman "aarch64-linux" "$CONSUMER_MUSL" \ 339 "$work/run-musl.out" "$work/run-musl.err" 340 if [ "$RUN_RC" -eq 0 ]; then 341 ok "A/run-musl" 342 else 343 printf 'consumer-musl exited %d\n' "$RUN_RC" >"$work/A-run-musl.diag" 344 [ -s "$work/run-musl.err" ] && sed 's/^/ | /' "$work/run-musl.err" >>"$work/A-run-musl.diag" 345 not_ok "A/run-musl" "$work/A-run-musl.diag" 346 fi 347 fi 348 fi 349 350 # ---- A/run-glibc: runtime execution in debian (glibc) container -------------- 351 if [ $have_consumer_glibc -eq 1 ]; then 352 if [ "${have_podman:-0}" -ne 1 ]; then 353 skip_test "A/run-glibc" "podman unavailable" 354 elif ! _exec_target_image_present "aarch64-linux-glibc"; then 355 skip_test "A/run-glibc" "aarch64 glibc image not provisioned (run: make test-images)" 356 else 357 exec_dso_podman "aarch64-linux-glibc" "$CONSUMER_GLIBC" \ 358 "$work/run-glibc.out" "$work/run-glibc.err" 359 if [ "$RUN_RC" -eq 0 ]; then 360 ok "A/run-glibc" 361 else 362 printf 'consumer-glibc exited %d\n' "$RUN_RC" >"$work/A-run-glibc.diag" 363 [ -s "$work/run-glibc.err" ] && sed 's/^/ | /' "$work/run-glibc.err" >>"$work/A-run-glibc.diag" 364 not_ok "A/run-glibc" "$work/A-run-glibc.diag" 365 fi 366 fi 367 fi 368 369 # ---- B: produced DSO depends on libc.so -------------------------------------- 370 # This lane links the shared object itself against the extracted aarch64 musl 371 # libc.so. The consumer only names libfoo_libc.so; libc is pulled transitively 372 # from libfoo_libc.so's DT_NEEDED entry at runtime. 373 374 have_libc_lane=0 375 if [ ! -f "$MUSL_SYSROOT/usr/lib/libc.so" ]; then 376 skip_test "B" "aarch64 musl sysroot unavailable (run: make test-libc-musl, or set KIT_MUSL_SYSROOT)" 377 else 378 if ! "$KIT" cc $KIT_TARGET \ 379 -O1 -fPIC \ 380 -c "$SRC_DIR/lib_foo_libc.c" -o "$LIBFOO_LIBC_O" \ 381 >"$work/compile-libc-lib.out" 2>"$work/compile-libc-lib.err"; then 382 not_ok "B/build-libc-lib" "$work/compile-libc-lib.err" 383 elif ! "$KIT" ld \ 384 -shared \ 385 -soname libfoo_libc.so \ 386 "$LIBFOO_LIBC_O" "$MUSL_SYSROOT/usr/lib/libc.so" \ 387 -o "$LIBFOO_LIBC_SO" \ 388 >"$work/link-libc-lib.out" 2>"$work/link-libc-lib.err"; then 389 not_ok "B/build-libc-lib" "$work/link-libc-lib.err" 390 else 391 ok "B/build-libc-lib" 392 have_libc_lane=1 393 fi 394 fi 395 396 if [ $have_libc_lane -eq 1 ]; then 397 DUMP_LIBC_DYN="$work/readelf-libc-dyn.txt" 398 DUMP_LIBC_DYNSYM="$work/readelf-libc-dynsym.txt" 399 "$READELF_BIN" -d "$LIBFOO_LIBC_SO" >"$DUMP_LIBC_DYN" 2>/dev/null 400 "$READELF_BIN" --dyn-syms "$LIBFOO_LIBC_SO" >"$DUMP_LIBC_DYNSYM" 2>/dev/null 401 402 if grep -q "(NEEDED)" "$DUMP_LIBC_DYN" && grep "(NEEDED)" "$DUMP_LIBC_DYN" | grep -q "libc"; then 403 ok "B/libc-needed" 404 else 405 printf 'FAIL: produced DSO missing a libc DT_NEEDED entry\n' >"$work/B-libc-needed.diag" 406 grep "NEEDED\|libc" "$DUMP_LIBC_DYN" >>"$work/B-libc-needed.diag" || true 407 not_ok "B/libc-needed" "$work/B-libc-needed.diag" 408 fi 409 410 if grep "malloc" "$DUMP_LIBC_DYNSYM" | grep -q "UND"; then 411 ok "B/import-malloc" 412 else 413 printf 'FAIL: malloc not in libfoo_libc.so .dynsym as UND\n' >"$work/B-import-malloc.diag" 414 grep "malloc" "$DUMP_LIBC_DYNSYM" >>"$work/B-import-malloc.diag" || true 415 not_ok "B/import-malloc" "$work/B-import-malloc.diag" 416 fi 417 418 if ! "$KIT" cc $KIT_TARGET \ 419 -O1 -ffreestanding \ 420 -nostdlib -rdynamic \ 421 -e _start \ 422 -Wl,-dynamic-linker,"$MUSL_INTERP" \ 423 -Wl,-rpath,\$ORIGIN \ 424 "$SRC_DIR/consumer.c" \ 425 -L"$work" -lfoo_libc \ 426 -o "$CONSUMER_LIBC_MUSL" \ 427 >"$work/build-consumer-libc-musl.out" 2>"$work/build-consumer-libc-musl.err"; then 428 skip_test "B/run-musl" "consumer-libc-musl build failed; see $work/build-consumer-libc-musl.err" 429 have_consumer_libc_musl=0 430 else 431 have_consumer_libc_musl=1 432 fi 433 434 if [ $have_consumer_libc_musl -eq 1 ]; then 435 if [ "${have_podman:-0}" -ne 1 ]; then 436 skip_test "B/run-musl" "podman unavailable" 437 elif ! _exec_target_image_present "aarch64-linux"; then 438 skip_test "B/run-musl" "aarch64 musl image not provisioned (run: make test-images)" 439 else 440 exec_dso_podman "aarch64-linux" "$CONSUMER_LIBC_MUSL" \ 441 "$work/run-libc-musl.out" "$work/run-libc-musl.err" 442 if [ "$RUN_RC" -eq 0 ]; then 443 ok "B/run-musl" 444 else 445 printf 'consumer-libc-musl exited %d\n' "$RUN_RC" >"$work/B-run-musl.diag" 446 [ -s "$work/run-libc-musl.err" ] && sed 's/^/ | /' "$work/run-libc-musl.err" >>"$work/B-run-musl.diag" 447 not_ok "B/run-musl" "$work/B-run-musl.diag" 448 fi 449 fi 450 fi 451 fi 452 453 # ---- summary ----------------------------------------------------------------- 454 kit_summary test-link-dso-aa64 455 kit_exit