This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFC] new commands: info pretty-printers, enable/disable pretty-printer
- From: dje at google dot com (Doug Evans)
- To: gdb-patches at sourceware dot org
- Date: Tue, 8 Jun 2010 12:33:38 -0700 (PDT)
- Subject: [RFC] new commands: info pretty-printers, enable/disable pretty-printer
Hi.
This patch provides a convention for naming pretty printers,
adds support for the common case of using a regexp on the type name,
and adds 3 new commands, written in python:
info pretty-printers [obj-regexp [name-regexp [subname-regexp]]]
enable pretty-printer [obj-regexp [name-regexp [subname-regexp]]]
disable pretty-printer [obj-regexp [name-regexp [subname-regexp]]]
obj-regexp is used to denote which pretty-printer list:
gdb, current-progspace, or objfile.
name-regexp is the name of the pretty-printer, e.g. for libstdc++
it could be "libstdc++".
subname-regexp is there because one "pretty-printer" can print an
arbitrary number of types.
This is just a strawman. [No NEWS, docs, this is just RFC.]
How *do* we want this to work, if at all?
Comments?
The testcase punts on testing this when build != host.
The preferred way of testing this is to set up a python module library
on the [possibly) remote host, but I can't find support in dejagnu for
setting up directories on the remote host (perhaps I missed it of course).
Example from the testcase:
(gdb) info pretty-printers
global pretty-printers:
pp-test
^struct s$
^s$
^struct ss$
^ss$
(gdb) disable pretty-printer global pp-test .*
4 printers disabled
0 printers enabled, 4 total printers
(gdb) enable pretty-printer global pp-test .*
4 printers enabled
4 printers enabled, 4 total printers
[The output of `enable' is a bit klunky, I figure that's the least
of my worries ...]
2010-06-08 Doug Evans <dje@google.com>
Give pretty-printers names. Add new commands:
info pretty-printers, enable|disable pretty-printer
* python/lib/gdb/printing.py: New file.
testsuite/
* gdb.python/py-pp-maint.c: New file.
* gdb.python/py-pp-maint.py: New file.
* gdb.python/py-pp-maint.exp: New file.
Index: python/lib/gdb/printing.py
===================================================================
RCS file: python/lib/gdb/printing.py
diff -N python/lib/gdb/printing.py
--- /dev/null 2009-04-24 06:57:12.000000000 -0700
+++ python/lib/gdb/printing.py 2010-06-08 10:46:41.000000000 -0700
@@ -0,0 +1,421 @@
+# Pretty-printer utilities.
+
+import gdb
+import re
+
+# Given a type, return the same type with references, typedefs and qualifiers
+# (const, volatile) stripped away.
+
+def get_base_type (val):
+ """Helper function: return 'base' type of VAL"""
+
+ tp = val.type
+ if tp.code == gdb.TYPE_CODE_REF:
+ tp = tp.target ()
+ tp = tp.unqualified ().strip_typedefs ()
+ return tp
+
+# A basic pretty-printer.
+#
+# `name' is 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".
+# `lookup' is a function of one argument: The value to be pretty-printed.
+# If `subprinters' is non-None, it must be an iterable object with each
+# element having a `name' attribute, and, potentially, "enabled" attribute.
+
+class PrettyPrinter (object):
+ def __init__ (self, name, lookup, subprinters=None):
+ self.name = name
+ self.lookup = lookup
+ self.subprinters = subprinters
+ # True if this printer is enabled.
+ self.enabled = True
+
+ # "new-style" classes need __call__ to be defined in the class,
+ # not in an instance. i.e. we can't do "self.__call__ = lookup"
+ # in __init__.
+ # http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes
+ def __call__ (self, val):
+ return self.lookup (self, val)
+
+# Baseclass for sub-pretty-printers.
+# Sub-pretty-printers needn't use this, but it formalizes what's needed.
+
+class SubPrettyPrinter (object):
+ def __init__ (self, name):
+ self.name = name
+ self.enabled = True
+
+# Add `printer' to the list of pretty-printers for `obj'.
+#
+# `printer' is either a function of one argument (old way) or any object which
+# has the `__call__' attribute.
+# In addition, if the caller wants the printer to be listable and disableable,
+# it must follow the PrettyPrinter API.
+# __call__ is a function of one argument: The value to be pretty-printed.
+# If you wish to make other state available to __call__, e.g., the list of
+# subprinters, you must create a closure.
+#
+# `obj' is either an objfile, progspace, or None (in which case the printer
+# is registered globally).
+
+def register_pretty_printer (obj, printer):
+ """Register pretty-printer PRINTER with OBJ."""
+
+ if not hasattr (printer, "name"):
+ raise "Printer missing attribute: name"
+ if not hasattr (printer, "__call__"):
+ raise "Printer missing attribute: __call__"
+ if obj == None:
+ if gdb.parameter ("verbose"):
+ gdb.write ("Registering global %s pretty-printer ...\n"
+ % printer.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"):
+ # First make sure the printer's name is unique.
+ # PERF: gdb records printers in a list, making this inefficient.
+ if printer.name in map (lambda p: p.name, obj.pretty_printers):
+ raise "pretty-printer already registered: %s" % printer.name
+
+ obj.pretty_printers.append (printer)
+
+# Utility to parse a command argv of
+# [object-regexp [name-regexp [subname-regexp]]].
+# The result is a 3-tuple of compiled regular expressions, except that
+# the resulting compiled subname regexp is None if not provided.
+#
+# If there's an error processing ARG, gdb.GdbError is thrown.
+
+def parse_printer_regexps (arg):
+ argv = gdb.string_to_argv (arg);
+ argc = len (argv)
+ object_regexp = "" # match everything
+ name_regexp = "" # match everything
+ subname_regexp = None
+ if (argc > 3):
+ gdb.GdbError.__str__ = None
+ raise gdb.GdbError
+ #raise gdb.GdbError ("Too many arguments")
+ #raise "Too many arguments", "fubar"
+ if argc >= 1:
+ object_regexp = argv[0]
+ if argc >= 2:
+ name_regexp = argv[1]
+ if argc >= 3:
+ subname_regexp = argv[2]
+ try:
+ object_re = re.compile (object_regexp)
+ except:
+ raise gdb.GdbError ("invalid object regexp: %s" % object_regexp)
+ try:
+ name_re = re.compile (name_regexp)
+ except:
+ raise gdb.GdbError ("invalid name regexp: %s" % name_regexp)
+ if subname_regexp != None:
+ try:
+ subname_re = re.compile (subname_regexp)
+ except:
+ raise gdb.GdbError ("invalid subname regexp: %s" % subname_regexp)
+ else:
+ subname_re = None
+ return (object_re, name_re, subname_re)
+
+# Internal utility to return True if PRINTER is enabled, False if disabled.
+# PRINTER is either a printer or subprinter.
+
+def printer_enabled_p (printer):
+ if hasattr (printer, "enabled"):
+ if printer.enabled:
+ return True
+ else:
+ return False
+ else:
+ return True
+
+# Class to implement the "info pretty-printers" command.
+
+class InfoPrettyPrinters (gdb.Command):
+ """List all registered pretty-printers.
+ Usage: info pretty-printers [object-regexp [name-regexp [subname-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.
+ SUBNAME-REGEXP matches the name of the subprinter."""
+
+ def __init__ (self):
+ super (InfoPrettyPrinters, self).__init__ ("info pretty-printers",
+ gdb.COMMAND_DATA)
+
+ # Return "" if PRINTER is enabled, otherwise " [disabled]".
+
+ def enabled_string (self, printer):
+ if printer_enabled_p (printer):
+ return ""
+ else:
+ return " [disabled]"
+
+ # Internal utility to print a list of pretty-printers.
+
+ def list_pretty_printers (self, pretty_printers, name_re, subname_re):
+ for printer in pretty_printers:
+ enabled = self.enabled_string (printer)
+ if hasattr (printer, "name"):
+ if name_re.match (printer.name):
+ print " %s%s" % (printer.name, enabled)
+ if hasattr (printer, "subprinters") \
+ and printer.subprinters != None:
+ for subprinter in printer.subprinters:
+ if subname_re == None \
+ or subname_re.match (subprinter.name):
+ print " %s%s" % (subprinter.name,
+ self.enabled_string (subprinter))
+ else:
+ if name_re.match ("unknown"):
+ print " unknown printer: %s%s" % (printer, enabled)
+
+ def invoke (self, arg, from_tty):
+ (object_re, name_re, subname_re) = parse_printer_regexps (arg)
+ if len (gdb.pretty_printers) > 0 \
+ and object_re.match ("global"):
+ print "global pretty-printers:"
+ self.list_pretty_printers (gdb.pretty_printers,
+ name_re, subname_re)
+ cp = gdb.current_progspace ()
+ if len (cp.pretty_printers) > 0 \
+ and object_re.match (cp.filename):
+ print "progspace %s pretty-printers:" % cp.filename
+ self.list_pretty_printers (cp.pretty_printers,
+ name_re, subname_re)
+ for objfile in gdb.objfiles ():
+ if len (objfile.pretty_printers) > 0 \
+ and object_re.match (objfile.filename):
+ print " objfile %s pretty-printers:" % objfile.filename
+ self.list_pretty_printers (objfile.pretty_printers,
+ name_re, subname_re)
+
+# Return a 2-tuple of number of enabled and total printers in PRETTY_PRINTERS.
+
+def count_enabled_printers (pretty_printers):
+ enabled = 0
+ total = 0
+ for printer in pretty_printers:
+ if hasattr (printer, "subprinters") \
+ and printer.subprinters != 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)
+
+# Return a 2-tuble of the enabled state and total number of all printers,
+# including subprinters.
+
+def count_all_enabled_printers ():
+ 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)
+
+# Internal utility to return TEXT pluralized if N != 1.
+
+def pluralize (text, n, suffix="s"):
+ if n != 1:
+ return "%s%s" % (text, suffix)
+ else:
+ return text
+
+# Print the number of printers enabled/disabled.
+# We count subprinters individually.
+
+def show_pretty_printer_enabled_summary ():
+ (enabled_count, total_count) = count_all_enabled_printers ()
+ print "%d %s enabled, %d total %s" \
+ % (enabled_count, pluralize ("printer", enabled_count),
+ total_count, pluralize ("printer", total_count))
+
+# Internal worker for enabling/disabling pretty-printers.
+# PRETTY_PRINTERS is a list of pretty-printers.
+# NAME_RE is a regular-expression object to select printers.
+# SUBNAME_RE is a regular expression object to select subprinters or None
+# if all are affected.
+# FLAG is True for Enable, False for Disable.
+#
+# The result is the number of printers affected.
+# This is just for informational purposes for the user.
+
+def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag):
+ total = 0
+ for printer in pretty_printers:
+ if hasattr (printer, "name") and name_re.match (printer.name):
+ if hasattr (printer, "subprinters"):
+ if subname_re == None:
+ # NOTE: We preserve individual subprinter settings.
+ printer.enabled = flag
+ total += len (printer.subprinters)
+ 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):
+ subprinter.enabled = flag
+ total += 1
+ 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 subname_re == None:
+ printer.enabled = flag
+ total += 1
+ return total
+
+# Internal worker for enabling/disabling pretty-printers.
+
+def do_enable_pretty_printer (arg, flag):
+ (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 (cp.filename):
+ 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):
+ """Enable the specified pretty-printer.
+ Usage: enable pretty-printer [object-regexp [name-regexp [subname-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.
+ SUBNAME-REGEXP matches the name of the subprinter."""
+
+ def __init__ (self):
+ super (EnablePrettyPrinter, self).__init__ ("enable pretty-printer",
+ gdb.COMMAND_DATA)
+
+ def invoke (self, arg, from_tty):
+ do_enable_pretty_printer (arg, True)
+
+class DisablePrettyPrinter (gdb.Command):
+ """Disable the specified pretty-printer.
+ Usage: disable pretty-printer [object-regexp [name-regexp [subname-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.
+ SUBNAME-REGEXP matches the name of the subprinter."""
+
+ def __init__ (self):
+ super (DisablePrettyPrinter, self).__init__ ("disable pretty-printer",
+ gdb.COMMAND_DATA)
+
+ def invoke (self, arg, from_tty):
+ do_enable_pretty_printer (arg, False)
+
+# Internal class for implementing regular-expression based pretty-printers.
+
+class RePrettyPrinter (SubPrettyPrinter):
+ def __init__ (self, regexp, gen_printer):
+ super (RePrettyPrinter, self).__init__ (regexp)
+ self.compiled_re = re.compile (regexp)
+ self.gen_printer = gen_printer
+
+# Utility for building a regular-expression based lookup table.
+# REGEXP is the regular expression, as a string.
+# GEN_PRINTER is a function that returns the pretty-printed form of its
+# argument.
+
+def add_re_printer (table, regexp, gen_printer):
+ table.append (RePrettyPrinter (regexp, gen_printer))
+
+# Standard lookup_function for regular-expression based pretty-printers.
+#
+# NOTE: This cannot be passed to register_pretty_printer "as is".
+# It is intended to be used as the "lookup" parameter of PrettyPrinter.
+# Normally this is used by calling register_pretty_printer as:
+#
+# pretty_printers_list = []
+# add_re_printer (pretty_printers_list, ...)
+# ...
+# add_re_printer (pretty_printers_list, ...)
+# register_pretty_printer (obj,
+# PrettyPrinter ("libstdc++",
+# re_lookup_function,
+# pretty_printers_list))
+
+def re_lookup_function (printer_object, val):
+ # Get the type name.
+ typename = get_base_type (val).tag
+ if typename == None:
+ 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 printer_object.subprinters:
+ if printer.enabled and printer.compiled_re.search (typename):
+ return printer.gen_printer (val)
+
+ # Cannot find a pretty printer. Return None.
+ return None
+
+# Call from a top level script to install the pretty-printer commands.
+
+def register_pretty_printer_commands ():
+ InfoPrettyPrinters ()
+ EnablePrettyPrinter ()
+ DisablePrettyPrinter ()
Index: testsuite/gdb.python/py-pp-maint.c
===================================================================
RCS file: testsuite/gdb.python/py-pp-maint.c
diff -N testsuite/gdb.python/py-pp-maint.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/py-pp-maint.c 8 Jun 2010 18:50:05 -0000
@@ -0,0 +1,54 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 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/>. */
+
+#include <string.h>
+
+struct s
+{
+ int a;
+ int *b;
+};
+
+struct ss
+{
+ struct s a;
+ struct s b;
+};
+
+void
+init_s (struct s *s, int a)
+{
+ s->a = a;
+ s->b = &s->a;
+}
+
+void
+init_ss (struct ss *s, int a, int b)
+{
+ init_s (&s->a, a);
+ init_s (&s->b, b);
+}
+
+int
+main ()
+{
+ struct ss ss;
+
+ init_ss (&ss, 1, 2);
+
+ return 0; /* break to inspect */
+}
Index: testsuite/gdb.python/py-pp-maint.exp
===================================================================
RCS file: testsuite/gdb.python/py-pp-maint.exp
diff -N testsuite/gdb.python/py-pp-maint.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/py-pp-maint.exp 8 Jun 2010 18:50:05 -0000
@@ -0,0 +1,82 @@
+# 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/>.
+
+# This file is part of the GDB testsuite. It tests Python-based
+# pretty-printing for the CLI.
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+if [is_remote host] {
+ untested "py-pp-maint.exp can only be run locally"
+ return -1
+}
+
+set testfile "py-pp-maint"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+# Start with a fresh gdb.
+gdb_exit
+gdb_start
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug"] != "" } {
+ untested "Couldn't compile ${srcfile}"
+ return -1
+}
+
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main ] then {
+ perror "couldn't run to breakpoint"
+ return
+}
+
+set gdb_python_dir [file normalize ${srcdir}/../python/lib]
+gdb_test_no_output "python sys.path.insert (0, '${gdb_python_dir}')"
+gdb_test_no_output "python gdb.__path__ = \[ '${gdb_python_dir}/gdb' \]"
+gdb_test_no_output "python from gdb.printing import register_pretty_printer_commands"
+gdb_test_no_output "python register_pretty_printer_commands ()"
+
+gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \
+ ".*Breakpoint.*"
+gdb_test "continue" ".*Breakpoint.*"
+
+set python_file ${srcdir}/${subdir}/${testfile}.py
+
+gdb_test_no_output "python execfile ('${python_file}')" ""
+
+gdb_test "info pretty-printers" \
+ {.*pp-test.*struct ss.*}
+
+gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>" \
+ "print ss enabled #1"
+
+gdb_test "disable pretty-printer global pp-test .*" \
+ "4 printers disabled.*"
+
+gdb_test "print ss" " = {a = {a = 1, b = $hex}, b = {a = 2, b = $hex}}" \
+ "print ss disabled"
+
+gdb_test "enable pretty-printer global pp-test .*" \
+ "4 printers enabled.*"
+
+gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>" \
+ "print ss enabled #2"
Index: testsuite/gdb.python/py-pp-maint.py
===================================================================
RCS file: testsuite/gdb.python/py-pp-maint.py
diff -N testsuite/gdb.python/py-pp-maint.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.python/py-pp-maint.py 8 Jun 2010 18:50:05 -0000
@@ -0,0 +1,55 @@
+# 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/>.
+
+# This file is part of the GDB testsuite. It tests python pretty
+# printers.
+
+import re
+from gdb.printing import add_re_printer
+
+class pp_s:
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ a = self.val["a"]
+ b = self.val["b"]
+ if a.address != b:
+ raise Exception("&a(%s) != b(%s)" % (str(a.address), str(b)))
+ return " a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">"
+
+class pp_ss:
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">"
+
+def build_pretty_printers ():
+ pp_list = []
+
+ add_re_printer (pp_list, '^struct s$', pp_s)
+ add_re_printer (pp_list, '^s$', pp_s)
+
+ add_re_printer (pp_list, '^struct ss$', pp_ss)
+ add_re_printer (pp_list, '^ss$', pp_ss)
+
+ return pp_list
+
+pretty_printers_list = build_pretty_printers ()
+gdb.printing.register_pretty_printer (gdb,
+ gdb.printing.PrettyPrinter ("pp-test",
+ gdb.printing.re_lookup_function,
+ pretty_printers_list))