From 679aeb24d4e5d7cbec7b9e8dc5775082dbc9e027 Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Thu, 12 Mar 2026 01:42:14 +0100 Subject: [PATCH] add build + fail recipes --- .gitignore | 1 + db.conf | 5 + docker-compose.yaml | 11 ++ justfile | 246 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 263 insertions(+) create mode 100644 .gitignore create mode 100644 db.conf create mode 100644 docker-compose.yaml create mode 100644 justfile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1aaaf52 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build-* diff --git a/db.conf b/db.conf new file mode 100644 index 0000000..4dbe0c1 --- /dev/null +++ b/db.conf @@ -0,0 +1,5 @@ +[client] +host=127.0.0.1 +user=fail +password=fail +database=fail diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..3519a33 --- /dev/null +++ b/docker-compose.yaml @@ -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" diff --git a/justfile b/justfile new file mode 100644 index 0000000..3b14852 --- /dev/null +++ b/justfile @@ -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