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.
This commit is contained in:
parent
a6bac58e84
commit
b631324398
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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},
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
99
gdb/testsuite/gdb.python/python-mi.exp
Normal file
99
gdb/testsuite/gdb.python/python-mi.exp
Normal file
@ -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"
|
@ -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 ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
534
gdb/varobj.c
534
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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user