Author: julianfoad
Date: Mon Jul 30 20:15:23 2012
New Revision: 1367262
URL: http://svn.apache.org/viewvc?rev=1367262&view=rev
Log:
Re-work the GDB pretty-printing support to make it simpler to implement
pretty-printing for commonly used data structure types and for pointers to
them.
* tools/dev/gdb-py/svndbg/printers.py
(TypedefRegexCollectionPrettyPrinter): Re-work to try looking up not only
the given type, but also the type with one or more layers of 'typedef'
stripped and/or a pointer dereferenced.
(AprHashPrinter, AprArrayPrinter, SvnStringPrinter, SvnMergeRangePrinter,
SvnRangelistPrinter): Assume that the value is not a pointer but that it
may be 'None'.
(libapr_printer2, libsvn_printer2): Remove.
(build_libsvn_printers, register_libsvn_printers): Simplify accordingly.
Modified:
subversion/trunk/tools/dev/gdb-py/svndbg/printers.py
Modified: subversion/trunk/tools/dev/gdb-py/svndbg/printers.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/tools/dev/gdb-py/svndbg/printers.py?rev=1367262&r1=1367261&r2=1367262&view=diff
==============================================================================
--- subversion/trunk/tools/dev/gdb-py/svndbg/printers.py (original)
+++ subversion/trunk/tools/dev/gdb-py/svndbg/printers.py Mon Jul 30 20:15:23
2012
@@ -28,34 +28,86 @@ from gdb.printing import RegexpCollectio
class TypedefRegexCollectionPrettyPrinter(RegexpCollectionPrettyPrinter):
- """Class for implementing a collection of regular-expression based
- pretty-printers, matching on the type name at the point of use, such
- as (but not necessarily) a 'typedef' name, ignoring 'const' or
- 'volatile' qualifiers.
-
- This is modeled on RegexpCollectionPrettyPrinter, which (in GDB 7.3)
- matches on the base type's tag name and can't match a pointer type or
- any other type that doesn't have a tag name.
+ """Class for implementing a collection of pretty-printers, matching the
+ type name to a regular expression.
+
+ A pretty-printer in this collection will be used if the type of the
+ value to be printed matches the printer's regular expression, or if
+ the value is a pointer to and/or typedef to a type name that matches
+ its regular expression. The variations are tried in this order:
+
+ 1. the type name as known to the debugger (could be a 'typedef');
+ 2. the type after stripping off any number of layers of 'typedef';
+ 3. if it is a pointer, the pointed-to type;
+ 4. if it is a pointer, the pointed-to type minus some 'typedef's.
+
+ In all cases, ignore 'const' and 'volatile' qualifiers. When
+ matching the pointed-to type, dereference the value or use 'None' if
+ the value was a null pointer.
+
+ This class is modeled on RegexpCollectionPrettyPrinter, which (in GDB
+ 7.3) matches on the base type's tag name and can't match a pointer
+ type or any other type that doesn't have a tag name.
"""
def __init__(self, name):
super(TypedefRegexCollectionPrettyPrinter, self).__init__(name)
def __call__(self, val):
- """Lookup the pretty-printer for the provided value."""
+ """Find and return an instantiation of a printer for VAL.
+ """
- # Get the type name, without 'const' or 'volatile' qualifiers.
- typename = str(val.type.unqualified())
- if not typename:
- return None
-
- # Iterate over table of type regexps to find an enabled printer for
- # that type. Return an instantiation of the printer if found.
- for printer in self.subprinters:
- if printer.enabled and printer.compiled_re.search(typename):
- return printer.gen_printer(val)
+ def lookup_type(type, val):
+ """Return the first printer whose regular expression matches the
+ name (tag name for struct/union/enum types) of TYPE, ignoring
+ any 'const' or 'volatile' qualifiers.
+
+ VAL is a gdb.Value, or may be None to indicate a dereferenced
+ null pointer. TYPE is the associated gdb.Type.
+ """
+ if type.code in [gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION,
+ gdb.TYPE_CODE_ENUM]:
+ typename = type.tag
+ else:
+ typename = str(type.unqualified())
+ for printer in self.subprinters:
+ if printer.enabled and printer.compiled_re.search(typename):
+ return printer.gen_printer(val)
+
+ def lookup_type_or_alias(type, val):
+ """Return the first printer matching TYPE, or else if TYPE is a
+ typedef then the first printer matching the aliased type.
+
+ VAL is a gdb.Value, or may be None to indicate a dereferenced
+ null pointer. TYPE is the associated gdb.Type.
+ """
+ # First, look for a printer for the given (but unqualified) type.
+ printer = lookup_type(type, val)
+ if printer:
+ return printer
+
+ # If it's a typedef, look for a printer for the aliased type ...
+ while type.code == gdb.TYPE_CODE_TYPEDEF:
+ type = type.target()
+ printer = lookup_type(type, val)
+ if printer:
+ return printer
+
+ # First, look for a printer for the given (but unqualified) type, or
+ # its aliased type if it's a typedef.
+ printer = lookup_type_or_alias(val.type, val)
+ if printer:
+ return printer
+
+ # If it's a pointer, look for a printer for the pointed-to type.
+ if val.type.code == gdb.TYPE_CODE_PTR:
+ type = val.type.target()
+ printer = lookup_type_or_alias(
+ type, val and val.dereference() or None)
+ if printer:
+ return printer
- # Cannot find a pretty printer. Return None.
+ # Cannot find a matching pretty printer in this collection.
return None
class InferiorFunction:
@@ -119,10 +171,10 @@ def children_of_apr_hash(hash_p, value_t
class AprHashPrinter:
"""for 'apr_hash_t' of 'char *' keys and unknown values"""
def __init__(self, val):
- if val.type.code == gdb.TYPE_CODE_PTR:
- self.hash_p = val
- else:
+ if val:
self.hash_p = val.address
+ else:
+ self.hash_p = val
def to_string(self):
"""Return a string to be displayed before children are displayed, or
@@ -153,10 +205,7 @@ def children_of_apr_array(array, value_t
class AprArrayPrinter:
"""for 'apr_array_header_t' of unknown elements"""
def __init__(self, val):
- if val.type.code == gdb.TYPE_CODE_PTR and val:
- self.array = val.dereference()
- else:
- self.array = val
+ self.array = val
def to_string(self):
if not self.array:
@@ -178,10 +227,7 @@ class AprArrayPrinter:
class SvnStringPrinter:
"""for svn_string_t"""
def __init__(self, val):
- if val.type.code == gdb.TYPE_CODE_PTR and val:
- self.val = val.dereference()
- else:
- self.val = val
+ self.val = val
def to_string(self):
if not self.val:
@@ -197,10 +243,7 @@ class SvnStringPrinter:
class SvnMergeRangePrinter:
"""for svn_merge_range_t"""
def __init__(self, val):
- if val.type.code == gdb.TYPE_CODE_PTR and val:
- self.val = val.dereference()
- else:
- self.val = val
+ self.val = val
def to_string(self):
if not self.val:
@@ -231,10 +274,7 @@ class SvnMergeRangePrinter:
class SvnRangelistPrinter:
"""for svn_rangelist_t"""
def __init__(self, val):
- if val.type.code == gdb.TYPE_CODE_PTR and val:
- self.array = val.dereference()
- else:
- self.array = val
+ self.array = val
self.svn_merge_range_t = gdb.lookup_type('svn_merge_range_t')
def to_string(self):
@@ -311,79 +351,42 @@ class SvnPathrevPrinter:
########################################################################
libapr_printer = None
-libapr_printer2 = None
libsvn_printer = None
-libsvn_printer2 = None
def build_libsvn_printers():
"""Construct the pretty-printer objects."""
- global libapr_printer, libapr_printer2, libsvn_printer, libsvn_printer2
+ global libapr_printer, libsvn_printer
- # These sub-printers match a struct's (or union)'s tag name,
- # after stripping typedefs, references and const/volatile qualifiers.
- libapr_printer = RegexpCollectionPrettyPrinter("libapr")
+ libapr_printer = TypedefRegexCollectionPrettyPrinter("libapr")
libapr_printer.add_printer('apr_hash_t', r'^apr_hash_t$',
AprHashPrinter)
libapr_printer.add_printer('apr_array_header_t', r'^apr_array_header_t$',
AprArrayPrinter)
- # These sub-printers match a type name at the point of use,
- # after stripping const/volatile qualifiers.
- #
- # TODO: The "apr_foo_t *" entries are in this collection merely because
- # the collection above can't match any pointer type (because the
- # pointer itself has no tag-name). Ideally we'd improve that
- # matching so that for example the 'apr_hash_t *' entry would
- # match both
- # any typedef that resolves to pointer-to-apr_hash_t
- # and
- # pointer to any typedef that resolves to apr_hash_t
- # for any typedef that doesn't have its own specific pretty-printer
- # registered.
- libapr_printer2 = TypedefRegexCollectionPrettyPrinter("libapr2")
- libapr_printer2.add_printer('apr_hash_t *', r'^apr_hash_t \*$',
- AprHashPrinter)
- libapr_printer2.add_printer('apr_array_header_t *', r'^apr_array_header_t
\*$',
- AprArrayPrinter)
-
- # These sub-printers match a struct's (or union)'s tag name,
- # after stripping typedefs, references and const/volatile qualifiers.
- libsvn_printer = RegexpCollectionPrettyPrinter("libsvn")
+ libsvn_printer = TypedefRegexCollectionPrettyPrinter("libsvn")
libsvn_printer.add_printer('svn_string_t', r'^svn_string_t$',
SvnStringPrinter)
-
- # These sub-printers match a type name at the point of use,
- # after stripping const/volatile qualifiers.
- libsvn_printer2 = TypedefRegexCollectionPrettyPrinter("libsvn2")
- libsvn_printer2.add_printer('svn_string_t *', r'^svn_string_t \*$',
- SvnStringPrinter)
- libsvn_printer2.add_printer('svn_client__pathrev_t',
r'^svn_client__pathrev_t$',
- SvnPathrevPrinter)
- libsvn_printer2.add_printer('svn_merge_range_t', r'^svn_merge_range_t$',
- SvnMergeRangePrinter)
- libsvn_printer2.add_printer('svn_merge_range_t *', r'^svn_merge_range_t
\*$',
- SvnMergeRangePrinter)
- libsvn_printer2.add_printer('svn_rangelist_t', r'^svn_rangelist_t$',
- SvnRangelistPrinter)
- libsvn_printer2.add_printer('svn_rangelist_t *', r'^svn_rangelist_t \*$',
- SvnRangelistPrinter)
- libsvn_printer2.add_printer('svn_mergeinfo_t', r'^svn_mergeinfo_t$',
- SvnMergeinfoPrinter)
- libsvn_printer2.add_printer('svn_mergeinfo_catalog_t',
r'^svn_mergeinfo_catalog_t$',
- SvnMergeinfoCatalogPrinter)
+ libsvn_printer.add_printer('svn_client__pathrev_t',
r'^svn_client__pathrev_t$',
+ SvnPathrevPrinter)
+ libsvn_printer.add_printer('svn_merge_range_t', r'^svn_merge_range_t$',
+ SvnMergeRangePrinter)
+ libsvn_printer.add_printer('svn_rangelist_t', r'^svn_rangelist_t$',
+ SvnRangelistPrinter)
+ libsvn_printer.add_printer('svn_mergeinfo_t', r'^svn_mergeinfo_t$',
+ SvnMergeinfoPrinter)
+ libsvn_printer.add_printer('svn_mergeinfo_catalog_t',
r'^svn_mergeinfo_catalog_t$',
+ SvnMergeinfoCatalogPrinter)
def register_libsvn_printers(obj):
"""Register the pretty-printers for the object file OBJ."""
- global libapr_printer, libapr_printer2, libsvn_printer, libsvn_printer2
+ global libapr_printer, libsvn_printer
# Printers registered later take precedence.
gdb.printing.register_pretty_printer(obj, libapr_printer)
- gdb.printing.register_pretty_printer(obj, libapr_printer2)
gdb.printing.register_pretty_printer(obj, libsvn_printer)
- gdb.printing.register_pretty_printer(obj, libsvn_printer2)
# Construct the pretty-printer objects, once, at GDB start-up time when this