diff options
| -rw-r--r-- | src/focaccia/deterministic.py | 10 | ||||
| -rw-r--r-- | src/focaccia/qemu/_qemu_tool.py | 67 |
2 files changed, 72 insertions, 5 deletions
diff --git a/src/focaccia/deterministic.py b/src/focaccia/deterministic.py index 1cfda0d..ffd519c 100644 --- a/src/focaccia/deterministic.py +++ b/src/focaccia/deterministic.py @@ -180,7 +180,8 @@ class MemoryMapping: source: str, offset: int, mmap_prot: int, - mmap_flags: int): + mmap_flags: int, + name: str | None = None): self.event_count = event_count self.start_address = start_address self.length = end_address - self.start_address @@ -188,10 +189,13 @@ class MemoryMapping: self.offset = offset self.mmap_prot = mmap_prot self.mmap_flags = mmap_flags + self.name = name def __repr__(self) -> str: - return f'Memory mapping at event {self.event_count}\n' \ - f'start = {hex(self.start_address)}\n' \ + header = f'Memory mapping at event {self.event_count}\n' + if self.name: + header += f'name = {self.name}\n' + return header + f'start = {hex(self.start_address)}\n' \ f'length = {self.length}\n' \ f'source = {self.source}\n' \ f'offset = {self.offset}\n' \ diff --git a/src/focaccia/qemu/_qemu_tool.py b/src/focaccia/qemu/_qemu_tool.py index 188ecf2..e6394e5 100644 --- a/src/focaccia/qemu/_qemu_tool.py +++ b/src/focaccia/qemu/_qemu_tool.py @@ -6,6 +6,7 @@ But please use `tools/validate_qemu.py` instead because we have some more setup work to do. """ +import re import gdb import logging import traceback @@ -156,11 +157,13 @@ class GDBServerStateIterator: self.arch = supported_architectures[archname] self.binary = self._process.progspace.filename + first_state = self.current_state() self._log_matcher = LogStateMatcher(self._deterministic_log.events(), self._deterministic_log.mmaps(), match_event, - from_state=self.current_state()) - info(f'Synchronizing at PC {hex(self.current_state().read_pc())} with {self._log_matcher.matched_events()}') + from_state=first_state) + event, _ = self._log_matcher.match(first_state) + info(f'Synchronized at PC={hex(first_state.read_pc())} to event:\n{event}') def current_state(self) -> ReadableProgramState: return GDBProgramState(self._process, gdb.selected_frame(), self.arch) @@ -272,6 +275,66 @@ class GDBServerStateIterator: def _step(self): gdb.execute('si', to_string=True) + def get_sections(self) -> list[MemoryMapping]: + mappings = [] + + # Skip everything until the header line + started = False + + text = gdb.execute('info proc mappings', to_string=True) + for line in text.splitlines(): + line = line.strip() + if not line: + continue + + # Detect header line once + if line.startswith("Start Addr"): + started = True + continue + + if not started: + continue + + # Lines look like: + # 0x0000000000400000 0x0000000000401000 0x1000 0x0 r--p /path + # or: + # 0x... 0x... 0x... 0x... rw-p [vdso] + parts = line.split(None, 6) + + if len(parts) < 5: + continue + + start = int(parts[0], 16) + end = int(parts[1], 16) + size = int(parts[2], 16) + offset = int(parts[3], 16) + perms = parts[4] + + file_or_tag = None + is_special = False + + if len(parts) >= 6: + tail = parts[5] + + # If it's [tag], mark as special + if tail.startswith("[") and tail.endswith("]"): + file_or_tag = tail.strip() + is_special = True + else: + # Might be a filename or absent + file_or_tag = tail + + mapping = MemoryMapping(0, + start, + end, + '', + offset, + 0, + 0) + mappings.append(mapping) + + return mappings + def record_minimal_snapshot(prev_state: ReadableProgramState, cur_state: ReadableProgramState, prev_transform: SymbolicTransform, |