This is the mail archive of the
archer@sourceware.org
mailing list for the Archer project.
[python] FYI: reimplment python varobj support
- From: Tom Tromey <tromey at redhat dot com>
- To: Project Archer <archer at sourceware dot org>
- Cc: Vladimir Prus <vladimir at codesourcery dot com>
- Date: Thu, 06 Aug 2009 14:44:29 -0600
- Subject: [python] FYI: reimplment python varobj support
- Reply-to: Tom Tromey <tromey at redhat dot com>
I'm checking this in on the python branch.
This implements the new python varobj spec to the best of my
understanding. There are a few oddities in here that I will explain in
a follow-up on the gdb list discussion about the spec.
Tom
b/gdb/ChangeLog:
2009-08-06 Tom Tromey <tromey@redhat.com>
* varobj.h (varobj_update_result_t) <new>: New field.
(varobj_get_child_range): Update.
(varobj_list_children): Update. Rewrite documentation.
(varobj_has_more): Declare.
* varobj.c (struct varobj) <child_iter, saved_item>: New fields.
(varobj_has_more): New function.
(restrict_range, install_dynamic_child): Likewise.
(update_dynamic_varobj_children): Change 'new_and_unchanged' to
'new'. Add 'update_children' and 'to' arguments. Fix logic to
conform to new spec.
(varobj_get_num_children): Don't call
update_dynamic_varobj_children.
(varobj_list_children): Add from, to arguments. Restrict result
range.
(install_visualizer): Clear child_iter field.
(varobj_get_child_range): Remove 'children' argument. Rewrite.
(varobj_update): Set 'new' field on result object. Fix logic to
conform to new spec.
(new_variable): Initialize new fields.
(free_variable): Destroy new fields.
(value_of_root): Copy from and to fields.
* mi/mi-cmds.h (mi_cmd_var_set_update_range): Declare.
* mi/mi-cmds.c (mi_cmds): Add var-set-update-range.
* mi/mi-cmd-var.c (mi_cmd_var_list_children): Don't set child
range. Use varobj_has_more.
(varobj_update_one): Emit new_num_children when the children
changed. Use varobj_has_more. Emit the new_children list.
(mi_cmd_var_set_update_range): New function.
b/gdb/doc/ChangeLog:
2009-08-06 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (GDB/MI Variable Objects): Document
-var-set-update-range.
b/gdb/testsuite/ChangeLog:
2009-08-06 Tom Tromey <tromey@redhat.com>
* lib/mi-support.exp (mi_create_floating_varobj): Update.
(mi_varobj_update_kv_helper): New proc.
(mi_varobj_update_dynamic_helper): Likewise.
(mi_varobj_update_dynamic): Rewrite.
* gdb.python/python-prettyprint.c (main): Update container in "MI"
mode.
* gdb.python/python-mi.exp: Update.
projecttype:gdb
email:tromey@gcc.gnu.org
revision:97a2b241637c361bb7c7ab48b342c4341ab9f80e
configure:
make:
check:
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2b8fcc7..fd7c9ab 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -23663,6 +23663,8 @@ access this functionality:
@tab update the variable and its children
@item @code{-var-set-frozen}
@tab set frozeness attribute
+@item @code{-var-set-update-range}
+@tab set range of children to display on update
@end multitable
In the next subsection we describe each operation in detail and suggest
@@ -23836,9 +23838,7 @@ and unions.
to report. If @var{from} or @var{to} is less than zero, the range is
reset and all children will be reported. Otherwise, children starting
at @var{from} (zero-based) and ending just before @var{to} will be
-reported. The selected range is sticky; future calls to
-@code{-var-update} or @code{-var-list-children} will use any
-previously set range.
+reported.
For each child the following results are returned:
@@ -23871,7 +23871,11 @@ Otherwise this result is not present.
@item frozen
If the variable object is frozen, this variable will be present with a value of 1.
+@end table
+
+The result may have its own attributes:
+@table @var
@item has_more
This is an integer attribute which is nonzero if there are children
remaining after the end of the selected range.
@@ -24058,6 +24062,9 @@ With the @samp{*} parameter, if a variable object is bound to a
currently running thread, it will not be updated, without any
diagnostic.
+If @code{-var-set-update-range} was previously used on a varobj, then
+only the selected range of children will be reported.
+
@subsubheading Example
@smallexample
@@ -24125,6 +24132,32 @@ Unfreezing a variable does not update it, only subsequent
(gdb)
@end smallexample
+@subheading The @code{-var-set-update-range} command
+@findex -var-set-update-range
+@anchor{-var-set-update-range}
+
+@subsubheading Synopsis
+
+@smallexample
+ -var-set-update-range @var{name} @var{from} @var{to}
+@end smallexample
+
+Set the range of children to be returned by future invocations of
+@code{-var-update}.
+
+@var{from} and @var{to} indicate the range of children to report. If
+@var{from} or @var{to} is less than zero, the range is reset and all
+children will be reported. Otherwise, children starting at @var{from}
+(zero-based) and ending just before @var{to} will be reported.
+
+@subsubheading Example
+
+@smallexample
+(gdb)
+-var-set-update-range V 1 2
+^done
+@end smallexample
+
@subheading The @code{-var-set-visualizer} command
@findex -var-set-visualizer
@anchor{-var-set-visualizer}
diff --git a/gdb/mi/mi-cmd-var.c b/gdb/mi/mi-cmd-var.c
index 82f7220..e5f237d 100644
--- a/gdb/mi/mi-cmd-var.c
+++ b/gdb/mi/mi-cmd-var.c
@@ -388,20 +388,20 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
{
from = atoi (argv[argc - 2]);
to = atoi (argv[argc - 1]);
- varobj_set_child_range (var, from, to);
+ }
+ else
+ {
+ from = -1;
+ to = -1;
}
- children = varobj_list_children (var);
+ children = varobj_list_children (var, &from, &to);
ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));
if (argc == 2 || argc == 4)
print_values = mi_parse_values_option (argv[0]);
else
print_values = PRINT_NO_VALUES;
- /* Re-fetch the child range, because varobj_get_child_range computes
- the real start and end indices for us. */
- varobj_get_child_range (var, children, &from, &to);
-
display_hint = varobj_get_display_hint (var);
if (display_hint)
{
@@ -430,8 +430,7 @@ mi_cmd_var_list_children (char *command, char **argv, int argc)
do_cleanups (cleanup_children);
}
- ui_out_field_int (uiout, "has_more",
- VEC_length (varobj_p, children) > to);
+ ui_out_field_int (uiout, "has_more", varobj_has_more (var, to));
}
void
@@ -698,11 +697,11 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
}
if (r->type_changed)
- {
- ui_out_field_string (uiout, "new_type", varobj_get_type (r->varobj));
- ui_out_field_int (uiout, "new_num_children",
- varobj_get_num_children (r->varobj));
- }
+ ui_out_field_string (uiout, "new_type", varobj_get_type (r->varobj));
+
+ if (r->type_changed || r->children_changed)
+ ui_out_field_int (uiout, "new_num_children",
+ varobj_get_num_children (r->varobj));
display_hint = varobj_get_display_hint (var);
if (display_hint)
@@ -713,30 +712,32 @@ varobj_update_one (struct varobj *var, enum print_values print_values,
if (r->children_changed)
{
- int ix, from, to;
- struct varobj *child;
- struct cleanup *cleanup =
- make_cleanup_ui_out_list_begin_end (uiout, "children");
+ int from, to;
+ varobj_get_child_range (r->varobj, &from, &to);
+ ui_out_field_int (uiout, "has_more",
+ varobj_has_more (r->varobj, to));
+ }
- VEC (varobj_p)* children = varobj_list_children (r->varobj);
- varobj_get_child_range (r->varobj, children, &from, &to);
+ if (r->new)
+ {
+ int j;
+ varobj_p child;
+ struct cleanup *cleanup;
- for (ix = from;
- ix < to && VEC_iterate (varobj_p, children, ix, child);
- ++ix)
+ cleanup = make_cleanup_ui_out_list_begin_end (uiout, "new_children");
+ for (j = 0; VEC_iterate (varobj_p, r->new, j, child); ++j)
{
struct cleanup *cleanup_child;
cleanup_child = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- print_varobj (child, print_values, 1 /* print expression */);
+ print_varobj (child, print_values, 1 /* print_expression */);
do_cleanups (cleanup_child);
}
do_cleanups (cleanup);
-
- ui_out_field_int (uiout, "has_more",
- VEC_length (varobj_p, children) > to);
+ VEC_free (varobj_p, r->new);
+ r->new = NULL; /* Paranoia. */
}
-
+
if (mi_version (uiout) > 1)
do_cleanups (cleanup);
}
@@ -750,3 +751,19 @@ mi_cmd_enable_pretty_printing (char *command, char **argv, int argc)
error (_("mi_cmd_enable_pretty_printing: no arguments allowed"));
varobj_enable_pretty_printing ();
}
+
+void
+mi_cmd_var_set_update_range (char *command, char **argv, int argc)
+{
+ struct varobj *var;
+ int from, to;
+
+ if (argc != 3)
+ error (_("mi_cmd_var_set_update_range: Usage: VAROBJ FROM TO"));
+
+ var = varobj_get_handle (argv[0]);
+ from = atoi (argv[1]);
+ to = atoi (argv[2]);
+
+ varobj_set_child_range (var, from, to);
+}
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 772566e..ef25cba 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -112,6 +112,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-update-range", { NULL, 0 }, mi_cmd_var_set_update_range },
{ "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},
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 79798ef..b0d68ed 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -99,6 +99,7 @@ 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;
extern mi_cmd_argv_ftype mi_cmd_enable_pretty_printing;
+extern mi_cmd_argv_ftype mi_cmd_var_set_update_range;
/* Description of a single command. */
diff --git a/gdb/testsuite/gdb.python/python-mi.exp b/gdb/testsuite/gdb.python/python-mi.exp
index e7bfe54..095ee78 100644
--- a/gdb/testsuite/gdb.python/python-mi.exp
+++ b/gdb/testsuite/gdb.python/python-mi.exp
@@ -69,16 +69,21 @@ mi_list_varobj_children container {
mi_next "next over update 1"
-mi_varobj_update_dynamic container {
- { {container.\[0\]} {\[0\]} 0 int }
-} "varobj update 1"
+mi_varobj_update_dynamic container "varobj update 1" {
+ type_changed false new_num_children 1 has_more 0
+} {
+} {
+ { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 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_varobj_update_dynamic container "varobj update 2" {
+ type_changed false new_num_children 2 has_more 0
+} {
+} {
+ { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 }
+}
mi_gdb_test "-var-set-visualizer container None" \
"\\^done" \
@@ -92,19 +97,26 @@ 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_varobj_update_dynamic container "varobj update after choosing default" {
+ type_changed false new_num_children 2 has_more 0
+} {
+} {
+ { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 }
+ { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 }
+}
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_varobj_update_dynamic container \
+ "varobj update after choosing via expression" {
+ type_changed false new_num_children 2 has_more 0
+ } {
+ } {
+ { name {container.\[0\]} exp {\[0\]} numchild 0 type int thread-id 1 }
+ { name {container.\[1\]} exp {\[1\]} numchild 0 type int thread-id 1 }
+ }
mi_list_varobj_children_range container 1 2 2 {
{ {container.\[1\]} {\[1\]} 0 int }
@@ -115,6 +127,39 @@ mi_list_varobj_children_range container -1 -1 2 {
{ {container.\[1\]} {\[1\]} 0 int }
} "list varobj children after resetting child range"
+mi_next "next over update 3"
+
+mi_gdb_test "-var-set-update-range container 0 1" \
+ "\\^done" \
+ "set update range"
+
+# This should truncate the list.
+mi_list_varobj_children container {
+ { {container.\[0\]} {\[0\]} 0 int }
+} "list children after setting update range"
+
+# This should return just the items in [1,2).
+mi_list_varobj_children_range container 1 2 2 {
+ { {container.\[1\]} {\[1\]} 0 int }
+} "list selected children after setting range"
+
+# This should not be affected by the previous list-children request.
+mi_list_varobj_children container {
+ { {container.\[0\]} {\[0\]} 0 int }
+} "list children after listing selected range"
+
+mi_next "next over update 4"
+
+# This should only show the first child, because the update range has
+# been set.
+mi_varobj_update_dynamic container \
+ "update after next with restricted range" {
+ type_changed false new_num_children 1 has_more 1
+ } {
+ { name {container.\[0\]} in_scope true type_changed false }
+ } {
+ }
+
mi_continue_to_line \
[gdb_get_line_number {Another MI breakpoint} ${testfile}.c] \
"step to second breakpoint"
diff --git a/gdb/testsuite/gdb.python/python-prettyprint.c b/gdb/testsuite/gdb.python/python-prettyprint.c
index 5cc35be..6bbbf1d 100644
--- a/gdb/testsuite/gdb.python/python-prettyprint.c
+++ b/gdb/testsuite/gdb.python/python-prettyprint.c
@@ -203,6 +203,9 @@ main ()
add_item (&c, 72);
#ifdef MI
+ add_item (&c, 1011);
+ c.elements[0] = 1023;
+
do_nothing ();
#endif
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 33f277a..f6b62e2 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1200,7 +1200,7 @@ proc mi_create_varobj { name expression testname } {
proc mi_create_floating_varobj { name expression testname } {
mi_gdb_test "-var-create $name @ $expression" \
- "\\^done,name=\"$name\",numchild=\"\[0-9\]+\",value=\".*\",type=.*" \
+ "\\^done,name=\"$name\",numchild=\"\(-1\|\[0-9\]+\)\",value=\".*\",type=.*" \
$testname
}
@@ -1249,16 +1249,64 @@ 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]
+# A helper that turns a key/value list into a regular expression
+# matching some MI output.
+proc mi_varobj_update_kv_helper {list} {
+ set first 1
+ set rx ""
+ foreach {key value} $list {
+ if {!$first} {
+ append rx ,
+ }
+ set first 0
+ if {$key == "new_children"} {
+ append rx "$key=\\\[$value\\\]"
+ } else {
+ append rx "$key=\"$value\""
+ }
+ }
+ return $rx
+}
+
+# A helper for mi_varobj_update_dynamic that computes a match
+# expression given a child list.
+proc mi_varobj_update_dynamic_helper {children} {
+ set crx ""
- set er "\\^done,changelist=\\\["
+ set first 1
+ foreach child $children {
+ if {!$first} {
+ append crx ,
+ }
+ set first 0
+ append crx "{"
+ append crx [mi_varobj_update_kv_helper $child]
+ append crx "}"
+ }
+
+ return $crx
+}
- append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\""
- append er ",children=\\\[$children_exp_j.*\\\],has_more=\".\"}\\\]"
+# Update a dynamic varobj named NAME. CHILDREN is a list of children
+# that have been updated; NEW_CHILDREN is a list of children that were
+# added to the primary varobj. Each child is a list of key/value
+# pairs that are expected. SELF is a key/value list holding
+# information about the varobj itself. TESTNAME is the name of the
+# test.
+proc mi_varobj_update_dynamic {name testname self children new_children} {
+ if {[llength $new_children]} {
+ set newrx [mi_varobj_update_dynamic_helper $new_children]
+ lappend self new_children $newrx
+ }
+ set selfrx [mi_varobj_update_kv_helper $self]
+ set crx [mi_varobj_update_dynamic_helper $children]
+
+ set er "\\^done,changelist=\\\[\{name=\"$name\",in_scope=\"true\""
+ append er ",$selfrx\}"
+ if {"$crx" != ""} {
+ append er ",$crx"
+ }
+ append er "\\\]"
verbose -log "Expecting: $er"
mi_gdb_test "-var-update $name" $er $testname
diff --git a/gdb/varobj.c b/gdb/varobj.c
index a3938d0..2a0d317 100644
--- a/gdb/varobj.c
+++ b/gdb/varobj.c
@@ -197,6 +197,17 @@ struct varobj
/* The pretty-printer that has been constructed. If NULL, then a
new printer object is needed, and one will be constructed. */
PyObject *pretty_printer;
+
+ /* The iterator returned by the printer's 'children' method, or NULL
+ if not available. */
+ PyObject *child_iter;
+
+ /* We request one extra item from the iterator, so that we can
+ report to the caller whether there are more items than we have
+ already reported. However, we don't want to install this value
+ when we read it, because that will mess up future updates. So,
+ we stash it here instead. */
+ PyObject *saved_item;
};
struct cpstack
@@ -815,6 +826,17 @@ varobj_get_display_hint (struct varobj *var)
return result;
}
+/* Return true if the varobj has items after TO, false otherwise. */
+
+int
+varobj_has_more (struct varobj *var, int to)
+{
+ if (VEC_length (varobj_p, var->children) > to)
+ return 1;
+ return (VEC_length (varobj_p, var->children) == to
+ && var->saved_item != NULL);
+}
+
/* 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
@@ -847,22 +869,73 @@ varobj_get_frozen (struct varobj *var)
return var->frozen;
}
+/* A helper function that restricts a range to what is actually
+ available in a VEC. This follows the usual rules for the meaning
+ of FROM and TO -- if either is negative, the entire range is
+ used. */
+
+static void
+restrict_range (VEC (varobj_p) *children, int *from, int *to)
+{
+ if (*from < 0 || *to < 0)
+ {
+ *from = 0;
+ *to = VEC_length (varobj_p, children);
+ }
+ else
+ {
+ if (*from > VEC_length (varobj_p, children))
+ *from = VEC_length (varobj_p, children);
+ if (*to > VEC_length (varobj_p, children))
+ *to = VEC_length (varobj_p, children);
+ if (*from > *to)
+ *from = *to;
+ }
+}
+
+/* A helper for update_dynamic_varobj_children that installs a new
+ child when needed. */
+
+static void
+install_dynamic_child (struct varobj *var,
+ VEC (varobj_p) **changed,
+ VEC (varobj_p) **new,
+ int *cchanged,
+ int index,
+ const char *name,
+ struct value *value)
+{
+ if (VEC_length (varobj_p, var->children) < index + 1)
+ {
+ /* There's no child yet. */
+ struct varobj *child = varobj_add_child (var, name, value);
+ if (new)
+ VEC_safe_push (varobj_p, *new, child);
+ *cchanged = 1;
+ }
+ else
+ {
+ varobj_p existing = VEC_index (varobj_p, var->children, index);
+ if (install_new_value (existing, value, 0))
+ {
+ if (changed)
+ VEC_safe_push (varobj_p, *changed, existing);
+ }
+ }
+}
+
static int
update_dynamic_varobj_children (struct varobj *var,
VEC (varobj_p) **changed,
- VEC (varobj_p) **new_and_unchanged,
- int *cchanged)
-
+ VEC (varobj_p) **new,
+ int *cchanged,
+ int update_children,
+ int to)
{
#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;
back_to = varobj_ensure_python_env (var);
@@ -874,89 +947,103 @@ update_dynamic_varobj_children (struct varobj *var,
return 0;
}
- children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
- NULL);
-
- if (!children)
+ if (update_children || !var->child_iter)
{
- gdbpy_print_stack ();
- error (_("Null value returned for children"));
- }
+ children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
+ NULL);
- make_cleanup_py_decref (children);
+ if (!children)
+ {
+ gdbpy_print_stack ();
+ error (_("Null value returned for children"));
+ }
- if (!PyIter_Check (children))
- error (_("Returned value is not iterable"));
+ make_cleanup_py_decref (children);
- iterator = PyObject_GetIter (children);
- if (!iterator)
- {
- gdbpy_print_stack ();
- error (_("Could not get children iterator"));
+ if (!PyIter_Check (children))
+ error (_("Returned value is not iterable"));
+
+ Py_XDECREF (var->child_iter);
+ var->child_iter = PyObject_GetIter (children);
+ if (!var->child_iter)
+ {
+ gdbpy_print_stack ();
+ error (_("Could not get children iterator"));
+ }
+
+ Py_XDECREF (var->saved_item);
+ var->saved_item = NULL;
+
+ i = 0;
}
- make_cleanup_py_decref (iterator);
+ else
+ i = VEC_length (varobj_p, var->children);
/* We ask for one extra child, so that MI can report whether there
are more children. */
- for (i = 0; var->to < 0 || i < var->to + 1; ++i)
+ for (; to < 0 || i < to + 1; ++i)
{
- PyObject *item = PyIter_Next (iterator);
- PyObject *py_v;
- struct value *v;
- char *name;
- struct cleanup *inner;
-
+ PyObject *item;
+
+ /* See if there was a leftover from last time. */
+ if (var->saved_item)
+ {
+ item = var->saved_item;
+ var->saved_item = NULL;
+ }
+ else
+ item = PyIter_Next (var->child_iter);
+
if (!item)
break;
- inner = make_cleanup_py_decref (item);
- if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
- error (_("Invalid item from the child list"));
-
- v = convert_value_from_python (py_v);
+ /* We don't want to push the extra child on any report list. */
+ if (to < 0 || i < to)
+ {
+ PyObject *py_v;
+ char *name;
+ struct value *v;
+ struct cleanup *inner;
- /* TODO: This assume the name of the i-th child never changes. */
+ inner = make_cleanup_py_decref (item);
- /* 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;
+ if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
+ error (_("Invalid item from the child list"));
+
+ v = convert_value_from_python (py_v);
+ install_dynamic_child (var, changed, new,
+ cchanged, i, name, v);
+ do_cleanups (inner);
}
- else
+ 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);
- }
- }
+ Py_XDECREF (var->saved_item);
+ var->saved_item = item;
- do_cleanups (inner);
+ /* We want to truncate the child list just before this
+ element. */
+ break;
+ }
}
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);
+ int j;
+ *cchanged = 1;
+ for (j = i; j < VEC_length (varobj_p, var->children); ++j)
+ varobj_delete (VEC_index (varobj_p, var->children, j), NULL, 0);
+ VEC_truncate (varobj_p, var->children, i);
}
- VEC_truncate (varobj_p, var->children, i);
+
+ /* If there are fewer children than requested, note that the list of
+ children changed. */
+ if (to >= 0 && VEC_length (varobj_p, var->children) < to)
+ *cchanged = 1;
+
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");
@@ -969,8 +1056,7 @@ varobj_get_num_children (struct varobj *var)
if (var->num_children == -1)
{
int changed;
- if (!var->pretty_printer
- || !update_dynamic_varobj_children (var, NULL, NULL, &changed))
+ if (!var->pretty_printer)
var->num_children = number_of_children (var);
}
@@ -981,7 +1067,7 @@ varobj_get_num_children (struct varobj *var)
the return code is the number of such children or -1 on error */
VEC (varobj_p)*
-varobj_list_children (struct varobj *var)
+varobj_list_children (struct varobj *var, int *from, int *to)
{
struct varobj *child;
char *name;
@@ -993,8 +1079,12 @@ varobj_list_children (struct varobj *var)
/* 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;
+ && update_dynamic_varobj_children (var, NULL, NULL, &children_changed,
+ 0, *to))
+ {
+ restrict_range (var->children, from, to);
+ return var->children;
+ }
if (var->num_children == -1)
var->num_children = number_of_children (var);
@@ -1023,6 +1113,7 @@ varobj_list_children (struct varobj *var)
}
}
+ restrict_range (var->children, from, to);
return var->children;
}
@@ -1216,6 +1307,9 @@ install_visualizer (struct varobj *var, PyObject *constructor,
Py_XDECREF (var->pretty_printer);
var->pretty_printer = visualizer;
+
+ Py_XDECREF (var->child_iter);
+ var->child_iter = NULL;
}
/* Install the default visualizer for VAR. */
@@ -1475,30 +1569,15 @@ install_new_value (struct varobj *var, struct value *value, int initial)
return changed;
}
-/* Return the effective requested range for a varobj. VAR is the
- varobj. CHILDREN is the computed list of children. FROM and TO
- are out parameters. If VAR has no bounds selected, *FROM and *TO
- will be set to the full range of CHILDREN. Otherwise, *FROM and
- *TO will be set to the selected sub-range of VAR, clipped to be in
- range of CHILDREN. */
+/* Return the requested range for a varobj. VAR is the varobj. FROM
+ and TO are out parameters; *FROM and *TO will be set to the
+ selected sub-range of VAR. If no range was selected using
+ -var-set-update-range, then both will be -1. */
void
-varobj_get_child_range (struct varobj *var, VEC (varobj_p) *children,
- int *from, int *to)
+varobj_get_child_range (struct varobj *var, int *from, int *to)
{
- if (var->from < 0 || var->to < 0)
- {
- *from = 0;
- *to = VEC_length (varobj_p, children);
- }
- else
- {
- *from = var->from;
- if (*from > VEC_length (varobj_p, children))
- *from = VEC_length (varobj_p, children);
- *to = var->to;
- if (*to > VEC_length (varobj_p, children))
- *to = VEC_length (varobj_p, children);
- }
+ *from = var->from;
+ *to = var->to;
}
/* Set the selected sub-range of children of VAR to start at index
@@ -1653,7 +1732,7 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
UI, so we need not bother getting it. */
if (v->pretty_printer)
{
- VEC (varobj_p) *changed = 0, *new_and_unchanged = 0;
+ VEC (varobj_p) *changed = 0, *new = 0;
int i, children_changed;
varobj_p tmp;
@@ -1665,28 +1744,28 @@ VEC(varobj_update_result) *varobj_update (struct varobj **varp, int explicit)
/* 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 (update_dynamic_varobj_children (v, &changed, &new,
+ &children_changed, 1, v->to))
{
- if (children_changed)
- r.children_changed = 1;
- for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i)
+ if (children_changed || new)
{
- varobj_update_result r = {tmp};
- r.changed = 1;
- r.value_installed = 1;
- VEC_safe_push (varobj_update_result, stack, &r);
+ r.children_changed = 1;
+ r.new = new;
}
- for (i = 0;
- VEC_iterate (varobj_p, new_and_unchanged, i, tmp);
- ++i)
+ 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);
}
if (r.changed || r.children_changed)
VEC_safe_push (varobj_update_result, result, &r);
+
+ /* Free CHANGED, but not NEW, because NEW has been put
+ into the result vector. */
+ VEC_free (varobj_p, changed);
+
continue;
}
}
@@ -1980,6 +2059,8 @@ new_variable (void)
var->to = -1;
var->constructor = 0;
var->pretty_printer = 0;
+ var->child_iter = 0;
+ var->saved_item = 0;
return var;
}
@@ -2009,7 +2090,10 @@ free_variable (struct varobj *var)
if (var->pretty_printer)
{
struct cleanup *cleanup = varobj_ensure_python_env (var);
- Py_DECREF (var->pretty_printer);
+ Py_XDECREF (var->constructor);
+ Py_XDECREF (var->pretty_printer);
+ Py_XDECREF (var->child_iter);
+ Py_XDECREF (var->saved_item);
do_cleanups (cleanup);
}
#endif
@@ -2256,6 +2340,8 @@ value_of_root (struct varobj **var_handle, int *type_changed)
else
{
tmp_var->obj_name = xstrdup (var->obj_name);
+ tmp_var->from = var->from;
+ tmp_var->to = var->to;
varobj_delete (var, NULL, 0);
install_variable (tmp_var);
diff --git a/gdb/varobj.h b/gdb/varobj.h
index 35053f8..635acf9 100644
--- a/gdb/varobj.h
+++ b/gdb/varobj.h
@@ -78,6 +78,12 @@ typedef struct varobj_update_result_t
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;
+
+ /* This will be non-NULL when new children were added to the varobj.
+ It lists the new children (which must necessarily come at the end
+ of the child list) added during an update. The caller is
+ responsible for freeing this vector. */
+ VEC (varobj_p) *new;
} varobj_update_result;
DEF_VEC_O (varobj_update_result);
@@ -112,9 +118,7 @@ extern void varobj_set_frozen (struct varobj *var, int frozen);
extern int varobj_get_frozen (struct varobj *var);
-extern void varobj_get_child_range (struct varobj *var,
- VEC (varobj_p) *children,
- int *from, int *to);
+extern void varobj_get_child_range (struct varobj *var, int *from, int *to);
extern void varobj_set_child_range (struct varobj *var, int from, int to);
@@ -122,9 +126,16 @@ 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
- should not be modified in any way. */
-extern VEC (varobj_p)* varobj_list_children (struct varobj *var);
+/* Return the list of children of VAR. The returned vector should not
+ be modified in any way. FROM and TO are in/out parameters
+ indicating the range of children to return. If either *FROM or *TO
+ is less than zero on entry, then all children will be returned. On
+ return, *FROM and *TO will be updated to indicate the real range
+ that was returned. The resulting VEC will contain at least the
+ children from *FROM to just before *TO; it might contain more
+ children, depending on whether any more were available. */
+extern VEC (varobj_p)* varobj_list_children (struct varobj *var,
+ int *from, int *to);
extern char *varobj_get_type (struct varobj *var);
@@ -159,4 +170,6 @@ varobj_set_visualizer (struct varobj *var, const char *visualizer);
extern void varobj_enable_pretty_printing (void);
+extern int varobj_has_more (struct varobj *var, int to);
+
#endif /* VAROBJ_H */