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