Phase 46 provides two complementary paths on QEMU aarch64:
- In-tree fault parent — Microkit hierarchy delivers a child’s fault to
debug-handler, which logs IP/address (smoke:just test-debug). - Host GDB via QEMU gdbstub — attach
gdb-multiarchfor interactive backtraces and breakpoints without forked seL4/Microkit.
Full in-guest GDB RSP (libgdb) needs non-upstream kernel/Microkit patches; see ADR-005.
just test-debug
# or: BOARD=qemu_virt_aarch64_debug just testExpected log sequence (debug UART):
lerux-debug: ready (parent fault handler)crash-demo: about to faultlerux-debug: fault child=1 …lerux-debug: VmFault ip=… addr=…lerux-debug: crash-demo stopped (no restart)lerux-debug: crash dump child=1 count=…(Phase 57; machine-parseable forlerux diagnose)
Layout: crash-demo is a child of debug-handler in debug.system.template (id="1" → Child::new(1)).
Default workstation stays lean: flat PDs, no hierarchy (ADR-005). To catch faults in a bulk app:
- Nest that PD under
debug-handlerin a debug-only system template (do not ship as the production profile). - Keep
just test-debugas the CI fault-path smoke. - On failure, use the serial capture:
just test-debug
# or after any smoke:
just diagnose LOG=build/smoke-logs/qemu_virt_aarch64_debug.serial.logHost GDB remains the interactive path for production-image PDs (gdbstub, no template change).
Any aarch64 board works; the debug demo is a good start:
just image BOARD=qemu_virt_aarch64_debug
# ELF + loader under build/qemu_virt_aarch64_debug/PD ELFs (with symbols in debug/release builds that retain them):
build/qemu_virt_aarch64_debug/debug-handler.elfbuild/qemu_virt_aarch64_debug/crash-demo.elf- Loader:
build/qemu_virt_aarch64_debug/loader.img
# From repo root (adjust paths if your build-dir differs)
qemu-system-aarch64 \
-machine virt,virtualization=on \
-cpu cortex-a53 \
-m size=2G \
-serial mon:stdio \
-nographic \
-device loader,file=build/qemu_virt_aarch64_debug/loader.img,addr=0x70000000,cpu-num=0 \
-s -S-s— listen ontcp::1234(short for-gdb tcp::1234)-S— do not start CPUs until GDB continues
lerux-cli does not pass -s by default (automated smokes would hang). Add it when debugging interactively.
gdb-multiarch build/qemu_virt_aarch64_debug/crash-demo.elfInside GDB:
(gdb) target remote :1234
(gdb) # Optional: also load parent symbols
(gdb) add-symbol-file build/qemu_virt_aarch64_debug/debug-handler.elf
(gdb) break main # or a Rust symbol if demangled / known
(gdb) continue
After the null write in crash-demo, the PD faults. From the host view you can still inspect registers and memory that QEMU exposes; the seL4 fault is handled in-guest by debug-handler.
For a hung (non-faulting) PD, interrupt with Ctrl-C in GDB after continue and use bt / info registers with the appropriate ELF loaded.
| Tip | Detail |
|---|---|
| Architecture | set architecture aarch64 if GDB does not auto-detect |
| Multiple PDs | Load one ELF at a time; VAs are per-PD address spaces |
| Release builds | Symbols may be thinner; use debug Microkit config for kernel UART |
| Workstation | Same QEMU flags; prefer a smaller board first |
Hardware GDB (OpenOCD / JTAG) is out of Phase 46 scope. On device, keep serial logging and reproduce issues under QEMU when possible. A future phase may document JTAG once hierarchy debugging is proven on virt.
just test-isolation
# BOARD=qemu_virt_aarch64_isolationCombines hierarchy fault handling with the FS stack: after crash-demo is suspended, debug-handler notifies fs-client, which must still get lerux-fs: round-trip ok. Trust map: security.md.
- ADR-005
- security.md — Phase 60 threat model + isolation
- Microkit hierarchy example (upstream
example/hierarchy) - boards.md —
qemu_virt_aarch64_debug,qemu_virt_aarch64_isolation