JSObject.py (4297B)
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 # Pretty-printers for SpiderMonkey JSObjects. 6 7 import re 8 9 import gdb 10 11 from mozilla import prettyprinters 12 from mozilla.CellHeader import get_header_ptr 13 from mozilla.jsval import JSValue 14 from mozilla.prettyprinters import ptr_pretty_printer, ref_pretty_printer 15 16 prettyprinters.clear_module_printers(__name__) 17 18 19 class JSObjectTypeCache: 20 def __init__(self): 21 object_flag = gdb.lookup_type("js::ObjectFlag") 22 self.objectflag_IsUsedAsPrototype = prettyprinters.enum_value( 23 object_flag, "js::ObjectFlag::IsUsedAsPrototype" 24 ) 25 self.value_ptr_t = gdb.lookup_type("JS::Value").pointer() 26 self.func_ptr_t = gdb.lookup_type("JSFunction").pointer() 27 self.class_NON_NATIVE = gdb.parse_and_eval("JSClass::NON_NATIVE") 28 self.BaseShape_ptr_t = gdb.lookup_type("js::BaseShape").pointer() 29 self.Shape_ptr_t = gdb.lookup_type("js::Shape").pointer() 30 self.JSClass_ptr_t = gdb.lookup_type("JSClass").pointer() 31 self.JSScript_ptr_t = gdb.lookup_type("JSScript").pointer() 32 self.JSFunction_AtomSlot = gdb.parse_and_eval("JSFunction::AtomSlot") 33 self.JSFunction_NativeJitInfoOrInterpretedScriptSlot = gdb.parse_and_eval( 34 "JSFunction::NativeJitInfoOrInterpretedScriptSlot" 35 ) 36 37 38 # There should be no need to register this for JSFunction as well, since we 39 # search for pretty-printers under the names of base classes, and 40 # JSFunction has JSObject as a base class. 41 42 43 gdb_string_regexp = re.compile(r'(?:0x[0-9a-z]+ )?(?:<.*> )?"(.*)"', re.I) 44 45 46 @ptr_pretty_printer("JSObject") 47 class JSObjectPtrOrRef(prettyprinters.Pointer): 48 def __init__(self, value, cache): 49 super().__init__(value, cache) 50 if not cache.mod_JSObject: 51 cache.mod_JSObject = JSObjectTypeCache() 52 self.otc = cache.mod_JSObject 53 54 def summary(self): 55 shape = get_header_ptr(self.value, self.otc.Shape_ptr_t) 56 baseshape = get_header_ptr(shape, self.otc.BaseShape_ptr_t) 57 classp = get_header_ptr(baseshape, self.otc.JSClass_ptr_t) 58 non_native = classp["flags"] & self.otc.class_NON_NATIVE 59 60 # Use GDB to format the class name, but then strip off the address 61 # and the quotes. 62 class_name = str(classp["name"]) 63 m = gdb_string_regexp.match(class_name) 64 if m: 65 class_name = m.group(1) 66 67 if non_native: 68 return f"[object {class_name}]" 69 else: 70 flags = shape["objectFlags_"]["flags_"] 71 used_as_prototype = bool(flags & self.otc.objectflag_IsUsedAsPrototype) 72 name = None 73 if class_name == "Function": 74 function = self.value 75 concrete_type = function.type.strip_typedefs() 76 if concrete_type.code == gdb.TYPE_CODE_REF: 77 function = function.address 78 name = get_function_name(function, self.cache) 79 return "[object {}{}]{}".format( 80 class_name, 81 " " + name if name else "", 82 " used_as_prototype" if used_as_prototype else "", 83 ) 84 85 86 def get_function_name(function, cache): 87 if not cache.mod_JSObject: 88 cache.mod_JSObject = JSObjectTypeCache() 89 otc = cache.mod_JSObject 90 91 function = function.cast(otc.func_ptr_t) 92 fixed_slots = (function + 1).cast(otc.value_ptr_t) 93 atom_value = JSValue(fixed_slots[otc.JSFunction_AtomSlot], cache) 94 95 if atom_value.is_undefined(): 96 return "<unnamed>" 97 98 return str(atom_value.get_string()) 99 100 101 def get_function_script(function, cache): 102 if not cache.mod_JSObject: 103 cache.mod_JSObject = JSObjectTypeCache() 104 otc = cache.mod_JSObject 105 106 function = function.cast(otc.func_ptr_t) 107 fixed_slots = (function + 1).cast(otc.value_ptr_t) 108 slot = otc.JSFunction_NativeJitInfoOrInterpretedScriptSlot 109 script_value = JSValue(fixed_slots[slot], cache) 110 111 if script_value.is_undefined(): 112 return 0 113 114 return script_value.get_private() 115 116 117 @ref_pretty_printer("JSObject") 118 def JSObjectRef(value, cache): 119 return JSObjectPtrOrRef(value, cache)