New python module gdb.printing, and new commands info pretty-printer,
enable pretty-printer, disable pretty-printer. * NEWS: Mention them. * data-directory/Makefile.in (PYTHON_FILES): Add gdb/printing.py, gdb/command/__init__.py, gdb/command/pretty_printers.py. * python/lib/gdb/__init__.py: Install pretty-printer commands. * python/lib/gdb/printing.py: New file. * python/lib/gdb/command/__init__.py: New file. * python/lib/gdb/command/pretty_printers.py: New file. doc/ * gdb.texinfo (Pretty Printing): Expand into three sections, introduction, example, and commands. (Python API): Delete section Disabling Pretty-Printers, merge into Selecting Pretty-Printers. (Writing a Pretty-Printer): New section. Move the pretty-printer example here, and reformat to match python coding style. Add a second example using the gdb.printing module. (Python modules): Add gdb.printing. testsuite/ * gdb.python/py-pp-maint.c: New file. * gdb.python/py-pp-maint.exp: New file. * gdb.python/py-pp-maint.py: New file.
This commit is contained in:
parent
50c97f3812
commit
7b51bc51e1
13 changed files with 1184 additions and 42 deletions
|
@ -12,3 +12,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import gdb.command.pretty_printers
|
||||
|
||||
gdb.command.pretty_printers.register_pretty_printer_commands()
|
||||
|
|
16
gdb/python/lib/gdb/command/__init__.py
Normal file
16
gdb/python/lib/gdb/command/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
369
gdb/python/lib/gdb/command/pretty_printers.py
Normal file
369
gdb/python/lib/gdb/command/pretty_printers.py
Normal file
|
@ -0,0 +1,369 @@
|
|||
# Pretty-printer commands.
|
||||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""GDB commands for working with pretty-printers."""
|
||||
|
||||
import copy
|
||||
import gdb
|
||||
import re
|
||||
|
||||
|
||||
def parse_printer_regexps(arg):
|
||||
"""Internal utility to parse a pretty-printer command argv.
|
||||
|
||||
Arguments:
|
||||
arg: The arguments to the command. The format is:
|
||||
[object-regexp [name-regexp]].
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
|
||||
Returns:
|
||||
The result is a 3-tuple of compiled regular expressions, except that
|
||||
the resulting compiled subprinter regexp is None if not provided.
|
||||
|
||||
Raises:
|
||||
SyntaxError: an error processing ARG
|
||||
"""
|
||||
|
||||
argv = gdb.string_to_argv(arg);
|
||||
argc = len(argv)
|
||||
object_regexp = "" # match everything
|
||||
name_regexp = "" # match everything
|
||||
subname_regexp = None
|
||||
if argc > 3:
|
||||
raise SyntaxError("too many arguments")
|
||||
if argc >= 1:
|
||||
object_regexp = argv[0]
|
||||
if argc >= 2:
|
||||
name_subname = argv[1].split(":", 1)
|
||||
name_regexp = name_subname[0]
|
||||
if len(name_subname) == 2:
|
||||
subname_regexp = name_subname[1]
|
||||
# That re.compile raises SyntaxError was determined empirically.
|
||||
# We catch it and reraise it to provide a slightly more useful
|
||||
# error message for the user.
|
||||
try:
|
||||
object_re = re.compile(object_regexp)
|
||||
except SyntaxError:
|
||||
raise SyntaxError("invalid object regexp: %s" % object_regexp)
|
||||
try:
|
||||
name_re = re.compile (name_regexp)
|
||||
except SyntaxError:
|
||||
raise SyntaxError("invalid name regexp: %s" % name_regexp)
|
||||
if subname_regexp is not None:
|
||||
try:
|
||||
subname_re = re.compile(subname_regexp)
|
||||
except SyntaxError:
|
||||
raise SyntaxError("invalid subname regexp: %s" % subname_regexp)
|
||||
else:
|
||||
subname_re = None
|
||||
return(object_re, name_re, subname_re)
|
||||
|
||||
|
||||
def printer_enabled_p(printer):
|
||||
"""Internal utility to see if printer (or subprinter) is enabled."""
|
||||
if hasattr(printer, "enabled"):
|
||||
return printer.enabled
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class InfoPrettyPrinter(gdb.Command):
|
||||
"""GDB command to list all registered pretty-printers.
|
||||
|
||||
Usage: info pretty-printer [object-regexp [name-regexp]]
|
||||
|
||||
OBJECT-REGEXP is a regular expression matching the objects to list.
|
||||
Objects are "global", the program space's file, and the objfiles within
|
||||
that program space.
|
||||
|
||||
NAME-REGEXP matches the name of the pretty-printer.
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
"""
|
||||
|
||||
def __init__ (self):
|
||||
super(InfoPrettyPrinter, self).__init__("info pretty-printer",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
@staticmethod
|
||||
def enabled_string(printer):
|
||||
"""Return "" if PRINTER is enabled, otherwise " [disabled]"."""
|
||||
if printer_enabled_p(printer):
|
||||
return ""
|
||||
else:
|
||||
return " [disabled]"
|
||||
|
||||
@staticmethod
|
||||
def printer_name(printer):
|
||||
"""Return the printer's name."""
|
||||
if hasattr(printer, "name"):
|
||||
return printer.name
|
||||
if hasattr(printer, "__name__"):
|
||||
return printer.__name__
|
||||
# This "shouldn't happen", but the public API allows for
|
||||
# direct additions to the pretty-printer list, and we shouldn't
|
||||
# crash because someone added a bogus printer.
|
||||
# Plus we want to give the user a way to list unknown printers.
|
||||
return "unknown"
|
||||
|
||||
def list_pretty_printers(self, pretty_printers, name_re, subname_re):
|
||||
"""Print a list of pretty-printers."""
|
||||
# A potential enhancement is to provide an option to list printers in
|
||||
# "lookup order" (i.e. unsorted).
|
||||
sorted_pretty_printers = copy.copy(pretty_printers)
|
||||
sorted_pretty_printers.sort(lambda x, y:
|
||||
cmp(self.printer_name(x),
|
||||
self.printer_name(y)))
|
||||
for printer in sorted_pretty_printers:
|
||||
name = self.printer_name(printer)
|
||||
enabled = self.enabled_string(printer)
|
||||
if name_re.match(name):
|
||||
print " %s%s" % (name, enabled)
|
||||
if (hasattr(printer, "subprinters") and
|
||||
printer.subprinters is not None):
|
||||
sorted_subprinters = copy.copy(printer.subprinters)
|
||||
sorted_subprinters.sort(lambda x, y:
|
||||
cmp(self.printer_name(x),
|
||||
self.printer_name(y)))
|
||||
for subprinter in sorted_subprinters:
|
||||
if (not subname_re or
|
||||
subname_re.match(subprinter.name)):
|
||||
print (" %s%s" %
|
||||
(subprinter.name,
|
||||
self.enabled_string(subprinter)))
|
||||
|
||||
def invoke1(self, title, printer_list,
|
||||
obj_name_to_match, object_re, name_re, subname_re):
|
||||
""""Subroutine of invoke to simplify it."""
|
||||
if printer_list and object_re.match(obj_name_to_match):
|
||||
print title
|
||||
self.list_pretty_printers(printer_list, name_re, subname_re)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
(object_re, name_re, subname_re) = parse_printer_regexps(arg)
|
||||
self.invoke1("global pretty-printers:", gdb.pretty_printers,
|
||||
"global", object_re, name_re, subname_re)
|
||||
cp = gdb.current_progspace()
|
||||
self.invoke1("progspace %s pretty-printers:" % cp.filename,
|
||||
cp.pretty_printers, "progspace",
|
||||
object_re, name_re, subname_re)
|
||||
for objfile in gdb.objfiles():
|
||||
self.invoke1(" objfile %s pretty-printers:" % objfile.filename,
|
||||
objfile.pretty_printers, objfile.filename,
|
||||
object_re, name_re, subname_re)
|
||||
|
||||
|
||||
def count_enabled_printers(pretty_printers):
|
||||
"""Return a 2-tuple of number of enabled and total printers."""
|
||||
enabled = 0
|
||||
total = 0
|
||||
for printer in pretty_printers:
|
||||
if (hasattr(printer, "subprinters")
|
||||
and printer.subprinters is not None):
|
||||
if printer_enabled_p(printer):
|
||||
for subprinter in printer.subprinters:
|
||||
if printer_enabled_p(subprinter):
|
||||
enabled += 1
|
||||
total += len(printer.subprinters)
|
||||
else:
|
||||
if printer_enabled_p(printer):
|
||||
enabled += 1
|
||||
total += 1
|
||||
return (enabled, total)
|
||||
|
||||
|
||||
def count_all_enabled_printers():
|
||||
"""Return a 2-tuble of the enabled state and total number of all printers.
|
||||
This includes subprinters.
|
||||
"""
|
||||
enabled_count = 0
|
||||
total_count = 0
|
||||
(t_enabled, t_total) = count_enabled_printers(gdb.pretty_printers)
|
||||
enabled_count += t_enabled
|
||||
total_count += t_total
|
||||
(t_enabled, t_total) = count_enabled_printers(gdb.current_progspace().pretty_printers)
|
||||
enabled_count += t_enabled
|
||||
total_count += t_total
|
||||
for objfile in gdb.objfiles():
|
||||
(t_enabled, t_total) = count_enabled_printers(objfile.pretty_printers)
|
||||
enabled_count += t_enabled
|
||||
total_count += t_total
|
||||
return (enabled_count, total_count)
|
||||
|
||||
|
||||
def pluralize(text, n, suffix="s"):
|
||||
"""Return TEXT pluralized if N != 1."""
|
||||
if n != 1:
|
||||
return "%s%s" % (text, suffix)
|
||||
else:
|
||||
return text
|
||||
|
||||
|
||||
def show_pretty_printer_enabled_summary():
|
||||
"""Print the number of printers enabled/disabled.
|
||||
We count subprinters individually.
|
||||
"""
|
||||
(enabled_count, total_count) = count_all_enabled_printers()
|
||||
print "%d of %d printers enabled" % (enabled_count, total_count)
|
||||
|
||||
|
||||
def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag):
|
||||
"""Worker for enabling/disabling pretty-printers.
|
||||
|
||||
Arguments:
|
||||
pretty_printers: list of pretty-printers
|
||||
name_re: regular-expression object to select printers
|
||||
subname_re: regular expression object to select subprinters or None
|
||||
if all are affected
|
||||
flag: True for Enable, False for Disable
|
||||
|
||||
Returns:
|
||||
The number of printers affected.
|
||||
This is just for informational purposes for the user.
|
||||
"""
|
||||
total = 0
|
||||
for printer in pretty_printers:
|
||||
if (hasattr(printer, "name") and name_re.match(printer.name) or
|
||||
hasattr(printer, "__name__") and name_re.match(printer.__name__)):
|
||||
if hasattr(printer, "subprinters"):
|
||||
if not subname_re:
|
||||
# Only record printers that change state.
|
||||
if printer_enabled_p(printer) != flag:
|
||||
for subprinter in printer.subprinters:
|
||||
if printer_enabled_p(subprinter):
|
||||
total += 1
|
||||
# NOTE: We preserve individual subprinter settings.
|
||||
printer.enabled = flag
|
||||
else:
|
||||
# NOTE: Whether this actually disables the subprinter
|
||||
# depends on whether the printer's lookup function supports
|
||||
# the "enable" API. We can only assume it does.
|
||||
for subprinter in printer.subprinters:
|
||||
if subname_re.match(subprinter.name):
|
||||
# Only record printers that change state.
|
||||
if (printer_enabled_p(printer) and
|
||||
printer_enabled_p(subprinter) != flag):
|
||||
total += 1
|
||||
subprinter.enabled = flag
|
||||
else:
|
||||
# This printer has no subprinters.
|
||||
# If the user does "disable pretty-printer .* .* foo"
|
||||
# should we disable printers that don't have subprinters?
|
||||
# How do we apply "foo" in this context? Since there is no
|
||||
# "foo" subprinter it feels like we should skip this printer.
|
||||
# There's still the issue of how to handle
|
||||
# "disable pretty-printer .* .* .*", and every other variation
|
||||
# that can match everything. For now punt and only support
|
||||
# "disable pretty-printer .* .*" (i.e. subname is elided)
|
||||
# to disable everything.
|
||||
if not subname_re:
|
||||
# Only record printers that change state.
|
||||
if printer_enabled_p(printer) != flag:
|
||||
total += 1
|
||||
printer.enabled = flag
|
||||
return total
|
||||
|
||||
|
||||
def do_enable_pretty_printer (arg, flag):
|
||||
"""Internal worker for enabling/disabling pretty-printers."""
|
||||
(object_re, name_re, subname_re) = parse_printer_regexps(arg)
|
||||
|
||||
total = 0
|
||||
if object_re.match("global"):
|
||||
total += do_enable_pretty_printer_1(gdb.pretty_printers,
|
||||
name_re, subname_re, flag)
|
||||
cp = gdb.current_progspace()
|
||||
if object_re.match("progspace"):
|
||||
total += do_enable_pretty_printer_1(cp.pretty_printers,
|
||||
name_re, subname_re, flag)
|
||||
for objfile in gdb.objfiles():
|
||||
if object_re.match(objfile.filename):
|
||||
total += do_enable_pretty_printer_1(objfile.pretty_printers,
|
||||
name_re, subname_re, flag)
|
||||
|
||||
if flag:
|
||||
state = "enabled"
|
||||
else:
|
||||
state = "disabled"
|
||||
print "%d %s %s" % (total, pluralize("printer", total), state)
|
||||
|
||||
# Print the total list of printers currently enabled/disabled.
|
||||
# This is to further assist the user in determining whether the result
|
||||
# is expected. Since we use regexps to select it's useful.
|
||||
show_pretty_printer_enabled_summary()
|
||||
|
||||
|
||||
# Enable/Disable one or more pretty-printers.
|
||||
#
|
||||
# This is intended for use when a broken pretty-printer is shipped/installed
|
||||
# and the user wants to disable that printer without disabling all the other
|
||||
# printers.
|
||||
#
|
||||
# A useful addition would be -v (verbose) to show each printer affected.
|
||||
|
||||
class EnablePrettyPrinter (gdb.Command):
|
||||
"""GDB command to enable the specified pretty-printer.
|
||||
|
||||
Usage: enable pretty-printer [object-regexp [name-regexp]]
|
||||
|
||||
OBJECT-REGEXP is a regular expression matching the objects to examine.
|
||||
Objects are "global", the program space's file, and the objfiles within
|
||||
that program space.
|
||||
|
||||
NAME-REGEXP matches the name of the pretty-printer.
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(EnablePrettyPrinter, self).__init__("enable pretty-printer",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
do_enable_pretty_printer(arg, True)
|
||||
|
||||
|
||||
class DisablePrettyPrinter (gdb.Command):
|
||||
"""GDB command to disable the specified pretty-printer.
|
||||
|
||||
Usage: disable pretty-printer [object-regexp [name-regexp]]
|
||||
|
||||
OBJECT-REGEXP is a regular expression matching the objects to examine.
|
||||
Objects are "global", the program space's file, and the objfiles within
|
||||
that program space.
|
||||
|
||||
NAME-REGEXP matches the name of the pretty-printer.
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(DisablePrettyPrinter, self).__init__("disable pretty-printer",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
do_enable_pretty_printer(arg, False)
|
||||
|
||||
|
||||
def register_pretty_printer_commands():
|
||||
"""Call from a top level script to install the pretty-printer commands."""
|
||||
InfoPrettyPrinter()
|
||||
EnablePrettyPrinter()
|
||||
DisablePrettyPrinter()
|
197
gdb/python/lib/gdb/printing.py
Normal file
197
gdb/python/lib/gdb/printing.py
Normal file
|
@ -0,0 +1,197 @@
|
|||
# Pretty-printer utilities.
|
||||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Utilities for working with pretty-printers."""
|
||||
|
||||
import gdb
|
||||
import gdb.types
|
||||
import re
|
||||
|
||||
|
||||
class PrettyPrinter(object):
|
||||
"""A basic pretty-printer.
|
||||
|
||||
Attributes:
|
||||
name: A unique string among all printers for the context in which
|
||||
it is defined (objfile, progspace, or global(gdb)), and should
|
||||
meaningfully describe what can be pretty-printed.
|
||||
E.g., "StringPiece" or "protobufs".
|
||||
subprinters: An iterable object with each element having a `name'
|
||||
attribute, and, potentially, "enabled" attribute.
|
||||
Or this is None if there are no subprinters.
|
||||
enabled: A boolean indicating if the printer is enabled.
|
||||
|
||||
Subprinters are for situations where "one" pretty-printer is actually a
|
||||
collection of several printers. E.g., The libstdc++ pretty-printer has
|
||||
a pretty-printer for each of several different types, based on regexps.
|
||||
"""
|
||||
|
||||
# While one might want to push subprinters into the subclass, it's
|
||||
# present here to formalize such support to simplify
|
||||
# commands/pretty_printers.py.
|
||||
|
||||
def __init__(self, name, subprinters=None):
|
||||
self.name = name
|
||||
self.subprinters = subprinters
|
||||
self.enabled = True
|
||||
|
||||
def __call__(self, val):
|
||||
# The subclass must define this.
|
||||
raise NotImplementedError("PrettyPrinter __call__")
|
||||
|
||||
|
||||
class SubPrettyPrinter(object):
|
||||
"""Baseclass for sub-pretty-printers.
|
||||
|
||||
Sub-pretty-printers needn't use this, but it formalizes what's needed.
|
||||
|
||||
Attributes:
|
||||
name: The name of the subprinter.
|
||||
enabled: A boolean indicating if the subprinter is enabled.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.enabled = True
|
||||
|
||||
|
||||
def register_pretty_printer(obj, printer):
|
||||
"""Register pretty-printer PRINTER with OBJ.
|
||||
|
||||
The printer is added to the front of the search list, thus one can override
|
||||
an existing printer if one needs to.
|
||||
|
||||
Arguments:
|
||||
obj: Either an objfile, progspace, or None (in which case the printer
|
||||
is registered globally).
|
||||
printer: Either a function of one argument (old way) or any object
|
||||
which has attributes: name, enabled, __call__.
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
|
||||
Raises:
|
||||
TypeError: A problem with the type of the printer.
|
||||
ValueError: The printer's name contains a colon ":".
|
||||
|
||||
If the caller wants the printer to be listable and disableable, it must
|
||||
follow the PrettyPrinter API. This applies to the old way (functions) too.
|
||||
If printer is an object, __call__ is a method of two arguments:
|
||||
self, and the value to be pretty-printed. See PrettyPrinter.
|
||||
"""
|
||||
|
||||
# Watch for both __name__ and name.
|
||||
# Functions get the former for free, but we don't want to use an
|
||||
# attribute named __foo__ for pretty-printers-as-objects.
|
||||
# If printer has both, we use `name'.
|
||||
if not hasattr(printer, "__name__") and not hasattr(printer, "name"):
|
||||
raise TypeError("printer missing attribute: name")
|
||||
if hasattr(printer, "name") and not hasattr(printer, "enabled"):
|
||||
raise TypeError("printer missing attribute: enabled")
|
||||
if not hasattr(printer, "__call__"):
|
||||
raise TypeError("printer missing attribute: __call__")
|
||||
|
||||
if obj is None:
|
||||
if gdb.parameter("verbose"):
|
||||
gdb.write("Registering global %s pretty-printer ...\n" % name)
|
||||
obj = gdb
|
||||
else:
|
||||
if gdb.parameter("verbose"):
|
||||
gdb.write("Registering %s pretty-printer for %s ...\n" %
|
||||
(printer.name, obj.filename))
|
||||
|
||||
if hasattr(printer, "name"):
|
||||
if not isinstance(printer.name, basestring):
|
||||
raise TypeError("printer name is not a string")
|
||||
# If printer provides a name, make sure it doesn't contain ":".
|
||||
# Colon is used by the info/enable/disable pretty-printer commands
|
||||
# to delimit subprinters.
|
||||
if printer.name.find(":") >= 0:
|
||||
raise ValueError("colon ':' in printer name")
|
||||
# Also make sure the name is unique.
|
||||
# Alas, we can't do the same for functions and __name__, they could
|
||||
# all have a canonical name like "lookup_function".
|
||||
# PERF: gdb records printers in a list, making this inefficient.
|
||||
if (printer.name in
|
||||
[p.name for p in obj.pretty_printers if hasattr(p, "name")]):
|
||||
raise RuntimeError("pretty-printer already registered: %s" %
|
||||
printer.name)
|
||||
|
||||
obj.pretty_printers.insert(0, printer)
|
||||
|
||||
|
||||
class RegexpCollectionPrettyPrinter(PrettyPrinter):
|
||||
"""Class for implementing a collection of regular-expression based pretty-printers.
|
||||
|
||||
Intended usage:
|
||||
|
||||
pretty_printer = RegexpCollectionPrettyPrinter("my_library")
|
||||
pretty_printer.add_printer("myclass1", "^myclass1$", MyClass1Printer)
|
||||
...
|
||||
pretty_printer.add_printer("myclassN", "^myclassN$", MyClassNPrinter)
|
||||
register_pretty_printer(obj, pretty_printer)
|
||||
"""
|
||||
|
||||
class RegexpSubprinter(SubPrettyPrinter):
|
||||
def __init__(self, name, regexp, gen_printer):
|
||||
super(RegexpCollectionPrettyPrinter.RegexpSubprinter, self).__init__(name)
|
||||
self.regexp = regexp
|
||||
self.gen_printer = gen_printer
|
||||
self.compiled_re = re.compile(regexp)
|
||||
|
||||
def __init__(self, name):
|
||||
super(RegexpCollectionPrettyPrinter, self).__init__(name, [])
|
||||
|
||||
def add_printer(self, name, regexp, gen_printer):
|
||||
"""Add a printer to the list.
|
||||
|
||||
The printer is added to the end of the list.
|
||||
|
||||
Arguments:
|
||||
name: The name of the subprinter.
|
||||
regexp: The regular expression, as a string.
|
||||
gen_printer: A function/method that given a value returns an
|
||||
object to pretty-print it.
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
"""
|
||||
|
||||
# NOTE: A previous version made the name of each printer the regexp.
|
||||
# That makes it awkward to pass to the enable/disable commands (it's
|
||||
# cumbersome to make a regexp of a regexp). So now the name is a
|
||||
# separate parameter.
|
||||
|
||||
self.subprinters.append(self.RegexpSubprinter(name, regexp,
|
||||
gen_printer))
|
||||
|
||||
def __call__(self, val):
|
||||
"""Lookup the pretty-printer for the provided value."""
|
||||
|
||||
# Get the type name.
|
||||
typename = gdb.types.get_basic_type(val.type).tag
|
||||
if not typename:
|
||||
return None
|
||||
|
||||
# Iterate over table of type regexps to determine
|
||||
# if a printer is registered 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
|
Loading…
Add table
Add a link
Reference in a new issue