import gdb
import gdb.types
import mozilla.prettyprinters
from mozilla.prettyprinters import pretty_printer
mozilla.prettyprinters.clear_module_printers(__name__)
class Box(object):
def __init__(self, asBits, jtc):
self.asBits = asBits
self.jtc = jtc
if self.asBits < 0:
self.asBits = self.asBits + (1 << 64)
def tag(self): raise NotImplementedError
def as_uint32(self): raise NotImplementedError
def as_double(self): raise NotImplementedError
def as_address(self): raise NotImplementedError
class Punbox(Box):
FULL_WIDTH = 64
TAG_SHIFT = 47
PAYLOAD_MASK = (1 << TAG_SHIFT) - 1
TAG_MASK = (1 << (FULL_WIDTH - TAG_SHIFT)) - 1
TAG_MAX_DOUBLE = 0x1fff0
TAG_TYPE_MASK = 0x0000f
def tag(self):
tag = self.asBits >> Punbox.TAG_SHIFT
if tag <= Punbox.TAG_MAX_DOUBLE:
return self.jtc.DOUBLE
else:
return tag & Punbox.TAG_TYPE_MASK
def as_uint32(self): return int(self.asBits & ((1 << 32) - 1))
def as_address(self): return gdb.Value(self.asBits & Punbox.PAYLOAD_MASK)
class Nunbox(Box):
TAG_SHIFT = 32
TAG_CLEAR = 0xffff0000
PAYLOAD_MASK = 0xffffffff
TAG_TYPE_MASK = 0x0000000f
def tag(self):
tag = self.asBits >> Nunbox.TAG_SHIFT
if tag < Nunbox.TAG_CLEAR:
return self.jtc.DOUBLE
return tag & Nunbox.TAG_TYPE_MASK
def as_uint32(self): return int(self.asBits & Nunbox.PAYLOAD_MASK)
def as_address(self): return gdb.Value(self.asBits & Nunbox.PAYLOAD_MASK)
class JSValueTypeCache(object):
def __init__(self, cache):
d = gdb.types.make_enum_dict(gdb.lookup_type('JSValueType'))
def get(key):
val = d.get(key)
if val is not None:
return val
return d['JSValueType::' + key]
self.DOUBLE = get('JSVAL_TYPE_DOUBLE')
self.INT32 = get('JSVAL_TYPE_INT32')
self.UNDEFINED = get('JSVAL_TYPE_UNDEFINED')
self.BOOLEAN = get('JSVAL_TYPE_BOOLEAN')
self.MAGIC = get('JSVAL_TYPE_MAGIC')
self.STRING = get('JSVAL_TYPE_STRING')
self.SYMBOL = get('JSVAL_TYPE_SYMBOL')
self.BIGINT = get('JSVAL_TYPE_BIGINT')
self.NULL = get('JSVAL_TYPE_NULL')
self.OBJECT = get('JSVAL_TYPE_OBJECT')
d = gdb.types.make_enum_dict(gdb.lookup_type('JSWhyMagic'))
self.magic_names = list(range(max(d.values()) + 1))
for (k, v) in d.items():
self.magic_names[v] = k
self.boxer = Punbox if cache.void_ptr_t.sizeof == 8 else Nunbox
@pretty_printer('JS::Value')
class JSValue(object):
def __init__(self, value, cache):
self.cache = cache
if not cache.mod_JS_Value:
cache.mod_JS_Value = JSValueTypeCache(cache)
self.jtc = cache.mod_JS_Value
self.value = value
self.box = self.jtc.boxer(value['asBits_'], self.jtc)
def to_string(self):
tag = self.box.tag()
if tag == self.jtc.UNDEFINED:
return '$JS::UndefinedValue()'
if tag == self.jtc.NULL:
return '$JS::NullValue()'
if tag == self.jtc.BOOLEAN:
return '$JS::BooleanValue(%s)' % str(self.box.as_uint32() != 0).lower()
if tag == self.jtc.MAGIC:
value = self.box.as_uint32()
if 0 <= value and value < len(self.jtc.magic_names):
return '$JS::MagicValue(%s)' % (self.jtc.magic_names[value],)
else:
return '$JS::MagicValue(%d)' % (value,)
if tag == self.jtc.INT32:
value = self.box.as_uint32()
signbit = 1 << 31
value = (value ^ signbit) - signbit
return '$JS::Int32Value(%s)' % value
if tag == self.jtc.DOUBLE:
return '$JS::DoubleValue(%s)' % self.value['asDouble_']
if tag == self.jtc.STRING:
value = self.box.as_address().cast(self.cache.JSString_ptr_t)
elif tag == self.jtc.OBJECT:
value = self.box.as_address().cast(self.cache.JSObject_ptr_t)
elif tag == self.jtc.SYMBOL:
value = self.box.as_address().cast(self.cache.JSSymbol_ptr_t)
elif tag == self.jtc.BIGINT:
return '$JS::BigIntValue()'
else:
value = 'unrecognized!'
return '$JS::Value(%s)' % (value,)