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:
Tom Tromey 2009-05-28 01:09:20 +00:00
parent a6bac58e84
commit b631324398
15 changed files with 961 additions and 61 deletions

View File

@ -1,3 +1,50 @@
2009-05-27 Vladimir Prus <vladimir@codesourcery.com>
Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
* mi/mi-main.c (mi_cmd_list_features): List "python" feature.
* varobj.h (varobj_set_visualizer): Declare.
(varobj_get_display_hint): Likewise.
(varobj_update_result_t) <children_changed, value_installed>: New
fields.
* mi/mi-cmds.c (mi_cmds): Add var-set-visualizer.
* mi/mi-cmds.h (mi_cmd_var_set_visualizer,
mi_cmd_var_set_child_range): Declare.
* mi/mi-cmd-var.c (mi_cmd_var_set_visualizer): New function.
(mi_cmd_var_list_children): Emit display hint.
(varobj_update_one): Emit display hint. Handle dynamic children.
* python/python.c (GdbMethods): Add "default_visualizer".
* python/python-internal.h (apply_varobj_pretty_printer,
gdbpy_get_varobj_pretty_printer, gdbpy_get_display_hint):
Declare.
(gdbpy_default_visualizer): Likewise.
* varobj.c: Include python.h, python-internal.h.
(PyObject): New typedef.
(struct varobj) <children_requested, pretty_printer>: New fields.
(varobj_create): Call install_default_visualizer.
(instantiate_pretty_printer): New function.
(varobj_set_display_format): Update.
(varobj_get_display_hint): New function.
(update_dynamic_varobj_children): New function.
(varobj_get_num_children): Handle dynamic children.
(varobj_list_children): Likewise.
(install_new_value): Likewise.
(varobj_add_child): New function.
(install_visualizer): Likewise.
(install_default_visualizer): Likewise.
(varobj_set_visualizer): Likewise.
(varobj_update): Handle dynamic children.
(create_child): Use create_child_with_value.
(create_child_with_value): New function.
(value_get_print_value): Call pretty printer. Add value_formatter
argument.
(c_value_of_variable): Update.
(varobj_invalidate): Always free all_rootvarobj.
* python/python-prettyprint.c (apply_varobj_pretty_printer): New
function.
(gdbpy_get_varobj_pretty_printer): Likewise.
(gdbpy_default_visualizer): Likewise.
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>

View File

@ -1,3 +1,15 @@
2009-05-27 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (GDB/MI Miscellaneous Commands): Document "python"
feature.
(GDB/MI Variable Objects): Document -var-set-visualizer.
2009-04-02 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (GDB/MI Miscellaneous Commands): Document "python"
feature.
(GDB/MI Variable Objects): Document -var-set-visualizer.
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>

View File

@ -23442,6 +23442,64 @@ Unfreezing a variable does not update it, only subsequent
(gdb)
@end smallexample
@subheading The @code{-var-set-visualizer} command
@findex -var-set-visualizer
@anchor{-var-set-visualizer}
@subsubheading Synopsis
@smallexample
-var-set-visualizer @var{name} @var{visualizer}
@end smallexample
Set a visualizer for the variable object @var{name}.
@var{visualizer} is the visualizer to use. The special value
@samp{None} means to disable any visualizer in use.
If not @samp{None}, @var{visualizer} must be a Python expression.
This expression must evaluate to a callable object which accepts a
single argument. @value{GDBN} will call this object with the value of
the varobj @var{name} as an argument (this is done so that the same
Python pretty-printing code can be used for both the CLI and MI).
When called, this object must return an object which conforms to the
pretty-printing interface (@pxref{Pretty Printing}).
The pre-defined function @code{gdb.default_visualizer} may be used to
select a visualizer by following the built-in process
(@pxref{Selecting Pretty-Printers}). This is done automatically when
a varobj is created, and so ordinarily is not needed.
This feature is only available if Python support is enabled. The MI
command @code{-list-features} (@pxref{GDB/MI Miscellaneous Commands})
can be used to check this.
@subsubheading Example
Resetting the visualizer:
@smallexample
(gdb)
-var-set-visualizer V None
^done
@end smallexample
Reselecting the default (type-based) visualizer:
@smallexample
(gdb)
-var-set-visualizer V gdb.default_visualizer
^done
@end smallexample
Suppose @code{SomeClass} is a visualizer class. A lambda expression
can be used to instantiate this class for a varobj:
@smallexample
(gdb)
-var-set-visualizer V "lambda val: SomeClass()"
^done
@end smallexample
@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@node GDB/MI Data Manipulation
@ -25001,6 +25059,10 @@ as possible presense of the @code{frozen} field in the output
of @code{-varobj-create}.
@item pending-breakpoints
Indicates presence of the @option{-f} option to the @code{-break-insert} command.
@item python
Indicates presence of Python scripting support, Python-based
pretty-printing commands, and possible presence of the
@samp{display_hint} field in the output of @code{-var-list-children}
@item thread-info
Indicates presence of the @code{-thread-info} command.

View File

@ -242,6 +242,22 @@ mi_cmd_var_set_format (char *command, char **argv, int argc)
ui_out_field_string (uiout, "value", varobj_get_value (var));
}
void
mi_cmd_var_set_visualizer (char *command, char **argv, int argc)
{
struct varobj *var;
if (argc != 2)
error ("Usage: NAME VISUALIZER_FUNCTION.");
var = varobj_get_handle (argv[0]);
if (var == NULL)
error ("Variable object not found");
varobj_set_visualizer (var, argv[1]);
}
void
mi_cmd_var_set_frozen (char *command, char **argv, int argc)
{
@ -357,6 +373,7 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
int numchild;
enum print_values print_values;
int ix;
char *display_hint;
if (argc != 1 && argc != 2)
error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME"));
@ -374,6 +391,13 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
else
print_values = PRINT_NO_VALUES;
display_hint = varobj_get_display_hint (var);
if (display_hint)
{
ui_out_field_string (uiout, "displayhint", display_hint);
xfree (display_hint);
}
if (VEC_length (varobj_p, children) == 0)
return;
@ -634,6 +658,8 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
for (i = 0; VEC_iterate (varobj_update_result, changes, i, r); ++i)
{
char *display_hint;
if (mi_version (uiout) > 1)
cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
ui_out_field_string (uiout, "name", varobj_get_objname (r->varobj));
@ -667,6 +693,33 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
ui_out_field_int (uiout, "new_num_children",
varobj_get_num_children (r->varobj));
}
display_hint = varobj_get_display_hint (var);
if (display_hint)
{
ui_out_field_string (uiout, "displayhint", display_hint);
xfree (display_hint);
}
if (r->children_changed)
{
int ix;
struct varobj *child;
struct cleanup *cleanup =
make_cleanup_ui_out_list_begin_end (uiout, "children");
VEC (varobj_p)* children = varobj_list_children (r->varobj);
for (ix = 0; VEC_iterate (varobj_p, children, ix, child); ++ix)
{
struct cleanup *cleanup_child;
cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
print_varobj (child, print_values, 1 /* print expression */);
do_cleanups (cleanup_child);
}
do_cleanups (cleanup);
}
if (mi_version (uiout) > 1)
do_cleanups (cleanup);

View File

@ -163,6 +163,7 @@ struct mi_cmd mi_cmds[] =
{ "var-list-children", { NULL, 0 }, mi_cmd_var_list_children},
{ "var-set-format", { NULL, 0 }, mi_cmd_var_set_format},
{ "var-set-frozen", { NULL, 0 }, mi_cmd_var_set_frozen},
{ "var-set-visualizer", { NULL, 0 }, mi_cmd_var_set_visualizer},
{ "var-show-attributes", { NULL, 0 }, mi_cmd_var_show_attributes},
{ "var-show-format", { NULL, 0 }, mi_cmd_var_show_format},
{ "var-update", { NULL, 0 }, mi_cmd_var_update},

View File

@ -94,6 +94,7 @@ extern mi_cmd_argv_ftype mi_cmd_var_info_type;
extern mi_cmd_argv_ftype mi_cmd_var_list_children;
extern mi_cmd_argv_ftype mi_cmd_var_set_format;
extern mi_cmd_argv_ftype mi_cmd_var_set_frozen;
extern mi_cmd_argv_ftype mi_cmd_var_set_visualizer;
extern mi_cmd_argv_ftype mi_cmd_var_show_attributes;
extern mi_cmd_argv_ftype mi_cmd_var_show_format;
extern mi_cmd_argv_ftype mi_cmd_var_update;

View File

@ -1113,6 +1113,10 @@ mi_cmd_list_features (char *command, char **argv, int argc)
ui_out_field_string (uiout, NULL, "pending-breakpoints");
ui_out_field_string (uiout, NULL, "thread-info");
#if HAVE_PYTHON
ui_out_field_string (uiout, NULL, "python");
#endif
do_cleanups (cleanup);
return;
}

View File

@ -111,6 +111,14 @@ char *python_string_to_host_string (PyObject *obj);
PyObject *target_string_to_unicode (const gdb_byte *str, int length);
int gdbpy_is_string (PyObject *obj);
/* Note that these are declared here, and not in python.h with the
other pretty-printer functions, because they refer to PyObject. */
char *apply_varobj_pretty_printer (PyObject *print_obj,
struct value **replacement);
PyObject *gdbpy_get_varobj_pretty_printer (struct value *value);
char *gdbpy_get_display_hint (PyObject *printer);
PyObject *gdbpy_default_visualizer (PyObject *self, PyObject *args);
extern PyObject *gdbpy_doc_cst;
extern PyObject *gdbpy_children_cst;
extern PyObject *gdbpy_to_string_cst;

View File

@ -508,6 +508,80 @@ apply_val_pretty_printer (struct type *type, const gdb_byte *valaddr,
return result;
}
/* Apply a pretty-printer for the varobj code. PRINTER_OBJ is the
print object. It must have a 'to_string' method (but this is
checked by varobj, not here) which takes no arguments and
returns a string. This function returns an xmalloc()d string if
the printer returns a string. The printer may return a replacement
value instead; in this case *REPLACEMENT is set to the replacement
value, and this function returns NULL. On error, *REPLACEMENT is
set to NULL and this function also returns NULL. */
char *
apply_varobj_pretty_printer (PyObject *printer_obj,
struct value **replacement)
{
char *result;
PyGILState_STATE state = PyGILState_Ensure ();
*replacement = NULL;
result = pretty_print_one_value (printer_obj, replacement);
if (result == NULL);
gdbpy_print_stack ();
PyGILState_Release (state);
return result;
}
/* Find a pretty-printer object for the varobj module. Returns a new
reference to the object if successful; returns NULL if not. VALUE
is the value for which a printer tests to determine if it
can pretty-print the value. */
PyObject *
gdbpy_get_varobj_pretty_printer (struct value *value)
{
PyObject *val_obj;
PyObject *pretty_printer = NULL;
volatile struct gdb_exception except;
TRY_CATCH (except, RETURN_MASK_ALL)
{
value = value_copy (value);
}
GDB_PY_HANDLE_EXCEPTION (except);
val_obj = value_to_value_object (value);
if (! val_obj)
return NULL;
pretty_printer = find_pretty_printer (val_obj);
Py_DECREF (val_obj);
return pretty_printer;
}
/* A Python function which wraps find_pretty_printer and instantiates
the resulting class. This accepts a Value argument and returns a
pretty printer instance, or None. This function is useful as an
argument to the MI command -var-set-visualizer. */
PyObject *
gdbpy_default_visualizer (PyObject *self, PyObject *args)
{
PyObject *val_obj;
PyObject *cons, *printer = NULL;
struct value *value;
if (! PyArg_ParseTuple (args, "O", &val_obj))
return NULL;
value = value_object_to_value (val_obj);
if (! value)
{
PyErr_SetString (PyExc_TypeError, "argument must be a gdb.Value");
return NULL;
}
cons = find_pretty_printer (val_obj);
return cons;
}
#else /* HAVE_PYTHON */
int

View File

@ -615,6 +615,9 @@ static PyMethodDef GdbMethods[] =
{ "get_parameter", get_parameter, METH_VARARGS,
"Return a gdb parameter's value" },
{ "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
"Find the default visualizer for a Value." },
{ "current_objfile", gdbpy_get_current_objfile, METH_NOARGS,
"Return the current Objfile being loaded, or None." },
{ "objfiles", gdbpy_objfiles, METH_NOARGS,

View File

@ -1,3 +1,13 @@
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
* lib/mi-support.exp (mi_varobj_update_dynamic): New proc.
(mi_child_regexp): Likewise.
(mi_list_varobj_children_range): Likewise.
(mi_get_features): Likewise.
(mi_list_varobj_children): Rewrite.
* gdb.python/python-mi.exp: New file.
2009-05-27 Tom Tromey <tromey@redhat.com>
Thiago Jung Bauermann <bauerman@br.ibm.com>
Phil Muldoon <pmuldoon@redhat.com>

View 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"

View File

@ -1249,6 +1249,21 @@ proc mi_varobj_update_with_type_change { name new_type new_children testname } {
mi_gdb_test "-var-update $name" $er $testname
}
# Update a dynamic varobj named NAME. CHILDREN is a list of children,
# in the same form as mi_list_varobj_children. TESTNAME is the name
# of the test.
proc mi_varobj_update_dynamic {name children testname} {
set children_exp_j [mi_child_regexp $children 0]
set er "\\^done,changelist=\\\["
append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\""
append er ",children=\\\[$children_exp_j.*\\\]}\\\]"
verbose -log "Expecting: $er"
mi_gdb_test "-var-update $name" $er $testname
}
proc mi_check_varobj_value { name value testname } {
mi_gdb_test "-var-evaluate-expression $name" \
@ -1256,6 +1271,42 @@ proc mi_check_varobj_value { name value testname } {
$testname
}
# Helper proc which constructs a child regexp for
# mi_list_varobj_children and mi_varobj_update_dynamic.
proc mi_child_regexp {children add_child} {
set children_exp {}
set whatever "\"\[^\"\]+\""
if {$add_child} {
set pre "child="
} else {
set pre ""
}
foreach item $children {
set name [lindex $item 0]
set exp [lindex $item 1]
set numchild [lindex $item 2]
if {[llength $item] == 5} {
set type [lindex $item 3]
set value [lindex $item 4]
lappend children_exp\
"$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
} elseif {[llength $item] == 4} {
set type [lindex $item 3]
lappend children_exp\
"$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
} else {
lappend children_exp\
"$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}"
}
}
return [join $children_exp ","]
}
# Check the results of the:
#
# -var-list-children VARNAME
@ -1277,39 +1328,23 @@ proc mi_check_varobj_value { name value testname } {
# have no value.
#
proc mi_list_varobj_children { varname children testname } {
mi_list_varobj_children_range $varname [llength $children] $children \
$testname
}
# Like mi_list_varobj_children, but assumes that a subrange has been
# selected with -var-set-child-range. NUMCHILDREN is the total number
# of children.
proc mi_list_varobj_children_range {varname numchildren children testname} {
set options ""
if {[llength $varname] == 2} {
set options [lindex $varname 1]
set varname [lindex $varname 0]
}
set numchildren [llength $children]
set children_exp {}
set whatever "\"\[^\"\]+\""
foreach item $children {
set name [lindex $item 0]
set exp [lindex $item 1]
set numchild [lindex $item 2]
if {[llength $item] == 5} {
set type [lindex $item 3]
set value [lindex $item 4]
lappend children_exp\
"child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
} elseif {[llength $item] == 4} {
set type [lindex $item 3]
lappend children_exp\
"child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
} else {
lappend children_exp\
"child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}"
}
}
set children_exp_j [join $children_exp ","]
set children_exp_j [mi_child_regexp $children 1]
if {$numchildren} {
set expected "\\^done,numchild=\".*\",children=\\\[$children_exp_j.*\\\]"
} {
@ -1782,3 +1817,25 @@ proc mi_check_thread_states { xstates test } {
verbose -log "expecting: $pattern"
mi_gdb_test "-thread-info" $pattern $test
}
# Return a list of MI features supported by this gdb.
proc mi_get_features {} {
global expect_out mi_gdb_prompt
send_gdb "-list-features\n"
gdb_expect {
-re "\\^done,features=\\\[(.*)\\\]\r\n$mi_gdb_prompt$" {
regsub -all -- \" $expect_out(1,string) "" features
return [split $features ,]
}
-re ".*\r\n$mi_gdb_prompt$" {
verbose -log "got $expect_out(buffer)"
return ""
}
timeout {
verbose -log "timeout in mi_gdb_prompt"
return ""
}
}
}

View File

@ -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);
}
}
}

View File

@ -71,8 +71,13 @@ typedef struct varobj_update_result_t
{
struct varobj *varobj;
int type_changed;
int children_changed;
int changed;
enum varobj_scope_status status;
/* This variable is used internally by varobj_update to indicate if the
new value of varobj is already computed and installed, or has to
be yet installed. Don't use this outside varobj.c */
int value_installed;
} varobj_update_result;
DEF_VEC_O (varobj_update_result);
@ -107,6 +112,8 @@ extern void varobj_set_frozen (struct varobj *var, int frozen);
extern int varobj_get_frozen (struct varobj *var);
extern char *varobj_get_display_hint (struct varobj *var);
extern int varobj_get_num_children (struct varobj *var);
/* Return the list of children of VAR. The returned vector
@ -141,4 +148,6 @@ extern int varobj_editable_p (struct varobj *var);
extern int varobj_floating_p (struct varobj *var);
extern void varobj_set_visualizer (struct varobj *var, const char *visualizer);
#endif /* VAROBJ_H */