Edit File: memory_mapping.py
from ptrace.os_tools import HAS_PROC from ptrace.debugger.process_error import ProcessError from ptrace.ctypes_tools import formatAddress import re from weakref import ref if HAS_PROC: from ptrace.linux_proc import openProc, ProcError PROC_MAP_REGEX = re.compile( # Address range: '08048000-080b0000 ' r'([0-9a-f]+)-([0-9a-f]+) ' # Permission: 'r-xp ' r'(.{4}) ' # Offset: '0804d000' r'([0-9a-f]+) ' # Device (major:minor): 'fe:01 ' r'([0-9a-f]{2,3}):([0-9a-f]{2}) ' # Inode: '3334030' r'([0-9]+)' # Filename: ' /usr/bin/synergyc' r'(?: +(.*))?') class MemoryMapping(object): """ Process memory mapping (metadata about the mapping). Attributes: - start (int): first byte address - end (int): last byte address + 1 - permissions (str) - offset (int): for file, offset in bytes from the file start - major_device / minor_device (int): major / minor device number - inode (int) - pathname (str) - _process: weak reference to the process Operations: - "address in mapping" checks the address is in the mapping. - "search(somestring)" returns the offsets of "somestring" in the mapping - "str(mapping)" create one string describing the mapping - "repr(mapping)" create a string representation of the mapping, useful in list contexts """ def __init__(self, process, start, end, permissions, offset, major_device, minor_device, inode, pathname): self._process = ref(process) self.start = start self.end = end self.permissions = permissions self.offset = offset self.major_device = major_device self.minor_device = minor_device self.inode = inode self.pathname = pathname def __contains__(self, address): return self.start <= address < self.end def __str__(self): text = "%s-%s" % (formatAddress(self.start), formatAddress(self.end)) if self.pathname: text += " => %s" % self.pathname text += " (%s)" % self.permissions return text __repr__ = __str__ def search(self, bytestr): process = self._process() bytestr_len = len(bytestr) buf_len = 64 * 1024 if buf_len < bytestr_len: buf_len = bytestr_len remaining = self.end - self.start covered = self.start while remaining >= bytestr_len: if remaining > buf_len: requested = buf_len else: requested = remaining data = process.readBytes(covered, requested) if data == "": break offset = data.find(bytestr) if (offset == -1): skip = requested - bytestr_len + 1 else: yield (covered + offset) skip = offset + bytestr_len covered += skip remaining -= skip def readProcessMappings(process): """ Read all memory mappings of the specified process. Return a list of MemoryMapping objects, or empty list if it's not possible to read the mappings. May raise a ProcessError. """ maps = [] if not HAS_PROC: return maps try: mapsfile = openProc("%s/maps" % process.pid) except ProcError as err: raise ProcessError(process, "Unable to read process maps: %s" % err) try: for line in mapsfile: line = line.rstrip() match = PROC_MAP_REGEX.match(line) if not match: raise ProcessError( process, "Unable to parse memory mapping: %r" % line) map = MemoryMapping( process, int(match.group(1), 16), int(match.group(2), 16), match.group(3), int(match.group(4), 16), int(match.group(5), 16), int(match.group(6), 16), int(match.group(7)), match.group(8)) maps.append(map) finally: mapsfile.close() return maps