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