memory_map.py revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import bisect
6
7
8class Map(object):
9  """Models the memory map of a given |backends.Process|.
10
11  This is typically obtained by calling backends.Process.DumpMemoryMaps()."""
12
13  def __init__(self):
14    self._entries = []
15
16  def Add(self, entry):
17    assert(isinstance(entry, MapEntry))
18    bisect.insort_right(self._entries, entry)
19
20  def Lookup(self, addr):
21    """Returns the MapEntry containing the given address, if any."""
22    idx = bisect.bisect_right(self._entries, addr) - 1
23    if idx < 0:
24      return None
25    entry = self._entries[idx]
26    assert(addr >= entry.start)
27    # bisect_right returns the latest element <= addr, but addr might fall after
28    # its end (in which case we want to return None here).
29    if addr > entry.end:
30      return None
31    return entry
32
33  def __getitem__(self, index):
34    return self._entries[index]
35
36  def __len__(self):
37    return len(self._entries)
38
39
40class MapEntry(object):
41  """An entry (address range + stats) in a memory |Map|."""
42  PAGE_SIZE = 4096
43
44  def __init__(self, start, end, prot_flags, mapped_file, mapped_offset):
45    assert(end > start)
46    assert(start >= 0)
47    self.start = start
48    self.end = end
49    self.prot_flags = prot_flags
50    self.mapped_file = mapped_file
51    self.mapped_offset = mapped_offset
52    self.priv_dirty_bytes = 0
53    self.priv_clean_bytes = 0
54    self.shared_dirty_bytes = 0
55    self.shared_clean_bytes = 0
56    # resident_pages is a bitmap (array of bytes) in which each bit represents
57    # the presence of its corresponding page.
58    self.resident_pages = []
59
60  def GetRelativeOffset(self, abs_addr):
61    """Converts abs_addr to the corresponding offset in the mapped file."""
62    assert(abs_addr >= self.start and abs_addr <= self.end)
63    return abs_addr - self.start + self.mapped_offset
64
65  def IsPageResident(self, relative_page_index):
66    """Checks whether a given memory page is resident in memory."""
67    assert(relative_page_index >= 0 and
68           relative_page_index < self.len / MapEntry.PAGE_SIZE)
69    assert(len(self.resident_pages) * MapEntry.PAGE_SIZE * 8 >= self.len)
70    arr_idx = relative_page_index / 8
71    arr_bit = relative_page_index % 8
72    return (self.resident_pages[arr_idx] & (1 << arr_bit)) != 0
73
74  def __cmp__(self, other):
75    """Comparison operator required for bisect."""
76    if isinstance(other, MapEntry):
77      return self.start - other.start
78    elif isinstance(other, int):
79      return self.start - other
80    else:
81      raise Exception('Cannot compare with %s' % other.__class__)
82
83  @property
84  def len(self):
85    return self.end - self.start + 1
86