1
# mozilla/prettyprinters.py --- infrastructure for SpiderMonkey's auto-loaded pretty-printers.
6
# Decorators for declaring pretty-printers.
8
# In each case, the decoratee should be a SpiderMonkey-style pretty-printer
9
# factory, taking both a gdb.Value instance and a TypeCache instance as
10
# arguments; see TypeCache, below.
12
# Check that |fn| hasn't been registered as a pretty-printer under some
13
# other name already. (The 'enabled' flags used by GDB's
14
# 'enable/disable/info pretty-printer' commands are simply stored as
15
# properties of the function objects themselves, so a single function
16
# object can't carry the 'enabled' flags for two different printers.)
17
def check_for_reused_pretty_printer(fn):
18
if hasattr(fn, 'enabled'):
19
raise RuntimeError, ("pretty-printer function %r registered more than once" % fn)
21
# a dictionary mapping gdb.Type tags to pretty-printer functions.
24
# A decorator: add the decoratee as a pretty-printer lookup function for types
26
def pretty_printer(type_name):
28
check_for_reused_pretty_printer(fn)
29
add_to_subprinter_list(fn, type_name)
30
printers_by_tag[type_name] = fn
34
# a dictionary mapping gdb.Type tags to pretty-printer functions for pointers to
36
ptr_printers_by_tag = {}
38
# A decorator: add the decoratee as a pretty-printer lookup function for
39
# pointers to types named |type_name|.
40
def ptr_pretty_printer(type_name):
42
check_for_reused_pretty_printer(fn)
43
add_to_subprinter_list(fn, "ptr-to-" + type_name)
44
ptr_printers_by_tag[type_name] = fn
48
# a dictionary mapping gdb.Type tags to pretty-printer functions for
49
# references to that type.
50
ref_printers_by_tag = {}
52
# A decorator: add the decoratee as a pretty-printer lookup function for
53
# references to instances of types named |type_name|.
54
def ref_pretty_printer(type_name):
56
check_for_reused_pretty_printer(fn)
57
add_to_subprinter_list(fn, "ref-to-" + type_name)
58
ref_printers_by_tag[type_name] = fn
62
# a dictionary mapping the template name portion of gdb.Type tags to
63
# pretty-printer functions for instantiations of that template.
64
template_printers_by_tag = {}
66
# A decorator: add the decoratee as a pretty-printer lookup function for
67
# instantiations of templates named |template_name|.
68
def template_pretty_printer(template_name):
70
check_for_reused_pretty_printer(fn)
71
add_to_subprinter_list(fn, 'instantiations-of-' + template_name)
72
template_printers_by_tag[template_name] = fn
76
# A list of (REGEXP, PRINTER) pairs, such that if REGEXP (a RegexObject)
77
# matches the result of converting a gdb.Value's type to a string, then
78
# PRINTER is a pretty-printer lookup function that will probably like that
80
printers_by_regexp = []
82
# A decorator: add the decoratee as a pretty-printer factory for types
83
# that, when converted to a string, match |pattern|. Use |name| as the
84
# pretty-printer's name, when listing, enabling and disabling.
85
def pretty_printer_for_regexp(pattern, name):
86
compiled = re.compile(pattern)
88
check_for_reused_pretty_printer(fn)
89
add_to_subprinter_list(fn, name)
90
printers_by_regexp.append((compiled, fn))
94
# Forget all pretty-printer lookup functions defined in the module name
95
# |module_name|, if any exist. Use this at the top of each pretty-printer
98
# clear_module_printers(__name__)
99
def clear_module_printers(module_name):
100
global printers_by_tag, ptr_printers_by_tag, ref_printers_by_tag
101
global template_printers_by_tag, printers_by_regexp
103
# Remove all pretty-printers defined in the module named |module_name|
105
def clear_dictionary(d):
106
# Walk the dictionary, building a list of keys whose entries we
107
# should remove. (It's not safe to delete entries from a dictionary
108
# while we're iterating over it.)
110
for (k, v) in d.iteritems():
111
if v.__module__ == module_name:
113
remove_from_subprinter_list(v)
117
clear_dictionary(printers_by_tag)
118
clear_dictionary(ptr_printers_by_tag)
119
clear_dictionary(ref_printers_by_tag)
120
clear_dictionary(template_printers_by_tag)
122
# Iterate over printers_by_regexp, deleting entries from the given module.
124
for p in printers_by_regexp:
125
if p.__module__ == module_name:
126
remove_from_subprinter_list(p)
129
printers_by_regexp = new_list
131
# Our subprinters array. The 'subprinters' attributes of all lookup
132
# functions returned by lookup_for_objfile point to this array instance,
133
# which we mutate as subprinters are added and removed.
136
# Set up the 'name' and 'enabled' attributes on |subprinter|, and add it to our
137
# list of all SpiderMonkey subprinters.
138
def add_to_subprinter_list(subprinter, name):
139
subprinter.name = name
140
subprinter.enabled = True
141
subprinters.append(subprinter)
143
# Remove |subprinter| from our list of all SpiderMonkey subprinters.
144
def remove_from_subprinter_list(subprinter):
145
subprinters.remove(subprinter)
147
# An exception class meaning, "This objfile has no SpiderMonkey in it."
148
class NotSpiderMonkeyObjfileError(TypeError):
151
# TypeCache: a cache for frequently used information about an objfile.
153
# When a new SpiderMonkey objfile is loaded, we construct an instance of
154
# this class for it. Then, whenever we construct a pretty-printer for some
155
# gdb.Value, we also pass, as a second argument, the TypeCache for the
156
# objfile to which that value's type belongs.
158
# if objfile doesn't seem to have SpiderMonkey code in it, the constructor
159
# raises NotSpiderMonkeyObjfileError.
161
# Pretty-printer modules may add attributes to this to hold their own
162
# cached values. Such attributes should be named mod_NAME, where the module
163
# is named mozilla.NAME; for example, mozilla.JSString should store its
164
# metadata in the TypeCache's mod_JSString attribute.
165
class TypeCache(object):
166
def __init__(self, objfile):
167
self.objfile = objfile
169
# Unfortunately, the Python interface doesn't allow us to specify
170
# the objfile in whose scope lookups should occur. But simply
171
# knowing that we need to lookup the types afresh is probably
173
self.void_t = gdb.lookup_type('void')
174
self.void_ptr_t = self.void_t.pointer()
176
self.JSString_ptr_t = gdb.lookup_type('JSString').pointer()
177
self.JSObject_ptr_t = gdb.lookup_type('JSObject').pointer()
179
raise NotSpiderMonkeyObjfileError
181
self.mod_JSString = None
182
self.mod_JSObject = None
183
self.mod_jsval = None
185
# Yield a series of all the types that |t| implements, by following typedefs
186
# and iterating over base classes. Specifically:
187
# - |t| itself is the first value yielded.
188
# - If we yield a typedef, we later yield its definition.
189
# - If we yield a type with base classes, we later yield those base classes.
190
# - If we yield a type with some base classes that are typedefs,
191
# we yield all the type's base classes before following the typedefs.
192
# (Actually, this never happens, because G++ doesn't preserve the typedefs in
195
# This is a hokey attempt to order the implemented types by meaningfulness when
196
# pretty-printed. Perhaps it is entirely misguided, and we should actually
197
# collect all applicable pretty-printers, and then use some ordering on the
198
# pretty-printers themselves.
200
# We may yield a type more than once (say, if it appears more than once in the
202
def implemented_types(t):
204
# Yield all types that follow |t|.
206
if t.code == gdb.TYPE_CODE_TYPEDEF:
208
for t2 in followers(t.target()): yield t2
209
elif t.code == gdb.TYPE_CODE_STRUCT:
214
base_classes.append(f.type)
215
for b in base_classes:
216
for t2 in followers(b): yield t2
219
for t2 in followers(t): yield t2
221
template_regexp = re.compile("([\w_:]+)<")
223
# Construct and return a pretty-printer lookup function for objfile, or
224
# return None if the objfile doesn't contain SpiderMonkey code
225
# (specifically, definitions for SpiderMonkey types).
226
def lookup_for_objfile(objfile):
227
# Create a type cache for this objfile.
229
cache = TypeCache(objfile)
230
except NotSpiderMonkeyObjfileError:
231
if gdb.parameter("verbose"):
232
gdb.write("objfile '%s' has no SpiderMonkey code; not registering pretty-printers\n"
233
% (objfile.filename,))
236
# Return a pretty-printer for |value|, if we have one. This is the lookup
237
# function object we place in each gdb.Objfile's pretty-printers list, so it
238
# carries |name|, |enabled|, and |subprinters| attributes.
240
# If |table| has a pretty-printer for |tag|, apply it to |value|.
241
def check_table(table, tag):
245
return f(value, cache)
248
def check_table_by_type_name(table, t):
249
if t.code == gdb.TYPE_CODE_TYPEDEF:
250
return check_table(table, str(t))
251
elif t.code == gdb.TYPE_CODE_STRUCT and t.tag:
252
return check_table(table, t.tag)
256
for t in implemented_types(value.type):
257
if t.code == gdb.TYPE_CODE_PTR:
258
for t2 in implemented_types(t.target()):
259
p = check_table_by_type_name(ptr_printers_by_tag, t2)
261
elif t.code == gdb.TYPE_CODE_REF:
262
for t2 in implemented_types(t.target()):
263
p = check_table_by_type_name(ref_printers_by_tag, t2)
266
p = check_table_by_type_name(printers_by_tag, t)
268
if t.code == gdb.TYPE_CODE_STRUCT and t.tag:
269
m = template_regexp.match(t.tag)
271
p = check_table(template_printers_by_tag, m.group(1))
274
# Failing that, look for a printer in printers_by_regexp. We have
275
# to scan the whole list, so regexp printers should be used
278
for (r, f) in printers_by_regexp:
288
# Give |lookup| the attributes expected of a pretty-printer with
289
# subprinters, for enabling and disabling.
290
lookup.name = "SpiderMonkey"
291
lookup.enabled = True
292
lookup.subprinters = subprinters
296
# A base class for pretty-printers for pointer values that handles null
297
# pointers, by declining to construct a pretty-printer for them at all.
298
# Derived classes may simply assume that self.value is non-null.
300
# To help share code, this class can also be used with reference types.
302
# This class provides the following methods, which subclasses are free to
305
# __init__(self, value, cache): Save value and cache as properties by those names
308
# to_string(self): format the type's name and address, as GDB would, and then
309
# call a 'summary' method (which the subclass must define) to produce a
310
# description of the referent.
312
# Note that pretty-printers returning a 'string' display hint must not use
313
# this default 'to_string' method, as GDB will take everything it returns,
314
# including the type name and address, as string contents.
315
class Pointer(object):
316
def __new__(cls, value, cache):
317
# Don't try to provide pretty-printers for NULL pointers.
318
if value.type.strip_typedefs().code == gdb.TYPE_CODE_PTR and value == 0:
320
return super(Pointer, cls).__new__(cls)
322
def __init__(self, value, cache):
328
assert not hasattr(self, 'display_hint') or self.display_hint() != 'string'
329
concrete_type = self.value.type.strip_typedefs()
330
if concrete_type.code == gdb.TYPE_CODE_PTR:
331
address = self.value.cast(self.cache.void_ptr_t)
332
elif concrete_type.code == gdb.TYPE_CODE_REF:
333
address = '@' + str(self.value.address.cast(self.cache.void_ptr_t))
335
assert not "mozilla.prettyprinters.Pointer applied to bad value type"
337
summary = self.summary()
338
except gdb.MemoryError as r:
340
v = '(%s) %s %s' % (self.value.type, address, summary)
344
raise NotImplementedError
346
field_enum_value = None
348
# Given |t|, a gdb.Type instance representing an enum type, return the
349
# numeric value of the enum value named |name|.
351
# Pre-2012-4-18 versions of GDB store the value of an enum member on the
352
# gdb.Field's 'bitpos' attribute; later versions store it on the 'enumval'
353
# attribute. This function retrieves the value from either.
354
def enum_value(t, name):
355
global field_enum_value
357
# Monkey-patching is a-okay in polyfills! Just because.
358
if not field_enum_value:
359
if hasattr(f, 'enumval'):
360
field_enum_value = lambda f: f.enumval
362
field_enum_value = lambda f: f.bitpos
363
return field_enum_value(f)