1# Copyright (c) 2013-2016 Jeffrey Pfau 2# 3# This Source Code Form is subject to the terms of the Mozilla Public 4# License, v. 2.0. If a copy of the MPL was not distributed with this 5# file, You can obtain one at http://mozilla.org/MPL/2.0/. 6from ._pylib import ffi, lib # pylint: disable=no-name-in-module 7 8 9class MemoryView(object): 10 def __init__(self, core, width, size, base=0, sign="u"): 11 self._core = core 12 self._width = width 13 self._size = size 14 self._base = base 15 self._bus_read = getattr(self._core, "busRead" + str(width * 8)) 16 self._bus_write = getattr(self._core, "busWrite" + str(width * 8)) 17 self._raw_read = getattr(self._core, "rawRead" + str(width * 8)) 18 self._raw_write = getattr(self._core, "rawWrite" + str(width * 8)) 19 self._mask = (1 << (width * 8)) - 1 # Used to force values to fit within range so that negative values work 20 if sign == "u" or sign == "unsigned": 21 self._type = "uint{}_t".format(width * 8) 22 elif sign == "i" or sign == "s" or sign == "signed": 23 self._type = "int{}_t".format(width * 8) 24 else: 25 raise ValueError("Invalid sign type: '{}'".format(sign)) 26 27 def _addr_check(self, address): 28 if isinstance(address, slice): 29 start = address.start or 0 30 stop = self._size - self._width if address.stop is None else address.stop 31 else: 32 start = address 33 stop = address + self._width 34 if start >= self._size or stop > self._size: 35 raise IndexError() 36 if start < 0 or stop < 0: 37 raise IndexError() 38 39 def __len__(self): 40 return self._size 41 42 def __getitem__(self, address): 43 self._addr_check(address) 44 if isinstance(address, slice): 45 start = address.start or 0 46 stop = self._size - self._width if address.stop is None else address.stop 47 step = address.step or self._width 48 return [int(ffi.cast(self._type, self._bus_read(self._core, self._base + a))) for a in range(start, stop, step)] 49 return int(ffi.cast(self._type, self._bus_read(self._core, self._base + address))) 50 51 def __setitem__(self, address, value): 52 self._addr_check(address) 53 if isinstance(address, slice): 54 start = address.start or 0 55 stop = self._size - self._width if address.stop is None else address.stop 56 step = address.step or self._width 57 for addr in range(start, stop, step): 58 self._bus_write(self._core, self._base + addr, value[addr] & self._mask) 59 else: 60 self._bus_write(self._core, self._base + address, value & self._mask) 61 62 def raw_read(self, address, segment=-1): 63 self._addr_check(address) 64 return int(ffi.cast(self._type, self._raw_read(self._core, self._base + address, segment))) 65 66 def raw_write(self, address, value, segment=-1): 67 self._addr_check(address) 68 self._raw_write(self._core, self._base + address, segment, value & self._mask) 69 70 71class MemorySearchResult(object): 72 def __init__(self, memory, result): 73 self.address = result.address 74 self.segment = result.segment 75 self.guessDivisor = result.guessDivisor 76 self.type = result.type 77 78 if result.type == Memory.SEARCH_INT: 79 if result.width == 1: 80 self._memory = memory.u8 81 elif result.width == 2: 82 self._memory = memory.u16 83 elif result.width == 4: 84 self._memory = memory.u32 85 elif result.type == Memory.SEARCH_STRING: 86 self._memory = memory.u8 87 else: 88 raise ValueError("Unknown type: %X" % result.type) 89 90 @property 91 def value(self): 92 if self.type == Memory.SEARCH_STRING: 93 raise ValueError 94 return self._memory[self.address] * self.guessDivisor 95 96 @value.setter 97 def value(self, v): 98 if self.type == Memory.SEARCH_STRING: 99 raise IndexError 100 self._memory[self.address] = v // self.guessDivisor 101 102 103class Memory(object): 104 SEARCH_INT = lib.mCORE_MEMORY_SEARCH_INT 105 SEARCH_STRING = lib.mCORE_MEMORY_SEARCH_STRING 106 SEARCH_GUESS = lib.mCORE_MEMORY_SEARCH_GUESS 107 108 SEARCH_EQUAL = lib.mCORE_MEMORY_SEARCH_EQUAL 109 110 READ = lib.mCORE_MEMORY_READ 111 WRITE = lib.mCORE_MEMORY_READ 112 RW = lib.mCORE_MEMORY_RW 113 114 def __init__(self, core, size, base=0): 115 self.size = size 116 self.base = base 117 self._core = core 118 119 self.u8 = MemoryView(core, 1, size, base, "u") 120 self.u16 = MemoryView(core, 2, size, base, "u") 121 self.u32 = MemoryView(core, 4, size, base, "u") 122 self.s8 = MemoryView(core, 1, size, base, "s") 123 self.s16 = MemoryView(core, 2, size, base, "s") 124 self.s32 = MemoryView(core, 4, size, base, "s") 125 126 def __len__(self): 127 return self.size 128 129 def search(self, value, type=SEARCH_GUESS, flags=RW, limit=10000, old_results=[]): 130 results = ffi.new("struct mCoreMemorySearchResults*") 131 lib.mCoreMemorySearchResultsInit(results, len(old_results)) 132 params = ffi.new("struct mCoreMemorySearchParams*") 133 params.memoryFlags = flags 134 params.type = type 135 params.op = self.SEARCH_EQUAL 136 if type == self.SEARCH_INT: 137 params.valueInt = int(value) 138 else: 139 params.valueStr = ffi.new("char[]", str(value).encode("ascii")) 140 141 for result in old_results: 142 native_result = lib.mCoreMemorySearchResultsAppend(results) 143 native_result.address = result.address 144 native_result.segment = result.segment 145 native_result.guessDivisor = result.guessDivisor 146 native_result.type = result.type 147 if old_results: 148 lib.mCoreMemorySearchRepeat(self._core, params, results) 149 else: 150 lib.mCoreMemorySearch(self._core, params, results, limit) 151 new_results = [MemorySearchResult(self, lib.mCoreMemorySearchResultsGetPointer(results, i)) for i in range(lib.mCoreMemorySearchResultsSize(results))] 152 lib.mCoreMemorySearchResultsDeinit(results) 153 return new_results 154 155 def __getitem__(self, address): 156 if isinstance(address, slice): 157 return bytearray(self.u8[address]) 158 return self.u8[address] 159