about summary refs log tree commit diff stats
path: root/snapshot.py
diff options
context:
space:
mode:
authorTheofilos Augoustis <theofilos.augoustis@gmail.com>2023-12-31 18:29:31 +0100
committerTheofilos Augoustis <theofilos.augoustis@gmail.com>2023-12-31 18:29:31 +0100
commiteae0b3b08bd078ad2f621ce2ef201e656da3f16a (patch)
treeeb93252f39543c46146297264ff548d9925178e0 /snapshot.py
parentd26ae0a7d583da5034cd6271f953b6253119ceae (diff)
downloadfocaccia-eae0b3b08bd078ad2f621ce2ef201e656da3f16a.tar.gz
focaccia-eae0b3b08bd078ad2f621ce2ef201e656da3f16a.zip
Refactor project structure
Read concrete state on demand during concolic exec

During concolic tracing, don't record full program snapshots at each
basic block, but instead read concrete values directly from the concrete
target when they are needed.
Diffstat (limited to 'snapshot.py')
-rw-r--r--snapshot.py135
1 files changed, 0 insertions, 135 deletions
diff --git a/snapshot.py b/snapshot.py
deleted file mode 100644
index 9c9e4b3..0000000
--- a/snapshot.py
+++ /dev/null
@@ -1,135 +0,0 @@
-from arch.arch import Arch
-
-class MemoryAccessError(Exception):
-    def __init__(self, addr: int, size: int, msg: str):
-        super().__init__(msg)
-        self.mem_addr = addr
-        self.mem_size = size
-
-class SparseMemory:
-    """Sparse memory.
-
-    Note that out-of-bound reads are possible when performed on unwritten
-    sections of existing pages and that there is no safeguard check for them.
-    """
-    def __init__(self, page_size=4096):
-        self.page_size = page_size
-        self._pages: dict[int, bytes] = {}
-
-    def _to_page_addr_and_offset(self, addr: int) -> tuple[int, int]:
-        off = addr % self.page_size
-        return addr - off, off
-
-    def read(self, addr: int, size: int) -> bytes:
-        """Read a number of bytes from memory.
-        :param addr: The offset from where to read.
-        :param size: The number of bytes to read, starting at at `addr`.
-
-        :return: `size` bytes of data.
-        :raise MemoryAccessError: If `[addr, addr + size)` is not entirely
-                                  contained in the set of stored bytes.
-        :raise ValueError: If `size < 0`.
-        """
-        if size < 0:
-            raise ValueError(f'A negative size is not allowed!')
-
-        res = bytes()
-        while size > 0:
-            page_addr, off = self._to_page_addr_and_offset(addr)
-            if page_addr not in self._pages:
-                raise MemoryAccessError(addr, size,
-                                        f'Address {addr} is not contained in'
-                                        f' the sparse memory.')
-            data = self._pages[page_addr]
-            assert(len(data) == self.page_size)
-            read_size = min(size, self.page_size - off)
-            res += data[off:off+read_size]
-
-            size -= read_size
-            addr += read_size
-        return res
-
-    def write(self, addr: int, data: bytes):
-        """Store bytes in the memory.
-        :param addr: The address at which to store the data.
-        :param data: The data to store at `addr`.
-        """
-        offset = 0  # Current offset into `data`
-        while offset < len(data):
-            page_addr, off = self._to_page_addr_and_offset(addr)
-            if page_addr not in self._pages:
-                self._pages[page_addr] = bytes(self.page_size)
-            page = self._pages[page_addr]
-            assert(len(page) == self.page_size)
-
-            write_size = min(len(data) - offset, self.page_size - off)
-            new_page = page[:off] + data[offset:offset + write_size] + page[off+write_size:]
-            assert(len(new_page) == self.page_size)
-            self._pages[page_addr] = new_page
-
-            offset += write_size
-            addr += write_size
-
-        assert(len(data) == offset)  # Exactly all data was written
-
-class ProgramState:
-    """A snapshot of the program's state."""
-    def __init__(self, arch: Arch):
-        self.arch = arch
-
-        dict_t = dict[str, int | None]
-        self.regs: dict_t = { reg: None for reg in arch.regnames }
-        self.mem = SparseMemory()
-
-    def read(self, reg: str) -> int:
-        """Read a register's value.
-
-        :raise KeyError:   If `reg` is not a register name.
-        :raise ValueError: If the register has no value.
-        """
-        regname = self.arch.to_regname(reg)
-        if regname is None:
-            raise KeyError(f'Not a register name: {reg}')
-
-        assert(regname in self.regs)
-        regval = self.regs[regname]
-        if regval is None:
-            raise ValueError(f'Unable to read value of register {reg} (aka.'
-                             f' {regname}): The register contains no value.')
-        return regval
-
-    def set(self, reg: str, value: int):
-        """Assign a value to a register.
-
-        :raise KeyError: If `reg` is not a register name.
-        """
-        regname = self.arch.to_regname(reg)
-        if regname is None:
-            raise KeyError(f'Not a register name: {reg}')
-
-        self.regs[regname] = value
-
-    def read_memory(self, addr: int, size: int) -> bytes:
-        """Read a number of bytes from memory.
-
-        :param addr: The address from which to read data.
-        :param data: Number of bytes to read, starting at `addr`. Must be
-                     at least zero.
-
-        :raise MemoryAccessError: If `[addr, addr + size)` is not entirely
-                                  contained in the set of stored bytes.
-        :raise ValueError: If `size < 0`.
-        """
-        return self.mem.read(addr, size)
-
-    def write_memory(self, addr: int, data: bytes):
-        """Write a number of bytes to memory.
-
-        :param addr: The address at which to store the data.
-        :param data: The data to store at `addr`.
-        """
-        self.mem.write(addr, data)
-
-    def __repr__(self):
-        return f'Snapshot ({self.arch.archname}): ' \
-               + repr({r: hex(v) for r, v in self.regs.items() if v is not None})