add build + fail recipes

This commit is contained in:
2026-03-12 01:42:14 +01:00
parent facf04df7f
commit 679aeb24d4
4 changed files with 263 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build-*

5
db.conf Normal file
View File

@ -0,0 +1,5 @@
[client]
host=127.0.0.1
user=fail
password=fail
database=fail

11
docker-compose.yaml Normal file
View File

@ -0,0 +1,11 @@
services:
fail-db:
image: mysql
container_name: fail-db
environment:
MYSQL_ROOT_PASSWORD: fail
MYSQL_USER: fail
MYSQL_PASSWORD: fail
MYSQL_DATABASE: fail
ports:
- "3306:3306"

246
justfile Normal file
View File

@ -0,0 +1,246 @@
BUILD_DIR := "build"
# Load environment variables set by "nix develop"-shell
FAIL_SHARE := env("FAIL_SHARE")
WASI_ROOT := env("WASI_ROOT")
WAMR_ROOT := env("WAMR_ROOT")
LIBIWASM_DEBUG := env("LIBIWASM_DEBUG")
LIBIWASM_RELEASE := env("LIBIWASM_RELEASE")
CROSS_CC := env("CROSSCC")
CROSS_CXX := env("CROSSCXX")
# C -> WASM
WASI_CC := f"{{WASI_ROOT}}/bin/clang"
WASI_CFLAGS := "\
--target=wasm32 \
--sysroot={{WASI_ROOT}}/share/wasi-sysroot \
-z stack-size=4096 \
-O0 \
-nostdlib \
-Wl,--no-entry \
-Wl,--export-all \
-Wl,--no-gc-sections \
-Wl,--initial-memory=65536 \
-Wl,--export=__heap_base \
-Wl,--export=__data_end \
"
# WASM -> AOT
WAMRC := "wamrc"
WAMRCFLAGS := "\
--target=i386 \
--cpu=generic \
--opt-level=0 \
"
XXD := "xxd"
# Load AOT from WAMR
CROSS_CFLAGS := "\
-I./targets/wasm-host \
-O2 \
-m32 \
-ffunction-sections \
-fdata-sections \
-ffreestanding \
-fomit-frame-pointer \
-ggdb \
"
CROSS_LDFLAGS := f"\
-Wl,--build-id=none \
-static \
-nostdlib \
-m32 \
-L{{LIBIWASM_RELEASE}} \
-liwasm \
-lc \
-lgcc \
-lm \
"
CROSS_INCLUDES := f"\
-I{{WAMR_ROOT}}/core/iwasm/include \
-I{{WAMR_ROOT}}/core/shared/utils \
-I{{WAMR_ROOT}}/core/shared/platform/baremetal \
"
# Build recipes
[default]
[private]
list:
@just --list --unsorted
[private]
create-build-dir module:
mkdir -p {{ BUILD_DIR }}-{{ module }}
[doc("Delete the build directory")]
clean module:
rm -rf {{ BUILD_DIR }}-{{ module }}
[doc("C -> WASM: Compile a C function to a WASM module using WASI-SDK")]
[group("build")]
build-wasm-module module: (create-build-dir module)
{{ WASI_CC }} {{ WASI_CFLAGS }} targets/wasm-module/{{ module }}.c -o {{ BUILD_DIR }}-{{ module }}/wasm_module.wasm
[doc("WASM -> AOT: Compile a WASM module ahead-of-time using WAMR")]
[group("build")]
build-wasm-aot module: (build-wasm-module module)
{{ WAMRC }} {{ WAMRCFLAGS }} -o {{ BUILD_DIR }}-{{ module }}/wasm_module.aot {{ BUILD_DIR }}-{{ module }}/wasm_module.wasm
[doc("AOT -> C-Array: Dump a WASM module compiled ahead-of-time to a binary array")]
[group("build")]
build-wasm-aot-array module: (build-wasm-aot module)
{{ XXD }} -i {{ BUILD_DIR }}-{{ module }}/wasm_module.aot > {{ BUILD_DIR }}-{{ module }}/wasm_module_array.c
[doc("Compile C-Host: The host uses WAMR to load the AOT module")]
[group("build")]
build-wasm-host module target="fail": (build-wasm-aot-array module)
cp targets/wasm-host/{{ target }}.c {{ BUILD_DIR }}-{{ module }}/module_host.c
sed -i \
-e "s/__WASM_ARRAY_FILE__/wasm_module_array.c/g" \
-e "s/__WASM_ARRAY__/build_{{ module }}_wasm_module_aot/g" \
-e "s/__WASM_ARRAY_LEN__/build_{{ module }}_wasm_module_aot_len/g" \
{{ BUILD_DIR }}-{{ module }}/module_host.c
{{ CROSS_CC }} {{ CROSS_CFLAGS }} {{ CROSS_INCLUDES }} \
-c {{ BUILD_DIR }}-{{ module }}/module_host.c \
-o {{ BUILD_DIR }}-{{ module }}/system.o
[doc("Compile bootloader")]
[group("build")]
build-system-startup module:
{{ CROSS_CC }} targets/startup.s {{ CROSS_CFLAGS }} -c -o {{ BUILD_DIR }}-{{ module }}/startup.o
[doc("Compile newlib syscall stubs")]
[group("build")]
build-system-syscalls module:
{{ CROSS_CC }} targets/syscalls.c {{ CROSS_CFLAGS }} -c -o {{ BUILD_DIR }}-{{ module }}/syscalls.o
[doc("Link C-Host, syscall stubs and bootloader")]
[group("build")]
build-system module target="fail": (build-wasm-host module target) (build-system-syscalls module) (build-system-startup module)
{{ CROSS_CC }} -Wl,-T targets/linker.ld \
{{ BUILD_DIR }}-{{ module }}/system.o \
{{ BUILD_DIR }}-{{ module }}/syscalls.o \
{{ BUILD_DIR }}-{{ module }}/startup.o \
{{ CROSS_LDFLAGS }} -o {{ BUILD_DIR }}-{{ module }}/system.elf
[doc("Create bootdisk")]
[group("build")]
build-iso module target="fail": (build-system module target)
mkdir -p {{ BUILD_DIR }}-{{ module }}/grub/boot/grub
cp targets/grub.cfg {{ BUILD_DIR }}-{{ module }}/grub/boot/grub/
cp {{ BUILD_DIR }}-{{ module }}/system.elf {{ BUILD_DIR }}-{{ module }}/grub/boot/
grub-mkrescue -o {{ BUILD_DIR }}-{{ module }}/system.iso {{ BUILD_DIR }}-{{ module }}/grub
# FAIL* recipes
BOCHS_RUNNER := "bochs-experiment-runner.py"
FAIL_TRACE := "fail-x86-tracing"
FAIL_DUMP := "dump-trace"
FAIL_IMPORT := "import-trace --database-option-file ./db.conf"
FAIL_PRUNE := "prune-trace --database-option-file ./db.conf"
FAIL_SERVER := "generic-experiment-server --database-option-file ./db.conf"
FAIL_INJECT := "generic-experiment-client"
RESULT_BROWSER := "resultbrowser.py -c ./db.conf"
[doc("Start MySQL to receive FAIL* trace/campaign results")]
[group("fail")]
start-db:
docker compose up
[doc("Stop MySQL")]
[group("fail")]
stop-db:
docker compose down
[doc("Trace a golden run using FAIL*")]
[group("fail")]
trace module:
{{ BOCHS_RUNNER }} \
-V {{ FAIL_SHARE }}/vgabios.bin \
-b {{ FAIL_SHARE }}/BIOS-bochs-latest \
-1 \
-f {{ FAIL_TRACE }} \
-e {{ BUILD_DIR }}-{{ module }}/system.elf \
-i {{ BUILD_DIR }}-{{ module }}/system.iso \
-- \
-Wf,--start-symbol=start_trace \
-Wf,--save-symbol=start_trace \
-Wf,--end-symbol=stop_trace \
-Wf,--state-file={{ BUILD_DIR }}-{{ module }}/state \
-Wf,--trace-file={{ BUILD_DIR }}-{{ module }}/trace.pb \
-Wf,--elf-file={{ BUILD_DIR }}-{{ module }}/system.elf
@echo "Next step: \"just import {{ module }}\""
[doc("Import a FAIL* golden run trace")]
[group("fail")]
import module:
{{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i MemoryImporter \
-e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b mem
{{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i RegisterImporter \
-e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b regs --flags
{{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i RegisterImporter \
-e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b ip --no-gp --ip
# TODO: Failed to decode DWARF data - wrong libdwarf version?
#
# {{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i ElfImporter --objdump objdump \
# -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b ip
# {{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i ElfImporter --objdump objdump \
# -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b mem
# {{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i ElfImporter --objdump objdump \
# -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b regs
# {{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i ElfImporter --objdump objdump \
# -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b ip --sources
# {{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i ElfImporter --objdump objdump \
# -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b mem --sources
# {{ FAIL_IMPORT }} -t {{ BUILD_DIR }}-{{ module }}/trace.pb -i ElfImporter --objdump objdump \
# -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b regs --sources
{{ FAIL_PRUNE }} -v {{ module }} -b %% --overwrite
@echo "Next step: \"just server {{ module }}\""
[doc("Start the FAIL* campaign server")]
[group("fail")]
server module:
{{ FAIL_SERVER }} -v {{ module }} -b % --inject-single-bit --inject-registers &
@echo "Next step: \"just client {{ module }}\""
[doc("Start a FAIL* campaign client")]
[group("fail")]
client module:
{{ BOCHS_RUNNER }} \
-V {{ FAIL_SHARE }}/vgabios.bin \
-b {{ FAIL_SHARE }}/BIOS-bochs-latest \
-f {{ FAIL_INJECT }} \
-e {{ BUILD_DIR }}-{{ module }}/system.elf \
-i {{ BUILD_DIR }}-{{ module }}/system.iso \
-j {{ num_cpus() }} \
-- \
-Wf,--state-dir={{ BUILD_DIR }}-{{ module }}/state \
-Wf,--trap \
-Wf,--timeout=500000 \
-Wf,--ok-marker=ok_marker \
-Wf,--fail-marker=fail_marker \
2>/dev/null | grep -B 2 -A 8 'INJECT'
@echo "Next step: \"just result {{ module }}\" or \"just resultbrowser\""
[doc("Query FAIL* marker statistics from the database")]
[group("fail")]
result module:
@echo "select variant, benchmark, resulttype, sum(t.time2 - t.time1 + 1) as faults \
FROM variant v \
JOIN trace t ON v.id = t.variant_id \
JOIN fspgroup g ON g.variant_id = t.variant_id AND g.instr2 = t.instr2 AND g.data_address = t.data_address \
JOIN result_GenericExperimentMessage r ON r.pilot_id = g.pilot_id \
JOIN fsppilot p ON r.pilot_id = p.id \
WHERE v.variant = \"{{ module }}\" \
GROUP BY v.id, resulttype \
ORDER BY variant, benchmark, resulttype;" | mariadb --defaults-file=./db.conf -t
[doc("Start the FAIL* resultbrowser")]
[group("fail")]
resultbrowser:
{{ RESULT_BROWSER }} --host=0.0.0.0 --port=5000