tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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)