This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
Re: [python] [rfc] Patch for pretty-printers registration API change
Tom Tromey wrote:
Hi Tom,
Phil> + function = PyList_GetItem (list, list_index);
Phil> + if (function == NULL)
Phil> + Py_RETURN_NONE;
I think it is not valid to ignore Python errors like this. Instead, I
think you either have to propagate the exception (return NULL) or
clear it. I suspect propagation is the better answer.
I elected propagation. I was not terribly sure in the CLI case if I
should start applying the gdb error () and gdbpy_print_stack () inside
apply_val_pretty_printer () .. or allow the error to propagate further.
I elected to let them continue as that was the case beforehand. We can
easily change this. What do you think?
Phil> + printer = gdbpy_instantiate_printer (function, value);
Phil> + if (printer && (printer != Py_None))
Still too many parens :)
Fixed ;)
Also, the same comment holds about error propagation.
Phil> + val_obj = value_to_value_object (value);
This can fail, returning NULL. I think this particular line should
probably be moved out of the TRY_CATCH and after the
GDB_PY_HANDLE_EXCEPTION. Then, it needs an error check.
Fixed these NULL cases ... and ...
So, I think the value_copy logic
should probably be removed from find_pretty_printer and pushed into
the callers that need it. What do you think about that?
I think we should only copy it when needed per you suggestion. It adds a
bit more code, but cuts down on memory-clutter. I did this in the cases
I thought it was needed (mainly when I get passed a varobj). In any
case, there are only 3 in total. Please check and let me know if you
disagree in the copy cases and we'll fix it up.
Phil> + // Do not instantiate NoneType.
Phil> + if (constructor == Py_None)
...
The refcount logic for "None" here is not correct. I think the
simplest fix is to add an incref to the true branch of the first if
Fixed, and as a bonus I fixed a case in search_pp_list and
find_pretty_printer where they was not decrementing Py_None while
searching for printers (Py_RETURN_NONE as part of the macro incref's
Py_None).
Regards
Phil
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4408635..4371672 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18531,6 +18531,11 @@ target's @code{char} type will be an 8-bit byte. However, on some
unusual platforms, this type may have a different size.
@end defmethod
+@defmethod Type strip_typedefs
+Return a new @code{gdb.Type} that represents the real type,
+after removing all layers of typedefs.
+@end defmethod
+
@defmethod Type tag
Return the tag name for this type. The tag name is the name after
@code{struct}, @code{union}, or @code{enum} in C; not all languages
@@ -18791,30 +18796,27 @@ convertible to @code{gdb.Value}, an exception is raised.
@subsubsection Selecting Pretty-Printers
-The Python dictionary @code{gdb.pretty_printers} maps regular
-expressions (strings) onto constructors. Each @code{gdb.Objfile} also
-contains a @code{pretty_printers} attribute. A constructor, in this
-context, is a function which takes a single @code{gdb.Value} argument
-and returns a a pretty-printer conforming to the interface definition
-above.
+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}.
-When printing a value, @value{GDBN} first computes the value's
-canonical type by following typedefs, following a reference type to
-its referenced type, and removing qualifiers, such as @code{const} or
-@code{volatile}.
-
-Then, @value{GDBN} tests each regular expression against this type name.
@value{GDBN} first checks the @code{pretty_printers} attribute of each
-@code{gdb.Objfile}; after these have been exhausted it tries the
-global @code{gdb.pretty_printers}.
-
-If a regular expression matches, then the corresponding pretty-printer
-is invoked with a @code{gdb.Value} representing the value to be
-printed.
+@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.
-Similarly, the order in which the regular expressions in a given
-dictionary are tried 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:
@@ -18823,13 +18825,34 @@ written:
class StdStringPrinter:
"Print a std::string"
- def __init__(self, val):
+ def __init__ (self, val):
self.val = val
- def to_string(self):
+ def to_string (self):
return self.val['_M_dataplus']['_M_p']
@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,
@@ -18842,7 +18865,7 @@ For example, in addition to the above, this code might appear in
@smallexample
def register_printers (objfile):
- objfile.pretty_printers['^std::basic_string<char.*>$'] = StdStringPrinter
+ objfile.pretty_printers.add (str_lookup_function)
@end smallexample
And then the corresponding contents of the auto-load file would be:
diff --git a/gdb/python/lib/gdb/libstdcxx/v6/printers.py b/gdb/python/lib/gdb/libstdcxx/v6/printers.py
index c9c8543..b8c6d6f 100644
--- a/gdb/python/lib/gdb/libstdcxx/v6/printers.py
+++ b/gdb/python/lib/gdb/libstdcxx/v6/printers.py
@@ -1,6 +1,6 @@
# Pretty-printers for libstc++.
-# Copyright (C) 2008 Free Software Foundation, Inc.
+# 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
@@ -17,6 +17,7 @@
import gdb
import itertools
+import re
class StdPointerPrinter:
"Print a smart pointer of some kind"
@@ -546,56 +547,90 @@ class Tr1UnorderedMapPrinter:
def display_hint (self):
return 'map'
-def register_libstdcxx_printers(obj):
+def register_libstdcxx_printers (obj):
"Register libstdc++ pretty-printers with objfile Obj."
if obj == None:
obj = gdb
+ obj.pretty_printers.append (lookup_function)
+
+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.search (typename):
+ return pretty_printers_dict[function] (val)
+
+ # Cannot find a pretty printer. Return None.
+ return None
+
+def build_libstdcxx_dictionary ():
# libstdc++ objects requiring pretty-printing.
# In order from:
# http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
- obj.pretty_printers['^std::basic_string<char,.*>$'] = lambda val: StdStringPrinter(None, val)
- obj.pretty_printers['^std::basic_string<wchar_t,.*>$'] = lambda val: StdStringPrinter(target_wide_charset, val)
- obj.pretty_printers['^std::basic_string<char16_t,.*>$'] = lambda val: StdStringPrinter('UTF-16', val)
- obj.pretty_printers['^std::basic_string<char32_t,.*>$'] = lambda val: StdStringPrinter('UTF-32', val)
- obj.pretty_printers['^std::bitset<.*>$'] = StdBitsetPrinter
- obj.pretty_printers['^std::deque<.*>$'] = StdDequePrinter
- obj.pretty_printers['^std::list<.*>$'] = StdListPrinter
- obj.pretty_printers['^std::map<.*>$'] = lambda val: StdMapPrinter("std::map", val)
- obj.pretty_printers['^std::multimap<.*>$'] = lambda val: StdMapPrinter("std::multimap", val)
- obj.pretty_printers['^std::multiset<.*>$'] = lambda val: StdSetPrinter("std::multiset", val)
- obj.pretty_printers['^std::priority_queue<.*>$'] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val)
- obj.pretty_printers['^std::queue<.*>$'] = lambda val: StdStackOrQueuePrinter("std::queue", val)
- obj.pretty_printers['^std::set<.*>$'] = lambda val: StdSetPrinter("std::set", val)
- obj.pretty_printers['^std::stack<.*>$'] = lambda val: StdStackOrQueuePrinter("std::stack", val)
- obj.pretty_printers['^std::vector<.*>$'] = StdVectorPrinter
+ pretty_printers_dict[re.compile('^std::basic_string<char,.*>$')] = lambda val: StdStringPrinter(None, val)
+ pretty_printers_dict[re.compile('^std::basic_string<wchar_t,.*>$')] = lambda val: StdStringPrinter(target_wide_charset, val)
+ pretty_printers_dict[re.compile('^std::basic_string<char16_t,.*>$')] = lambda val: StdStringPrinter('UTF-16', val)
+ pretty_printers_dict[re.compile('^std::basic_string<char32_t,.*>$')] = lambda val: StdStringPrinter('UTF-32', val)
+ pretty_printers_dict[re.compile('^std::bitset<.*>$')] = StdBitsetPrinter
+ pretty_printers_dict[re.compile('^std::deque<.*>$')] = StdDequePrinter
+ pretty_printers_dict[re.compile('^std::list<.*>$')] = StdListPrinter
+ pretty_printers_dict[re.compile('^std::map<.*>$')] = lambda val: StdMapPrinter("std::map", val)
+ pretty_printers_dict[re.compile('^std::multimap<.*>$')] = lambda val: StdMapPrinter("std::multimap", val)
+ pretty_printers_dict[re.compile('^std::multiset<.*>$')] = lambda val: StdSetPrinter("std::multiset", val)
+ pretty_printers_dict[re.compile('^std::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val)
+ pretty_printers_dict[re.compile('^std::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::queue", val)
+ pretty_printers_dict[re.compile('^std::set<.*>$')] = lambda val: StdSetPrinter("std::set", val)
+ pretty_printers_dict[re.compile('^std::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::stack", val)
+ pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter
# vector<bool>
# C++0x stuff.
# array - the default seems reasonable
# smart_ptr? seems to only be in boost right now
- obj.pretty_printers['^std::tr1::shared_ptr<.*>$'] = lambda val: StdPointerPrinter ('std::shared_ptr', val)
- obj.pretty_printers['^std::tr1::weak_ptr<.*>$'] = lambda val: StdPointerPrinter ('std::weak_ptr', val)
- obj.pretty_printers['^std::tr1::unique_ptr<.*>$'] = UniquePointerPrinter
- obj.pretty_printers['^std::tr1::unordered_map<.*>$'] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val)
- obj.pretty_printers['^std::tr1::unordered_set<.*>$'] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val)
- obj.pretty_printers['^std::tr1::unordered_multimap<.*>$'] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val)
- obj.pretty_printers['^std::tr1::unordered_multiset<.*>$'] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val)
+ pretty_printers_dict[re.compile('^std::tr1::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val)
+ pretty_printers_dict[re.compile('^std::tr1::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val)
+ pretty_printers_dict[re.compile('^std::tr1::unique_ptr<.*>$')] = UniquePointerPrinter
+ pretty_printers_dict[re.compile('^std::tr1::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val)
+ pretty_printers_dict[re.compile('^std::tr1::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val)
+ pretty_printers_dict[re.compile('^std::tr1::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val)
+ pretty_printers_dict[re.compile('^std::tr1::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val)
# Extensions.
- obj.pretty_printers['^__gnu_cxx::slist<.*>$'] = StdSlistPrinter
+ pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter
if True:
# These shouldn't be necessary, if GDB "print *i" worked.
# But it often doesn't, so here they are.
- obj.pretty_printers['^std::_List_iterator<.*>$'] = lambda val: StdListIteratorPrinter(val)
- obj.pretty_printers['^std::_List_const_iterator<.*>$'] = lambda val: StdListIteratorPrinter(val)
- obj.pretty_printers['^std::_Rb_tree_iterator<.*>$'] = lambda val: StdRbtreeIteratorPrinter(val)
- obj.pretty_printers['^std::_Rb_tree_const_iterator<.*>$'] = lambda val: StdRbtreeIteratorPrinter(val)
- obj.pretty_printers['^std::_Deque_iterator<.*>$'] = lambda val: StdDequeIteratorPrinter(val)
- obj.pretty_printers['^std::_Deque_const_iterator<.*>$'] = lambda val: StdDequeIteratorPrinter(val)
- obj.pretty_printers['^__gnu_cxx::__normal_iterator<.*>$'] = lambda val: StdVectorIteratorPrinter(val)
- obj.pretty_printers['^__gnu_cxx::_Slist_iterator<.*>$'] = lambda val: StdSlistIteratorPrinter(val)
-
+ pretty_printers_dict[re.compile('^std::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
+ pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
+ pretty_printers_dict[re.compile('^std::_Rb_tree_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
+ pretty_printers_dict[re.compile('^std::_Rb_tree_const_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
+ pretty_printers_dict[re.compile('^std::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
+ pretty_printers_dict[re.compile('^std::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
+ pretty_printers_dict[re.compile('^__gnu_cxx::__normal_iterator<.*>$')] = lambda val: StdVectorIteratorPrinter(val)
+ pretty_printers_dict[re.compile('^__gnu_cxx::_Slist_iterator<.*>$')] = lambda val: StdSlistIteratorPrinter(val)
+
+pretty_printers_dict = {}
+
+build_libstdcxx_dictionary ()
register_libstdcxx_printers (gdb.current_objfile())
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index afdf821..e2fc9f1 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -161,8 +161,8 @@ int gdbpy_is_string (PyObject *obj);
other pretty-printer functions, because they refer to PyObject. */
char *apply_varobj_pretty_printer (PyObject *print_obj, struct value *value,
struct value **replacement);
-PyObject *gdbpy_get_varobj_pretty_printer (struct type *type);
-PyObject *gdbpy_instantiate_printer (PyObject *cons, struct value *value);
+PyObject *gdbpy_get_varobj_pretty_printer (struct value *value);
+PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value);
char *gdbpy_get_display_hint (PyObject *printer);
extern PyObject *gdbpy_children_cst;
diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c
index a225409..e97d3a2 100644
--- a/gdb/python/python-objfile.c
+++ b/gdb/python/python-objfile.c
@@ -1,6 +1,6 @@
/* Python interface to objfiles.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
@@ -29,7 +29,7 @@ typedef struct
/* The corresponding objfile. */
struct objfile *objfile;
- /* The pretty-printer dictionary. */
+ /* The pretty-printer list of functions. */
PyObject *printers;
} objfile_object;
@@ -66,7 +66,7 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
{
self->objfile = NULL;
- self->printers = PyDict_New ();
+ self->printers = PyList_New (0);
if (!self->printers)
{
Py_DECREF (self);
@@ -95,10 +95,10 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore)
return -1;
}
- if (! PyDict_Check (value))
+ if (! PyList_Check (value))
{
PyErr_SetString (PyExc_TypeError,
- "the pretty_printers attribute must be a dictionary");
+ "the pretty_printers attribute must be a list");
return -1;
}
@@ -139,7 +139,7 @@ objfile_to_objfile_object (struct objfile *objfile)
object->objfile = objfile;
- object->printers = PyDict_New ();
+ object->printers = PyList_New (0);
if (!object->printers)
{
Py_DECREF (object);
diff --git a/gdb/python/python-type.c b/gdb/python/python-type.c
index 5aa82f6..d336456 100644
--- a/gdb/python/python-type.c
+++ b/gdb/python/python-type.c
@@ -1,6 +1,6 @@
/* Python interface to types.
- Copyright (C) 2008 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
@@ -233,6 +233,15 @@ typy_tag (PyObject *self, PyObject *args)
return PyString_FromString (TYPE_TAG_NAME (type));
}
+/* Return the type, stripped of typedefs. */
+static PyObject *
+typy_strip_typedefs (PyObject *self, PyObject *args)
+{
+ struct type *type = ((type_object *) self)->type;
+
+ return type_to_type_object (check_typedef (type));
+}
+
/* Return a Type object which represents a pointer to SELF. */
static PyObject *
typy_pointer (PyObject *self, PyObject *args)
@@ -710,6 +719,8 @@ Each field is a dictionary." },
"Return the size of this type, in bytes" },
{ "tag", typy_tag, METH_NOARGS,
"Return the tag name for this type, or None." },
+ { "strip_typedefs", typy_strip_typedefs, METH_NOARGS,
+ "Return a type stripped of typedefs"},
{ "target", typy_target, METH_NOARGS,
"Return the target type of this type" },
{ "template_argument", typy_template_argument, METH_VARARGS,
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 8677da6..3897132 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -842,53 +842,47 @@ get_type (struct type *type)
}
/* Helper function for find_pretty_printer which iterates over a
- dictionary and tries to find a match. */
+ list, calls each function and inspects output. */
static PyObject *
-search_pp_dictionary (PyObject *dict, char *type_name)
+search_pp_list (PyObject *list, PyObject *value)
{
- Py_ssize_t iter;
- PyObject *key, *func, *found = NULL;
-
- /* See if the type matches a pretty-printer regexp. */
- iter = 0;
- while (! found && PyDict_Next (dict, &iter, &key, &func))
+ 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++)
{
- char *rx_str;
+ 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;
- if (! PyString_Check (key))
- continue;
- rx_str = PyString_AsString (key);
- if (re_comp (rx_str) == NULL && re_exec (type_name) == 1)
- found = func;
+ Py_DECREF (Py_None);
}
- return found;
+ 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 (struct type *type)
+find_pretty_printer (PyObject *value)
{
- PyObject *dict, *found = NULL;
- char *type_name = NULL;
+ PyObject *pp_list = NULL;
+ PyObject *function = NULL;
struct objfile *obj;
volatile struct gdb_exception except;
- /* Get the name of the type. */
- TRY_CATCH (except, RETURN_MASK_ALL)
- {
- /* If we have a reference, use the referenced type. */
- if (TYPE_CODE (type) == TYPE_CODE_REF)
- type = TYPE_TARGET_TYPE (type);
- /* Strip off any qualifiers from the type. */
- type = make_cv_type (0, 0, type, NULL);
- type_name = get_type (type);
- }
- if (except.reason < 0)
- return NULL;
-
/* Look at the pretty-printer dictionary for each objfile. */
ALL_OBJFILES (obj)
{
@@ -896,34 +890,43 @@ find_pretty_printer (struct type *type)
if (!objf)
continue;
- dict = objfpy_get_printers (objf, NULL);
- found = search_pp_dictionary (dict, type_name);
- if (found)
- goto done;
+ 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;
+ }
- Py_DECREF (dict);
+ if (function && 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. */
- dict = NULL;
if (! PyObject_HasAttrString (gdb_module, "pretty_printers"))
goto done;
- dict = PyObject_GetAttrString (gdb_module, "pretty_printers");
- if (! dict)
+ pp_list = PyObject_GetAttrString (gdb_module, "pretty_printers");
+ if (! pp_list)
goto done;
- if (! PyDict_Check (dict) || ! PyDict_Size (dict))
+ if (! PyList_Check (pp_list))
goto done;
- found = search_pp_dictionary (dict, type_name);
+ function = search_pp_list (pp_list, value);
done:
- xfree (type_name);
-
- if (found)
- Py_INCREF (found);
- Py_XDECREF (dict);
-
- return found;
+ Py_XDECREF (pp_list);
+
+ return function;
}
/* Pretty-print a single value, via the printer object PRINTER. If
@@ -964,24 +967,13 @@ pretty_print_one_value (PyObject *printer, struct value **out_value)
}
/* Instantiate a pretty-printer given a constructor, CONS, and a
- value, VAL. Return NULL on error. */
+ value, VAL. Return NULL on error. Ownership of the object
+ instance is transferred to the reciever */
PyObject *
-gdbpy_instantiate_printer (PyObject *cons, struct value *value)
+gdbpy_instantiate_printer (PyObject *cons, PyObject *value)
{
- PyObject *val_obj = NULL, *result;
- volatile struct gdb_exception except;
-
- TRY_CATCH (except, RETURN_MASK_ALL)
- {
- /* FIXME: memory management here. Why are values so
- funny? */
- value = value_copy (value);
- val_obj = value_to_value_object (value);
- }
- GDB_PY_HANDLE_EXCEPTION (except);
-
- result = PyObject_CallFunctionObjArgs (cons, val_obj, NULL);
- Py_DECREF (val_obj);
+ PyObject *result;
+ result = PyObject_CallFunctionObjArgs (cons, value, NULL);
return result;
}
@@ -1174,9 +1166,12 @@ print_children (PyObject *printer, const char *hint,
if (! item)
{
+ if (PyErr_Occurred ())
+ gdbpy_print_stack ();
/* Set a flag so we can know whether we printed all the
available elements. */
- done_flag = 1;
+ else
+ done_flag = 1;
break;
}
@@ -1296,7 +1291,8 @@ apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
const struct value_print_options *options,
const struct language_defn *language)
{
- PyObject *func, *printer;
+ PyObject *printer = NULL;
+ PyObject *val_obj = NULL;
struct value *value;
char *hint = NULL;
struct cleanup *cleanups;
@@ -1306,36 +1302,30 @@ apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
state = PyGILState_Ensure ();
cleanups = make_cleanup_py_restore_gil (&state);
- /* Find the constructor. */
- func = find_pretty_printer (type);
- if (! func)
- goto done;
-
/* Instantiate the printer. */
if (valaddr)
valaddr += embedded_offset;
value = value_from_contents_and_address (type, valaddr, address);
- printer = gdbpy_instantiate_printer (func, value);
- Py_DECREF (func);
- if (!printer)
- {
- gdbpy_print_stack ();
- goto done;
- }
+ val_obj = value_to_value_object (value);
+ if (! val_obj)
+ goto done;
+
+ /* Find the constructor. */
+ printer = find_pretty_printer (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);
- make_cleanup_py_decref (printer);
- if (printer != Py_None)
- {
- print_string_repr (printer, hint, stream, recurse, options, language);
- print_children (printer, hint, stream, recurse, options, language);
+ /* Print the section */
+ print_string_repr (printer, hint, stream, recurse, options, language);
+ print_children (printer, hint, stream, recurse, options, language);
+ result = 1;
- result = 1;
- }
done:
do_cleanups (cleanups);
@@ -1367,13 +1357,29 @@ apply_varobj_pretty_printer (PyObject *printer_obj, struct value *value,
}
/* Find a pretty-printer object for the varobj module. Returns a new
- reference to the object if successful; returns NULL if not. TYPE
- is the type of the varobj for which a printer should be
- returned. */
+ reference to the object if successful; returns NULL if not. VALUE
+ is the value for which a printer tests to determine if it
+ can pretty-print the value. */
PyObject *
-gdbpy_get_varobj_pretty_printer (struct type *type)
+gdbpy_get_varobj_pretty_printer (struct value *value)
{
- return find_pretty_printer (type);
+ PyObject *val_obj;
+ PyObject *pretty_printer = NULL;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ value = value_copy (value);
+ }
+ GDB_PY_HANDLE_EXCEPTION (except);
+
+ val_obj = value_to_value_object (value);
+ if (! val_obj)
+ return NULL;
+
+ pretty_printer = find_pretty_printer (val_obj);
+ Py_DECREF (val_obj);
+ return pretty_printer;
}
/* A Python function which wraps find_pretty_printer and instantiates
@@ -1396,24 +1402,8 @@ gdbpy_default_visualizer (PyObject *self, PyObject *args)
return NULL;
}
- cons = find_pretty_printer (value_type (value));
- if (cons)
- {
- /* While it is a bit lame to pass value here and make a new
- Value, it is probably better to share the instantiation
- code. */
- printer = gdbpy_instantiate_printer (cons, value);
- Py_DECREF (cons);
- }
-
- if (!printer)
- {
- PyErr_Clear ();
- printer = Py_None;
- Py_INCREF (printer);
- }
-
- return printer;
+ cons = find_pretty_printer (val_obj);
+ return cons;
}
#else /* HAVE_PYTHON */
@@ -1566,7 +1556,7 @@ Enables or disables auto-loading of Python code when an object is opened."),
gdbpy_initialize_membuf ();
PyRun_SimpleString ("import gdb");
- PyRun_SimpleString ("gdb.pretty_printers = {}");
+ PyRun_SimpleString ("gdb.pretty_printers = []");
observer_attach_new_objfile (gdbpy_new_objfile);
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.py b/gdb/testsuite/gdb.python/python-prettyprint.py
index ecd4fc6..0d9cb87 100644
--- a/gdb/testsuite/gdb.python/python-prettyprint.py
+++ b/gdb/testsuite/gdb.python/python-prettyprint.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2008 Free Software Foundation, Inc.
+# 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
@@ -16,6 +16,8 @@
# 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):
@@ -76,21 +78,57 @@ class pp_sss:
def to_string(self):
return "a=<" + str(self.val['a']) + "> b=<" + str(self.val["b"]) + ">"
-gdb.pretty_printers['^struct s$'] = pp_s
-gdb.pretty_printers['^s$'] = pp_s
-gdb.pretty_printers['^S$'] = pp_s
-
-gdb.pretty_printers['^struct ss$'] = pp_ss
-gdb.pretty_printers['^ss$'] = pp_ss
-
-gdb.pretty_printers['^const S &$'] = pp_s
-gdb.pretty_printers['^SSS$'] = pp_sss
-
-# 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.
-gdb.pretty_printers['^struct string_repr$'] = string_print
-gdb.pretty_printers['^struct container$'] = ContainerPrinter
-gdb.pretty_printers['^string_repr$'] = string_print
-gdb.pretty_printers['^container$'] = ContainerPrinter
+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
+
+ # 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/varobj.c b/gdb/varobj.c
index 7f77902..150d8f8 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -181,10 +181,6 @@ struct varobj
int from;
int to;
- /* If NULL, no pretty printer is installed. If not NULL, the
- constructor to call to get a pretty-printer object. */
- PyObject *constructor;
-
/* The pretty-printer that has been constructed. If NULL, then a
new printer object is needed, and one will be constructed. */
PyObject *pretty_printer;
@@ -711,21 +707,29 @@ varobj_delete (struct varobj *var, char ***dellist, int only_children)
return delcount;
}
-/* Instantiate a pretty-printer for a given value. */
+/* Convenience function for varobj_set_visualizer. Instantiate a
+ pretty-printer for a given value. */
static PyObject *
-instantiate_pretty_printer (struct varobj *var, struct value *value)
+instantiate_pretty_printer (PyObject *constructor, struct value *value)
{
#if HAVE_PYTHON
- if (var->constructor)
+ PyObject *val_obj = NULL;
+ PyObject *printer;
+ volatile struct gdb_exception except;
+
+ TRY_CATCH (except, RETURN_MASK_ALL)
{
- PyObject *printer = gdbpy_instantiate_printer (var->constructor, value);
- if (printer == Py_None)
- {
- Py_DECREF (printer);
- printer = NULL;
- }
- return printer;
+ value = value_copy (value);
}
+ GDB_PY_HANDLE_EXCEPTION (except);
+ val_obj = value_to_value_object (value);
+
+ if (! val_obj)
+ return NULL;
+
+ printer = gdbpy_instantiate_printer (constructor, val_obj);
+ Py_DECREF (val_obj);
+ return printer;
#endif
return NULL;
}
@@ -1224,7 +1228,7 @@ install_new_value (struct varobj *var, struct value *value, int initial)
/* If the type has custom visualizer, we consider it to be always
changeable. FIXME: need to make sure this behaviour will not
mess up read-sensitive values. */
- if (var->constructor)
+ if (var->pretty_printer)
changeable = 1;
need_to_fetch = changeable;
@@ -1278,20 +1282,6 @@ install_new_value (struct varobj *var, struct value *value, int initial)
}
}
-#if HAVE_PYTHON
- {
- PyGILState_STATE state = PyGILState_Ensure ();
- if (var->pretty_printer)
- {
- Py_DECREF (var->pretty_printer);
- }
- if (value)
- var->pretty_printer = instantiate_pretty_printer (var, value);
- else
- var->pretty_printer = NULL;
- PyGILState_Release (state);
- }
-#endif
/* Below, we'll be comparing string rendering of old and new
values. Don't get string rendering if the value is
@@ -1408,11 +1398,8 @@ install_visualizer (struct varobj *var, PyObject *visualizer)
varobj_delete (var, NULL, 1 /* children only */);
var->num_children = -1;
- Py_XDECREF (var->constructor);
- var->constructor = visualizer;
-
Py_XDECREF (var->pretty_printer);
- var->pretty_printer = NULL;
+ var->pretty_printer = visualizer;
install_new_value (var, var->value, 1);
@@ -1433,15 +1420,28 @@ install_default_visualizer (struct varobj *var)
#if HAVE_PYTHON
struct cleanup *cleanup;
PyGILState_STATE state;
- PyObject *constructor = NULL;
+ PyObject *pretty_printer = NULL;
state = PyGILState_Ensure ();
cleanup = make_cleanup_py_restore_gil (&state);
- if (var->type)
- constructor = gdbpy_get_varobj_pretty_printer (var->type);
- install_visualizer (var, constructor);
-
+ if (var->value)
+ {
+ pretty_printer = gdbpy_get_varobj_pretty_printer (var->value);
+ if (! pretty_printer)
+ {
+ gdbpy_print_stack ();
+ error (_("Cannot instantiate printer for default visualizer"));
+ }
+ }
+
+ if (pretty_printer == Py_None)
+ {
+ Py_DECREF (pretty_printer);
+ pretty_printer = NULL;
+ }
+
+ install_visualizer (var, pretty_printer);
do_cleanups (cleanup);
#else
error ("Python support required");
@@ -1452,10 +1452,11 @@ void
varobj_set_visualizer (struct varobj *var, const char *visualizer)
{
#if HAVE_PYTHON
- PyObject *mainmod, *globals, *constructor;
- struct cleanup *back_to;
+ PyObject *mainmod, *globals, *pretty_printer, *constructor;
+ struct cleanup *back_to, *value;
PyGILState_STATE state;
+
state = PyGILState_Ensure ();
back_to = make_cleanup_py_restore_gil (&state);
@@ -1465,20 +1466,31 @@ varobj_set_visualizer (struct varobj *var, const char *visualizer)
make_cleanup_py_decref (globals);
constructor = PyRun_String (visualizer, Py_eval_input, globals, globals);
+
+ /* Do not instantiate NoneType. */
+ if (constructor == Py_None)
+ {
+ pretty_printer = Py_None;
+ Py_INCREF (pretty_printer);
+ }
+ else
+ pretty_printer = instantiate_pretty_printer (constructor, var->value);
- if (! constructor)
+ Py_XDECREF (constructor);
+
+ if (! pretty_printer)
{
gdbpy_print_stack ();
error ("Could not evaluate visualizer expression: %s", visualizer);
}
- if (constructor == Py_None)
+ if (pretty_printer == Py_None)
{
- Py_DECREF (constructor);
- constructor = NULL;
+ Py_DECREF (pretty_printer);
+ pretty_printer = NULL;
}
- install_visualizer (var, constructor);
+ install_visualizer (var, pretty_printer);
do_cleanups (back_to);
#else
@@ -1917,7 +1929,6 @@ new_variable (void)
var->children_requested = 0;
var->from = -1;
var->to = -1;
- var->constructor = 0;
var->pretty_printer = 0;
return var;
@@ -1954,7 +1965,6 @@ free_variable (struct varobj *var)
#if HAVE_PYTHON
{
PyGILState_STATE state = PyGILState_Ensure ();
- Py_XDECREF (var->constructor);
Py_XDECREF (var->pretty_printer);
PyGILState_Release (state);
}
@@ -2753,7 +2763,7 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
/* If we have a custom formatter, return whatever string it has
produced. */
- if (var->constructor && var->print_value)
+ if (var->pretty_printer && var->print_value)
return xstrdup (var->print_value);
/* Strip top-level references. */