From: andrew@ado.is-a-geek.net
To: gdb@sourceware.org
Cc: Andrew Oakley <andrew@ado.is-a-geek.net>
Subject: [PATCH] Allow nested python pretty printers.
Date: Tue, 16 Aug 2011 22:23:00 -0000 [thread overview]
Message-ID: <1313533386-3222-1-git-send-email-andrew@ado.is-a-geek.net> (raw)
In-Reply-To: <CAN9gPaHodL56VOOdhRAkq=re6j7EVgcHyFT4KONo34i-XJuQGg@mail.gmail.com>
From: Andrew Oakley <andrew@ado.is-a-geek.net>
I don't think this is quite ready to commit - MI support needs to be added and
documentation needs to be updated. I thought it was sensible to post it now
though so I can deal with any feedback and so that others don't find the need
to implement the same thing again.
Will resend to gdb-patches when I think it's ready.
By allowing the children iterator of pretty printers to return more
pretty printers multi levels of display can be created.
Most of the changes here are simple refactoring to make the desired APIs
avaliable:
- try_convert_value_from_python trys to convert a python PyObject to a
gdb struct value like convert_value_from_python but does not raise an
error if the PyObject type was not valid.
- run_pretty_printer performs all of the steps to print a value given a
pretty printer rather having this split between
apply_val_pretty_printer and print_children.
---
gdb/python/py-prettyprint.c | 69 +++++++++++++++++----------
gdb/python/py-value.c | 50 ++++++++++++-------
gdb/python/python-internal.h | 1 +
gdb/testsuite/gdb.python/py-prettyprint.c | 5 ++
gdb/testsuite/gdb.python/py-prettyprint.exp | 2 +
gdb/testsuite/gdb.python/py-prettyprint.py | 23 +++++++++
6 files changed, 107 insertions(+), 43 deletions(-)
diff --git a/gdb/python/py-prettyprint.c b/gdb/python/py-prettyprint.c
index b3660de..df71fdf 100644
--- a/gdb/python/py-prettyprint.c
+++ b/gdb/python/py-prettyprint.c
@@ -458,20 +458,31 @@ push_dummy_python_frame (void)
return (PyObject *) frame;
}
-/* Helper for apply_val_pretty_printer that formats children of the
- printer, if any exist. If is_py_none is true, then nothing has
- been printed by to_string, and format output accordingly. */
+/* Helper for apply_val_pretty_printer that runs a pretty printer,
+ including formattin of the children 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_py_none)
+run_pretty_printer (PyObject *printer, struct ui_file *stream, int recurse,
+ const struct value_print_options *options,
+ const struct language_defn *language,
+ struct gdbarch *gdbarch)
{
- int is_map, is_array, done_flag, pretty;
+ int is_py_none, is_map, is_array, done_flag, pretty;
unsigned int i;
PyObject *children, *iter, *frame;
struct cleanup *cleanups;
+ enum string_repr_result print_result;
+
+ /* If we are printing a map, we want some special formatting. */
+ char * hint = gdbpy_get_display_hint (printer);
+ cleanups = make_cleanup(free_current_contents, &hint);
+
+ /* Print the section */
+ print_result = print_string_repr (printer, hint, stream, recurse,
+ options, language, gdbarch);
+ if (print_result == string_repr_error)
+ return;
+
+ is_py_none = print_result == string_repr_none;
if (! PyObject_HasAttr (printer, gdbpy_children_cst))
return;
@@ -489,7 +500,7 @@ print_children (PyObject *printer, const char *hint,
return;
}
- cleanups = make_cleanup_py_decref (children);
+ make_cleanup_py_decref (children);
iter = PyObject_GetIter (children);
if (!iter)
@@ -634,15 +645,33 @@ print_children (PyObject *printer, const char *hint,
}
else
{
- struct value *value = convert_value_from_python (py_v);
+ struct value *value;
- if (value == NULL)
+ if (try_convert_value_from_python (py_v, &value))
+ {
+ if (value == NULL)
+ {
+ gdbpy_print_stack ();
+ error (_("Error while executing Python code."));
+ }
+ else
+ common_val_print (value, stream, recurse + 1, options,
+ language);
+ }
+ else if (PyObject_HasAttr (py_v, gdbpy_to_string_cst))
+ {
+ /* have another pretty printer to run */
+ run_pretty_printer (py_v, stream, recurse + 1, options, language,
+ gdbarch);
+ }
+ else
{
+ PyErr_Format (PyExc_TypeError,
+ _("Could not convert Python object: %s."),
+ PyString_AsString (PyObject_Str (py_v)));
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)
@@ -722,20 +751,10 @@ apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
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_result = print_string_repr (printer, hint, stream, recurse,
- options, language, gdbarch);
- if (print_result != string_repr_error)
- print_children (printer, hint, stream, recurse, options, language,
- print_result == string_repr_none);
+ run_pretty_printer (printer, stream, recurse, options, language, gdbarch);
result = 1;
-
done:
if (PyErr_Occurred ())
print_stack_unless_memory_error (stream);
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index fc5053a..dff3be6 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -1074,17 +1074,19 @@ value_object_to_value (PyObject *self)
}
/* Try to convert a Python value to a gdb value. If the value cannot
- be converted, set a Python exception and return NULL. Returns a
- reference to a new value on the all_values chain. */
-
-struct value *
-convert_value_from_python (PyObject *obj)
+ be converted because it was of the incorrect type return 0. If the value
+ was of the correct type set value to a reference to a new value on the
+ all_values chain and returns 1. If a Python exception occurs attempting to
+ convert the value then value is set to NULL and 1 is returned */
+int
+try_convert_value_from_python (PyObject *obj, struct value **value)
{
- struct value *value = NULL; /* -Wall */
+ int typeok = 1;
struct cleanup *old;
volatile struct gdb_exception except;
int cmp;
+ *value = NULL;
gdb_assert (obj != NULL);
TRY_CATCH (except, RETURN_MASK_ALL)
@@ -1093,14 +1095,14 @@ convert_value_from_python (PyObject *obj)
{
cmp = PyObject_IsTrue (obj);
if (cmp >= 0)
- value = value_from_longest (builtin_type_pybool, cmp);
+ *value = value_from_longest (builtin_type_pybool, cmp);
}
else if (PyInt_Check (obj))
{
long l = PyInt_AsLong (obj);
if (! PyErr_Occurred ())
- value = value_from_longest (builtin_type_pyint, l);
+ *value = value_from_longest (builtin_type_pyint, l);
}
else if (PyLong_Check (obj))
{
@@ -1124,7 +1126,7 @@ convert_value_from_python (PyObject *obj)
ul = PyLong_AsUnsignedLongLong (obj);
if (! PyErr_Occurred ())
- value = value_from_ulongest (builtin_type_upylong, ul);
+ *value = value_from_ulongest (builtin_type_upylong, ul);
}
else
/* There's nothing we can do. */
@@ -1134,14 +1136,14 @@ convert_value_from_python (PyObject *obj)
}
}
else
- value = value_from_longest (builtin_type_pylong, l);
+ *value = value_from_longest (builtin_type_pylong, l);
}
else if (PyFloat_Check (obj))
{
double d = PyFloat_AsDouble (obj);
if (! PyErr_Occurred ())
- value = value_from_double (builtin_type_pyfloat, d);
+ *value = value_from_double (builtin_type_pyfloat, d);
}
else if (gdbpy_is_string (obj))
{
@@ -1151,32 +1153,44 @@ convert_value_from_python (PyObject *obj)
if (s != NULL)
{
old = make_cleanup (xfree, s);
- value = value_cstring (s, strlen (s), builtin_type_pychar);
+ *value = value_cstring (s, strlen (s), builtin_type_pychar);
do_cleanups (old);
}
}
else if (PyObject_TypeCheck (obj, &value_object_type))
- value = value_copy (((value_object *) obj)->value);
+ *value = value_copy (((value_object *) obj)->value);
else if (gdbpy_is_lazy_string (obj))
{
PyObject *result;
result = PyObject_CallMethodObjArgs (obj, gdbpy_value_cst, NULL);
- value = value_copy (((value_object *) result)->value);
+ *value = value_copy (((value_object *) result)->value);
}
else
- PyErr_Format (PyExc_TypeError,
- _("Could not convert Python object: %s."),
- PyString_AsString (PyObject_Str (obj)));
+ typeok = 0;
}
if (except.reason < 0)
{
PyErr_Format (except.reason == RETURN_QUIT
? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
"%s", except.message);
- return NULL;
+ *value = NULL;
}
+ return typeok;
+}
+
+/* Try to convert a Python value to a gdb value. If the value cannot
+ be converted, set a Python exception and return NULL. Returns a
+ reference to a new value on the all_values chain. */
+struct value *
+convert_value_from_python (PyObject *obj)
+{
+ struct value * value;
+ if (!try_convert_value_from_python(obj, &value))
+ PyErr_Format (PyExc_TypeError,
+ _("Could not convert Python object: %s."),
+ PyString_AsString (PyObject_Str (obj)));
return value;
}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 996b23b..1cfaf75 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -180,6 +180,7 @@ PyObject *inferior_to_inferior_object (struct inferior *inferior);
struct block *block_object_to_block (PyObject *obj);
struct symbol *symbol_object_to_symbol (PyObject *obj);
struct value *value_object_to_value (PyObject *self);
+int try_convert_value_from_python (PyObject *obj, struct value **value);
struct value *convert_value_from_python (PyObject *obj);
struct type *type_object_to_type (PyObject *obj);
struct symtab *symtab_object_to_symtab (PyObject *obj);
diff --git a/gdb/testsuite/gdb.python/py-prettyprint.c b/gdb/testsuite/gdb.python/py-prettyprint.c
index 30f649c..10ab025 100644
--- a/gdb/testsuite/gdb.python/py-prettyprint.c
+++ b/gdb/testsuite/gdb.python/py-prettyprint.c
@@ -48,6 +48,10 @@ struct hint_error {
int x;
};
+struct nested_printer {
+ int x;
+};
+
#ifdef __cplusplus
struct S : public s {
int zs;
@@ -236,6 +240,7 @@ main ()
struct ns ns, ns2;
struct lazystring estring, estring2;
struct hint_error hint_error;
+ struct nested_printer nested_printer;
nstype.elements = narray;
nstype.len = 0;
diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp
index b0e7d62..f362cfd 100644
--- a/gdb/testsuite/gdb.python/py-prettyprint.exp
+++ b/gdb/testsuite/gdb.python/py-prettyprint.exp
@@ -102,6 +102,8 @@ proc run_lang_tests {exefile lang} {
gdb_test "print c" " = container \"container\" with 2 elements = {$nl *.0. = 23,$nl *.1. = 72$nl}"
+ gdb_test "print nested_printer" " = nested_printer_val = {$nl *child1 = child_val_1,$nl *child2 = child_val_2$nl}"
+
gdb_test "print nstype" " = {$nl *.0. = 7,$nl *.1. = 42$nl}"
gdb_test_no_output "set print pretty off"
diff --git a/gdb/testsuite/gdb.python/py-prettyprint.py b/gdb/testsuite/gdb.python/py-prettyprint.py
index 8bff3c0..be85682 100644
--- a/gdb/testsuite/gdb.python/py-prettyprint.py
+++ b/gdb/testsuite/gdb.python/py-prettyprint.py
@@ -187,6 +187,26 @@ class pp_outer:
yield 's', self.val['s']
yield 'x', self.val['x']
+class pp_nested_printer:
+ "Return a pretty printer as a child"
+
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return 'nested_printer_val'
+
+ def children(self):
+ class pp_child:
+ def __init__(self, val):
+ self.val = val
+
+ def to_string(self):
+ return self.val
+
+ yield 'child1', pp_child('child_val_1')
+ yield 'child2', pp_child('child_val_2')
+
class MemoryErrorString:
"Raise an error"
@@ -274,6 +294,9 @@ def register_pretty_printers ():
pretty_printers_dict[re.compile ('^struct hint_error$')] = pp_hint_error
pretty_printers_dict[re.compile ('^hint_error$')] = pp_hint_error
+ pretty_printers_dict[re.compile ('^struct nested_printer$')] = pp_nested_printer
+ pretty_printers_dict[re.compile ('^nested_printer$')] = pp_nested_printer
+
pretty_printers_dict[re.compile ('^memory_error$')] = MemoryErrorString
pretty_printers_dict = {}
--
1.7.3.4
next prev parent reply other threads:[~2011-08-16 22:23 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-14 16:11 Python API - nested pretty printers MI implications Andrew Oakley
2011-08-14 22:18 ` Daniel Jacobowitz
2011-08-15 12:36 ` André Pönitz
2011-08-15 13:26 ` Pedro Alves
2011-08-15 14:33 ` André Pönitz
2011-08-15 14:49 ` Pedro Alves
2011-08-15 15:36 ` André Pönitz
2011-08-16 22:12 ` Andrew Oakley
2011-08-16 22:23 ` andrew [this message]
2011-08-17 9:56 ` [PATCH] Allow nested python pretty printers Phil Muldoon
2011-08-17 13:28 ` Andrew Oakley
2011-08-15 12:58 ` Python API - nested pretty printers MI implications Pedro Alves
2011-08-15 14:06 ` Andrew Oakley
2011-08-15 14:30 ` Pedro Alves
2011-08-16 22:12 ` Andrew Oakley
2011-08-17 12:49 ` Pedro Alves
2011-08-17 18:31 ` Andrew Oakley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1313533386-3222-1-git-send-email-andrew@ado.is-a-geek.net \
--to=andrew@ado.is-a-geek.net \
--cc=gdb@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox