diff --git a/qiling/extensions/r2/mem.py b/qiling/extensions/r2/mem.py index 7bfbd91e4..bfb9d64d7 100644 --- a/qiling/extensions/r2/mem.py +++ b/qiling/extensions/r2/mem.py @@ -10,7 +10,7 @@ class R2Mem(QlMemoryManager): '''A wrapper for QlMemoryManager that uses map_ptr and store raw memory in map_info - NOTE: ql.mem already contains map_infor after loader.run(), so instead of super().__init__(), + NOTE: ql.mem already contains map_info after loader.run(), so instead of super().__init__(), we accept mem object to simulate inheritance by composition ''' @@ -43,14 +43,12 @@ def map(self, addr: int, size: int, perms: int = UC_PROT_ALL, info: Optional[str """ assert perms & ~UC_PROT_ALL == 0, f'unexpected permissions mask {perms}' - + if not self.is_available(addr, size): - for line in self.get_formatted_mapinfo(): - print(line) raise QlMemoryMappedError(f'Requested memory {addr:#x} + {size:#x} is unavailable') - buf = self.map_ptr(addr, size, perms, ptr) - self.add_mapinfo(addr, addr + size, perms, info or '[mapped]', is_mmio=False, data=buf) + self.map_ptr(addr, size, perms, ptr) + self.add_mapinfo(addr, addr + size, perms, info or '[mapped]', is_mmio=False) def map_ptr(self, addr: int, size: int, perms: int = UC_PROT_ALL, buf: Optional[bytearray] = None) -> bytearray: """Map a new memory range allocated as Python bytearray, will not affect map_info @@ -67,123 +65,6 @@ def map_ptr(self, addr: int, size: int, perms: int = UC_PROT_ALL, buf: Optional[ buf = buf or bytearray(size) buf_type = ctypes.c_ubyte * size cdata = buf_type.from_buffer(buf) - self.cmap[addr] = cdata + self.cmap[addr] = cdata # NOTE: will memory leak or invalid reference happen if not updated when splitting memory? self.ql.uc.mem_map_ptr(addr, size, perms, cdata) return buf - - def add_mapinfo(self, mem_s: int, mem_e: int, mem_p: int, mem_info: str, is_mmio: bool = False, data : bytearray = None): - """Add a new memory range to map. - - Args: - mem_s: memory range start - mem_e: memory range end - mem_p: permissions mask - mem_info: map entry label - is_mmio: memory range is mmio - """ - self.map_info.append((mem_s, mem_e, mem_p, mem_info, is_mmio, data)) - self.map_info.sort(key=lambda tp: tp[0]) - - def del_mapinfo(self, mem_s: int, mem_e: int): - """Subtract a memory range from map, will destroy data and unmap uc mem in the range. - - Args: - mem_s: memory range start - mem_e: memory range end - """ - - tmp_map_info: MutableSequence[MapInfoEntry] = [] - - for s, e, p, info, mmio, data in self.map_info: - if e <= mem_s: - tmp_map_info.append((s, e, p, info, mmio, data)) - continue - - if s >= mem_e: - tmp_map_info.append((s, e, p, info, mmio, data)) - continue - - del self.cmap[s] # remove cdata reference starting at s - if s < mem_s: - self.ql.uc.mem_unmap(s, mem_s - s) - self.map_ptr(s, mem_s - s, p, data[:mem_s - s]) - tmp_map_info.append((s, mem_s, p, info, mmio, data[:mem_s - s])) - - if s == mem_s: - pass - - if e > mem_e: - self.ql.uc.mem_unmap(mem_e, e - mem_e) - self.map_ptr(mem_e, e - mem_e, p, data[mem_e - e:]) - tmp_map_info.append((mem_e, e, p, info, mmio, data[mem_e - e:])) - - if e == mem_e: - pass - - del data[mem_s - s:mem_e - s] - - self.map_info = tmp_map_info - - def change_mapinfo(self, mem_s: int, mem_e: int, mem_p: Optional[int] = None, mem_info: Optional[str] = None, data: Optional[bytearray] = None): - tmp_map_info: Optional[MapInfoEntry] = None - info_idx: int = None - - for idx, map_info in enumerate(self.map_info): - if mem_s >= map_info[0] and mem_e <= map_info[1]: - tmp_map_info = map_info - info_idx = idx - break - - if tmp_map_info is None: - self.ql.log.error(f'Cannot change mapinfo at {mem_s:#08x}-{mem_e:#08x}') - return - - if mem_p is not None: - data = data or self.read(mem_s, mem_e - mem_s).copy() - assert(len(data) == mem_e - mem_s) - self.unmap(mem_s, mem_e - mem_s) - self.map_ptr(mem_s, mem_e - mem_s, mem_p, data) - self.add_mapinfo(mem_s, mem_e, mem_p, mem_info or tmp_map_info[3], tmp_map_info[4], data) - return - - if mem_info is not None: - self.map_info[info_idx] = (tmp_map_info[0], tmp_map_info[1], tmp_map_info[2], mem_info, tmp_map_info[4], tmp_map_info[5]) - - def save(self): - """Save entire memory content. - """ - - mem_dict = { - "ram" : [], - "mmio" : [] - } - - for lbound, ubound, perm, label, is_mmio, data in self.map_info: - if is_mmio: - mem_dict['mmio'].append((lbound, ubound, perm, label, *self.mmio_cbs[(lbound, ubound)])) - else: - data = self.read(lbound, ubound - lbound) # read instead of using data from map_info to avoid error - mem_dict['ram'].append((lbound, ubound, perm, label, data)) - - return mem_dict - - def restore(self, mem_dict): - """Restore saved memory content. - """ - - for lbound, ubound, perms, label, data in mem_dict['ram']: - self.ql.log.debug(f'restoring memory range: {lbound:#08x} {ubound:#08x} {label}') - - size = ubound - lbound - if self.is_available(lbound, size): - self.ql.log.debug(f'mapping {lbound:#08x} {ubound:#08x}, mapsize = {size:#x}') - self.map(lbound, size, perms, label, data) - - self.ql.log.debug(f'writing {len(data):#x} bytes at {lbound:#08x}') - self.write(lbound, bytes(data)) - - for lbound, ubound, perms, label, read_cb, write_cb in mem_dict['mmio']: - self.ql.log.debug(f"restoring mmio range: {lbound:#08x} {ubound:#08x} {label}") - - #TODO: Handle overlapped MMIO? - self.map_mmio(lbound, ubound - lbound, read_cb, write_cb, info=label) diff --git a/qiling/extensions/r2/r2.py b/qiling/extensions/r2/r2.py index 79c3ea19e..20564fc30 100644 --- a/qiling/extensions/r2/r2.py +++ b/qiling/extensions/r2/r2.py @@ -246,7 +246,7 @@ def _rbuf_map(self, cbuf: ctypes.Array, perm: int = UC_PROT_ALL, addr: int = 0, def _setup_mem(self, ql: 'R2Qiling'): if not hasattr(ql, '_mem'): return - for start, _end, perms, _label, _mmio, _buf in ql.mem.map_info: + for start, _end, perms, _label, _mmio in ql.mem.map_info: cbuf = ql.mem.cmap[start] self._rbuf_map(cbuf, perms, start) # set architecture and bits for r2 asm