New python module gdb.printing, and new commands info pretty-printer,
enable pretty-printer, disable pretty-printer. * NEWS: Mention them. * data-directory/Makefile.in (PYTHON_FILES): Add gdb/printing.py, gdb/command/__init__.py, gdb/command/pretty_printers.py. * python/lib/gdb/__init__.py: Install pretty-printer commands. * python/lib/gdb/printing.py: New file. * python/lib/gdb/command/__init__.py: New file. * python/lib/gdb/command/pretty_printers.py: New file. doc/ * gdb.texinfo (Pretty Printing): Expand into three sections, introduction, example, and commands. (Python API): Delete section Disabling Pretty-Printers, merge into Selecting Pretty-Printers. (Writing a Pretty-Printer): New section. Move the pretty-printer example here, and reformat to match python coding style. Add a second example using the gdb.printing module. (Python modules): Add gdb.printing. testsuite/ * gdb.python/py-pp-maint.c: New file. * gdb.python/py-pp-maint.exp: New file. * gdb.python/py-pp-maint.py: New file.
This commit is contained in:
parent
50c97f3812
commit
7b51bc51e1
13 changed files with 1184 additions and 42 deletions
|
@ -1,3 +1,15 @@
|
|||
2010-11-02 Doug Evans <dje@google.com>
|
||||
|
||||
New python module gdb.printing, and new commands info pretty-printer,
|
||||
enable pretty-printer, disable pretty-printer.
|
||||
* NEWS: Mention them.
|
||||
* data-directory/Makefile.in (PYTHON_FILES): Add gdb/printing.py,
|
||||
gdb/command/__init__.py, gdb/command/pretty_printers.py.
|
||||
* python/lib/gdb/__init__.py: Install pretty-printer commands.
|
||||
* python/lib/gdb/printing.py: New file.
|
||||
* python/lib/gdb/command/__init__.py: New file.
|
||||
* python/lib/gdb/command/pretty_printers.py: New file.
|
||||
|
||||
2010-11-02 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* NEWS: Mention Guile removal.
|
||||
|
|
9
gdb/NEWS
9
gdb/NEWS
|
@ -16,6 +16,15 @@
|
|||
It contains a collection of utilities for working with gdb.Types objects:
|
||||
get_basic_type, has_field, make_enum_dict.
|
||||
|
||||
** Module gdb.printing has been added.
|
||||
It contains utilities for writing and registering pretty-printers.
|
||||
New classes: PrettyPrinter, SubPrettyPrinter,
|
||||
RegexpCollectionPrettyPrinter.
|
||||
New function: register_pretty_printer.
|
||||
|
||||
** New commands "info pretty-printers", "enable pretty-printer" and
|
||||
"disable pretty-printer" have been added.
|
||||
|
||||
* C++ Improvements:
|
||||
|
||||
** GDB now puts template parameters in scope when debugging in an
|
||||
|
|
|
@ -52,7 +52,10 @@ PYTHON_DIR = python
|
|||
PYTHON_INSTALL_DIR = $(DESTDIR)/$(GDB_DATADIR)/$(PYTHON_DIR)
|
||||
PYTHON_FILES = \
|
||||
gdb/__init__.py \
|
||||
gdb/types.py
|
||||
gdb/types.py \
|
||||
gdb/printing.py \
|
||||
gdb/command/__init__.py \
|
||||
gdb/command/pretty_printers.py
|
||||
|
||||
FLAGS_TO_PASS = \
|
||||
"prefix=$(prefix)" \
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
2010-11-02 Doug Evans <dje@google.com>
|
||||
|
||||
* gdb.texinfo (Pretty Printing): Expand into three sections,
|
||||
introduction, example, and commands.
|
||||
(Python API): Delete section Disabling Pretty-Printers, merge into
|
||||
Selecting Pretty-Printers.
|
||||
(Writing a Pretty-Printer): New section. Move the pretty-printer
|
||||
example here, and reformat to match python coding style. Add a second
|
||||
example using the gdb.printing module.
|
||||
(Python modules): Add gdb.printing.
|
||||
|
||||
2010-10-29 Doug Evans <dje@google.com>
|
||||
|
||||
* gdb.texinfo (Python): Fix long line.
|
||||
|
|
|
@ -8127,8 +8127,60 @@ Show whether C@t{++} virtual function tables are pretty printed, or not.
|
|||
Python code. It greatly simplifies the display of complex objects. This
|
||||
mechanism works for both MI and the CLI.
|
||||
|
||||
For example, here is how a C@t{++} @code{std::string} looks without a
|
||||
pretty-printer:
|
||||
@menu
|
||||
* Pretty-Printer Introduction:: Introduction to pretty-printers
|
||||
* Pretty-Printer Example:: An example pretty-printer
|
||||
* Pretty-Printer Commands:: Pretty-printer commands
|
||||
@end menu
|
||||
|
||||
@node Pretty-Printer Introduction
|
||||
@subsection Pretty-Printer Introduction
|
||||
|
||||
When @value{GDBN} prints a value, it first sees if there is a pretty-printer
|
||||
registered for the value. If there is then @value{GDBN} invokes the
|
||||
pretty-printer to print the value. Otherwise the value is printed normally.
|
||||
|
||||
Pretty-printers are normally named. This makes them easy to manage.
|
||||
The @samp{info pretty-printer} command will list all the installed
|
||||
pretty-printers with their names.
|
||||
If a pretty-printer can handle multiple data types, then its
|
||||
@dfn{subprinters} are the printers for the individual data types.
|
||||
Each such subprinter has its own name.
|
||||
The format of the name is @var{printer-name}:@var{subprinter-name}.
|
||||
|
||||
Pretty-printers are installed by @dfn{registering} them with @value{GDBN}.
|
||||
Typically they are automatically loaded and registered when the corresponding
|
||||
debug information is loaded, thus making them available without having to
|
||||
do anything special.
|
||||
|
||||
There are three places where a pretty-printer can be registered.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Pretty-printers registered globally are available when debugging
|
||||
all inferiors.
|
||||
|
||||
@item
|
||||
Pretty-printers registered with a program space are available only
|
||||
when debugging that program.
|
||||
@xref{Progspaces In Python}, for more details on program spaces in Python.
|
||||
|
||||
@item
|
||||
Pretty-printers registered with an objfile are loaded and unloaded
|
||||
with the corresponding objfile (e.g., shared library).
|
||||
@xref{Objfiles In Python}, for more details on objfiles in Python.
|
||||
@end itemize
|
||||
|
||||
@xref{Selecting Pretty-Printers}, for further information on how
|
||||
pretty-printers are selected,
|
||||
|
||||
@xref{Writing a Pretty-Printer}, for implementing pretty printers
|
||||
for new types.
|
||||
|
||||
@node Pretty-Printer Example
|
||||
@subsection Pretty-Printer Example
|
||||
|
||||
Here is how a C@t{++} @code{std::string} looks without a pretty-printer:
|
||||
|
||||
@smallexample
|
||||
(@value{GDBP}) print s
|
||||
|
@ -8153,8 +8205,91 @@ With a pretty-printer for @code{std::string} only the contents are printed:
|
|||
$2 = "abcd"
|
||||
@end smallexample
|
||||
|
||||
For implementing pretty printers for new types you should read the Python API
|
||||
details (@pxref{Pretty Printing API}).
|
||||
@node Pretty-Printer Commands
|
||||
@subsection Pretty-Printer Commands
|
||||
@cindex pretty-printer commands
|
||||
|
||||
@table @code
|
||||
@kindex info pretty-printer
|
||||
@item info pretty-printer [@var{object-regexp} [@var{name-regexp}]]
|
||||
Print the list of installed pretty-printers.
|
||||
This includes disabled pretty-printers, which are marked as such.
|
||||
|
||||
@var{object-regexp} is a regular expression matching the objects
|
||||
whose pretty-printers to list.
|
||||
Objects can be @code{global}, the program space's file
|
||||
(@pxref{Progspaces In Python}),
|
||||
and the object files within that program space (@pxref{Objfiles In Python}).
|
||||
@xref{Selecting Pretty-Printers}, for details on how @value{GDBN}
|
||||
looks up a printer from these three objects.
|
||||
|
||||
@var{name-regexp} is a regular expression matching the name of the printers
|
||||
to list.
|
||||
|
||||
@kindex disable pretty-printer
|
||||
@item disable pretty-printer [@var{object-regexp} [@var{name-regexp}]]
|
||||
Disable pretty-printers matching @var{object-regexp} and @var{name-regexp}.
|
||||
A disabled pretty-printer is not forgotten, it may be enabled again later.
|
||||
|
||||
@kindex enable pretty-printer
|
||||
@item enable pretty-printer [@var{object-regexp} [@var{name-regexp}]]
|
||||
Enable pretty-printers matching @var{object-regexp} and @var{name-regexp}.
|
||||
@end table
|
||||
|
||||
Example:
|
||||
|
||||
Suppose we have three pretty-printers installed: one from library1.so
|
||||
named @code{foo} that prints objects of type @code{foo}, and
|
||||
another from library2.so named @code{bar} that prints two types of objects,
|
||||
@code{bar1} and @code{bar2}.
|
||||
|
||||
@smallexample
|
||||
(gdb) info pretty-printer
|
||||
library1.so:
|
||||
foo
|
||||
library2.so:
|
||||
bar
|
||||
bar1
|
||||
bar2
|
||||
(gdb) info pretty-printer library2
|
||||
library2.so:
|
||||
bar
|
||||
bar1
|
||||
bar2
|
||||
(gdb) disable pretty-printer library1
|
||||
1 printer disabled
|
||||
2 of 3 printers enabled
|
||||
(gdb) info pretty-printer
|
||||
library1.so:
|
||||
foo [disabled]
|
||||
library2.so:
|
||||
bar
|
||||
bar1
|
||||
bar2
|
||||
(gdb) disable pretty-printer library2 bar:bar1
|
||||
1 printer disabled
|
||||
1 of 3 printers enabled
|
||||
(gdb) info pretty-printer library2
|
||||
library1.so:
|
||||
foo [disabled]
|
||||
library2.so:
|
||||
bar
|
||||
bar1 [disabled]
|
||||
bar2
|
||||
(gdb) disable pretty-printer library2 bar
|
||||
1 printer disabled
|
||||
0 of 3 printers enabled
|
||||
(gdb) info pretty-printer library2
|
||||
library1.so:
|
||||
foo [disabled]
|
||||
library2.so:
|
||||
bar [disabled]
|
||||
bar1 [disabled]
|
||||
bar2
|
||||
@end smallexample
|
||||
|
||||
Note that for @code{bar} the entire printer can be disabled,
|
||||
as can each individual subprinter.
|
||||
|
||||
@node Value History
|
||||
@section Value History
|
||||
|
@ -20484,7 +20619,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
|
|||
* Types In Python:: Python representation of types.
|
||||
* Pretty Printing API:: Pretty-printing values.
|
||||
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
|
||||
* Disabling Pretty-Printers:: Disabling broken printers.
|
||||
* Writing a Pretty-Printer:: Writing a Pretty-Printer.
|
||||
* Inferiors In Python:: Python representation of inferiors (processes)
|
||||
* Threads In Python:: Accessing inferior threads from Python.
|
||||
* Commands In Python:: Implementing new commands in Python.
|
||||
|
@ -21349,12 +21484,13 @@ printer exists, then this returns @code{None}.
|
|||
|
||||
The Python list @code{gdb.pretty_printers} contains an array of
|
||||
functions or callable objects that have been registered via addition
|
||||
as a pretty-printer.
|
||||
as a pretty-printer. Printers in this list are called @code{global}
|
||||
printers, they're available when debugging all inferiors.
|
||||
Each @code{gdb.Progspace} contains a @code{pretty_printers} attribute.
|
||||
Each @code{gdb.Objfile} also contains a @code{pretty_printers}
|
||||
attribute.
|
||||
|
||||
A function on one of these lists is passed a single @code{gdb.Value}
|
||||
Each function on these lists is passed a single @code{gdb.Value}
|
||||
argument and should return a pretty-printer object conforming to the
|
||||
interface definition above (@pxref{Pretty Printing API}). If a function
|
||||
cannot create a pretty-printer for the value, it should return
|
||||
|
@ -21362,9 +21498,8 @@ cannot create a pretty-printer for the value, it should return
|
|||
|
||||
@value{GDBN} first checks the @code{pretty_printers} attribute of each
|
||||
@code{gdb.Objfile} in the current program space and iteratively calls
|
||||
each enabled function (@pxref{Disabling Pretty-Printers})
|
||||
in the list for that @code{gdb.Objfile} until it receives
|
||||
a pretty-printer object.
|
||||
each enabled lookup routine in the list for that @code{gdb.Objfile}
|
||||
until it receives a pretty-printer object.
|
||||
If no pretty-printer is found in the objfile lists, @value{GDBN} then
|
||||
searches the pretty-printer list of the current program space,
|
||||
calling each enabled function until an object is returned.
|
||||
|
@ -21377,20 +21512,43 @@ given list, functions are always invoked from the head of the list,
|
|||
and iterated over sequentially until the end of the list, or a printer
|
||||
object is returned.
|
||||
|
||||
For various reasons a pretty-printer may not work.
|
||||
For example, the underlying data structure may have changed and
|
||||
the pretty-printer is out of date.
|
||||
|
||||
The consequences of a broken pretty-printer are severe enough that
|
||||
@value{GDBN} provides support for enabling and disabling individual
|
||||
printers. For example, if @code{print frame-arguments} is on,
|
||||
a backtrace can become highly illegible if any argument is printed
|
||||
with a broken printer.
|
||||
|
||||
Pretty-printers are enabled and disabled by attaching an @code{enabled}
|
||||
attribute to the registered function or callable object. If this attribute
|
||||
is present and its value is @code{False}, the printer is disabled, otherwise
|
||||
the printer is enabled.
|
||||
|
||||
@node Writing a Pretty-Printer
|
||||
@subsubsection Writing a Pretty-Printer
|
||||
@cindex writing a pretty-printer
|
||||
|
||||
A pretty-printer consists of two parts: a lookup function to detect
|
||||
if the type is supported, and the printer itself.
|
||||
|
||||
Here is an example showing how a @code{std::string} printer might be
|
||||
written:
|
||||
written. @xref{Pretty Printing API}, for details on the API this class
|
||||
must provide.
|
||||
|
||||
@smallexample
|
||||
class StdStringPrinter:
|
||||
class StdStringPrinter(object):
|
||||
"Print a std::string"
|
||||
|
||||
def __init__ (self, val):
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string (self):
|
||||
def to_string(self):
|
||||
return self.val['_M_dataplus']['_M_p']
|
||||
|
||||
def display_hint (self):
|
||||
def display_hint(self):
|
||||
return 'string'
|
||||
@end smallexample
|
||||
|
||||
|
@ -21398,15 +21556,13 @@ And here is an example showing how a lookup function for the printer
|
|||
example above might be written.
|
||||
|
||||
@smallexample
|
||||
def str_lookup_function (val):
|
||||
|
||||
def str_lookup_function(val):
|
||||
lookup_tag = val.type.tag
|
||||
regex = re.compile ("^std::basic_string<char,.*>$")
|
||||
if lookup_tag == None:
|
||||
return None
|
||||
if regex.match (lookup_tag):
|
||||
return StdStringPrinter (val)
|
||||
|
||||
regex = re.compile("^std::basic_string<char,.*>$")
|
||||
if regex.match(lookup_tag):
|
||||
return StdStringPrinter(val)
|
||||
return None
|
||||
@end smallexample
|
||||
|
||||
|
@ -21442,8 +21598,8 @@ To continue the @code{std::string} example (@pxref{Pretty Printing API}),
|
|||
this code might appear in @code{gdb.libstdcxx.v6}:
|
||||
|
||||
@smallexample
|
||||
def register_printers (objfile):
|
||||
objfile.pretty_printers.add (str_lookup_function)
|
||||
def register_printers(objfile):
|
||||
objfile.pretty_printers.add(str_lookup_function)
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
|
@ -21451,27 +21607,92 @@ And then the corresponding contents of the auto-load file would be:
|
|||
|
||||
@smallexample
|
||||
import gdb.libstdcxx.v6
|
||||
gdb.libstdcxx.v6.register_printers (gdb.current_objfile ())
|
||||
gdb.libstdcxx.v6.register_printers(gdb.current_objfile())
|
||||
@end smallexample
|
||||
|
||||
@node Disabling Pretty-Printers
|
||||
@subsubsection Disabling Pretty-Printers
|
||||
@cindex disabling pretty-printers
|
||||
The previous example illustrates a basic pretty-printer.
|
||||
There are a few things that can be improved on.
|
||||
The printer doesn't have a name, making it hard to identify in a
|
||||
list of installed printers. The lookup function has a name, but
|
||||
lookup functions can have arbitrary, even identical, names.
|
||||
|
||||
For various reasons a pretty-printer may not work.
|
||||
For example, the underlying data structure may have changed and
|
||||
the pretty-printer is out of date.
|
||||
Second, the printer only handles one type, whereas a library typically has
|
||||
several types. One could install a lookup function for each desired type
|
||||
in the library, but one could also have a single lookup function recognize
|
||||
several types. The latter is the conventional way this is handled.
|
||||
If a pretty-printer can handle multiple data types, then its
|
||||
@dfn{subprinters} are the printers for the individual data types.
|
||||
|
||||
The consequences of a broken pretty-printer are severe enough that
|
||||
@value{GDBN} provides support for enabling and disabling individual
|
||||
printers. For example, if @code{print frame-arguments} is on,
|
||||
a backtrace can become highly illegible if any argument is printed
|
||||
with a broken printer.
|
||||
The @code{gdb.printing} module provides a formal way of solving these
|
||||
problems (@pxref{gdb.printing}).
|
||||
Here is another example that handles multiple types.
|
||||
|
||||
Pretty-printers are enabled and disabled by attaching an @code{enabled}
|
||||
attribute to the registered function or callable object. If this attribute
|
||||
is present and its value is @code{False}, the printer is disabled, otherwise
|
||||
the printer is enabled.
|
||||
These are the types we are going to pretty-print:
|
||||
|
||||
@smallexample
|
||||
struct foo @{ int a, b; @};
|
||||
struct bar @{ struct foo x, y; @};
|
||||
@end smallexample
|
||||
|
||||
Here are the printers:
|
||||
|
||||
@smallexample
|
||||
class fooPrinter:
|
||||
"""Print a foo object."""
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
return ("a=<" + str(self.val["a"]) +
|
||||
"> b=<" + str(self.val["b"]) + ">")
|
||||
|
||||
class barPrinter:
|
||||
"""Print a bar object."""
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
return ("x=<" + str(self.val["x"]) +
|
||||
"> y=<" + str(self.val["y"]) + ">")
|
||||
@end smallexample
|
||||
|
||||
This example doesn't need a lookup function, that is handled by the
|
||||
@code{gdb.printing} module. Instead a function is provided to build up
|
||||
the object that handles the lookup.
|
||||
|
||||
@smallexample
|
||||
import gdb.printing
|
||||
|
||||
def build_pretty_printer():
|
||||
pp = gdb.printing.RegexpCollectionPrettyPrinter(
|
||||
"my_library")
|
||||
pp.add_printer('foo', '^foo$', fooPrinter)
|
||||
pp.add_printer('bar', '^bar$', barPrinter)
|
||||
return pp
|
||||
@end smallexample
|
||||
|
||||
And here is the autoload support:
|
||||
|
||||
@smallexample
|
||||
import gdb.printing
|
||||
import my_library
|
||||
gdb.printing.register_pretty_printer(
|
||||
gdb.current_objfile(),
|
||||
my_library.build_pretty_printer())
|
||||
@end smallexample
|
||||
|
||||
Finally, when this printer is loaded into @value{GDBN}, here is the
|
||||
corresponding output of @samp{info pretty-printer}:
|
||||
|
||||
@smallexample
|
||||
(gdb) info pretty-printer
|
||||
my_library.so:
|
||||
my_library
|
||||
foo
|
||||
bar
|
||||
@end smallexample
|
||||
|
||||
@node Inferiors In Python
|
||||
@subsubsection Inferiors In Python
|
||||
|
@ -22920,16 +23141,42 @@ top of the source tree to the source search path.
|
|||
@subsection Python modules
|
||||
@cindex python modules
|
||||
|
||||
@c It is assumed that at least one more module will be added before
|
||||
@c the next release of gdb. Thus we use a menu here.
|
||||
@value{GDBN} comes with a module to assist writing Python code.
|
||||
|
||||
@menu
|
||||
* gdb.printing:: Building and registering pretty-printers.
|
||||
* gdb.types:: Utilities for working with types.
|
||||
@end menu
|
||||
|
||||
@node gdb.printing
|
||||
@subsubsection gdb.printing
|
||||
@cindex gdb.printing
|
||||
|
||||
This module provides a collection of utilities for working with
|
||||
pretty-printers.
|
||||
|
||||
@table @code
|
||||
@item PrettyPrinter (@var{name}, @var{subprinters}=None)
|
||||
This class specifies the API that makes @samp{info pretty-printer},
|
||||
@samp{enable pretty-printer} and @samp{disable pretty-printer} work.
|
||||
Pretty-printers should generally inherit from this class.
|
||||
|
||||
@item SubPrettyPrinter (@var{name})
|
||||
For printers that handle multiple types, this class specifies the
|
||||
corresponding API for the subprinters.
|
||||
|
||||
@item RegexpCollectionPrettyPrinter (@var{name})
|
||||
Utility class for handling multiple printers, all recognized via
|
||||
regular expressions.
|
||||
@xref{Writing a Pretty-Printer}, for an example.
|
||||
|
||||
@item register_pretty_printer (@var{obj}, @var{printer})
|
||||
Register @var{printer} with the pretty-printer list of @var{obj}.
|
||||
@end table
|
||||
|
||||
@node gdb.types
|
||||
@subsubsection gdb.types
|
||||
@cindex gdb.types
|
||||
|
||||
This module provides a collection of utilities for working with
|
||||
@code{gdb.Types} objects.
|
||||
|
|
|
@ -12,3 +12,7 @@
|
|||
#
|
||||
# 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.command.pretty_printers
|
||||
|
||||
gdb.command.pretty_printers.register_pretty_printer_commands()
|
||||
|
|
16
gdb/python/lib/gdb/command/__init__.py
Normal file
16
gdb/python/lib/gdb/command/__init__.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
369
gdb/python/lib/gdb/command/pretty_printers.py
Normal file
369
gdb/python/lib/gdb/command/pretty_printers.py
Normal file
|
@ -0,0 +1,369 @@
|
|||
# Pretty-printer commands.
|
||||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""GDB commands for working with pretty-printers."""
|
||||
|
||||
import copy
|
||||
import gdb
|
||||
import re
|
||||
|
||||
|
||||
def parse_printer_regexps(arg):
|
||||
"""Internal utility to parse a pretty-printer command argv.
|
||||
|
||||
Arguments:
|
||||
arg: The arguments to the command. The format is:
|
||||
[object-regexp [name-regexp]].
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
|
||||
Returns:
|
||||
The result is a 3-tuple of compiled regular expressions, except that
|
||||
the resulting compiled subprinter regexp is None if not provided.
|
||||
|
||||
Raises:
|
||||
SyntaxError: an error processing ARG
|
||||
"""
|
||||
|
||||
argv = gdb.string_to_argv(arg);
|
||||
argc = len(argv)
|
||||
object_regexp = "" # match everything
|
||||
name_regexp = "" # match everything
|
||||
subname_regexp = None
|
||||
if argc > 3:
|
||||
raise SyntaxError("too many arguments")
|
||||
if argc >= 1:
|
||||
object_regexp = argv[0]
|
||||
if argc >= 2:
|
||||
name_subname = argv[1].split(":", 1)
|
||||
name_regexp = name_subname[0]
|
||||
if len(name_subname) == 2:
|
||||
subname_regexp = name_subname[1]
|
||||
# That re.compile raises SyntaxError was determined empirically.
|
||||
# We catch it and reraise it to provide a slightly more useful
|
||||
# error message for the user.
|
||||
try:
|
||||
object_re = re.compile(object_regexp)
|
||||
except SyntaxError:
|
||||
raise SyntaxError("invalid object regexp: %s" % object_regexp)
|
||||
try:
|
||||
name_re = re.compile (name_regexp)
|
||||
except SyntaxError:
|
||||
raise SyntaxError("invalid name regexp: %s" % name_regexp)
|
||||
if subname_regexp is not None:
|
||||
try:
|
||||
subname_re = re.compile(subname_regexp)
|
||||
except SyntaxError:
|
||||
raise SyntaxError("invalid subname regexp: %s" % subname_regexp)
|
||||
else:
|
||||
subname_re = None
|
||||
return(object_re, name_re, subname_re)
|
||||
|
||||
|
||||
def printer_enabled_p(printer):
|
||||
"""Internal utility to see if printer (or subprinter) is enabled."""
|
||||
if hasattr(printer, "enabled"):
|
||||
return printer.enabled
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class InfoPrettyPrinter(gdb.Command):
|
||||
"""GDB command to list all registered pretty-printers.
|
||||
|
||||
Usage: info pretty-printer [object-regexp [name-regexp]]
|
||||
|
||||
OBJECT-REGEXP is a regular expression matching the objects to list.
|
||||
Objects are "global", the program space's file, and the objfiles within
|
||||
that program space.
|
||||
|
||||
NAME-REGEXP matches the name of the pretty-printer.
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
"""
|
||||
|
||||
def __init__ (self):
|
||||
super(InfoPrettyPrinter, self).__init__("info pretty-printer",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
@staticmethod
|
||||
def enabled_string(printer):
|
||||
"""Return "" if PRINTER is enabled, otherwise " [disabled]"."""
|
||||
if printer_enabled_p(printer):
|
||||
return ""
|
||||
else:
|
||||
return " [disabled]"
|
||||
|
||||
@staticmethod
|
||||
def printer_name(printer):
|
||||
"""Return the printer's name."""
|
||||
if hasattr(printer, "name"):
|
||||
return printer.name
|
||||
if hasattr(printer, "__name__"):
|
||||
return printer.__name__
|
||||
# This "shouldn't happen", but the public API allows for
|
||||
# direct additions to the pretty-printer list, and we shouldn't
|
||||
# crash because someone added a bogus printer.
|
||||
# Plus we want to give the user a way to list unknown printers.
|
||||
return "unknown"
|
||||
|
||||
def list_pretty_printers(self, pretty_printers, name_re, subname_re):
|
||||
"""Print a list of pretty-printers."""
|
||||
# A potential enhancement is to provide an option to list printers in
|
||||
# "lookup order" (i.e. unsorted).
|
||||
sorted_pretty_printers = copy.copy(pretty_printers)
|
||||
sorted_pretty_printers.sort(lambda x, y:
|
||||
cmp(self.printer_name(x),
|
||||
self.printer_name(y)))
|
||||
for printer in sorted_pretty_printers:
|
||||
name = self.printer_name(printer)
|
||||
enabled = self.enabled_string(printer)
|
||||
if name_re.match(name):
|
||||
print " %s%s" % (name, enabled)
|
||||
if (hasattr(printer, "subprinters") and
|
||||
printer.subprinters is not None):
|
||||
sorted_subprinters = copy.copy(printer.subprinters)
|
||||
sorted_subprinters.sort(lambda x, y:
|
||||
cmp(self.printer_name(x),
|
||||
self.printer_name(y)))
|
||||
for subprinter in sorted_subprinters:
|
||||
if (not subname_re or
|
||||
subname_re.match(subprinter.name)):
|
||||
print (" %s%s" %
|
||||
(subprinter.name,
|
||||
self.enabled_string(subprinter)))
|
||||
|
||||
def invoke1(self, title, printer_list,
|
||||
obj_name_to_match, object_re, name_re, subname_re):
|
||||
""""Subroutine of invoke to simplify it."""
|
||||
if printer_list and object_re.match(obj_name_to_match):
|
||||
print title
|
||||
self.list_pretty_printers(printer_list, name_re, subname_re)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
(object_re, name_re, subname_re) = parse_printer_regexps(arg)
|
||||
self.invoke1("global pretty-printers:", gdb.pretty_printers,
|
||||
"global", object_re, name_re, subname_re)
|
||||
cp = gdb.current_progspace()
|
||||
self.invoke1("progspace %s pretty-printers:" % cp.filename,
|
||||
cp.pretty_printers, "progspace",
|
||||
object_re, name_re, subname_re)
|
||||
for objfile in gdb.objfiles():
|
||||
self.invoke1(" objfile %s pretty-printers:" % objfile.filename,
|
||||
objfile.pretty_printers, objfile.filename,
|
||||
object_re, name_re, subname_re)
|
||||
|
||||
|
||||
def count_enabled_printers(pretty_printers):
|
||||
"""Return a 2-tuple of number of enabled and total printers."""
|
||||
enabled = 0
|
||||
total = 0
|
||||
for printer in pretty_printers:
|
||||
if (hasattr(printer, "subprinters")
|
||||
and printer.subprinters is not None):
|
||||
if printer_enabled_p(printer):
|
||||
for subprinter in printer.subprinters:
|
||||
if printer_enabled_p(subprinter):
|
||||
enabled += 1
|
||||
total += len(printer.subprinters)
|
||||
else:
|
||||
if printer_enabled_p(printer):
|
||||
enabled += 1
|
||||
total += 1
|
||||
return (enabled, total)
|
||||
|
||||
|
||||
def count_all_enabled_printers():
|
||||
"""Return a 2-tuble of the enabled state and total number of all printers.
|
||||
This includes subprinters.
|
||||
"""
|
||||
enabled_count = 0
|
||||
total_count = 0
|
||||
(t_enabled, t_total) = count_enabled_printers(gdb.pretty_printers)
|
||||
enabled_count += t_enabled
|
||||
total_count += t_total
|
||||
(t_enabled, t_total) = count_enabled_printers(gdb.current_progspace().pretty_printers)
|
||||
enabled_count += t_enabled
|
||||
total_count += t_total
|
||||
for objfile in gdb.objfiles():
|
||||
(t_enabled, t_total) = count_enabled_printers(objfile.pretty_printers)
|
||||
enabled_count += t_enabled
|
||||
total_count += t_total
|
||||
return (enabled_count, total_count)
|
||||
|
||||
|
||||
def pluralize(text, n, suffix="s"):
|
||||
"""Return TEXT pluralized if N != 1."""
|
||||
if n != 1:
|
||||
return "%s%s" % (text, suffix)
|
||||
else:
|
||||
return text
|
||||
|
||||
|
||||
def show_pretty_printer_enabled_summary():
|
||||
"""Print the number of printers enabled/disabled.
|
||||
We count subprinters individually.
|
||||
"""
|
||||
(enabled_count, total_count) = count_all_enabled_printers()
|
||||
print "%d of %d printers enabled" % (enabled_count, total_count)
|
||||
|
||||
|
||||
def do_enable_pretty_printer_1 (pretty_printers, name_re, subname_re, flag):
|
||||
"""Worker for enabling/disabling pretty-printers.
|
||||
|
||||
Arguments:
|
||||
pretty_printers: list of pretty-printers
|
||||
name_re: regular-expression object to select printers
|
||||
subname_re: regular expression object to select subprinters or None
|
||||
if all are affected
|
||||
flag: True for Enable, False for Disable
|
||||
|
||||
Returns:
|
||||
The number of printers affected.
|
||||
This is just for informational purposes for the user.
|
||||
"""
|
||||
total = 0
|
||||
for printer in pretty_printers:
|
||||
if (hasattr(printer, "name") and name_re.match(printer.name) or
|
||||
hasattr(printer, "__name__") and name_re.match(printer.__name__)):
|
||||
if hasattr(printer, "subprinters"):
|
||||
if not subname_re:
|
||||
# Only record printers that change state.
|
||||
if printer_enabled_p(printer) != flag:
|
||||
for subprinter in printer.subprinters:
|
||||
if printer_enabled_p(subprinter):
|
||||
total += 1
|
||||
# NOTE: We preserve individual subprinter settings.
|
||||
printer.enabled = flag
|
||||
else:
|
||||
# NOTE: Whether this actually disables the subprinter
|
||||
# depends on whether the printer's lookup function supports
|
||||
# the "enable" API. We can only assume it does.
|
||||
for subprinter in printer.subprinters:
|
||||
if subname_re.match(subprinter.name):
|
||||
# Only record printers that change state.
|
||||
if (printer_enabled_p(printer) and
|
||||
printer_enabled_p(subprinter) != flag):
|
||||
total += 1
|
||||
subprinter.enabled = flag
|
||||
else:
|
||||
# This printer has no subprinters.
|
||||
# If the user does "disable pretty-printer .* .* foo"
|
||||
# should we disable printers that don't have subprinters?
|
||||
# How do we apply "foo" in this context? Since there is no
|
||||
# "foo" subprinter it feels like we should skip this printer.
|
||||
# There's still the issue of how to handle
|
||||
# "disable pretty-printer .* .* .*", and every other variation
|
||||
# that can match everything. For now punt and only support
|
||||
# "disable pretty-printer .* .*" (i.e. subname is elided)
|
||||
# to disable everything.
|
||||
if not subname_re:
|
||||
# Only record printers that change state.
|
||||
if printer_enabled_p(printer) != flag:
|
||||
total += 1
|
||||
printer.enabled = flag
|
||||
return total
|
||||
|
||||
|
||||
def do_enable_pretty_printer (arg, flag):
|
||||
"""Internal worker for enabling/disabling pretty-printers."""
|
||||
(object_re, name_re, subname_re) = parse_printer_regexps(arg)
|
||||
|
||||
total = 0
|
||||
if object_re.match("global"):
|
||||
total += do_enable_pretty_printer_1(gdb.pretty_printers,
|
||||
name_re, subname_re, flag)
|
||||
cp = gdb.current_progspace()
|
||||
if object_re.match("progspace"):
|
||||
total += do_enable_pretty_printer_1(cp.pretty_printers,
|
||||
name_re, subname_re, flag)
|
||||
for objfile in gdb.objfiles():
|
||||
if object_re.match(objfile.filename):
|
||||
total += do_enable_pretty_printer_1(objfile.pretty_printers,
|
||||
name_re, subname_re, flag)
|
||||
|
||||
if flag:
|
||||
state = "enabled"
|
||||
else:
|
||||
state = "disabled"
|
||||
print "%d %s %s" % (total, pluralize("printer", total), state)
|
||||
|
||||
# Print the total list of printers currently enabled/disabled.
|
||||
# This is to further assist the user in determining whether the result
|
||||
# is expected. Since we use regexps to select it's useful.
|
||||
show_pretty_printer_enabled_summary()
|
||||
|
||||
|
||||
# Enable/Disable one or more pretty-printers.
|
||||
#
|
||||
# This is intended for use when a broken pretty-printer is shipped/installed
|
||||
# and the user wants to disable that printer without disabling all the other
|
||||
# printers.
|
||||
#
|
||||
# A useful addition would be -v (verbose) to show each printer affected.
|
||||
|
||||
class EnablePrettyPrinter (gdb.Command):
|
||||
"""GDB command to enable the specified pretty-printer.
|
||||
|
||||
Usage: enable pretty-printer [object-regexp [name-regexp]]
|
||||
|
||||
OBJECT-REGEXP is a regular expression matching the objects to examine.
|
||||
Objects are "global", the program space's file, and the objfiles within
|
||||
that program space.
|
||||
|
||||
NAME-REGEXP matches the name of the pretty-printer.
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(EnablePrettyPrinter, self).__init__("enable pretty-printer",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
do_enable_pretty_printer(arg, True)
|
||||
|
||||
|
||||
class DisablePrettyPrinter (gdb.Command):
|
||||
"""GDB command to disable the specified pretty-printer.
|
||||
|
||||
Usage: disable pretty-printer [object-regexp [name-regexp]]
|
||||
|
||||
OBJECT-REGEXP is a regular expression matching the objects to examine.
|
||||
Objects are "global", the program space's file, and the objfiles within
|
||||
that program space.
|
||||
|
||||
NAME-REGEXP matches the name of the pretty-printer.
|
||||
Individual printers in a collection are named as
|
||||
printer-name:subprinter-name.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(DisablePrettyPrinter, self).__init__("disable pretty-printer",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""GDB calls this to perform the command."""
|
||||
do_enable_pretty_printer(arg, False)
|
||||
|
||||
|
||||
def register_pretty_printer_commands():
|
||||
"""Call from a top level script to install the pretty-printer commands."""
|
||||
InfoPrettyPrinter()
|
||||
EnablePrettyPrinter()
|
||||
DisablePrettyPrinter()
|
197
gdb/python/lib/gdb/printing.py
Normal file
197
gdb/python/lib/gdb/printing.py
Normal file
|
@ -0,0 +1,197 @@
|
|||
# Pretty-printer utilities.
|
||||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Utilities for working with pretty-printers."""
|
||||
|
||||
import gdb
|
||||
import gdb.types
|
||||
import re
|
||||
|
||||
|
||||
class PrettyPrinter(object):
|
||||
"""A basic pretty-printer.
|
||||
|
||||
Attributes:
|
||||
name: A unique string among all printers for the context in which
|
||||
it is defined (objfile, progspace, or global(gdb)), and should
|
||||
meaningfully describe what can be pretty-printed.
|
||||
E.g., "StringPiece" or "protobufs".
|
||||
subprinters: An iterable object with each element having a `name'
|
||||
attribute, and, potentially, "enabled" attribute.
|
||||
Or this is None if there are no subprinters.
|
||||
enabled: A boolean indicating if the printer is enabled.
|
||||
|
||||
Subprinters are for situations where "one" pretty-printer is actually a
|
||||
collection of several printers. E.g., The libstdc++ pretty-printer has
|
||||
a pretty-printer for each of several different types, based on regexps.
|
||||
"""
|
||||
|
||||
# While one might want to push subprinters into the subclass, it's
|
||||
# present here to formalize such support to simplify
|
||||
# commands/pretty_printers.py.
|
||||
|
||||
def __init__(self, name, subprinters=None):
|
||||
self.name = name
|
||||
self.subprinters = subprinters
|
||||
self.enabled = True
|
||||
|
||||
def __call__(self, val):
|
||||
# The subclass must define this.
|
||||
raise NotImplementedError("PrettyPrinter __call__")
|
||||
|
||||
|
||||
class SubPrettyPrinter(object):
|
||||
"""Baseclass for sub-pretty-printers.
|
||||
|
||||
Sub-pretty-printers needn't use this, but it formalizes what's needed.
|
||||
|
||||
Attributes:
|
||||
name: The name of the subprinter.
|
||||
enabled: A boolean indicating if the subprinter is enabled.
|
||||
"""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.enabled = True
|
||||
|
||||
|
||||
def register_pretty_printer(obj, printer):
|
||||
"""Register pretty-printer PRINTER with OBJ.
|
||||
|
||||
The printer is added to the front of the search list, thus one can override
|
||||
an existing printer if one needs to.
|
||||
|
||||
Arguments:
|
||||
obj: Either an objfile, progspace, or None (in which case the printer
|
||||
is registered globally).
|
||||
printer: Either a function of one argument (old way) or any object
|
||||
which has attributes: name, enabled, __call__.
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
|
||||
Raises:
|
||||
TypeError: A problem with the type of the printer.
|
||||
ValueError: The printer's name contains a colon ":".
|
||||
|
||||
If the caller wants the printer to be listable and disableable, it must
|
||||
follow the PrettyPrinter API. This applies to the old way (functions) too.
|
||||
If printer is an object, __call__ is a method of two arguments:
|
||||
self, and the value to be pretty-printed. See PrettyPrinter.
|
||||
"""
|
||||
|
||||
# Watch for both __name__ and name.
|
||||
# Functions get the former for free, but we don't want to use an
|
||||
# attribute named __foo__ for pretty-printers-as-objects.
|
||||
# If printer has both, we use `name'.
|
||||
if not hasattr(printer, "__name__") and not hasattr(printer, "name"):
|
||||
raise TypeError("printer missing attribute: name")
|
||||
if hasattr(printer, "name") and not hasattr(printer, "enabled"):
|
||||
raise TypeError("printer missing attribute: enabled")
|
||||
if not hasattr(printer, "__call__"):
|
||||
raise TypeError("printer missing attribute: __call__")
|
||||
|
||||
if obj is None:
|
||||
if gdb.parameter("verbose"):
|
||||
gdb.write("Registering global %s pretty-printer ...\n" % name)
|
||||
obj = gdb
|
||||
else:
|
||||
if gdb.parameter("verbose"):
|
||||
gdb.write("Registering %s pretty-printer for %s ...\n" %
|
||||
(printer.name, obj.filename))
|
||||
|
||||
if hasattr(printer, "name"):
|
||||
if not isinstance(printer.name, basestring):
|
||||
raise TypeError("printer name is not a string")
|
||||
# If printer provides a name, make sure it doesn't contain ":".
|
||||
# Colon is used by the info/enable/disable pretty-printer commands
|
||||
# to delimit subprinters.
|
||||
if printer.name.find(":") >= 0:
|
||||
raise ValueError("colon ':' in printer name")
|
||||
# Also make sure the name is unique.
|
||||
# Alas, we can't do the same for functions and __name__, they could
|
||||
# all have a canonical name like "lookup_function".
|
||||
# PERF: gdb records printers in a list, making this inefficient.
|
||||
if (printer.name in
|
||||
[p.name for p in obj.pretty_printers if hasattr(p, "name")]):
|
||||
raise RuntimeError("pretty-printer already registered: %s" %
|
||||
printer.name)
|
||||
|
||||
obj.pretty_printers.insert(0, printer)
|
||||
|
||||
|
||||
class RegexpCollectionPrettyPrinter(PrettyPrinter):
|
||||
"""Class for implementing a collection of regular-expression based pretty-printers.
|
||||
|
||||
Intended usage:
|
||||
|
||||
pretty_printer = RegexpCollectionPrettyPrinter("my_library")
|
||||
pretty_printer.add_printer("myclass1", "^myclass1$", MyClass1Printer)
|
||||
...
|
||||
pretty_printer.add_printer("myclassN", "^myclassN$", MyClassNPrinter)
|
||||
register_pretty_printer(obj, pretty_printer)
|
||||
"""
|
||||
|
||||
class RegexpSubprinter(SubPrettyPrinter):
|
||||
def __init__(self, name, regexp, gen_printer):
|
||||
super(RegexpCollectionPrettyPrinter.RegexpSubprinter, self).__init__(name)
|
||||
self.regexp = regexp
|
||||
self.gen_printer = gen_printer
|
||||
self.compiled_re = re.compile(regexp)
|
||||
|
||||
def __init__(self, name):
|
||||
super(RegexpCollectionPrettyPrinter, self).__init__(name, [])
|
||||
|
||||
def add_printer(self, name, regexp, gen_printer):
|
||||
"""Add a printer to the list.
|
||||
|
||||
The printer is added to the end of the list.
|
||||
|
||||
Arguments:
|
||||
name: The name of the subprinter.
|
||||
regexp: The regular expression, as a string.
|
||||
gen_printer: A function/method that given a value returns an
|
||||
object to pretty-print it.
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
"""
|
||||
|
||||
# NOTE: A previous version made the name of each printer the regexp.
|
||||
# That makes it awkward to pass to the enable/disable commands (it's
|
||||
# cumbersome to make a regexp of a regexp). So now the name is a
|
||||
# separate parameter.
|
||||
|
||||
self.subprinters.append(self.RegexpSubprinter(name, regexp,
|
||||
gen_printer))
|
||||
|
||||
def __call__(self, val):
|
||||
"""Lookup the pretty-printer for the provided value."""
|
||||
|
||||
# Get the type name.
|
||||
typename = gdb.types.get_basic_type(val.type).tag
|
||||
if not typename:
|
||||
return None
|
||||
|
||||
# Iterate over table of type regexps to determine
|
||||
# if a printer is registered for that type.
|
||||
# Return an instantiation of the printer if found.
|
||||
for printer in self.subprinters:
|
||||
if printer.enabled and printer.compiled_re.search(typename):
|
||||
return printer.gen_printer(val)
|
||||
|
||||
# Cannot find a pretty printer. Return None.
|
||||
return None
|
|
@ -1,3 +1,9 @@
|
|||
2010-11-02 Doug Evans <dje@google.com>
|
||||
|
||||
* gdb.python/py-pp-maint.c: New file.
|
||||
* gdb.python/py-pp-maint.exp: New file.
|
||||
* gdb.python/py-pp-maint.py: New file.
|
||||
|
||||
2010-11-02 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* gdb.base/default.exp: Remove "scheme" from language list.
|
||||
|
|
68
gdb/testsuite/gdb.python/py-pp-maint.c
Normal file
68
gdb/testsuite/gdb.python/py-pp-maint.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2010 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct function_lookup_test
|
||||
{
|
||||
int x,y;
|
||||
};
|
||||
|
||||
void
|
||||
init_flt (struct function_lookup_test *p, int x, int y)
|
||||
{
|
||||
p->x = x;
|
||||
p->y = y;
|
||||
}
|
||||
|
||||
struct s
|
||||
{
|
||||
int a;
|
||||
int *b;
|
||||
};
|
||||
|
||||
struct ss
|
||||
{
|
||||
struct s a;
|
||||
struct s b;
|
||||
};
|
||||
|
||||
void
|
||||
init_s (struct s *s, int a)
|
||||
{
|
||||
s->a = a;
|
||||
s->b = &s->a;
|
||||
}
|
||||
|
||||
void
|
||||
init_ss (struct ss *s, int a, int b)
|
||||
{
|
||||
init_s (&s->a, a);
|
||||
init_s (&s->b, b);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
struct function_lookup_test flt;
|
||||
struct ss ss;
|
||||
|
||||
init_flt (&flt, 42, 43);
|
||||
init_ss (&ss, 1, 2);
|
||||
|
||||
return 0; /* break to inspect */
|
||||
}
|
126
gdb/testsuite/gdb.python/py-pp-maint.exp
Normal file
126
gdb/testsuite/gdb.python/py-pp-maint.exp
Normal file
|
@ -0,0 +1,126 @@
|
|||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This file is part of the GDB testsuite. It tests Python-based
|
||||
# pretty-printing for the CLI.
|
||||
|
||||
if $tracelevel then {
|
||||
strace $tracelevel
|
||||
}
|
||||
|
||||
if [is_remote host] {
|
||||
untested "py-pp-maint.exp can only be run locally"
|
||||
return -1
|
||||
}
|
||||
|
||||
load_lib gdb-python.exp
|
||||
|
||||
set testfile "py-pp-maint"
|
||||
set srcfile ${testfile}.c
|
||||
set binfile ${objdir}/${subdir}/${testfile}
|
||||
|
||||
# Start with a fresh gdb.
|
||||
gdb_exit
|
||||
gdb_start
|
||||
|
||||
# Skip all tests if Python scripting is not enabled.
|
||||
if { [skip_python_tests] } { continue }
|
||||
|
||||
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug"] != "" } {
|
||||
untested "Couldn't compile ${srcfile}"
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_reinitialize_dir $srcdir/$subdir
|
||||
gdb_load ${binfile}
|
||||
|
||||
if ![runto_main ] then {
|
||||
fail "Can't run to main"
|
||||
return -1
|
||||
}
|
||||
|
||||
# Ensure sys.path, et.al. are initialized properly.
|
||||
gdb_check_python_config
|
||||
|
||||
gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \
|
||||
".*Breakpoint.*"
|
||||
gdb_test "continue" ".*Breakpoint.*"
|
||||
|
||||
set python_file ${srcdir}/${subdir}/${testfile}.py
|
||||
|
||||
gdb_test_no_output "python execfile ('${python_file}')" ""
|
||||
|
||||
gdb_test "info pretty-printer" \
|
||||
{.*function_lookup_test.*pp-test.*struct ss.*}
|
||||
|
||||
gdb_test "info pretty-printer global .*function" \
|
||||
{.*function_lookup_test.*}
|
||||
|
||||
gdb_test "info pretty-printer .* pp-test" \
|
||||
{.*pp-test.*struct ss.*}
|
||||
|
||||
gdb_test "print flt" " = x=<42> y=<43>" \
|
||||
"print flt enabled #1"
|
||||
|
||||
gdb_test "print ss" " = a=<a=<1> b=<$hex>> b=<a=<2> b=<$hex>>" \
|
||||
"print ss enabled #1"
|
||||
|
||||
gdb_test "disable pretty-printer" \
|
||||
"5 printers disabled.*0 of 5 printers enabled"
|
||||
|
||||
gdb_test "disable pretty-printer global" \
|
||||
"0 printers disabled.*0 of 5 printers enabled"
|
||||
|
||||
gdb_test "disable pretty-printer global lookup_function_lookup_test" \
|
||||
"0 printers disabled.*0 of 5 printers enabled"
|
||||
|
||||
gdb_test "disable pretty-printer global pp-test:.*" \
|
||||
"0 printers disabled.*0 of 5 printers enabled"
|
||||
|
||||
gdb_test "info pretty-printer global .*function" \
|
||||
{.*function_lookup_test \[disabled\].*}
|
||||
|
||||
gdb_test "info pretty-printer .* pp-test" \
|
||||
{.*pp-test.*struct ss \[disabled\].*}
|
||||
|
||||
gdb_test "print flt" " = {x = 42, y = 43}" \
|
||||
"print flt disabled"
|
||||
|
||||
gdb_test "print ss" " = {a = {a = 1, b = $hex}, b = {a = 2, b = $hex}}" \
|
||||
"print ss disabled"
|
||||
|
||||
gdb_test "enable pretty-printer global lookup_function_lookup_test" \
|
||||
"1 printer enabled.*1 of 5 printers enabled"
|
||||
|
||||
# This doesn't enable any printers because each subprinter in the collection
|
||||
# is still individually disabled. But this is still needed, to enable the
|
||||
# collection itself.
|
||||
gdb_test "enable pretty-printer global pp-test" \
|
||||
"0 printers enabled.*1 of 5 printers enabled"
|
||||
|
||||
gdb_test "enable pretty-printer global pp-test:.*ss.*" \
|
||||
"2 printers enabled.*3 of 5 printers enabled"
|
||||
|
||||
gdb_test "enable pretty-printer global pp-test:.*s.*" \
|
||||
"2 printers enabled.*5 of 5 printers enabled"
|
||||
|
||||
gdb_test "info pretty-printer" \
|
||||
{.*function_lookup_test.*pp-test.*struct ss.*}
|
||||
|
||||
gdb_test "print flt" " = x=<42> y=<43>" \
|
||||
"print flt re-enabled"
|
||||
|
||||
gdb_test "print ss" " = a=<a=<1> b=<$hex>> b=<a=<2> b=<$hex>>" \
|
||||
"print ss re-enabled"
|
74
gdb/testsuite/gdb.python/py-pp-maint.py
Normal file
74
gdb/testsuite/gdb.python/py-pp-maint.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
# Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This file is part of the GDB testsuite. It tests python pretty
|
||||
# printers.
|
||||
|
||||
import re
|
||||
import gdb.types
|
||||
import gdb.printing
|
||||
|
||||
|
||||
def lookup_function_lookup_test(val):
|
||||
class PrintFunctionLookup(object):
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
return ("x=<" + str(self.val["x"]) +
|
||||
"> y=<" + str(self.val["y"]) + ">")
|
||||
|
||||
typename = gdb.types.get_basic_type(val.type).tag
|
||||
# Note: typename could be None.
|
||||
if typename == "function_lookup_test":
|
||||
return PrintFunctionLookup(val)
|
||||
return None
|
||||
|
||||
|
||||
class pp_s:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
a = self.val["a"]
|
||||
b = self.val["b"]
|
||||
if a.address != b:
|
||||
raise Exception("&a(%s) != b(%s)" % (str(a.address), str(b)))
|
||||
return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">"
|
||||
|
||||
|
||||
class pp_ss:
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
return "a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">"
|
||||
|
||||
|
||||
def build_pretty_printer():
|
||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("pp-test")
|
||||
|
||||
pp.add_printer('struct s', '^struct s$', pp_s)
|
||||
pp.add_printer('s', '^s$', pp_s)
|
||||
|
||||
# Use a lambda this time to exercise doing things this way.
|
||||
pp.add_printer('struct ss', '^struct ss$', lambda val: pp_ss(val))
|
||||
pp.add_printer('ss', '^ss$', lambda val: pp_ss(val))
|
||||
|
||||
return pp
|
||||
|
||||
|
||||
gdb.printing.register_pretty_printer(gdb, lookup_function_lookup_test)
|
||||
gdb.printing.register_pretty_printer(gdb, build_pretty_printer())
|
Loading…
Reference in a new issue