[RFC] Variable objects for STL containers

Nick Roberts nickrob@snap.net.nz
Wed Feb 13 03:33:00 GMT 2008


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;
+ }
  
  
  /*
*************** 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);
!     }
  }


More information about the Gdb-patches mailing list