This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB 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 pretty-printing [6/6]


>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

Tom> +This feature is only available if Python support is enabled.

Eli> Should we say how to check for that?

Sure.

I also found a bug in the text -- a place where a code change was not
reflected in the docs.

This version of the patch fixes both of these problems.
It has also been modified to work with the change to using
python-prettyprint.c.

Tom

2009-04-02  Vladimir Prus  <vladimir@codesourcery.com>
	    Tom Tromey  <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* mi/mi-main.c (mi_cmd_list_features): List "python" feature.
	* varobj.h (varobj_set_visualizer): Declare.
	(varobj_get_child_range, varobj_set_child_range,
	varobj_get_display_hint): Likewise.
	(varobj_update_result_t) <children_changed, value_installed>: New
	fields.
	* mi/mi-cmds.c (mi_cmds): Add var-set-visualizer and
	var-set-child-range.
	* mi/mi-cmds.h (mi_cmd_var_set_visualizer,
	mi_cmd_var_set_child_range): Declare.
	* mi/mi-cmd-var.c (mi_cmd_var_set_visualizer): New function.
	(mi_cmd_var_set_child_range): Likewise.
	(mi_cmd_var_list_children): Handle child range.  Emit display
	hint.
	(varobj_update_one): Emit display hint.  Handle dynamic children.
	* python/python.c (GdbMethods): Add "default_visualizer".
	* python/python-internal.h (apply_varobj_pretty_printer,
	gdbpy_get_varobj_pretty_printer, gdbpy_get_display_hint):
	Declare.
	(gdbpy_default_visualizer): Likewise.
	* varobj.c: Include python.h, python-internal.h.
	(PyObject): New typedef.
	(struct varobj) <children_requested, from, to, pretty_printer>:
	New fields.
	(varobj_create): Call install_default_visualizer.
	(instantiate_pretty_printer): New function.
	(varobj_set_display_format): Update.
	(varobj_get_display_hint): New function.
	(update_dynamic_varobj_children): New function.
	(varobj_get_num_children): Handle dynamic children.
	(varobj_list_children): Likewise.
	(install_new_value): Likewise.
	(varobj_add_child): New function.
	(varobj_get_child_range): Likewise.
	(varobj_set_child_range): Likewise.
	(install_visualizer): Likewise.
	(install_default_visualizer): Likewise.
	(varobj_set_visualizer): Likewise.
	(varobj_update): Handle dynamic children.
	(create_child): Use create_child_with_value.
	(create_child_with_value): New function.
	(value_get_print_value): Call pretty printer.  Add value_formatter
	argument.
	(c_value_of_variable): Update.
	(varobj_invalidate): Always free all_rootvarobj.
	* python/python-prettyprint.c (apply_varobj_pretty_printer): New
	function.
	(gdbpy_get_varobj_pretty_printer): Likewise.
	(gdbpy_default_visualizer): Likewise.

2009-04-02  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (GDB/MI Miscellaneous Commands): Document "python"
	feature.
	(GDB/MI Variable Objects): Document -var-set-visualizer,
	-var-set-child-range.

2009-04-02  Tom Tromey  <tromey@redhat.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* lib/mi-support.exp (mi_varobj_update_dynamic): New proc.
	(mi_child_regexp): Likewise.
	(mi_list_varobj_children_range): Likewise.
	(mi_get_features): Likewise.
	(mi_list_varobj_children): Rewrite.
	* gdb.python/python-mi.exp: New file.

 gdb/ChangeLog                          |   54 +++
 gdb/doc/ChangeLog                      |    7 +
 gdb/doc/gdb.texinfo                    |  101 ++++++
 gdb/mi/mi-cmd-var.c                    |   81 +++++-
 gdb/mi/mi-cmds.c                       |    2 +
 gdb/mi/mi-cmds.h                       |    2 +
 gdb/mi/mi-main.c                       |    4 +
 gdb/python/python-internal.h           |    8 +
 gdb/python/python-prettyprint.c        |   74 ++++
 gdb/python/python.c                    |    3 +
 gdb/testsuite/ChangeLog                |   10 +
 gdb/testsuite/gdb.python/python-mi.exp |  124 +++++++
 gdb/testsuite/lib/mi-support.exp       |  105 +++++--
 gdb/varobj.c                           |  578 ++++++++++++++++++++++++++++++--
 gdb/varobj.h                           |   15 +
 15 files changed, 1105 insertions(+), 63 deletions(-)
 create mode 100644 gdb/testsuite/gdb.python/python-mi.exp

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3e38175..7b3f1ad 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -23029,6 +23029,103 @@ Unfreezing a variable does not update it, only subsequent
 (gdb)
 @end smallexample
 
+@subheading The @code{-var-set-visualizer} command
+@findex -var-set-visualizer
+@anchor{-var-set-visualizer}
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-set-visualizer @var{name} @var{visualizer}
+@end smallexample
+
+@subheading The @code{-var-set-child-range} command
+@findex -var-set-child-range
+@anchor{-var-set-child-range}
+
+Set a visualizer for the variable object @var{name}.
+
+@var{visualizer} is the visualizer to use.  The special value
+@samp{None} means to disable any visualizer in use.
+
+If not @samp{None}, @var{visualizer} must be a Python expression.
+This expression must evaluate to a callable object which accepts a
+single argument.  @value{GDBN} will call this object with the value of
+the varobj @var{name} as an argument.  This function must return an
+object which conforms to the pretty-printing interface (@pxref{Pretty
+Printing}).
+
+The pre-defined function @code{gdb.default_visualizer} may be used to
+select a visualizer by following the built-in process
+(@pxref{Selecting Pretty-Printers}).  This is done automatically when
+a varobj is created, and so ordinarily is not needed.
+
+This feature is only available if Python support is enabled.  The MI
+command @code{-list-features} (@pxref{GDB/MI Miscellaneous Commands})
+can be used to check this.
+
+@subsubheading Example
+
+Resetting the visualizer:
+
+@smallexample
+(gdb)
+-var-set-visualizer V None
+^done
+@end smallexample
+
+Reselecting the default (type-based) visualizer:
+
+@smallexample
+(gdb)
+-var-set-visualizer V gdb.default_visualizer
+^done
+@end smallexample
+
+Suppose @code{SomeClass} is a visualizer class.  A lambda expression
+can be used to instantiate this class for a varobj:
+
+@smallexample
+(gdb)
+-var-set-visualizer V "lambda val: SomeClass()"
+^done
+@end smallexample
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-set-child-range @var{name} @var{from} @var{to}
+@end smallexample
+
+Select a sub-range of the children of the variable object @var{name};
+future calls to @code{-var-list-children} will only report the
+selected range of children.  This allows an MI consumer to avoid
+inefficiencies if the varobj has very many children.
+
+If either @var{from} or @var{to} is less than zero, then sub-range
+selection is disabled, and @code{-var-list-children} will report all
+children.
+
+Otherwise, @var{from} and @var{to} are indexes into the array of
+children.  Children starting at @var{from} and stopping jsut before
+@var{to} will be reported.
+
+@subsubheading Example
+
+@smallexample
+(gdb)
+ -var-list-children n
+ ^done,numchild=3,children=[@{name="a",numchild=0,type="int"@},
+ @{name="b",numchild=0,type="int"@},
+ @{name="c",numchild=0,type="int"@}]
+(gdb)
+ -var-set-child-range n 1 2
+(gdb)
+ -var-list-children n
+ ^done,numchild=3,children=[@{name="b",numchild=0,type="int"@},
+ @{name="c",numchild=0,type="int"@}]
+@end smallexample
+
 
 @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @node GDB/MI Data Manipulation
@@ -24588,6 +24685,10 @@ as possible presense of the @code{frozen} field in the output
 of @code{-varobj-create}.
 @item pending-breakpoints
 Indicates presence of the @option{-f} option to the @code{-break-insert} command.
+@item python
+Indicates presence of Python scripting support, Python-based
+pretty-printing commands, and possible presence of the
+@samp{display_hint} field in the output of @code{-var-list-children}
 @item thread-info
 Indicates presence of the @code{-thread-info} command.
 
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 143074b..0f4efba 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -249,6 +249,41 @@ mi_cmd_var_set_format (char *command, char **argv, int argc)
 }
 
 void
+mi_cmd_var_set_visualizer (char *command, char **argv, int argc)
+{
+  struct varobj *var;
+
+  if (argc != 2)
+    error ("Usage: NAME VISUALIZER_FUNCTION.");
+
+  var = varobj_get_handle (argv[0]);
+
+  if (var == NULL)
+    error ("Variable object not found");
+
+  varobj_set_visualizer (var, argv[1]);
+}
+
+void
+mi_cmd_var_set_child_range (char *command, char **argv, int argc)
+{
+  struct varobj *var;
+  int from, to;
+
+  if (argc != 3)
+    error (_("-var-set-child-range: NAME FROM TO"));
+
+  var = varobj_get_handle (argv[0]);
+  if (var == NULL)
+    error (_("Variable object not found"));
+
+  from = atoi (argv[1]);
+  to = atoi (argv[2]);
+
+  varobj_set_child_range (var, from, to);
+}
+
+void
 mi_cmd_var_set_frozen (char *command, char **argv, int argc)
 {
   struct varobj *var;
@@ -369,6 +404,8 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
   int numchild;
   enum print_values print_values;
   int ix;
+  int from, to;
+  char *display_hint;
 
   if (argc != 1 && argc != 2)
     error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME"));
@@ -388,14 +425,22 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
   else
     print_values = PRINT_NO_VALUES;
 
-  if (VEC_length (varobj_p, children) == 0)
+  varobj_get_child_range (var, children, &from, &to);
+  if (from >= to)
     return;
 
+  display_hint = varobj_get_display_hint (var);
+  if (display_hint)
+    {
+      ui_out_field_string (uiout, "displayhint", display_hint);
+      xfree (display_hint);
+    }
+
   if (mi_version (uiout) == 1)
     cleanup_children = make_cleanup_ui_out_tuple_begin_end (uiout, "children");
   else
     cleanup_children = make_cleanup_ui_out_list_begin_end (uiout, "children");
-  for (ix = 0; VEC_iterate (varobj_p, children, ix, child); ++ix)
+  for (ix = from; ix < to && VEC_iterate (varobj_p, children, ix, child); ++ix)
     {
       struct cleanup *cleanup_child;
       cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, "child");
@@ -662,6 +707,8 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
   
   for (i = 0; VEC_iterate (varobj_update_result, changes, i, r); ++i)
     {
+      char *display_hint;
+
       if (mi_version (uiout) > 1)
         cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
       ui_out_field_string (uiout, "name", varobj_get_objname (r->varobj));
@@ -695,6 +742,36 @@ 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));
 	}
+
+      display_hint = varobj_get_display_hint (var);
+      if (display_hint)
+	{
+	  ui_out_field_string (uiout, "displayhint", display_hint);
+	  xfree (display_hint);
+	}
+
+      if (r->children_changed)
+	{
+	  int ix, from, to;
+	  struct varobj *child;
+	  struct cleanup *cleanup =
+	    make_cleanup_ui_out_list_begin_end (uiout, "children");
+
+	  VEC (varobj_p)* children = varobj_list_children (r->varobj);
+	  varobj_get_child_range (r->varobj, children, &from, &to);
+
+	  for (ix = from;
+	       ix < to && 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 2610b6a..43387ec 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -160,8 +160,10 @@ struct mi_cmd mi_cmds[] =
   { "var-info-num-children", { NULL, 0 }, mi_cmd_var_info_num_children},
   { "var-info-type", { NULL, 0 }, mi_cmd_var_info_type},
   { "var-list-children", { NULL, 0 }, mi_cmd_var_list_children},
+  { "var-set-child-range", { NULL, 0 }, mi_cmd_var_set_child_range },
   { "var-set-format", { NULL, 0 }, mi_cmd_var_set_format},
   { "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen},
+  { "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 39f16fb..291a07f 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -92,7 +92,9 @@ extern mi_cmd_argv_ftype mi_cmd_var_info_num_children;
 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_child_range;
 extern mi_cmd_argv_ftype mi_cmd_var_set_frozen;
+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/mi/mi-main.c b/gdb/mi/mi-main.c
index 3201ead..cfde2e8 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -1106,6 +1106,10 @@ mi_cmd_list_features (char *command, char **argv, int argc)
       ui_out_field_string (uiout, NULL, "pending-breakpoints");
       ui_out_field_string (uiout, NULL, "thread-info");
       
+#if HAVE_PYTHON
+      ui_out_field_string (uiout, NULL, "python");
+#endif
+      
       do_cleanups (cleanup);
       return;
     }
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 06d9ba2..4cef746 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -108,6 +108,14 @@ char *python_string_to_host_string (PyObject *obj);
 PyObject *target_string_to_unicode (const gdb_byte *str, int length);
 int gdbpy_is_string (PyObject *obj);
 
+/* Note that these are declared here, and not in python.h with the
+   other pretty-printer functions, because they refer to PyObject.  */
+char *apply_varobj_pretty_printer (PyObject *print_obj,
+				   struct value **replacement);
+PyObject *gdbpy_get_varobj_pretty_printer (struct value *value);
+char *gdbpy_get_display_hint (PyObject *printer);
+PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args);
+
 extern PyObject *gdbpy_doc_cst;
 extern PyObject *gdbpy_children_cst;
 extern PyObject *gdbpy_to_string_cst;
diff --git a/gdb/python/python-prettyprint.c b/gdb/python/python-prettyprint.c
index 34e9b80..b9cddcd 100644
--- a/gdb/python/python-prettyprint.c
+++ b/gdb/python/python-prettyprint.c
@@ -497,6 +497,80 @@ apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
   return result;
 }
 
+/* Apply a pretty-printer for the varobj code.  PRINTER_OBJ is the
+   print object.  It must have a 'to_string' method (but this is
+   checked by varobj, not here) which takes no arguments and
+   returns a string.  This function returns an xmalloc()d string if
+   the printer returns a string.  The printer may return a replacement
+   value instead; in this case *REPLACEMENT is set to the replacement
+   value, and this function returns NULL.  On error, *REPLACEMENT is
+   set to NULL and this function also returns NULL.  */
+char *
+apply_varobj_pretty_printer (PyObject *printer_obj,
+			     struct value **replacement)
+{
+  char *result;
+  PyGILState_STATE state = PyGILState_Ensure ();
+
+  *replacement = NULL;
+  result = pretty_print_one_value (printer_obj, replacement);
+  if (result == NULL);
+    gdbpy_print_stack ();
+  PyGILState_Release (state);
+
+  return result;
+}
+
+/* Find a pretty-printer object for the varobj module.  Returns a new
+   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 value *value)
+{
+  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
+   the resulting class.  This accepts a Value argument and returns a
+   pretty printer instance, or None.  This function is useful as an
+   argument to the MI command -var-set-visualizer.  */
+PyObject *
+gdbpy_default_visualizer (PyObject *self, PyObject *args)
+{
+  PyObject *val_obj;
+  PyObject *cons, *printer = NULL;
+  struct value *value;
+
+  if (! PyArg_ParseTuple (args, "O", &val_obj))
+    return NULL;
+  value = value_object_to_value (val_obj);
+  if (! value)
+    {
+      PyErr_SetString (PyExc_TypeError, "argument must be a gdb.Value");
+      return NULL;
+    }
+
+  cons = find_pretty_printer (val_obj);
+  return cons;
+}
+
 #else /* HAVE_PYTHON */
 
 int
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 8fa8aeb..6f47757 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -614,6 +614,9 @@ static PyMethodDef GdbMethods[] =
   { "get_parameter", get_parameter, METH_VARARGS,
     "Return a gdb parameter's value" },
 
+  { "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
+    "Find the default visualizer for a Value." },
+
   { "current_objfile", gdbpy_get_current_objfile, METH_NOARGS,
     "Return the current Objfile being loaded, or None." },
   { "objfiles", gdbpy_objfiles, METH_NOARGS,
diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp
new file mode 100644
index 0000000..5c9f3c7
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-mi.exp
@@ -0,0 +1,124 @@
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests Python-based
+# pretty-printing for MI.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi2"
+
+gdb_exit
+if [mi_gdb_start] {
+    continue
+}
+
+set testfile "python-prettyprint"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug additional_flags=-DMI}] != "" } {
+    untested mi2-var-child.exp
+    return -1
+}
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+
+if {[lsearch -exact [mi_get_features] python] < 0} {
+    unsupported "python support is disabled"
+    return -1
+}
+
+mi_runto main
+
+mi_gdb_test "python execfile ('${srcdir}/${subdir}/${testfile}.py')" ""
+
+mi_continue_to_line [gdb_get_line_number {MI breakpoint here} ${testfile}.c] \
+  "step to breakpoint"
+
+mi_create_floating_varobj container c "create container varobj"
+
+mi_list_varobj_children container {
+} "examine container children=0"
+
+mi_next "next over update 1"
+
+mi_varobj_update_dynamic container {
+    { {container.\[0\]} {\[0\]} 0 int }
+} "varobj update 1"
+
+mi_next "next over update 2"
+
+mi_varobj_update_dynamic container {
+    { {container.\[0\]} {\[0\]} 0 int }
+    { {container.\[1\]} {\[1\]} 0 int }
+} "varobj update 2"
+
+mi_gdb_test "-var-set-visualizer container None" \
+  "\\^done" \
+  "clear visualizer"
+
+mi_gdb_test "-var-update container" \
+  "\\^done,changelist=\\\[\\\]" \
+  "varobj update after clearing"
+
+mi_gdb_test "-var-set-visualizer container gdb.default_visualizer" \
+  "\\^done" \
+  "choose default visualizer"
+
+mi_varobj_update_dynamic container {
+    { {container.\[0\]} {\[0\]} 0 int }
+    { {container.\[1\]} {\[1\]} 0 int }
+} "varobj update after choosing default"
+
+mi_gdb_test "-var-set-visualizer container ContainerPrinter" \
+  "\\^done" \
+  "choose visualizer using expression"
+
+mi_varobj_update_dynamic container {
+    { {container.\[0\]} {\[0\]} 0 int }
+    { {container.\[1\]} {\[1\]} 0 int }
+} "varobj update after choosing via expression"
+
+mi_gdb_test "-var-set-child-range container 1 2" \
+  "\\^done" \
+  "select child range"
+
+mi_gdb_test "-var-update container" \
+  "\\^done,changelist=\\\[\\\]" \
+  "varobj update after selecting child range"
+
+mi_list_varobj_children_range container 2 {
+    { {container.\[1\]} {\[1\]} 0 int }
+} "list varobj children after selecting child range"
+
+mi_gdb_test "-var-set-child-range container -1 -1" \
+  "\\^done" \
+  "reset child range"
+
+mi_gdb_test "-var-update container" \
+  "\\^done,changelist=\\\[\\\]" \
+  "varobj update after resetting child range"
+
+mi_list_varobj_children container {
+    { {container.\[0\]} {\[0\]} 0 int }
+    { {container.\[1\]} {\[1\]} 0 int }
+} "list varobj children after resetting child range"
+
+mi_continue_to_line \
+    [gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \
+    "step to second breakpoint"
+
+mi_varobj_update_with_type_change container int 0 "update after type change"
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index f62c240..bda7ea1 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1237,6 +1237,21 @@ proc mi_varobj_update_with_type_change { name new_type new_children testname } {
     mi_gdb_test "-var-update $name" $er $testname
 }
 
+# Update a dynamic varobj named NAME.  CHILDREN is a list of children,
+# in the same form as mi_list_varobj_children.  TESTNAME is the name
+# of the test.
+proc mi_varobj_update_dynamic {name children testname} {
+    set children_exp_j [mi_child_regexp $children 0]
+
+    set er "\\^done,changelist=\\\["
+
+    append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\""
+    append er ",children=\\\[$children_exp_j.*\\\]}\\\]"
+
+    verbose -log "Expecting: $er"
+    mi_gdb_test "-var-update $name" $er $testname
+}
+
 proc mi_check_varobj_value { name value testname } {
 
     mi_gdb_test "-var-evaluate-expression $name" \
@@ -1244,6 +1259,42 @@ proc mi_check_varobj_value { name value testname } {
 	$testname
 }
 
+# Helper proc which constructs a child regexp for
+# mi_list_varobj_children and mi_varobj_update_dynamic.
+proc mi_child_regexp {children add_child} {
+    set children_exp {}
+    set whatever "\"\[^\"\]+\""
+
+    if {$add_child} {
+	set pre "child="
+    } else {
+	set pre ""
+    }
+
+    foreach item $children {
+
+        set name [lindex $item 0]
+        set exp [lindex $item  1]
+        set numchild [lindex $item 2]
+        if {[llength $item] == 5} {
+            set type [lindex $item 3]
+            set value [lindex $item 4]
+
+            lappend children_exp\
+                "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
+        } elseif {[llength $item] == 4} {
+            set type [lindex $item 3]
+
+            lappend children_exp\
+                "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
+        } else {
+            lappend children_exp\
+                "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}"
+        }
+    }
+    return [join $children_exp ","]
+}
+
 # Check the results of the:
 #
 #   -var-list-children VARNAME
@@ -1265,39 +1316,23 @@ proc mi_check_varobj_value { name value testname } {
 # have no value.
 #
 proc mi_list_varobj_children { varname children testname } {
+    mi_list_varobj_children_range $varname [llength $children] $children \
+      $testname
+}
 
+# Like mi_list_varobj_children, but assumes that a subrange has been
+# selected with -var-set-child-range.  NUMCHILDREN is the total number
+# of children.
+proc mi_list_varobj_children_range {varname numchildren children testname} {
     set options ""
     if {[llength $varname] == 2} {
         set options [lindex $varname 1]
         set varname [lindex $varname 0]
     }
 
-    set numchildren [llength $children]
-    set children_exp {}
     set whatever "\"\[^\"\]+\""
 
-    foreach item $children {
-
-        set name [lindex $item 0]
-        set exp [lindex $item  1]
-        set numchild [lindex $item 2]
-        if {[llength $item] == 5} {
-            set type [lindex $item 3]
-            set value [lindex $item 4]
-
-            lappend children_exp\
-                "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
-        } elseif {[llength $item] == 4} {
-            set type [lindex $item 3]
-
-            lappend children_exp\
-                "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
-        } else {
-            lappend children_exp\
-                "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}"
-        }
-    }
-    set children_exp_j [join $children_exp ","]
+    set children_exp_j [mi_child_regexp $children 1]
     if {$numchildren} {
         set expected "\\^done,numchild=\".*\",children=\\\[$children_exp_j.*\\\]"
     } {
@@ -1770,3 +1805,25 @@ proc mi_check_thread_states { xstates test } {
     verbose -log "expecting: $pattern"
     mi_gdb_test "-thread-info" $pattern $test
 }
+
+# Return a list of MI features supported by this gdb.
+proc mi_get_features {} {
+    global expect_out mi_gdb_prompt
+
+    send_gdb "-list-features\n"
+
+    gdb_expect {
+	-re "\\^done,features=\\\[(.*)\\\]\r\n$mi_gdb_prompt$" {
+	    regsub -all -- \" $expect_out(1,string) "" features
+	    return [split $features ,]
+	}
+	-re ".*\r\n$mi_gdb_prompt$" {
+	    verbose -log "got $expect_out(buffer)"
+	    return ""
+	}
+	timeout {
+	    verbose -log "timeout in mi_gdb_prompt"
+	    return ""
+	}
+    }
+}
diff --git a/gdb/varobj.c b/gdb/varobj.c
index 0147ecb..e1fdbaf 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -35,6 +35,13 @@
 #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;
@@ -138,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;
 
@@ -159,6 +172,16 @@ struct varobj
      not fetched if either the variable is frozen, or any parents is
      frozen.  */
   int not_fetched;
+
+  /* Sub-range of children which the MI consumer has requested.  If
+     FROM < 0 or TO < 0, means that all children have been
+     requested.  */
+  int from;
+  int to;
+
+  /* The pretty-printer that has been constructed.  If NULL, then a
+     new printer object is needed, and one will be constructed.  */
+  PyObject *pretty_printer;
 };
 
 struct cpstack
@@ -190,6 +213,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);
@@ -215,6 +242,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);
@@ -233,12 +262,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);
@@ -572,6 +605,7 @@ varobj_create (char *objname,
 	}
     }
 
+  install_default_visualizer (var);
   discard_cleanups (old_chain);
   return var;
 }
@@ -678,6 +712,33 @@ varobj_delete (struct varobj *var, char ***dellist, int only_children)
   return delcount;
 }
 
+/* Convenience function for varobj_set_visualizer.  Instantiate a
+   pretty-printer for a given value.  */
+static PyObject *
+instantiate_pretty_printer (PyObject *constructor, struct value *value)
+{
+#if HAVE_PYTHON
+  PyObject *val_obj = NULL; 
+  PyObject *printer;
+  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;
+
+  printer = PyObject_CallFunctionObjArgs (constructor, val_obj, NULL);
+  Py_DECREF (val_obj);
+  return printer;
+#endif
+  return NULL;
+}
+
 /* Set/Get variable object display format */
 
 enum varobj_display_formats
@@ -702,7 +763,8 @@ varobj_set_display_format (struct varobj *var,
       && var->value && !value_lazy (var->value))
     {
       xfree (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->pretty_printer);
     }
 
   return var->format;
@@ -714,6 +776,21 @@ varobj_get_display_format (struct varobj *var)
   return var->format;
 }
 
+char *
+varobj_get_display_hint (struct varobj *var)
+{
+  char *result = NULL;
+
+#if HAVE_PYTHON
+  PyGILState_STATE state = PyGILState_Ensure ();
+  if (var->pretty_printer)
+    result = gdbpy_get_display_hint (var->pretty_printer);
+  PyGILState_Release (state);
+#endif
+
+  return result;
+}
+
 /* If the variable object is bound to a specific thread, that
    is its evaluation can always be done in context of a frame
    inside that thread, returns GDB id of the thread -- which
@@ -746,12 +823,141 @@ varobj_get_frozen (struct varobj *var)
   return var->frozen;
 }
 
+static int
+update_dynamic_varobj_children (struct varobj *var,
+				VEC (varobj_p) **changed,
+				VEC (varobj_p) **new_and_unchanged,
+				int *cchanged)
+
+{
+#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 *children;
+  PyObject *iterator;
+  int i;
+  int children_changed = 0;
+  PyObject *printer = var->pretty_printer;
+  PyGILState_STATE state;
+
+  state = PyGILState_Ensure ();
+  back_to = make_cleanup_py_restore_gil (&state);
+
+  *cchanged = 0;
+  if (!PyObject_HasAttr (printer, gdbpy_children_cst))
+    {
+      do_cleanups (back_to);
+      return 0;
+    }
+
+  children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
+					 NULL);
+
+  if (!children)
+    {
+      gdbpy_print_stack ();
+      error ("Null value returned for children");
+    }
+
+  make_cleanup_py_decref (children);
+
+  if (!PyIter_Check (children))
+    error ("Returned value is not iterable");
+
+  iterator = PyObject_GetIter (children);
+  if (!iterator)
+    {
+      gdbpy_print_stack ();
+      error ("Could not get children iterator");
+    }
+  make_cleanup_py_decref (iterator);
+
+  for (i = 0; ; ++i)
+    {
+      PyObject *item = PyIter_Next (iterator);
+      PyObject *py_v;
+      struct value *v;
+      char *name;
+      struct cleanup *inner;
+      
+      if (!item)
+	break;
+      inner = make_cleanup_py_decref (item);
+
+      if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
+	error ("Invalid item from the child list");
+      
+      if (PyObject_TypeCheck (py_v, &value_object_type))
+	{
+	  /* If we just call convert_value_from_python for this type,
+	     we won't know who owns the result.  For this one case we
+	     need to copy the resulting value.  */
+	  v = value_object_to_value (py_v);
+	  v = value_copy (v);
+	}
+      else
+	v = convert_value_from_python (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_unchanged)
+	    VEC_safe_push (varobj_p, *new_and_unchanged, 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_unchanged)
+		VEC_safe_push (varobj_p, *new_and_unchanged, existing);
+	    }
+	}
+
+      do_cleanups (inner);
+    }
+
+  if (i < VEC_length (varobj_p, var->children))
+    {
+      int i;
+      children_changed = 1;
+      for (i = 0; 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, i);
+  var->num_children = VEC_length (varobj_p, var->children);
+ 
+  do_cleanups (back_to);
+
+  *cchanged = children_changed;
+  return 1;
+#else
+  gdb_assert (0 && "should never be called if Python is not enabled");
+#endif
+}
 
 int
 varobj_get_num_children (struct varobj *var)
 {
   if (var->num_children == -1)
-    var->num_children = number_of_children (var);
+    {
+      int changed;
+      if (!var->pretty_printer
+	  || !update_dynamic_varobj_children (var, NULL, NULL, &changed))
+	var->num_children = number_of_children (var);
+    }
 
   return var->num_children;
 }
@@ -764,7 +970,16 @@ varobj_list_children (struct varobj *var)
 {
   struct varobj *child;
   char *name;
-  int i;
+  int i, children_changed;
+
+  var->children_requested = 1;
+
+  if (var->pretty_printer
+      /* 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, &children_changed))
+    return var->children;
 
   if (var->num_children == -1)
     var->num_children = number_of_children (var);
@@ -790,12 +1005,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 */
 
@@ -1002,6 +1229,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->pretty_printer)
+    changeable = 1;
+
   need_to_fetch = changeable;
 
   /* We are not interested in the address of references, and given
@@ -1053,12 +1287,14 @@ install_new_value (struct varobj *var, struct value *value, int initial)
 	}
     }
 
+
   /* Below, we'll be comparing string rendering of old and new
      values.  Don't get string rendering if the value is
      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->pretty_printer);
 
   /* 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
@@ -1123,6 +1359,150 @@ install_new_value (struct varobj *var, struct value *value, int initial)
   return changed;
 }
 
+/* Return the effective requested range for a varobj.  VAR is the
+   varobj.  CHILDREN is the computed list of children.  FROM and TO
+   are out parameters.  If VAR has no bounds selected, *FROM and *TO
+   will be set to the full range of CHILDREN.  Otherwise, *FROM and
+   *TO will be set to the selected sub-range of VAR, clipped to be in
+   range of CHILDREN.  */
+void
+varobj_get_child_range (struct varobj *var, VEC (varobj_p) *children,
+			int *from, int *to)
+{
+  if (var->from < 0 || var->to < 0)
+    {
+      *from = 0;
+      *to = VEC_length (varobj_p, children);
+    }
+  else
+    {
+      *from = var->from;
+      if (*from > VEC_length (varobj_p, children))
+	*from = VEC_length (varobj_p, children);
+      *to = var->to;
+      if (*to > VEC_length (varobj_p, children))
+	*to = VEC_length (varobj_p, children);
+    }
+}
+
+/* Set the selected sub-range of children of VAR to start at index
+   FROM and end at index TO.  If either FROM or TO is less than zero,
+   this is interpreted as a request for all children.  */
+void
+varobj_set_child_range (struct varobj *var, int from, int to)
+{
+  var->from = from;
+  var->to = to;
+}
+
+static void
+install_visualizer (struct varobj *var, PyObject *visualizer)
+{
+#if HAVE_PYTHON
+  /* If there are any children now, wipe them.  */
+  varobj_delete (var, NULL, 1 /* children only */);
+  var->num_children = -1;
+
+  Py_XDECREF (var->pretty_printer);
+  var->pretty_printer = visualizer;
+
+  install_new_value (var, var->value, 1);
+
+  /* If we removed the visualizer, and the user ever requested the
+     object's children, then we must compute the list of children.
+     Note that we needn't do this when installing a visualizer,
+     because updating will recompute dynamic children.  */
+  if (!visualizer && var->children_requested)
+    varobj_list_children (var);
+#else
+  error ("Python support required");
+#endif
+}
+
+static void
+install_default_visualizer (struct varobj *var)
+{
+#if HAVE_PYTHON
+  struct cleanup *cleanup;
+  PyGILState_STATE state;
+  PyObject *pretty_printer = NULL;
+
+  state = PyGILState_Ensure ();
+  cleanup = make_cleanup_py_restore_gil (&state);
+
+  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
+  /* No error is right as this function is inserted just as a hook.  */
+#endif
+}
+
+void 
+varobj_set_visualizer (struct varobj *var, const char *visualizer)
+{
+#if HAVE_PYTHON
+  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);
+
+  mainmod = PyImport_AddModule ("__main__");
+  globals = PyModule_GetDict (mainmod);
+  Py_INCREF (globals);
+  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);
+
+  Py_XDECREF (constructor);
+
+  if (! pretty_printer)
+    {
+      gdbpy_print_stack ();
+      error ("Could not evaluate visualizer expression: %s", visualizer);
+    }
+
+  if (pretty_printer == Py_None)
+    {
+      Py_DECREF (pretty_printer);
+      pretty_printer = NULL;
+    }
+
+  install_visualizer (var, pretty_printer);
+
+  do_cleanups (back_to);
+#else
+  error ("Python support required");
+#endif
+}
+
 /* 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
@@ -1148,7 +1528,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;
 
@@ -1187,20 +1567,85 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
       
       if (new == NULL)
 	r.status = VAROBJ_NOT_IN_SCOPE;
-
-      if (r.type_changed || r.changed)
-	VEC_safe_push (varobj_update_result, result, &r);
+      r.value_installed = 1;
 
       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 a
+	 pretty-printer, 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->pretty_printer)
+	{
+	  VEC (varobj_p) *changed = 0, *new_and_unchanged = 0;
+	  int i, children_changed;
+	  varobj_p tmp;
+
+	  if (!v->children_requested)
+	    continue;
+
+	  if (v->frozen)
+	    continue;
+
+	  /* If update_dynamic_varobj_children returns 0, then we have
+	     a non-conforming pretty-printer, so we skip it.  */
+	  if (update_dynamic_varobj_children (v, &changed, &new_and_unchanged,
+					      &children_changed))
+	    {
+	      if (children_changed)
+		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_unchanged, 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
@@ -1211,26 +1656,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;
 }
 
@@ -1429,16 +1866,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);
@@ -1487,6 +1931,10 @@ new_variable (void)
   var->print_value = NULL;
   var->frozen = 0;
   var->not_fetched = 0;
+  var->children_requested = 0;
+  var->from = -1;
+  var->to = -1;
+  var->pretty_printer = 0;
 
   return var;
 }
@@ -1521,6 +1969,14 @@ free_variable (struct varobj *var)
       xfree (var->root);
     }
 
+#if HAVE_PYTHON
+  {
+    PyGILState_STATE state = PyGILState_Ensure ();
+    Py_XDECREF (var->pretty_printer);
+    PyGILState_Release (state);
+  }
+#endif
+
   xfree (var->name);
   xfree (var->obj_name);
   xfree (var->print_value);
@@ -1795,23 +2251,65 @@ 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;
   struct cleanup *old_chain;
-  char *thevalue;
+  char *thevalue = NULL;
   struct value_print_options opts;
 
   if (value == NULL)
     return NULL;
 
+#if HAVE_PYTHON
+  {
+    PyGILState_STATE state = PyGILState_Ensure ();
+    if (value_formatter && PyObject_HasAttr (value_formatter,
+					     gdbpy_to_string_cst))
+      {
+	char *hint;
+	struct value *replacement;
+	int string_print = 0;
+
+	hint = gdbpy_get_display_hint (value_formatter);
+	if (hint)
+	  {
+	    if (!strcmp (hint, "string"))
+	      string_print = 1;
+	    xfree (hint);
+	  }
+
+	thevalue = apply_varobj_pretty_printer (value_formatter,
+						&replacement);
+	if (thevalue && !string_print)
+	  {
+	    PyGILState_Release (state);
+	    return thevalue;
+	  }
+	if (replacement)
+	  value = replacement;
+      }
+    PyGILState_Release (state);
+  }
+#endif
+
   stb = mem_fileopen ();
   old_chain = make_cleanup_ui_file_delete (stb);
 
   get_formatted_print_options (&opts, format_code[(int) format]);
   opts.deref_ref = 0;
-  common_val_print (value, stb, 0, &opts, current_language);
+  opts.raw = 1;
+  if (thevalue)
+    {
+      make_cleanup (xfree, thevalue);
+      LA_PRINT_STRING (stb, builtin_type (current_gdbarch)->builtin_char,
+		       (gdb_byte *) thevalue, strlen (thevalue),
+		       0, &opts);
+    }
+  else
+    common_val_print (value, stb, 0, &opts, current_language);
   thevalue = ui_file_xstrdup (stb, &dummy);
 
   do_cleanups (old_chain);
@@ -1902,7 +2400,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,
@@ -2271,6 +2769,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->pretty_printer && 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));
@@ -2315,7 +2818,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->pretty_printer);
 	  }
       }
     }
diff --git a/gdb/varobj.h b/gdb/varobj.h
index f2cdcf8..720cca5 100644
--- a/gdb/varobj.h
+++ b/gdb/varobj.h
@@ -71,8 +71,13 @@ typedef struct varobj_update_result_t
 {
   struct varobj *varobj;
   int type_changed;
+  int children_changed;
   int 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);
@@ -107,6 +112,14 @@ extern void varobj_set_frozen (struct varobj *var, int frozen);
 
 extern int varobj_get_frozen (struct varobj *var);
 
+extern void varobj_get_child_range (struct varobj *var,
+				    VEC (varobj_p) *children,
+				    int *from, int *to);
+
+extern void varobj_set_child_range (struct varobj *var, int from, int to);
+
+extern char *varobj_get_display_hint (struct varobj *var);
+
 extern int varobj_get_num_children (struct varobj *var);
 
 /* Return the list of children of VAR.  The returned vector
@@ -141,4 +154,6 @@ extern int varobj_editable_p (struct varobj *var);
 
 extern int varobj_floating_p (struct varobj *var);
 
+extern void varobj_set_visualizer (struct varobj *var, const char *visualizer);
+
 #endif /* VAROBJ_H */
-- 
1.6.0.6


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