Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .ci/check-matrix-lists.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env bash

# Keep the test-matrix skip lists honest.
#
# tests/test-matrix.sh runs each test under two runners and carries a skip list
# per runner: QEMU_SKIP for tests the reference kernel cannot adjudicate,
# ELFUSE_SKIP for tests that need a writable byte-exact root the elfuse lane
# does not have. Both lists are matched against a test's label by string, and a
# string that matches nothing fails silently: the suite still reports success,
# having run one test fewer than the reader believes.
#
# Two ways that goes wrong, both of which cost coverage without costing a red
# build, and neither of which the suite itself can notice:
#
# 1. A label in a skip list that no longer names a registered test. Dead
# config: it reads as deliberate coverage policy while guarding nothing,
# and it hides the rename that orphaned it.
# 2. A label in both lists at once. The test is then skipped under every
# runner the matrix has, so it never executes anywhere while still looking
# registered.
#
# The pass counts themselves are not checked here. test-matrix.sh already holds
# each lane to its EXPECTED_BASELINES floor at runtime, which is a stronger
# check than anything static, and duplicating it would only add a second number
# to keep in step.

set -e -u -o pipefail

MATRIX="${1:-$(dirname "$0")/../tests/test-matrix.sh}"

if [ ! -r "$MATRIX" ]; then
echo "check-matrix-lists: cannot read $MATRIX" >&2
exit 2
fi

# Body of a NAME="..." block spanning lines, one entry per line.
list_entries()
{
sed -n "/^$1=\"/,/^\"\$/p" "$MATRIX" | sed '1d;$d' | tr -s ' \t' '\n' \
| grep -v '^$' || true
}

# Labels registered with the test_* wrappers: the argument after "$runner".
registered_labels()
{
grep -oE '\btest_(check|rc|pipe) +"\$runner" +"[^"]+"' "$MATRIX" \
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
| sed -E 's/.*"\$runner" +"([^"]+)"$/\1/' | sort -u
}

ret=0
registered="$(registered_labels)"

for list in QEMU_SKIP ELFUSE_SKIP; do
while IFS= read -r label; do
[ -n "$label" ] || continue
if ! printf '%s\n' "$registered" | grep -qxF "$label"; then
echo "Error: $list names '$label', which no test_* call registers" >&2
ret=1
fi
done < <(list_entries "$list")
done

while IFS= read -r label; do
[ -n "$label" ] || continue
if list_entries QEMU_SKIP | grep -qxF "$label"; then
echo "Error: '$label' is in both QEMU_SKIP and ELFUSE_SKIP, so it never runs" >&2
ret=1
fi
done < <(list_entries ELFUSE_SKIP)

exit $ret
31 changes: 30 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ SRCS := \
syscall/mem.c \
syscall/path.c \
syscall/fuse.c \
syscall/sidecar.c \
syscall/casefold.c \
syscall/casefold-walk.c \
syscall/chown-overlay.c \
syscall/fs.c \
syscall/fs-stat.c \
Expand Down Expand Up @@ -192,6 +193,29 @@ $(BUILD_DIR)/test-teardown-live-vcpu-host: \
@echo " LD $@"
$(Q)$(CC) $(CFLAGS) -o $@ $^ $(HVF_LDFLAGS)

## Build the volume naming probe (native macOS binary)
# Standalone: it measures the filesystem, so it links nothing from the project.
$(BUILD_DIR)/probe-volume-naming: $(BUILD_DIR)/probe-volume-naming.o \
| $(BUILD_DIR)
@echo " LD $@"
$(Q)$(CC) $(CFLAGS) -o $@ $^

## Build the filename codec host test (native macOS binary)
# casefold.o is a leaf translation unit with no syscall-layer dependencies, so
# the test links exactly the code under test and nothing else.
$(BUILD_DIR)/test-casefold-host: $(BUILD_DIR)/test-casefold-host.o \
$(BUILD_DIR)/syscall/casefold.o | $(BUILD_DIR)
@echo " LD $@"
$(Q)$(CC) $(CFLAGS) -o $@ $^

## Build the case-exact path resolution host test (native macOS binary)
# Links the resolver and the codec; the two process-state symbols the resolver
# reads are stubbed in the test.
$(BUILD_DIR)/test-casefold-walk-host: $(BUILD_DIR)/test-casefold-walk-host.o \
$(BUILD_DIR)/syscall/casefold-walk.o \
$(BUILD_DIR)/syscall/casefold.o | $(BUILD_DIR)
@echo " LD $@"
$(Q)$(CC) $(CFLAGS) -o $@ $^

# Guest test binaries (cross-compiled, aarch64-linux)
# Only used when GUEST_TEST_BINARIES is not set.
Expand All @@ -214,6 +238,11 @@ $(BUILD_DIR)/test-pthread: tests/test-pthread.c | $(BUILD_DIR)
@echo " CROSS $< (with -lpthread)"
$(Q)$(CROSS_COMPILE)gcc -D_GNU_SOURCE -static -O2 -o $@ $< -lpthread

# test-sysroot-name-soak churns from worker threads plus forked children
$(BUILD_DIR)/test-sysroot-name-soak: tests/test-sysroot-name-soak.c | $(BUILD_DIR)
@echo " CROSS $< (with -lpthread)"
$(Q)$(CROSS_COMPILE)gcc -D_GNU_SOURCE -static -O2 -o $@ $< -lpthread

# test-process-lifecycle creates a worker to verify that process PIDs and
# thread TIDs share one namespace-wide allocator across fork children.
$(BUILD_DIR)/test-process-lifecycle: tests/test-process-lifecycle.c src/utils.h | $(BUILD_DIR)
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ linker resolved against an external sysroot via `--sysroot`.
signals, timers, futexes (incl. PI ops), and polling
- Guest reads and writes the macOS filesystem directly; no overlay or
volume mount layer
- Linux byte-exact filename semantics under `--sysroot`, including
case-colliding names on the default case-folding APFS (see
[docs/filenames.md](docs/filenames.md))
- Synthetic `/proc` and selected `/dev` emulation for user-space probes
- Guest-internal FUSE: `/dev/fuse` and `mount("fuse")` work without
macFUSE / FUSE-T / FSKit
Expand All @@ -53,7 +56,7 @@ boot-time overhead those tools impose.
- GNU `objcopy` or `llvm-objcopy`
- Hypervisor entitlement: `com.apple.security.hypervisor`

To build only (`make elfuse`) without running tests, just the
To build only (`make elfuse`) without running tests, just the
Xcode Command Line Tools and `objcopy` (`brew install binutils`) suffice.

For guest test binaries, the project also expects an AArch64 Linux cross
Expand All @@ -62,7 +65,7 @@ used by the repository test harness, but `CROSS_COMPILE` and
`BAREMETAL_CROSS` are overridable.

See
[docs/testing.md](docs/testing.md#build-requirements) for toolchain setup guide.
[docs/testing.md](docs/testing.md#build-requirements) for toolchain setup guide.

## Quick Start

Expand Down Expand Up @@ -109,6 +112,9 @@ The build signs `build/elfuse` before use. Override the signing identity with
- [docs/testing.md](docs/testing.md): build prerequisites, the
`make check` flow, the QEMU and Rosetta cross-check matrices, and
fixture handling.
- [docs/filenames.md](docs/filenames.md): how a guest filename becomes a
name on disk and back: case folding and normalization on the sysroot
volume, the escape encoding, and the length limits both systems impose.
- [docs/internals.md](docs/internals.md): canonical technical
reference -- runtime lifecycle, HVF constraints, EL1 shim and HVC
protocol, page-table splitting, syscall translation tables, threads
Expand Down
Loading
Loading