aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2012-11-12 17:41:59 +0000
committerTom Tromey <tromey@redhat.com>2012-11-12 17:41:59 +0000
commit18a9fc1261b8a654fe6db7eea7e60b0c59296d96 (patch)
tree50b1290ab9827f259ea103cf50367d7ac6c0e878
parentbd69fc683f383772bb8fab43c5d4af8d0cd4a8b4 (diff)
downloadgdb-18a9fc1261b8a654fe6db7eea7e60b0c59296d96.zip
gdb-18a9fc1261b8a654fe6db7eea7e60b0c59296d96.tar.gz
gdb-18a9fc1261b8a654fe6db7eea7e60b0c59296d96.tar.bz2
* NEWS: Update.
* data-directory/Makefile.in (PYTHON_FILES): Add type_printers.py. * python/lib/gdb/command/type_printers.py: New file. * python/lib/gdb/command/types.py (TypePrinter): New class. (_get_some_type_recognizers, get_type_recognizers, apply_type_recognizers, register_type_printer): New functions. * python/py-objfile.c (objfile_object) <type_printers>: New field. (objfpy_dealloc): Decref new field. (objfpy_new): Set new field. (objfpy_get_type_printers, objfpy_set_type_printers): New functions. (objfile_to_objfile_object): Set new field. (objfile_getset): Add "type_printers". * python/py-progspace.c (pspace_object) <type_printers>: New field. (pspy_dealloc): Decref new field. (pspy_new): Set new field. (pspy_get_type_printers, pspy_set_type_printers): New functions. (pspace_to_pspace_object): Set new field. (pspace_getset): Add "type_printers". * python/python.c (start_type_printers, apply_type_printers, free_type_printers): New functions. (_initialize_python): Set gdb.type_printers. * python/python.h (start_type_printers, apply_type_printers, free_type_printers): Declare. * typeprint.c (type_print_raw_options, default_ptype_flags): Update for new fields. (do_free_global_table, create_global_typedef_table, find_global_typedef): New functions. (find_typedef_in_hash): Use find_global_typedef. (whatis_exp): Use create_global_typedef_table. Change cleanup handling. * typeprint.h (struct type_print_options) <global_typedefs, global_printers>: New fields. doc * gdb.texinfo (Symbols): Document "info type-printers", "enable type-printer" and "disable type-printer". (Python API): Add new node to menu. (Type Printing API): New node. (Progspaces In Python): Document type_printers field. (Objfiles In Python): Likewise. (gdb.types) <get_type_recognizers, apply_type_recognizers, register_type_printer, TypePrinter>: Document. testsuite * gdb.base/completion.exp: Update for "info type-printers". * gdb.python/py-typeprint.cc: New file. * gdb.python/py-typeprint.exp: New file. * gdb.python/py-typeprint.py: New file.
-rw-r--r--gdb/ChangeLog40
-rw-r--r--gdb/NEWS6
-rw-r--r--gdb/data-directory/Makefile.in1
-rw-r--r--gdb/doc/ChangeLog11
-rw-r--r--gdb/doc/gdb.texinfo122
-rw-r--r--gdb/python/lib/gdb/__init__.py3
-rw-r--r--gdb/python/lib/gdb/command/type_printers.py125
-rw-r--r--gdb/python/lib/gdb/types.py65
-rw-r--r--gdb/python/py-objfile.c62
-rw-r--r--gdb/python/py-progspace.c62
-rw-r--r--gdb/python/python.c136
-rw-r--r--gdb/python/python.h6
-rw-r--r--gdb/testsuite/ChangeLog7
-rw-r--r--gdb/testsuite/gdb.base/completion.exp6
-rw-r--r--gdb/testsuite/gdb.python/py-typeprint.cc37
-rw-r--r--gdb/testsuite/gdb.python/py-typeprint.exp53
-rw-r--r--gdb/testsuite/gdb.python/py-typeprint.py35
-rw-r--r--gdb/typeprint.c106
-rw-r--r--gdb/typeprint.h8
19 files changed, 874 insertions, 17 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index fcf5ffc..583f1c0 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,45 @@
2012-11-12 Tom Tromey <tromey@redhat.com>
+ * NEWS: Update.
+ * data-directory/Makefile.in (PYTHON_FILES): Add
+ type_printers.py.
+ * python/lib/gdb/command/type_printers.py: New file.
+ * python/lib/gdb/command/types.py (TypePrinter): New class.
+ (_get_some_type_recognizers, get_type_recognizers,
+ apply_type_recognizers, register_type_printer): New
+ functions.
+ * python/py-objfile.c (objfile_object) <type_printers>: New
+ field.
+ (objfpy_dealloc): Decref new field.
+ (objfpy_new): Set new field.
+ (objfpy_get_type_printers, objfpy_set_type_printers): New
+ functions.
+ (objfile_to_objfile_object): Set new field.
+ (objfile_getset): Add "type_printers".
+ * python/py-progspace.c (pspace_object) <type_printers>: New
+ field.
+ (pspy_dealloc): Decref new field.
+ (pspy_new): Set new field.
+ (pspy_get_type_printers, pspy_set_type_printers): New functions.
+ (pspace_to_pspace_object): Set new field.
+ (pspace_getset): Add "type_printers".
+ * python/python.c (start_type_printers, apply_type_printers,
+ free_type_printers): New functions.
+ (_initialize_python): Set gdb.type_printers.
+ * python/python.h (start_type_printers, apply_type_printers,
+ free_type_printers): Declare.
+ * typeprint.c (type_print_raw_options, default_ptype_flags):
+ Update for new fields.
+ (do_free_global_table, create_global_typedef_table,
+ find_global_typedef): New functions.
+ (find_typedef_in_hash): Use find_global_typedef.
+ (whatis_exp): Use create_global_typedef_table. Change cleanup
+ handling.
+ * typeprint.h (struct type_print_options) <global_typedefs,
+ global_printers>: New fields.
+
+2012-11-12 Tom Tromey <tromey@redhat.com>
+
* c-typeprint.c (find_typedef_for_canonicalize,
print_name_maybe_canonical): New functions.
(c_print_type): Look up type name.
diff --git a/gdb/NEWS b/gdb/NEWS
index b7a92720..739a7b3 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -17,6 +17,8 @@
** Python's atexit.register now works in GDB.
+ ** Types can be pretty-printed via a Python API.
+
* New Python-based convenience functions:
** $_memeq(buf1, buf2, length)
@@ -51,6 +53,10 @@ pi [command]
py [command]
"py" is a new alias for "python".
+enable type-printer [name]...
+disable type-printer [name]...
+ Enable or disable type printers.
+
* Removed commands
** For the Renesas Super-H architecture, the "regs" command has been removed
diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index 41947c6..2e2fbf9 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -57,6 +57,7 @@ PYTHON_FILES = \
gdb/printing.py \
gdb/prompt.py \
gdb/command/__init__.py \
+ gdb/command/type_printers.py \
gdb/command/pretty_printers.py \
gdb/command/prompt.py \
gdb/command/explore.py \
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index f59b001..0410dbc 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,16 @@
2012-11-12 Tom Tromey <tromey@redhat.com>
+ * gdb.texinfo (Symbols): Document "info type-printers",
+ "enable type-printer" and "disable type-printer".
+ (Python API): Add new node to menu.
+ (Type Printing API): New node.
+ (Progspaces In Python): Document type_printers field.
+ (Objfiles In Python): Likewise.
+ (gdb.types) <get_type_recognizers, apply_type_recognizers,
+ register_type_printer, TypePrinter>: Document.
+
+2012-11-12 Tom Tromey <tromey@redhat.com>
+
* gdb.texinfo (Symbols): Document "set print type methods",
"set print type typedefs", and flags to ptype and whatis.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6f9d3f6..86cfe8e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -15218,6 +15218,22 @@ This command differs from @code{ptype} in two ways: first, like
@code{whatis}, it does not print a detailed description; second, it
lists all source files where a type is defined.
+@kindex info type-printers
+@item info type-printers
+Versions of @value{GDBN} that ship with Python scripting enabled may
+have ``type printers'' available. When using @command{ptype} or
+@command{whatis}, these printers are consulted when the name of a type
+is needed. @xref{Type Printing API}, for more information on writing
+type printers.
+
+@code{info type-printers} displays all the available type printers.
+
+@kindex enable type-printer
+@kindex disable type-printer
+@item enable type-printer @var{name}@dots{}
+@item disable type-printer @var{name}@dots{}
+These commands can be used to enable or disable type printers.
+
@kindex info scope
@cindex local variables
@item info scope @var{location}
@@ -22671,6 +22687,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Pretty Printing API:: Pretty-printing values.
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
* Writing a Pretty-Printer:: Writing a Pretty-Printer.
+* Type Printing API:: Pretty-printing types.
* Inferiors In Python:: Python representation of inferiors (processes)
* Events In Python:: Listening for events from @value{GDBN}.
* Threads In Python:: Accessing inferior threads from Python.
@@ -23966,6 +23983,68 @@ my_library.so:
bar
@end smallexample
+@node Type Printing API
+@subsubsection Type Printing API
+@cindex type printing API for Python
+
+@value{GDBN} provides a way for Python code to customize type display.
+This is mainly useful for substituting canonical typedef names for
+types.
+
+@cindex type printer
+A @dfn{type printer} is just a Python object conforming to a certain
+protocol. A simple base class implementing the protocol is provided;
+see @ref{gdb.types}. A type printer must supply at least:
+
+@defivar type_printer enabled
+A boolean which is True if the printer is enabled, and False
+otherwise. This is manipulated by the @code{enable type-printer}
+and @code{disable type-printer} commands.
+@end defivar
+
+@defivar type_printer name
+The name of the type printer. This must be a string. This is used by
+the @code{enable type-printer} and @code{disable type-printer}
+commands.
+@end defivar
+
+@defmethod type_printer instantiate (self)
+This is called by @value{GDBN} at the start of type-printing. It is
+only called if the type printer is enabled. This method must return a
+new object that supplies a @code{recognize} method, as described below.
+@end defmethod
+
+
+When displaying a type, say via the @code{ptype} command, @value{GDBN}
+will compute a list of type recognizers. This is done by iterating
+first over the per-objfile type printers (@pxref{Objfiles In Python}),
+followed by the per-progspace type printers (@pxref{Progspaces In
+Python}), and finally the global type printers.
+
+@value{GDBN} will call the @code{instantiate} method of each enabled
+type printer. If this method returns @code{None}, then the result is
+ignored; otherwise, it is appended to the list of recognizers.
+
+Then, when @value{GDBN} is going to display a type name, it iterates
+over the list of recognizers. For each one, it calls the recognition
+function, stopping if the function returns a non-@code{None} value.
+The recognition function is defined as:
+
+@defmethod type_recognizer recognize (self, type)
+If @var{type} is not recognized, return @code{None}. Otherwise,
+return a string which is to be printed as the name of @var{type}.
+@var{type} will be an instance of @code{gdb.Type} (@pxref{Types In
+Python}).
+@end defmethod
+
+@value{GDBN} uses this two-pass approach so that type printers can
+efficiently cache information without holding on to it too long. For
+example, it can be convenient to look up type information in a type
+printer and hold it for a recognizer's lifetime; if a single pass were
+done then type printers would have to make use of the event system in
+order to avoid holding information that could become stale as the
+inferior changed.
+
@node Inferiors In Python
@subsubsection Inferiors In Python
@cindex inferiors in Python
@@ -24810,6 +24889,11 @@ which is used to format the value. @xref{Pretty Printing API}, for more
information.
@end defvar
+@defvar Progspace.type_printers
+The @code{type_printers} attribute is a list of type printer objects.
+@xref{Type Printing API}, for more information.
+@end defvar
+
@node Objfiles In Python
@subsubsection Objfiles In Python
@@ -24855,6 +24939,11 @@ which is used to format the value. @xref{Pretty Printing API}, for more
information.
@end defvar
+@defvar Objfile.type_printers
+The @code{type_printers} attribute is a list of type printer objects.
+@xref{Type Printing API}, for more information.
+@end defvar
+
A @code{gdb.Objfile} object has the following methods:
@defun Objfile.is_valid ()
@@ -26057,7 +26146,7 @@ if a printer with the same name already exists.
@cindex gdb.types
This module provides a collection of utilities for working with
-@code{gdb.Types} objects.
+@code{gdb.Type} objects.
@table @code
@item get_basic_type (@var{type})
@@ -26118,6 +26207,37 @@ Then in @value{GDBN}:
@{['a', 'b0', 'b1']@}
@end smallexample
+@item get_type_recognizers ()
+Return a list of the enabled type recognizers for the current context.
+This is called by @value{GDBN} during the type-printing process
+(@pxref{Type Printing API}).
+
+@item apply_type_recognizers (recognizers, type_obj)
+Apply the type recognizers, @var{recognizers}, to the type object
+@var{type_obj}. If any recognizer returns a string, return that
+string. Otherwise, return @code{None}. This is called by
+@value{GDBN} during the type-printing process (@pxref{Type Printing
+API}).
+
+@item register_type_printer (locus, printer)
+This is a convenience function to register a type printer.
+@var{printer} is the type printer to register. It must implement the
+type printer protocol. @var{locus} is either a @code{gdb.Objfile}, in
+which case the printer is registered with that objfile; a
+@code{gdb.Progspace}, in which case the printer is registered with
+that progspace; or @code{None}, in which case the printer is
+registered globally.
+
+@item TypePrinter
+This is a base class that implements the type printer protocol. Type
+printers are encouraged, but not required, to derive from this class.
+It defines a constructor:
+
+@defmethod TypePrinter __init__ (self, name)
+Initialize the type printer with the given name. The new printer
+starts in the enabled state.
+@end defmethod
+
@end table
@node gdb.prompt
diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
index 0e020fe..0671526 100644
--- a/gdb/python/lib/gdb/__init__.py
+++ b/gdb/python/lib/gdb/__init__.py
@@ -70,6 +70,9 @@ sys.argv = ['']
# Initial pretty printers.
pretty_printers = []
+# Initial type printers.
+type_printers = []
+
# Convenience variable to GDB's python directory
PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
diff --git a/gdb/python/lib/gdb/command/type_printers.py b/gdb/python/lib/gdb/command/type_printers.py
new file mode 100644
index 0000000..b7d6930
--- /dev/null
+++ b/gdb/python/lib/gdb/command/type_printers.py
@@ -0,0 +1,125 @@
+# Type printer commands.
+# Copyright (C) 2010-2012 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/>.
+
+import copy
+import gdb
+
+"""GDB commands for working with type-printers."""
+
+class InfoTypePrinter(gdb.Command):
+ """GDB command to list all registered type-printers.
+
+ Usage: info type-printers
+ """
+
+ def __init__ (self):
+ super(InfoTypePrinter, self).__init__("info type-printers",
+ gdb.COMMAND_DATA)
+
+ def list_type_printers(self, type_printers):
+ """Print a list of type printers."""
+ # A potential enhancement is to provide an option to list printers in
+ # "lookup order" (i.e. unsorted).
+ sorted_type_printers = copy.copy(type_printers)
+ sorted_type_printers.sort(lambda x, y: cmp(x.name, y.name))
+ for printer in sorted_type_printers:
+ if printer.enabled:
+ enabled = ''
+ else:
+ enabled = " [disabled]"
+ print " %s%s" % (printer.name, enabled)
+
+ def invoke(self, arg, from_tty):
+ """GDB calls this to perform the command."""
+ sep = ''
+ for objfile in gdb.objfiles():
+ if objfile.type_printers:
+ print "%sType printers for %s:" % (sep, objfile.name)
+ self.list_type_printers(objfile.type_printers)
+ sep = '\n'
+ if gdb.current_progspace().type_printers:
+ print "%sType printers for program space:" % sep
+ self.list_type_printers(gdb.current_progspace().type_printers)
+ sep = '\n'
+ if gdb.type_printers:
+ print "%sGlobal type printers:" % sep
+ self.list_type_printers(gdb.type_printers)
+
+class _EnableOrDisableCommand(gdb.Command):
+ def __init__(self, setting, name):
+ super(_EnableOrDisableCommand, self).__init__(name, gdb.COMMAND_DATA)
+ self.setting = setting
+
+ def set_some(self, name, printers):
+ result = False
+ for p in printers:
+ if name == p.name:
+ p.enabled = self.setting
+ result = True
+ return result
+
+ def invoke(self, arg, from_tty):
+ """GDB calls this to perform the command."""
+ for name in arg.split():
+ ok = False
+ for objfile in gdb.objfiles():
+ if self.set_some(name, objfile.type_printers):
+ ok = True
+ if self.set_some(name, gdb.current_progspace().type_printers):
+ ok = True
+ if self.set_some(name, gdb.type_printers):
+ ok = True
+ if not ok:
+ print "No type printer named '%s'" % name
+
+ def add_some(self, result, word, printers):
+ for p in printers:
+ if p.name.startswith(word):
+ result.append(p.name)
+
+ def complete(self, text, word):
+ result = []
+ for objfile in gdb.objfiles():
+ self.add_some(result, word, objfile.type_printers)
+ self.add_some(result, word, gdb.current_progspace().type_printers)
+ self.add_some(result, word, gdb.type_printers)
+ return result
+
+class EnableTypePrinter(_EnableOrDisableCommand):
+ """GDB command to enable the specified type printer.
+
+ Usage: enable type-printer NAME
+
+ NAME is the name of the type-printer.
+ """
+
+ def __init__(self):
+ super(EnableTypePrinter, self).__init__(True, "enable type-printer")
+
+class DisableTypePrinter(_EnableOrDisableCommand):
+ """GDB command to disable the specified type-printer.
+
+ Usage: disable type-printer NAME
+
+ NAME is the name of the type-printer.
+ """
+
+ def __init__(self):
+ super(DisableTypePrinter, self).__init__(False, "disable type-printer")
+
+InfoTypePrinter()
+EnableTypePrinter()
+DisableTypePrinter()
diff --git a/gdb/python/lib/gdb/types.py b/gdb/python/lib/gdb/types.py
index 66c9528..3745383 100644
--- a/gdb/python/lib/gdb/types.py
+++ b/gdb/python/lib/gdb/types.py
@@ -109,3 +109,68 @@ def deep_items (type_):
else:
for i in deep_items (v.type):
yield i
+
+class TypePrinter(object):
+ """The base class for type printers.
+
+ Instances of this type can be used to substitute type names during
+ 'ptype'.
+
+ A type printer must have at least 'name' and 'enabled' attributes,
+ and supply an 'instantiate' method.
+
+ The 'instantiate' method must either return None, or return an
+ object which has a 'recognize' method. This method must accept a
+ gdb.Type argument and either return None, meaning that the type
+ was not recognized, or a string naming the type.
+ """
+
+ def __init__(self, name):
+ self.name = name
+ self.enabled = True
+
+ def instantiate(self):
+ return None
+
+# Helper function for computing the list of type recognizers.
+def _get_some_type_recognizers(result, plist):
+ for printer in plist:
+ if printer.enabled:
+ inst = printer.instantiate()
+ if inst is not None:
+ result.append(inst)
+ return None
+
+def get_type_recognizers():
+ "Return a list of the enabled type recognizers for the current context."
+ result = []
+
+ # First try the objfiles.
+ for objfile in gdb.objfiles():
+ _get_some_type_recognizers(result, objfile.type_printers)
+ # Now try the program space.
+ _get_some_type_recognizers(result, gdb.current_progspace().type_printers)
+ # Finally, globals.
+ _get_some_type_recognizers(result, gdb.type_printers)
+
+ return result
+
+def apply_type_recognizers(recognizers, type_obj):
+ """Apply the given list of type recognizers to the type TYPE_OBJ.
+ If any recognizer in the list recognizes TYPE_OBJ, returns the name
+ given by the recognizer. Otherwise, this returns None."""
+ for r in recognizers:
+ result = r.recognize(type_obj)
+ if result is not None:
+ return result
+ return None
+
+def register_type_printer(locus, printer):
+ """Register a type printer.
+ PRINTER is the type printer instance.
+ LOCUS is either an objfile, a program space, or None, indicating
+ global registration."""
+
+ if locus is None:
+ locus = gdb
+ locus.type_printers.insert(0, printer)
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 9fa6813..5d2398f 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -32,6 +32,9 @@ typedef struct
/* The pretty-printer list of functions. */
PyObject *printers;
+
+ /* The type-printer list. */
+ PyObject *type_printers;
} objfile_object;
static PyTypeObject objfile_object_type;
@@ -58,6 +61,7 @@ objfpy_dealloc (PyObject *o)
objfile_object *self = (objfile_object *) o;
Py_XDECREF (self->printers);
+ Py_XDECREF (self->type_printers);
self->ob_type->tp_free ((PyObject *) self);
}
@@ -76,6 +80,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
Py_DECREF (self);
return NULL;
}
+
+ self->type_printers = PyList_New (0);
+ if (!self->type_printers)
+ {
+ Py_DECREF (self);
+ return NULL;
+ }
}
return (PyObject *) self;
}
@@ -118,6 +129,48 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore)
return 0;
}
+/* Get the 'type_printers' attribute. */
+
+static PyObject *
+objfpy_get_type_printers (PyObject *o, void *ignore)
+{
+ objfile_object *self = (objfile_object *) o;
+
+ Py_INCREF (self->type_printers);
+ return self->type_printers;
+}
+
+/* Set the 'type_printers' attribute. */
+
+static int
+objfpy_set_type_printers (PyObject *o, PyObject *value, void *ignore)
+{
+ PyObject *tmp;
+ objfile_object *self = (objfile_object *) o;
+
+ if (! value)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("Cannot delete the type_printers attribute."));
+ return -1;
+ }
+
+ if (! PyList_Check (value))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ _("The type_printers attribute must be a list."));
+ return -1;
+ }
+
+ /* Take care in case the LHS and RHS are related somehow. */
+ tmp = self->type_printers;
+ Py_INCREF (value);
+ self->type_printers = value;
+ Py_XDECREF (tmp);
+
+ return 0;
+}
+
/* Implementation of gdb.Objfile.is_valid (self) -> Boolean.
Returns True if this object file still exists in GDB. */
@@ -172,6 +225,13 @@ objfile_to_objfile_object (struct objfile *objfile)
return NULL;
}
+ object->type_printers = PyList_New (0);
+ if (!object->type_printers)
+ {
+ Py_DECREF (object);
+ return NULL;
+ }
+
set_objfile_data (objfile, objfpy_objfile_data_key, object);
}
}
@@ -210,6 +270,8 @@ static PyGetSetDef objfile_getset[] =
"The objfile's filename, or None.", NULL },
{ "pretty_printers", objfpy_get_printers, objfpy_set_printers,
"Pretty printers.", NULL },
+ { "type_printers", objfpy_get_type_printers, objfpy_set_type_printers,
+ "Type printers.", NULL },
{ NULL }
};
diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
index e4b029b..c1b1cac 100644
--- a/gdb/python/py-progspace.c
+++ b/gdb/python/py-progspace.c
@@ -34,6 +34,9 @@ typedef struct
/* The pretty-printer list of functions. */
PyObject *printers;
+
+ /* The type-printer list. */
+ PyObject *type_printers;
} pspace_object;
static PyTypeObject pspace_object_type;
@@ -66,6 +69,7 @@ pspy_dealloc (PyObject *self)
pspace_object *ps_self = (pspace_object *) self;
Py_XDECREF (ps_self->printers);
+ Py_XDECREF (ps_self->type_printers);
self->ob_type->tp_free (self);
}
@@ -84,6 +88,13 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
Py_DECREF (self);
return NULL;
}
+
+ self->type_printers = PyList_New (0);
+ if (!self->type_printers)
+ {
+ Py_DECREF (self);
+ return NULL;
+ }
}
return (PyObject *) self;
}
@@ -126,6 +137,48 @@ pspy_set_printers (PyObject *o, PyObject *value, void *ignore)
return 0;
}
+/* Get the 'type_printers' attribute. */
+
+static PyObject *
+pspy_get_type_printers (PyObject *o, void *ignore)
+{
+ pspace_object *self = (pspace_object *) o;
+
+ Py_INCREF (self->type_printers);
+ return self->type_printers;
+}
+
+/* Set the 'type_printers' attribute. */
+
+static int
+pspy_set_type_printers (PyObject *o, PyObject *value, void *ignore)
+{
+ PyObject *tmp;
+ pspace_object *self = (pspace_object *) o;
+
+ if (! value)
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "cannot delete the type_printers attribute");
+ return -1;
+ }
+
+ if (! PyList_Check (value))
+ {
+ PyErr_SetString (PyExc_TypeError,
+ "the type_printers attribute must be a list");
+ return -1;
+ }
+
+ /* Take care in case the LHS and RHS are related somehow. */
+ tmp = self->type_printers;
+ Py_INCREF (value);
+ self->type_printers = value;
+ Py_XDECREF (tmp);
+
+ return 0;
+}
+
/* Clear the PSPACE pointer in a Pspace object and remove the reference. */
@@ -168,6 +221,13 @@ pspace_to_pspace_object (struct program_space *pspace)
return NULL;
}
+ object->type_printers = PyList_New (0);
+ if (!object->type_printers)
+ {
+ Py_DECREF (object);
+ return NULL;
+ }
+
set_program_space_data (pspace, pspy_pspace_data_key, object);
}
}
@@ -197,6 +257,8 @@ static PyGetSetDef pspace_getset[] =
"The progspace's main filename, or None.", NULL },
{ "pretty_printers", pspy_get_printers, pspy_set_printers,
"Pretty printers.", NULL },
+ { "type_printers", pspy_get_type_printers, pspy_set_type_printers,
+ "Type printers.", NULL },
{ NULL }
};
diff --git a/gdb/python/python.c b/gdb/python/python.c
index cd50e50..359d238 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1181,6 +1181,125 @@ gdbpy_objfiles (PyObject *unused1, PyObject *unused2)
return list;
}
+/* Compute the list of active type printers and return it. The result
+ of this function can be passed to apply_type_printers, and should
+ be freed by free_type_printers. */
+
+void *
+start_type_printers (void)
+{
+ struct cleanup *cleanups;
+ PyObject *type_module, *func, *result_obj;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+
+ type_module = PyImport_ImportModule ("gdb.types");
+ if (type_module == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (type_module);
+
+ func = PyObject_GetAttrString (type_module, "get_type_recognizers");
+ if (func == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (func);
+
+ result_obj = PyObject_CallFunctionObjArgs (func, (char *) NULL);
+ if (result_obj == NULL)
+ gdbpy_print_stack ();
+
+ done:
+ do_cleanups (cleanups);
+ return result_obj;
+}
+
+/* If TYPE is recognized by some type printer, return a newly
+ allocated string holding the type's replacement name. The caller
+ is responsible for freeing the string. Otherwise, return NULL.
+
+ This function has a bit of a funny name, since it actually applies
+ recognizers, but this seemed clearer given the start_type_printers
+ and free_type_printers functions. */
+
+char *
+apply_type_printers (void *printers, struct type *type)
+{
+ struct cleanup *cleanups;
+ PyObject *type_obj, *type_module, *func, *result_obj;
+ PyObject *printers_obj = printers;
+ char *result = NULL;
+
+ if (printers_obj == NULL)
+ return NULL;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+
+ type_obj = type_to_type_object (type);
+ if (type_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (type_obj);
+
+ type_module = PyImport_ImportModule ("gdb.types");
+ if (type_module == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (type_module);
+
+ func = PyObject_GetAttrString (type_module, "apply_type_recognizers");
+ if (func == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (func);
+
+ result_obj = PyObject_CallFunctionObjArgs (func, printers_obj,
+ type_obj, (char *) NULL);
+ if (result_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ goto done;
+ }
+ make_cleanup_py_decref (result_obj);
+
+ if (result_obj != Py_None)
+ {
+ result = python_string_to_host_string (result_obj);
+ if (result == NULL)
+ gdbpy_print_stack ();
+ }
+
+ done:
+ do_cleanups (cleanups);
+ return result;
+}
+
+/* Free the result of start_type_printers. */
+
+void
+free_type_printers (void *arg)
+{
+ struct cleanup *cleanups;
+ PyObject *printers = arg;
+
+ if (printers == NULL)
+ return;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+ Py_DECREF (printers);
+ do_cleanups (cleanups);
+}
+
#else /* HAVE_PYTHON */
/* Dummy implementation of the gdb "python-interactive" and "python"
@@ -1238,6 +1357,23 @@ gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj)
"scripting is not supported."));
}
+void *
+start_type_printers (void)
+{
+ return NULL;
+}
+
+char *
+apply_type_printers (void *ignore, struct type *type)
+{
+ return NULL;
+}
+
+void
+free_type_printers (void *arg)
+{
+}
+
#endif /* HAVE_PYTHON */
diff --git a/gdb/python/python.h b/gdb/python/python.h
index 0d07271..72872b0 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -49,4 +49,10 @@ int gdbpy_should_stop (struct breakpoint_object *bp_obj);
int gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj);
+void *start_type_printers (void);
+
+char *apply_type_printers (void *, struct type *type);
+
+void free_type_printers (void *arg);
+
#endif /* GDB_PYTHON_H */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9e04326..5293c88 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,12 @@
2012-11-12 Tom Tromey <tromey@redhat.com>
+ * gdb.base/completion.exp: Update for "info type-printers".
+ * gdb.python/py-typeprint.cc: New file.
+ * gdb.python/py-typeprint.exp: New file.
+ * gdb.python/py-typeprint.py: New file.
+
+2012-11-12 Tom Tromey <tromey@redhat.com>
+
* gdb.base/call-sc.exp: Use "ptype/r".
* gdb.base/volatile.exp: Don't expect "int".
* gdb.cp/ptype-flags.cc: New file.
diff --git a/gdb/testsuite/gdb.base/completion.exp b/gdb/testsuite/gdb.base/completion.exp
index ccdc199..8b1facb 100644
--- a/gdb/testsuite/gdb.base/completion.exp
+++ b/gdb/testsuite/gdb.base/completion.exp
@@ -161,7 +161,7 @@ gdb_test_multiple "" "$test" {
-re "^info t foo\\\x07$" {
send_gdb "\n"
gdb_test_multiple "" "$test" {
- -re "Ambiguous info command \"t foo\": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\..*$gdb_prompt $" {
+ -re "Ambiguous info command \"t foo\": target, tasks, terminal, threads, tp, tracepoints, tvariables, (type-printers, )?types\\..*$gdb_prompt $" {
pass "$test"
}
}
@@ -174,7 +174,7 @@ gdb_test_multiple "" "$test" {
-re "^info t\\\x07$" {
send_gdb "\n"
gdb_test_multiple "" "$test" {
- -re "Ambiguous info command \"t\": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\..*$gdb_prompt $" {
+ -re "Ambiguous info command \"t\": target, tasks, terminal, threads, tp, tracepoints, tvariables, (type-printers, )?types\\..*$gdb_prompt $" {
pass "$test"
}
}
@@ -187,7 +187,7 @@ gdb_test_multiple "" "$test" {
-re "^info t \\\x07$" {
send_gdb "\n"
gdb_test_multiple "" "$test" {
- -re "Ambiguous info command \"t \": target, tasks, terminal, threads, tp, tracepoints, tvariables, types\\..*$gdb_prompt $" {
+ -re "Ambiguous info command \"t \": target, tasks, terminal, threads, tp, tracepoints, tvariables, (type-printers, )?types\\..*$gdb_prompt $" {
pass "$test"
}
}
diff --git a/gdb/testsuite/gdb.python/py-typeprint.cc b/gdb/testsuite/gdb.python/py-typeprint.cc
new file mode 100644
index 0000000..65c06f0
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-typeprint.cc
@@ -0,0 +1,37 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2008-2012 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/>. */
+
+class basic_string
+{
+};
+
+template<typename T>
+class templ
+{
+public:
+ T x;
+ templ<T> *value;
+};
+
+templ<basic_string> s;
+
+basic_string bs;
+
+int main()
+{
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.python/py-typeprint.exp b/gdb/testsuite/gdb.python/py-typeprint.exp
new file mode 100644
index 0000000..ef07055
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-typeprint.exp
@@ -0,0 +1,53 @@
+# Copyright (C) 2012 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/>.
+
+if { [skip_cplus_tests] } { continue }
+
+load_lib gdb-python.exp
+load_lib cp-support.exp
+
+standard_testfile .cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+ return -1
+}
+
+if { [skip_python_tests] } { continue }
+
+set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py]
+
+gdb_test_no_output "python execfile ('${remote_python_file}')"
+
+cp_test_ptype_class s "basic test" "class" "templ<string>" {
+ { field public "T x;" }
+ { field public "templ<T> *value;" }
+} "" {} ""
+
+cp_test_ptype_class s "raw test" "class" "templ<basic_string>" {
+ { field public "basic_string x;" }
+ { field public "templ<basic_string> *value;" }
+} "" {} "/r"
+
+gdb_test_no_output "disable type-printer string"
+gdb_test "whatis bs" "basic_string" "whatis with disabled printer"
+
+gdb_test "info type-printers" "Global type printers:.*string.*disabled.*"
+
+gdb_test_no_output "enable type-printer string"
+gdb_test "whatis bs" "string" "whatis with enabled printer"
+
+gdb_test "whatis s" "templ<string>"
+
+remote_file host delete ${remote_python_file}
diff --git a/gdb/testsuite/gdb.python/py-typeprint.py b/gdb/testsuite/gdb.python/py-typeprint.py
new file mode 100644
index 0000000..a4351cd
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-typeprint.py
@@ -0,0 +1,35 @@
+# Copyright (C) 2012 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/>.
+
+import gdb
+
+class Recognizer(object):
+ def __init__(self):
+ self.enabled = True
+
+ def recognize(self, type_obj):
+ if type_obj.tag == 'basic_string':
+ return 'string'
+ return None
+
+class StringTypePrinter(object):
+ def __init__(self):
+ self.name = 'string'
+ self.enabled = True
+
+ def instantiate(self):
+ return Recognizer()
+
+gdb.type_printers.append(StringTypePrinter())
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 0e1c93c..cf3ba381 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -38,6 +38,7 @@
#include <errno.h>
#include <ctype.h>
#include "cli/cli-utils.h"
+#include "python/python.h"
extern void _initialize_typeprint (void);
@@ -52,7 +53,9 @@ const struct type_print_options type_print_raw_options =
1, /* raw */
1, /* print_methods */
1, /* print_typedefs */
- NULL /* local_typedefs */
+ NULL, /* local_typedefs */
+ NULL, /* global_table */
+ NULL /* global_printers */
};
/* The default flags for 'ptype' and 'whatis'. */
@@ -62,7 +65,9 @@ static struct type_print_options default_ptype_flags =
0, /* raw */
1, /* print_methods */
1, /* print_typedefs */
- NULL /* local_typedefs */
+ NULL, /* local_typedefs */
+ NULL, /* global_table */
+ NULL /* global_printers */
};
@@ -235,6 +240,74 @@ copy_typedef_hash (struct typedef_hash_table *table)
return result;
}
+/* A cleanup to free the global typedef hash. */
+
+static void
+do_free_global_table (void *arg)
+{
+ struct type_print_options *flags = arg;
+
+ free_typedef_hash (flags->global_typedefs);
+ free_type_printers (flags->global_printers);
+}
+
+/* Create the global typedef hash. */
+
+static struct cleanup *
+create_global_typedef_table (struct type_print_options *flags)
+{
+ gdb_assert (flags->global_typedefs == NULL && flags->global_printers == NULL);
+ flags->global_typedefs = create_typedef_hash ();
+ flags->global_printers = start_type_printers ();
+ return make_cleanup (do_free_global_table, flags);
+}
+
+/* Look up the type T in the global typedef hash. If it is found,
+ return the typedef name. If it is not found, apply the
+ type-printers, if any, given by start_type_printers and return the
+ result. A NULL return means that the name was not found. */
+
+static const char *
+find_global_typedef (const struct type_print_options *flags,
+ struct type *t)
+{
+ char *applied;
+ void **slot;
+ struct typedef_field tf, *new_tf;
+
+ if (flags->global_typedefs == NULL)
+ return NULL;
+
+ tf.name = NULL;
+ tf.type = t;
+
+ slot = htab_find_slot (flags->global_typedefs->table, &tf, INSERT);
+ if (*slot != NULL)
+ {
+ new_tf = *slot;
+ return new_tf->name;
+ }
+
+ /* Put an entry into the hash table now, in case apply_type_printers
+ recurses. */
+ new_tf = XOBNEW (&flags->global_typedefs->storage, struct typedef_field);
+ new_tf->name = NULL;
+ new_tf->type = t;
+
+ *slot = new_tf;
+
+ applied = apply_type_printers (flags->global_printers, t);
+
+ if (applied != NULL)
+ {
+ new_tf->name = obstack_copy0 (&flags->global_typedefs->storage, applied,
+ strlen (applied));
+ xfree (applied);
+ }
+
+ return new_tf->name;
+}
+
/* Look up the type T in the typedef hash table in with FLAGS. If T
is in the table, return its short (class-relative) typedef name.
Otherwise return NULL. If the table is NULL, this always returns
@@ -243,16 +316,19 @@ copy_typedef_hash (struct typedef_hash_table *table)
const char *
find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
{
- struct typedef_field tf, *found;
+ if (flags->local_typedefs != NULL)
+ {
+ struct typedef_field tf, *found;
- if (flags->local_typedefs == NULL)
- return NULL;
+ tf.name = NULL;
+ tf.type = t;
+ found = htab_find (flags->local_typedefs->table, &tf);
- tf.name = NULL;
- tf.type = t;
- found = htab_find (flags->local_typedefs->table, &tf);
+ if (found != NULL)
+ return found->name;
+ }
- return found == NULL ? NULL : found->name;
+ return find_global_typedef (flags, t);
}
@@ -325,7 +401,7 @@ whatis_exp (char *exp, int show)
{
struct expression *expr;
struct value *val;
- struct cleanup *old_chain = NULL;
+ struct cleanup *old_chain;
struct type *real_type = NULL;
struct type *type;
int full = 0;
@@ -334,6 +410,8 @@ whatis_exp (char *exp, int show)
struct value_print_options opts;
struct type_print_options flags = default_ptype_flags;
+ old_chain = make_cleanup (null_cleanup, NULL);
+
if (exp)
{
if (*exp == '/')
@@ -373,7 +451,7 @@ whatis_exp (char *exp, int show)
}
expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
+ make_cleanup (free_current_contents, &expr);
val = evaluate_type (expr);
}
else
@@ -394,6 +472,9 @@ whatis_exp (char *exp, int show)
printf_filtered ("type = ");
+ if (!flags.raw)
+ create_global_typedef_table (&flags);
+
if (real_type)
{
printf_filtered ("/* real type = ");
@@ -406,8 +487,7 @@ whatis_exp (char *exp, int show)
LA_PRINT_TYPE (type, "", gdb_stdout, show, 0, &flags);
printf_filtered ("\n");
- if (exp)
- do_cleanups (old_chain);
+ do_cleanups (old_chain);
}
static void
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 71bac01..a201bdd 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -38,6 +38,14 @@ struct type_print_options
/* If not NULL, a local typedef hash table used when printing a
type. */
struct typedef_hash_table *local_typedefs;
+
+ /* If not NULL, a global typedef hash table used when printing a
+ type. */
+ struct typedef_hash_table *global_typedefs;
+
+ /* The list of type printers associated with the global typedef
+ table. This is intentionally opaque. */
+ void *global_printers;
};
extern const struct type_print_options type_print_raw_options;