• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      priv_dirty_bytes=0, priv_clean_bytes=0, shared_dirty_bytes=0,
46      shared_clean_bytes=0, resident_pages=None):
47    assert(end > start)
48    assert(start >= 0)
49    self.start = start
50    self.end = end
51    self.prot_flags = prot_flags
52    self.mapped_file = mapped_file
53    self.mapped_offset = mapped_offset
54    self.priv_dirty_bytes = priv_dirty_bytes
55    self.priv_clean_bytes = priv_clean_bytes
56    self.shared_dirty_bytes = shared_dirty_bytes
57    self.shared_clean_bytes = shared_clean_bytes
58    # resident_pages is a bitmap (array of bytes) in which each bit represents
59    # the presence of its corresponding page.
60    self.resident_pages = resident_pages or []
61
62  def GetRelativeOffset(self, abs_addr):
63    """Converts abs_addr to the corresponding offset in the mapped file."""
64    assert(abs_addr >= self.start and abs_addr <= self.end)
65    return abs_addr - self.start + self.mapped_offset
66
67  def IsPageResident(self, relative_page_index):
68    """Checks whether a given memory page is resident in memory."""
69    assert(relative_page_index >= 0 and
70           relative_page_index < self.len / MapEntry.PAGE_SIZE)
71    assert(len(self.resident_pages) * MapEntry.PAGE_SIZE * 8 >= self.len)
72    arr_idx = relative_page_index / 8
73    arr_bit = relative_page_index % 8
74    return (self.resident_pages[arr_idx] & (1 << arr_bit)) != 0
75
76  def __cmp__(self, other):
77    """Comparison operator required for bisect."""
78    if isinstance(other, MapEntry):
79      return self.start - other.start
80    elif isinstance(other, int):
81      return self.start - other
82    else:
83      raise Exception('Cannot compare with %s' % other.__class__)
84
85  @property
86  def len(self):
87    return self.end - self.start + 1
88