about summary refs log tree commit diff stats
path: root/tools/qemu_tool.py
diff options
context:
space:
mode:
authorTheofilos Augoustis <theofilos.augoustis@gmail.com>2024-01-30 17:15:37 +0100
committerTheofilos Augoustis <theofilos.augoustis@gmail.com>2024-01-30 17:15:37 +0100
commit6471febedbdf5d0b4d14d75eafcf75ae48022c61 (patch)
treebe31073c3cda145c368919eb24a0de3f7def4d67 /tools/qemu_tool.py
parenta0a317e7d6c74005be94fef0711def86e57a616b (diff)
downloadfocaccia-6471febedbdf5d0b4d14d75eafcf75ae48022c61.tar.gz
focaccia-6471febedbdf5d0b4d14d75eafcf75ae48022c61.zip
Verify QEMU by abstracting over inconsistencies in trace logs via matching algorithm
Co-authored-by: Theofilos Augoustis <theofilos.augoustis@gmail.com>
Co-authored-by: Nicola Crivellin <nicola.crivellin98@gmail.com>
Diffstat (limited to 'tools/qemu_tool.py')
-rw-r--r--tools/qemu_tool.py125
1 files changed, 0 insertions, 125 deletions
diff --git a/tools/qemu_tool.py b/tools/qemu_tool.py
deleted file mode 100644
index d670692..0000000
--- a/tools/qemu_tool.py
+++ /dev/null
@@ -1,125 +0,0 @@
-"""Invocable like this:
-
-    gdb -n --batch -x qemu_tool.py
-"""
-
-import gdb
-import platform
-
-import focaccia.parser as parser
-from focaccia.arch import supported_architectures, Arch
-from focaccia.compare import compare_symbolic, ErrorTypes
-from focaccia.snapshot import ProgramState
-from focaccia.symbolic import SymbolicTransform, eval_symbol
-from focaccia.utils import print_result
-
-from verify_qemu import make_argparser
-
-class GDBProgramState:
-    def __init__(self, process: gdb.Inferior, frame: gdb.Frame):
-        self._proc = process
-        self._frame = frame
-
-    def read_register(self, regname: str) -> int | None:
-        try:
-            return int(self._frame.read_register(regname.lower()))
-        except ValueError as err:
-            from focaccia.arch import x86
-            rflags = int(self._frame.read_register('eflags'))
-            rflags = x86.decompose_rflags(rflags)
-            if regname in rflags:
-                return rflags[regname]
-
-            print(f'{regname}: {err}')
-            return None
-
-    def read_memory(self, addr: int, size: int) -> bytes | None:
-        try:
-            return self._proc.read_memory(addr, size).tobytes()
-        except gdb.MemoryError as err:
-            print(f'@{size}[{hex(addr)}]: {err}')
-            return None
-
-class GDBServerStateIterator:
-    def __init__(self, address: str, port: int):
-        gdb.execute('set pagination 0')
-        gdb.execute('set sysroot')
-        gdb.execute(f'target remote {address}:{port}')
-        self._process = gdb.selected_inferior()
-        self._first_next = True
-
-    def __iter__(self):
-        return self
-
-    def __next__(self):
-        # The first call to __next__ should yield the first program state,
-        # i.e. before stepping the first time
-        if self._first_next:
-            self._first_next = False
-            return GDBProgramState(self._process, gdb.selected_frame())
-
-        # Step
-        pc = gdb.selected_frame().read_register('pc')
-        new_pc = pc
-        while pc == new_pc:
-            gdb.execute('si', to_string=True)
-            if not self._process.is_valid() or len(self._process.threads()) == 0:
-                raise StopIteration
-            new_pc = gdb.selected_frame().read_register('pc')
-
-        return GDBProgramState(self._process, gdb.selected_frame())
-
-def collect_conc_trace(arch: Arch, \
-                       gdb: GDBServerStateIterator, \
-                       strace: list[SymbolicTransform]) \
-        -> list[ProgramState]:
-    states = []
-    for qemu, transform in zip(gdb, strace):
-        qemu_pc = qemu.read_register('pc')
-        assert(qemu_pc is not None)
-
-        if qemu_pc != transform.addr:
-            print(f'Fatal error: QEMU\'s program counter'
-                  f' ({hex(qemu_pc)}) does not match the'
-                  f' expected program counter in the symbolic trace'
-                  f' ({hex(transform.addr)}).')
-            print(f'Processing only partial trace up to this instruction.')
-            return states
-
-        state = ProgramState(arch)
-        state.set_register('PC', transform.addr)
-
-        accessed_regs = transform.get_used_registers()
-        accessed_mems = transform.get_used_memory_addresses()
-        for regname in accessed_regs:
-            regval = qemu.read_register(regname)
-            if regval is not None:
-                state.set_register(regname, regval)
-        for mem in accessed_mems:
-            assert(mem.size % 8 == 0)
-            addr = eval_symbol(mem.ptr, qemu)
-            mem = qemu.read_memory(addr, int(mem.size / 8))
-            if mem is not None:
-                state.write_memory(addr, mem)
-        states.append(state)
-
-    return states
-
-def main():
-    args = make_argparser().parse_args()
-
-    gdbserver_port = args.gdbserver_port
-    with open(args.symb_trace, 'r') as strace:
-        symb_transforms = parser.parse_transformations(strace)
-
-    arch = supported_architectures[platform.machine()]
-    conc_states = collect_conc_trace(
-        arch,
-        GDBServerStateIterator('localhost', gdbserver_port),
-        symb_transforms)
-
-    res = compare_symbolic(conc_states, symb_transforms)
-    print_result(res, ErrorTypes.POSSIBLE)
-
-if __name__ == "__main__":
-    main()