Package envi :: Module memory
[hide private]
[frames] | no frames]

Source Code for Module envi.memory

  1  import re 
  2  import struct 
  3   
  4  import envi 
  5   
  6  """ 
  7  A module containing memory utilities and the definition of the 
  8  memory access API used by all vtoys trace/emulators/workspaces. 
  9  """ 
 10   
 11  # Memory Map Permission Flags 
 12  MM_NONE = 0x0 
 13  MM_READ = 0x4 
 14  MM_WRITE = 0x2 
 15  MM_EXEC = 0x1 
 16  MM_SHARED = 0x08 
 17   
 18  MM_READ_WRITE = MM_READ | MM_WRITE 
 19  MM_READ_EXEC  =  MM_READ | MM_EXEC 
 20  MM_RWX = MM_READ | MM_WRITE | MM_EXEC 
 21   
 22  pnames = ['No Access', 'Execute', 'Write', None, 'Read'] 
23 -def getPermName(perm):
24 ''' 25 Return the human readable name for a *single* memory 26 perm enumeration value. 27 ''' 28 return pnames[perm]
29
30 -def reprPerms(mask):
31 plist = ['-','-','-','-'] 32 if mask & MM_SHARED: 33 plist[0] = 's' 34 if mask & MM_READ: 35 plist[1] = 'r' 36 if mask & MM_WRITE: 37 plist[2] = 'w' 38 if mask & MM_EXEC: 39 plist[3] = 'x' 40 41 return "".join(plist)
42
43 -def parsePerms(pstr):
44 ret = 0 45 if pstr.find('s') != -1: ret |= MM_SHARED 46 if pstr.find('r') != -1: ret |= MM_READ 47 if pstr.find('w') != -1: ret |= MM_WRITE 48 if pstr.find('x') != -1: ret |= MM_EXEC 49 return ret
50
51 -class IMemory:
52 """ 53 This is the interface spec (and a few helper utils) 54 for the unified memory object interface. 55 56 NOTE: If your actual underlying memory format is such 57 that over-riding anything (like isValidPointer!) can 58 be faster than the default implementation, DO IT! 59 """ 60
61 - def __init__(self, archmod=None):
62 self.imem_psize = struct.calcsize("P") 63 self.imem_arch = archmod 64 # If the specified an arch module, use that! 65 if archmod != None: 66 self.imem_psize = archmod.getPointerSize()
67
68 - def getPointerSize(self):
69 return self.imem_arch.getPointerSize()
70
71 - def readMemory(self, va, size):
72 """ 73 Read memory from the specified virtual address for size bytes 74 and return it as a python string. 75 76 Example: mem.readMemory(0x41414141, 20) -> "A..." 77 """ 78 raise Exception("must implement readMemory!")
79
80 - def writeMemory(self, va, bytes):
81 """ 82 Write the given bytes to the specified virtual address. 83 84 Example: mem.writeMemory(0x41414141, "VISI") 85 """ 86 raise Exception("must implement writeMemory!")
87
88 - def protectMemory(self, va, size, perms):
89 """ 90 Change the protections for the given memory map. On most platforms 91 the va/size *must* exactly match an existing memory map. 92 """ 93 raise Exception("must implement protectMemory!")
94
95 - def probeMemory(self, va, size, perm):
96 """ 97 Check to be sure that the given virtual address and size 98 is contained within one memory map, and check that the 99 perms are contained within the permission bits 100 for the memory map. (MM_READ | MM_WRITE | MM_EXEC | ...) 101 102 Example probeMemory(0x41414141, 20, envi.memory.MM_WRITE) 103 (check if the memory for 20 bytes at 0x41414141 is writable) 104 """ 105 map = self.getMemoryMap(va) 106 if map == None: 107 return False 108 mapva, mapsize, mapperm, mapfile = map 109 mapend = mapva+mapsize 110 if va+size >= mapend: 111 return False 112 if mapperm & perm != perm: 113 return False 114 return True
115
116 - def allocateMemory(self, size, perms=MM_RWX, suggestaddr=0):
117 raise Exception("must implement allocateMemory!")
118
119 - def addMemoryMap(self, mapva, perms, fname, bytes):
120 raise Exception("must implement addMemoryMap!")
121
122 - def getMemoryMaps(self):
123 raise Exception("must implement getMemoryMaps!")
124 125 # Mostly helpers from here down...
126 - def readMemoryFormat(self, va, fmt):
127 # Somehow, pointers are "signed" when they 128 # get chopped up by python's struct package 129 if self.imem_psize == 4: 130 fmt = fmt.replace("P","I") 131 elif self.imem_psize == 8: 132 fmt = fmt.replace("P","Q") 133 134 size = struct.calcsize(fmt) 135 bytes = self.readMemory(va, size) 136 return struct.unpack(fmt, bytes)
137
138 - def getSegmentInfo(self, id):
139 return (0,0xffffffff)
140
141 - def readMemValue(self, addr, size):
142 bytes = self.readMemory(addr, size) 143 if bytes == None: 144 return None 145 #FIXME change this (and all uses of it) to passing in format... 146 if len(bytes) != size: 147 raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes))) 148 if size == 1: 149 return struct.unpack("B", bytes)[0] 150 elif size == 2: 151 return struct.unpack("<H", bytes)[0] 152 elif size == 4: 153 return struct.unpack("<I", bytes)[0] 154 elif size == 8: 155 return struct.unpack("<Q", bytes)[0]
156 157
158 - def writeMemoryFormat(self, va, fmt, *args):
159 ''' 160 Write a python format sequence of variables out to memory after 161 serializing using struct pack... 162 163 Example: 164 trace.writeMemoryFormat(va, '<PBB', 10, 30, 99) 165 ''' 166 if self.imem_psize == 4: 167 fmt = fmt.replace("P","I") 168 elif self.imem_psize == 8: 169 fmt = fmt.replace("P","Q") 170 mbytes = struct.pack(fmt, *args) 171 self.writeMemory(va, mbytes)
172
173 - def getMemoryMap(self, va):
174 """ 175 Return a tuple of mapva,size,perms,filename for the memory 176 map which contains the specified address (or None). 177 """ 178 for mapva,size,perms,mname in self.getMemoryMaps(): 179 if va >= mapva and va < (mapva+size): 180 return (mapva,size,perms,mname) 181 return None
182
183 - def isValidPointer(self, va):
184 return self.getMemoryMap(va) != None
185
186 - def isReadable(self, va):
187 maptup = self.getMemoryMap(va) 188 if maptup == None: 189 return False 190 return bool(maptup[2] & MM_READ)
191
192 - def isWriteable(self, va):
193 maptup = self.getMemoryMap(va) 194 if maptup == None: 195 return False 196 return bool(maptup[2] & MM_WRITE)
197
198 - def isExecutable(self, va):
199 maptup = self.getMemoryMap(va) 200 if maptup == None: 201 return False 202 return bool(maptup[2] & MM_EXEC)
203
204 - def isShared(self, va):
205 maptup = self.getMemoryMap(va) 206 if maptup == None: 207 return False 208 return bool(maptup[2] & MM_SHAR)
209 210
211 - def searchMemory(self, needle, regex=False):
212 """ 213 A quick cheater way to searchMemoryRange() for each 214 of the current memory maps. 215 """ 216 results = [] 217 for va,size,perm,fname in self.getMemoryMaps(): 218 try: 219 results.extend(self.searchMemoryRange(needle, va, size, regex=regex)) 220 except: 221 pass # Some platforms dont let debuggers read non-readable mem 222 223 return results
224
225 - def searchMemoryRange(self, needle, address, size, regex=False):
226 """ 227 Search the specified memory range (address -> size) 228 for the string needle. Return a list of addresses 229 where the match occurs. 230 """ 231 results = [] 232 memory = self.readMemory(address, size) 233 if regex: 234 for match in re.finditer(needle, memory): 235 off = match.start() 236 results.append(address+off) 237 else: 238 offset = 0 239 while offset < size: 240 loc = memory.find(needle, offset) 241 if loc == -1: # No more to be found ;) 242 break 243 results.append(address+loc) 244 offset = loc+len(needle) # Skip one past our matcher 245 246 return results
247
248 - def parseOpcode(self, va):
249 ''' 250 Parse an opcode from the specified virtual address. 251 252 Example: op = m.parseOpcode(0x7c773803) 253 ''' 254 if self.imem_arch == None: 255 raise Exception('IMemory got no architecture module (%s)' % (self.__class__.__name__)) 256 b = self.readMemory(va, 16) 257 return self.imem_arch.makeOpcode(b, 0, va)
258
259 -class MemoryObject(IMemory):
260
261 - def __init__(self, archmod=None):
262 """ 263 Take a set of memory maps (va, perms, fname, bytes) and put them in 264 a sparse space finder. You may specify your own page-size to optimize 265 the search for an architecture. 266 """ 267 IMemory.__init__(self, archmod=archmod) 268 self._map_defs = []
269 270 #FIXME MemoryObject: def allocateMemory(self, size, perms=MM_RWX, suggestaddr=0): 271
272 - def addMemoryMap(self, va, perms, fname, bytes):
273 ''' 274 Add a memory map to this object... 275 ''' 276 msize = len(bytes) 277 map = (va, msize, perms, fname) 278 hlpr = [va, va+msize, map, bytes] 279 self._map_defs.append(hlpr) 280 return
281
282 - def getMemorySnap(self):
283 ''' 284 Take a memory snapshot which may be restored later. 285 286 Example: snap = mem.getMemorySnap() 287 ''' 288 return [ list(mdef) for mdef in self._map_defs ]
289
290 - def setMemorySnap(self, snap):
291 ''' 292 Restore a previously saved memory snapshot. 293 294 Example: mem.setMemorySnap(snap) 295 ''' 296 self._map_defs = [list(md) for md in snap]
297
298 - def getMemoryMap(self, va):
299 """ 300 Get the va,size,perms,fname tuple for this memory map 301 """ 302 for mva, mmaxva, mmap, mbytes in self._map_defs: 303 if va >= mva and va < mmaxva: 304 return mmap 305 return None
306
307 - def getMemoryMaps(self):
308 return [ mmap for mva, mmaxva, mmap, mbytes in self._map_defs ]
309
310 - def readMemory(self, va, size):
311 312 for mva, mmaxva, mmap, mbytes in self._map_defs: 313 if va >= mva and va < mmaxva: 314 mva, msize, mperms, mfname = mmap 315 if not mperms & MM_READ: 316 raise envi.SegmentationViolation(va) 317 offset = va - mva 318 return mbytes[offset:offset+size] 319 raise envi.SegmentationViolation(va)
320
321 - def writeMemory(self, va, bytes):
322 for mapdef in self._map_defs: 323 mva, mmaxva, mmap, mbytes = mapdef 324 if va >= mva and va < mmaxva: 325 mva, msize, mperms, mfname = mmap 326 if not mperms & MM_WRITE: 327 raise envi.SegmentationViolation(va) 328 offset = va - mva 329 mapdef[3] = mbytes[:offset] + bytes + mbytes[offset+len(bytes):] 330 return 331 332 raise envi.SegmentationViolation(va)
333
334 - def getByteDef(self, va):
335 """ 336 An optimized routine which returns the existing 337 segment bytes sequence without creating a new 338 string object *AND* an offset of va into the 339 buffer. Used internally for optimized memory 340 handling. Returns (offset, bytes) 341 """ 342 for mapdef in self._map_defs: 343 mva, mmaxva, mmap, mbytes = mapdef 344 if va >= mva and va < mmaxva: 345 offset = va - mva 346 return (offset, mbytes) 347 raise envi.SegmentationViolation(va)
348
349 -class MemoryFile:
350 ''' 351 A file like object to wrap around a memory object. 352 '''
353 - def __init__(self, memobj, baseaddr):
354 self.baseaddr = baseaddr 355 self.offset = baseaddr 356 self.memobj = memobj
357
358 - def seek(self, offset):
359 self.offset = self.baseaddr + offset
360
361 - def read(self, size):
362 ret = self.memobj.readMemory(self.offset, size) 363 self.offset += size 364 return ret
365
366 - def write(self, bytes):
367 self.memobj.writeMemory(self.offset, bytes) 368 self.offset += len(bytes)
369 370
371 -def memdiff(bytes1, bytes2):
372 ''' 373 Return a list of (offset, size) tuples showing any memory 374 differences between the given bytes. 375 ''' 376 377 size = len(bytes1) 378 if size != len(bytes2): 379 raise Exception('memdiff *requires* same size bytes') 380 ret = [] 381 offset = 0 382 while offset < size: 383 if bytes1[offset] != bytes2[offset]: 384 beginoff = offset 385 # Gather up all the difference bytes. 386 while ( offset < size and 387 bytes1[offset] != bytes2[offset]): 388 offset += 1 389 ret.append((beginoff, offset-beginoff)) 390 offset += 1 391 return ret
392