2009-05-27  Tom Tromey  <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Phil Muldoon  <pmuldoon@redhat.com>
	    Paul Pluzhnikov  <ppluzhnikov@google.com>
	    Vladimir Prus  <vladimir@codesourcery.com>

	* python/python-value.c (value_object_to_value): New function.
	* python/python-internal.h: Include frameobject.h.
	(gdbpy_children_cst, gdbpy_to_string_cst, gdbpy_display_hint_cst):
	Declare.
	(value_object_to_value): Declare.
	* printcmd.c (struct format_data) <raw>: New field.
	(last_format): Default to 0.
	(decode_format): Initialize val.raw.  Handle /r flag.
	(print_command_1): Initialize fmt.raw and opts.raw.
	(output_command): Likewise.
	(x_command): Fix initialization of fmt.format.  Initialize
	fmt.raw.
	(display_command): Initialize fmt.raw.
	(do_one_display): Set opts.raw.
	* python/python.c (gdbpy_to_string_cst, gdbpy_children_cst,
	gdbpy_display_hint_cst): New globals.
	(_initialize_python): Initialize them.  Set gdb.pretty_printers.
	* cp-valprint.c: Include python.h.
	(cp_print_value): Call apply_val_pretty_printer.
	* python/python.h (apply_val_pretty_printer): Declare.
	* stack.c (print_this_frame_argument_p): Remove.
	(print_frame_args): Compute summary flag.  Don't use
	print_this_frame_argument_p.
	* valprint.c: Include python.h.
	(user_print_options): Initialize new fields.
	(scalar_type_p): New function.
	(val_print): Handle 'raw' and 'summary' modes.  Call
	apply_val_pretty_printer.
	(value_print): Handle 'raw' mode.
	* valprint.h (struct value_print_options) <raw, summary>: New
	fields.
	* Makefile.in (SUBDIR_PYTHON_OBS): Add python-prettyprint.o
	(SUBDIR_PYTHON_SRCS): Add python-prettyprint.c.
	(python-prettyprint.o): New target.
	* python/python-prettyprint.c: New file.

gdb/doc

2009-05-27  Tom Tromey  <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Phil Muldoon  <pmuldoon@redhat.com>

	* gdb.texinfo (Objfiles In Python): Reference pretty printing.
	(Pretty Printing): New node.
	(Selecting Pretty-Printers): Likewise.
	(Python API): Update.
	(Output Formats): Document /r format.

gdb/testsuite

2009-05-27  Tom Tromey  <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
	    Phil Muldoon  <pmuldoon@redhat.com>
	    Paul Pluzhnikov  <ppluzhnikov@google.com>

	* gdb.python/python-prettyprint.exp: New file.
	* gdb.python/python-prettyprint.c: New file.
	* gdb.python/python-prettyprint.py: New file.
	* gdb.base/display.exp: print/r is now valid.
This commit is contained in:
Tom Tromey 2009-05-28 01:05:14 +00:00
parent 42ae523077
commit a6bac58e84
19 changed files with 1399 additions and 55 deletions

View file

@ -1,3 +1,45 @@
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>
Paul Pluzhnikov <ppluzhnikov@google.com>
Vladimir Prus <vladimir@codesourcery.com>
* python/python-value.c (value_object_to_value): New function.
* python/python-internal.h: Include frameobject.h.
(gdbpy_children_cst, gdbpy_to_string_cst, gdbpy_display_hint_cst):
Declare.
(value_object_to_value): Declare.
* printcmd.c (struct format_data) <raw>: New field.
(last_format): Default to 0.
(decode_format): Initialize val.raw. Handle /r flag.
(print_command_1): Initialize fmt.raw and opts.raw.
(output_command): Likewise.
(x_command): Fix initialization of fmt.format. Initialize
fmt.raw.
(display_command): Initialize fmt.raw.
(do_one_display): Set opts.raw.
* python/python.c (gdbpy_to_string_cst, gdbpy_children_cst,
gdbpy_display_hint_cst): New globals.
(_initialize_python): Initialize them. Set gdb.pretty_printers.
* cp-valprint.c: Include python.h.
(cp_print_value): Call apply_val_pretty_printer.
* python/python.h (apply_val_pretty_printer): Declare.
* stack.c (print_this_frame_argument_p): Remove.
(print_frame_args): Compute summary flag. Don't use
print_this_frame_argument_p.
* valprint.c: Include python.h.
(user_print_options): Initialize new fields.
(scalar_type_p): New function.
(val_print): Handle 'raw' and 'summary' modes. Call
apply_val_pretty_printer.
(value_print): Handle 'raw' mode.
* valprint.h (struct value_print_options) <raw, summary>: New
fields.
* Makefile.in (SUBDIR_PYTHON_OBS): Add python-prettyprint.o
(SUBDIR_PYTHON_SRCS): Add python-prettyprint.c.
(python-prettyprint.o): New target.
* python/python-prettyprint.c: New file.
2009-05-27 Tom Tromey <tromey@redhat.com> 2009-05-27 Tom Tromey <tromey@redhat.com>
Paul Pluzhnikov <ppluzhnikov@google.com> Paul Pluzhnikov <ppluzhnikov@google.com>

View file

@ -268,6 +268,7 @@ SUBDIR_PYTHON_OBS = \
python-frame.o \ python-frame.o \
python-function.o \ python-function.o \
python-objfile.o \ python-objfile.o \
python-prettyprint.o \
python-type.o \ python-type.o \
python-utils.o \ python-utils.o \
python-value.o python-value.o
@ -277,6 +278,7 @@ SUBDIR_PYTHON_SRCS = \
python/python-frame.c \ python/python-frame.c \
python/python-function.c \ python/python-function.c \
python/python-objfile.c \ python/python-objfile.c \
python/python-prettyprint.c \
python/python-type.c \ python/python-type.c \
python/python-utils.c \ python/python-utils.c \
python/python-value.c python/python-value.c
@ -1872,6 +1874,10 @@ python-objfile.o: $(srcdir)/python/python-objfile.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c
$(POSTCOMPILE) $(POSTCOMPILE)
python-prettyprint.o: $(srcdir)/python/python-prettyprint.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-prettyprint.c
$(POSTCOMPILE)
python-type.o: $(srcdir)/python/python-type.c python-type.o: $(srcdir)/python/python-type.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c
$(POSTCOMPILE) $(POSTCOMPILE)

View file

@ -36,6 +36,7 @@
#include "valprint.h" #include "valprint.h"
#include "cp-support.h" #include "cp-support.h"
#include "language.h" #include "language.h"
#include "python/python.h"
/* Controls printing of vtbl's */ /* Controls printing of vtbl's */
static void static void
@ -418,12 +419,27 @@ cp_print_value (struct type *type, struct type *real_type,
if (skip >= 1) if (skip >= 1)
fprintf_filtered (stream, "<invalid address>"); fprintf_filtered (stream, "<invalid address>");
else else
cp_print_value_fields (baseclass, thistype, base_valaddr, {
thisoffset + boffset, address + boffset, int result = 0;
stream, recurse, options,
((struct type **) /* Attempt to run the Python pretty-printers on the
obstack_base (&dont_print_vb_obstack)), baseclass if possible. */
0); if (!options->raw)
result = apply_val_pretty_printer (baseclass, base_valaddr,
thisoffset + boffset,
address + boffset,
stream, recurse,
options,
current_language);
if (!result)
cp_print_value_fields (baseclass, thistype, base_valaddr,
thisoffset + boffset, address + boffset,
stream, recurse, options,
((struct type **)
obstack_base (&dont_print_vb_obstack)),
0);
}
fputs_filtered (", ", stream); fputs_filtered (", ", stream);
flush_it: flush_it:

View file

@ -1,3 +1,13 @@
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>
* gdb.texinfo (Objfiles In Python): Reference pretty printing.
(Pretty Printing): New node.
(Selecting Pretty-Printers): Likewise.
(Python API): Update.
(Output Formats): Document /r format.
2009-05-27 Thiago Jung Bauermann <bauerman@br.ibm.com> 2009-05-27 Thiago Jung Bauermann <bauerman@br.ibm.com>
Tom Tromey <tromey@redhat.com> Tom Tromey <tromey@redhat.com>

View file

@ -6774,6 +6774,12 @@ Without this format, @value{GDBN} displays pointers to and arrays of
@code{char}, @w{@code{unsigned char}}, and @w{@code{signed char}} as @code{char}, @w{@code{unsigned char}}, and @w{@code{signed char}} as
strings. Single-byte members of a vector are displayed as an integer strings. Single-byte members of a vector are displayed as an integer
array. array.
@item r
@cindex raw printing
Print using the @samp{raw} formatting. By default, @value{GDBN} will
use a type-specific pretty-printer. The @samp{r} format bypasses any
pretty-printer which might exist for the value's type.
@end table @end table
For example, to print the program counter in hex (@pxref{Registers}), type For example, to print the program counter in hex (@pxref{Registers}), type
@ -18517,6 +18523,8 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Auto-loading:: Automatically loading Python code. * Auto-loading:: Automatically loading Python code.
* Values From Inferior:: * Values From Inferior::
* Types In Python:: Python representation of types. * Types In Python:: Python representation of types.
* Pretty Printing:: Pretty-printing values.
* Selecting Pretty-Printers:: How GDB chooses a pretty-printer.
* Commands In Python:: Implementing new commands in Python. * Commands In Python:: Implementing new commands in Python.
* Functions In Python:: Writing new convenience functions. * Functions In Python:: Writing new convenience functions.
* Objfiles In Python:: Object files. * Objfiles In Python:: Object files.
@ -19044,6 +19052,217 @@ A function internal to @value{GDBN}. This is the type used to represent
convenience functions. convenience functions.
@end table @end table
@node Pretty Printing
@subsubsection Pretty Printing
@value{GDBN} provides a mechanism to allow pretty-printing of values
using Python code. The pretty-printer API allows application-specific
code to greatly simplify 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:
@smallexample
(@value{GDBP}) print s
$1 = @{
static npos = 4294967295,
_M_dataplus = @{
<std::allocator<char>> = @{
<__gnu_cxx::new_allocator<char>> = @{<No data fields>@}, <No data fields>@},
members of std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Alloc_hider:
_M_p = 0x804a014 "abcd"
@}
@}
@end smallexample
After a pretty-printer for @code{std::string} has been installed, only
the contents are printed:
@smallexample
(@value{GDBP}) print s
$2 = "abcd"
@end smallexample
A pretty-printer is just an object that holds a value and implements a
specific interface, defined here.
@defop Operation {pretty printer} children (self)
@value{GDBN} will call this method on a pretty-printer to compute the
children of the pretty-printer's value.
This method must return an object conforming to the Python iterator
protocol. Each item returned by the iterator must be a tuple holding
two elements. The first element is the ``name'' of the child; the
second element is the child's value. The value can be any Python
object which is convertible to a @value{GDBN} value.
This method is optional. If it does not exist, @value{GDBN} will act
as though the value has no children.
@end defop
@defop Operation {pretty printer} display_hint (self)
The CLI may call this method and use its result to change the
formatting of a value. The result will also be supplied to an MI
consumer as a @samp{displayhint} attribute of the variable being
printed.
This method is optional. If it does exist, this method must return a
string.
Some display hints are predefined by @value{GDBN}:
@table @samp
@item array
Indicate that the object being printed is ``array-like''. The CLI
uses this to respect parameters such as @code{set print elements} and
@code{set print array}.
@item map
Indicate that the object being printed is ``map-like'', and that the
children of this value can be assumed to alternate between keys and
values.
@item string
Indicate that the object being printed is ``string-like''. If the
printer's @code{to_string} method returns a Python string of some
kind, then @value{GDBN} will call its internal language-specific
string-printing function to format the string. For the CLI this means
adding quotation marks, possibly escaping some characters, respecting
@code{set print elements}, and the like.
@end table
@end defop
@defop Operation {pretty printer} to_string (self)
@value{GDBN} will call this method to display the string
representation of the value passed to the object's constructor.
When printing from the CLI, if the @code{to_string} method exists,
then @value{GDBN} will prepend its result to the values returned by
@code{children}. Exactly how this formatting is done is dependent on
the display hint, and may change as more hints are added. Also,
depending on the print settings (@pxref{Print Settings}), the CLI may
print just the result of @code{to_string} in a stack trace, omitting
the result of @code{children}.
If this method returns a string, it is printed verbatim.
Otherwise, if this method returns an instance of @code{gdb.Value},
then @value{GDBN} prints this value. This may result in a call to
another pretty-printer.
If instead the method returns a Python value which is convertible to a
@code{gdb.Value}, then @value{GDBN} performs the conversion and prints
the resulting value. Again, this may result in a call to another
pretty-printer. Python scalars (integers, floats, and booleans) and
strings are convertible to @code{gdb.Value}; other types are not.
If the result is not one of these types, an exception is raised.
@end defop
@node Selecting Pretty-Printers
@subsubsection Selecting Pretty-Printers
The Python list @code{gdb.pretty_printers} contains an array of
functions that have been registered via addition as a pretty-printer.
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}
argument and should return a pretty-printer object conforming to the
interface definition above (@pxref{Pretty Printing}). If a function
cannot create a pretty-printer for the value, it should return
@code{None}.
@value{GDBN} first checks the @code{pretty_printers} attribute of each
@code{gdb.Objfile} and iteratively calls each function in the list for
that @code{gdb.Objfile} until it receives a pretty-printer object.
After these lists have been exhausted, it tries the global
@code{gdb.pretty-printers} list, again calling each function until an
object is returned.
The order in which the objfiles are searched is not specified. For a
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.
Here is an example showing how a @code{std::string} printer might be
written:
@smallexample
class StdStringPrinter:
"Print a std::string"
def __init__ (self, val):
self.val = val
def to_string (self):
return self.val['_M_dataplus']['_M_p']
def display_hint (self):
return 'string'
@end smallexample
And here is an example showing how a lookup function for the printer
example above might be written.
@smallexample
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)
return None
@end smallexample
The example lookup function extracts the value's type, and attempts to
match it to a type that it can pretty-print. If it is a type the
printer can pretty-print, it will return a printer object. If not, it
returns @code{None}.
We recommend that you put your core pretty-printers into a Python
package. If your pretty-printers are for use with a library, we
further recommend embedding a version number into the package name.
This practice will enable @value{GDBN} to load multiple versions of
your pretty-printers at the same time, because they will have
different names.
You should write auto-loaded code (@pxref{Auto-loading}) such that it
can be evaluated multiple times without changing its meaning. An
ideal auto-load file will consist solely of @code{import}s of your
printer modules, followed by a call to a register pretty-printers with
the current objfile.
Taken as a whole, this approach will scale nicely to multiple
inferiors, each potentially using a different library version.
Embedding a version number in the Python package name will ensure that
@value{GDBN} is able to load both sets of printers simultaneously.
Then, because the search for pretty-printers is done by objfile, and
because your auto-loaded code took care to register your library's
printers with a specific objfile, @value{GDBN} will find the correct
printers for the specific version of the library used by each
inferior.
To continue the @code{std::string} example (@pxref{Pretty Printing}),
this code might appear in @code{gdb.libstdcxx.v6}:
@smallexample
def register_printers (objfile):
objfile.pretty_printers.add (str_lookup_function)
@end smallexample
@noindent
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 ())
@end smallexample
@node Commands In Python @node Commands In Python
@subsubsection Commands In Python @subsubsection Commands In Python
@ -19396,7 +19615,8 @@ The @code{pretty_printers} attribute is a list of functions. It is
used to look up pretty-printers. A @code{Value} is passed to each used to look up pretty-printers. A @code{Value} is passed to each
function in order; if the function returns @code{None}, then the function in order; if the function returns @code{None}, then the
search continues. Otherwise, the return value should be an object search continues. Otherwise, the return value should be an object
which is used to format the value. which is used to format the value. @xref{Pretty Printing}, for more
information.
@end defivar @end defivar
@node Frames In Python @node Frames In Python

View file

@ -68,11 +68,15 @@ struct format_data
int count; int count;
char format; char format;
char size; char size;
/* True if the value should be printed raw -- that is, bypassing
python-based formatters. */
unsigned char raw;
}; };
/* Last specified output format. */ /* Last specified output format. */
static char last_format = 'x'; static char last_format = 0;
/* Last specified examination size. 'b', 'h', 'w' or `q'. */ /* Last specified examination size. 'b', 'h', 'w' or `q'. */
@ -181,6 +185,7 @@ decode_format (char **string_ptr, int oformat, int osize)
val.format = '?'; val.format = '?';
val.size = '?'; val.size = '?';
val.count = 1; val.count = 1;
val.raw = 0;
if (*p >= '0' && *p <= '9') if (*p >= '0' && *p <= '9')
val.count = atoi (p); val.count = atoi (p);
@ -193,6 +198,11 @@ decode_format (char **string_ptr, int oformat, int osize)
{ {
if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
val.size = *p++; val.size = *p++;
else if (*p == 'r')
{
val.raw = 1;
p++;
}
else if (*p >= 'a' && *p <= 'z') else if (*p >= 'a' && *p <= 'z')
val.format = *p++; val.format = *p++;
else else
@ -874,6 +884,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
fmt.count = 1; fmt.count = 1;
fmt.format = 0; fmt.format = 0;
fmt.size = 0; fmt.size = 0;
fmt.raw = 0;
} }
if (exp && *exp) if (exp && *exp)
@ -909,6 +920,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
get_formatted_print_options (&opts, format); get_formatted_print_options (&opts, format);
opts.inspect_it = inspect; opts.inspect_it = inspect;
opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout); print_formatted (val, fmt.size, &opts, gdb_stdout);
printf_filtered ("\n"); printf_filtered ("\n");
@ -959,6 +971,7 @@ output_command (char *exp, int from_tty)
struct value_print_options opts; struct value_print_options opts;
fmt.size = 0; fmt.size = 0;
fmt.raw = 0;
if (exp && *exp == '/') if (exp && *exp == '/')
{ {
@ -976,6 +989,7 @@ output_command (char *exp, int from_tty)
annotate_value_begin (value_type (val)); annotate_value_begin (value_type (val));
get_formatted_print_options (&opts, format); get_formatted_print_options (&opts, format);
opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout); print_formatted (val, fmt.size, &opts, gdb_stdout);
annotate_value_end (); annotate_value_end ();
@ -1296,9 +1310,10 @@ x_command (char *exp, int from_tty)
struct cleanup *old_chain; struct cleanup *old_chain;
struct value *val; struct value *val;
fmt.format = last_format; fmt.format = last_format ? last_format : 'x';
fmt.size = last_size; fmt.size = last_size;
fmt.count = 1; fmt.count = 1;
fmt.raw = 0;
if (exp && *exp == '/') if (exp && *exp == '/')
{ {
@ -1402,6 +1417,7 @@ display_command (char *exp, int from_tty)
fmt.format = 0; fmt.format = 0;
fmt.size = 0; fmt.size = 0;
fmt.count = 0; fmt.count = 0;
fmt.raw = 0;
} }
innermost_block = NULL; innermost_block = NULL;
@ -1613,6 +1629,7 @@ do_one_display (struct display *d)
annotate_display_expression (); annotate_display_expression ();
get_formatted_print_options (&opts, d->format.format); get_formatted_print_options (&opts, d->format.format);
opts.raw = d->format.raw;
print_formatted (evaluate_expression (d->exp), print_formatted (evaluate_expression (d->exp),
d->format.size, &opts, gdb_stdout); d->format.size, &opts, gdb_stdout);
printf_filtered ("\n"); printf_filtered ("\n");

View file

@ -33,6 +33,7 @@
#if HAVE_LIBPYTHON2_4 #if HAVE_LIBPYTHON2_4
#include "python2.4/Python.h" #include "python2.4/Python.h"
#include "python2.4/frameobject.h"
/* Py_ssize_t is not defined until 2.5. /* Py_ssize_t is not defined until 2.5.
Logical type for Py_ssize_t is Py_intptr_t, but that fails in 64-bit Logical type for Py_ssize_t is Py_intptr_t, but that fails in 64-bit
compilation due to several apparent mistakes in python2.4 API, so we compilation due to several apparent mistakes in python2.4 API, so we
@ -40,8 +41,10 @@
typedef int Py_ssize_t; typedef int Py_ssize_t;
#elif HAVE_LIBPYTHON2_5 #elif HAVE_LIBPYTHON2_5
#include "python2.5/Python.h" #include "python2.5/Python.h"
#include "python2.5/frameobject.h"
#elif HAVE_LIBPYTHON2_6 #elif HAVE_LIBPYTHON2_6
#include "python2.6/Python.h" #include "python2.6/Python.h"
#include "python2.6/frameobject.h"
#else #else
#error "Unable to find usable Python.h" #error "Unable to find usable Python.h"
#endif #endif
@ -74,6 +77,7 @@ PyObject *objfile_to_objfile_object (struct objfile *);
PyObject *objfpy_get_printers (PyObject *, void *); PyObject *objfpy_get_printers (PyObject *, void *);
struct value *value_object_to_value (PyObject *self);
struct value *convert_value_from_python (PyObject *obj); struct value *convert_value_from_python (PyObject *obj);
struct type *type_object_to_type (PyObject *obj); struct type *type_object_to_type (PyObject *obj);
@ -108,5 +112,8 @@ PyObject *target_string_to_unicode (const gdb_byte *str, int length);
int gdbpy_is_string (PyObject *obj); int gdbpy_is_string (PyObject *obj);
extern PyObject *gdbpy_doc_cst; extern PyObject *gdbpy_doc_cst;
extern PyObject *gdbpy_children_cst;
extern PyObject *gdbpy_to_string_cst;
extern PyObject *gdbpy_display_hint_cst;
#endif /* GDB_PYTHON_INTERNAL_H */ #endif /* GDB_PYTHON_INTERNAL_H */

View file

@ -0,0 +1,524 @@
/* Python pretty-printing
Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
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 "defs.h"
#include "exceptions.h"
#include "objfiles.h"
#include "symtab.h"
#include "language.h"
#include "valprint.h"
#include "python.h"
#include "python-internal.h"
#ifdef HAVE_PYTHON
/* Helper function for find_pretty_printer which iterates over a list,
calls each function and inspects output. This will return a
printer object if one recognizes VALUE. If no printer is found, it
will return None. On error, it will set the Python error and
return NULL. */
static PyObject *
search_pp_list (PyObject *list, PyObject *value)
{
Py_ssize_t pp_list_size, list_index;
PyObject *function, *printer = NULL;
pp_list_size = PyList_Size (list);
for (list_index = 0; list_index < pp_list_size; list_index++)
{
function = PyList_GetItem (list, list_index);
if (! function)
return NULL;
printer = PyObject_CallFunctionObjArgs (function, value, NULL);
if (! printer)
return NULL;
else if (printer != Py_None)
return printer;
Py_DECREF (printer);
}
Py_RETURN_NONE;
}
/* Find the pretty-printing constructor function for VALUE. If no
pretty-printer exists, return None. If one exists, return a new
reference. On error, set the Python error and return NULL. */
static PyObject *
find_pretty_printer (PyObject *value)
{
PyObject *pp_list = NULL;
PyObject *function = NULL;
struct objfile *obj;
volatile struct gdb_exception except;
/* Look at the pretty-printer dictionary for each objfile. */
ALL_OBJFILES (obj)
{
PyObject *objf = objfile_to_objfile_object (obj);
if (!objf)
{
/* Ignore the error and continue. */
PyErr_Clear ();
continue;
}
pp_list = objfpy_get_printers (objf, NULL);
function = search_pp_list (pp_list, value);
/* If there is an error in any objfile list, abort the search and
exit. */
if (! function)
{
Py_XDECREF (pp_list);
return NULL;
}
if (function != Py_None)
goto done;
Py_DECREF (function);
Py_XDECREF (pp_list);
}
pp_list = NULL;
/* Fetch the global pretty printer dictionary. */
if (! PyObject_HasAttrString (gdb_module, "pretty_printers"))
{
function = Py_None;
Py_INCREF (function);
goto done;
}
pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers");
if (! pp_list)
goto done;
if (! PyList_Check (pp_list))
goto done;
function = search_pp_list (pp_list, value);
done:
Py_XDECREF (pp_list);
return function;
}
/* Pretty-print a single value, via the printer object PRINTER. If
the function returns a string, an xmalloc()d copy is returned.
Otherwise, if the function returns a value, a *OUT_VALUE is set to
the value, and NULL is returned. On error, *OUT_VALUE is set to
NULL and NULL is returned. */
static char *
pretty_print_one_value (PyObject *printer, struct value **out_value)
{
char *output = NULL;
volatile struct gdb_exception except;
TRY_CATCH (except, RETURN_MASK_ALL)
{
PyObject *result;
result = PyObject_CallMethodObjArgs (printer, gdbpy_to_string_cst, NULL);
if (result)
{
if (gdbpy_is_string (result))
output = python_string_to_host_string (result);
else
*out_value = convert_value_from_python (result);
Py_DECREF (result);
}
}
return output;
}
/* Return the display hint for the object printer, PRINTER. Return
NULL if there is no display_hint method, or if the method did not
return a string. On error, print stack trace and return NULL. On
success, return an xmalloc()d string. */
char *
gdbpy_get_display_hint (PyObject *printer)
{
PyObject *hint;
char *result = NULL;
if (! PyObject_HasAttr (printer, gdbpy_display_hint_cst))
return NULL;
hint = PyObject_CallMethodObjArgs (printer, gdbpy_display_hint_cst, NULL);
if (gdbpy_is_string (hint))
result = python_string_to_host_string (hint);
if (hint)
Py_DECREF (hint);
else
gdbpy_print_stack ();
return result;
}
/* Helper for apply_val_pretty_printer which calls to_string and
formats the result. */
static void
print_string_repr (PyObject *printer, const char *hint,
struct ui_file *stream, int recurse,
const struct value_print_options *options,
const struct language_defn *language)
{
char *output;
struct value *replacement = NULL;
output = pretty_print_one_value (printer, &replacement);
if (output)
{
if (hint && !strcmp (hint, "string"))
LA_PRINT_STRING (stream, builtin_type (current_gdbarch)->builtin_char,
(gdb_byte *) output, strlen (output),
0, options);
else
fputs_filtered (output, stream);
xfree (output);
}
else if (replacement)
common_val_print (replacement, stream, recurse, options, language);
else
gdbpy_print_stack ();
}
static void
py_restore_tstate (void *p)
{
PyFrameObject *frame = p;
PyThreadState *tstate = PyThreadState_GET ();
tstate->frame = frame;
}
/* Create a dummy PyFrameObject, needed to work around
a Python-2.4 bug with generators. */
static PyObject *
push_dummy_python_frame ()
{
PyObject *empty_string, *null_tuple, *globals;
PyCodeObject *code;
PyFrameObject *frame;
PyThreadState *tstate;
empty_string = PyString_FromString ("");
if (!empty_string)
return NULL;
null_tuple = PyTuple_New (0);
if (!null_tuple)
{
Py_DECREF (empty_string);
return NULL;
}
code = PyCode_New (0, /* argcount */
0, /* nlocals */
0, /* stacksize */
0, /* flags */
empty_string, /* code */
null_tuple, /* consts */
null_tuple, /* names */
null_tuple, /* varnames */
#if PYTHON_API_VERSION >= 1010
null_tuple, /* freevars */
null_tuple, /* cellvars */
#endif
empty_string, /* filename */
empty_string, /* name */
1, /* firstlineno */
empty_string /* lnotab */
);
Py_DECREF (empty_string);
Py_DECREF (null_tuple);
if (!code)
return NULL;
globals = PyDict_New ();
if (!globals)
{
Py_DECREF (code);
return NULL;
}
tstate = PyThreadState_GET ();
frame = PyFrame_New (tstate, code, globals, NULL);
Py_DECREF (globals);
Py_DECREF (code);
if (!frame)
return NULL;
tstate->frame = frame;
make_cleanup (py_restore_tstate, frame->f_back);
return (PyObject *) frame;
}
/* Helper for apply_val_pretty_printer that formats children of the
printer, if any exist. */
static void
print_children (PyObject *printer, const char *hint,
struct ui_file *stream, int recurse,
const struct value_print_options *options,
const struct language_defn *language)
{
int is_map, is_array, done_flag, pretty;
unsigned int i;
PyObject *children, *iter, *frame;
struct cleanup *cleanups;
if (! PyObject_HasAttr (printer, gdbpy_children_cst))
return;
/* If we are printing a map or an array, we want some special
formatting. */
is_map = hint && ! strcmp (hint, "map");
is_array = hint && ! strcmp (hint, "array");
children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
NULL);
if (! children)
{
gdbpy_print_stack ();
return;
}
cleanups = make_cleanup_py_decref (children);
iter = PyObject_GetIter (children);
if (!iter)
{
gdbpy_print_stack ();
goto done;
}
make_cleanup_py_decref (iter);
/* Use the prettyprint_arrays option if we are printing an array,
and the pretty option otherwise. */
pretty = is_array ? options->prettyprint_arrays : options->pretty;
/* Manufacture a dummy Python frame to work around Python 2.4 bug,
where it insists on having a non-NULL tstate->frame when
a generator is called. */
frame = push_dummy_python_frame ();
if (!frame)
{
gdbpy_print_stack ();
goto done;
}
make_cleanup_py_decref (frame);
done_flag = 0;
for (i = 0; i < options->print_max; ++i)
{
PyObject *py_v, *item = PyIter_Next (iter);
char *name;
struct cleanup *inner_cleanup;
if (! item)
{
if (PyErr_Occurred ())
gdbpy_print_stack ();
/* Set a flag so we can know whether we printed all the
available elements. */
else
done_flag = 1;
break;
}
if (! PyArg_ParseTuple (item, "sO", &name, &py_v))
{
gdbpy_print_stack ();
Py_DECREF (item);
continue;
}
inner_cleanup = make_cleanup_py_decref (item);
/* Print initial "{". For other elements, there are three
cases:
1. Maps. Print a "," after each value element.
2. Arrays. Always print a ",".
3. Other. Always print a ",". */
if (i == 0)
fputs_filtered (" = {", stream);
else if (! is_map || i % 2 == 0)
fputs_filtered (pretty ? "," : ", ", stream);
/* In summary mode, we just want to print "= {...}" if there is
a value. */
if (options->summary)
{
/* This increment tricks the post-loop logic to print what
we want. */
++i;
/* Likewise. */
pretty = 0;
break;
}
if (! is_map || i % 2 == 0)
{
if (pretty)
{
fputs_filtered ("\n", stream);
print_spaces_filtered (2 + 2 * recurse, stream);
}
else
wrap_here (n_spaces (2 + 2 *recurse));
}
if (is_map && i % 2 == 0)
fputs_filtered ("[", stream);
else if (is_array)
{
/* We print the index, not whatever the child method
returned as the name. */
if (options->print_array_indexes)
fprintf_filtered (stream, "[%d] = ", i);
}
else if (! is_map)
{
fputs_filtered (name, stream);
fputs_filtered (" = ", stream);
}
if (gdbpy_is_string (py_v))
{
char *text = python_string_to_host_string (py_v);
if (! text)
gdbpy_print_stack ();
else
{
fputs_filtered (text, stream);
xfree (text);
}
}
else
{
struct value *value = convert_value_from_python (py_v);
if (value == NULL)
{
gdbpy_print_stack ();
error (_("Error while executing Python code."));
}
else
common_val_print (value, stream, recurse + 1, options, language);
}
if (is_map && i % 2 == 0)
fputs_filtered ("] = ", stream);
do_cleanups (inner_cleanup);
}
if (i)
{
if (!done_flag)
{
if (pretty)
{
fputs_filtered ("\n", stream);
print_spaces_filtered (2 + 2 * recurse, stream);
}
fputs_filtered ("...", stream);
}
if (pretty)
{
fputs_filtered ("\n", stream);
print_spaces_filtered (2 * recurse, stream);
}
fputs_filtered ("}", stream);
}
done:
do_cleanups (cleanups);
}
int
apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
const struct value_print_options *options,
const struct language_defn *language)
{
PyObject *printer = NULL;
PyObject *val_obj = NULL;
struct value *value;
char *hint = NULL;
struct cleanup *cleanups;
int result = 0;
PyGILState_STATE state;
state = PyGILState_Ensure ();
cleanups = make_cleanup_py_restore_gil (&state);
/* Instantiate the printer. */
if (valaddr)
valaddr += embedded_offset;
value = value_from_contents_and_address (type, valaddr, address);
val_obj = value_to_value_object (value);
if (! val_obj)
goto done;
/* Find the constructor. */
printer = find_pretty_printer (val_obj);
Py_DECREF (val_obj);
make_cleanup_py_decref (printer);
if (! printer || printer == Py_None)
goto done;
/* If we are printing a map, we want some special formatting. */
hint = gdbpy_get_display_hint (printer);
make_cleanup (free_current_contents, &hint);
/* Print the section */
print_string_repr (printer, hint, stream, recurse, options, language);
print_children (printer, hint, stream, recurse, options, language);
result = 1;
done:
if (PyErr_Occurred ())
gdbpy_print_stack ();
do_cleanups (cleanups);
return result;
}
#else /* HAVE_PYTHON */
int
apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int format,
int deref_ref, int recurse,
enum val_prettyprint pretty,
const struct language_defn *language)
{
return 0;
}
#endif /* HAVE_PYTHON */

View file

@ -805,6 +805,17 @@ value_to_value_object (struct value *val)
return (PyObject *) val_obj; return (PyObject *) val_obj;
} }
/* Returns value structure corresponding to the given value object. */
struct value *
value_object_to_value (PyObject *self)
{
value_object *real;
if (! PyObject_TypeCheck (self, &value_object_type))
return NULL;
real = (value_object *) self;
return real->value;
}
/* Try to convert a Python value to a gdb value. If the value cannot /* Try to convert a Python value to a gdb value. If the value cannot
be converted, set a Python exception and return NULL. */ be converted, set a Python exception and return NULL. */

View file

@ -52,6 +52,10 @@ static PyMethodDef GdbMethods[];
PyObject *gdb_module; PyObject *gdb_module;
/* Some string constants we may wish to use. */
PyObject *gdbpy_to_string_cst;
PyObject *gdbpy_children_cst;
PyObject *gdbpy_display_hint_cst;
PyObject *gdbpy_doc_cst; PyObject *gdbpy_doc_cst;
/* Given a command_line, return a command string suitable for passing /* Given a command_line, return a command string suitable for passing
@ -556,9 +560,13 @@ Enables or disables auto-loading of Python code when an object is opened."),
gdbpy_initialize_objfile (); gdbpy_initialize_objfile ();
PyRun_SimpleString ("import gdb"); PyRun_SimpleString ("import gdb");
PyRun_SimpleString ("gdb.pretty_printers = []");
observer_attach_new_objfile (gdbpy_new_objfile); observer_attach_new_objfile (gdbpy_new_objfile);
gdbpy_to_string_cst = PyString_FromString ("to_string");
gdbpy_children_cst = PyString_FromString ("children");
gdbpy_display_hint_cst = PyString_FromString ("display_hint");
gdbpy_doc_cst = PyString_FromString ("__doc__"); gdbpy_doc_cst = PyString_FromString ("__doc__");
/* Create a couple objects which are used for Python's stdout and /* Create a couple objects which are used for Python's stdout and

View file

@ -26,4 +26,10 @@ extern struct value *values_in_python;
void eval_python_from_control_command (struct command_line *); void eval_python_from_control_command (struct command_line *);
int apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
int embedded_offset, CORE_ADDR address,
struct ui_file *stream, int recurse,
const struct value_print_options *options,
const struct language_defn *language);
#endif /* GDB_PYTHON_H */ #endif /* GDB_PYTHON_H */

View file

@ -158,46 +158,6 @@ print_frame_nameless_args (struct frame_info *frame, long start, int num,
} }
} }
/* Return non-zero if the debugger should print the value of the provided
symbol parameter (SYM). */
static int
print_this_frame_argument_p (struct symbol *sym)
{
struct type *type;
/* If the user asked to print no argument at all, then obviously
do not print this argument. */
if (strcmp (print_frame_arguments, "none") == 0)
return 0;
/* If the user asked to print all arguments, then we should print
that one. */
if (strcmp (print_frame_arguments, "all") == 0)
return 1;
/* The user asked to print only the scalar arguments, so do not
print the non-scalar ones. */
type = check_typedef (SYMBOL_TYPE (sym));
while (TYPE_CODE (type) == TYPE_CODE_REF)
type = check_typedef (TYPE_TARGET_TYPE (type));
switch (TYPE_CODE (type))
{
case TYPE_CODE_ARRAY:
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_SET:
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
return 0;
default:
return 1;
}
}
/* Print the arguments of frame FRAME on STREAM, given the function /* Print the arguments of frame FRAME on STREAM, given the function
FUNC running in that frame (as a symbol), where NUM is the number FUNC running in that frame (as a symbol), where NUM is the number
of arguments according to the stack frame (or -1 if the number of of arguments according to the stack frame (or -1 if the number of
@ -220,6 +180,10 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
int args_printed = 0; int args_printed = 0;
struct cleanup *old_chain, *list_chain; struct cleanup *old_chain, *list_chain;
struct ui_stream *stb; struct ui_stream *stb;
/* True if we should print arguments, false otherwise. */
int print_args = strcmp (print_frame_arguments, "none");
/* True in "summary" mode, false otherwise. */
int summary = !strcmp (print_frame_arguments, "scalars");
stb = ui_out_stream_new (uiout); stb = ui_out_stream_new (uiout);
old_chain = make_cleanup_ui_out_stream_delete (stb); old_chain = make_cleanup_ui_out_stream_delete (stb);
@ -354,7 +318,7 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
annotate_arg_name_end (); annotate_arg_name_end ();
ui_out_text (uiout, "="); ui_out_text (uiout, "=");
if (print_this_frame_argument_p (sym)) if (print_args)
{ {
/* Avoid value_print because it will deref ref parameters. /* Avoid value_print because it will deref ref parameters.
We just want to print their addresses. Print ??? for We just want to print their addresses. Print ??? for
@ -381,8 +345,8 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
get_raw_print_options (&opts); get_raw_print_options (&opts);
opts.deref_ref = 0; opts.deref_ref = 0;
common_val_print (val, stb->stream, 2, opts.summary = summary;
&opts, language); common_val_print (val, stb->stream, 2, &opts, language);
ui_out_field_stream (uiout, "value", stb); ui_out_field_stream (uiout, "value", stb);
} }
else else

View file

@ -1,3 +1,13 @@
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>
Paul Pluzhnikov <ppluzhnikov@google.com>
* gdb.python/python-prettyprint.exp: New file.
* gdb.python/python-prettyprint.c: New file.
* gdb.python/python-prettyprint.py: New file.
* gdb.base/display.exp: print/r is now valid.
2009-05-27 Thiago Jung Bauermann <bauerman@br.ibm.com> 2009-05-27 Thiago Jung Bauermann <bauerman@br.ibm.com>
Tom Tromey <tromey@redhat.com> Tom Tromey <tromey@redhat.com>
Pedro Alves <pedro@codesourcery.com> Pedro Alves <pedro@codesourcery.com>

View file

@ -180,8 +180,12 @@ gdb_test "printf \"%p\\n\", 1" "0x1"
# play with "print", too # play with "print", too
# #
gdb_test "print/r j" ".*Undefined output format.*" gdb_test "print/z j" ".*Undefined output format.*"
gdb_test "print j" ".*" "debug test output" gdb_test "print/d j" " = 0\[\\r\\n\]+" "debug test output 1"
gdb_test "print/r j" " = 0\[\\r\\n\]+" "debug test output 1a"
gdb_test "print/x j" " = 0x0\[\\r\\n\]+" "debug test output 2"
gdb_test "print/r j" " = 0x0\[\\r\\n\]+" "debug test output 2a"
gdb_test "print j" " = 0\[\\r\\n\]+" "debug test output 3"
# x/0 j doesn't produce any output and terminates PA64 process when testing # x/0 j doesn't produce any output and terminates PA64 process when testing
if [istarget "hppa2.0w-hp-hpux11*"] { if [istarget "hppa2.0w-hp-hpux11*"] {

View file

@ -0,0 +1,191 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2008, 2009 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/>. */
struct s
{
int a;
int *b;
};
struct ss
{
struct s a;
struct s b;
};
#ifdef __cplusplus
struct S : public s {
int zs;
};
struct SS {
int zss;
S s;
};
struct SSS
{
SSS (int x, const S& r);
int a;
const S &b;
};
SSS::SSS (int x, const S& r) : a(x), b(r) { }
class VirtualTest
{
private:
int value;
public:
VirtualTest ()
{
value = 1;
}
};
class Vbase1 : public virtual VirtualTest { };
class Vbase2 : public virtual VirtualTest { };
class Vbase3 : public virtual VirtualTest { };
class Derived : public Vbase1, public Vbase2, public Vbase3
{
private:
int value;
public:
Derived ()
{
value = 2;
}
};
#endif
typedef struct string_repr
{
struct whybother
{
const char *contents;
} whybother;
} string;
/* This lets us avoid malloc. */
int array[100];
struct container
{
string name;
int len;
int *elements;
};
typedef struct container zzz_type;
string
make_string (const char *s)
{
string result;
result.whybother.contents = s;
return result;
}
zzz_type
make_container (const char *s)
{
zzz_type result;
result.name = make_string (s);
result.len = 0;
result.elements = 0;
return result;
}
void
add_item (zzz_type *c, int val)
{
if (c->len == 0)
c->elements = array;
c->elements[c->len] = val;
++c->len;
}
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);
}
void do_nothing(void)
{
int c;
c = 23; /* Another MI breakpoint */
}
int
main ()
{
struct ss ss;
struct ss ssa[2];
string x = make_string ("this is x");
zzz_type c = make_container ("container");
const struct string_repr cstring = { { "const string" } };
init_ss(&ss, 1, 2);
init_ss(ssa+0, 3, 4);
init_ss(ssa+1, 5, 6);
#ifdef __cplusplus
S cps;
cps.zs = 7;
init_s(&cps, 8);
SS cpss;
cpss.zss = 9;
init_s(&cpss.s, 10);
SS cpssa[2];
cpssa[0].zss = 11;
init_s(&cpssa[0].s, 12);
cpssa[1].zss = 13;
init_s(&cpssa[1].s, 14);
SSS sss(15, cps);
SSS& ref (sss);
Derived derived;
#endif
add_item (&c, 23); /* MI breakpoint here */
add_item (&c, 72);
#ifdef MI
do_nothing ();
#endif
return 0; /* break to inspect struct and union */
}

View file

@ -0,0 +1,92 @@
# Copyright (C) 2008, 2009 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
}
set testfile "python-prettyprint"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}
# Start with a fresh gdb.
gdb_exit
gdb_start
gdb_test_multiple "python print 'hello, world!'" "verify python support" {
-re "not supported.*$gdb_prompt $" {
unsupported "python support is disabled"
return -1
}
-re "$gdb_prompt $" {}
}
proc run_lang_tests {lang} {
global srcdir subdir srcfile binfile testfile hex
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug $lang"] != "" } {
untested "Couldn't compile ${srcfile} in $lang mode"
return -1
}
set nl "\[\r\n\]+"
# Start with a fresh gdb.
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
if ![runto_main ] then {
perror "couldn't run to breakpoint"
return
}
gdb_test "set print pretty on" ""
gdb_test "b [gdb_get_line_number {break to inspect} ${testfile}.c ]" \
".*Breakpoint.*"
gdb_test "continue" ".*Breakpoint.*"
gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" ""
gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>"
gdb_test "print ssa\[1\]" " = a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>"
gdb_test "print ssa" " = {a=< a=<3> b=<$hex>> b=< a=<4> b=<$hex>>, a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>}"
if {$lang == "c++"} {
gdb_test "print cps" "= a=<8> b=<$hex>"
gdb_test "print cpss" " = {$nl *zss = 9, *$nl *s = a=<10> b=<$hex>$nl}"
gdb_test "print cpssa\[0\]" " = {$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl}"
gdb_test "print cpssa\[1\]" " = {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl}"
gdb_test "print cpssa" " = {{$nl *zss = 11, *$nl *s = a=<12> b=<$hex>$nl *}, {$nl *zss = 13, *$nl *s = a=<14> b=<$hex>$nl *}}"
gdb_test "print sss" "= a=<15> b=< a=<8> b=<$hex>>"
gdb_test "print ref" "= a=<15> b=< a=<8> b=<$hex>>"
gdb_test "print derived" \
" = \{.*<Vbase1> = pp class name: Vbase1.*<Vbase2> = \{.*<VirtualTest> = pp value variable is: 1,.*members of Vbase2:.*_vptr.Vbase2 = $hex.*<Vbase3> = \{.*members of Vbase3.*members of Derived:.*value = 2.*"
}
gdb_test "print x" " = $hex \"this is x\""
gdb_test "print cstring" " = $hex \"const string\""
gdb_test "print c" " = container $hex \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}"
gdb_test "continue" "Program exited normally\."
}
run_lang_tests "c"
run_lang_tests "c++"

View file

@ -0,0 +1,151 @@
# Copyright (C) 2008, 2009 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
# Test returning a Value from a printer.
class string_print:
def __init__(self, val):
self.val = val
def to_string(self):
return self.val['whybother']['contents']
# Test a class-based printer.
class ContainerPrinter:
class _iterator:
def __init__ (self, pointer, len):
self.start = pointer
self.pointer = pointer
self.end = pointer + len
def __iter__(self):
return self
def next(self):
if self.pointer == self.end:
raise StopIteration
result = self.pointer
self.pointer = self.pointer + 1
return ('[%d]' % int (result - self.start), result.dereference())
def __init__(self, val):
self.val = val
def to_string(self):
return 'container %s with %d elements' % (self.val['name'], self.val['len'])
def children(self):
return self._iterator(self.val['elements'], self.val['len'])
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"]) + ">"
class pp_sss:
def __init__(self, val):
self.val = val
def to_string(self):
return "a=<" + str(self.val['a']) + "> b=<" + str(self.val["b"]) + ">"
class pp_multiple_virtual:
def __init__ (self, val):
self.val = val
def to_string (self):
return "pp value variable is: " + str (self.val['value'])
class pp_vbase1:
def __init__ (self, val):
self.val = val
def to_string (self):
return "pp class name: " + self.val.type.tag
def lookup_function (val):
"Look-up and return a pretty-printer that can print val."
# Get the type.
type = val.type;
# If it points to a reference, get the reference.
if type.code == gdb.TYPE_CODE_REF:
type = type.target ()
# Get the unqualified type, stripped of typedefs.
type = type.unqualified ().strip_typedefs ()
# Get the type name.
typename = type.tag
if typename == None:
return None
# Iterate over local dictionary of types to determine
# if a printer is registered for that type. Return an
# instantiation of the printer if found.
for function in pretty_printers_dict:
if function.match (typename):
return pretty_printers_dict[function] (val)
# Cannot find a pretty printer. Return None.
return None
def register_pretty_printers ():
pretty_printers_dict[re.compile ('^struct s$')] = pp_s
pretty_printers_dict[re.compile ('^s$')] = pp_s
pretty_printers_dict[re.compile ('^S$')] = pp_s
pretty_printers_dict[re.compile ('^struct ss$')] = pp_ss
pretty_printers_dict[re.compile ('^ss$')] = pp_ss
pretty_printers_dict[re.compile ('^const S &$')] = pp_s
pretty_printers_dict[re.compile ('^SSS$')] = pp_sss
pretty_printers_dict[re.compile ('^VirtualTest$')] = pp_multiple_virtual
pretty_printers_dict[re.compile ('^Vbase1$')] = pp_vbase1
# Note that we purposely omit the typedef names here.
# Printer lookup is based on canonical name.
# However, we do need both tagged and untagged variants, to handle
# both the C and C++ cases.
pretty_printers_dict[re.compile ('^struct string_repr$')] = string_print
pretty_printers_dict[re.compile ('^struct container$')] = ContainerPrinter
pretty_printers_dict[re.compile ('^string_repr$')] = string_print
pretty_printers_dict[re.compile ('^container$')] = ContainerPrinter
pretty_printers_dict = {}
register_pretty_printers ()
gdb.pretty_printers.append (lookup_function)

View file

@ -34,6 +34,7 @@
#include "doublest.h" #include "doublest.h"
#include "exceptions.h" #include "exceptions.h"
#include "dfp.h" #include "dfp.h"
#include "python/python.h"
#include <errno.h> #include <errno.h>
@ -80,7 +81,9 @@ struct value_print_options user_print_options =
0, /* print_array_indexes */ 0, /* print_array_indexes */
0, /* deref_ref */ 0, /* deref_ref */
1, /* static_field_print */ 1, /* static_field_print */
1 /* pascal_static_field_print */ 1, /* pascal_static_field_print */
0, /* raw */
0 /* summary */
}; };
/* Initialize *OPTS to be a copy of the user print options. */ /* Initialize *OPTS to be a copy of the user print options. */
@ -214,6 +217,33 @@ show_addressprint (struct ui_file *file, int from_tty,
} }
/* A helper function for val_print. When printing in "summary" mode,
we want to print scalar arguments, but not aggregate arguments.
This function distinguishes between the two. */
static int
scalar_type_p (struct type *type)
{
CHECK_TYPEDEF (type);
while (TYPE_CODE (type) == TYPE_CODE_REF)
{
type = TYPE_TARGET_TYPE (type);
CHECK_TYPEDEF (type);
}
switch (TYPE_CODE (type))
{
case TYPE_CODE_ARRAY:
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_SET:
case TYPE_CODE_STRING:
case TYPE_CODE_BITSTRING:
return 0;
default:
return 1;
}
}
/* Print using the given LANGUAGE the data of type TYPE located at VALADDR /* Print using the given LANGUAGE the data of type TYPE located at VALADDR
(within GDB), which came from the inferior at address ADDRESS, onto (within GDB), which came from the inferior at address ADDRESS, onto
stdio stream STREAM according to OPTIONS. stdio stream STREAM according to OPTIONS.
@ -257,6 +287,23 @@ val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
return (0); return (0);
} }
if (!options->raw)
{
ret = apply_val_pretty_printer (type, valaddr, embedded_offset,
address, stream, recurse, options,
language);
if (ret)
return ret;
}
/* Handle summary mode. If the value is a scalar, print it;
otherwise, print an ellipsis. */
if (options->summary && !scalar_type_p (type))
{
fprintf_filtered (stream, "...");
return 0;
}
TRY_CATCH (except, RETURN_MASK_ERROR) TRY_CATCH (except, RETURN_MASK_ERROR)
{ {
ret = language->la_val_print (type, valaddr, embedded_offset, address, ret = language->la_val_print (type, valaddr, embedded_offset, address,
@ -331,6 +378,18 @@ value_print (struct value *val, struct ui_file *stream,
if (!value_check_printable (val, stream)) if (!value_check_printable (val, stream))
return 0; return 0;
if (!options->raw)
{
int r = apply_val_pretty_printer (value_type (val),
value_contents_all (val),
value_embedded_offset (val),
value_address (val),
stream, 0, options,
current_language);
if (r)
return r;
}
return LA_VALUE_PRINT (val, stream, options); return LA_VALUE_PRINT (val, stream, options);
} }

View file

@ -84,6 +84,12 @@ struct value_print_options
/* If nonzero, print static fields for Pascal. FIXME: C++ and Java /* If nonzero, print static fields for Pascal. FIXME: C++ and Java
share one flag, why not Pascal too? */ share one flag, why not Pascal too? */
int pascal_static_field_print; int pascal_static_field_print;
/* Controls Python pretty-printing. */
int raw;
/* If nonzero, print the value in "summary" form. */
int summary;
}; };
/* The global print options set by the user. In general this should /* The global print options set by the user. In general this should