about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/focaccia/parser.py53
-rw-r--r--src/focaccia/qemu/_qemu_tool.py8
-rwxr-xr-xsrc/focaccia/tools/capture_transforms.py7
-rwxr-xr-xsrc/focaccia/tools/validate_qemu.py4
4 files changed, 59 insertions, 13 deletions
diff --git a/src/focaccia/parser.py b/src/focaccia/parser.py
index 4df14ec..9c7b283 100644
--- a/src/focaccia/parser.py
+++ b/src/focaccia/parser.py
@@ -2,8 +2,9 @@
 
 import re
 import base64
+import msgpack
 import orjson as json
-from typing import TextIO
+from typing import TextIO, Literal
 
 from .arch import supported_architectures, Arch
 from .snapshot import ProgramState
@@ -30,15 +31,49 @@ def parse_transformations(json_stream: TextIO) -> TraceContainer[SymbolicTransfo
 
     return TraceContainer(strace, env)
 
-def serialize_transformations(transforms: Trace[SymbolicTransform],
-                              out_stream: TextIO):
+def stream_transformation(stream) -> Trace[SymbolicTransform]:
+    unpacker = msgpack.Unpacker(stream, raw=False)
+
+    # First object always contains env
+    header = next(unpacker)
+    env = TraceEnvironment.from_json(header['env'])
+    addresses = header.get('addresses')
+
+    def state_iter():
+        for obj in unpacker:
+            t = SymbolicTransform.from_json(obj['state'])
+            yield t
+
+    return Trace(state_iter(), addresses, env)
+
+def serialize_transformations(trace: Trace[SymbolicTransform],
+                              out_file: str,
+                              out_type: Literal['msgpack', 'json'] = 'json'):
     """Serialize symbolic transformations to a text stream."""
-    data = json.dumps({
-        'env': transforms.env.to_json(),
-        'addrs': transforms.addresses,
-        'states': [t.to_json() for t in transforms],
-    }, option=json.OPT_INDENT_2).decode()
-    out_stream.write(data)
+    if out_type == 'json':
+        with open(out_file, 'w') as out_stream:
+            data = json.dumps({
+                'env': trace.env.to_json(),
+                'addrs': trace.addresses,
+                'states': [t.to_json() for t in trace],
+            }, option=json.OPT_INDENT_2).decode()
+            out_stream.write(data)
+    elif out_type == 'msgpack':
+        with open(out_file, 'wb') as out_stream:
+            pack = msgpack.Packer()
+
+            # Header: env + addresses (list[int])
+            header = {
+                "env": trace.env.to_json(),
+                "addresses": getattr(trace, "addresses", None),
+            }
+            out_stream.write(pack.pack(header))
+
+            # States streamed one by one
+            for state in trace:
+                out_stream.write(pack.pack({"state": state.to_json()}))
+    else:
+        raise NotImplementedError(f'Unable to write transformations to type {out_type}')
 
 def parse_snapshots(json_stream: TextIO) -> TraceContainer[ProgramState]:
     """Parse snapshots from our JSON format."""
diff --git a/src/focaccia/qemu/_qemu_tool.py b/src/focaccia/qemu/_qemu_tool.py
index 42f1628..7f1d108 100644
--- a/src/focaccia/qemu/_qemu_tool.py
+++ b/src/focaccia/qemu/_qemu_tool.py
@@ -261,8 +261,12 @@ def main():
 
     # Read pre-computed symbolic trace
     try:
-        with open(args.symb_trace, 'r') as strace:
-            symb_transforms = parser.parse_transformations(strace)
+        if args.trace_type == 'json':
+            file = open(args.symb_trace, 'r')
+            symb_transforms = parser.parse_transformations(file)
+        else:
+            file = open(args.symb_trace, 'rb')
+            symb_transforms = parser.stream_transformation(file)
     except Exception as e:
         raise Exception(f'Failed to parse state transformations from native trace: {e}')
 
diff --git a/src/focaccia/tools/capture_transforms.py b/src/focaccia/tools/capture_transforms.py
index 268af36..d69c786 100755
--- a/src/focaccia/tools/capture_transforms.py
+++ b/src/focaccia/tools/capture_transforms.py
@@ -51,6 +51,10 @@ def main():
                       type=utils.to_num,
                       help='Set a time limit for executing an instruction symbolically, skip'
                            'instruction when limit is exceeded')
+    prog.add_argument('--out-type',
+                      default='json',
+                      choices=['json', 'msgpack'],
+                      help='Symbolic trace output format')
     args = prog.parse_args()
 
     if args.debug:
@@ -77,6 +81,5 @@ def main():
 
     trace = tracer.trace(time_limit=args.insn_time_limit)
 
-    with open(args.output, 'w') as file:
-        parser.serialize_transformations(trace, file)
+    parser.serialize_transformations(trace, args.output, args.out_type)
 
diff --git a/src/focaccia/tools/validate_qemu.py b/src/focaccia/tools/validate_qemu.py
index 4b5160f..1d713bd 100755
--- a/src/focaccia/tools/validate_qemu.py
+++ b/src/focaccia/tools/validate_qemu.py
@@ -86,6 +86,10 @@ memory, and stepping forward by single instructions.
                       help='GDB binary to invoke.')
     prog.add_argument('--deterministic-log', default=None,
                       help='The directory containing rr traces')
+    prog.add_argument('--trace-type',
+                      default='json',
+                      choices=['msgpack', 'json'],
+                      help='The format of the input symbolic trace')
     return prog
 
 def quoted(s: str) -> str: