* Python pretty-printing [5/6]
@ 2009-04-02 20:57 Tom Tromey
2009-04-03 15:29 ` Eli Zaretskii
` (3 more replies)
0 siblings, 4 replies; 20+ messages in thread
From: Tom Tromey @ 2009-04-02 20:57 UTC (permalink / raw)
To: gdb-patches
This is the main part of the pretty-printing code.
It hooks the Python pretty-printer into various value-printing calls
(including the C++ base-class printing code, as discussed on the gdb
list).
It adds a new "/r" ("raw") option to the print command family.
It also changes how "set print frame-arguments" is implemented, to let
the Python pretty-printing code implement its own form of summary
output.
Tom
2009-04-01 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.
(gdbpy_instantiate_printer): 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 (search_pp_list): New function.
(find_pretty_printer): Likewise.
(pretty_print_one_value): Likewise.
(gdbpy_instantiate_printer): Likewise.
(gdbpy_get_display_hint): Likewise.
(print_string_repr): Likewise.
(py_restore_tstate): Likewise.
(push_dummy_python_frame): Likewise.
(print_children): Likewise.
(apply_val_pretty_printer): Likewise.
(gdbpy_to_string_cst, gdbpy_children_cst, gdbpy_display_hint_cst):
New globals.
(_initialize_python): Initialize them. Set gdb.pretty_printers.
Include language.h, valprint.h.
* 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.
2009-04-01 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.
(Python API): Update.
2009-04-01 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.
gdb/ChangeLog | 50 +++
gdb/cp-valprint.c | 28 +-
gdb/doc/ChangeLog | 8 +
gdb/doc/gdb.texinfo | 158 +++++++-
gdb/printcmd.c | 21 +-
gdb/python/python-internal.h | 9 +
gdb/python/python-value.c | 11 +
gdb/python/python.c | 518 +++++++++++++++++++++++
gdb/python/python.h | 6 +
gdb/stack.c | 50 +--
gdb/testsuite/ChangeLog | 10 +
gdb/testsuite/gdb.base/display.exp | 8 +-
gdb/testsuite/gdb.python/python-prettyprint.c | 191 +++++++++
gdb/testsuite/gdb.python/python-prettyprint.exp | 92 ++++
gdb/testsuite/gdb.python/python-prettyprint.py | 151 +++++++
gdb/valprint.c | 61 +++-
gdb/valprint.h | 6 +
17 files changed, 1323 insertions(+), 55 deletions(-)
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.c
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.exp
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.py
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 181b4ff..d264b40 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -36,6 +36,7 @@
#include "valprint.h"
#include "cp-support.h"
#include "language.h"
+#include "python/python.h"
/* Controls printing of vtbl's */
static void
@@ -418,12 +419,27 @@ cp_print_value (struct type *type, struct type *real_type,
if (skip >= 1)
fprintf_filtered (stream, "<invalid address>");
else
- cp_print_value_fields (baseclass, thistype, base_valaddr,
- thisoffset + boffset, address + boffset,
- stream, recurse, options,
- ((struct type **)
- obstack_base (&dont_print_vb_obstack)),
- 0);
+ {
+ int result = 0;
+
+ /* Attempt to run the Python pretty-printers on the
+ baseclass if possible. */
+ 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);
flush_it:
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5196842..dae6178 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18194,6 +18194,7 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Auto-loading:: Automatically loading Python code.
* Values From Inferior::
* Types From Inferior:: Python representation of types.
+* Pretty Printing:: Pretty-printing values.
* Commands In Python:: Implementing new commands in Python.
* Functions In Python:: Writing new convenience functions.
* Objfiles In Python:: Object files.
@@ -18719,6 +18720,160 @@ A function internal to @value{GDBN}. This is the type used to represent
convenience functions.
@end table
+@node Pretty Printing
+@subsubsection Pretty Printing
+
+@value{GDBN} provides a mechanism to allow pretty-printing of values
+using Python code. This mechanism works for both MI and the CLI.
+
+A pretty-printer is an object that implements a specific interface.
+There is no predefined base class for pretty-printers.
+
+@defop Operation {pretty printer} __init__ (self, val)
+When printing a value, @value{GDBN} constructs an instance of the
+pretty-printer. @var{val} is the value to be printed, an instance of
+@code{gdb.Value}.
+@end defop
+
+@defop Operation {pretty printer} children (self)
+When printing a value, @value{GDBN} will call this method to compute
+the children of the value passed to the object's constructor.
+
+This method must return an object conforming to the Python iterator
+protocol. Each element 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)
+This method must return a string. The CLI may use this to change the
+formatting of children of a value. The result will also be supplied
+to an MI consumer as a @samp{displayhint} attribute of the variable
+being printed.
+
+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}.
+
+If this method returns a string, it is printed verbatim. Otherwise,
+the result is converted to a @code{gdb.Value}, following the usual
+algorithm. Then @value{GDBN} prints this value; this may possibly
+result in a call to another pretty-printer. If the result is not
+convertible to @code{gdb.Value}, an exception is raised.
+@end defop
+
+@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 function will be called with a @code{gdb.Value} to be
+pretty-printed. Each @code{gdb.Objfile} also contains a
+@code{pretty_printers} attribute. A function on one of these lists
+takes a single @code{gdb.Value} argument and returns a pretty-printer
+object conforming to the interface definition above. If this 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 @code{gdb.Objfile} 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.
+Functions are always invoked from the head of the
+@code{gdb.pretty-printers} 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']
+@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 versioned
+python package, and then restrict your auto-loaded code to idempotent
+behavior -- for example, just @code{import}s of your printer modules,
+followed by a call to a register pretty-printers with the current
+objfile. This approach will scale more nicely to multiple inferiors,
+potentially using different library versions.
+
+For example, in addition to the above, this code might appear in
+@code{gdb.libstdcxx.v6}:
+
+@smallexample
+def register_printers (objfile):
+ objfile.pretty_printers.add (str_lookup_function)
+@end smallexample
+
+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
@subsubsection Commands In Python
@@ -19053,7 +19208,8 @@ The file name of the objfile as a string.
@defivar Objfile pretty_printers
The @code{pretty_printers} attribute is used to look up
pretty-printers by type. This is a dictionary which maps regular
-expressions (strings) to pretty-printing objects.
+expressions (strings) to pretty-printing objects. @xref{Pretty
+Printing}, for more information.
@end defivar
@node Interpreters
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index cab7032..4cb681f 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -68,11 +68,15 @@ struct format_data
int count;
char format;
char size;
+
+ /* True if the value should be printed raw -- that is, bypassing
+ python-based formatters. */
+ unsigned char raw;
};
/* Last specified output format. */
-static char last_format = 'x';
+static char last_format = 0;
/* 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.size = '?';
val.count = 1;
+ val.raw = 0;
if (*p >= '0' && *p <= '9')
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')
val.size = *p++;
+ else if (*p == 'r')
+ {
+ val.raw = 1;
+ p++;
+ }
else if (*p >= 'a' && *p <= 'z')
val.format = *p++;
else
@@ -874,6 +884,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
fmt.count = 1;
fmt.format = 0;
fmt.size = 0;
+ fmt.raw = 0;
}
if (exp && *exp)
@@ -909,6 +920,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
get_formatted_print_options (&opts, format);
opts.inspect_it = inspect;
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
printf_filtered ("\n");
@@ -959,6 +971,7 @@ output_command (char *exp, int from_tty)
struct value_print_options opts;
fmt.size = 0;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
@@ -976,6 +989,7 @@ output_command (char *exp, int from_tty)
annotate_value_begin (value_type (val));
get_formatted_print_options (&opts, format);
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
annotate_value_end ();
@@ -1296,9 +1310,10 @@ x_command (char *exp, int from_tty)
struct cleanup *old_chain;
struct value *val;
- fmt.format = last_format;
+ fmt.format = last_format ? last_format : 'x';
fmt.size = last_size;
fmt.count = 1;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
@@ -1402,6 +1417,7 @@ display_command (char *exp, int from_tty)
fmt.format = 0;
fmt.size = 0;
fmt.count = 0;
+ fmt.raw = 0;
}
innermost_block = NULL;
@@ -1613,6 +1629,7 @@ do_one_display (struct display *d)
annotate_display_expression ();
get_formatted_print_options (&opts, d->format.format);
+ opts.raw = d->format.raw;
print_formatted (evaluate_expression (d->exp),
d->format.size, &opts, gdb_stdout);
printf_filtered ("\n");
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index aca61d9..10a489f 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -33,6 +33,7 @@
#if HAVE_LIBPYTHON2_4
#include "python2.4/Python.h"
+#include "python2.4/frameobject.h"
/* 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
compilation due to several apparent mistakes in python2.4 API, so we
@@ -40,8 +41,10 @@
typedef int Py_ssize_t;
#elif HAVE_LIBPYTHON2_5
#include "python2.5/Python.h"
+#include "python2.5/frameobject.h"
#elif HAVE_LIBPYTHON2_6
#include "python2.6/Python.h"
+#include "python2.6/frameobject.h"
#else
#error "Unable to find usable Python.h"
#endif
@@ -71,6 +74,7 @@ PyObject *objfile_to_objfile_object (struct objfile *);
PyObject *objfpy_get_printers (PyObject *, void *);
+struct value *value_object_to_value (PyObject *self);
struct value *convert_value_from_python (PyObject *obj);
struct type *type_object_to_type (PyObject *obj);
@@ -103,6 +107,11 @@ char *python_string_to_host_string (PyObject *obj);
PyObject *target_string_to_unicode (const gdb_byte *str, int length);
int gdbpy_is_string (PyObject *obj);
+PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value);
+
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 */
diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c
index f34c41b..0c3caca 100644
--- a/gdb/python/python-value.c
+++ b/gdb/python/python-value.c
@@ -787,6 +787,17 @@ value_to_value_object (struct value *val)
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
be converted, set a Python exception and return NULL. */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 81d762f..6dba48e 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -24,6 +24,8 @@
#include "gdbcmd.h"
#include "objfiles.h"
#include "observer.h"
+#include "language.h"
+#include "valprint.h"
#include <ctype.h>
@@ -52,6 +54,10 @@ static PyMethodDef GdbMethods[];
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;
/* Given a command_line, return a command string suitable for passing
@@ -430,6 +436,503 @@ gdbpy_objfiles (PyObject *unused1, PyObject *unused2)
return list;
}
+\f
+
+/* Helper function for find_pretty_printer which iterates over a
+ list, calls each function and inspects output. */
+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;
+
+ /* gdbpy_instantiate_printer can return three possible return
+ values: NULL on error; Py_None if the pretty-printer
+ in the list cannot print the value; or a printer instance if
+ the printer can print the value. */
+ printer = gdbpy_instantiate_printer (function, value);
+ if (! printer)
+ return NULL;
+ else if (printer != Py_None)
+ return printer;
+
+ Py_DECREF (printer);
+ }
+
+ Py_RETURN_NONE;
+}
+
+/* Find the pretty-printing constructor function for TYPE. If no
+ pretty-printer exists, return NULL. If one exists, return a new
+ reference. */
+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)
+ 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;
+
+ /* In this loop, if function is not an instantiation of a
+ pretty-printer, and it is not null, then it is a return of
+ Py_RETURN_NONE, which must be decremented. */
+ Py_DECREF (function);
+ Py_XDECREF (pp_list);
+ }
+
+ pp_list = NULL;
+ /* Fetch the global pretty printer dictionary. */
+ if (! PyObject_HasAttrString (gdb_module, "pretty_printers"))
+ 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 if (PyObject_TypeCheck (result, &value_object_type))
+ {
+ /* If we just call convert_value_from_python for this
+ type, we won't know who owns the result. For this
+ one case we need to copy the resulting value. */
+ struct value *v = value_object_to_value (result);
+ *out_value = value_copy (v);
+ }
+ else
+ *out_value = convert_value_from_python (result);
+ Py_DECREF (result);
+ }
+ }
+
+ return output;
+}
+
+/* Instantiate a pretty-printer given a constructor, CONS, and a
+ value, VAL. Return NULL on error. Ownership of the object
+ instance is transferred to the reciever */
+PyObject *
+gdbpy_instantiate_printer (PyObject *cons, PyObject *value)
+{
+ PyObject *result;
+ result = PyObject_CallFunctionObjArgs (cons, value, NULL);
+ return result;
+}
+
+/* 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 */
/* Dummy implementation of the gdb "python" command. */
@@ -456,6 +959,17 @@ eval_python_from_control_command (struct command_line *cmd)
error (_("Python scripting is not supported in this copy of GDB."));
}
+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 */
\f
@@ -561,9 +1075,13 @@ Enables or disables auto-loading of Python code when an object is opened."),
gdbpy_initialize_objfile ();
PyRun_SimpleString ("import gdb");
+ PyRun_SimpleString ("gdb.pretty_printers = []");
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__");
/* Create a couple objects which are used for Python's stdout and
diff --git a/gdb/python/python.h b/gdb/python/python.h
index e63c447..33b0437 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -26,4 +26,10 @@ extern struct value *values_in_python;
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 */
diff --git a/gdb/stack.c b/gdb/stack.c
index bf9e576..eb97eeb 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -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
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
@@ -220,6 +180,10 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
int args_printed = 0;
struct cleanup *old_chain, *list_chain;
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);
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 ();
ui_out_text (uiout, "=");
- if (print_this_frame_argument_p (sym))
+ if (print_args)
{
/* Avoid value_print because it will deref ref parameters.
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);
opts.deref_ref = 0;
- common_val_print (val, stb->stream, 2,
- &opts, language);
+ opts.summary = summary;
+ common_val_print (val, stb->stream, 2, &opts, language);
ui_out_field_stream (uiout, "value", stb);
}
else
diff --git a/gdb/testsuite/gdb.base/display.exp b/gdb/testsuite/gdb.base/display.exp
index d62e8bf..aa65373 100644
--- a/gdb/testsuite/gdb.base/display.exp
+++ b/gdb/testsuite/gdb.base/display.exp
@@ -180,8 +180,12 @@ gdb_test "printf \"%p\\n\", 1" "0x1"
# play with "print", too
#
-gdb_test "print/r j" ".*Undefined output format.*"
-gdb_test "print j" ".*" "debug test output"
+gdb_test "print/z j" ".*Undefined output format.*"
+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
if [istarget "hppa2.0w-hp-hpux11*"] {
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c
new file mode 100644
index 0000000..399be23
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.c
@@ -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 */
+}
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp
new file mode 100644
index 0000000..f83b1cd
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.exp
@@ -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++"
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py
new file mode 100644
index 0000000..367baa9
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.py
@@ -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)
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 5659f99..756dc50 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -34,6 +34,7 @@
#include "doublest.h"
#include "exceptions.h"
#include "dfp.h"
+#include "python/python.h"
#include <errno.h>
@@ -80,7 +81,9 @@ struct value_print_options user_print_options =
0, /* print_array_indexes */
0, /* deref_ref */
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. */
@@ -214,6 +217,33 @@ show_addressprint (struct ui_file *file, int from_tty,
}
\f
+/* 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
(within GDB), which came from the inferior at address ADDRESS, onto
stdio stream STREAM according to OPTIONS.
@@ -257,6 +287,23 @@ val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
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)
{
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))
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);
}
diff --git a/gdb/valprint.h b/gdb/valprint.h
index 90dcdc2..4f63fa6 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -84,6 +84,12 @@ struct value_print_options
/* If nonzero, print static fields for Pascal. FIXME: C++ and Java
share one flag, why not Pascal too? */
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
--
1.6.0.6
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-02 20:57 Python pretty-printing [5/6] Tom Tromey
@ 2009-04-03 15:29 ` Eli Zaretskii
2009-04-09 0:29 ` Tom Tromey
2009-04-04 16:39 ` Thiago Jung Bauermann
` (2 subsequent siblings)
3 siblings, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2009-04-03 15:29 UTC (permalink / raw)
To: tromey; +Cc: gdb-patches
> From: Tom Tromey <tromey@redhat.com>
> Date: Thu, 02 Apr 2009 14:56:55 -0600
>
> This is the main part of the pretty-printing code.
Thanks.
> It adds a new "/r" ("raw") option to the print command family.
But this change in behavior is not documented in the docs patch,
right?
> 2009-04-01 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.
> (Python API): Update.
Comments:
> +@node Pretty Printing
> +@subsubsection Pretty Printing
Please add a @cindex entry here suitable for this subsection.
> +A pretty-printer is an object that implements a specific interface.
> +There is no predefined base class for pretty-printers.
Is it possible to expand this a bit? This explanation did not explain
anything to me; I needed to read the whole text below several times,
and then look at the code and think, before I managed to come up with
some vague idea of what this feature offers me, and what I can and
cannot do with it.
> +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}.
I suggest an example here of what is, or could be, prepended.
> +If this method returns a string, it is printed verbatim. Otherwise,
> +the result is converted to a @code{gdb.Value}, following the usual
> +algorithm.
If we describe the "usual algorithm" somewhere, a cross-reference here
would be a good idea.
> Then @value{GDBN} prints this value; this may possibly
> +result in a call to another pretty-printer. If the result is not
> +convertible to @code{gdb.Value}, an exception is raised.
Should we say what exception is raised?
> +@subsubsection Selecting Pretty-Printers
Please make this a @node, and please add a @cindex entry for it.
> A function on one of these lists
> +takes a single @code{gdb.Value} argument and returns a pretty-printer
> +object conforming to the interface definition above.
I presume that "above" refers to the previous section, right? If so,
please add a cross-reference.
> +We recommend that you put your core pretty-printers into a versioned
> +python package, and then restrict your auto-loaded code to idempotent
> +behavior -- for example, just @code{import}s of your printer modules,
Please use "---" (3 dashes) for em-dash.
> +@smallexample
> +def register_printers (objfile):
> + objfile.pretty_printers.add (str_lookup_function)
> +@end smallexample
> +
> +And then the corresponding contents of the auto-load file would be:
I think you want @noindent before "And then ...", because it is
logically a continuation of the previous example, not a new paragraph.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-02 20:57 Python pretty-printing [5/6] Tom Tromey
2009-04-03 15:29 ` Eli Zaretskii
@ 2009-04-04 16:39 ` Thiago Jung Bauermann
2009-04-09 0:52 ` Tom Tromey
2009-04-07 18:32 ` Joel Brobecker
2009-04-09 1:08 ` Tom Tromey
3 siblings, 1 reply; 20+ messages in thread
From: Thiago Jung Bauermann @ 2009-04-04 16:39 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches ml
El jue, 02-04-2009 a las 14:56 -0600, Tom Tromey escribió:
> This is the main part of the pretty-printing code.
Awesome. Some comments follow. Feel free to mention if you think they
cross the line from useful to nag and pedantic.
> gdb/python/python.c | 518 +++++++++++++++++++++++
The pretty-printing specific code in python.c is enough to warrant it to
go in its own .c file. WDYT of moving it to, say, python-prettyprint.c?
I was meaning to post a RFC patch to the archer list doing the move, but
you submitted the code upstream before I got around to it. :-)
> +the second element is the child's value. The value can be any Python
> +object which is convertible to a @value{GDBN} value.
Perhaps we should explain which Python objects can be convertible to a
GDB value? Something like:
"... which is convertible to a @value{GDBN} value, e.g.: scalars
(integers, floats, booleans), strings and @code{gdb.Value} objects)."
> +We recommend that you put your core pretty-printers into a versioned
> +python package, and then restrict your auto-loaded code to idempotent
Sorry if this is silly, but: at least to me, it's not immediately clear
what "versioned python package" means. The first thing I think of is a
python package checked into a VCS but since this cannot be what the text
is talking about, my brain raises a parser error. Perhaps rewording this
to "... into a python package whose name includes the library version"
or something like that?
I agree that the example given right after this paragraph clears the
doubts I had, though, so perhaps this is moot.
> +/* Find the pretty-printing constructor function for TYPE. If no
> + pretty-printer exists, return NULL. If one exists, return a new
> + reference. */
> +static PyObject *
> +find_pretty_printer (PyObject *value)
s/TYPE/VALUE/
Also, if this function returns NULL, sometimes a Python exception will
be set, sometimes it won't. Is this intended? If so, this should be
noted.
> +/* 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 if (PyObject_TypeCheck (result, &value_object_type))
> + {
> + /* If we just call convert_value_from_python for this
> + type, we won't know who owns the result. For this
> + one case we need to copy the resulting value. */
> + struct value *v = value_object_to_value (result);
> + *out_value = value_copy (v);
> + }
> + else
> + *out_value = convert_value_from_python (result);
> + Py_DECREF (result);
> + }
Like I said earlier in the archer mailing list:
The comment about convert_value_from_python above is outdated. Jim
Blandy fixed it to always return a caller-owned result.
Because of this, pretty_print_one_value can now probably just call
convert_value_from_python and return a struct value in all cases and be
done with it. Either this function should be changed to work that way,
or the comment above removed.
Since (as you mentioned on IRC yesterday) the call to
python_string_to_host_string will have to be changed anyway to take into
account the length of the Python string, IMHO it's easier to make this
function always return a struct value. Then in print_string_repr you can
call LA_GET_STRING on it before calling LA_PRINT_STRING.
That will solve the problem of assuming that the string ends with a \0
byte (c_get_string still assumes that strings end with a null
character). Well, almost. value_from_string needs to be changed to
receive a length argument instead of using strlen as it does now, and
convert_value_from_python needs to pass the length obtained from the
python string to it. But that's trivial to do.
From a cursory look at the varobj side of things (where
pretty_print_one_value is also used), things may get more complicated if
this function is changed. But only because varobj.c uses and expects
\0-terminated strings, so IMHO it's better to make the change, and
either fix or accomodate varobj.c. WDYT?
[ This ended up less like a comment and more like a braindump. I tried
to polish the text, though... ]
> +/* Instantiate a pretty-printer given a constructor, CONS, and a
> + value, VAL. Return NULL on error. Ownership of the object
> + instance is transferred to the reciever */
> +PyObject *
> +gdbpy_instantiate_printer (PyObject *cons, PyObject *value)
> +{
> + PyObject *result;
> + result = PyObject_CallFunctionObjArgs (cons, value, NULL);
> + return result;
> +}
Is it worth having this function, which is in fact just a call to
PyObject_CallFunctionObjArgs? Also, there's a typo in the comment:
s/reciever/receiver/
> +/* 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)
I use the *py_ prefix for functions that can be directly called from
Python. I think it's a useful hint. I don't think I ever mentioned this
practice though.
If you agree it's useful, this method should be renamed to not use the
gdbpy_ prefix.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-02 20:57 Python pretty-printing [5/6] Tom Tromey
2009-04-03 15:29 ` Eli Zaretskii
2009-04-04 16:39 ` Thiago Jung Bauermann
@ 2009-04-07 18:32 ` Joel Brobecker
2009-04-07 18:41 ` Tom Tromey
2009-04-09 1:08 ` Tom Tromey
3 siblings, 1 reply; 20+ messages in thread
From: Joel Brobecker @ 2009-04-07 18:32 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> #if HAVE_LIBPYTHON2_4
> #include "python2.4/Python.h"
> +#include "python2.4/frameobject.h"
> /* 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
> compilation due to several apparent mistakes in python2.4 API, so we
> @@ -40,8 +41,10 @@
> typedef int Py_ssize_t;
> #elif HAVE_LIBPYTHON2_5
> #include "python2.5/Python.h"
> +#include "python2.5/frameobject.h"
> #elif HAVE_LIBPYTHON2_6
> #include "python2.6/Python.h"
> +#include "python2.6/frameobject.h"
> #else
> #error "Unable to find usable Python.h"
> #endif
Can we avoid this by using the right -I option? It seems to be a shame
that we keep having to include the same file 3 times just because
the file resides in a different directory name...
In other words, do:
#include <Python.h>
instead of:
#if HAVE_LIBPYTHON2_4
#include "python2.4/Python.h"
#elif HAVE_LIBPYTHON2_5
#include "python2.5/Python.h"
#elif HAVE_LIBPYTHON2_6
#include "python2.6/Python.h"
#else
...
#endif
--
Joel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-07 18:32 ` Joel Brobecker
@ 2009-04-07 18:41 ` Tom Tromey
2009-04-07 20:38 ` Joel Brobecker
0 siblings, 1 reply; 20+ messages in thread
From: Tom Tromey @ 2009-04-07 18:41 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
>>>>> "Joel" == Joel Brobecker <brobecker@adacore.com> writes:
>> +#include "python2.5/frameobject.h"
Joel> Can we avoid this by using the right -I option? It seems to be a shame
Joel> that we keep having to include the same file 3 times just because
Joel> the file resides in a different directory name...
I think we ought to be able to. That's what the Python docs show:
#include "Python.h"
I don't remember why we do it this way, or, for that matter, why we
don't use python-config to get the paths.
I would prefer to do this as a follow-up patch.
Tom
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-07 18:41 ` Tom Tromey
@ 2009-04-07 20:38 ` Joel Brobecker
0 siblings, 0 replies; 20+ messages in thread
From: Joel Brobecker @ 2009-04-07 20:38 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> I would prefer to do this as a follow-up patch.
Of course!
--
Joel
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-03 15:29 ` Eli Zaretskii
@ 2009-04-09 0:29 ` Tom Tromey
0 siblings, 0 replies; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 0:29 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:
Tom> It adds a new "/r" ("raw") option to the print command family.
Eli> But this change in behavior is not documented in the docs patch,
Eli> right?
Thanks, I forgot to merge that hunk.
It will show up in the next revision of this patch.
Tom> +A pretty-printer is an object that implements a specific interface.
Tom> +There is no predefined base class for pretty-printers.
Eli> Is it possible to expand this a bit?
I added a real-world example here.
Tom> Then @value{GDBN} prints this value; this may possibly
Tom> +result in a call to another pretty-printer. If the result is not
Tom> +convertible to @code{gdb.Value}, an exception is raised.
Eli> Should we say what exception is raised?
For the time being I would rather not. I think we will probably
introduce our own exception types at some point, so I'd rather not
make a promise here.
Tom
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-04 16:39 ` Thiago Jung Bauermann
@ 2009-04-09 0:52 ` Tom Tromey
2009-04-09 15:00 ` Thiago Jung Bauermann
2009-04-09 19:37 ` Tom Tromey
0 siblings, 2 replies; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 0:52 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches ml
>>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes:
Thiago> The pretty-printing specific code in python.c is enough to
Thiago> warrant it to go in its own .c file. WDYT of moving it to,
Thiago> say, python-prettyprint.c?
Ok, I'll do that.
Thiago> Perhaps we should explain which Python objects can be
Thiago> convertible to a GDB value?
Thanks, I did this too.
Tom> +We recommend that you put your core pretty-printers into a versioned
Tom> +python package, and then restrict your auto-loaded code to idempotent
Thiago> Sorry if this is silly, but: at least to me, it's not immediately clear
Thiago> what "versioned python package" means. The first thing I think of is a
Thiago> python package checked into a VCS but since this cannot be what the text
Thiago> is talking about, my brain raises a parser error. Perhaps rewording this
Thiago> to "... into a python package whose name includes the library version"
Thiago> or something like that?
Did it.
Tom> +find_pretty_printer (PyObject *value)
Thiago> Also, if this function returns NULL, sometimes a Python exception will
Thiago> be set, sometimes it won't. Is this intended? If so, this should be
Thiago> noted.
I looked again and I don't see how it can return NULL without setting
the exception. Can you point it out to me?
Thiago> The comment about convert_value_from_python above is outdated. Jim
Thiago> Blandy fixed it to always return a caller-owned result.
Thanks, I fixed this.
Thiago> Because of this, pretty_print_one_value can now probably just call
Thiago> convert_value_from_python and return a struct value in all cases and be
Thiago> done with it. Either this function should be changed to work that way,
Thiago> or the comment above removed.
I made the minimal change here. I don't want to refactor this right
now; Phil is in the middle of doing that for the embedded \0 problem.
We can apply his fix separately; the current code is not ideal, due to
this problem, but it is still usable for a variety of printers.
[...]
Thiago> But only because varobj.c uses and expects
Thiago> \0-terminated strings, so IMHO it's better to make the change, and
Thiago> either fix or accomodate varobj.c. WDYT?
I'll make sure Phil looks at the varobj part of this problem as well.
It is less clear to me how MI ought to work with embedded \0 in a
string, so if an MI expert wants to speak up...
Tom> +gdbpy_instantiate_printer (PyObject *cons, PyObject *value)
Thiago> Is it worth having this function, which is in fact just a call to
Thiago> PyObject_CallFunctionObjArgs?
Nope, it was a leftover. I nuked it.
Tom> +char *
Tom> +gdbpy_get_display_hint (PyObject *printer)
Thiago> I use the *py_ prefix for functions that can be directly called from
Thiago> Python. I think it's a useful hint. I don't think I ever mentioned this
Thiago> practice though.
Thiago> If you agree it's useful, this method should be renamed to not use the
Thiago> gdbpy_ prefix.
I am leaving this for now. We use the gdbpy_ prefix inconsistently,
even in CVS gdb, and I would prefer to see a single cleanup if we are
going to adopt a solid naming convention.
I will send an updated patch shortly.
Tom
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-02 20:57 Python pretty-printing [5/6] Tom Tromey
` (2 preceding siblings ...)
2009-04-07 18:32 ` Joel Brobecker
@ 2009-04-09 1:08 ` Tom Tromey
2009-04-09 7:40 ` Eli Zaretskii
3 siblings, 1 reply; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 1:08 UTC (permalink / raw)
To: gdb-patches
Here is the new version of this patch.
I think I have addressed all the comments; either by making the
requested change or explaining why I did not. Still, you probably
should check.
Tom
2009-04-01 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-04-01 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-04-01 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.
gdb/ChangeLog | 42 ++
gdb/Makefile.in | 6 +
gdb/cp-valprint.c | 28 +-
gdb/doc/ChangeLog | 10 +
gdb/doc/gdb.texinfo | 214 ++++++++++-
gdb/printcmd.c | 21 +-
gdb/python/python-internal.h | 7 +
gdb/python/python-prettyprint.c | 513 +++++++++++++++++++++++
gdb/python/python-value.c | 11 +
gdb/python/python.c | 8 +
gdb/python/python.h | 6 +
gdb/stack.c | 50 +--
gdb/testsuite/ChangeLog | 10 +
gdb/testsuite/gdb.base/display.exp | 8 +-
gdb/testsuite/gdb.python/python-prettyprint.c | 191 +++++++++
gdb/testsuite/gdb.python/python-prettyprint.exp | 92 ++++
gdb/testsuite/gdb.python/python-prettyprint.py | 151 +++++++
gdb/valprint.c | 61 +++-
gdb/valprint.h | 6 +
19 files changed, 1380 insertions(+), 55 deletions(-)
create mode 100644 gdb/python/python-prettyprint.c
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.c
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.exp
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.py
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 265ec94..0dc664b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -268,6 +268,7 @@ SUBDIR_PYTHON_OBS = \
python-cmd.o \
python-function.o \
python-objfile.o \
+ python-prettyprint.o \
python-type.o \
python-utils.o \
python-value.o
@@ -276,6 +277,7 @@ SUBDIR_PYTHON_SRCS = \
python/python-cmd.c \
python/python-function.c \
python/python-objfile.c \
+ python/python-prettyprint.c \
python/python-type.c \
python/python-utils.c \
python/python-value.c
@@ -1859,6 +1861,10 @@ python-objfile.o: $(srcdir)/python/python-objfile.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c
$(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
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c
$(POSTCOMPILE)
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 181b4ff..d264b40 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -36,6 +36,7 @@
#include "valprint.h"
#include "cp-support.h"
#include "language.h"
+#include "python/python.h"
/* Controls printing of vtbl's */
static void
@@ -418,12 +419,27 @@ cp_print_value (struct type *type, struct type *real_type,
if (skip >= 1)
fprintf_filtered (stream, "<invalid address>");
else
- cp_print_value_fields (baseclass, thistype, base_valaddr,
- thisoffset + boffset, address + boffset,
- stream, recurse, options,
- ((struct type **)
- obstack_base (&dont_print_vb_obstack)),
- 0);
+ {
+ int result = 0;
+
+ /* Attempt to run the Python pretty-printers on the
+ baseclass if possible. */
+ 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);
flush_it:
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 45ee8cf..3e38175 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6565,6 +6565,12 @@ Without this format, @value{GDBN} displays pointers to and arrays of
@code{char}, @w{@code{unsigned char}}, and @w{@code{signed char}} as
strings. Single-byte members of a vector are displayed as an integer
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
For example, to print the program counter in hex (@pxref{Registers}), type
@@ -18226,6 +18232,8 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Auto-loading:: Automatically loading Python code.
* Values From Inferior::
* 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.
* Functions In Python:: Writing new convenience functions.
* Objfiles In Python:: Object files.
@@ -18752,6 +18760,209 @@ A function internal to @value{GDBN}. This is the type used to represent
convenience functions.
@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, 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.
+
+You should write auto-loaded code such that it can be evaluated
+multiple times without changing its meaning. For example, an
+auto-load file may 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.
+
+For example, in addition to the above, 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
@subsubsection Commands In Python
@@ -19104,7 +19315,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
function in order; if the function returns @code{None}, then the
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
@node Interpreters
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index cab7032..4cb681f 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -68,11 +68,15 @@ struct format_data
int count;
char format;
char size;
+
+ /* True if the value should be printed raw -- that is, bypassing
+ python-based formatters. */
+ unsigned char raw;
};
/* Last specified output format. */
-static char last_format = 'x';
+static char last_format = 0;
/* 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.size = '?';
val.count = 1;
+ val.raw = 0;
if (*p >= '0' && *p <= '9')
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')
val.size = *p++;
+ else if (*p == 'r')
+ {
+ val.raw = 1;
+ p++;
+ }
else if (*p >= 'a' && *p <= 'z')
val.format = *p++;
else
@@ -874,6 +884,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
fmt.count = 1;
fmt.format = 0;
fmt.size = 0;
+ fmt.raw = 0;
}
if (exp && *exp)
@@ -909,6 +920,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
get_formatted_print_options (&opts, format);
opts.inspect_it = inspect;
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
printf_filtered ("\n");
@@ -959,6 +971,7 @@ output_command (char *exp, int from_tty)
struct value_print_options opts;
fmt.size = 0;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
@@ -976,6 +989,7 @@ output_command (char *exp, int from_tty)
annotate_value_begin (value_type (val));
get_formatted_print_options (&opts, format);
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
annotate_value_end ();
@@ -1296,9 +1310,10 @@ x_command (char *exp, int from_tty)
struct cleanup *old_chain;
struct value *val;
- fmt.format = last_format;
+ fmt.format = last_format ? last_format : 'x';
fmt.size = last_size;
fmt.count = 1;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
@@ -1402,6 +1417,7 @@ display_command (char *exp, int from_tty)
fmt.format = 0;
fmt.size = 0;
fmt.count = 0;
+ fmt.raw = 0;
}
innermost_block = NULL;
@@ -1613,6 +1629,7 @@ do_one_display (struct display *d)
annotate_display_expression ();
get_formatted_print_options (&opts, d->format.format);
+ opts.raw = d->format.raw;
print_formatted (evaluate_expression (d->exp),
d->format.size, &opts, gdb_stdout);
printf_filtered ("\n");
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 408d329..06d9ba2 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -33,6 +33,7 @@
#if HAVE_LIBPYTHON2_4
#include "python2.4/Python.h"
+#include "python2.4/frameobject.h"
/* 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
compilation due to several apparent mistakes in python2.4 API, so we
@@ -40,8 +41,10 @@
typedef int Py_ssize_t;
#elif HAVE_LIBPYTHON2_5
#include "python2.5/Python.h"
+#include "python2.5/frameobject.h"
#elif HAVE_LIBPYTHON2_6
#include "python2.6/Python.h"
+#include "python2.6/frameobject.h"
#else
#error "Unable to find usable Python.h"
#endif
@@ -72,6 +75,7 @@ PyObject *objfile_to_objfile_object (struct objfile *);
PyObject *objfpy_get_printers (PyObject *, void *);
+struct value *value_object_to_value (PyObject *self);
struct value *convert_value_from_python (PyObject *obj);
struct type *type_object_to_type (PyObject *obj);
@@ -105,5 +109,8 @@ PyObject *target_string_to_unicode (const gdb_byte *str, int length);
int gdbpy_is_string (PyObject *obj);
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 */
diff --git a/gdb/python/python-prettyprint.c b/gdb/python/python-prettyprint.c
new file mode 100644
index 0000000..34e9b80
--- /dev/null
+++ b/gdb/python/python-prettyprint.c
@@ -0,0 +1,513 @@
+/* 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. */
+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 NULL. If one exists, return a new
+ reference. */
+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)
+ 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"))
+ 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 */
diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c
index 76f5cde..46af318 100644
--- a/gdb/python/python-value.c
+++ b/gdb/python/python-value.c
@@ -805,6 +805,17 @@ value_to_value_object (struct value *val)
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
be converted, set a Python exception and return NULL. */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 1330cd1..8fa8aeb 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -52,6 +52,10 @@ static PyMethodDef GdbMethods[];
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;
/* Given a command_line, return a command string suitable for passing
@@ -555,9 +559,13 @@ Enables or disables auto-loading of Python code when an object is opened."),
gdbpy_initialize_objfile ();
PyRun_SimpleString ("import gdb");
+ PyRun_SimpleString ("gdb.pretty_printers = []");
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__");
/* Create a couple objects which are used for Python's stdout and
diff --git a/gdb/python/python.h b/gdb/python/python.h
index e63c447..33b0437 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -26,4 +26,10 @@ extern struct value *values_in_python;
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 */
diff --git a/gdb/stack.c b/gdb/stack.c
index bf9e576..eb97eeb 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -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
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
@@ -220,6 +180,10 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
int args_printed = 0;
struct cleanup *old_chain, *list_chain;
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);
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 ();
ui_out_text (uiout, "=");
- if (print_this_frame_argument_p (sym))
+ if (print_args)
{
/* Avoid value_print because it will deref ref parameters.
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);
opts.deref_ref = 0;
- common_val_print (val, stb->stream, 2,
- &opts, language);
+ opts.summary = summary;
+ common_val_print (val, stb->stream, 2, &opts, language);
ui_out_field_stream (uiout, "value", stb);
}
else
diff --git a/gdb/testsuite/gdb.base/display.exp b/gdb/testsuite/gdb.base/display.exp
index d62e8bf..aa65373 100644
--- a/gdb/testsuite/gdb.base/display.exp
+++ b/gdb/testsuite/gdb.base/display.exp
@@ -180,8 +180,12 @@ gdb_test "printf \"%p\\n\", 1" "0x1"
# play with "print", too
#
-gdb_test "print/r j" ".*Undefined output format.*"
-gdb_test "print j" ".*" "debug test output"
+gdb_test "print/z j" ".*Undefined output format.*"
+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
if [istarget "hppa2.0w-hp-hpux11*"] {
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c
new file mode 100644
index 0000000..399be23
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.c
@@ -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 */
+}
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp
new file mode 100644
index 0000000..f83b1cd
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.exp
@@ -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++"
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py
new file mode 100644
index 0000000..493cf29
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.py
@@ -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)
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 5659f99..756dc50 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -34,6 +34,7 @@
#include "doublest.h"
#include "exceptions.h"
#include "dfp.h"
+#include "python/python.h"
#include <errno.h>
@@ -80,7 +81,9 @@ struct value_print_options user_print_options =
0, /* print_array_indexes */
0, /* deref_ref */
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. */
@@ -214,6 +217,33 @@ show_addressprint (struct ui_file *file, int from_tty,
}
\f
+/* 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
(within GDB), which came from the inferior at address ADDRESS, onto
stdio stream STREAM according to OPTIONS.
@@ -257,6 +287,23 @@ val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
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)
{
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))
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);
}
diff --git a/gdb/valprint.h b/gdb/valprint.h
index 90dcdc2..4f63fa6 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -84,6 +84,12 @@ struct value_print_options
/* If nonzero, print static fields for Pascal. FIXME: C++ and Java
share one flag, why not Pascal too? */
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
--
1.6.0.6
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 1:08 ` Tom Tromey
@ 2009-04-09 7:40 ` Eli Zaretskii
2009-04-09 16:16 ` Tom Tromey
0 siblings, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2009-04-09 7:40 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> From: Tom Tromey <tromey@redhat.com>
> Date: Wed, 08 Apr 2009 19:07:52 -0600
>
> Here is the new version of this patch.
>
> I think I have addressed all the comments; either by making the
> requested change or explaining why I did not. Still, you probably
> should check.
Thanks. I have 2 minor comments:
> +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.
I couldn't quite understand the importance of the version numbers, and
how that would allow GDB to have multiple versions of the same
pretty-printer. I asked myself how the ``right'' version will be
selected in that case. Is the way this works documented somewhere
else? if so, a cross-reference here would be good. If not, I think we
need to say a few words about that.
> +You should write auto-loaded code such that it can be evaluated
> +multiple times without changing its meaning.
Here, I suggest a cross-reference to where auto-loading is described.
Otherwise, this patch for the manual is fine with me.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 0:52 ` Tom Tromey
@ 2009-04-09 15:00 ` Thiago Jung Bauermann
2009-04-09 15:19 ` Phil Muldoon
2009-04-09 15:44 ` Tom Tromey
2009-04-09 19:37 ` Tom Tromey
1 sibling, 2 replies; 20+ messages in thread
From: Thiago Jung Bauermann @ 2009-04-09 15:00 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches ml
El mié, 08-04-2009 a las 18:52 -0600, Tom Tromey escribió:
> >>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes:
> Tom> +find_pretty_printer (PyObject *value)
>
> Thiago> Also, if this function returns NULL, sometimes a Python exception will
> Thiago> be set, sometimes it won't. Is this intended? If so, this should be
> Thiago> noted.
>
> I looked again and I don't see how it can return NULL without setting
> the exception. Can you point it out to me?
I can't find it either, now. Should have pointed out the first time
around. :-( I probably thought search_pp_list could return NULL without
setting a Python exception, and because of this find_pretty_printer
would blindly return NULL too. But I can't find that case anymore. I
probably made a mistake.
I found one potential problem, which could cause the function to return
NULL without an exception being set (it's not the case I thought of
before, I think): suppose there's no objfile Python object when this
function is called, to the ALL_OBJFILES loop will skip all objs, then
the gdb module has no pretty_printers attribute, or the pretty_printers
value is not a list object. In that case, the function will return NULL
without a Python exception being set. Can it happen?
Also, I noticed that the function may return Py_None if no
pretty-printer is found, and the callers even expect that. The function
comment needs to be fixed then:
/* Find the pretty-printing constructor function for TYPE. If no
pretty-printer exists, return NULL. If one exists, return a new
reference. */
> Thiago> Because of this, pretty_print_one_value can now probably just call
> Thiago> convert_value_from_python and return a struct value in all cases and be
> Thiago> done with it. Either this function should be changed to work that way,
> Thiago> or the comment above removed.
>
> I made the minimal change here. I don't want to refactor this right
> now; Phil is in the middle of doing that for the embedded \0 problem.
> We can apply his fix separately; the current code is not ideal, due to
> this problem, but it is still usable for a variety of printers.
Fine with me.
> Tom> +char *
> Tom> +gdbpy_get_display_hint (PyObject *printer)
>
> Thiago> I use the *py_ prefix for functions that can be directly called from
> Thiago> Python. I think it's a useful hint. I don't think I ever mentioned this
> Thiago> practice though.
>
> Thiago> If you agree it's useful, this method should be renamed to not use the
> Thiago> gdbpy_ prefix.
>
> I am leaving this for now. We use the gdbpy_ prefix inconsistently,
> even in CVS gdb, and I would prefer to see a single cleanup if we are
> going to adopt a solid naming convention.
Alright.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 15:00 ` Thiago Jung Bauermann
@ 2009-04-09 15:19 ` Phil Muldoon
2009-04-09 15:41 ` Thiago Jung Bauermann
2009-04-09 15:44 ` Tom Tromey
1 sibling, 1 reply; 20+ messages in thread
From: Phil Muldoon @ 2009-04-09 15:19 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Tom Tromey, gdb-patches ml
Thiago Jung Bauermann wrote:
> El mié, 08-04-2009 a las 18:52 -0600, Tom Tromey escribió:
>
>> I looked again and I don't see how it can return NULL without setting
>> the exception. Can you point it out to me?
>>
>
> I found one potential problem, which could cause the function to return
> NULL without an exception being set (it's not the case I thought of
> before, I think): suppose there's no objfile Python object when this
> function is called, to the ALL_OBJFILES loop will skip all objs, then
> the gdb module has no pretty_printers attribute, or the pretty_printers
> value is not a list object. In that case, the function will return NULL
> without a Python exception being set. Can it happen?
>
>
This would require the gdb.pretty_printers attribute in the code to be
changed from a list to something else (or removed for the not existing
scenario). Anyway it would require a conscious code change on behalf of
another author, and not an environmental change. It could happen if
somebody changed the code, but I suspect (in this scenario) it would
fail long before it reached here.
> Also, I noticed that the function may return Py_None if no
> pretty-printer is found, and the callers even expect that. The function
> comment needs to be fixed then:
>
> /* Find the pretty-printing constructor function for TYPE. If no
> pretty-printer exists, return NULL. If one exists, return a new
> reference. */
>
>
Yes, my fault. Missed this :(
>> Thiago> Because of this, pretty_print_one_value can now probably just call
>> Thiago> convert_value_from_python and return a struct value in all cases and be
>> Thiago> done with it. Either this function should be changed to work that way,
>> Thiago> or the comment above removed.
>>
>> I made the minimal change here. I don't want to refactor this right
>> now; Phil is in the middle of doing that for the embedded \0 problem.
>> We can apply his fix separately; the current code is not ideal, due to
>> this problem, but it is still usable for a variety of printers.
>>
>
> Fine with me.
>
>
I'm in the middle of this right now. I'm putting the finishing touches
on the optional string fetch parameter from the comments posted to the
archer list, and will start work on fixing string output.
Regards
Phil
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 15:19 ` Phil Muldoon
@ 2009-04-09 15:41 ` Thiago Jung Bauermann
2009-04-09 16:18 ` Tom Tromey
0 siblings, 1 reply; 20+ messages in thread
From: Thiago Jung Bauermann @ 2009-04-09 15:41 UTC (permalink / raw)
To: Phil Muldoon; +Cc: Tom Tromey, gdb-patches ml
El jue, 09-04-2009 a las 16:19 +0100, Phil Muldoon escribió:
> Thiago Jung Bauermann wrote:
> > I found one potential problem, which could cause the function to return
> > NULL without an exception being set (it's not the case I thought of
> > before, I think): suppose there's no objfile Python object when this
> > function is called, to the ALL_OBJFILES loop will skip all objs, then
> > the gdb module has no pretty_printers attribute, or the pretty_printers
> > value is not a list object. In that case, the function will return NULL
> > without a Python exception being set. Can it happen?
>
> This would require the gdb.pretty_printers attribute in the code to be
> changed from a list to something else (or removed for the not existing
> scenario). Anyway it would require a conscious code change on behalf of
> another author, and not an environmental change. It could happen if
> somebody changed the code, but I suspect (in this scenario) it would
> fail long before it reached here.
I wonder if the pretty printing code in general would be better off
manipulating pretty_printers as a Sequence object, instead of a List.
After all, the OO people say you never know when you want to change your
implementation from a List to a FunkyStringOfObjects. :-)
I think me asking this to be changed would be pedantic, though. I agree
with you in that there's no real problem here.
> I'm in the middle of this right now. I'm putting the finishing touches
> on the optional string fetch parameter from the comments posted to the
> archer list, and will start work on fixing string output.
Awesome! I'm owing you an e-mail reply. Will do right now.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 15:00 ` Thiago Jung Bauermann
2009-04-09 15:19 ` Phil Muldoon
@ 2009-04-09 15:44 ` Tom Tromey
1 sibling, 0 replies; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 15:44 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches ml
>>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes:
Thiago> I found one potential problem, which could cause the function to return
Thiago> NULL without an exception being set (it's not the case I thought of
Thiago> before, I think): suppose there's no objfile Python object when this
Thiago> function is called, to the ALL_OBJFILES loop will skip all objs, then
Thiago> the gdb module has no pretty_printers attribute, or the pretty_printers
Thiago> value is not a list object. In that case, the function will return NULL
Thiago> without a Python exception being set. Can it happen?
Yes, I see it now:
/* Fetch the global pretty printer dictionary. */
if (! PyObject_HasAttrString (gdb_module, "pretty_printers"))
goto done;
That is the bad branch. Thanks.
Also, I think here:
PyObject *objf = objfile_to_objfile_object (obj);
if (!objf)
continue;
... we need to clear the python error.
I will make the needed changes.
Thiago> Also, I noticed that the function may return Py_None if no
Thiago> pretty-printer is found, and the callers even expect that. The function
Thiago> comment needs to be fixed then:
Thanks.
Tom
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 7:40 ` Eli Zaretskii
@ 2009-04-09 16:16 ` Tom Tromey
2009-04-09 16:41 ` Eli Zaretskii
0 siblings, 1 reply; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 16:16 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
Eli> I couldn't quite understand the importance of the version numbers, and
Eli> how that would allow GDB to have multiple versions of the same
Eli> pretty-printer. I asked myself how the ``right'' version will be
Eli> selected in that case. Is the way this works documented somewhere
Eli> else? if so, a cross-reference here would be good. If not, I think we
Eli> need to say a few words about that.
I modified a couple of paragraphs; the text now reads:
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
[...]
>> +You should write auto-loaded code such that it can be evaluated
>> +multiple times without changing its meaning.
Eli> Here, I suggest a cross-reference to where auto-loading is described.
I added this.
Tom
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 15:41 ` Thiago Jung Bauermann
@ 2009-04-09 16:18 ` Tom Tromey
0 siblings, 0 replies; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 16:18 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Phil Muldoon, gdb-patches ml
>>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes:
Thiago> I wonder if the pretty printing code in general would be
Thiago> better off manipulating pretty_printers as a Sequence object,
Thiago> instead of a List.
Yeah, I agree. We can comfortably relax this at any later point,
though.
Tom
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 16:16 ` Tom Tromey
@ 2009-04-09 16:41 ` Eli Zaretskii
0 siblings, 0 replies; 20+ messages in thread
From: Eli Zaretskii @ 2009-04-09 16:41 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
> Cc: gdb-patches@sourceware.org
> From: Tom Tromey <tromey@redhat.com>
> Date: Thu, 09 Apr 2009 10:16:21 -0600
>
> Eli> I couldn't quite understand the importance of the version numbers, and
> Eli> how that would allow GDB to have multiple versions of the same
> Eli> pretty-printer. I asked myself how the ``right'' version will be
> Eli> selected in that case. Is the way this works documented somewhere
> Eli> else? if so, a cross-reference here would be good. If not, I think we
> Eli> need to say a few words about that.
>
> I modified a couple of paragraphs; the text now reads:
Thanks, now even I understand.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 0:52 ` Tom Tromey
2009-04-09 15:00 ` Thiago Jung Bauermann
@ 2009-04-09 19:37 ` Tom Tromey
2009-04-09 22:09 ` Thiago Jung Bauermann
1 sibling, 1 reply; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 19:37 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches ml
Thiago wanted to see the latest version of this patch, so here it is.
Tom
2009-04-01 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-04-01 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-04-01 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.
gdb/ChangeLog | 42 ++
gdb/Makefile.in | 6 +
gdb/cp-valprint.c | 28 +-
gdb/doc/ChangeLog | 10 +
gdb/doc/gdb.texinfo | 222 ++++++++++-
gdb/printcmd.c | 21 +-
gdb/python/python-internal.h | 7 +
gdb/python/python-prettyprint.c | 524 +++++++++++++++++++++++
gdb/python/python-value.c | 11 +
gdb/python/python.c | 8 +
gdb/python/python.h | 6 +
gdb/stack.c | 50 +--
gdb/testsuite/ChangeLog | 10 +
gdb/testsuite/gdb.base/display.exp | 8 +-
gdb/testsuite/gdb.python/python-prettyprint.c | 191 ++++++++
gdb/testsuite/gdb.python/python-prettyprint.exp | 92 ++++
gdb/testsuite/gdb.python/python-prettyprint.py | 151 +++++++
gdb/valprint.c | 61 +++-
gdb/valprint.h | 6 +
19 files changed, 1399 insertions(+), 55 deletions(-)
create mode 100644 gdb/python/python-prettyprint.c
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.c
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.exp
create mode 100644 gdb/testsuite/gdb.python/python-prettyprint.py
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 685b001..b1e4171 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -269,6 +269,7 @@ SUBDIR_PYTHON_OBS = \
python-frame.o \
python-function.o \
python-objfile.o \
+ python-prettyprint.o \
python-type.o \
python-utils.o \
python-value.o
@@ -278,6 +279,7 @@ SUBDIR_PYTHON_SRCS = \
python/python-frame.c \
python/python-function.c \
python/python-objfile.c \
+ python/python-prettyprint.c \
python/python-type.c \
python/python-utils.c \
python/python-value.c
@@ -1865,6 +1867,10 @@ python-objfile.o: $(srcdir)/python/python-objfile.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-objfile.c
$(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
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-type.c
$(POSTCOMPILE)
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 181b4ff..d264b40 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -36,6 +36,7 @@
#include "valprint.h"
#include "cp-support.h"
#include "language.h"
+#include "python/python.h"
/* Controls printing of vtbl's */
static void
@@ -418,12 +419,27 @@ cp_print_value (struct type *type, struct type *real_type,
if (skip >= 1)
fprintf_filtered (stream, "<invalid address>");
else
- cp_print_value_fields (baseclass, thistype, base_valaddr,
- thisoffset + boffset, address + boffset,
- stream, recurse, options,
- ((struct type **)
- obstack_base (&dont_print_vb_obstack)),
- 0);
+ {
+ int result = 0;
+
+ /* Attempt to run the Python pretty-printers on the
+ baseclass if possible. */
+ 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);
flush_it:
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5057e73..1c72dc6 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6577,6 +6577,12 @@ Without this format, @value{GDBN} displays pointers to and arrays of
@code{char}, @w{@code{unsigned char}}, and @w{@code{signed char}} as
strings. Single-byte members of a vector are displayed as an integer
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
For example, to print the program counter in hex (@pxref{Registers}), type
@@ -18301,6 +18307,8 @@ situation, a Python @code{KeyboardInterrupt} exception is thrown.
* Auto-loading:: Automatically loading Python code.
* Values From Inferior::
* 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.
* Functions In Python:: Writing new convenience functions.
* Objfiles In Python:: Object files.
@@ -18828,6 +18836,217 @@ A function internal to @value{GDBN}. This is the type used to represent
convenience functions.
@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, 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
@subsubsection Commands In Python
@@ -19180,7 +19399,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
function in order; if the function returns @code{None}, then the
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
@node Frames In Python
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index cab7032..4cb681f 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -68,11 +68,15 @@ struct format_data
int count;
char format;
char size;
+
+ /* True if the value should be printed raw -- that is, bypassing
+ python-based formatters. */
+ unsigned char raw;
};
/* Last specified output format. */
-static char last_format = 'x';
+static char last_format = 0;
/* 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.size = '?';
val.count = 1;
+ val.raw = 0;
if (*p >= '0' && *p <= '9')
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')
val.size = *p++;
+ else if (*p == 'r')
+ {
+ val.raw = 1;
+ p++;
+ }
else if (*p >= 'a' && *p <= 'z')
val.format = *p++;
else
@@ -874,6 +884,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
fmt.count = 1;
fmt.format = 0;
fmt.size = 0;
+ fmt.raw = 0;
}
if (exp && *exp)
@@ -909,6 +920,7 @@ print_command_1 (char *exp, int inspect, int voidprint)
get_formatted_print_options (&opts, format);
opts.inspect_it = inspect;
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
printf_filtered ("\n");
@@ -959,6 +971,7 @@ output_command (char *exp, int from_tty)
struct value_print_options opts;
fmt.size = 0;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
@@ -976,6 +989,7 @@ output_command (char *exp, int from_tty)
annotate_value_begin (value_type (val));
get_formatted_print_options (&opts, format);
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
annotate_value_end ();
@@ -1296,9 +1310,10 @@ x_command (char *exp, int from_tty)
struct cleanup *old_chain;
struct value *val;
- fmt.format = last_format;
+ fmt.format = last_format ? last_format : 'x';
fmt.size = last_size;
fmt.count = 1;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
@@ -1402,6 +1417,7 @@ display_command (char *exp, int from_tty)
fmt.format = 0;
fmt.size = 0;
fmt.count = 0;
+ fmt.raw = 0;
}
innermost_block = NULL;
@@ -1613,6 +1629,7 @@ do_one_display (struct display *d)
annotate_display_expression ();
get_formatted_print_options (&opts, d->format.format);
+ opts.raw = d->format.raw;
print_formatted (evaluate_expression (d->exp),
d->format.size, &opts, gdb_stdout);
printf_filtered ("\n");
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 819867f..983d24d 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -33,6 +33,7 @@
#if HAVE_LIBPYTHON2_4
#include "python2.4/Python.h"
+#include "python2.4/frameobject.h"
/* 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
compilation due to several apparent mistakes in python2.4 API, so we
@@ -40,8 +41,10 @@
typedef int Py_ssize_t;
#elif HAVE_LIBPYTHON2_5
#include "python2.5/Python.h"
+#include "python2.5/frameobject.h"
#elif HAVE_LIBPYTHON2_6
#include "python2.6/Python.h"
+#include "python2.6/frameobject.h"
#else
#error "Unable to find usable Python.h"
#endif
@@ -74,6 +77,7 @@ PyObject *objfile_to_objfile_object (struct objfile *);
PyObject *objfpy_get_printers (PyObject *, void *);
+struct value *value_object_to_value (PyObject *self);
struct value *convert_value_from_python (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);
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 */
diff --git a/gdb/python/python-prettyprint.c b/gdb/python/python-prettyprint.c
new file mode 100644
index 0000000..5be4f36
--- /dev/null
+++ b/gdb/python/python-prettyprint.c
@@ -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 */
diff --git a/gdb/python/python-value.c b/gdb/python/python-value.c
index 76f5cde..46af318 100644
--- a/gdb/python/python-value.c
+++ b/gdb/python/python-value.c
@@ -805,6 +805,17 @@ value_to_value_object (struct value *val)
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
be converted, set a Python exception and return NULL. */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 701a931..19098cc 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -52,6 +52,10 @@ static PyMethodDef GdbMethods[];
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;
/* 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 ();
PyRun_SimpleString ("import gdb");
+ PyRun_SimpleString ("gdb.pretty_printers = []");
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__");
/* Create a couple objects which are used for Python's stdout and
diff --git a/gdb/python/python.h b/gdb/python/python.h
index e63c447..33b0437 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -26,4 +26,10 @@ extern struct value *values_in_python;
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 */
diff --git a/gdb/stack.c b/gdb/stack.c
index dfe3900..381e0ea 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -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
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
@@ -220,6 +180,10 @@ print_frame_args (struct symbol *func, struct frame_info *frame,
int args_printed = 0;
struct cleanup *old_chain, *list_chain;
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);
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 ();
ui_out_text (uiout, "=");
- if (print_this_frame_argument_p (sym))
+ if (print_args)
{
/* Avoid value_print because it will deref ref parameters.
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);
opts.deref_ref = 0;
- common_val_print (val, stb->stream, 2,
- &opts, language);
+ opts.summary = summary;
+ common_val_print (val, stb->stream, 2, &opts, language);
ui_out_field_stream (uiout, "value", stb);
}
else
diff --git a/gdb/testsuite/gdb.base/display.exp b/gdb/testsuite/gdb.base/display.exp
index d62e8bf..aa65373 100644
--- a/gdb/testsuite/gdb.base/display.exp
+++ b/gdb/testsuite/gdb.base/display.exp
@@ -180,8 +180,12 @@ gdb_test "printf \"%p\\n\", 1" "0x1"
# play with "print", too
#
-gdb_test "print/r j" ".*Undefined output format.*"
-gdb_test "print j" ".*" "debug test output"
+gdb_test "print/z j" ".*Undefined output format.*"
+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
if [istarget "hppa2.0w-hp-hpux11*"] {
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c
new file mode 100644
index 0000000..399be23
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.c
@@ -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 */
+}
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.exp b/gdb/testsuite/gdb.python/python-prettyprint.exp
new file mode 100644
index 0000000..f83b1cd
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.exp
@@ -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++"
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py
new file mode 100644
index 0000000..493cf29
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-prettyprint.py
@@ -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)
diff --git a/gdb/valprint.c b/gdb/valprint.c
index 5659f99..756dc50 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -34,6 +34,7 @@
#include "doublest.h"
#include "exceptions.h"
#include "dfp.h"
+#include "python/python.h"
#include <errno.h>
@@ -80,7 +81,9 @@ struct value_print_options user_print_options =
0, /* print_array_indexes */
0, /* deref_ref */
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. */
@@ -214,6 +217,33 @@ show_addressprint (struct ui_file *file, int from_tty,
}
\f
+/* 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
(within GDB), which came from the inferior at address ADDRESS, onto
stdio stream STREAM according to OPTIONS.
@@ -257,6 +287,23 @@ val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
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)
{
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))
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);
}
diff --git a/gdb/valprint.h b/gdb/valprint.h
index 90dcdc2..4f63fa6 100644
--- a/gdb/valprint.h
+++ b/gdb/valprint.h
@@ -84,6 +84,12 @@ struct value_print_options
/* If nonzero, print static fields for Pascal. FIXME: C++ and Java
share one flag, why not Pascal too? */
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
--
1.6.0.6
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 19:37 ` Tom Tromey
@ 2009-04-09 22:09 ` Thiago Jung Bauermann
2009-04-09 22:36 ` Tom Tromey
0 siblings, 1 reply; 20+ messages in thread
From: Thiago Jung Bauermann @ 2009-04-09 22:09 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches ml
El jue, 09-04-2009 a las 13:37 -0600, Tom Tromey escribió:
> Thiago wanted to see the latest version of this patch, so here it is.
Thanks, just small nits.
> +The order in which the objfiles are searched is not specified. For a
> +given list, functions are always invoked from the head of the, and
s/from the head of the/from their head/ ?
> +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).
There shouldn't be a parenthesis at the end.
--
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Python pretty-printing [5/6]
2009-04-09 22:09 ` Thiago Jung Bauermann
@ 2009-04-09 22:36 ` Tom Tromey
0 siblings, 0 replies; 20+ messages in thread
From: Tom Tromey @ 2009-04-09 22:36 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: gdb-patches ml
>>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes:
Thiago> Thanks, just small nits.
[...]
Thanks. I fixed these.
Tom
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2009-04-09 22:36 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-02 20:57 Python pretty-printing [5/6] Tom Tromey
2009-04-03 15:29 ` Eli Zaretskii
2009-04-09 0:29 ` Tom Tromey
2009-04-04 16:39 ` Thiago Jung Bauermann
2009-04-09 0:52 ` Tom Tromey
2009-04-09 15:00 ` Thiago Jung Bauermann
2009-04-09 15:19 ` Phil Muldoon
2009-04-09 15:41 ` Thiago Jung Bauermann
2009-04-09 16:18 ` Tom Tromey
2009-04-09 15:44 ` Tom Tromey
2009-04-09 19:37 ` Tom Tromey
2009-04-09 22:09 ` Thiago Jung Bauermann
2009-04-09 22:36 ` Tom Tromey
2009-04-07 18:32 ` Joel Brobecker
2009-04-07 18:41 ` Tom Tromey
2009-04-07 20:38 ` Joel Brobecker
2009-04-09 1:08 ` Tom Tromey
2009-04-09 7:40 ` Eli Zaretskii
2009-04-09 16:16 ` Tom Tromey
2009-04-09 16:41 ` Eli Zaretskii
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox