This is the mail archive of the archer@sourceware.org mailing list for the Archer project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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. */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]