diff options
| author | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-11-07 10:27:31 +0000 |
|---|---|---|
| committer | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-11-07 10:27:31 +0000 |
| commit | 7453b5b6e8931dccf5763a5aa0d18777922b2cb7 (patch) | |
| tree | 222abf0ad211638ceae0e9688e34bc0f82c8d366 /src | |
| parent | cfd9715eeff97c11ebc3f78288f9f516c79b0663 (diff) | |
| download | focaccia-7453b5b6e8931dccf5763a5aa0d18777922b2cb7.tar.gz focaccia-7453b5b6e8931dccf5763a5aa0d18777922b2cb7.zip | |
Enable high-level interface for reading mmaps and tasks
Diffstat (limited to 'src')
| -rw-r--r-- | src/focaccia/deterministic.py | 164 |
1 files changed, 159 insertions, 5 deletions
diff --git a/src/focaccia/deterministic.py b/src/focaccia/deterministic.py index 5a2b411..dfc48a3 100644 --- a/src/focaccia/deterministic.py +++ b/src/focaccia/deterministic.py @@ -1,8 +1,7 @@ """Parsing of JSON files containing snapshot data.""" import os -import itertools -from typing import Union, Iterable +from typing import Union import brotli @@ -138,6 +137,109 @@ class Event: return repr_str +class MemoryMapping: + def __init__(self, + event_count: int, + start_address: int, + end_address: int, + source: str, + offset: int, + mmap_prot: int, + mmap_flags: int): + self.event_count = event_count + self.start_address = start_address + self.length = end_address - self.start_address + self.source = source + self.offset = offset + self.mmap_prot = mmap_prot + self.mmap_flags = mmap_flags + + def __repr__(self) -> str: + return f'Memory mapping at event {self.event_count}\n' \ + f'start = {hex(self.start_address)}\n' \ + f'length = {self.length}\n' \ + f'source = {self.source}\n' \ + f'offset = {self.offset}\n' \ + f'mmap_prot = {hex(self.mmap_prot)}\n' \ + f'mmap_flags = {hex(self.mmap_flags)}' + +class Task: + def __init__(self, + event_count: int, + tid: int): + self.event_count = event_count + self.tid = tid + + def __repr__(self) -> str: + return f'For event index {self.event_count} at tid = {hex(self.tid)}' + +class CloneTask(Task): + def __init__(self, + event_count: int, + tid: int, + parent_tid: int, + clone_flags: int, + own_namespace_tid: int): + super().__init__(event_count, tid) + self.parent_tid = parent_tid + self.clone_flags = clone_flags + self.own_namespace_tid = own_namespace_tid + + def __repr__(self) -> str: + repr_str = f'Clone task\n{super().__repr__()}\n' + repr_str += f'parent tid = {hex(self.parent_tid)}\n' \ + f'clone flags = {hex(self.clone_flags)}\n' \ + f'own namespace tid = {hex(self.own_namespace_tid)}' + return repr_str + +class ExecTask(Task): + def __init__(self, + event_count: int, + tid: int, + filename: str, + commandline: list[str], + execution_base_address: int, + interpreter_base_address: int, + interpreter_name: str): + super().__init__(event_count, tid) + self.filename = filename + self.commandline = commandline + self.execution_base_address = execution_base_address + self.interpreter_base_address = interpreter_base_address + self.interpreter_name = interpreter_name + + def __repr__(self): + repr_str = f'Exec task\n{super().__repr__()}\n' + repr_str += f'filename = {self.filename}\n' \ + f'command-line = {self.commandline}\n' \ + f'execution base address = {hex(self.execution_base_address)}\n' \ + f'interpereter base address = {hex(self.interpreter_base_address)}\n' \ + f'interpreter name = {self.interpreter_name}' + return repr_str + +class ExitTask(Task): + def __init__(self, + event_count: int, + tid: int, + exit_status: int): + super().__init__(event_count, tid) + self.exit_status = exit_status + + def __repr__(self): + repr_str = f'Exit task\n{super().__repr__()}\n' + repr_str += f'exit status = {hex(self.exit_status)}' + return repr_str + +class DetachTask(Task): + def __init__(self, + event_count: int, + tid: int): + super().__init__(event_count, tid) + + def __repr__(self): + repr_str = f'Detach task\n{super().__repr__()}' + return repr_str + class DeterministicLog: def __init__(self, log_dir: str): self.base_directory = log_dir @@ -176,13 +278,13 @@ class DeterministicLog: objects.append(deser) return objects - def raw_events(self) -> list[SerializedObject]: + def raw_events(self) -> list[Frame]: return self._read(self.events_file(), Frame) - def raw_tasks(self) -> list[SerializedObject]: + def raw_tasks(self) -> list[TaskEvent]: return self._read(self.tasks_file(), TaskEvent) - def raw_mmaps(self) -> list[SerializedObject]: + def raw_mmaps(self) -> list[MMap]: return self._read(self.mmaps_file(), MMap) def events(self) -> list[Event]: @@ -224,3 +326,55 @@ class DeterministicLog: return events + def tasks(self) -> list[Task]: + tasks = [] + raw_tasks = self.raw_tasks() + for raw_task in raw_tasks: + task_type = raw_task.which() + + task = None + if task_type == 'clone': + task = CloneTask(raw_task.frameTime, + raw_task.tid, + raw_task.clone.parentTid, + raw_task.clone.flags, + raw_task.clone.ownNsTid) + if task_type == 'exec': + task = ExecTask(raw_task.frameTime, + raw_task.tid, + raw_task.exec.fileName, + raw_task.exec.cmdLine, + raw_task.exec.exeBase, + raw_task.exec.interpBase, + raw_task.exec.interpName) + if task_type == 'exit': + task = ExitTask(raw_task.frameTime, raw_task.tid, raw_task.exit.exitStatus) + if task_type == 'detach': + task = DetachTask(raw_task.frameTime, raw_task.tid) + tasks.append(task) + return tasks + + def mmaps(self) -> list[MemoryMapping]: + def mapping_source(mmap: MMap) -> str: + source_type = mmap.source.which() + if source_type == 'zero' or source_type == 'trace': + return source_type + elif source_type == 'file': + return mmap.source.file.backingFileName + else: + raise NotImplementedError(f'Unable to handle memory mappings from source type:' + f' {source_type}') + + mmaps = [] + raw_mmaps = self.raw_mmaps() + for raw_mmap in raw_mmaps: + mmap = MemoryMapping(raw_mmap.frameTime, + raw_mmap.start, + raw_mmap.end, + mapping_source(raw_mmap), + raw_mmap.fileOffsetBytes, + raw_mmap.prot, + raw_mmap.flags) + mmaps.append(mmap) + return mmaps + |