1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
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,3}) '
# 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
|