* 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.
This commit is contained in:
Tom Tromey 2012-11-12 17:41:59 +00:00
parent bd69fc683f
commit 18a9fc1261
19 changed files with 874 additions and 17 deletions

View File

@ -1,3 +1,43 @@
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,

View File

@ -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

View File

@ -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 \

View File

@ -1,3 +1,14 @@
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",

View File

@ -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

View File

@ -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__))

View File

@ -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()

View File

@ -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)

View File

@ -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 }
};

View File

@ -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 }
};

View File

@ -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 */

View File

@ -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 */

View File

@ -1,3 +1,10 @@
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".

View File

@ -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"
}
}

View File

@ -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;
}

View File

@ -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}

View File

@ -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())

View File

@ -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

View File

@ -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;