gdb
authorTom Tromey <tromey@redhat.com>
Thu, 28 May 2009 01:09:20 +0000 (01:09 +0000)
committerTom Tromey <tromey@redhat.com>
Thu, 28 May 2009 01:09:20 +0000 (01:09 +0000)
2009-05-27  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_display_hint): Likewise.
(varobj_update_result_t) <children_changed, value_installed>: New
fields.
* mi/mi-cmds.c (mi_cmds): Add var-set-visualizer.
* 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_list_children): 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, 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.
(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.

gdb/doc

2009-05-27  Tom Tromey  <tromey@redhat.com>

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

gdb/testsuite

2009-05-27  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.

15 files changed:
gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/mi/mi-cmd-var.c
gdb/mi/mi-cmds.c
gdb/mi/mi-cmds.h
gdb/mi/mi-main.c
gdb/python/python-internal.h
gdb/python/python-prettyprint.c
gdb/python/python.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.python/python-mi.exp [new file with mode: 0644]
gdb/testsuite/lib/mi-support.exp
gdb/varobj.c
gdb/varobj.h

index 8365765e31b91bf382fcdac58640234ce7e57ac3..fec8eb2b3fbca65da7e7d00336c458ee2b7d89dd 100644 (file)
@@ -1,3 +1,50 @@
+2009-05-27  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_display_hint): Likewise.
+       (varobj_update_result_t) <children_changed, value_installed>: New
+       fields.
+       * mi/mi-cmds.c (mi_cmds): Add var-set-visualizer.
+       * 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_list_children): 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, 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.
+       (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-05-27  Tom Tromey  <tromey@redhat.com>
            Thiago Jung Bauermann  <bauerman@br.ibm.com>
            Phil Muldoon  <pmuldoon@redhat.com>
index 2e28f37a8ee7247ffc1eb02b27f0e2789e1e4b55..95c9e6620d00ecb096cc850de49b7e91531535f1 100644 (file)
@@ -1,3 +1,15 @@
+2009-05-27  Tom Tromey  <tromey@redhat.com>
+
+       * gdb.texinfo (GDB/MI Miscellaneous Commands): Document "python"
+       feature.
+       (GDB/MI Variable Objects): Document -var-set-visualizer.
+
+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.
+
 2009-05-27  Tom Tromey  <tromey@redhat.com>
            Thiago Jung Bauermann  <bauerman@br.ibm.com>
            Phil Muldoon  <pmuldoon@redhat.com>
index 45e580cd2b6827e18767b883a0f5de61e542cdb4..971ed041aa64c8fbf1cdc6062adbbc66bee5bb13 100644 (file)
@@ -23442,6 +23442,64 @@ 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
+
+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 is done so that the same
+Python pretty-printing code can be used for both the CLI and MI).
+When called, this object 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
 
 @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @node GDB/MI Data Manipulation
@@ -25001,6 +25059,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.
 
index 9de8d3d005d7b6cf92a2845cb905e38f486587c6..cad411717377cbe6756da6145945058b2738917a 100644 (file)
@@ -242,6 +242,22 @@ mi_cmd_var_set_format (char *command, char **argv, int argc)
   ui_out_field_string (uiout, "value", varobj_get_value (var));
 }
 
+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_frozen (char *command, char **argv, int argc)
 {
@@ -357,6 +373,7 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
   int numchild;
   enum print_values print_values;
   int ix;
+  char *display_hint;
 
   if (argc != 1 && argc != 2)
     error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME"));
@@ -374,6 +391,13 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
   else
     print_values = PRINT_NO_VALUES;
 
+  display_hint = varobj_get_display_hint (var);
+  if (display_hint)
+    {
+      ui_out_field_string (uiout, "displayhint", display_hint);
+      xfree (display_hint);
+    }
+
   if (VEC_length (varobj_p, children) == 0)
     return;
 
@@ -634,6 +658,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));
@@ -667,6 +693,33 @@ 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;
+         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);
index df8f74a107bb04005619ff5c6c078d294c5c94b3..01f9a4bcbbed945409e1063a4d4a10fda4fd1721 100644 (file)
@@ -163,6 +163,7 @@ 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-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},
index 634aac1594bc5f97d0f122e9bac6d2d661a58f19..afcba1e4b42bee593a47cce54fad474e2534f5cf 100644 (file)
@@ -94,6 +94,7 @@ 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_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;
index 0bf2b84850290c1f925bf5cc9d904933b7ffc701..9a064c17bf6ffe9f28169d8134fde7ba8f9940e4 100644 (file)
@@ -1113,6 +1113,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;
     }
index 983d24d0984ff2bdce7f82fe470b5f78269ae071..35d38706e171c79b29cf69ba6b9021074ac174bb 100644 (file)
@@ -111,6 +111,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;
index 5be4f360d4368d6d8bd5667b12d0c06f854d861f..6e17f9ad7015dab15d1b7534ab7a40d7376b8ee3 100644 (file)
@@ -508,6 +508,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
index 19098ccebaf4feee2abc328114acd99153fd6119..7f32d665e8a2901ea0b601958192017ded7c35fb 100644 (file)
@@ -615,6 +615,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,
index f1b04641bc47b14940a392100906baea3af49a59..c4b0fab23a27557db27f525822ad4d772bb90e5b 100644 (file)
@@ -1,3 +1,13 @@
+2009-05-27  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.
+
 2009-05-27  Tom Tromey  <tromey@redhat.com>
            Thiago Jung Bauermann  <bauerman@br.ibm.com>
            Phil Muldoon  <pmuldoon@redhat.com>
diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp
new file mode 100644 (file)
index 0000000..3258810
--- /dev/null
@@ -0,0 +1,99 @@
+# 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
+# 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_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"
index c31111b3ebebcd11d4319a489e7f34ede3740be9..ad78360342e65579c36e5e7ea3408edb47ceba37 100644 (file)
@@ -1249,6 +1249,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" \
@@ -1256,6 +1271,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
@@ -1277,39 +1328,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.*\\\]"
     } {
@@ -1782,3 +1817,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 ""
+       }
+    }
+}
index e8556d78fd3d6f62d647a81657c5bbb644c38e26..ca698dce6bb2965c4449ab53891543b5c76abeb2 100644 (file)
 #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,10 @@ struct varobj
      not fetched if either the variable is frozen, or any parents is
      frozen.  */
   int not_fetched;
+
+  /* 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 +207,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 +236,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 +256,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);
@@ -570,6 +597,7 @@ varobj_create (char *objname,
        }
     }
 
+  install_default_visualizer (var);
   discard_cleanups (old_chain);
   return var;
 }
@@ -676,6 +704,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
@@ -700,7 +755,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;
@@ -712,6 +768,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
@@ -744,12 +815,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;
 }
@@ -762,7 +962,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);
@@ -788,12 +997,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 */
 
@@ -1003,6 +1224,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
@@ -1054,12 +1282,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
@@ -1133,6 +1363,114 @@ install_new_value (struct varobj *var, struct value *value, int initial)
   return changed;
 }
 
+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
@@ -1158,7 +1496,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;
 
@@ -1197,20 +1535,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
@@ -1221,26 +1624,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;
 }
 \f
@@ -1438,17 +1833,24 @@ uninstall_variable (struct varobj *var)
 /* Create and install a child of the parent of the given name */
 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);
@@ -1497,6 +1899,8 @@ new_variable (void)
   var->print_value = NULL;
   var->frozen = 0;
   var->not_fetched = 0;
+  var->children_requested = 0;
+  var->pretty_printer = 0;
 
   return var;
 }
@@ -1531,6 +1935,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);
@@ -1804,23 +2216,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);
@@ -1911,7 +2365,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,
@@ -2277,6 +2731,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));
@@ -2321,7 +2780,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);
          }
       }
     }
index f2cdcf8eff243712ef3a30f7f7683426585088a7..c1ad09904f7415c26774b497b828d59a5a4643c1 100644 (file)
@@ -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,8 @@ extern void varobj_set_frozen (struct varobj *var, int frozen);
 
 extern int varobj_get_frozen (struct varobj *var);
 
+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 +148,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 */