* 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:
parent
bd69fc683f
commit
18a9fc1261
|
@ -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,
|
||||
|
|
6
gdb/NEWS
6
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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__))
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -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)
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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}
|
|
@ -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())
|
106
gdb/typeprint.c
106
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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue