Bug 822563: Pretty-print references to JSObject and its subclasses. r=sfink

This commit is contained in:
Jim Blandy 2012-12-20 13:24:45 -08:00
Родитель d67d0c218c
Коммит ef6e51ee3c
5 изменённых файлов: 66 добавлений и 22 удалений

Просмотреть файл

@ -3,7 +3,7 @@
import gdb
import mozilla.JSString
import mozilla.prettyprinters as prettyprinters
from mozilla.prettyprinters import ptr_pretty_printer
from mozilla.prettyprinters import ptr_pretty_printer, ref_pretty_printer
from mozilla.Root import deref
prettyprinters.clear_module_printers(__name__)
@ -19,9 +19,9 @@ class JSObjectTypeCache(object):
# JSFunction has JSObject as a base class.
@ptr_pretty_printer('JSObject')
class JSObjectPtr(prettyprinters.Pointer):
class JSObjectPtrOrRef(prettyprinters.Pointer):
def __init__(self, value, cache):
super(JSObjectPtr, self).__init__(value, cache)
super(JSObjectPtrOrRef, self).__init__(value, cache)
if not cache.mod_JSObject:
cache.mod_JSObject = JSObjectTypeCache(value, cache)
self.otc = cache.mod_JSObject
@ -34,9 +34,15 @@ class JSObjectPtr(prettyprinters.Pointer):
is_delegate = bool(flags & self.otc.flag_DELEGATE)
name = None
if class_name == 'Function':
function = self.value.cast(self.otc.func_ptr_type)
if self.value.type.code == gdb.TYPE_CODE_PTR:
function = self.value.cast(self.otc.func_ptr_type)
elif self.value.type.code == gdb.TYPE_CODE_REF:
function = self.value.address.cast(self.otc.func_ptr_type)
atom = deref(function['atom_'])
name = str(atom) if atom else '<unnamed>'
return '[object %s%s]%s' % (class_name,
' ' + name if name else '',
' delegate' if is_delegate else '')
@ref_pretty_printer('JSObject')
def JSObjectRef(value, cache): return JSObjectPtrOrRef(value, cache)

Просмотреть файл

@ -45,6 +45,20 @@ def ptr_pretty_printer(type_name):
return fn
return add
# a dictionary mapping gdb.Type tags to pretty-printer functions for
# references to that type.
ref_printers_by_tag = {}
# A decorator: add the decoratee as a pretty-printer lookup function for
# references to instances of types named |type_name|.
def ref_pretty_printer(type_name):
def add(fn):
check_for_reused_pretty_printer(fn)
add_to_subprinter_list(fn, "ref-to-" + type_name)
ref_printers_by_tag[type_name] = fn
return fn
return add
# a dictionary mapping the template name portion of gdb.Type tags to
# pretty-printer functions for instantiations of that template.
template_printers_by_tag = {}
@ -83,7 +97,8 @@ def pretty_printer_for_regexp(pattern, name):
#
# clear_module_printers(__name__)
def clear_module_printers(module_name):
global printers_by_tag, ptr_printers_by_tag, template_printers_by_tag, printers_by_regexp
global printers_by_tag, ptr_printers_by_tag, ref_printers_by_tag
global template_printers_by_tag, printers_by_regexp
# Remove all pretty-printers defined in the module named |module_name|
# from d.
@ -101,6 +116,7 @@ def clear_module_printers(module_name):
clear_dictionary(printers_by_tag)
clear_dictionary(ptr_printers_by_tag)
clear_dictionary(ref_printers_by_tag)
clear_dictionary(template_printers_by_tag)
# Iterate over printers_by_regexp, deleting entries from the given module.
@ -226,28 +242,31 @@ def lookup_for_objfile(objfile):
return f(value, cache)
return None
def check_table_by_type_name(table, t):
if t.code == gdb.TYPE_CODE_TYPEDEF:
return check_table(table, str(t))
elif t.code == gdb.TYPE_CODE_STRUCT and t.tag:
return check_table(table, t.tag)
else:
return None
for t in implemented_types(value.type):
if t.code == gdb.TYPE_CODE_PTR:
for t2 in implemented_types(t.target()):
if t2.code == gdb.TYPE_CODE_TYPEDEF:
p = check_table(ptr_printers_by_tag, str(t2))
elif t2.code == gdb.TYPE_CODE_STRUCT and t2.tag:
p = check_table(ptr_printers_by_tag, t2.tag)
else:
p = None
p = check_table_by_type_name(ptr_printers_by_tag, t2)
if p: return p
elif t.code == gdb.TYPE_CODE_REF:
for t2 in implemented_types(t.target()):
p = check_table_by_type_name(ref_printers_by_tag, t2)
if p: return p
else:
if t.code == gdb.TYPE_CODE_TYPEDEF:
p = check_table(printers_by_tag, str(t))
elif t.code == gdb.TYPE_CODE_STRUCT and t.tag:
p = check_table_by_type_name(printers_by_tag, t)
if p: return p
if t.code == gdb.TYPE_CODE_STRUCT and t.tag:
m = template_regexp.match(t.tag)
if m:
p = check_table(template_printers_by_tag, m.group(1))
else:
p = check_table(printers_by_tag, t.tag)
else:
p = None
if p: return p
if p: return p
# Failing that, look for a printer in printers_by_regexp. We have
# to scan the whole list, so regexp printers should be used
@ -275,6 +294,8 @@ def lookup_for_objfile(objfile):
# pointers, by declining to construct a pretty-printer for them at all.
# Derived classes may simply assume that self.value is non-null.
#
# To help share code, this class can also be used with reference types.
#
# This class provides the following methods, which subclasses are free to
# override:
#
@ -291,7 +312,8 @@ def lookup_for_objfile(objfile):
class Pointer(object):
def __new__(cls, value, cache):
# Don't try to provide pretty-printers for NULL pointers.
if value == 0: return None
if value.type.code == gdb.TYPE_CODE_PTR and value == 0:
return None
return super(Pointer, cls).__new__(cls)
def __init__(self, value, cache):
@ -301,7 +323,10 @@ class Pointer(object):
def to_string(self):
# See comment above.
assert not hasattr(self, 'display_hint') or self.display_hint() != 'string'
address = self.value.cast(self.cache.void_ptr_t)
if self.value.type.code == gdb.TYPE_CODE_PTR:
address = self.value.cast(self.cache.void_ptr_t)
elif self.value.type.code == gdb.TYPE_CODE_REF:
address = '@' + str(self.value.address.cast(self.cache.void_ptr_t))
try:
summary = self.summary()
except gdb.MemoryError as r:

Просмотреть файл

@ -10,6 +10,9 @@ FRAGMENT(JSObject, simple) {
js::Rooted<JSFunction *> funcPtr(cx, JS_NewFunction(cx, (JSNative) 1, 0, 0,
JS_GetGlobalObject(cx), "formFollows"));
JSObject &plainRef = *plain;
JSFunction &funcRef = *funcPtr;
breakpoint();
(void) glob;
@ -17,6 +20,8 @@ FRAGMENT(JSObject, simple) {
(void) func;
(void) anon;
(void) funcPtr;
(void) plainRef;
(void) funcRef;
}
FRAGMENT(JSObject, null) {
@ -26,4 +31,3 @@ FRAGMENT(JSObject, null) {
(void) null;
}

Просмотреть файл

@ -1,6 +1,8 @@
# Printing JSObjects.
assert_subprinter_registered('SpiderMonkey', 'ptr-to-JSObject')
assert_subprinter_registered('SpiderMonkey', 'ref-to-JSObject')
run_fragment('JSObject.simple')
# These patterns look a little strange because of prolog.py's 'set print
@ -13,3 +15,6 @@ assert_pretty('plain', '(JSObject *) [object Object]')
assert_pretty('func', '(JSObject *) [object Function "dys"]')
assert_pretty('anon', '(JSObject *) [object Function <unnamed>]')
assert_pretty('funcPtr', '(JSFunction *) [object Function "formFollows"]')
assert_pretty('plainRef', '(JSObject &) @ [object Object]')
assert_pretty('funcRef', '(JSFunction &) @ [object Function "formFollows"]')

Просмотреть файл

@ -16,3 +16,7 @@ assert_eq(implemented_type_names('e'), ['E', 'C', 'D'])
assert_eq(implemented_type_names('e_'), ['E_', 'E', 'C', 'D'])
assert_eq(implemented_type_names('f'), ['F', 'C', 'D'])
assert_eq(implemented_type_names('h'), ['H', 'F', 'G', 'C', 'D'])
# Check that our pretty-printers aren't interfering with printing other types.
assert_pretty('10', '10')
assert_pretty('(void*) 0', '') # Because of 'set print address off'