You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2012/03/29 17:02:46 UTC
svn commit: r1306891 - /subversion/trunk/tools/dev/gdb-py/svndbg/printers.py
Author: julianfoad
Date: Thu Mar 29 15:02:45 2012
New Revision: 1306891
URL: http://svn.apache.org/viewvc?rev=1306891&view=rev
Log:
Expand the support for GDB to pretty-print Subversion data structures.
Building on Hyrum's work, this enables GDB to automatically print a
human-readable representation of a few more data structures. The most
significant change here is the introduction of matching on the type name as
it appears at the point of use, such as 'svn_mergeinfo_catalog_t'.
Previously we could only match on the structure tag name after stripping
away typedefs, so a 'svn_mergeinfo_catalog_t' (defined as 'apr_hash_t *'
could only have been printed as an 'apr_hash_t'. Now, however, we will
print just the keys of a plain apr_hash_t, but both the keys and the values
(which are nested hashes) of svn_mergeinfo_catalog_t.
* tools/dev/gdb-py/svndbg/printers.py
(TypedefRegexCollectionPrettyPrinter, InferiorFunction, children_as_map):
New classes and function for general pretty-printing.
(children_of_apr_hash, AprHashPrinter, PtrAprHashPrinter, AprArrayPrinter,
PtrAprArrayPrinter): New classes and functions for pretty-printing APR
types.
(SvnMergeinfoCatalogPrinter): New class for pretty-printing a Subversion
type.
(build_libsvn_printer, register_libsvn_printers): Initialize and register
the new printers. Add some commentary.
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=1306891&r1=1306890&r2=1306891&view=diff
==============================================================================
--- subversion/trunk/tools/dev/gdb-py/svndbg/printers.py (original)
+++ subversion/trunk/tools/dev/gdb-py/svndbg/printers.py Thu Mar 29 15:02:45 2012
@@ -24,8 +24,168 @@ import gdb
import re
import gdb.printing
+from gdb.printing import RegexpCollectionPrettyPrinter
+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."""
+
+ def __init__(self, name):
+ super(TypedefRegexCollectionPrettyPrinter, self).__init__(name)
+
+ def __call__(self, val):
+ """Lookup the pretty-printer for the provided value."""
+
+ # 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)
+
+ # Cannot find a pretty printer. Return None.
+ return None
+
+class InferiorFunction:
+ """A class whose instances are callable functions on the inferior
+ process."""
+ def __init__(self, function_name):
+ self.function_name = function_name
+ self.func = None
+
+ def __call__(self, *args):
+ if not self.func:
+ self.func = gdb.parse_and_eval(self.function_name)
+ return self.func(*args)
+
+def children_as_map(children_iterator):
+ """Convert an iteration of (key, value) pairs into the form required for
+ a pretty-printer 'children' method when the display-hint is 'map'."""
+ for k, v in children_iterator:
+ yield 'key', k
+ yield 'val', v
+
+
+########################################################################
+
+# Pretty-printing for APR library types.
+
+# Some useful gdb.Type instances that can be initialized before any object
+# files are loaded.
+pvoidType = gdb.lookup_type('void').pointer()
+cstringType = gdb.lookup_type('char').pointer()
+
+# Some functions that resolve to calls into the inferior process.
+apr_hash_count = InferiorFunction('apr_hash_count')
+apr_hash_first = InferiorFunction('apr_hash_first')
+apr_hash_next = InferiorFunction('apr_hash_next')
+svn__apr_hash_index_key = InferiorFunction('svn__apr_hash_index_key')
+svn__apr_hash_index_val = InferiorFunction('svn__apr_hash_index_val')
+
+def children_of_apr_hash(hash_p, value_type=None):
+ """Iterate over an 'apr_hash_t *' GDB value, in the way required for a
+ pretty-printer 'children' method when the display-hint is 'array'.
+ Cast the value pointers to VALUE_TYPE, or return values as '...' if
+ VALUE_TYPE is None."""
+ hi = apr_hash_first(0, hash_p)
+ while (hi):
+ k = svn__apr_hash_index_key(hi).reinterpret_cast(cstringType)
+ if value_type:
+ val = svn__apr_hash_index_val(hi).reinterpret_cast(value_type)
+ else:
+ val = '...'
+ try:
+ key = k.string()
+ except:
+ key = '<unreadable>'
+ yield key, val
+ hi = apr_hash_next(hi)
+
+class AprHashPrinter:
+ """for 'apr_hash_t' of 'char *' keys and unknown values"""
+ def __init__(self, val):
+ self.hash_p = val.address
+
+ def to_string(self):
+ """Return a string to be displayed before children are displayed, or
+ return None if we don't want any such."""
+ return 'hash of ' + str(apr_hash_count(self.hash_p)) + ' items'
+
+ def children(self):
+ if not self.hash_p:
+ return []
+ return children_as_map(children_of_apr_hash(self.hash_p))
+
+ def display_hint(self):
+ return 'map'
+
+class PtrAprHashPrinter(AprHashPrinter):
+ """for pointer to 'apr_hash_t' of 'char *' keys and unknown values"""
+ def __init__(self, val):
+ self.hash_p = val
+
+ def to_string(self):
+ if not self.hash_p:
+ return 'NULL'
+ return AprHashPrinter.to_string(self)
+
+ def children(self):
+ if not self.hash_p:
+ return []
+ return AprHashPrinter.children(self)
+
+class AprArrayPrinter:
+ """for 'apr_array_header_t' of unknown elements"""
+ def __init__(self, val):
+ self.array = val
+
+ def to_string(self):
+ if not self.array:
+ return 'NULL'
+ nelts = self.array['nelts']
+ return 'array of ' + str(int(nelts)) + ' items'
+
+ def children(self):
+ # We can't display the children as we don't know their type.
+ return []
+
+ def display_hint(self):
+ return 'array'
+
+class PtrAprArrayPrinter(AprArrayPrinter):
+ """for pointer to 'apr_array_header_t' of unknown elements"""
+ def __init__(self, val):
+ if not val:
+ self.array = None
+ else:
+ self.array = val.dereference()
+
+ def to_string(self):
+ if not self.array:
+ return 'NULL'
+ return AprArrayPrinter.to_string(self)
+
+ def children(self):
+ if not self.array:
+ return []
+ return AprArrayPrinter.children(self)
+
+
+########################################################################
+
+# Pretty-printing for Subversion library types.
+
class SvnStringPrinter:
def __init__(self, val):
self.val = val
@@ -42,22 +202,86 @@ class SvnStringPrinter:
def display_hint(self):
return 'string'
+class SvnMergeinfoCatalogPrinter:
+ """for svn_mergeinfo_catalog_t"""
+ def __init__(self, val):
+ self.hash_p = val
+
+ def to_string(self):
+ if self.hash_p == 0:
+ return 'NULL'
+ return 'mergeinfo catalog of ' + str(apr_hash_count(self.hash_p)) + ' items'
+
+ def children(self):
+ if self.hash_p == 0:
+ return None
+ mergeinfoType = gdb.lookup_type('svn_mergeinfo_t')
+ return children_as_map(children_of_apr_hash(self.hash_p, mergeinfoType))
+
+ def display_hint(self):
+ return 'map'
-def build_libsvn_printer():
- global libsvn_printer
- libsvn_printer = gdb.printing.RegexpCollectionPrettyPrinter("libsvn")
+########################################################################
+
+libapr_printer = None
+libapr_printer2 = None
+libsvn_printer = None
+libsvn_printer2 = None
- libsvn_printer.add_printer('svn_string_t', '^svn_string_t$',
+def build_libsvn_printers():
+ """Construct the pretty-printer objects."""
+
+ global libapr_printer, libapr_printer2, libsvn_printer, libsvn_printer2
+
+ # 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.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 them, but ideally we'd fix that
+ # matching and move these entries to there so that they get used
+ # 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 \*$',
+ PtrAprHashPrinter)
+ libapr_printer2.add_printer('apr_array_header_t *', r'^apr_array_header_t \*$',
+ PtrAprArrayPrinter)
+
+ # 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.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_mergeinfo_catalog_t', r'^svn_mergeinfo_catalog_t$',
+ SvnMergeinfoCatalogPrinter)
-libsvn_printer = None
def register_libsvn_printers(obj):
- global libsvn_printer
+ """Register the pretty-printers for the object file OBJ."""
+
+ global libapr_printer, libapr_printer2, libsvn_printer, libsvn_printer2
+ # 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)
-build_libsvn_printer()
+# Construct the pretty-printer objects, once, at GDB start-up time when this
+# Python module is loaded. (Registration happens later, once per object
+# file.)
+build_libsvn_printers()