about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-10-28 17:00:43 +0000
committerTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-11-06 17:23:20 +0000
commitcdf397ecd85921eb38b673dae4dbbdf15b5a3e56 (patch)
treefbf21c0bf90be90f56f72d61ba4e6fc1fd4d3c8e /src
parent1644f0843e6338092098f3f20e2a275dd62e9434 (diff)
downloadfocaccia-cdf397ecd85921eb38b673dae4dbbdf15b5a3e56.tar.gz
focaccia-cdf397ecd85921eb38b673dae4dbbdf15b5a3e56.zip
Package RR trace parsing mechanism in Focaccia
Diffstat (limited to 'src')
-rw-r--r--src/focaccia/deterministic.py48
-rwxr-xr-xsrc/focaccia/tools/capture_transforms.py10
-rw-r--r--src/focaccia/trace.py7
3 files changed, 63 insertions, 2 deletions
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."""