diff options
| author | Theofilos Augoustis <37243696+taugoust@users.noreply.github.com> | 2025-10-24 17:36:27 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-24 17:36:27 +0200 |
| commit | 9337176fc0b7b1d86cdd3a5abfd32f6336210d89 (patch) | |
| tree | 168f642a3f842a0d062dcde5fb3371fdaf916b20 | |
| parent | c6a2f0793963c6146a1fe14243831615ddb611e3 (diff) | |
| parent | 4010158a369b4b4561cef2325377475500c45158 (diff) | |
| download | focaccia-9337176fc0b7b1d86cdd3a5abfd32f6336210d89.tar.gz focaccia-9337176fc0b7b1d86cdd3a5abfd32f6336210d89.zip | |
Merge pull request #10 from TUM-DSE/ck/box64-parser
Add Box64 trace parser
| -rw-r--r-- | README.md | 13 | ||||
| -rw-r--r-- | fix-box64.patch | 46 | ||||
| -rw-r--r-- | flake.nix | 47 | ||||
| -rwxr-xr-x | src/focaccia/cli.py | 1 | ||||
| -rw-r--r-- | src/focaccia/parser.py | 33 |
5 files changed, 138 insertions, 2 deletions
diff --git a/README.md b/README.md index 0eb103b..94e6889 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ It will take a while to compile. `focaccia` is the main executable. Invoke `focaccia --help` to see what you can do with it. +### QEMU + A number of additional tools are included to simplify use when validating QEMU: `capture-transforms`, `convert-log`, `validate-qemu`. They enable the following workflow. @@ -37,6 +39,17 @@ validate-qemu --symb-trace oracle.trace localhost 12345 Using this workflow, Focaccia can determine whether a mistranslation occured in that particular QEMU run. +### Box64 + +For validating Box64, we create the oracle and test traces and compare them +using the main executable. + +```bash +capture-transforms -o oracle.trace bug.out +BOX64_TRACE_FILE=test.trace box64 bug.out +focaccia -o oracle.trace --symbolic -t test.trace --test-trace-type box64 --error-level error +``` + ## Tools The `tools/` directory contains additional utility scripts to work with focaccia. diff --git a/fix-box64.patch b/fix-box64.patch new file mode 100644 index 0000000..495dd4a --- /dev/null +++ b/fix-box64.patch @@ -0,0 +1,46 @@ +From 5f7a1982ac307d2bcdc9119c85847f48d193e378 Mon Sep 17 00:00:00 2001 +From: ckrinitsin <101062646+ckrinitsin@users.noreply.github.com> +Date: Wed, 22 Oct 2025 18:20:31 +0200 +Subject: [PATCH] [TRACE] Fix flags output for better parsing (#3090) + +--- + src/emu/x64emu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/emu/x64emu.c b/src/emu/x64emu.c +index f4fa700b..dde9a496 100644 +--- a/src/emu/x64emu.c ++++ b/src/emu/x64emu.c +@@ -442,12 +442,12 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip, int is32bits) + if(i==_RBX) { + if(emu->df) { + #define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "?" +- sprintf(tmp, "flags=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); ++ sprintf(tmp, " flags=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); + strcat(buff, tmp); + #undef FLAG_CHAR + } else { + #define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "-" +- sprintf(tmp, "FLAGS=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); ++ sprintf(tmp, " FLAGS=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); + strcat(buff, tmp); + #undef FLAG_CHAR + } +@@ -473,12 +473,12 @@ const char* DumpCPURegs(x64emu_t* emu, uintptr_t ip, int is32bits) + if(i==4) { + if(emu->df) { + #define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "?" +- sprintf(tmp, "flags=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); ++ sprintf(tmp, " flags=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); + strcat(buff, tmp); + #undef FLAG_CHAR + } else { + #define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "-" +- sprintf(tmp, "FLAGS=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); ++ sprintf(tmp, " FLAGS=%s%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(D), FLAG_CHAR(S), FLAG_CHAR(Z), FLAG_CHAR(A), FLAG_CHAR(P), FLAG_CHAR(C)); + strcat(buff, tmp); + #undef FLAG_CHAR + } +-- +2.51.1.dirty + diff --git a/flake.nix b/flake.nix index 425040b..fccabba 100644 --- a/flake.nix +++ b/flake.nix @@ -71,6 +71,45 @@ members = [ "focaccia" "miasm" ]; }; + # Box64 + zydis-shared-object = pkgs.zydis.overrideAttrs (oldAttrs: { + cmakeFlags = (oldAttrs.cmakeFlags or []) ++ [ + "-DZYDIS_BUILD_SHARED_LIB=ON" + ]; + }); + + box64-patched = pkgs.stdenv.mkDerivation { + pname = "box64"; + version = "74d4db"; + + src = pkgs.fetchFromGitHub { + owner = "ptitSeb"; + repo = "box64"; + rev = "74d4db051b4c74aaab23b19fbb51e441448faf8e"; + sha256 = "sha256-G6tsqXsnTrs8I47YLnuivC79IFDGfbiLSm4J2Djc0kU="; + }; + + nativeBuildInputs = with pkgs; [ + cmake + python + pkg-config + zydis-shared-object + ]; + + cmakeFlags = [ + "-DDYNAREC=ON" + "-DHAVE_TRACE=ON" + ]; + + patches = [ ./fix-box64.patch ]; + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp box64 $out/bin/ + runHook postInstall + ''; + }; + # Another overlay layer for flake-specific overloads # This might be needed because uv does not have sufficient metadata # Here, uv does include metadata about build systems used by each dependency @@ -312,12 +351,18 @@ packages.dev musl-pkgs.gcc musl-pkgs.pkg-config + box64-patched ]; hardeningDisable = [ "pie" ]; env = uvEnv; - shellHook = uvShellHook; + shellHook = uvShellHook + '' + export BOX64_TRACE=1 + export BOX64_DYNAREC_TRACE=1 + export BOX64_DYNAREC_DF=0 + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${zydis-shared-object}/lib + ''; }; }; diff --git a/src/focaccia/cli.py b/src/focaccia/cli.py index f0c6efe..88c6313 100755 --- a/src/focaccia/cli.py +++ b/src/focaccia/cli.py @@ -26,6 +26,7 @@ concrete_trace_parsers = { 'focaccia': lambda f, _: parser.parse_snapshots(f), 'qemu': parser.parse_qemu, 'arancini': parser.parse_arancini, + 'box64': parser.parse_box64, } _MatchingAlgorithm = Callable[ diff --git a/src/focaccia/parser.py b/src/focaccia/parser.py index 950f462..e9e5e0c 100644 --- a/src/focaccia/parser.py +++ b/src/focaccia/parser.py @@ -84,7 +84,7 @@ def serialize_snapshots(snapshots: Trace[ProgramState], out_stream: TextIO): json.dump(res, out_stream, indent=4) def _make_unknown_env() -> TraceEnvironment: - return TraceEnvironment('', [], [], '?') + return TraceEnvironment('', [], False, [], '?') def parse_qemu(stream: TextIO, arch: Arch) -> Trace[ProgramState]: """Parse a QEMU log from a stream. @@ -170,3 +170,34 @@ def parse_arancini(stream: TextIO, arch: Arch) -> Trace[ProgramState]: states[-1].set_register(regname, int(value, 16)) return Trace(states, _make_unknown_env()) + +def parse_box64(stream: TextIO, arch: Arch) -> Trace[ProgramState]: + def parse_box64_flags(state: ProgramState, flags_dump: str): + flags = ['O', 'D', 'S', 'Z', 'A', 'P', 'C'] + for i, flag in enumerate(flags): + if flag == flags_dump[i]: # Flag is set + state.set_register(arch.to_regname(flag + 'F'), 1) + elif '-' == flags_dump[i]: # Flag is not set + state.set_register(arch.to_regname(flag + 'F'), 0) + + trace_string = stream.read() + + blocks = re.split(r'(?=\nES=)', trace_string.strip())[1:] + blocks = [block.strip() for block in blocks if block.strip()] + + states = [] + pattern = r'([A-Z0-9]{2,3}|flags|FLAGS)=([0-9a-fxODSZAPC?\-]+)' + for block in blocks: + states.append(ProgramState(arch)) + matches = re.findall(pattern, block) + + for regname, value in matches: + if regname.lower() == "flags": + parse_box64_flags(states[-1], value) + continue + + regname = arch.to_regname(regname) + if regname is not None: + states[-1].set_register(regname, int(value, 16)) + + return Trace(states, _make_unknown_env()) |