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") LIBIWASM_LINUX_DEBUG := env("LIBIWASM_LINUX_DEBUG") LIBIWASM_LINUX_RELEASE := env("LIBIWASM_LINUX_RELEASE") CROSS_CC := env("CROSS_CC") LINUX_CC := env("LINUX_CC") # =================================================================================================================== # # Helper 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 }} # =================================================================================================================== # # Build WASM module recipes # =================================================================================================================== # 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 \ " WAMRC := "wamrc" WAMRCFLAGS := "\ --target=i386 \ --cpu=generic \ --opt-level=0 \ " XXD := "xxd" [doc("C -> WASM: Compile a C function to a WASM module using WASI-SDK")] [group("build-module")] 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-module")] 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-module")] build-wasm-aot-array module: (build-wasm-aot module) {{ XXD }} -i {{ BUILD_DIR }}-{{ module }}/wasm_module.aot > {{ BUILD_DIR }}-{{ module }}/wasm_module_array.c # =================================================================================================================== # # Host program recipes # =================================================================================================================== # # FAIL* 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 \ " # LINUX-POSIX LINUX_CFLAGS := "\ -I./targets/wasm-host \ -O0 \ -m32 \ -ffunction-sections \ -fdata-sections \ -ggdb \ " LINUX_LDFLAGS := f"\ -Wl,--build-id=none \ -m32 \ -Wl,-rpath,{{LIBIWASM_LINUX_DEBUG}} \ -L{{LIBIWASM_LINUX_DEBUG}} \ -liwasm \ -lm \ " LINUX_INCLUDES := f"\ -I{{WAMR_ROOT}}/core/iwasm/include \ -I{{WAMR_ROOT}}/core/shared/utils \ -I{{WAMR_ROOT}}/core/shared/platform/linux \ " # LINUX-Baremetal LINUX_BAREMETAL_CFLAGS := "\ -I./targets/wasm-host \ -O0 \ -m32 \ -ffunction-sections \ -fdata-sections \ -ffreestanding \ -ggdb \ " LINUX_BAREMETAL_LDFLAGS := f"\ -Wl,--build-id=none \ -static \ -nostdlib \ -m32 \ -L{{LIBIWASM_DEBUG}} \ -liwasm \ -lc \ -lgcc \ -lm \ --entry main \ " LINUX_BAREMETAL_INCLUDES := f"\ -I{{WAMR_ROOT}}/core/iwasm/include \ -I{{WAMR_ROOT}}/core/shared/utils \ -I{{WAMR_ROOT}}/core/shared/platform/baremetal \ " # TODO: Grave mistake to template the commands depending on the target... Should've used shebang recipes instead [private] build-wasm-host-fail module: {{ CROSS_CC }} {{ CROSS_CFLAGS }} {{ CROSS_INCLUDES }} \ -c {{ BUILD_DIR }}-{{ module }}/module_host.c \ -o {{ BUILD_DIR }}-{{ module }}/system.o [private] build-wasm-host-linux module: {{ LINUX_CC }} {{ LINUX_CFLAGS }} {{ LINUX_INCLUDES }} \ -c {{ BUILD_DIR }}-{{ module }}/module_host.c \ -o {{ BUILD_DIR }}-{{ module }}/system.o [private] build-wasm-host-linux-baremetal module: {{ CROSS_CC }} {{ LINUX_BAREMETAL_CFLAGS }} {{ LINUX_BAREMETAL_INCLUDES }} \ -c {{ BUILD_DIR }}-{{ module }}/module_host.c \ -o {{ BUILD_DIR }}-{{ module }}/system.o [private] build-wasm-host-dispatch module target="fail": #!/usr/bin/env sh if [ "{{ target }}" = "fail" ]; then just build-wasm-host-fail "{{ module }}" elif [ "{{ target }}" = "linux" ]; then just build-wasm-host-linux "{{ module }}" elif [ "{{ target }}" = "linux-baremetal" ]; then just build-wasm-host-linux-baremetal "{{ module }}" else echo "unknown target: {{ target }}" >&2 exit 1 fi [doc("Compile C-Host: The host uses WAMR to load the AOT module")] [group("build-host")] build-wasm-host module target="fail": (build-wasm-aot-array module) && (build-wasm-host-dispatch module target) 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 [private] build-system-startup-fail module: {{ CROSS_CC }} targets/startup.s {{ CROSS_CFLAGS }} -c -o {{ BUILD_DIR }}-{{ module }}/startup.o [doc("Compile bootloader")] [group("build-host")] build-system-startup module target="fail": #!/usr/bin/env sh if [ "{{ target }}" = "fail" ]; then just build-system-startup-fail "{{ module }}" else echo "{{ target }} doesn't need bootloader" fi [private] build-system-syscalls-fail module: {{ CROSS_CC }} targets/syscalls.c {{ CROSS_CFLAGS }} -c -o {{ BUILD_DIR }}-{{ module }}/syscalls.o [private] build-system-syscalls-linux-baremetal module: {{ CROSS_CC }} targets/syscalls.c {{ LINUX_BAREMETAL_CFLAGS }} -c -o {{ BUILD_DIR }}-{{ module }}/syscalls.o [doc("Compile newlib syscall stubs")] [group("build-host")] build-system-syscalls module target="fail": #!/usr/bin/env sh if [ "{{ target }}" = "fail" ]; then just build-system-syscalls-fail "{{ module }}" elif [ "{{ target }}" = "linux-baremetal" ]; then just build-system-syscalls-linux-baremetal "{{ module }}" else echo "{{ target }} doesn't require syscall stubs" fi [private] link-system-fail module: {{ CROSS_CC }} \ -Wl,-T targets/linker.ld \ {{ BUILD_DIR }}-{{ module }}/system.o \ {{ BUILD_DIR }}-{{ module }}/startup.o \ {{ BUILD_DIR }}-{{ module }}/syscalls.o \ {{ CROSS_LDFLAGS }} \ -o {{ BUILD_DIR }}-{{ module }}/system.elf [private] link-system-linux module: {{ LINUX_CC }} \ {{ BUILD_DIR }}-{{ module }}/system.o \ {{ LINUX_LDFLAGS }} \ -o {{ BUILD_DIR }}-{{ module }}/system.elf [private] link-system-linux-baremetal module: {{ CROSS_CC }} \ {{ BUILD_DIR }}-{{ module }}/system.o \ {{ BUILD_DIR }}-{{ module }}/syscalls.o \ {{ LINUX_BAREMETAL_LDFLAGS }} \ -o {{ BUILD_DIR }}-{{ module }}/system.elf [doc("Link C-Host, syscall stubs and bootloader")] [group("build-host")] link-system module target="fail": (build-wasm-host module target) (build-system-syscalls module target) (build-system-startup module target) #!/usr/bin/env sh if [ "{{ target }}" = "fail" ]; then just link-system-fail "{{ module }}" elif [ "{{ target }}" = "linux" ]; then just link-system-linux "{{ module }}" elif [ "{{ target }}" = "linux-baremetal" ]; then just link-system-linux-baremetal "{{ module }}" else echo "unknown target: {{ target }}" >&2 exit 1 fi [doc("Create bootdisk")] [group("build-host")] build-iso module target="fail": (link-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 # =================================================================================================================== # # MySQL recipes # =================================================================================================================== # [doc("Start MySQL container to receive FAIL* trace/campaign results")] [group("fail-db")] start-db: docker run -d \ --name fail-db \ -e MYSQL_ROOT_PASSWORD=fail \ -e MYSQL_USER=fail \ -e MYSQL_PASSWORD=fail \ -e MYSQL_DATABASE=fail \ -p 3306:3306 \ mysql [doc("Connect to MySQL database using DBeaver")] [group("fail-db")] connect-db: dbeaver -con "name=fail|driver=mysql|host=localhost|port=3306|database=fail|user=fail|password=fail" [doc("Stop MySQL container")] [group("fail-db")] stop-db: docker stop fail-db [doc("Remove MySQL container")] [group("fail-db")] remove-db: docker container rm fail-db # =================================================================================================================== # # FAIL* recipes # =================================================================================================================== # BOCHS_RUNNER := "bochs-experiment-runner.py" FAIL_TRACE := "fail-x86-tracing" FAIL_DUMP := "dump-trace" FAIL_IMPORT := "import-trace" FAIL_PRUNE := "prune-trace" FAIL_SERVER := "generic-experiment-server" FAIL_INJECT := "generic-experiment-client" RESULT_BROWSER := "resultbrowser.py" [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("Dump a FAIL* golden run trace")] # [group("fail")] # dump module: # {{ FAIL_DUMP }} {{ BUILD_DIR }}-{{ module }}/trace.pb [doc("Import a FAIL* golden run trace")] [group("fail")] import module: {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i MemoryImporter \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b mem {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i RegisterImporter \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b regs --flags {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i RegisterImporter \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b ip --no-gp --ip {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i ElfImporter --objdump objdump \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b ip {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i ElfImporter --objdump objdump \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b mem {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i ElfImporter --objdump objdump \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b regs {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i ElfImporter --objdump objdump \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b ip --sources {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i ElfImporter --objdump objdump \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b mem --sources {{ FAIL_IMPORT }} --database-option-file ./db.conf -t {{ BUILD_DIR }}-{{ module }}/trace.pb \ -i ElfImporter --objdump objdump \ -e {{ BUILD_DIR }}-{{ module }}/system.elf -v {{ module }} -b regs --sources {{ FAIL_PRUNE }} --database-option-file ./db.conf -v {{ module }} -b %% --overwrite @echo "Next step: \"just server {{ module }}\"" [doc("Start the FAIL* campaign server")] [group("fail")] server module: {{ FAIL_SERVER }} --database-option-file ./db.conf -v {{ module }} -b % --inject-single-bit --inject-registers & @echo "Next step: \"just client {{ module }}\"" [doc("Stop the FAIL* campaign server")] [group("fail")] stop-server: pkill -f {{ FAIL_SERVER }} [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 \ > /dev/null @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 }} -c ./db.conf --host=0.0.0.0 --port=5000 # =================================================================================================================== # # Debugging recipes # =================================================================================================================== # [doc("Run binary")] [group("debug")] run module: {{ BUILD_DIR }}-{{ module }}/system.elf [doc("Launch gdb")] [group("debug")] gdb module: gdb --tui {{ BUILD_DIR }}-{{ module }}/system.elf [doc("Launch radare2 at os_main")] [group("debug")] radare module: radare2 -AA -c "s dbg.os_main; pdf" {{ BUILD_DIR }}-{{ module }}/system.elf