* [RFC] Variable objects for STL containers
@ 2008-02-13 3:33 Nick Roberts
2008-02-15 14:29 ` Marc Khouzam
2008-02-17 13:36 ` Vladimir Prus
0 siblings, 2 replies; 10+ messages in thread
From: Nick Roberts @ 2008-02-13 3:33 UTC (permalink / raw)
To: gdb-patches
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=us-ascii, Size: 11786 bytes --]
I realise that Vladimir is also working on this too but this patch doesn't
require Python scripting and it's quite simple too, just involving changes
to varobj.c and mi-cmd-var.c. It uses a special variable object to keep track
of the number of STL members as I described previously. It's for after the
release of 6.8 and intended as the basis of a discussion. I don't expect it to
be approved as is.
Here's a sample transaction. Currently the variable object must be created
after initialisation, e.g.,
(gdb)
n
&"n\n"
~"16\t vector<int> v1; // create an empty vector of integers\n"
^done
(gdb)
-var-create - * v
^done,name="var1",numchild="1",value="{...}",type="std::vector<int,std::allocator<int> >"
(gdb)
-var-list-children --all-values var1
^done,numchild="4",children=[child={name="var1.0",exp="0",numchild="0",value="3",type="long"},child={name="var1.1",exp="1",numchild="0",value="0",type="int"},child={name="var1.2",exp="2",numchild="0",value="0",type="int"},child={name="var1.3",exp="3",numchild="0",value="0",type="int"}]
(gdb)
so that GDB doesn't find a ridiculous (uninitialised) number of children.
Note there are four children. var1.0 is the special variable object which
is equal to the actual number of STL members.
(v._M_impl._M_finish - v._M_impl._M_start)
u
&"u\n"
~"33\t v[0] = 1;\n"
^done
(gdb)
u
&"u\n"
~"34\t v[1] = 11;\n"
^done
(gdb)
u
&"u\n"
~"35\t v[2] = 22;\n"
^done
(gdb)
Remember that line 35 hasn't been executed yet.
-var-update --all-values *
^done,changelist=[{name="var1.1",value="1",in_scope="true",type_changed="false"},{name="var1.2",value="11",in_scope="true",type_changed="false"}]
(gdb)
u
&"u\n"
~"36\t v.push_back (7);\n"
^done
(gdb)
Now it has.
-var-update --all-values *
^done,changelist=[{name="var1.3",value="22",in_scope="true",type_changed="false"}]
(gdb)
u
&"u\n"
~"38\t cout << endl;\n"
^done
(gdb)
Now v.push_back (7) has added a new member which changes the value of var1.0.
-var-update --all-values *
^done,changelist=[{name="var1.0",value="4",in_scope="true",type_changed="false"}]
(gdb)
And we can automatically see the new member here.
-var-list-children --all-values var1
^done,numchild="5",children=[child={name="var1.0",exp="0",numchild="0",value="4",type="long"},child={name="var1.1",exp="1",numchild="0",value="1",type="int"},child={name="var1.2",exp="2",numchild="0",value="11",type="int"},child={name="var1.3",exp="3",numchild="0",value="22",type="int"},child={name="var1.4",exp="4",numchild="0",value="7",type="int"}]
--
Nick http://www.inet.net.nz/~nickrob
2008-02-13 Nick Roberts <nickrob@snap.net.nz>
* varobj.c (struct varobj): New member.
(varobj_list_stl_children, create_stl_child, value_of_stl_child):
New functions.
(install_new_value): Create/delete STL children if number has changed.
(varobj_update): Update STL children.
(new_variable): Initialise stl component to 0.
* mi/mi-cmd-var.c: Include wrapper.h.
(mi_cmd_var_list_children): Compute STL children separately.
*** varobj.c 05 Feb 2008 09:38:32 +1300 1.103
--- varobj.c 13 Feb 2008 16:10:13 +1300
*************** struct varobj
*** 147,152 ****
--- 147,156 ----
not fetched if either the variable is frozen, or any parents is
frozen. */
int not_fetched;
+
+ /* 0 means normal varobj,
+ 1 means special varobj to track number of STL members. */
+ int stl;
};
struct cpstack
*************** static void uninstall_variable (struct v
*** 178,183 ****
--- 182,189 ----
static struct varobj *create_child (struct varobj *, int, char *);
+ static struct varobj *create_stl_child (struct varobj *, int, char *);
+
/* Utility routines */
static struct varobj *new_variable (void);
*************** static struct value *value_of_root (stru
*** 217,222 ****
--- 223,230 ----
static struct value *value_of_child (struct varobj *parent, int index);
+ static struct value *value_of_stl_child (struct varobj *parent, int index);
+
static char *my_value_of_variable (struct varobj *var);
static char *value_get_print_value (struct value *value,
*************** varobj_list_children (struct varobj *var
*** 758,763 ****
--- 766,815 ----
return var->children;
}
+ VEC (varobj_p)*
+ varobj_list_stl_children (struct varobj *var)
+ {
+ struct varobj *child;
+ struct value *value;
+ struct expression *expr;
+ char *stl_child;
+ char *name;
+ int i;
+
+
+ stl_child = xstrprintf ("%s.%s - %s.%s",
+ var->name, "_M_impl._M_finish",
+ var->name, "_M_impl._M_start");
+ expr = parse_expression (stl_child);
+ gdb_evaluate_expression (expr, &value);
+ var->num_children = 1 + (int) unpack_long (value_type (value),
+ value_contents (value));
+ xfree (stl_child);
+
+ /* If we're called when the list of children is not yet initialized,
+ allocate enough elements in it. */
+ while (VEC_length (varobj_p, var->children) < var->num_children)
+ VEC_safe_push (varobj_p, var->children, NULL);
+
+ for (i = 0; i < var->num_children; i++)
+ {
+ varobj_p existing = VEC_index (varobj_p, var->children, i);
+
+ if (existing == NULL)
+ {
+ /* Either it's the first call to varobj_list_children for
+ this variable object, and the child was never created,
+ or it was explicitly deleted by the client. */
+ name = xstrprintf ("%d", i);
+
+ existing = create_stl_child (var, i, name);
+ VEC_replace (varobj_p, var->children, i, existing);
+ }
+ }
+
+ return var->children;
+ }
+
/* Obtain the type of an object Variable as a string similar to the one gdb
prints on the console */
*************** install_new_value (struct varobj *var, s
*** 1055,1061 ****
gdb_assert (var->print_value != NULL && print_value != NULL);
if (strcmp (var->print_value, print_value) != 0)
! changed = 1;
}
}
}
--- 1107,1117 ----
gdb_assert (var->print_value != NULL && print_value != NULL);
if (strcmp (var->print_value, print_value) != 0)
! {
! changed = 1;
! if (var->stl)
! varobj_list_stl_children (var->parent);
! }
}
}
}
*************** varobj_update (struct varobj **varp, str
*** 1191,1197 ****
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 */
--- 1247,1266 ----
updated. */
if (v->root->rootvar != v)
{
! struct expression *expr;
! struct value *value;
! char* stl_member;
!
! //TODO: Just deal with vectors for the moment.
! stl_member = xstrprintf ("%s._M_impl._M_start",
! varobj_get_expression (v->parent));
! expr = parse_expression (stl_member);
! if (gdb_evaluate_expression (expr, &value))
! new = value_of_stl_child (v->parent, v->index);
! else
! new = value_of_child (v->parent, v->index);
! xfree (stl_member);
!
if (install_new_value (v, new, 0 /* type not changed */))
{
/* Note that it's changed */
*************** create_child (struct varobj *parent, int
*** 1448,1453 ****
--- 1517,1557 ----
return child;
}
+
+ static struct varobj *
+ create_stl_child (struct varobj *parent, int index, char *name)
+ {
+ struct varobj *child;
+ char *childs_name;
+ struct value *value;
+
+ child = new_variable ();
+
+ /* name is allocated by name_of_child */
+ child->name = name;
+ child->index = index;
+ value = value_of_stl_child (parent, index);
+ child->parent = parent;
+ child->root = parent->root;
+ childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
+ child->obj_name = childs_name;
+ if (index == 0) child->stl = 1;
+ install_variable (child);
+
+ /* Compute the type of the child. Must do this before
+ calling install_new_value. */
+ if (value != NULL)
+ /* If the child had no evaluation errors, var->value
+ will be non-NULL and contain a valid type. */
+ child->type = value_type (value);
+ else
+ /* Otherwise, we must compute the type. */
+ child->type = (*child->root->lang->type_of_child) (child->parent,
+ child->index);
+ install_new_value (child, value, 1);
+
+ return child;
+ }
\f
/*
*************** new_variable (void)
*** 1476,1481 ****
--- 1580,1586 ----
var->print_value = NULL;
var->frozen = 0;
var->not_fetched = 0;
+ var->stl = 0;
return var;
}
*************** value_of_child (struct varobj *parent, i
*** 1768,1773 ****
--- 1873,1901 ----
return value;
}
+ static struct value *
+ value_of_stl_child (struct varobj *parent, int index)
+ {
+ struct expression *expr;
+ struct value *value;
+ char *stl_child;
+
+ if (index == 0)
+ /* With i == 0, create a special varobj to detect creation/deletion
+ of STL members. */
+ stl_child = xstrprintf ("%s.%s - %s.%s",
+ parent->name, "_M_impl._M_finish",
+ parent->name, "_M_impl._M_start");
+ else
+ stl_child = xstrprintf ("*(%s.%s + %d)",
+ parent->name, "_M_impl._M_start", index - 1);
+
+ expr = parse_expression (stl_child);
+ gdb_evaluate_expression (expr, &value);
+ xfree (stl_child);
+ return value;
+ }
+
/* GDB already has a command called "value_of_variable". Sigh. */
static char *
my_value_of_variable (struct varobj *var)
*** mi-cmd-var.c 05 Feb 2008 12:13:22 +1300 1.45
--- mi-cmd-var.c 13 Feb 2008 15:41:50 +1300
***************
*** 28,33 ****
--- 28,34 ----
#include "value.h"
#include <ctype.h>
#include "gdb_string.h"
+ #include "wrapper.h"
const char mi_no_values[] = "--no-values";
const char mi_simple_values[] = "--simple-values";
*************** mi_cmd_var_list_children (char *command,
*** 361,366 ****
--- 362,370 ----
int numchild;
enum print_values print_values;
int ix;
+ struct expression *expr;
+ struct value *value;
+ char* stl_member;
if (argc != 1 && argc != 2)
error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME"));
*************** mi_cmd_var_list_children (char *command,
*** 373,379 ****
if (var == NULL)
error (_("Variable object not found"));
! children = varobj_list_children (var);
ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));
if (argc == 2)
print_values = mi_parse_values_option (argv[0]);
--- 377,391 ----
if (var == NULL)
error (_("Variable object not found"));
! //TODO: Just deal with vectors for the moment.
! stl_member = xstrprintf ("%s._M_impl._M_start", varobj_get_expression (var));
! expr = parse_expression (stl_member);
! if (gdb_evaluate_expression (expr, &value))
! children = varobj_list_stl_children (var);
! else
! children = varobj_list_children (var);
! xfree (stl_member);
!
ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));
if (argc == 2)
print_values = mi_parse_values_option (argv[0]);
*************** varobj_update_one (struct varobj *var, e
*** 651,657 ****
cc++;
}
xfree (changelist);
! }Write failed flushing stdout buffer.
! write stdout: Broken pipe
!
}
--- 663,667 ----
cc++;
}
xfree (changelist);
! }
}\x16º&Öéj×!zÊÞ¶êçç:ÖX¬µªÜ\a[¥«\
ë
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [RFC] Variable objects for STL containers
2008-02-13 3:33 [RFC] Variable objects for STL containers Nick Roberts
@ 2008-02-15 14:29 ` Marc Khouzam
2008-02-15 14:42 ` Daniel Jacobowitz
2008-02-15 21:57 ` Nick Roberts
2008-02-17 13:36 ` Vladimir Prus
1 sibling, 2 replies; 10+ messages in thread
From: Marc Khouzam @ 2008-02-15 14:29 UTC (permalink / raw)
To: Nick Roberts, gdb-patches
Hi,
> Here's a sample transaction. Currently the variable object must be created
> after initialisation, e.g.,
>
> -var-create - * v
> ^done,name="var1",numchild="1",value="{...}",type="std::vector<int,std::allocator<int> >"
> (gdb)
> -var-list-children --all-values var1
> ^done,numchild="4",children=[child={name="var1.0",exp="0",numchild="0",value="3",type="long"},child={name="var1.1",exp="1",numchild="0",value="0",type="int"},child={name="var1.2",exp="2",numchild="0",value="0",type="int"},child={name="var1.3",exp="3",numchild="0",value="0",type="int"}]
>
> so that GDB doesn't find a ridiculous (uninitialised) number of children.
> Note there are four children.
Note that I didn't look at the details of the patch yet, so I may be missing some info.
I noticed that in the var-create response of the example above, the number of children
is only 1 instead of 4. Is that just a typo?
Also I wanted to point out that with Eclipse, it may prove tricky to create
a variable object after initialization. In eclipse, when starting a debugged program,
the user (most) often selects the "Stop at main" option; that means that the program
will start showing variables right at main(). Since the command
-stack-list-locals shows all locals, even if they have not been declared yet, we
don't know if that variable is initialized yet, and we'll do the var-create and
var-list-children right away.
Is there a way to know that a variable has not been declared yet? Or maybe
we can add some support in GDB for this?
Marc
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Variable objects for STL containers
2008-02-15 14:29 ` Marc Khouzam
@ 2008-02-15 14:42 ` Daniel Jacobowitz
2008-02-15 21:57 ` Nick Roberts
1 sibling, 0 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-02-15 14:42 UTC (permalink / raw)
To: Marc Khouzam; +Cc: Nick Roberts, gdb-patches
On Fri, Feb 15, 2008 at 09:28:35AM -0500, Marc Khouzam wrote:
> Is there a way to know that a variable has not been declared yet? Or maybe
> we can add some support in GDB for this?
There's DWARF encodings for this information. But the data GCC
generates is insufficient, especially at -O0.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [RFC] Variable objects for STL containers
2008-02-15 14:29 ` Marc Khouzam
2008-02-15 14:42 ` Daniel Jacobowitz
@ 2008-02-15 21:57 ` Nick Roberts
1 sibling, 0 replies; 10+ messages in thread
From: Nick Roberts @ 2008-02-15 21:57 UTC (permalink / raw)
To: Marc Khouzam; +Cc: gdb-patches
> > Here's a sample transaction. Currently the variable object must be created
> > after initialisation, e.g.,
> >
> > -var-create - * v
> > ^done,name="var1",numchild="1",value="{...}",type="std::vector<int,std::allocator<int> >"
> > (gdb)
> > -var-list-children --all-values var1
> > ^done,numchild="4",children=[child={name="var1.0",exp="0",numchild="0",value="3",type="long"},child={name="var1.1",exp="1",numchild="0",value="0",type="int"},child={name="var1.2",exp="2",numchild="0",value="0",type="int"},child={name="var1.3",exp="3",numchild="0",value="0",type="int"}]
> >
> > so that GDB doesn't find a ridiculous (uninitialised) number of children.
> > Note there are four children.
>
> Note that I didn't look at the details of the patch yet, so I may be missing
> some info. I noticed that in the var-create response of the example above,
> the number of children is only 1 instead of 4. Is that just a typo?
No, it's real output :-). The patch doesn't check for STL containers until the
user tries to expand the watch expression (-var-list-children is issued)
although I guess, in the case of vectors, it would be quite easy to get the
number of children immediately.
--
Nick http://www.inet.net.nz/~nickrob
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Variable objects for STL containers
2008-02-13 3:33 [RFC] Variable objects for STL containers Nick Roberts
2008-02-15 14:29 ` Marc Khouzam
@ 2008-02-17 13:36 ` Vladimir Prus
2008-02-17 20:18 ` Nick Roberts
1 sibling, 1 reply; 10+ messages in thread
From: Vladimir Prus @ 2008-02-17 13:36 UTC (permalink / raw)
To: gdb-patches
Nick Roberts wrote:
>
> I realise that Vladimir is also working on this too but this patch doesn't
> require Python scripting and it's quite simple too, just involving changes
> to varobj.c and mi-cmd-var.c. It uses a special variable object to keep track
> of the number of STL members as I described previously. It's for after the
> release of 6.8 and intended as the basis of a discussion. I don't expect it to
> be approved as is.
>
> Here's a sample transaction. Currently the variable object must be created
> after initialisation, e.g.,
>
> (gdb)
> n
> &"n\n"
> ~"16\t vector<int> v1; // create an empty vector of integers\n"
> ^done
> (gdb)
> -var-create - * v
> ^done,name="var1",numchild="1",value="{...}",type="std::vector<int,std::allocator<int> >"
> (gdb)
> -var-list-children --all-values var1
>
^done,numchild="4",children=[child={name="var1.0",exp="0",numchild="0",value="3",type="long"},child={name="var1.1",exp="1",numchild="0",value="0",type="int"},child={name="var1.2",exp="2",numchild="0",value="0",type="int"},child={name="var1.3",exp="3",numchild="0",value="0",type="int"}]
> (gdb)
I don't particularly like the use of this special child to indicate
the number of children. We already have a mechanism to report the number of
children and having yet another mechanism seems just confusing.
Of course, if we use the existing mechanism then -var-update will have
to be able to report the variable objects that have the number of children
changed -- and a frontend will have to be adjusted to handle that mechanism.
However, it's not harder for frontend than the approach above. In fact,
using the approach above, how will frontend know that a varobj is
the special one that reports the number of children? I don't see anything
in the output above to indicate the special role of var1.0
> so that GDB doesn't find a ridiculous (uninitialised) number of children.
> Note there are four children. var1.0 is the special variable object which
> is equal to the actual number of STL members.
> (v._M_impl._M_finish - v._M_impl._M_start)
I must admit I don't know who to solve the problem of uninitialized
classes satisfactory, short of hacking gcc. The only thing we can do is
to use on-demand special presentation -- only when user requests it.
That sounds pretty uncool.
> u
> &"u\n"
> ~"33\t v[0] = 1;\n"
> ^done
> (gdb)
> u
> &"u\n"
> ~"34\t v[1] = 11;\n"
> ^done
> (gdb)
> u
> &"u\n"
> ~"35\t v[2] = 22;\n"
> ^done
> (gdb)
>
>
> Remember that line 35 hasn't been executed yet.
>
>
> -var-update --all-values *
> ^done,changelist=[{name="var1.1",value="1",in_scope="true",type_changed="false"}
{name="var1.2",value="11",in_scope="true",type_changed="false"}]
> (gdb)
> u
> &"u\n"
> ~"36\t v.push_back (7);\n"
> ^done
> (gdb)
>
>
> Now it has.
>
>
> -var-update --all-values *
> ^done,changelist=[{name="var1.3",value="22",in_scope="true",type_changed="false"}]
> (gdb)
> u
> &"u\n"
> ~"38\t cout << endl;\n"
> ^done
> (gdb)
>
>
> Now v.push_back (7) has added a new member which changes the value of var1.0.
>
>
> -var-update --all-values *
> ^done,changelist=[{name="var1.0",value="4",in_scope="true",type_changed="false"}]
> (gdb)
>
>
> And we can automatically see the new member here.
>
>
> -var-list-children --all-values var1
>
^done,numchild="5",children=[child={name="var1.0",exp="0",numchild="0",value="4",type="long"},child={name="var1.1",exp="1",numchild="0",value="1",type="int"},child={name="var1.2",exp="2",numchild="0",value="11",type="int"},child={name="var1.3",exp="3",numchild="0",value="22",type="int"},child={name="var1.4",exp="4",numchild="0",value="7",type="int"}]
>
I would have preferred for the new variable objects to be present in the
output of -var-update.
> *** varobj.c 05 Feb 2008 09:38:32 +1300 1.103
> --- varobj.c 13 Feb 2008 16:10:13 +1300
> *************** struct varobj
> *** 147,152 ****
> --- 147,156 ----
> not fetched if either the variable is frozen, or any parents is
> frozen. */
> int not_fetched;
> +
> + /* 0 means normal varobj,
> + 1 means special varobj to track number of STL members. */
> + int stl;
> };
>
> struct cpstack
> *************** static void uninstall_variable (struct v
> *** 178,183 ****
> --- 182,189 ----
>
> static struct varobj *create_child (struct varobj *, int, char *);
>
> + static struct varobj *create_stl_child (struct varobj *, int, char *);
> +
> /* Utility routines */
>
> static struct varobj *new_variable (void);
> *************** static struct value *value_of_root (stru
> *** 217,222 ****
> --- 223,230 ----
>
> static struct value *value_of_child (struct varobj *parent, int index);
>
> + static struct value *value_of_stl_child (struct varobj *parent, int index);
> +
> static char *my_value_of_variable (struct varobj *var);
>
> static char *value_get_print_value (struct value *value,
> *************** varobj_list_children (struct varobj *var
> *** 758,763 ****
> --- 766,815 ----
> return var->children;
> }
>
> + VEC (varobj_p)*
> + varobj_list_stl_children (struct varobj *var)
> + {
> + struct varobj *child;
> + struct value *value;
> + struct expression *expr;
> + char *stl_child;
> + char *name;
> + int i;
> +
> +
> + stl_child = xstrprintf ("%s.%s - %s.%s",
> + var->name, "_M_impl._M_finish",
> + var->name, "_M_impl._M_start");
> + expr = parse_expression (stl_child);
> + gdb_evaluate_expression (expr, &value);
> + var->num_children = 1 + (int) unpack_long (value_type (value),
> + value_contents (value));
IIUC, at this point the number of children can decrease. It does not seem like
we're informing the frontend about this, or free the varobjs. We probably should.
> + xfree (stl_child);
> +
> + /* If we're called when the list of children is not yet initialized,
> + allocate enough elements in it. */
> + while (VEC_length (varobj_p, var->children) < var->num_children)
> + VEC_safe_push (varobj_p, var->children, NULL);
> +
> + for (i = 0; i < var->num_children; i++)
> + {
> + varobj_p existing = VEC_index (varobj_p, var->children, i);
> +
> + if (existing == NULL)
> + {
> + /* Either it's the first call to varobj_list_children for
> + this variable object, and the child was never created,
> + or it was explicitly deleted by the client. */
> + name = xstrprintf ("%d", i);
> +
> + existing = create_stl_child (var, i, name);
> + VEC_replace (varobj_p, var->children, i, existing);
> + }
> + }
> +
> + return var->children;
> + }
> +
> /* Obtain the type of an object Variable as a string similar to the one gdb
> prints on the console */
>
> *************** install_new_value (struct varobj *var, s
> *** 1055,1061 ****
>
> gdb_assert (var->print_value != NULL && print_value != NULL);
> if (strcmp (var->print_value, print_value) != 0)
> ! changed = 1;
> }
> }
> }
> --- 1107,1117 ----
>
> gdb_assert (var->print_value != NULL && print_value != NULL);
> if (strcmp (var->print_value, print_value) != 0)
> ! {
> ! changed = 1;
> ! if (var->stl)
> ! varobj_list_stl_children (var->parent);
> ! }
> }
> }
> }
> *************** varobj_update (struct varobj **varp, str
> *** 1191,1197 ****
> 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 */
> --- 1247,1266 ----
> updated. */
> if (v->root->rootvar != v)
> {
> ! struct expression *expr;
> ! struct value *value;
> ! char* stl_member;
> !
> ! //TODO: Just deal with vectors for the moment.
> ! stl_member = xstrprintf ("%s._M_impl._M_start",
> ! varobj_get_expression (v->parent));
> ! expr = parse_expression (stl_member);
Is parse_expression guaranteed not to throw? (Not a rhetoric
question -- I don't know). If not, then you should use cleanup here.
> ! if (gdb_evaluate_expression (expr, &value))
> ! new = value_of_stl_child (v->parent, v->index);
> ! else
> ! new = value_of_child (v->parent, v->index);
> ! xfree (stl_member);
> !
> if (install_new_value (v, new, 0 /* type not changed */))
> {
> /* Note that it's changed */
> *************** create_child (struct varobj *parent, int
> *** 1448,1453 ****
> --- 1517,1557 ----
>
> return child;
> }
> +
> + static struct varobj *
> + create_stl_child (struct varobj *parent, int index, char *name)
> + {
> + struct varobj *child;
> + char *childs_name;
> + struct value *value;
> +
> + child = new_variable ();
> +
> + /* name is allocated by name_of_child */
> + child->name = name;
> + child->index = index;
> + value = value_of_stl_child (parent, index);
> + child->parent = parent;
> + child->root = parent->root;
> + childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
> + child->obj_name = childs_name;
> + if (index == 0) child->stl = 1;
> + install_variable (child);
> +
> + /* Compute the type of the child. Must do this before
> + calling install_new_value. */
> + if (value != NULL)
> + /* If the child had no evaluation errors, var->value
> + will be non-NULL and contain a valid type. */
> + child->type = value_type (value);
> + else
> + /* Otherwise, we must compute the type. */
> + child->type = (*child->root->lang->type_of_child) (child->parent,
> + child->index);
> + install_new_value (child, value, 1);
> +
> + return child;
How this one differs from create_child? It appears that the differences are minimal,
so a helper function is called for.
> + }
>
>
> /*
> *************** new_variable (void)
> *** 1476,1481 ****
> --- 1580,1586 ----
> var->print_value = NULL;
> var->frozen = 0;
> var->not_fetched = 0;
> + var->stl = 0;
>
> return var;
> }
> *************** value_of_child (struct varobj *parent, i
> *** 1768,1773 ****
> --- 1873,1901 ----
> return value;
> }
>
> + static struct value *
> + value_of_stl_child (struct varobj *parent, int index)
> + {
> + struct expression *expr;
> + struct value *value;
> + char *stl_child;
> +
> + if (index == 0)
> + /* With i == 0, create a special varobj to detect creation/deletion
> + of STL members. */
> + stl_child = xstrprintf ("%s.%s - %s.%s",
> + parent->name, "_M_impl._M_finish",
> + parent->name, "_M_impl._M_start");
> + else
> + stl_child = xstrprintf ("*(%s.%s + %d)",
> + parent->name, "_M_impl._M_start", index - 1);
> +
> + expr = parse_expression (stl_child);
> + gdb_evaluate_expression (expr, &value);
> + xfree (stl_child);
> + return value;
> + }
> +
> /* GDB already has a command called "value_of_variable". Sigh. */
> static char *
> my_value_of_variable (struct varobj *var)
>
>
>
> *** mi-cmd-var.c 05 Feb 2008 12:13:22 +1300 1.45
> --- mi-cmd-var.c 13 Feb 2008 15:41:50 +1300
> ***************
> *** 28,33 ****
> --- 28,34 ----
> #include "value.h"
> #include <ctype.h>
> #include "gdb_string.h"
> + #include "wrapper.h"
>
> const char mi_no_values[] = "--no-values";
> const char mi_simple_values[] = "--simple-values";
> *************** mi_cmd_var_list_children (char *command,
> *** 361,366 ****
> --- 362,370 ----
> int numchild;
> enum print_values print_values;
> int ix;
> + struct expression *expr;
> + struct value *value;
> + char* stl_member;
>
> if (argc != 1 && argc != 2)
> error (_("mi_cmd_var_list_children: Usage: [PRINT_VALUES] NAME"));
> *************** mi_cmd_var_list_children (char *command,
> *** 373,379 ****
> if (var == NULL)
> error (_("Variable object not found"));
>
> ! children = varobj_list_children (var);
> ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));
> if (argc == 2)
> print_values = mi_parse_values_option (argv[0]);
> --- 377,391 ----
> if (var == NULL)
> error (_("Variable object not found"));
>
> ! //TODO: Just deal with vectors for the moment.
> ! stl_member = xstrprintf ("%s._M_impl._M_start", varobj_get_expression (var));
> ! expr = parse_expression (stl_member);
> ! if (gdb_evaluate_expression (expr, &value))
> ! children = varobj_list_stl_children (var);
> ! else
> ! children = varobj_list_children (var);
I think it's clearer not to break encapsulation of varobj, and have just
varobj_list_children in the public interface, which then can do anything it likes.
This way, we won't need to adjust this place when we add some new kind of
special type.
> ! xfree (stl_member);
> !
> ui_out_field_int (uiout, "numchild", VEC_length (varobj_p, children));
> if (argc == 2)
> print_values = mi_parse_values_option (argv[0]);
> *************** varobj_update_one (struct varobj *var, e
> *** 651,657 ****
> cc++;
> }
> xfree (changelist);
> ! }Write failed flushing stdout buffer.
> ! write stdout: Broken pipe
> !
> }
> --- 663,667 ----
> cc++;
> }
> xfree (changelist);
> ! }
> }
There's one overall thing I'd do differently. In your patch,
we see varobj_list_stl_children, create_stl_child
and value_of_stl_child, where the first basically computes the number of children,
the third knows how to map from child index into value, and the second is a
helper function.
For scripting purposes, and for simplicity in general, in better if one
has to implement just one function for any new type. Further, while mapping
from index to value is simple for std::vector, it's much less trivial for
list, and even less trivial for map. We better not traverse the list when
getting each element.
So, I will prefer a mechanism where one can write a function taking a varobj.
That function should be able to compute the list of children, and then create
varobj children specifying the value directly. So, in case of std::list,
we'd traverse the list once, get the values and create varobjs with those
values. Of course, we'd need some support -- in particular a version of
create_child that takes a value. We will need to change varobj_update so
that it knows not to call value_of_child on children of special varobj, as well.
- Volodya
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Variable objects for STL containers
2008-02-17 13:36 ` Vladimir Prus
@ 2008-02-17 20:18 ` Nick Roberts
2008-02-17 21:57 ` Doug Evans
0 siblings, 1 reply; 10+ messages in thread
From: Nick Roberts @ 2008-02-17 20:18 UTC (permalink / raw)
To: Vladimir Prus; +Cc: gdb-patches
> I don't particularly like the use of this special child to indicate
> the number of children. We already have a mechanism to report the number of
> children and having yet another mechanism seems just confusing.
GDB needs some way to report the extra children in -var-update but I'm not
worried what way is used. I wanted to establish that using gcc internals was
OK and the feasibility of doing this within the C code.
> Of course, if we use the existing mechanism then -var-update will have
> to be able to report the variable objects that have the number of children
> changed -- and a frontend will have to be adjusted to handle that mechanism.
We should probably add an option to Gdb to process the STL container as a
variable object in the normal way and make that the default. That also will
mean we can write code for STL containers in an incremental fashion, provided
we explain this in the manual.
> However, it's not harder for frontend than the approach above. In fact,
> using the approach above, how will frontend know that a varobj is
> the special one that reports the number of children? I don't see anything
> in the output above to indicate the special role of var1.0
We could just add another field, stl="1" say to the output of var-update,
-var-list-children, etc.
>...
> For scripting purposes, and for simplicity in general, in better if one
> has to implement just one function for any new type. Further, while mapping
> from index to value is simple for std::vector, it's much less trivial for
> list, and even less trivial for map. We better not traverse the list when
> getting each element.
>
> So, I will prefer a mechanism where one can write a function taking a
> varobj. That function should be able to compute the list of children, and
> then create varobj children specifying the value directly. So, in case of
> std::list, we'd traverse the list once, get the values and create varobjs
> with those values. Of course, we'd need some support -- in particular a
> version of create_child that takes a value. We will need to change
> varobj_update so that it knows not to call value_of_child on children of
> special varobj, as well.
I think for lists, maps etc, Gdb needs to traverse the internal data structure
each to see if there are new elements or if any have been deleted. This need
only be done when execution stops, of course, but I guess it could be expensive
for stepping.
The ideas here are just for discussion and I'm more than happy to look at any
changes you might like to make.
--
Nick http://www.inet.net.nz/~nickrob
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Variable objects for STL containers
2008-02-17 20:18 ` Nick Roberts
@ 2008-02-17 21:57 ` Doug Evans
2008-02-17 22:27 ` Nick Roberts
2008-02-18 7:45 ` Vladimir Prus
0 siblings, 2 replies; 10+ messages in thread
From: Doug Evans @ 2008-02-17 21:57 UTC (permalink / raw)
To: Nick Roberts; +Cc: Vladimir Prus, gdb-patches
On Feb 17, 2008 12:18 PM, Nick Roberts <nickrob@snap.net.nz> wrote:
>
> I think for lists, maps etc, Gdb needs to traverse the internal data structure
> each to see if there are new elements or if any have been deleted. This need
> only be done when execution stops, of course, but I guess it could be expensive
> for stepping.
>
> The ideas here are just for discussion and I'm more than happy to look at any
> changes you might like to make.
There's something I don't understand, and maybe you can help clear
things up. It seems like this approach is going down a path of
hardwiring a lot of knowledge into gdb. Solving this just for STL
(and then only one version of STL) seems to be one piece of a general
problem, why pick an unscalable solution? If the knowledge was in a
collection of dlopen'd .so (or some such), and users could provide
more, then that might be reasonable. [Setting aside use of python for
this, I understand there is some pushback to going that route. It'd
be cool if the python support used the same interface, then one could
have it both ways. The python support is, of course, not just for
this and one wouldn't want python to plug into gdb in a piecemeal
fashion. OTOH, if a clean solution could be found that let one solve
this with either C[/C++] or python then that might be very useful.]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Variable objects for STL containers
2008-02-17 21:57 ` Doug Evans
@ 2008-02-17 22:27 ` Nick Roberts
2008-02-26 2:34 ` Daniel Jacobowitz
2008-02-18 7:45 ` Vladimir Prus
1 sibling, 1 reply; 10+ messages in thread
From: Nick Roberts @ 2008-02-17 22:27 UTC (permalink / raw)
To: Doug Evans; +Cc: Vladimir Prus, gdb-patches
> There's something I don't understand, and maybe you can help clear
> things up. It seems like this approach is going down a path of
> hardwiring a lot of knowledge into gdb. Solving this just for STL
> (and then only one version of STL) seems to be one piece of a general
> problem, why pick an unscalable solution?
This is not any STL, but Gcc's STL. Gdb and Gcc are both part of the GNU
project so should possibly have a special relationship. By unscaleable, I
guess you mean not general. Hardwiring is a worry but I have briefly discussed
this subject on the Gcc and been assured that the code used is quite stable.
It's also a matter of keeping Gcc developers informed about intended use of
Gcc internals.
> If the knowledge was in a
> collection of dlopen'd .so (or some such), and users could provide
> more, then that might be reasonable.
If you know how to do it, that would be an improvement. Presumably it could
also be done at a later stage, adapting any hardwired solution.
> [Setting aside use of python for
> this, I understand there is some pushback to going that route. It'd
> be cool if the python support used the same interface, then one could
> have it both ways. The python support is, of course, not just for
> this and one wouldn't want python to plug into gdb in a piecemeal
> fashion. OTOH, if a clean solution could be found that let one solve
> this with either C[/C++] or python then that might be very useful.]
I don't really understand how the python support will be implemented but I
don't see why variable objects for STL containers should require Python
libraries to be present.
--
Nick http://www.inet.net.nz/~nickrob
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Variable objects for STL containers
2008-02-17 21:57 ` Doug Evans
2008-02-17 22:27 ` Nick Roberts
@ 2008-02-18 7:45 ` Vladimir Prus
1 sibling, 0 replies; 10+ messages in thread
From: Vladimir Prus @ 2008-02-18 7:45 UTC (permalink / raw)
To: gdb-patches
Doug Evans wrote:
> On Feb 17, 2008 12:18 PM, Nick Roberts <nickrob@snap.net.nz> wrote:
>>
>> I think for lists, maps etc, Gdb needs to traverse the internal data structure
>> each to see if there are new elements or if any have been deleted. This need
>> only be done when execution stops, of course, but I guess it could be expensive
>> for stepping.
>>
>> The ideas here are just for discussion and I'm more than happy to look at any
>> changes you might like to make.
>
> There's something I don't understand, and maybe you can help clear
> things up. It seems like this approach is going down a path of
> hardwiring a lot of knowledge into gdb. Solving this just for STL
> (and then only one version of STL) seems to be one piece of a general
> problem, why pick an unscalable solution? If the knowledge was in a
> collection of dlopen'd .so (or some such), and users could provide
> more, then that might be reasonable. [Setting aside use of python for
> this, I understand there is some pushback to going that route. It'd
> be cool if the python support used the same interface, then one could
> have it both ways. The python support is, of course, not just for
> this and one wouldn't want python to plug into gdb in a piecemeal
> fashion. OTOH, if a clean solution could be found that let one solve
> this with either C[/C++] or python then that might be very useful.]
I think we should have Python as the official solution for those kinds
of things. While plugins might be nice, in order to implement plugins
you need gdb to install some headers one can compile against, and
maybe guarantee source and binary compatibility. Really, using Python,
where users don't have to compile anything, and where the interface for
extenders will be relatively small and capable of hiding gdb internals,
seems preferrable.
- Volodya
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Variable objects for STL containers
2008-02-17 22:27 ` Nick Roberts
@ 2008-02-26 2:34 ` Daniel Jacobowitz
0 siblings, 0 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-02-26 2:34 UTC (permalink / raw)
To: Nick Roberts; +Cc: Doug Evans, Vladimir Prus, gdb-patches
On Mon, Feb 18, 2008 at 11:27:08AM +1300, Nick Roberts wrote:
> This is not any STL, but Gcc's STL. Gdb and Gcc are both part of the GNU
> project so should possibly have a special relationship.
I agree, but I don't think this is the way to do it. I've found that
the easier we make it to hack on this sort of thing (in this case,
support for custom display of objects), the more likely we are to get
people who are experienced in the right areas to help out. Suppose we
support this as a bunch of text scripts, ignoring what language
they're written in. Then they can ship with GDB for old versions of
GCC but transition to shipping with GCC for new versions of libstdc++;
and I think the libstdc++ maintainers will be happy to improve them
and keep them up to date.
> I don't really understand how the python support will be implemented but I
> don't see why variable objects for STL containers should require Python
> libraries to be present.
Script engines are just tools. If we want to use tools, I think it's
OK to have a dependence on them. For practical reasons, I believe we
should use generally portable tools and (for now, at least) support
building a functional GDB without them; that's the decision we made
for expat.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2008-02-26 2:31 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-13 3:33 [RFC] Variable objects for STL containers Nick Roberts
2008-02-15 14:29 ` Marc Khouzam
2008-02-15 14:42 ` Daniel Jacobowitz
2008-02-15 21:57 ` Nick Roberts
2008-02-17 13:36 ` Vladimir Prus
2008-02-17 20:18 ` Nick Roberts
2008-02-17 21:57 ` Doug Evans
2008-02-17 22:27 ` Nick Roberts
2008-02-26 2:34 ` Daniel Jacobowitz
2008-02-18 7:45 ` Vladimir Prus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox