From 8a660acb03f244116938dd9f6346ceffb3ec8f5b Mon Sep 17 00:00:00 2001
From: Vladimir Prus <vladimir@codesourcery.com>
Date: Fri, 2 May 2008 21:26:35 +0400
Subject: [RFA] Implement Python-based computation of varobj children.
To: gdb-patches@sources.redhat.com
X-KMail-Transport: CodeSourcery
X-KMail-Identity: 901867920

	* mi/mi-cmd-var.c (mi_cmd_var_set_type_visualizer)
	(mi_cmd_var_clear_type_visualizers, mi_cmd_var_set_visualizer): New.
	(varobj_update_one): List children, if they have changed.
	* mi-cmds.c (mi_cmds): Register var-set-type-visualizer,
	var-clear-type-visualizers and var-set-visualizer.
	* mi-cmds.h (mi_cmd_var_set_type_visualizer)
	(mi_cmd_var_clear_type_visualizers, mi_cmd_var_set_visualizer): New.
	* python/python-internal.h (make_cleanup_py_decref): Declare.
	* python/python.c (py_decref, make_cleanup_py_decref): New.
	* varobj.c (struct varobj): New fields children_requested,
	value_formatter and children_lister.
	(struct type_visualizer): New.
	(create_child_with_value, install_default_visualizer): New.
	(value_get_print_value): New parameter value_formatter.
	(varobj_add_child): New.
	(type_visualizers): New variable.
	(varobj_create): Call install_default_visualizer
	(varobj_set_display_format): Adjust call to value_get_print_value.
	(varobj_set_visualizer, varobj_set_type_visualizer)
	(varobj_clear_type_visualizers, update_dynamic_varobj_children)
	(varobj_list_children): Set children_requested.  Call
	update_dynamic_varobj_children if necessary.  Call
	install_default_visualizer on children.
	(install_new_value): Always fetch dynamic varobjs.
	(varobj_update): Rework not to try to get value of children for
	which Python code has already computed the value.
	(create_child): Use create_child_with_value.
	(new_variable): Zero new fields.
	(free_variable): Free Python objects.
	(value_get_print_value): Call Python visualizer, is necessary.
	(c_value_of_variable): Directly return Python-produced string
	value.
	* varobj.h (struct varobj_update_result_t): New field
	value_installed.
	(varobj_set_type_visualizer, varobj_clear_type_visualizers)
	(varobj_set_visualizer): New.
	* Makefile.in: Update dependencies.
---
 gdb/Makefile.in              |    2 +-
 gdb/mi/mi-cmd-var.c          |   60 ++++++
 gdb/mi/mi-cmds.c             |    4 +
 gdb/mi/mi-cmds.h             |    3 +
 gdb/python/python-internal.h |    2 +
 gdb/python/python.c          |   15 ++
 gdb/varobj.c                 |  460 +++++++++++++++++++++++++++++++++++++++---
 gdb/varobj.h                 |   14 ++
 8 files changed, 527 insertions(+), 33 deletions(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 6153186..4fbfcb9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2979,7 +2979,7 @@ value.o: value.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
 varobj.o: varobj.c $(defs_h) $(exceptions_h) $(value_h) $(expression_h) \
 	$(frame_h) $(language_h) $(wrapper_h) $(gdbcmd_h) $(block_h) \
 	$(gdb_assert_h) $(gdb_string_h) $(varobj_h) $(vec_h) $(gdbthread_h) \
-	$(inferior_h)
+	$(inferior_h) $(python_h) $(python_internal_h)
 vaxbsd-nat.o: vaxbsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) $(target_h) \
 	$(vax_tdep_h) $(inf_ptrace_h) $(bsd_kvm_h)
 vax-nat.o: vax-nat.c $(defs_h) $(inferior_h) $(gdb_assert_h) $(vax_tdep_h) \
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 50f7add..f2ebcdf 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -251,6 +251,46 @@ mi_cmd_var_set_format (char *command, char **argv, int argc)
 }
 
 enum mi_cmd_result
+mi_cmd_var_set_type_visualizer (char *command, char **argv, int argc)
+{
+  if (argc != 2)
+    error ("Usage: TYPE VISUALIZER_CLASS.");
+
+  varobj_set_type_visualizer (argv[0], argv[1]);
+
+  return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_clear_type_visualizers (char *command, char **argv, int argc)
+{
+  if (argc != 0)
+    error ("No parameters allowed.");
+
+  varobj_clear_type_visualizers ();
+
+  return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
+mi_cmd_var_set_visualizer (char *command, char **argv, int argc)
+{
+  struct varobj *var;
+
+  if (argc != 2)
+    error ("Usage: NAME VISUALIZER_CLASS.");
+
+  var = varobj_get_handle (argv[0]);
+
+  if (var == NULL)
+    error ("Variable object not found");
+
+  varobj_set_visualizer (var, argv[1]);
+
+  return MI_CMD_DONE;
+}
+
+enum mi_cmd_result
 mi_cmd_var_set_frozen (char *command, char **argv, int argc)
 {
   struct varobj *var;
@@ -697,6 +737,26 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
           ui_out_field_int (uiout, "new_num_children", 
 			    varobj_get_num_children (r->varobj));
 	}
+
+      if (r->children_changed)
+	{
+	  int ix;
+	  struct varobj *child;
+	  struct cleanup *cleanup =
+	    make_cleanup_ui_out_list_begin_end (uiout, "children");
+
+	  VEC (varobj_p)* children = varobj_list_children (r->varobj);
+
+	  for (ix = 0; VEC_iterate (varobj_p, children, ix, child); ++ix)
+	    {
+	      struct cleanup *cleanup_child;
+	      cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+	      print_varobj (child, print_values, 1 /* print expression */);
+	      do_cleanups (cleanup_child);
+	    }
+
+	  do_cleanups (cleanup);
+	}
   
       if (mi_version (uiout) > 1)
 	do_cleanups (cleanup);
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index e94648b..2488e40 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -159,6 +159,10 @@ struct mi_cmd mi_cmds[] =
   { "var-list-children", { NULL, 0 }, mi_cmd_var_list_children},
   { "var-set-format", { NULL, 0 }, mi_cmd_var_set_format},
   { "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen},
+  { "var-set-type-visualizer", { NULL, 0 }, mi_cmd_var_set_type_visualizer},
+  { "var-clear-type-visualizers", { NULL, 0 }, 
+    mi_cmd_var_clear_type_visualizers},
+  { "var-set-visualizer", { NULL, 0 }, mi_cmd_var_set_visualizer},
   { "var-show-attributes", { NULL, 0 }, mi_cmd_var_show_attributes},
   { "var-show-format", { NULL, 0 }, mi_cmd_var_show_format},
   { "var-update", { NULL, 0 }, mi_cmd_var_update},
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 087b5e4..9b79077 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -110,6 +110,9 @@ extern mi_cmd_argv_ftype mi_cmd_var_info_type;
 extern mi_cmd_argv_ftype mi_cmd_var_list_children;
 extern mi_cmd_argv_ftype mi_cmd_var_set_format;
 extern mi_cmd_argv_ftype mi_cmd_var_set_frozen;
+extern mi_cmd_argv_ftype mi_cmd_var_set_type_visualizer;
+extern mi_cmd_argv_ftype mi_cmd_var_clear_type_visualizers;
+extern mi_cmd_argv_ftype mi_cmd_var_set_visualizer;
 extern mi_cmd_argv_ftype mi_cmd_var_show_attributes;
 extern mi_cmd_argv_ftype mi_cmd_var_show_format;
 extern mi_cmd_argv_ftype mi_cmd_var_update;
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 5fd680b..fd841ed 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -78,4 +78,6 @@ void gdbpy_initialize_blocks (void);
 void gdbpy_breakpoint_created (int);
 void gdbpy_breakpoint_deleted (int);
 
+struct cleanup *make_cleanup_py_decref (PyObject *py);
+
 #endif /* GDB_PYTHON_INTERNAL_H */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 7772a42..c61883f 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -553,6 +553,21 @@ gdbpy_switch_to_thread (PyObject *self, PyObject *args)
   Py_RETURN_NONE;
 }
 
+static void
+py_decref (void *p)
+{
+  PyObject *py = p;
+  if (py)
+    {
+      Py_DECREF (py);
+    }
+}
+
+struct cleanup *make_cleanup_py_decref (PyObject *py)
+{
+  return make_cleanup (py_decref, (void *)py);
+}
+
 
 
 void
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 0b434ee..34f13ac 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -28,12 +28,20 @@
 
 #include "gdb_assert.h"
 #include "gdb_string.h"
+#include "gdb_regex.h"
 
 #include "varobj.h"
 #include "vec.h"
 #include "gdbthread.h"
 #include "inferior.h"
 
+#if HAVE_PYTHON
+#include "python/python.h"
+#include "python/python-internal.h"
+#else
+typedef int PyObject;
+#endif
+
 /* Non-zero if we want to see trace of varobj level stuff.  */
 
 int varobjdebug = 0;
@@ -137,6 +145,12 @@ struct varobj
   /* Children of this object.  */
   VEC (varobj_p) *children;
 
+  /* Whether the children of this varobj were requested.  This field is
+     used to decide if dynamic varobj should recompute their children.
+     In the event that the frontend never asked for the children, we
+     can avoid that.  */
+  int children_requested;
+
   /* Description of the root variable. Points to root variable for children. */
   struct varobj_root *root;
 
@@ -158,6 +172,16 @@ struct varobj
      not fetched if either the variable is frozen, or any parents is
      frozen.  */
   int not_fetched;
+
+  /* A Python object used to compute the string value of varobj.  Must
+     be a callable, accepting a single parameter -- Gdb.Value instance. 
+     Must return a string.  */
+  PyObject *value_formatter;
+  /* A Python object used to compute the list of children.  Must be
+     a callable, accepting a single parameter -- Gdb.Value instance.
+     Should return a sequence of Gdb.Value instances.  May return
+     empty sequence, but may not return None, or non-sequence.  */
+  PyObject *children_lister;
 };
 
 struct cpstack
@@ -174,6 +198,14 @@ struct vlist
   struct vlist *next;
 };
 
+typedef struct type_visualizer
+{
+  char *type_regexp;
+  char *visualizer;
+} type_visualizer;
+
+DEF_VEC_O (type_visualizer);
+
 /* Private function prototypes */
 
 /* Helper functions for the above subcommands. */
@@ -189,6 +221,10 @@ static void uninstall_variable (struct varobj *);
 
 static struct varobj *create_child (struct varobj *, int, char *);
 
+static struct varobj *
+create_child_with_value (struct varobj *parent, int index, const char *name,
+			 struct value *value);
+
 /* Utility routines */
 
 static struct varobj *new_variable (void);
@@ -214,6 +250,8 @@ static char *cppop (struct cpstack **pstack);
 static int install_new_value (struct varobj *var, struct value *value, 
 			      int initial);
 
+static void install_default_visualizer (struct varobj *var);
+
 /* Language-specific routines. */
 
 static enum varobj_languages variable_language (struct varobj *var);
@@ -232,12 +270,16 @@ static char *my_value_of_variable (struct varobj *var,
 				   enum varobj_display_formats format);
 
 static char *value_get_print_value (struct value *value,
-				    enum varobj_display_formats format);
+				    enum varobj_display_formats format,
+				    PyObject *value_formatter);
 
 static int varobj_value_is_changeable_p (struct varobj *var);
 
 static int is_root_p (struct varobj *var);
 
+static struct varobj *
+varobj_add_child (struct varobj *var, const char *name, struct value *value);
+
 /* C implementation */
 
 static int c_number_of_children (struct varobj *var);
@@ -405,6 +447,8 @@ static int rootcount = 0;	/* number of root varobjs in the list */
 /* Pointer to the varobj hash table (built at run time) */
 static struct vlist **varobj_table;
 
+static VEC (type_visualizer) *type_visualizers = NULL;
+
 /* Is the variable X one of our "fake" children? */
 #define CPLUS_FAKE_CHILD(x) \
 ((x) != NULL && (x)->type == NULL && (x)->value == NULL)
@@ -565,6 +609,7 @@ varobj_create (char *objname,
     }
 
   discard_cleanups (old_chain);
+  install_default_visualizer (var);
   return var;
 }
 
@@ -694,12 +739,103 @@ varobj_set_display_format (struct varobj *var,
       && var->value && !value_lazy (var->value))
     {
       free (var->print_value);
-      var->print_value = value_get_print_value (var->value, var->format);
+      var->print_value = value_get_print_value (var->value, var->format,
+						var->value_formatter);
     }
 
   return var->format;
 }
 
+void 
+varobj_set_visualizer (struct varobj *var, const char *visualizer)
+{
+#if HAVE_PYTHON
+  PyObject *python_main;
+  PyObject *global;
+  PyObject *vclass;
+  struct cleanup *back_to;
+
+  /* If there are any children now, wipe them.  */
+  varobj_delete (var, NULL, 1 /* children only */);
+
+  if (strcmp (visualizer, "none") == 0)
+    {
+      Py_XDECREF (var->value_formatter);
+      Py_XDECREF (var->children_lister);
+
+      var->value_formatter = 0;
+      var->children_lister = 0;
+     
+      install_new_value (var, var->value, 1);
+      return;
+    }
+  else if (strcmp (visualizer, "default") == 0)
+    {
+      install_default_visualizer  (var);
+      return;
+    }
+    
+  python_main = PyImport_ImportModule ("__main__");
+  back_to = make_cleanup_py_decref (python_main);
+
+  global = PyModule_GetDict (python_main);
+  /* TODO: allow to reset things by passing empty string.  */
+  vclass = PyDict_GetItemString (global, visualizer);
+
+  if (!vclass)
+    error ("The specified visualizer class cannot be found");
+  else
+    {
+      PyObject *tuple;
+      PyObject *dict;
+      PyObject *instance;
+
+      tuple = PyTuple_New (0);
+      make_cleanup_py_decref (tuple);
+      dict = PyDict_New ();
+      make_cleanup_py_decref (dict);
+      instance = PyObject_Call (vclass, tuple, dict);
+      make_cleanup_py_decref (instance);
+
+      if (!instance)
+	{
+	  PyErr_Print ();
+	  error ("Failed to instantiate the visualizer");
+	}
+
+      Py_XDECREF (var->value_formatter);
+      Py_XDECREF (var->children_lister);
+
+      var->value_formatter = PyObject_GetAttrString (instance, "to_string");
+      var->children_lister = PyObject_GetAttrString (instance, "children");
+     
+      install_new_value (var, var->value, 1);
+    }
+  do_cleanups (back_to);
+#else
+  error ("Python support required");
+#endif
+}
+
+void 
+varobj_set_type_visualizer (const char *type_regexp, const char *visualizer)
+{
+#if HAVE_PYTHON
+  type_visualizer t;
+  t.type_regexp = xstrdup (type_regexp);
+  t.visualizer = xstrdup (visualizer);
+  VEC_safe_push (type_visualizer, type_visualizers, &t);
+#else
+  error ("Python support required");
+#endif
+}
+
+void 
+varobj_clear_type_visualizers ()
+{
+  VEC_free (type_visualizer, type_visualizers);
+}
+
 enum varobj_display_formats
 varobj_get_display_format (struct varobj *var)
 {
@@ -748,6 +884,102 @@ varobj_get_num_children (struct varobj *var)
   return var->num_children;
 }
 
+static
+int update_dynamic_varobj_children (struct varobj *var,
+				    VEC (varobj_p) **changed,
+				    VEC (varobj_p) **new_and_unchaged)
+
+{
+#if HAVE_PYTHON
+  /* FIXME: we *might* want to provide this functionality as
+     a standalone function, so that other interested parties
+     than varobj code can benefit for this.  */
+  struct cleanup *back_to;
+  PyObject *py_value;
+  PyObject *tuple;
+  PyObject *children;
+  int n, i;
+  int children_changed = 0;
+    
+  tuple = PyTuple_New (1);
+  back_to = make_cleanup_py_decref (tuple);
+  /* Steals the reference.  */
+  PyTuple_SetItem (tuple, 0, gdb_owned_value_to_value_object (var->value));
+  children = PyObject_Call (var->children_lister, tuple, Py_None);
+  make_cleanup_py_decref (children);
+      
+  if (!children)
+    {
+      /* FIXME: need a way to translate python exceptions
+	 into gdb exceptions. */
+      PyErr_Print ();
+      error ("Null value returned for children");
+    }
+  
+  if (!PySequence_Check (children))
+    error ("Returned value is a sequence");
+  
+  n = PySequence_Size (children);
+  
+  for (i = 0; i < n; ++i)
+    {
+      PyObject *item = PySequence_GetItem (children, i);
+      PyObject *py_v;
+      struct value *v;
+      char *name;
+      
+      if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
+	error ("Invalid item from the child list");
+      
+      if (!PyObject_IsInstance (py_v, (PyObject *)&value_object_type))
+	error ("child list has object of invalid type");
+      
+      v = value_object_to_value (py_v);
+
+      /* TODO: This assume the name of the i-th child never changes.  */
+
+      /* Now see what to do here.  */
+      if (VEC_length (varobj_p, var->children) < i + 1)
+	{
+	  /* There's no child yet.  */
+	  struct varobj *child = varobj_add_child (var, name, v);
+	  if (new_and_unchaged)
+	    VEC_safe_push (varobj_p, *new_and_unchaged, child);
+	  children_changed = 1;
+	}
+      else 
+	{
+	  varobj_p existing = VEC_index (varobj_p, var->children, i);
+	  if (install_new_value (existing, v, 0) && changed)
+	    {
+	      if (changed)
+		VEC_safe_push (varobj_p, *changed, existing);
+	    }
+	  else
+	    {
+	      if (new_and_unchaged)
+		VEC_safe_push (varobj_p, *new_and_unchaged, existing);
+	    }
+	}
+    }
+  if (n < VEC_length (varobj_p, var->children))
+    {
+      int i;
+      children_changed = 1;
+      for (i = n; i < VEC_length (varobj_p, var->children); ++i)
+	varobj_delete (VEC_index (varobj_p, var->children, i), NULL, 0);
+    }
+  VEC_truncate (varobj_p, var->children, n);
+ 
+  do_cleanups (back_to);
+
+  return children_changed;
+#else
+  gdb_assert (0 && "should never be called if Python is not enabled");
+#endif
+}
+
+
 /* Creates a list of the immediate children of a variable object;
    the return code is the number of such children or -1 on error */
 
@@ -758,6 +990,17 @@ varobj_list_children (struct varobj *var)
   char *name;
   int i;
 
+  var->children_requested = 1;
+
+  if (var->children_lister)
+    {
+      /* This, in theory, can result in the number of children changing without
+	 frontend noticing.  But well, calling -var-list-children on the same
+	 varobj twice is not something a sane frontend would do.  */
+      update_dynamic_varobj_children (var, NULL, NULL);
+      return var->children;      
+    }
+
   if (var->num_children == -1)
     var->num_children = number_of_children (var);
 
@@ -782,12 +1025,24 @@ varobj_list_children (struct varobj *var)
 	  name = name_of_child (var, i);
 	  existing = create_child (var, i, name);
 	  VEC_replace (varobj_p, var->children, i, existing);
+	  install_default_visualizer (existing);
 	}
     }
 
   return var->children;
 }
 
+static struct varobj *
+varobj_add_child (struct varobj *var, const char *name, struct value *value)
+{
+  varobj_p v = create_child_with_value (var, 
+					VEC_length (varobj_p, var->children), 
+					name, value);
+  VEC_safe_push (varobj_p, var->children, v);
+  install_default_visualizer (v);
+  return v;
+}
+
 /* Obtain the type of an object Variable as a string similar to the one gdb
    prints on the console */
 
@@ -994,6 +1249,13 @@ install_new_value (struct varobj *var, struct value *value, int initial)
      a type. */
   gdb_assert (var->type || CPLUS_FAKE_CHILD (var));
   changeable = varobj_value_is_changeable_p (var);
+
+  /* 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->value_formatter || var->children_lister)
+    changeable = 1;
+
   need_to_fetch = changeable;
 
   /* We are not interested in the address of references, and given
@@ -1050,7 +1312,8 @@ install_new_value (struct varobj *var, struct value *value, int initial)
      lazy -- if it is, the code above has decided that the value
      should not be fetched.  */
   if (value && !value_lazy (value))
-      print_value = value_get_print_value (value, var->format);
+    print_value = value_get_print_value (value, var->format, 
+					 var->value_formatter);
 
   /* If the type is changeable, compare the old and the new values.
      If this is the initial assignment, we don't have any old value
@@ -1115,6 +1378,26 @@ install_new_value (struct varobj *var, struct value *value, int initial)
   return changed;
 }
 
+void install_default_visualizer (struct varobj *var)
+{
+  char *type = varobj_get_type (var);
+
+  if (type)
+    {
+      type_visualizer *v;
+      int i;
+      for (i = 0; VEC_iterate (type_visualizer, type_visualizers, i, v); ++i)
+	{
+	  if (re_comp (v->type_regexp) == NULL && re_exec (type) == 1)
+	    {
+	      varobj_set_visualizer (var, v->visualizer);
+	      break;
+	    }
+	}
+      xfree (type);
+    }
+}
+
 /* Update the values for a variable and its children.  This is a
    two-pronged attack.  First, re-parse the value for the root's
    expression to see if it's changed.  Then go all the way
@@ -1140,7 +1423,7 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
   struct varobj **cv;
   struct varobj **templist = NULL;
   struct value *new;
-  VEC (varobj_p) *stack = NULL;
+  VEC (varobj_update_result) *stack = NULL;
   VEC (varobj_update_result) *result = NULL;
   struct frame_info *fi;
 
@@ -1179,20 +1462,80 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
 
       if (new == NULL)
 	r.status = VAROBJ_NOT_IN_SCOPE;
+      r.value_installed = 1;
 
-      if (r.type_changed || r.changed)
-	VEC_safe_push (varobj_update_result, result, &r);
+      if (r.type_changed)
+	install_default_visualizer (*varp);
 
       if (r.status == VAROBJ_NOT_IN_SCOPE)
-	return result;
+	{
+	  VEC_safe_push (varobj_update_result, result, &r);
+	  return result;
+	}
+            
+      VEC_safe_push (varobj_update_result, stack, &r);
+    }
+  else
+    {
+      varobj_update_result r = {*varp};
+      VEC_safe_push (varobj_update_result, stack, &r);
     }
-
-  VEC_safe_push (varobj_p, stack, *varp);
 
   /* Walk through the children, reconstructing them all.  */
-  while (!VEC_empty (varobj_p, stack))
+  while (!VEC_empty (varobj_update_result, stack))
     {
-      v = VEC_pop (varobj_p, stack);
+      varobj_update_result r = *(VEC_last (varobj_update_result, stack));
+      struct varobj *v = r.varobj;
+
+      VEC_pop (varobj_update_result, stack);
+
+      /* Update this variable, unless it's a root, which is already
+	 updated.  */
+      if (!r.value_installed)
+	{	  
+	  new = value_of_child (v->parent, v->index);
+	  if (install_new_value (v, new, 0 /* type not changed */))
+	    {
+	      r.changed = 1;
+	      v->updated = 0;
+	    }
+	}
+
+      /* We probably should not get children of a varobj that has 
+	 children_lister, but for which -var-list-children was never
+	 invoked.  Presumably, such varobj is not yet expanded in the
+	 UI, so we need not bother getting it.  */
+      if (v->children_lister)
+	{
+	  VEC (varobj_p) *changed = 0, *new_and_unchaged = 0;
+	  int i;
+	  varobj_p tmp;
+
+	  if (!v->children_requested)
+	    continue;
+
+	  if (v->frozen)
+	    continue;
+
+	  if (update_dynamic_varobj_children (v, &changed, &new_and_unchaged))
+	    r.children_changed = 1;
+	  for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i)
+	    {
+	      varobj_update_result r = {tmp};
+	      r.changed = 1;
+	      r.value_installed = 1;
+	      VEC_safe_push (varobj_update_result, stack, &r);
+	    }
+	  for (i = 0; VEC_iterate (varobj_p, new_and_unchaged, i, tmp); ++i)
+	    {
+	      varobj_update_result r = {tmp};
+	      r.value_installed = 1;
+	      VEC_safe_push (varobj_update_result, stack, &r);
+	    }
+	  if (r.changed || r.children_changed)
+	    VEC_safe_push (varobj_update_result, result, &r);
+	  continue;
+	}
 
       /* Push any children.  Use reverse order so that the first
 	 child is popped from the work stack first, and so
@@ -1203,26 +1546,18 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
 	  varobj_p c = VEC_index (varobj_p, v->children, i);
 	  /* Child may be NULL if explicitly deleted by -var-delete.  */
 	  if (c != NULL && !c->frozen)
-	    VEC_safe_push (varobj_p, stack, c);
-	}
-
-      /* Update this variable, unless it's a root, which is already
-	 updated.  */
-      if (v->root->rootvar != v)
-	{	  
-	  new = value_of_child (v->parent, v->index);
-	  if (install_new_value (v, new, 0 /* type not changed */))
 	    {
-	      /* Note that it's changed */
-	      varobj_update_result r = {v};
-	      r.changed = 1;
-	      VEC_safe_push (varobj_update_result, result, &r);
-	      v->updated = 0;
+	      varobj_update_result r = {c};
+	      VEC_safe_push (varobj_update_result, stack, &r);
 	    }
 	}
+
+      if (r.changed || r.type_changed)
+	VEC_safe_push (varobj_update_result, result, &r);
     }
 
-  VEC_free (varobj_p, stack);
+  VEC_free (varobj_update_result, stack);
+
   return result;
 }
 
@@ -1421,16 +1756,23 @@ uninstall_variable (struct varobj *var)
 static struct varobj *
 create_child (struct varobj *parent, int index, char *name)
 {
+  return create_child_with_value (parent, index, name, 
+				  value_of_child (parent, index));
+}
+
+static struct varobj *
+create_child_with_value (struct varobj *parent, int index, const char *name,
+			 struct value *value)
+{
   struct varobj *child;
   char *childs_name;
-  struct value *value;
 
   child = new_variable ();
 
   /* name is allocated by name_of_child */
-  child->name = name;
+  /* FIXME: xstrdup should not be here.  */
+  child->name = xstrdup (name);
   child->index = index;
-  value = value_of_child (parent, index);
   child->parent = parent;
   child->root = parent->root;
   childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
@@ -1479,6 +1821,9 @@ new_variable (void)
   var->print_value = NULL;
   var->frozen = 0;
   var->not_fetched = 0;
+  var->children_requested = 0;
+  var->value_formatter = 0;
+  var->children_lister = 0;
 
   return var;
 }
@@ -1511,6 +1856,11 @@ free_variable (struct varobj *var)
       xfree (var->root);
     }
 
+#if HAVE_PYTHON
+  Py_XDECREF (var->value_formatter);
+  Py_XDECREF (var->children_lister);
+#endif
+
   xfree (var->name);
   xfree (var->obj_name);
   xfree (var->print_value);
@@ -1785,7 +2135,8 @@ my_value_of_variable (struct varobj *var, enum varobj_display_formats format)
 }
 
 static char *
-value_get_print_value (struct value *value, enum varobj_display_formats format)
+value_get_print_value (struct value *value, enum varobj_display_formats format,
+		       PyObject *value_formatter)
 {
   long dummy;
   struct ui_file *stb;
@@ -1795,6 +2146,45 @@ value_get_print_value (struct value *value, enum varobj_display_formats format)
   if (value == NULL)
     return NULL;
 
+#if HAVE_PYTHON
+  if (value_formatter)
+    {
+      /* FIXME: we *might* want to provide this functionality as
+	 a standalone function, so that other interested parties
+	 than varobj code can benefit for this.  */
+      struct cleanup *back_to;
+      PyObject *py_value;
+      PyObject *tuple;
+      PyObject *py_s;
+      char *s;
+
+      py_value = gdb_owned_value_to_value_object (value);
+      tuple = PyTuple_New (1);
+      back_to = make_cleanup_py_decref (tuple);
+      /* Steals the reference.  */
+      PyTuple_SetItem (tuple, 0, py_value);
+      py_s = PyObject_Call (value_formatter, tuple, Py_None);
+      make_cleanup_py_decref (py_s);
+
+      if (!py_s)
+	{
+	  /* FIXME: need a way to translate python exceptions
+	     into gdb exceptions. */
+	  PyErr_Print ();
+	  error ("Null value returned for string");
+	}
+      
+      if (!PyString_Check (py_s))
+	error ("Returned value is not a string");
+      
+      s = PyString_AsString (py_s);
+      gdb_assert (s);
+      
+      do_cleanups (back_to);
+      return xstrdup (s);				       
+    }
+#endif
+
   stb = mem_fileopen ();
   old_chain = make_cleanup_ui_file_delete (stb);
 
@@ -1889,7 +2279,7 @@ varobj_floating_p (struct varobj *var)
    value is not known.  
 
    If WAS_PTR is not NULL, set *WAS_PTR to 0 or 1
-   depending on whether pointer was deferenced
+   depending on whether pointer was dereferenced
    in this function.  */
 static void
 adjust_value_for_child_access (struct value **value,
@@ -2259,6 +2649,11 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
      catch that case explicitly.  */
   struct type *type = get_type (var);
 
+  /* If we have a custom formatter, return whatever string it has
+     produced.  */
+  if (var->value_formatter && var->print_value)
+    return xstrdup (var->print_value);
+  
   /* Strip top-level references. */
   while (TYPE_CODE (type) == TYPE_CODE_REF)
     type = check_typedef (TYPE_TARGET_TYPE (type));
@@ -2303,7 +2698,8 @@ c_value_of_variable (struct varobj *var, enum varobj_display_formats format)
 	    if (format == var->format)
 	      return xstrdup (var->print_value);
 	    else
-	      return value_get_print_value (var->value, format);
+	      return value_get_print_value (var->value, format, 
+					    var->value_formatter);
 	  }
       }
     }
diff --git a/gdb/varobj.h b/gdb/varobj.h
index 9ecef0f..d79fbd6 100644
--- a/gdb/varobj.h
+++ b/gdb/varobj.h
@@ -72,7 +72,12 @@ typedef struct varobj_update_result_t
   struct varobj *varobj;
   int type_changed;
   int changed;
+  int children_changed;
   enum varobj_scope_status status;
+  /* This variable is used internally by varobj_update to indicate if the
+     new value of varobj is already computed and installed, or has to
+     be yet installed.  Don't use this outside varobj.c */
+  int value_installed;  
 } varobj_update_result;
 
 DEF_VEC_O (varobj_update_result);
@@ -141,4 +146,13 @@ extern int varobj_editable_p (struct varobj *var);
 
 extern int varobj_floating_p (struct varobj *var);
 
+extern void 
+varobj_set_type_visualizer (const char *type_regexp, const char *visualizer);
+
+extern void 
+varobj_clear_type_visualizers ();
+
+extern void 
+varobj_set_visualizer (struct varobj *var, const char *visualizer);
+
 #endif /* VAROBJ_H */
-- 
1.5.3.5

