forked from Imagelibrary/binutils-gdb
* 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:
@@ -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>
|
2012-11-12 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
* c-typeprint.c (find_typedef_for_canonicalize,
|
* 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.
|
** Python's atexit.register now works in GDB.
|
||||||
|
|
||||||
|
** Types can be pretty-printed via a Python API.
|
||||||
|
|
||||||
* New Python-based convenience functions:
|
* New Python-based convenience functions:
|
||||||
|
|
||||||
** $_memeq(buf1, buf2, length)
|
** $_memeq(buf1, buf2, length)
|
||||||
@@ -51,6 +53,10 @@ pi [command]
|
|||||||
py [command]
|
py [command]
|
||||||
"py" is a new alias for "python".
|
"py" is a new alias for "python".
|
||||||
|
|
||||||
|
enable type-printer [name]...
|
||||||
|
disable type-printer [name]...
|
||||||
|
Enable or disable type printers.
|
||||||
|
|
||||||
* Removed commands
|
* Removed commands
|
||||||
|
|
||||||
** For the Renesas Super-H architecture, the "regs" command has been removed
|
** For the Renesas Super-H architecture, the "regs" command has been removed
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ PYTHON_FILES = \
|
|||||||
gdb/printing.py \
|
gdb/printing.py \
|
||||||
gdb/prompt.py \
|
gdb/prompt.py \
|
||||||
gdb/command/__init__.py \
|
gdb/command/__init__.py \
|
||||||
|
gdb/command/type_printers.py \
|
||||||
gdb/command/pretty_printers.py \
|
gdb/command/pretty_printers.py \
|
||||||
gdb/command/prompt.py \
|
gdb/command/prompt.py \
|
||||||
gdb/command/explore.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>
|
2012-11-12 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
* gdb.texinfo (Symbols): Document "set print type methods",
|
* 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
|
@code{whatis}, it does not print a detailed description; second, it
|
||||||
lists all source files where a type is defined.
|
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
|
@kindex info scope
|
||||||
@cindex local variables
|
@cindex local variables
|
||||||
@item info scope @var{location}
|
@item info scope @var{location}
|
||||||
@@ -22671,6 +22687,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
|
|||||||
* Pretty Printing API:: Pretty-printing values.
|
* Pretty Printing API:: Pretty-printing values.
|
||||||
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
|
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
|
||||||
* Writing a Pretty-Printer:: Writing 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)
|
* Inferiors In Python:: Python representation of inferiors (processes)
|
||||||
* Events In Python:: Listening for events from @value{GDBN}.
|
* Events In Python:: Listening for events from @value{GDBN}.
|
||||||
* Threads In Python:: Accessing inferior threads from Python.
|
* Threads In Python:: Accessing inferior threads from Python.
|
||||||
@@ -23966,6 +23983,68 @@ my_library.so:
|
|||||||
bar
|
bar
|
||||||
@end smallexample
|
@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
|
@node Inferiors In Python
|
||||||
@subsubsection Inferiors In Python
|
@subsubsection Inferiors In Python
|
||||||
@cindex 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.
|
information.
|
||||||
@end defvar
|
@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
|
@node Objfiles In Python
|
||||||
@subsubsection 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.
|
information.
|
||||||
@end defvar
|
@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:
|
A @code{gdb.Objfile} object has the following methods:
|
||||||
|
|
||||||
@defun Objfile.is_valid ()
|
@defun Objfile.is_valid ()
|
||||||
@@ -26057,7 +26146,7 @@ if a printer with the same name already exists.
|
|||||||
@cindex gdb.types
|
@cindex gdb.types
|
||||||
|
|
||||||
This module provides a collection of utilities for working with
|
This module provides a collection of utilities for working with
|
||||||
@code{gdb.Types} objects.
|
@code{gdb.Type} objects.
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@item get_basic_type (@var{type})
|
@item get_basic_type (@var{type})
|
||||||
@@ -26118,6 +26207,37 @@ Then in @value{GDBN}:
|
|||||||
@{['a', 'b0', 'b1']@}
|
@{['a', 'b0', 'b1']@}
|
||||||
@end smallexample
|
@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
|
@end table
|
||||||
|
|
||||||
@node gdb.prompt
|
@node gdb.prompt
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ sys.argv = ['']
|
|||||||
# Initial pretty printers.
|
# Initial pretty printers.
|
||||||
pretty_printers = []
|
pretty_printers = []
|
||||||
|
|
||||||
|
# Initial type printers.
|
||||||
|
type_printers = []
|
||||||
|
|
||||||
# Convenience variable to GDB's python directory
|
# Convenience variable to GDB's python directory
|
||||||
PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
|
PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|||||||
125
gdb/python/lib/gdb/command/type_printers.py
Normal file
125
gdb/python/lib/gdb/command/type_printers.py
Normal 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:
|
else:
|
||||||
for i in deep_items (v.type):
|
for i in deep_items (v.type):
|
||||||
yield i
|
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. */
|
/* The pretty-printer list of functions. */
|
||||||
PyObject *printers;
|
PyObject *printers;
|
||||||
|
|
||||||
|
/* The type-printer list. */
|
||||||
|
PyObject *type_printers;
|
||||||
} objfile_object;
|
} objfile_object;
|
||||||
|
|
||||||
static PyTypeObject objfile_object_type;
|
static PyTypeObject objfile_object_type;
|
||||||
@@ -58,6 +61,7 @@ objfpy_dealloc (PyObject *o)
|
|||||||
objfile_object *self = (objfile_object *) o;
|
objfile_object *self = (objfile_object *) o;
|
||||||
|
|
||||||
Py_XDECREF (self->printers);
|
Py_XDECREF (self->printers);
|
||||||
|
Py_XDECREF (self->type_printers);
|
||||||
self->ob_type->tp_free ((PyObject *) self);
|
self->ob_type->tp_free ((PyObject *) self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +80,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
|
|||||||
Py_DECREF (self);
|
Py_DECREF (self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->type_printers = PyList_New (0);
|
||||||
|
if (!self->type_printers)
|
||||||
|
{
|
||||||
|
Py_DECREF (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (PyObject *) self;
|
return (PyObject *) self;
|
||||||
}
|
}
|
||||||
@@ -118,6 +129,48 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore)
|
|||||||
return 0;
|
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.
|
/* Implementation of gdb.Objfile.is_valid (self) -> Boolean.
|
||||||
Returns True if this object file still exists in GDB. */
|
Returns True if this object file still exists in GDB. */
|
||||||
|
|
||||||
@@ -172,6 +225,13 @@ objfile_to_objfile_object (struct objfile *objfile)
|
|||||||
return NULL;
|
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);
|
set_objfile_data (objfile, objfpy_objfile_data_key, object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,6 +270,8 @@ static PyGetSetDef objfile_getset[] =
|
|||||||
"The objfile's filename, or None.", NULL },
|
"The objfile's filename, or None.", NULL },
|
||||||
{ "pretty_printers", objfpy_get_printers, objfpy_set_printers,
|
{ "pretty_printers", objfpy_get_printers, objfpy_set_printers,
|
||||||
"Pretty printers.", NULL },
|
"Pretty printers.", NULL },
|
||||||
|
{ "type_printers", objfpy_get_type_printers, objfpy_set_type_printers,
|
||||||
|
"Type printers.", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ typedef struct
|
|||||||
|
|
||||||
/* The pretty-printer list of functions. */
|
/* The pretty-printer list of functions. */
|
||||||
PyObject *printers;
|
PyObject *printers;
|
||||||
|
|
||||||
|
/* The type-printer list. */
|
||||||
|
PyObject *type_printers;
|
||||||
} pspace_object;
|
} pspace_object;
|
||||||
|
|
||||||
static PyTypeObject pspace_object_type;
|
static PyTypeObject pspace_object_type;
|
||||||
@@ -66,6 +69,7 @@ pspy_dealloc (PyObject *self)
|
|||||||
pspace_object *ps_self = (pspace_object *) self;
|
pspace_object *ps_self = (pspace_object *) self;
|
||||||
|
|
||||||
Py_XDECREF (ps_self->printers);
|
Py_XDECREF (ps_self->printers);
|
||||||
|
Py_XDECREF (ps_self->type_printers);
|
||||||
self->ob_type->tp_free (self);
|
self->ob_type->tp_free (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +88,13 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
|
|||||||
Py_DECREF (self);
|
Py_DECREF (self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->type_printers = PyList_New (0);
|
||||||
|
if (!self->type_printers)
|
||||||
|
{
|
||||||
|
Py_DECREF (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (PyObject *) self;
|
return (PyObject *) self;
|
||||||
}
|
}
|
||||||
@@ -126,6 +137,48 @@ pspy_set_printers (PyObject *o, PyObject *value, void *ignore)
|
|||||||
return 0;
|
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. */
|
/* 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;
|
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);
|
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 },
|
"The progspace's main filename, or None.", NULL },
|
||||||
{ "pretty_printers", pspy_get_printers, pspy_set_printers,
|
{ "pretty_printers", pspy_get_printers, pspy_set_printers,
|
||||||
"Pretty printers.", NULL },
|
"Pretty printers.", NULL },
|
||||||
|
{ "type_printers", pspy_get_type_printers, pspy_set_type_printers,
|
||||||
|
"Type printers.", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1181,6 +1181,125 @@ gdbpy_objfiles (PyObject *unused1, PyObject *unused2)
|
|||||||
return list;
|
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 */
|
#else /* HAVE_PYTHON */
|
||||||
|
|
||||||
/* Dummy implementation of the gdb "python-interactive" and "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."));
|
"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 */
|
#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);
|
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 */
|
#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>
|
2012-11-12 Tom Tromey <tromey@redhat.com>
|
||||||
|
|
||||||
* gdb.base/call-sc.exp: Use "ptype/r".
|
* gdb.base/call-sc.exp: Use "ptype/r".
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ gdb_test_multiple "" "$test" {
|
|||||||
-re "^info t foo\\\x07$" {
|
-re "^info t foo\\\x07$" {
|
||||||
send_gdb "\n"
|
send_gdb "\n"
|
||||||
gdb_test_multiple "" "$test" {
|
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"
|
pass "$test"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ gdb_test_multiple "" "$test" {
|
|||||||
-re "^info t\\\x07$" {
|
-re "^info t\\\x07$" {
|
||||||
send_gdb "\n"
|
send_gdb "\n"
|
||||||
gdb_test_multiple "" "$test" {
|
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"
|
pass "$test"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,7 +187,7 @@ gdb_test_multiple "" "$test" {
|
|||||||
-re "^info t \\\x07$" {
|
-re "^info t \\\x07$" {
|
||||||
send_gdb "\n"
|
send_gdb "\n"
|
||||||
gdb_test_multiple "" "$test" {
|
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"
|
pass "$test"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
gdb/testsuite/gdb.python/py-typeprint.cc
Normal file
37
gdb/testsuite/gdb.python/py-typeprint.cc
Normal 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;
|
||||||
|
}
|
||||||
53
gdb/testsuite/gdb.python/py-typeprint.exp
Normal file
53
gdb/testsuite/gdb.python/py-typeprint.exp
Normal 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}
|
||||||
35
gdb/testsuite/gdb.python/py-typeprint.py
Normal file
35
gdb/testsuite/gdb.python/py-typeprint.py
Normal 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 <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "cli/cli-utils.h"
|
#include "cli/cli-utils.h"
|
||||||
|
#include "python/python.h"
|
||||||
|
|
||||||
extern void _initialize_typeprint (void);
|
extern void _initialize_typeprint (void);
|
||||||
|
|
||||||
@@ -52,7 +53,9 @@ const struct type_print_options type_print_raw_options =
|
|||||||
1, /* raw */
|
1, /* raw */
|
||||||
1, /* print_methods */
|
1, /* print_methods */
|
||||||
1, /* print_typedefs */
|
1, /* print_typedefs */
|
||||||
NULL /* local_typedefs */
|
NULL, /* local_typedefs */
|
||||||
|
NULL, /* global_table */
|
||||||
|
NULL /* global_printers */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The default flags for 'ptype' and 'whatis'. */
|
/* The default flags for 'ptype' and 'whatis'. */
|
||||||
@@ -62,7 +65,9 @@ static struct type_print_options default_ptype_flags =
|
|||||||
0, /* raw */
|
0, /* raw */
|
||||||
1, /* print_methods */
|
1, /* print_methods */
|
||||||
1, /* print_typedefs */
|
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;
|
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
|
/* 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.
|
is in the table, return its short (class-relative) typedef name.
|
||||||
Otherwise return NULL. If the table is NULL, this always returns
|
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 *
|
const char *
|
||||||
find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
|
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)
|
tf.name = NULL;
|
||||||
return NULL;
|
tf.type = t;
|
||||||
|
found = htab_find (flags->local_typedefs->table, &tf);
|
||||||
|
|
||||||
tf.name = NULL;
|
if (found != NULL)
|
||||||
tf.type = t;
|
return found->name;
|
||||||
found = htab_find (flags->local_typedefs->table, &tf);
|
}
|
||||||
|
|
||||||
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 expression *expr;
|
||||||
struct value *val;
|
struct value *val;
|
||||||
struct cleanup *old_chain = NULL;
|
struct cleanup *old_chain;
|
||||||
struct type *real_type = NULL;
|
struct type *real_type = NULL;
|
||||||
struct type *type;
|
struct type *type;
|
||||||
int full = 0;
|
int full = 0;
|
||||||
@@ -334,6 +410,8 @@ whatis_exp (char *exp, int show)
|
|||||||
struct value_print_options opts;
|
struct value_print_options opts;
|
||||||
struct type_print_options flags = default_ptype_flags;
|
struct type_print_options flags = default_ptype_flags;
|
||||||
|
|
||||||
|
old_chain = make_cleanup (null_cleanup, NULL);
|
||||||
|
|
||||||
if (exp)
|
if (exp)
|
||||||
{
|
{
|
||||||
if (*exp == '/')
|
if (*exp == '/')
|
||||||
@@ -373,7 +451,7 @@ whatis_exp (char *exp, int show)
|
|||||||
}
|
}
|
||||||
|
|
||||||
expr = parse_expression (exp);
|
expr = parse_expression (exp);
|
||||||
old_chain = make_cleanup (free_current_contents, &expr);
|
make_cleanup (free_current_contents, &expr);
|
||||||
val = evaluate_type (expr);
|
val = evaluate_type (expr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -394,6 +472,9 @@ whatis_exp (char *exp, int show)
|
|||||||
|
|
||||||
printf_filtered ("type = ");
|
printf_filtered ("type = ");
|
||||||
|
|
||||||
|
if (!flags.raw)
|
||||||
|
create_global_typedef_table (&flags);
|
||||||
|
|
||||||
if (real_type)
|
if (real_type)
|
||||||
{
|
{
|
||||||
printf_filtered ("/* 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);
|
LA_PRINT_TYPE (type, "", gdb_stdout, show, 0, &flags);
|
||||||
printf_filtered ("\n");
|
printf_filtered ("\n");
|
||||||
|
|
||||||
if (exp)
|
do_cleanups (old_chain);
|
||||||
do_cleanups (old_chain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -38,6 +38,14 @@ struct type_print_options
|
|||||||
/* If not NULL, a local typedef hash table used when printing a
|
/* If not NULL, a local typedef hash table used when printing a
|
||||||
type. */
|
type. */
|
||||||
struct typedef_hash_table *local_typedefs;
|
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;
|
extern const struct type_print_options type_print_raw_options;
|
||||||
|
|||||||
Reference in New Issue
Block a user