This document covers the command-line interface, common launch patterns,
dynamic linking through --sysroot, and debugger attachment.
build/elfuse [options] <elf-path> [args...]Supported user-facing options:
| Option | Meaning |
|---|---|
-h, --help |
Print built-in usage help |
-V, --version |
Print the build version and exit |
-v, --verbose |
Enable syscall-level and loader diagnostics |
-t, --timeout N |
Per-iteration vCPU watchdog, in seconds (default 10) |
--sysroot PATH |
Resolve guest absolute paths under PATH first |
--gdb PORT |
Listen for a GDB RSP client on PORT |
--gdb-stop-on-entry |
Stop before the first guest instruction |
-- |
End elfuse option parsing; remaining tokens are guest argv |
--timeout is a run-loop watchdog. It does not cap total process runtime. It
only bounds a single hv_vcpu_run() iteration before the host regains control,
which is what allows host-side timers and signals to be observed promptly.
Run a statically linked guest binary:
build/elfuse ./build/test-helloRun with verbose tracing:
build/elfuse --verbose ./guest-program arg1 arg2Pass guest arguments that begin with -:
build/elfuse -- ./guest-program --guest-flagDynamic Linux guests need a sysroot that contains the expected interpreter and
shared libraries. elfuse reads PT_INTERP, loads the requested interpreter
from the supplied sysroot, and redirects guest absolute-path opens to that tree
before falling back to the host filesystem.
Example:
build/elfuse --sysroot /path/to/sysroot ./hello-dynamicThis model supports both musl and glibc guest environments as long as the
expected interpreter path (for example /lib/ld-musl-aarch64.so.1 or
/lib/ld-linux-aarch64.so.1) exists inside the sysroot.
Practical notes:
- The sysroot is consulted only for guest absolute paths; relative paths still resolve from the guest working directory.
- The sysroot setting is preserved across guest
forkandexecve, so spawned children see the same view of the filesystem.
elfuse includes a built-in GDB Remote Serial Protocol stub.
Start the guest and wait at entry:
build/elfuse --gdb 1234 --gdb-stop-on-entry ./guest-programAttach with GNU GDB:
aarch64-linux-gnu-gdb -ex "target remote :1234" ./guest-programOr attach with LLDB:
lldb --batch -o "gdb-remote 1234" ./guest-programThe stub supports all-stop debugging, up to 16 hardware breakpoints, up to 16 watchpoints, single-step (implemented as a temporary breakpoint), full register and memory access, and per-thread inspection. Implementation details, including the snapshot protocol used to keep Hypervisor.framework register access on the owning thread, are documented in internals.md.
elfuse is designed for Linux user-space workloads, not for booting a Linux
kernel or presenting a complete Linux host environment. Compatibility comes
from targeted ABI translation and emulation at the syscall boundary.
That has a few direct implications:
/procand/devare compatibility surfaces, not passthrough mounts.- macOS and Linux file, socket, and signal semantics are normalized in the host syscall layer.
- Behavior is strongest for normal command-line tools, language runtimes, test binaries, and debugger-driven workflows.