diff options
Diffstat (limited to 'focaccia.py')
| -rwxr-xr-x | focaccia.py | 54 |
1 files changed, 46 insertions, 8 deletions
diff --git a/focaccia.py b/focaccia.py index bf5a9ff..0637690 100755 --- a/focaccia.py +++ b/focaccia.py @@ -1,17 +1,21 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 import argparse import platform -from typing import Iterable +from typing import Iterable, Tuple from focaccia.arch import supported_architectures from focaccia.compare import compare_simple, compare_symbolic, ErrorTypes from focaccia.lldb_target import LLDBConcreteTarget -from focaccia.match import fold_traces -from focaccia.parser import parse_arancini +from focaccia.match import fold_traces, match_traces +from focaccia.parser import parse_arancini, parse_snapshots from focaccia.snapshot import ProgramState from focaccia.symbolic import collect_symbolic_trace from focaccia.utils import print_result +from focaccia.reproducer import Reproducer +from focaccia.compare import ErrorSeverity + + verbosity = { 'info': ErrorTypes.INFO, @@ -20,7 +24,7 @@ verbosity = { } def collect_concrete_trace(oracle_program: str, breakpoints: Iterable[int]) \ - -> list[ProgramState]: + -> Tuple[list[ProgramState], list]: """Gather snapshots from a native execution via an external debugger. :param oracle_program: Program to execute. @@ -37,11 +41,13 @@ def collect_concrete_trace(oracle_program: str, breakpoints: Iterable[int]) \ # Execute the native program snapshots = [] + basic_blocks = [] while not target.is_exited(): snapshots.append(target.record_snapshot()) + basic_blocks.append(target.get_next_basic_block()) target.run() - return snapshots + return snapshots, basic_blocks def parse_arguments(): parser = argparse.ArgumentParser(description='Comparator for emulator logs to reference') @@ -77,9 +83,32 @@ def parse_arguments(): ' may as well stem from incomplete input data.' ' \'info\' will report absolutely everything.' ' [Default: warning]') + parser.add_argument('-r', '--reproducer', + action='store_true', + default=False, + help='Enable reproducer to get assembly code' + ' which should replicate the first error.') + parser.add_argument('--trace-type', + type=str, + default='qemu', + choices=['qemu', 'arancini'], + help='Trace type of the emulator.' + ' Currently only Qemu and Arancini traces are accepted.' + ' Use \'qemu\' for Qemu and \'arancini\' for Arancini.' + ' [Default: qemu]') args = parser.parse_args() return args +def print_reproducer(result, min_severity: ErrorSeverity, oracle, oracle_args): + for res in result: + errs = [e for e in res['errors'] if e.severity >= min_severity] + #breakpoint() + if errs: + rep = Reproducer(oracle, oracle_args, res['snap'], res['ref']) + print(rep.asm()) + return + + def main(): args = parse_arguments() @@ -97,13 +126,19 @@ def main(): # Parse reference trace with open(txl_path, "r") as txl_file: - test_states = parse_arancini(txl_file, arch) + if args.trace_type == 'qemu': + test_states = parse_snapshots(txl_file) + elif args.trace_type == 'arancini': + test_states = parse_arancini(txl_file, arch) + else: + test_states = parse_snapshots(txl_file) # Compare reference trace to a truth if args.symbolic: print(f'Tracing {oracle} symbolically with arguments {oracle_args}...') transforms = collect_symbolic_trace(oracle, oracle_args) - fold_traces(test_states, transforms) + test_states, transforms = match_traces(test_states, transforms) + #fold_traces(test_states, transforms) result = compare_symbolic(test_states, transforms) else: # Record truth states from a concrete execution of the oracle @@ -113,5 +148,8 @@ def main(): print_result(result, verbosity[args.error_level]) + if args.reproducer: + print_reproducer(result, verbosity[args.error_level], oracle, oracle_args) + if __name__ == '__main__': main() |