memory_map.py revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 8PAGE_SIZE = 4096 9 10 11class Map(object): 12 """Models the memory map of a given |backends.Process|. 13 14 This is typically obtained by calling backends.Process.DumpMemoryMaps().""" 15 16 def __init__(self): 17 self.entries = [] # List of |MapEntry|, sorted by start address. 18 19 def Add(self, entry): 20 assert(isinstance(entry, MapEntry)) 21 bisect.insort_right(self.entries, entry) 22 23 def Lookup(self, addr): 24 """Returns the MapEntry containing the given address, if any.""" 25 idx = bisect.bisect_right(self.entries, addr) - 1 26 if idx < 0: 27 return None 28 entry = self.entries[idx] 29 assert(addr >= entry.start) 30 # bisect_right returns the latest element <= addr, but addr might fall after 31 # its end (in which case we want to return None here). 32 if addr > entry.end: 33 return None 34 return entry 35 36 def __getitem__(self, index): 37 return self.entries[index] 38 39 def __len__(self): 40 return len(self.entries) 41 42 43class MapEntry(object): 44 """An entry (address range + stats) in a memory |Map|.""" 45 46 def __init__(self, start, end, prot_flags, mapped_file, mapped_offset, 47 priv_dirty_bytes=0, priv_clean_bytes=0, shared_dirty_bytes=0, 48 shared_clean_bytes=0, resident_pages=None): 49 assert(end > start) 50 assert(start >= 0) 51 self.start = start 52 self.end = end 53 self.prot_flags = prot_flags 54 self.mapped_file = mapped_file 55 self.mapped_offset = mapped_offset 56 self.priv_dirty_bytes = priv_dirty_bytes 57 self.priv_clean_bytes = priv_clean_bytes 58 self.shared_dirty_bytes = shared_dirty_bytes 59 self.shared_clean_bytes = shared_clean_bytes 60 # resident_pages is a bitmap (array of bytes) in which each bit represents 61 # the presence of its corresponding page. 62 self.resident_pages = resident_pages or [] 63 64 def GetRelativeMMOffset(self, abs_addr): 65 """Converts abs_addr to the corresponding offset in the mm. 66 67 Returns: 68 A tuple: (page_index, offset_in_page) 69 """ 70 assert(self.Contains(abs_addr)) 71 offset = abs_addr - self.start 72 return (offset / PAGE_SIZE, offset & (PAGE_SIZE - 1)) 73 74 def GetRelativeFileOffset(self, abs_addr): 75 """Converts abs_addr to the corresponding offset in the mapped file.""" 76 assert(self.Contains(abs_addr)) 77 return abs_addr - self.start + self.mapped_offset 78 79 def IsPageResident(self, relative_page_index): 80 """Checks whether a given memory page is resident in memory.""" 81 assert(relative_page_index >= 0 and 82 relative_page_index < self.len / PAGE_SIZE) 83 arr_idx = relative_page_index / 8 84 arr_bit = relative_page_index % 8 85 # Trailing zeros are trimmed by memdump (to optimize dump time). 86 if arr_idx >= len(self.resident_pages): 87 return False 88 return (self.resident_pages[arr_idx] & (1 << arr_bit)) != 0 89 90 def Contains(self, abs_addr): 91 """Determines whether a given absolute address belongs to the current mm.""" 92 return abs_addr >= self.start and abs_addr <= self.end 93 94 def __cmp__(self, other): 95 """Comparison operator required for bisect.""" 96 if isinstance(other, MapEntry): 97 return self.start - other.start 98 elif isinstance(other, (long, int)): 99 return self.start - other 100 else: 101 raise Exception('Cannot compare with %s' % other.__class__) 102 103 @property 104 def len(self): 105 return self.end - self.start + 1 106 107 @property 108 def num_pages(self): 109 return self.len / PAGE_SIZE 110 111 @property 112 def rss_bytes(self): 113 return (self.priv_dirty_bytes + self.priv_clean_bytes + 114 self.shared_dirty_bytes + self.shared_clean_bytes) 115