* [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 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
* 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
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