diff options
| author | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-11-06 20:01:48 +0000 |
|---|---|---|
| committer | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-11-06 20:06:26 +0000 |
| commit | 19011ecfb472a1a61577f8a9ad622b1f2dd1ac39 (patch) | |
| tree | ac1b3b4a2c86c2e5beaa35134486d0f97f1b3b59 | |
| parent | bf283192197c971d84ad2766bd4b6f55e95e509a (diff) | |
| download | focaccia-19011ecfb472a1a61577f8a9ad622b1f2dd1ac39.tar.gz focaccia-19011ecfb472a1a61577f8a9ad622b1f2dd1ac39.zip | |
Fix QEMU partial validation support ta/fixup-qemu-partial-validation
| -rw-r--r-- | src/focaccia/tools/_qemu_tool.py | 27 | ||||
| -rw-r--r-- | src/focaccia/trace.py | 5 |
2 files changed, 23 insertions, 9 deletions
diff --git a/src/focaccia/tools/_qemu_tool.py b/src/focaccia/tools/_qemu_tool.py index 61fbb7c..cc97c95 100644 --- a/src/focaccia/tools/_qemu_tool.py +++ b/src/focaccia/tools/_qemu_tool.py @@ -154,6 +154,12 @@ class GDBServerStateIterator: return GDBProgramState(self._process, gdb.selected_frame(), self.arch) + def run_until(self, addr: int): + breakpoint = gdb.Breakpoint(f'*{addr:#x}') + gdb.execute('continue') + breakpoint.delete() + return GDBProgramState(self._process, gdb.selected_frame(), self.arch) + def record_minimal_snapshot(prev_state: ReadableProgramState, cur_state: ReadableProgramState, prev_transform: SymbolicTransform, @@ -261,13 +267,15 @@ def collect_conc_trace(gdb: GDBServerStateIterator, \ symb_i = 0 # Skip to start - pc = None - while start_addr: + try: pc = cur_state.read_register('pc') - if pc == start_addr: - info(f'Tracing QEMU from starting address: {start_addr}') - break - next(state_iter) + if start_addr and pc != start_addr: + info(f'Tracing QEMU from starting address: {hex(start_addr)}') + cur_state = state_iter.run_until(start_addr) + except Exception as e: + if start_addr: + raise Exception(f'Unable to reach start address {hex(start_addr)}: {e}') + raise Exception(f'Unable to trace: {e}') # An online trace matching algorithm. while True: @@ -275,6 +283,8 @@ def collect_conc_trace(gdb: GDBServerStateIterator, \ pc = cur_state.read_register('pc') while pc != strace[symb_i].addr: + info(f'PC {hex(pc)} does not match next symbolic reference {hex(strace[symb_i].addr)}') + next_i = find_index(strace[symb_i+1:], pc, lambda t: t.addr) # Drop the concrete state if no address in the symbolic trace @@ -293,6 +303,7 @@ def collect_conc_trace(gdb: GDBServerStateIterator, \ break assert(cur_state.read_register('pc') == strace[symb_i].addr) + info(f'Validating instruction at address {hex(pc)}') states.append(record_minimal_snapshot( states[-1] if states else cur_state, cur_state, @@ -354,8 +365,8 @@ def main(): conc_states, matched_transforms = collect_conc_trace( gdb_server, symb_transforms.states, - env.start_address, - env.stop_address) + symb_transforms.env.start_address, + symb_transforms.env.stop_address) except Exception as e: raise Exception(f'Failed to collect concolic trace from QEMU: {e}') diff --git a/src/focaccia/trace.py b/src/focaccia/trace.py index b488e6c..14c475b 100644 --- a/src/focaccia/trace.py +++ b/src/focaccia/trace.py @@ -34,6 +34,7 @@ class TraceEnvironment: json['argv'], json['envp'], json['binary_hash'], + None, json['start_address'], json['stop_address'] ) @@ -61,7 +62,9 @@ class TraceEnvironment: def __repr__(self) -> str: return f'{self.binary_name} {" ".join(self.argv)}' \ f'\n bin-hash={self.binary_hash}' \ - f'\n envp={repr(self.envp)}' + f'\n envp={repr(self.envp)}' \ + f'\n start_address={self.start_address}' \ + f'\n stop_address={self.stop_address}' class Trace(Generic[T]): def __init__(self, |