ExecutableAllocator.py (3642B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 # You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 """ 6 All jitted code is allocated via the ExecutableAllocator class. Make GDB aware 7 of them, such that we can query for pages which are containing code which are 8 allocated by the Jits. 9 """ 10 11 import gdb 12 13 import mozilla.prettyprinters 14 from mozilla.prettyprinters import pretty_printer, ptr_pretty_printer 15 16 # Forget any printers from previous loads of this module. 17 mozilla.prettyprinters.clear_module_printers(__name__) 18 19 20 class jsjitExecutableAllocatorCache: 21 """Cache information about the ExecutableAllocator type for this objfile.""" 22 23 def __init__(self): 24 self.d = None 25 26 def __getattr__(self, name): 27 if self.d is None: 28 self.initialize() 29 return self.d[name] 30 31 def initialize(self): 32 self.d = {} 33 self.d["ExecutableAllocator"] = gdb.lookup_type("js::jit::ExecutableAllocator") 34 self.d["ExecutablePool"] = gdb.lookup_type("js::jit::ExecutablePool") 35 self.d["HashNumber"] = gdb.lookup_type("mozilla::HashNumber") 36 37 38 @pretty_printer("js::jit::ExecutableAllocator") 39 class jsjitExecutableAllocator: 40 def __init__(self, value, cache): 41 if not cache.mod_ExecutableAllocator: 42 cache.mod_ExecutableAllocator = jsjitExecutableAllocatorCache() 43 self.value = value 44 self.cache = cache.mod_ExecutableAllocator 45 46 def to_string(self): 47 return "ExecutableAllocator([%s])" % ", ".join([str(x) for x in self]) 48 49 def __iter__(self): 50 return self.PoolIterator(self) 51 52 class PoolIterator: 53 def __init__(self, allocator): 54 self.allocator = allocator 55 self.entryType = allocator.cache.ExecutablePool.pointer() 56 self.hashNumType = allocator.cache.HashNumber 57 # Emulate the HashSet::Range 58 self.table = allocator.value["m_pools"]["mImpl"]["mTable"] 59 self.index = 0 60 kHashNumberBits = 32 61 hashShiftMask = 0xFF 62 genAndHashShift = allocator.value["m_pools"]["mImpl"]["mGenAndHashShift"] 63 hashShift = genAndHashShift & hashShiftMask 64 self.capacity = 1 << (kHashNumberBits - hashShift) 65 if self.table == 0: 66 self.capacity = 0 67 # auto hashes = reinterpret_cast<HashNumber*>(mTable); 68 self.hashes = self.table.cast(self.hashNumType.pointer()) 69 # auto entries = reinterpret_cast<Entry*>(&hashes[capacity()]); 70 self.entries = (self.hashes + self.capacity).cast(self.entryType.pointer()) 71 72 def __iter__(self): 73 return self 74 75 def next(self): 76 return self.__next__() 77 78 def __next__(self): 79 cur = self.index 80 if cur >= self.capacity: 81 raise StopIteration() 82 self.index = self.index + 1 83 if self.hashes[cur] > 1: # table[i]->isLive() 84 return self.entries[cur] 85 return self.__next__() 86 87 88 @ptr_pretty_printer("js::jit::ExecutablePool") 89 class jsjitExecutablePool(mozilla.prettyprinters.Pointer): 90 def __init__(self, value, cache): 91 if not cache.mod_ExecutableAllocator: 92 cache.mod_ExecutableAllocator = jsjitExecutableAllocatorCache() 93 self.value = value 94 self.cache = cache.mod_ExecutableAllocator 95 96 def to_string(self): 97 pages = self.value["m_allocation"]["pages"] 98 size = self.value["m_allocation"]["size"] 99 return "ExecutablePool %08x-%08x" % (pages, pages + size)