Index: varobj.c =================================================================== RCS file: /cvs/src/src/gdb/varobj.c,v retrieving revision 1.58 diff -u -p -r1.58 varobj.c --- varobj.c 14 Feb 2006 19:05:40 -0000 1.58 +++ varobj.c 17 Mar 2006 14:25:08 -0000 @@ -42,6 +42,10 @@ show_varobjdebug (struct ui_file *file, fprintf_filtered (file, _("Varobj debugging is %s.\n"), value); } +/* Non-zero if we use a varobj's full type to construct its children. */ +static int varobj_use_dynamic_type = 1; + + /* String representations of gdb's format codes */ char *varobj_format_string[] = { "natural", "binary", "decimal", "hexadecimal", "octal" }; @@ -91,6 +95,10 @@ struct varobj /* NOTE: This is the "expression" */ char *name; + /* Alloc'd expression for this child. Can be used to create a + root variable corresponding to this child. */ + char *path_expr; + /* The alloc'd name for this variable's object. This is here for convenience when constructing this object's children. */ char *obj_name; @@ -101,6 +109,17 @@ struct varobj /* The type of this variable. This may NEVER be NULL. */ struct type *type; + /* This is the most specific type of a C++ class object - as obtained from + value_rtti_type. It will be set in two cases: + + a) If the varobj is a pointer or reference to a C++ object. In this + case the dynamic_type will be a pointer or reference to the full + class. + b) If the varobj is a C++ object. In this case, it will be the type + of the full object, and the value field will be adjusted by + value_full_object to the full object. */ + struct type *dynamic_type; + /* The value of this expression or subexpression. This may be NULL. */ struct value *value; @@ -176,7 +195,7 @@ static int install_variable (struct varo static void uninstall_variable (struct varobj *); -static struct varobj *child_exists (struct varobj *, char *); +static struct varobj *child_exists (struct varobj *, int index); static struct varobj *create_child (struct varobj *, int, char *); @@ -196,7 +215,7 @@ static struct cleanup *make_cleanup_free static struct type *get_type (struct varobj *var); -static struct type *get_type_deref (struct varobj *var); +static struct type *get_type_deref (struct varobj *var, int *was_ptr); static struct type *get_target_type (struct type *); @@ -220,8 +239,12 @@ static int number_of_children (struct va static char *name_of_variable (struct varobj *); +static char *path_expr_of_variable (struct varobj *); + static char *name_of_child (struct varobj *, int); +static char *path_expr_of_child (struct varobj *, int); + static struct value *value_of_root (struct varobj **var_handle, int *); static struct value *value_of_child (struct varobj *parent, int index); @@ -232,6 +255,8 @@ static int variable_editable (struct var static char *my_value_of_variable (struct varobj *var); +static int is_root_p (struct varobj *var); + static int type_changeable (struct varobj *var); /* C implementation */ @@ -242,6 +267,8 @@ static char *c_name_of_variable (struct static char *c_name_of_child (struct varobj *parent, int index); +static char *c_path_expr_of_child (struct varobj *parent, int index); + static struct value *c_value_of_root (struct varobj **var_handle); static struct value *c_value_of_child (struct varobj *parent, int index); @@ -262,6 +289,8 @@ static char *cplus_name_of_variable (str static char *cplus_name_of_child (struct varobj *parent, int index); +static char *cplus_path_expr_of_child (struct varobj *parent, int index); + static struct value *cplus_value_of_root (struct varobj **var_handle); static struct value *cplus_value_of_child (struct varobj *parent, int index); @@ -280,6 +309,8 @@ static char *java_name_of_variable (stru static char *java_name_of_child (struct varobj *parent, int index); +static char *java_path_expr_of_child (struct varobj *parent, int index); + static struct value *java_value_of_root (struct varobj **var_handle); static struct value *java_value_of_child (struct varobj *parent, int index); @@ -307,6 +338,9 @@ struct language_specific /* The name of the INDEX'th child of PARENT. */ char *(*name_of_child) (struct varobj * parent, int index); + /* Returns the rooted expression of the INDEX'th child of PARENT. */ + char *(*path_expr_of_child) (struct varobj * parent, int index); + /* The ``struct value *'' of the root variable ROOT. */ struct value *(*value_of_root) (struct varobj ** root_handle); @@ -332,6 +366,7 @@ static struct language_specific c_number_of_children, c_name_of_variable, c_name_of_child, + c_path_expr_of_child, c_value_of_root, c_value_of_child, c_type_of_child, @@ -344,6 +379,7 @@ static struct language_specific c_number_of_children, c_name_of_variable, c_name_of_child, + c_path_expr_of_child, c_value_of_root, c_value_of_child, c_type_of_child, @@ -356,6 +392,7 @@ static struct language_specific cplus_number_of_children, cplus_name_of_variable, cplus_name_of_child, + cplus_path_expr_of_child, cplus_value_of_root, cplus_value_of_child, cplus_type_of_child, @@ -368,6 +405,7 @@ static struct language_specific java_number_of_children, java_name_of_variable, java_name_of_child, + java_path_expr_of_child, java_value_of_root, java_value_of_child, java_type_of_child, @@ -380,6 +418,12 @@ enum vsections { v_public = 0, v_private, v_protected }; +static int cplus_real_type_index_for_fake_child_index ( + struct type *type, + enum vsections prot, + int num); + + /* Private data */ @@ -402,6 +446,12 @@ static struct vlist **varobj_table; ((x) != NULL && (x)->type == NULL && (x)->value == NULL) +static int +is_root_p (struct varobj *var) +{ + return (var->root->rootvar == var); +} + /* API Implementation */ /* Creates a varobj (not its children) */ @@ -436,6 +486,7 @@ varobj_create (char *objname, struct frame_info *old_fi = NULL; struct block *block; struct cleanup *old_chain; + int expr_len; /* Fill out a varobj structure for the (root) variable being constructed. */ var = new_root_variable (); @@ -489,7 +540,12 @@ varobj_create (char *objname, var->format = variable_default_display (var); var->root->valid_block = innermost_block; - var->name = savestring (expression, strlen (expression)); + + /* Cache expr_len so we don't compute it twice. */ + expr_len = strlen (expression); + var->name = savestring (expression, expr_len); + /* For a root var, the name and the expr are the same... */ + var->path_expr = savestring (expression, expr_len); /* When the frame is different from the current frame, we must select the appropriate frame before parsing @@ -717,10 +773,12 @@ varobj_list_children (struct varobj *var *((*childlist) + i) = NULL; /* check if child exists, if not create */ - name = name_of_child (var, i); - child = child_exists (var, name); + child = child_exists (var, i); if (child == NULL) - child = create_child (var, i, name); + { + name = name_of_child (var, i); + child = create_child (var, i, name); + } *((*childlist) + i) = child; } @@ -761,6 +819,12 @@ varobj_get_type (struct varobj *var) return thetype; } +char * +varobj_get_path_expr (struct varobj *var) +{ + return path_expr_of_variable(var); +} + /* Obtain the type of an object variable. */ struct type * @@ -1237,22 +1301,26 @@ uninstall_variable (struct varobj *var) } -/* Does a child with the name NAME exist in VAR? If so, return its data. - If not, return NULL. */ +/* Does a child with the index INDEX exist in VAR? If so, return its data. + If not, return NULL. NB. The child must already have been installed + in its parent for this call to work. */ static struct varobj * -child_exists (struct varobj *var, char *name) +child_exists (struct varobj *var, int index) { struct varobj_child *vc; for (vc = var->children; vc != NULL; vc = vc->next) { - if (strcmp (vc->child->name, name) == 0) + /* APPLE LOCAL */ + if (vc->child->index == index) return vc->child; } return NULL; } + + /* Create and install a child of the parent of the given name */ static struct varobj * create_child (struct varobj *parent, int index, char *name) @@ -1336,6 +1404,7 @@ new_variable (void) var = (struct varobj *) xmalloc (sizeof (struct varobj)); var->name = NULL; + var->path_expr = NULL; var->obj_name = NULL; var->index = -1; var->type = NULL; @@ -1379,6 +1448,7 @@ free_variable (struct varobj *var) } xfree (var->name); + xfree (var->path_expr); xfree (var->obj_name); xfree (var); } @@ -1412,9 +1482,12 @@ get_type (struct varobj *var) return type; } -/* This returns the type of the variable, dereferencing pointers, too. */ +/* This returns the type of the variable, dereferencing pointers, too. + If was_ptr non-null, this will also return whether the original + was a pointer or not. */ + static struct type * -get_type_deref (struct varobj *var) +get_type_deref (struct varobj *var, int *was_ptr) { struct type *type; @@ -1422,7 +1495,13 @@ get_type_deref (struct varobj *var) if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_PTR || TYPE_CODE (type) == TYPE_CODE_REF)) - type = get_target_type (type); + { + type = get_target_type (type); + if (was_ptr != NULL) + *was_ptr = 1; + } + else if (was_ptr != NULL) + *was_ptr = 0; return type; } @@ -1596,6 +1675,18 @@ name_of_variable (struct varobj *var) return (*var->root->lang->name_of_variable) (var); } +static char * +path_expr_of_variable (struct varobj *var) +{ + if (var->path_expr != NULL) + return var->path_expr; + /* APPLE LOCAL is_root_p */ + else if (is_root_p (var)) + return var->name; + else + return path_expr_of_child (var->parent, var->index); +} + /* What is the name of the INDEX'th child of VAR? Returns a malloc'd string. */ static char * name_of_child (struct varobj *var, int index) @@ -1603,6 +1694,15 @@ name_of_child (struct varobj *var, int i return (*var->root->lang->name_of_child) (var, index); } +/* What is the rooted expression of the INDEX'th child of VAR? Returns + a malloc'd string. */ +static char * +path_expr_of_child (struct varobj *var, int index) +{ + return (*var->root->lang->path_expr_of_child) (var, index); +} + + /* What is the ``struct value *'' of the root variable VAR? TYPE_CHANGED controls what to do if the type of a use_selected_frame = 1 variable changes. On input, @@ -1814,6 +1914,80 @@ c_number_of_children (struct varobj *var } static char * +c_path_expr_of_child (struct varobj *parent, int index) +{ + struct type *type; + struct type *target; + char *path_expr; + struct varobj *child = child_exists (parent, index); + char *parent_expr; + char *name; + int parent_len, child_len, len; + + if (child == NULL) + error ("c_path_expr_of_child: " + "Tried to get path expression for a null child."); + + parent_expr = path_expr_of_variable (parent); + name = name_of_variable (child); + parent_len = strlen (parent_expr); + child_len = strlen (name); + len = parent_len + child_len + 2 + 1; /* 2 for (), and 1 for null */ + + type = get_type (parent); + target = get_target_type (type); + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + { + /* We never get here unless parent->num_children is greater than 0... */ + + len += 2; + path_expr = (char *) xmalloc (len); + sprintf (path_expr, "(%s)[%s]", parent_expr, name); + } + break; + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + len += 1; + path_expr = (char *) xmalloc (len); + sprintf (path_expr, "(%s).%s", parent_expr, name); + break; + + case TYPE_CODE_PTR: + switch (TYPE_CODE (target)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + len += 2; + path_expr = (char *) xmalloc (len); + sprintf (path_expr, "(%s)->%s", parent_expr, name); + break; + + default: + len += parent_len + 2 + 1 + 1; + path_expr = (char *) xmalloc (len); + sprintf (path_expr, "*(%s)", parent_expr); + break; + } + break; + + default: + /* This should not happen */ + len = 5; + path_expr = + (char *) xmalloc (len); + sprintf (path_expr, "????"); + } + + child->path_expr = path_expr; + return path_expr; +} + + +static char * c_name_of_variable (struct varobj *parent) { return savestring (parent->name, strlen (parent->name)); @@ -2113,7 +2287,7 @@ cplus_number_of_children (struct varobj if (!CPLUS_FAKE_CHILD (var)) { - type = get_type_deref (var); + type = get_type_deref (var, 0); if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) || ((TYPE_CODE (type)) == TYPE_CODE_UNION)) @@ -2139,7 +2313,7 @@ cplus_number_of_children (struct varobj { int kids[3]; - type = get_type_deref (var->parent); + type = get_type_deref (var->parent, 0); cplus_class_num_children (type, kids); if (strcmp (var->name, "public") == 0) @@ -2185,6 +2359,271 @@ cplus_class_num_children (struct type *t } static char * +cplus_path_expr_of_child (struct varobj *parent, int index) +{ + char *path_expr; + struct type *type; + int children[3]; + struct varobj *child = child_exists (parent, index); + char *parent_expr = path_expr_of_variable (parent); + int parent_len = strlen (parent_expr); + int child_len; + char *child_name; + int is_ptr; + + if (child == NULL) + error ("cplus_path_expr_of_child: " + "Tried to get path expression for a null child."); + + /* The path expression for a fake child is just the parent, + that way we can just concatenate the fake child's expr and + its real children. */ + + if (CPLUS_FAKE_CHILD (child)) + return parent_expr; + + if (CPLUS_FAKE_CHILD (parent)) + { + /* Looking for children of public, private, or protected. */ + type = get_type_deref (parent->parent, &is_ptr); + } + else + type = get_type_deref (parent, &is_ptr); + + path_expr = NULL; + switch (TYPE_CODE (type)) + { + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + cplus_class_num_children (type, children); + + if (CPLUS_FAKE_CHILD (parent)) + { + int index_in_type; + enum vsections prot; + char *parent_name = name_of_variable (parent); + int child_is_ptr; + int dynamic_expr_len, join_expr_len; + char *dynamic_expr, *join_expr; + + if (strcmp (parent_name, "private") == 0) + prot = v_private; + else if (strcmp (parent_name, "protected") == 0) + prot = v_protected; + else if (strcmp (parent_name, "public") == 0) + prot = v_public; + else + { + error ("cplus_make_name_of_child got a parent with invalid " + "fake child name: \"%s\".", parent_name); + return NULL; + } + + index_in_type = + cplus_real_type_index_for_fake_child_index (type, prot, index); + + child_name = TYPE_FIELD_NAME (type, index_in_type); + child_len = strlen (child_name); + + /* Here's another tricky point. This child varobj might have a + dynamic type that's different from it's type, and this could be + one of the fields from the dynamic type. If we don't + cast it to the dynamic type in this expression, then we won't + be able to access those fields. */ + + if (varobj_use_dynamic_type != 0 + && child->dynamic_type != NULL + && child->dynamic_type != child->type) + { + struct type *child_type = NULL; + child_type = get_type_deref (child, &child_is_ptr); + if (!child_is_ptr) + dynamic_expr_len = 0; + else + { + dynamic_expr = TYPE_NAME (child_type); + dynamic_expr_len = strlen (dynamic_expr); + } + } + else + { + dynamic_expr_len = 0; + } + + if (is_ptr) + { + join_expr = "->"; + join_expr_len = 2; + } + else + { + join_expr = "."; + join_expr_len = 1; + } + if (dynamic_expr_len > 0) + { + /* The literal is duplicated because if we create a temporary + variable, gcc warns that it can't check format string, + and this breaks compilation if -Werror is given. + */ + path_expr = (char *) xmalloc (dynamic_expr_len + parent_len + + join_expr_len + child_len + strlen ("((%s)%s%s)") - 6 + 1); + sprintf (path_expr, "((%s *) ((%s)%s%s))", dynamic_expr, parent_expr, join_expr, child_name); + } + else + { + path_expr = (char *) xmalloc (parent_len + join_expr_len + + child_len + strlen ("((%s)%s%s)") - 4 + 1); + sprintf (path_expr, "((%s)%s%s)", parent_expr, join_expr, child_name); + } + } + else if (index < TYPE_N_BASECLASSES (type)) + { + child_name = TYPE_FIELD_NAME (type, index); + child_len = strlen (child_name); + + if (is_ptr) + { + path_expr = (char *) xmalloc (parent_len + child_len + 7 + 1); + sprintf (path_expr, "((%s *) %s)", child_name, parent_expr); + } + else + { + path_expr = (char *) xmalloc (parent_len + child_len + 5 + 1); + sprintf (path_expr, "((%s) %s)", child_name, parent_expr); + } + } + else + { + /* Everything beyond the baseclasses can + only be "public", "private", or "protected" */ + index -= TYPE_N_BASECLASSES (type); + switch (index) + { + case 0: + if (children[v_public] != 0) + { + path_expr = "public"; + break; + } + case 1: + if (children[v_private] != 0) + { + path_expr = "private"; + break; + } + case 2: + if (children[v_protected] != 0) + { + path_expr = "protected"; + break; + } + default: + /* error! */ + break; + } + } + break; + + default: + break; + } + + if (path_expr == NULL) + return c_path_expr_of_child (parent, index); + else + { + child->path_expr = path_expr; + } + + return path_expr; +} + +/* Compute the index in the type structure TYPE of the NUM'th field + of protection level PROT */ +static int +cplus_real_type_index_for_fake_child_index (struct type *type, + enum vsections prot, + int num) +{ + int num_found = 0; + int foundit = 0; + int i = 0; + + switch (prot) + { + case v_public: + for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++) + { + /* If we have a virtual table pointer, omit it. */ + if (TYPE_VPTR_BASETYPE (type) == type + && TYPE_VPTR_FIELDNO (type) == i) + continue; + + if (!TYPE_FIELD_PROTECTED (type, i) + && !TYPE_FIELD_PRIVATE (type, i)) + { + if (num_found == num) + { + foundit = 1; + break; + } + else + num_found++; + } + } + break; + case v_protected: + for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++) + { + /* If we have a virtual table pointer, omit it. */ + if (TYPE_VPTR_BASETYPE (type) == type + && TYPE_VPTR_FIELDNO (type) == i) + continue; + + if (TYPE_FIELD_PROTECTED (type, i)) + { + if (num_found == num) + { + foundit = 1; + break; + } + else + num_found++; + } + } + break; + case v_private: + for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++) + { + /* If we have a virtual table pointer, omit it. */ + if (TYPE_VPTR_BASETYPE (type) == type + && TYPE_VPTR_FIELDNO (type) == i) + continue; + + if (TYPE_FIELD_PRIVATE (type, i)) + { + if (num_found == num) + { + foundit = 1; + break; + } + else + num_found++; + } + } + break; + } + + if (!foundit) + return -1; + + return i; + } + + + +static char * cplus_name_of_variable (struct varobj *parent) { return c_name_of_variable (parent); @@ -2199,10 +2638,10 @@ cplus_name_of_child (struct varobj *pare if (CPLUS_FAKE_CHILD (parent)) { /* Looking for children of public, private, or protected. */ - type = get_type_deref (parent->parent); + type = get_type_deref (parent->parent, 0); } else - type = get_type_deref (parent); + type = get_type_deref (parent, 0); name = NULL; switch (TYPE_CODE (type)) @@ -2335,9 +2774,9 @@ cplus_value_of_child (struct varobj *par struct value *value; if (CPLUS_FAKE_CHILD (parent)) - type = get_type_deref (parent->parent); + type = get_type_deref (parent->parent, 0); else - type = get_type_deref (parent); + type = get_type_deref (parent, 0); value = NULL; @@ -2410,10 +2849,10 @@ cplus_type_of_child (struct varobj *pare if (CPLUS_FAKE_CHILD (parent)) { /* Looking for the type of a child of public, private, or protected. */ - t = get_type_deref (parent->parent); + t = get_type_deref (parent->parent, 0); } else - t = get_type_deref (parent); + t = get_type_deref (parent, 0); type = NULL; switch (TYPE_CODE (t)) @@ -2542,6 +2981,12 @@ java_value_of_variable (struct varobj *v { return cplus_value_of_variable (var); } + +static char * +java_path_expr_of_child (struct varobj *parent, int index) +{ + return cplus_path_expr_of_child (parent, index); +} extern void _initialize_varobj (void); void @@ -2552,6 +2997,14 @@ _initialize_varobj (void) varobj_table = xmalloc (sizeof_table); memset (varobj_table, 0, sizeof_table); + add_setshow_boolean_cmd ("varobj-print-object", class_obscure, + &varobj_use_dynamic_type, _("\ +Set varobj to construct children using the most specific class type."), _("\ +abc"), NULL, + NULL, NULL, + &setlist, &showlist); + + add_setshow_zinteger_cmd ("debugvarobj", class_maintenance, &varobjdebug, _("\ Set varobj debugging."), _("\ Index: varobj.h =================================================================== RCS file: /cvs/src/src/gdb/varobj.h,v retrieving revision 1.6 diff -u -p -r1.6 varobj.h --- varobj.h 17 Dec 2005 22:34:03 -0000 1.6 +++ varobj.h 17 Mar 2006 14:25:08 -0000 @@ -83,6 +83,8 @@ extern int varobj_get_num_children (stru extern int varobj_list_children (struct varobj *var, struct varobj ***childlist); +extern char *varobj_get_path_expr (struct varobj *var); + extern char *varobj_get_type (struct varobj *var); extern struct type *varobj_get_gdb_type (struct varobj *var); Index: mi/mi-cmd-var.c =================================================================== RCS file: /cvs/src/src/gdb/mi/mi-cmd-var.c,v retrieving revision 1.23 diff -u -p -r1.23 mi-cmd-var.c --- mi/mi-cmd-var.c 23 Dec 2005 18:57:46 -0000 1.23 +++ mi/mi-cmd-var.c 17 Mar 2006 14:25:08 -0000 @@ -371,6 +371,28 @@ mi_cmd_var_info_type (char *command, cha } enum mi_cmd_result +mi_cmd_var_info_path_expression (char *command, char **argv, int argc) +{ + struct varobj *var; + char *path_expr; + + if (argc != 1) + error ("mi_cmd_var_info_path_expression: Usage: NAME."); + + /* Get varobj handle, if a valid var obj name was specified */ + var = varobj_get_handle (argv[0]); + if (var == NULL) + error ("mi_cmd_var_info_path_expression: Variable object not found"); + + path_expr = varobj_get_path_expr (var); + + ui_out_field_string (uiout, "path_expr", path_expr); + + return MI_CMD_DONE; +} + + +enum mi_cmd_result mi_cmd_var_info_expression (char *command, char **argv, int argc) { enum varobj_languages lang; Index: mi/mi-cmds.c =================================================================== RCS file: /cvs/src/src/gdb/mi/mi-cmds.c,v retrieving revision 1.20 diff -u -p -r1.20 mi-cmds.c --- mi/mi-cmds.c 23 Dec 2005 18:57:46 -0000 1.20 +++ mi/mi-cmds.c 17 Mar 2006 14:25:08 -0000 @@ -162,6 +162,7 @@ struct mi_cmd mi_cmds[] = { "var-info-expression", { NULL, 0 }, 0, mi_cmd_var_info_expression}, { "var-info-num-children", { NULL, 0 }, 0, mi_cmd_var_info_num_children}, { "var-info-type", { NULL, 0 }, 0, mi_cmd_var_info_type}, + { "var-info-path-expression", { NULL, 0 }, 0, mi_cmd_var_info_path_expression}, { "var-list-children", { NULL, 0 }, 0, mi_cmd_var_list_children}, { "var-set-format", { NULL, 0 }, 0, mi_cmd_var_set_format}, { "var-show-attributes", { NULL, 0 }, 0, mi_cmd_var_show_attributes}, Index: mi/mi-cmds.h =================================================================== RCS file: /cvs/src/src/gdb/mi/mi-cmds.h,v retrieving revision 1.19 diff -u -p -r1.19 mi-cmds.h --- mi/mi-cmds.h 23 Dec 2005 18:57:46 -0000 1.19 +++ mi/mi-cmds.h 17 Mar 2006 14:25:08 -0000 @@ -110,6 +110,7 @@ extern mi_cmd_argv_ftype mi_cmd_var_eval extern mi_cmd_argv_ftype mi_cmd_var_info_expression; extern mi_cmd_argv_ftype mi_cmd_var_info_num_children; extern mi_cmd_argv_ftype mi_cmd_var_info_type; +extern mi_cmd_argv_ftype mi_cmd_var_info_path_expression; extern mi_cmd_argv_ftype mi_cmd_var_list_children; extern mi_cmd_argv_ftype mi_cmd_var_set_format; extern mi_cmd_argv_ftype mi_cmd_var_show_attributes;