diff options
| author | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-10-28 17:00:43 +0000 |
|---|---|---|
| committer | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-11-06 17:23:20 +0000 |
| commit | cdf397ecd85921eb38b673dae4dbbdf15b5a3e56 (patch) | |
| tree | fbf21c0bf90be90f56f72d61ba4e6fc1fd4d3c8e | |
| parent | 1644f0843e6338092098f3f20e2a275dd62e9434 (diff) | |
| download | focaccia-cdf397ecd85921eb38b673dae4dbbdf15b5a3e56.tar.gz focaccia-cdf397ecd85921eb38b673dae4dbbdf15b5a3e56.zip | |
Package RR trace parsing mechanism in Focaccia
| -rw-r--r-- | flake.nix | 1 | ||||
| -rw-r--r-- | src/focaccia/deterministic.py | 48 | ||||
| -rwxr-xr-x | src/focaccia/tools/capture_transforms.py | 10 | ||||
| -rw-r--r-- | src/focaccia/trace.py | 7 |
4 files changed, 64 insertions, 2 deletions
diff --git a/flake.nix b/flake.nix index aa381b3..45ec28d 100644 --- a/flake.nix +++ b/flake.nix @@ -378,6 +378,7 @@ packages.dev rr musl-pkgs.gcc + pkgs.capnproto musl-pkgs.pkg-config ]; diff --git a/src/focaccia/deterministic.py b/src/focaccia/deterministic.py new file mode 100644 index 0000000..d05ac7f --- /dev/null +++ b/src/focaccia/deterministic.py @@ -0,0 +1,48 @@ +"""Parsing of JSON files containing snapshot data.""" + +import os +from typing import Union + +import brotli + +try: + import capnp + rr_trace = capnp.load(file_name='./rr/src/rr_trace.capnp', + imports=[os.path.dirname(p) for p in capnp.__path__]) +except Exception as e: + print(f'Cannot load RR trace loader: {e}') + exit(2) + +Frame = rr_trace.Frame +TaskEvent = rr_trace.TaskEvent +MMap = rr_trace.MMap +SerializedObject = Union[Frame, TaskEvent, MMap] + +class DeterministicLog: + def __init__(self, log_dir: str): + self.base_directory = log_dir + + def events_file(self) -> str: + return os.path.join(self.base_directory, 'events') + + def tasks_file(self) -> str: + return os.path.join(self.base_directory, 'tasks') + + def mmaps_file(self) -> str: + return os.path.join(self.base_directory, 'mmaps') + + def _read(self, file, obj: SerializedObject) -> list[SerializedObject]: + with open(file, 'rb') as f: + f.read(8) + data = brotli.decompress(f.read()) + return obj.read_multiple_bytes_packed(data) + + def events(self): + return self._read(self.events_file(), Frame) + + def tasks(self): + return self._read(self.tasks_file(), TaskEvent) + + def mmaps(self): + return self._read(self.mmaps_file(), MMap) + diff --git a/src/focaccia/tools/capture_transforms.py b/src/focaccia/tools/capture_transforms.py index 0adba43..f41d6f4 100755 --- a/src/focaccia/tools/capture_transforms.py +++ b/src/focaccia/tools/capture_transforms.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import sys import argparse import logging @@ -24,6 +25,8 @@ def main(): prog.add_argument('-r', '--remote', default=False, help='Remote target to trace (e.g. 127.0.0.1:12345)') + prog.add_argument('-l', '--deterministic-log', + help='Path of the directory storing the deterministic log produced by RR') prog.add_argument('--log-level', help='Set the logging level') prog.add_argument('--force', @@ -46,7 +49,12 @@ def main(): else: logging.basicConfig(level=logging.INFO) - env = TraceEnvironment(args.binary, args.args, utils.get_envp()) + detlog = None + if args.deterministic_log: + from focaccia.deterministic import DeterministicLog + detlog = DeterministicLog(args.deterministic_log) + + env = TraceEnvironment(args.binary, args.args, utils.get_envp(), nondeterminism_log=detlog) tracer = SymbolicTracer(env, remote=args.remote, cross_validate=args.cross_validate, force=args.force) trace = tracer.trace() diff --git a/src/focaccia/trace.py b/src/focaccia/trace.py index 829b03f..f274418 100644 --- a/src/focaccia/trace.py +++ b/src/focaccia/trace.py @@ -11,15 +11,20 @@ class TraceEnvironment: binary: str, argv: list[str], envp: list[str], - binary_hash: str | None = None): + binary_hash: str | None = None, + nondeterminism_log = None): self.argv = argv self.envp = envp self.binary_name = binary + self.detlog = nondeterminism_log if binary_hash is None and self.binary_name is not None: self.binary_hash = file_hash(binary) else: self.binary_hash = binary_hash + def is_deterministic(self) -> bool: + return self.detlog is not None + @classmethod def from_json(cls, json: dict) -> TraceEnvironment: """Parse a JSON object into a TraceEnvironment.""" |