aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2009-05-28 01:09:20 +0000
committerTom Tromey <tromey@redhat.com>2009-05-28 01:09:20 +0000
commitb6313243984b74ee6772dd8273b0e6073ad1815b (patch)
tree79db018823e681990855f3c379c40e2cc7de9f6e
parenta6bac58e84001d33b9540e208e9ca6d6ab265bf3 (diff)
downloadgdb-b6313243984b74ee6772dd8273b0e6073ad1815b.zip
gdb-b6313243984b74ee6772dd8273b0e6073ad1815b.tar.gz
gdb-b6313243984b74ee6772dd8273b0e6073ad1815b.tar.bz2
gdb
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.
-rw-r--r--gdb/ChangeLog47
-rw-r--r--gdb/doc/ChangeLog12
-rw-r--r--gdb/doc/gdb.texinfo62
-rw-r--r--gdb/mi/mi-cmd-var.c53
-rw-r--r--gdb/mi/mi-cmds.c1
-rw-r--r--gdb/mi/mi-cmds.h1
-rw-r--r--gdb/mi/mi-main.c4
-rw-r--r--gdb/python/python-internal.h8
-rw-r--r--gdb/python/python-prettyprint.c74
-rw-r--r--gdb/python/python.c3
-rw-r--r--gdb/testsuite/ChangeLog10
-rw-r--r--gdb/testsuite/gdb.python/python-mi.exp99
-rw-r--r--gdb/testsuite/lib/mi-support.exp105
-rw-r--r--gdb/varobj.c534
-rw-r--r--gdb/varobj.h9
15 files changed, 961 insertions, 61 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 8365765..fec8eb2 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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>
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 2e28f37..95c9e66 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,4 +1,16 @@
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>
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 45e580c..971ed04 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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.
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 9de8d3d..cad4117 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -243,6 +243,22 @@ 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_frozen (char *command, char **argv, int argc)
{
struct varobj *var;
@@ -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);
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index df8f74a..01f9a4b 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -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},
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 634aac1..afcba1e 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -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;
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 0bf2b84..9a064c1 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -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;
}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 983d24d..35d3870 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -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;
diff --git a/gdb/python/python-prettyprint.c b/gdb/python/python-prettyprint.c
index 5be4f36..6e17f9a 100644
--- a/gdb/python/python-prettyprint.c
+++ b/gdb/python/python-prettyprint.c
@@ -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
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 19098cc..7f32d66 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -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,
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index f1b0464..c4b0fab 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,15 @@
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>
Paul Pluzhnikov <ppluzhnikov@google.com>
diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp
new file mode 100644
index 0000000..3258810
--- /dev/null
+++ b/gdb/testsuite/gdb.python/python-mi.exp
@@ -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"
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index c31111b..ad78360 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -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 ""
+ }
+ }
+}
diff --git a/gdb/varobj.c b/gdb/varobj.c
index e8556d7..ca698dc 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,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;
}
@@ -1439,16 +1834,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);
@@ -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);
}
}
}
diff --git a/gdb/varobj.h b/gdb/varobj.h
index f2cdcf8..c1ad099 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,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 */