memory_map.py revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import bisect 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class Map(object): 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Models the memory map of a given |backends.Process|. 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) This is typically obtained by calling backends.Process.DumpMemoryMaps().""" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __init__(self): 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self._entries = [] 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def Add(self, entry): 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert(isinstance(entry, MapEntry)) 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bisect.insort_right(self._entries, entry) 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def Lookup(self, addr): 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Returns the MapEntry containing the given address, if any.""" 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) idx = bisect.bisect_right(self._entries, addr) - 1 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if idx < 0: 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return None 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) entry = self._entries[idx] 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert(addr >= entry.start) 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # bisect_right returns the latest element <= addr, but addr might fall after 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # its end (in which case we want to return None here). 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if addr > entry.end: 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return None 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return entry 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __getitem__(self, index): 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return self._entries[index] 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __len__(self): 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return len(self._entries) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class MapEntry(object): 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """An entry (address range + stats) in a memory |Map|.""" 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PAGE_SIZE = 4096 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __init__(self, start, end, prot_flags, mapped_file, mapped_offset): 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert(end > start) 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert(start >= 0) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.start = start 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.end = end 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.prot_flags = prot_flags 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.mapped_file = mapped_file 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.mapped_offset = mapped_offset 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.priv_dirty_bytes = 0 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.priv_clean_bytes = 0 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.shared_dirty_bytes = 0 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.shared_clean_bytes = 0 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # resident_pages is a bitmap (array of bytes) in which each bit represents 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # the presence of its corresponding page. 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) self.resident_pages = [] 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def GetRelativeOffset(self, abs_addr): 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Converts abs_addr to the corresponding offset in the mapped file.""" 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert(abs_addr >= self.start and abs_addr <= self.end) 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return abs_addr - self.start + self.mapped_offset 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def IsPageResident(self, relative_page_index): 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Checks whether a given memory page is resident in memory.""" 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert(relative_page_index >= 0 and 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) relative_page_index < self.len / MapEntry.PAGE_SIZE) 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) assert(len(self.resident_pages) * MapEntry.PAGE_SIZE * 8 >= self.len) 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) arr_idx = relative_page_index / 8 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) arr_bit = relative_page_index % 8 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return (self.resident_pages[arr_idx] & (1 << arr_bit)) != 0 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def __cmp__(self, other): 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Comparison operator required for bisect.""" 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if isinstance(other, MapEntry): 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return self.start - other.start 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) elif isinstance(other, int): 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return self.start - other 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) else: 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise Exception('Cannot compare with %s' % other.__class__) 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @property 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def len(self): 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return self.end - self.start + 1 86