X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fvarobj.c;h=056cf58f65091c10d2805c1b55053f560668a93d;hb=8526541313ba0cc16d8c40b587744d70c325782f;hp=e3c193e1ae6e50c846d5940c263700ad7ef1dde8;hpb=30b28db19b6dfe929dadd706aa0b9eab0da17948;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/varobj.c b/gdb/varobj.c index e3c193e1ae..056cf58f65 100644 --- a/gdb/varobj.c +++ b/gdb/varobj.c @@ -1,5 +1,7 @@ /* Implementation of the GDB variable objects API. - Copyright 1999, 2000, 2001 Free Software Foundation, Inc. + + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,23 +15,34 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ #include "defs.h" +#include "exceptions.h" #include "value.h" #include "expression.h" #include "frame.h" #include "language.h" #include "wrapper.h" #include "gdbcmd.h" -#include +#include "block.h" + +#include "gdb_assert.h" +#include "gdb_string.h" #include "varobj.h" +#include "vec.h" /* Non-zero if we want to see trace of varobj level stuff. */ int varobjdebug = 0; +static void +show_varobjdebug (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("Varobj debugging is %s.\n"), value); +} /* String representations of gdb's format codes */ char *varobj_format_string[] = @@ -52,7 +65,7 @@ struct varobj_root struct block *valid_block; /* The frame for this expression */ - CORE_ADDR frame; + struct frame_id frame; /* If 1, "update" always recomputes the frame & valid block using the currently selected frame. */ @@ -68,6 +81,10 @@ struct varobj_root struct varobj_root *next; }; +typedef struct varobj *varobj_p; + +DEF_VEC_P (varobj_p); + /* Every variable in the system has a structure of this type defined for it. This structure holds all information necessary to manipulate a particular object variable. Members which must be freed are noted. */ @@ -90,7 +107,9 @@ struct varobj /* The type of this variable. This may NEVER be NULL. */ struct type *type; - /* The value of this expression or subexpression. This may be NULL. */ + /* The value of this expression or subexpression. This may be NULL. + Invariant: if varobj_value_is_changeable_p (this) is non-zero, + the value is either NULL, or not lazy. */ struct value *value; /* Did an error occur evaluating the expression or getting its value? */ @@ -102,37 +121,20 @@ struct varobj /* If this object is a child, this points to its immediate parent. */ struct varobj *parent; - /* A list of this object's children */ - struct varobj_child *children; + /* Children of this object. */ + VEC (varobj_p) *children; /* Description of the root variable. Points to root variable for children. */ struct varobj_root *root; /* The format of the output for this object */ enum varobj_display_formats format; -}; - -/* Every variable keeps a linked list of its children, described - by the following structure. */ -/* FIXME: Deprecated. All should use vlist instead */ - -struct varobj_child -{ - - /* Pointer to the child's data */ - struct varobj *child; - - /* Pointer to the next child */ - struct varobj_child *next; -}; -/* A stack of varobjs */ -/* FIXME: Deprecated. All should use vlist instead */ + /* Was this variable updated via a varobj_set_value operation */ + int updated; -struct vstack -{ - struct varobj *var; - struct vstack *next; + /* Last print value. */ + char *print_value; }; struct cpstack @@ -162,14 +164,8 @@ static int install_variable (struct varobj *); static void uninstall_variable (struct varobj *); -static struct varobj *child_exists (struct varobj *, char *); - static struct varobj *create_child (struct varobj *, int, char *); -static void save_child_in_parent (struct varobj *, struct varobj *); - -static void remove_child_from_parent (struct varobj *, struct varobj *); - /* Utility routines */ static struct varobj *new_variable (void); @@ -188,16 +184,13 @@ static struct type *get_target_type (struct type *); static enum varobj_display_formats variable_default_display (struct varobj *); -static int my_value_equal (struct value *, struct value *, int *); - -static void vpush (struct vstack **pstack, struct varobj *var); - -static struct varobj *vpop (struct vstack **pstack); - static void cppush (struct cpstack **pstack, char *name); static char *cppop (struct cpstack **pstack); +static int install_new_value (struct varobj *var, struct value *value, + int initial); + /* Language-specific routines. */ static enum varobj_languages variable_language (struct varobj *var); @@ -212,13 +205,16 @@ static struct value *value_of_root (struct varobj **var_handle, int *); static struct value *value_of_child (struct varobj *parent, int index); -static struct type *type_of_child (struct varobj *var); - static int variable_editable (struct varobj *var); static char *my_value_of_variable (struct varobj *var); -static int type_changeable (struct varobj *var); +static char *value_get_print_value (struct value *value, + enum varobj_display_formats format); + +static int varobj_value_is_changeable_p (struct varobj *var); + +static int is_root_p (struct varobj *var); /* C implementation */ @@ -310,8 +306,7 @@ struct language_specific }; /* Array of known source language routines. */ -static struct language_specific - languages[vlang_end][sizeof (struct language_specific)] = { +static struct language_specific languages[vlang_end] = { /* Unknown (try treating as C */ { vlang_unknown, @@ -389,9 +384,35 @@ static struct vlist **varobj_table; /* API Implementation */ +static int +is_root_p (struct varobj *var) +{ + return (var->root->rootvar == var); +} /* Creates a varobj (not its children) */ +/* Return the full FRAME which corresponds to the given CORE_ADDR + or NULL if no FRAME on the chain corresponds to CORE_ADDR. */ + +static struct frame_info * +find_frame_addr_in_frame_chain (CORE_ADDR frame_addr) +{ + struct frame_info *frame = NULL; + + if (frame_addr == (CORE_ADDR) 0) + return NULL; + + while (1) + { + frame = get_prev_frame (frame); + if (frame == NULL) + return NULL; + if (get_frame_base_address (frame) == frame_addr) + return frame; + } +} + struct varobj * varobj_create (char *objname, char *expression, CORE_ADDR frame, enum varobj_type type) @@ -410,14 +431,21 @@ varobj_create (char *objname, { char *p; enum varobj_languages lang; + struct value *value; /* Parse and evaluate the expression, filling in as much of the variable's data as possible */ /* Allow creator to specify context of variable */ if ((type == USE_CURRENT_FRAME) || (type == USE_SELECTED_FRAME)) - fi = selected_frame; + fi = deprecated_selected_frame; else + /* FIXME: cagney/2002-11-23: This code should be doing a + lookup using the frame ID and not just the frame's + ``address''. This, of course, means an interface change. + However, with out that interface change ISAs, such as the + ia64 with its two stacks, won't work. Similar goes for the + case where there is a frameless function. */ fi = find_frame_addr_in_frame_chain (frame); /* frame = -2 means always use selected frame */ @@ -426,7 +454,7 @@ varobj_create (char *objname, block = NULL; if (fi != NULL) - block = get_frame_block (fi); + block = get_frame_block (fi, 0); p = expression; innermost_block = NULL; @@ -441,8 +469,8 @@ varobj_create (char *objname, if (var->root->exp->elts[0].opcode == OP_TYPE) { do_cleanups (old_chain); - fprintf_unfiltered (gdb_stderr, - "Attempt to use a type name as an expression."); + fprintf_unfiltered (gdb_stderr, "Attempt to use a type name" + " as an expression.\n"); return NULL; } @@ -456,36 +484,32 @@ varobj_create (char *objname, Since select_frame is so benign, just call it for all cases. */ if (fi != NULL) { - var->root->frame = FRAME_FP (fi); - old_fi = selected_frame; - select_frame (fi, -1); + var->root->frame = get_frame_id (fi); + old_fi = deprecated_selected_frame; + select_frame (fi); } /* We definitively need to catch errors here. If evaluate_expression succeeds we got the value we wanted. But if it fails, we still go on with a call to evaluate_type() */ - if (gdb_evaluate_expression (var->root->exp, &var->value)) - { - /* no error */ - release_value (var->value); - if (VALUE_LAZY (var->value)) - gdb_value_fetch_lazy (var->value); - } - else - var->value = evaluate_type (var->root->exp); + if (!gdb_evaluate_expression (var->root->exp, &value)) + /* Error getting the value. Try to at least get the + right type. */ + value = evaluate_type (var->root->exp); - var->type = VALUE_TYPE (var->value); + var->type = value_type (value); + install_new_value (var, value, 1 /* Initial assignment */); /* Set language info */ lang = variable_language (var); - var->root->lang = languages[lang]; + var->root->lang = &languages[lang]; /* Set ourselves as our root */ var->root->rootvar = var; /* Reset the selected frame */ if (fi != NULL) - select_frame (old_fi, -1); + select_frame (old_fi); } /* If the variable object name is null, that means this @@ -514,13 +538,13 @@ char * varobj_gen_name (void) { static int id = 0; - char obj_name[31]; + char *obj_name; /* generate a name for this object */ id++; - sprintf (obj_name, "var%d", id); + obj_name = xstrprintf ("var%d", id); - return xstrdup (obj_name); + return obj_name; } /* Given an "objname", returns the pointer to the corresponding varobj @@ -544,7 +568,7 @@ varobj_get_handle (char *objname) cv = cv->next; if (cv == NULL) - error ("Variable object not found"); + error (_("Variable object not found")); return cv->var; } @@ -603,7 +627,7 @@ varobj_delete (struct varobj *var, char ***dellist, int only_children) } if (mycount || (*cp != NULL)) - warning ("varobj_delete: assertion failed - mycount(=%d) <> 0", + warning (_("varobj_delete: assertion failed - mycount(=%d) <> 0"), mycount); } @@ -667,21 +691,38 @@ varobj_list_children (struct varobj *var, struct varobj ***childlist) if (var->num_children == -1) var->num_children = number_of_children (var); + /* If that failed, give up. */ + if (var->num_children == -1) + return -1; + + /* 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); + /* List of children */ *childlist = xmalloc ((var->num_children + 1) * sizeof (struct varobj *)); for (i = 0; i < var->num_children; i++) { + varobj_p existing; + /* Mark as the end in case we bail out */ *((*childlist) + i) = NULL; - /* check if child exists, if not create */ - name = name_of_child (var, i); - child = child_exists (var, name); - if (child == NULL) - child = create_child (var, i, name); + existing = VEC_index (varobj_p, var->children, i); - *((*childlist) + i) = child; + 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 = name_of_child (var, i); + existing = create_child (var, i, name); + VEC_replace (varobj_p, var->children, i, existing); + } + + *((*childlist) + i) = existing; } /* End of list is marked by a NULL pointer */ @@ -713,13 +754,21 @@ varobj_get_type (struct varobj *var) /* To print the type, we simply create a zero ``struct value *'' and cast it to our type. We then typeprint this variable. */ val = value_zero (var->type, not_lval); - type_print (VALUE_TYPE (val), "", stb, -1); + type_print (value_type (val), "", stb, -1); thetype = ui_file_xstrdup (stb, &length); do_cleanups (old_chain); return thetype; } +/* Obtain the type of an object variable. */ + +struct type * +varobj_get_gdb_type (struct varobj *var) +{ + return var->type; +} + enum varobj_languages varobj_get_language (struct varobj *var) { @@ -753,6 +802,7 @@ varobj_set_value (struct varobj *var, char *expression) { struct value *val; int offset = 0; + int error = 0; /* The argument "expression" contains the variable's new value. We need to first construct a legal expression for this -- ugh! */ @@ -761,16 +811,13 @@ varobj_set_value (struct varobj *var, char *expression) struct value *value; int saved_input_radix = input_radix; - if (variable_editable (var) && !var->error) + if (var->value != NULL && variable_editable (var) && !var->error) { char *s = expression; int i; - struct value *temp; input_radix = 10; /* ALWAYS reset to decimal temporarily */ - if (!gdb_parse_exp_1 (&s, 0, 0, &exp)) - /* We cannot proceed without a well-formed expression. */ - return 0; + exp = parse_exp_1 (&s, 0, 0); if (!gdb_evaluate_expression (exp, &value)) { /* We cannot proceed without a valid expression. */ @@ -778,39 +825,35 @@ varobj_set_value (struct varobj *var, char *expression) return 0; } - /* If our parent is "public", "private", or "protected", we could - be asking to modify the value of a baseclass. If so, we need to - adjust our address by the offset of our baseclass in the subclass, - since VALUE_ADDRESS (var->value) points at the start of the subclass. - For some reason, value_cast doesn't take care of this properly. */ - temp = var->value; - if (var->parent != NULL && CPLUS_FAKE_CHILD (var->parent)) - { - struct varobj *super, *sub; - struct type *type; - super = var->parent->parent; - sub = super->parent; - if (sub != NULL) - { - /* Yes, it is a baseclass */ - type = get_type_deref (sub); - - if (super->index < TYPE_N_BASECLASSES (type)) - { - temp = value_copy (var->value); - for (i = 0; i < super->index; i++) - offset += TYPE_LENGTH (TYPE_FIELD_TYPE (type, i)); - } - } - } - - VALUE_ADDRESS (temp) += offset; - if (!gdb_value_assign (temp, value, &val)) + /* All types that are editable must also be changeable. */ + gdb_assert (varobj_value_is_changeable_p (var)); + + /* The value of a changeable variable object must not be lazy. */ + gdb_assert (!value_lazy (var->value)); + + /* Need to coerce the input. We want to check if the + value of the variable object will be different + after assignment, and the first thing value_assign + does is coerce the input. + For example, if we are assigning an array to a pointer variable we + should compare the pointer with the the array's address, not with the + array's content. */ + value = coerce_array (value); + + /* The new value may be lazy. gdb_value_assign, or + rather value_contents, will take care of this. + If fetching of the new value will fail, gdb_value_assign + with catch the exception. */ + if (!gdb_value_assign (var->value, value, &val)) return 0; - VALUE_ADDRESS (val) -= offset; - value_free (var->value); - release_value (val); - var->value = val; + + /* If the value has changed, record it, so that next -var-update can + report this change. If a variable had a value of '1', we've set it + to '333' and then set again to '1', when -var-update will report this + variable as changed -- because the first assignment has set the + 'updated' flag. There's no need to optimize that, because return value + of -var-update should be considered an approximation. */ + var->updated = install_new_value (var, val, 0 /* Compare values. */); input_radix = saved_input_radix; return 1; } @@ -849,6 +892,124 @@ varobj_list (struct varobj ***varlist) return rootcount; } +/* Assign a new value to a variable object. If INITIAL is non-zero, + this is the first assignement after the variable object was just + created, or changed type. In that case, just assign the value + and return 0. + Otherwise, assign the value and if type_changeable returns non-zero, + find if the new value is different from the current value. + Return 1 if so, and 0 if the values are equal. + + The VALUE parameter should not be released -- the function will + take care of releasing it when needed. */ +static int +install_new_value (struct varobj *var, struct value *value, int initial) +{ + int changeable; + int need_to_fetch; + int changed = 0; + + var->error = 0; + /* We need to know the varobj's type to decide if the value should + be fetched or not. C++ fake children (public/protected/private) don't have + a type. */ + gdb_assert (var->type || CPLUS_FAKE_CHILD (var)); + changeable = varobj_value_is_changeable_p (var); + need_to_fetch = changeable; + + /* We are not interested in the address of references, and given + that in C++ a reference is not rebindable, it cannot + meaningfully change. So, get hold of the real value. */ + if (value) + { + value = coerce_ref (value); + release_value (value); + } + + if (var->type && TYPE_CODE (var->type) == TYPE_CODE_UNION) + /* For unions, we need to fetch the value implicitly because + of implementation of union member fetch. When gdb + creates a value for a field and the value of the enclosing + structure is not lazy, it immediately copies the necessary + bytes from the enclosing values. If the enclosing value is + lazy, the call to value_fetch_lazy on the field will read + the data from memory. For unions, that means we'll read the + same memory more than once, which is not desirable. So + fetch now. */ + need_to_fetch = 1; + + /* The new value might be lazy. If the type is changeable, + that is we'll be comparing values of this type, fetch the + value now. Otherwise, on the next update the old value + will be lazy, which means we've lost that old value. */ + if (need_to_fetch && value && value_lazy (value)) + { + if (!gdb_value_fetch_lazy (value)) + { + var->error = 1; + /* Set the value to NULL, so that for the next -var-update, + we don't try to compare the new value with this value, + that we couldn't even read. */ + value = NULL; + } + else + var->error = 0; + } + + /* If the type is changeable, compare the old and the new values. + If this is the initial assignment, we don't have any old value + to compare with. */ + if (initial) + var->print_value = value_get_print_value (value, var->format); + else if (changeable) + { + /* If the value of the varobj was changed by -var-set-value, then the + value in the varobj and in the target is the same. However, that value + is different from the value that the varobj had after the previous + -var-update. So need to the varobj as changed. */ + if (var->updated) + changed = 1; + else + { + /* Try to compare the values. That requires that both + values are non-lazy. */ + + /* Quick comparison of NULL values. */ + if (var->value == NULL && value == NULL) + /* Equal. */ + ; + else if (var->value == NULL || value == NULL) + changed = 1; + else + { + char *print_value; + gdb_assert (!value_lazy (var->value)); + gdb_assert (!value_lazy (value)); + print_value = value_get_print_value (value, var->format); + + if (strcmp (var->print_value, print_value) != 0) + { + xfree (var->print_value); + var->print_value = print_value; + changed = 1; + } + else + xfree (print_value); + } + } + } + + /* We must always keep the new value, since children depend on it. */ + if (var->value != NULL) + value_free (var->value); + var->value = value; + var->updated = 0; + + gdb_assert (!var->value || value_type (var->value)); + + return changed; +} + /* Update the values for a variable and its children. This is a two-pronged attack. First, re-parse the value for the root's expression to see if it's changed. Then go all the way @@ -869,30 +1030,31 @@ int varobj_update (struct varobj **varp, struct varobj ***changelist) { int changed = 0; + int error = 0; int type_changed; int i; int vleft; - int error2; struct varobj *v; struct varobj **cv; struct varobj **templist = NULL; struct value *new; - struct vstack *stack = NULL; - struct vstack *result = NULL; - struct frame_info *old_fi; + VEC (varobj_p) *stack = NULL; + VEC (varobj_p) *result = NULL; + struct frame_id old_fid; + struct frame_info *fi; /* sanity check: have we been passed a pointer? */ if (changelist == NULL) return -1; /* Only root variables can be updated... */ - if ((*varp)->root->rootvar != *varp) + if (!is_root_p (*varp)) /* Not a root var */ return -1; /* Save the selected stack frame, since we will need to change it in order to evaluate expressions. */ - old_fi = selected_frame; + old_fid = get_frame_id (deprecated_selected_frame); /* Update the root variable. value_of_root can return NULL if the variable is no longer around, i.e. we stepped out of @@ -901,118 +1063,76 @@ varobj_update (struct varobj **varp, struct varobj ***changelist) has changed. */ type_changed = 1; new = value_of_root (varp, &type_changed); + + /* Restore selected frame */ + fi = frame_find_by_id (old_fid); + if (fi) + select_frame (fi); + if (new == NULL) { (*varp)->error = 1; return -1; } - /* Initialize a stack for temporary results */ - vpush (&result, NULL); - /* If this is a "use_selected_frame" varobj, and its type has changed, them note that it's changed. */ if (type_changed) - { - vpush (&result, *varp); - changed++; - } - /* If values are not equal, note that it's changed. - There a couple of exceptions here, though. - We don't want some types to be reported as "changed". */ - else if (type_changeable (*varp) - && !my_value_equal ((*varp)->value, new, &error2)) - { - vpush (&result, *varp); - changed++; - /* error2 replaces var->error since this new value - WILL replace the old one. */ - (*varp)->error = error2; - } - - /* We must always keep around the new value for this root - variable expression, or we lose the updated children! */ - value_free ((*varp)->value); - (*varp)->value = new; - - /* Initialize a stack */ - vpush (&stack, NULL); + VEC_safe_push (varobj_p, result, *varp); - /* Push the root's children */ - if ((*varp)->children != NULL) + if (install_new_value ((*varp), new, type_changed)) { - struct varobj_child *c; - for (c = (*varp)->children; c != NULL; c = c->next) - vpush (&stack, c->child); + /* If type_changed is 1, install_new_value will never return + non-zero, so we'll never report the same variable twice. */ + gdb_assert (!type_changed); + VEC_safe_push (varobj_p, result, *varp); } + VEC_safe_push (varobj_p, stack, *varp); + /* Walk through the children, reconstructing them all. */ - v = vpop (&stack); - while (v != NULL) + while (!VEC_empty (varobj_p, stack)) { - /* Push any children */ - if (v->children != NULL) - { - struct varobj_child *c; - for (c = v->children; c != NULL; c = c->next) - vpush (&stack, c->child); - } + v = VEC_pop (varobj_p, stack); - /* Update this variable */ - new = value_of_child (v->parent, v->index); - if (type_changeable (v) && !my_value_equal (v->value, new, &error2)) + /* Push any children. Use reverse order so that the first + child is popped from the work stack first, and so + will be added to result first. This does not + affect correctness, just "nicer". */ + for (i = VEC_length (varobj_p, v->children)-1; i >= 0; --i) { - /* Note that it's changed */ - vpush (&result, v); - changed++; + varobj_p c = VEC_index (varobj_p, v->children, i); + /* Child may be NULL if explicitly deleted by -var-delete. */ + if (c != NULL) + VEC_safe_push (varobj_p, stack, c); } - /* error2 replaces v->error since this new value - WILL replace the old one. */ - v->error = error2; - /* We must always keep new values, since children depend on it. */ - if (v->value != NULL) - value_free (v->value); - v->value = new; - - /* Get next child */ - v = vpop (&stack); + /* Update this variable, unless it's a root, which is already + updated. */ + if (v != *varp) + { + new = value_of_child (v->parent, v->index); + if (install_new_value (v, new, 0 /* type not changed */)) + { + /* Note that it's changed */ + VEC_safe_push (varobj_p, result, v); + v->updated = 0; + } + } } /* Alloc (changed + 1) list entries */ - /* FIXME: add a cleanup for the allocated list(s) - because one day the select_frame called below can longjump */ + changed = VEC_length (varobj_p, result); *changelist = xmalloc ((changed + 1) * sizeof (struct varobj *)); - if (changed > 1) - { - templist = xmalloc ((changed + 1) * sizeof (struct varobj *)); - cv = templist; - } - else - cv = *changelist; - - /* Copy from result stack to list */ - vleft = changed; - *cv = vpop (&result); - while ((*cv != NULL) && (vleft > 0)) - { - vleft--; - cv++; - *cv = vpop (&result); - } - if (vleft) - warning ("varobj_update: assertion failed - vleft <> 0"); + cv = *changelist; - if (changed > 1) + for (i = 0; i < changed; ++i) { - /* Now we revert the order. */ - for (i = 0; i < changed; i++) - *(*changelist + i) = *(templist + changed - 1 - i); - *(*changelist + changed) = NULL; + *cv = VEC_index (varobj_p, result, i); + gdb_assert (*cv != NULL); + ++cv; } - - /* Restore selected frame */ - select_frame (old_fi, -1); + *cv = 0; if (type_changed) return -2; @@ -1048,18 +1168,17 @@ delete_variable_1 (struct cpstack **resultp, int *delcountp, struct varobj *var, int only_children_p, int remove_from_parent_p) { - struct varobj_child *vc; - struct varobj_child *next; + int i; /* Delete any children of this variable, too. */ - for (vc = var->children; vc != NULL; vc = next) - { + for (i = 0; i < VEC_length (varobj_p, var->children); ++i) + { + varobj_p child = VEC_index (varobj_p, var->children, i); if (!remove_from_parent_p) - vc->child->parent = NULL; - delete_variable_1 (resultp, delcountp, vc->child, 0, only_children_p); - next = vc->next; - xfree (vc); + child->parent = NULL; + delete_variable_1 (resultp, delcountp, child, 0, only_children_p); } + VEC_free (varobj_p, var->children); /* if we were called to delete only the children we are done here */ if (only_children_p) @@ -1081,7 +1200,7 @@ delete_variable_1 (struct cpstack **resultp, int *delcountp, discarding the list afterwards */ if ((remove_from_parent_p) && (var->parent != NULL)) { - remove_child_from_parent (var->parent, var); + VEC_replace (varobj_p, var->parent->children, var->index, NULL); } if (var->obj_name != NULL) @@ -1111,7 +1230,7 @@ install_variable (struct varobj *var) cv = cv->next; if (cv != NULL) - error ("Duplicate variable object name"); + error (_("Duplicate variable object name")); /* Add varobj to hash table */ newvl = xmalloc (sizeof (struct vlist)); @@ -1120,7 +1239,7 @@ install_variable (struct varobj *var) *(varobj_table + index) = newvl; /* If root, add varobj to root list */ - if (var->root->rootvar == var) + if (is_root_p (var)) { /* Add to list of root variables */ if (rootlist == NULL) @@ -1179,7 +1298,7 @@ uninstall_variable (struct varobj *var) xfree (cv); /* If root, remove varobj from root list */ - if (var->root->rootvar == var) + if (is_root_p (var)) { /* Remove from list of root variables */ if (rootlist == var->root) @@ -1210,94 +1329,43 @@ uninstall_variable (struct varobj *var) } -/* Does a child with the name NAME exist in VAR? If so, return its data. - If not, return NULL. */ -static struct varobj * -child_exists (struct varobj *var, char *name) -{ - struct varobj_child *vc; - - for (vc = var->children; vc != NULL; vc = vc->next) - { - if (STREQ (vc->child->name, name)) - 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) { 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; - child->value = value_of_child (parent, index); - if (child->value == NULL || parent->error) - child->error = 1; + value = value_of_child (parent, index); child->parent = parent; child->root = parent->root; - childs_name = - (char *) xmalloc ((strlen (parent->obj_name) + strlen (name) + 2) * - sizeof (char)); - sprintf (childs_name, "%s.%s", parent->obj_name, name); + childs_name = xstrprintf ("%s.%s", parent->obj_name, name); child->obj_name = childs_name; install_variable (child); - /* Save a pointer to this child in the parent */ - save_child_in_parent (parent, 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); - /* Note the type of this child */ - child->type = type_of_child (child); + if ((!CPLUS_FAKE_CHILD (child) && child->value == NULL) || parent->error) + child->error = 1; return child; } - -/* FIXME: This should be a generic add to list */ -/* Save CHILD in the PARENT's data. */ -static void -save_child_in_parent (struct varobj *parent, struct varobj *child) -{ - struct varobj_child *vc; - - /* Insert the child at the top */ - vc = parent->children; - parent->children = - (struct varobj_child *) xmalloc (sizeof (struct varobj_child)); - - parent->children->next = vc; - parent->children->child = child; -} - -/* FIXME: This should be a generic remove from list */ -/* Remove the CHILD from the PARENT's list of children. */ -static void -remove_child_from_parent (struct varobj *parent, struct varobj *child) -{ - struct varobj_child *vc, *prev; - - /* Find the child in the parent's list */ - prev = NULL; - for (vc = parent->children; vc != NULL;) - { - if (vc->child == child) - break; - prev = vc; - vc = vc->next; - } - - if (prev == NULL) - parent->children = vc->next; - else - prev->next = vc->next; - -} /* @@ -1322,6 +1390,8 @@ new_variable (void) var->children = NULL; var->format = 0; var->root = NULL; + var->updated = 0; + var->print_value = NULL; return var; } @@ -1335,7 +1405,7 @@ new_root_variable (void) var->root->lang = NULL; var->root->exp = NULL; var->root->valid_block = NULL; - var->root->frame = (CORE_ADDR) -1; + var->root->frame = null_frame_id; var->root->use_selected_frame = 0; var->root->rootvar = NULL; @@ -1347,14 +1417,15 @@ static void free_variable (struct varobj *var) { /* Free the expression if this is a root variable. */ - if (var->root->rootvar == var) + if (is_root_p (var)) { - free_current_contents ((char **) &var->root->exp); + free_current_contents (&var->root->exp); xfree (var->root); } xfree (var->name); xfree (var->obj_name); + xfree (var->print_value); xfree (var); } @@ -1370,22 +1441,25 @@ make_cleanup_free_variable (struct varobj *var) return make_cleanup (do_free_variable_cleanup, var); } -/* This returns the type of the variable. This skips past typedefs - and returns the real type of the variable. It also dereferences - pointers and references. */ +/* This returns the type of the variable. It also skips past typedefs + to return the real type of the variable. + + NOTE: TYPE_TARGET_TYPE should NOT be used anywhere in this file + except within get_target_type and get_type. */ static struct type * get_type (struct varobj *var) { struct type *type; type = var->type; - while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF) - type = TYPE_TARGET_TYPE (type); + if (type != NULL) + type = check_typedef (type); return type; } -/* This returns the type of the variable, dereferencing pointers, too. */ +/* This returns the type of the variable, dereferencing references, pointers + and references to pointers, too. */ static struct type * get_type_deref (struct varobj *var) { @@ -1393,23 +1467,30 @@ get_type_deref (struct varobj *var) type = get_type (var); - if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_PTR - || TYPE_CODE (type) == TYPE_CODE_REF)) - type = get_target_type (type); + if (type) + { + if (TYPE_CODE (type) == TYPE_CODE_REF) + type = get_target_type (type); + if (TYPE_CODE (type) == TYPE_CODE_PTR) + type = get_target_type (type); + } return type; } /* This returns the target type (or NULL) of TYPE, also skipping - past typedefs, just like get_type (). */ + past typedefs, just like get_type (). + + NOTE: TYPE_TARGET_TYPE should NOT be used anywhere in this file + except within get_target_type and get_type. */ static struct type * get_target_type (struct type *type) { if (type != NULL) { type = TYPE_TARGET_TYPE (type); - while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF) - type = TYPE_TARGET_TYPE (type); + if (type != NULL) + type = check_typedef (type); } return type; @@ -1423,92 +1504,6 @@ variable_default_display (struct varobj *var) return FORMAT_NATURAL; } -/* This function is similar to gdb's value_equal, except that this - one is "safe" -- it NEVER longjmps. It determines if the VAR's - value is the same as VAL2. */ -static int -my_value_equal (struct value *val1, struct value *val2, int *error2) -{ - int r, err1, err2; - - *error2 = 0; - /* Special case: NULL values. If both are null, say - they're equal. */ - if (val1 == NULL && val2 == NULL) - return 1; - else if (val1 == NULL || val2 == NULL) - return 0; - - /* This is bogus, but unfortunately necessary. We must know - exactly what caused an error -- reading val1 or val2 -- so - that we can really determine if we think that something has changed. */ - err1 = 0; - err2 = 0; - /* We do need to catch errors here because the whole purpose - is to test if value_equal() has errored */ - if (!gdb_value_equal (val1, val1, &r)) - err1 = 1; - - if (!gdb_value_equal (val2, val2, &r)) - *error2 = err2 = 1; - - if (err1 != err2) - return 0; - - if (!gdb_value_equal (val1, val2, &r)) - { - /* An error occurred, this could have happened if - either val1 or val2 errored. ERR1 and ERR2 tell - us which of these it is. If both errored, then - we assume nothing has changed. If one of them is - valid, though, then something has changed. */ - if (err1 == err2) - { - /* both the old and new values caused errors, so - we say the value did not change */ - /* This is indeterminate, though. Perhaps we should - be safe and say, yes, it changed anyway?? */ - return 1; - } - else - { - return 0; - } - } - - return r; -} - -/* FIXME: The following should be generic for any pointer */ -static void -vpush (struct vstack **pstack, struct varobj *var) -{ - struct vstack *s; - - s = (struct vstack *) xmalloc (sizeof (struct vstack)); - s->var = var; - s->next = *pstack; - *pstack = s; -} - -/* FIXME: The following should be generic for any pointer */ -static struct varobj * -vpop (struct vstack **pstack) -{ - struct vstack *s; - struct varobj *v; - - if ((*pstack)->var == NULL && (*pstack)->next == NULL) - return NULL; - - s = *pstack; - v = s->var; - *pstack = (*pstack)->next; - xfree (s); - - return v; -} - /* FIXME: The following should be generic for any pointer */ static void cppush (struct cpstack **pstack, char *name) @@ -1616,7 +1611,7 @@ value_of_root (struct varobj **var_handle, int *type_changed) /* This should really be an exception, since this should only get called with a root variable. */ - if (var->root->rootvar != var) + if (!is_root_p (var)) return NULL; if (var->root->use_selected_frame) @@ -1670,27 +1665,9 @@ value_of_child (struct varobj *parent, int index) value = (*parent->root->lang->value_of_child) (parent, index); - /* If we're being lazy, fetch the real value of the variable. */ - if (value != NULL && VALUE_LAZY (value)) - gdb_value_fetch_lazy (value); - return value; } -/* What is the type of VAR? */ -static struct type * -type_of_child (struct varobj *var) -{ - - /* If the child had no evaluation errors, var->value - will be non-NULL and contain a valid type. */ - if (var->value != NULL) - return VALUE_TYPE (var->value); - - /* Otherwise, we must compute the type. */ - return (*var->root->lang->type_of_child) (var->parent, var->index); -} - /* Is this variable editable? Use the variable's type to make this determination. */ static int @@ -1706,11 +1683,31 @@ my_value_of_variable (struct varobj *var) return (*var->root->lang->value_of_variable) (var); } -/* Is VAR something that can change? Depending on language, - some variable's values never change. For example, - struct and unions never change values. */ +static char * +value_get_print_value (struct value *value, enum varobj_display_formats format) +{ + long dummy; + struct ui_file *stb = mem_fileopen (); + struct cleanup *old_chain = make_cleanup_ui_file_delete (stb); + char *thevalue; + + common_val_print (value, stb, format_code[(int) format], 1, 0, 0); + thevalue = ui_file_xstrdup (stb, &dummy); + do_cleanups (old_chain); + return thevalue; +} + +/* Return non-zero if changes in value of VAR + must be detected and reported by -var-update. + Return zero is -var-update should never report + changes of such values. This makes sense for structures + (since the changes in children values will be reported separately), + or for artifical objects (like 'public' pseudo-field in C++). + + Return value of 0 means that gdb need not call value_fetch_lazy + for the value of this variable object. */ static int -type_changeable (struct varobj *var) +varobj_value_is_changeable_p (struct varobj *var) { int r; struct type *type; @@ -1754,7 +1751,9 @@ c_number_of_children (struct varobj *var) && TYPE_ARRAY_UPPER_BOUND_TYPE (type) != BOUND_CANNOT_BE_DETERMINED) children = TYPE_LENGTH (type) / TYPE_LENGTH (target); else - children = -1; + /* If we don't know how many elements there are, don't display + any. */ + children = 0; break; case TYPE_CODE_STRUCT: @@ -1763,9 +1762,9 @@ c_number_of_children (struct varobj *var) break; case TYPE_CODE_PTR: - /* This is where things get compilcated. All pointers have one child. + /* This is where things get complicated. All pointers have one child. Except, of course, for struct and union ptr, which we automagically - dereference for the user and function ptrs, which have no children. + dereference for the user, and function ptrs which have no children. We also don't dereference void* as we don't know what to show. We can show char* so we allow it to be dereferenced. If you decide to test for it, please mind that a little magic is necessary to @@ -1803,71 +1802,155 @@ c_name_of_variable (struct varobj *parent) return savestring (parent->name, strlen (parent->name)); } -static char * -c_name_of_child (struct varobj *parent, int index) +/* Return the value of element TYPE_INDEX of a structure + value VALUE. VALUE's type should be a structure, + or union, or a typedef to struct/union. + + Returns NULL if getting the value fails. Never throws. */ +static struct value * +value_struct_element_index (struct value *value, int type_index) { - struct type *type; - struct type *target; - char *name; - char *string; + struct value *result = NULL; + volatile struct gdb_exception e; - type = get_type (parent); - target = get_target_type (type); + struct type *type = value_type (value); + type = check_typedef (type); + gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT + || TYPE_CODE (type) == TYPE_CODE_UNION); + + TRY_CATCH (e, RETURN_MASK_ERROR) + { + if (TYPE_FIELD_STATIC (type, type_index)) + result = value_static_field (type, type_index); + else + result = value_primitive_field (value, 0, type_index, type); + } + if (e.reason < 0) + { + return NULL; + } + else + { + return result; + } +} + +/* Obtain the information about child INDEX of the variable + object PARENT. + If CNAME is not null, sets *CNAME to the name of the child relative + to the parent. + If CVALUE is not null, sets *CVALUE to the value of the child. + If CTYPE is not null, sets *CTYPE to the type of the child. + + If any of CNAME, CVALUE, or CTYPE is not null, but the corresponding + information cannot be determined, set *CNAME, *CVALUE, or *CTYPE + to NULL. */ +static void +c_describe_child (struct varobj *parent, int index, + char **cname, struct value **cvalue, struct type **ctype) +{ + struct value *value = parent->value; + struct type *type = get_type (parent); + + if (cname) + *cname = NULL; + if (cvalue) + *cvalue = NULL; + if (ctype) + *ctype = NULL; + + /* Pointers to structures are treated just like + structures when accessing children. */ + if (TYPE_CODE (type) == TYPE_CODE_PTR) + { + struct type *target_type = get_target_type (type); + if (TYPE_CODE (target_type) == TYPE_CODE_STRUCT + || TYPE_CODE (target_type) == TYPE_CODE_UNION) + { + if (value) + gdb_value_ind (value, &value); + type = target_type; + } + } + switch (TYPE_CODE (type)) { case TYPE_CODE_ARRAY: - { - /* We never get here unless parent->num_children is greater than 0... */ - int len = 1; - while ((int) pow ((double) 10, (double) len) < index) - len++; - name = (char *) xmalloc (1 + len * sizeof (char)); - sprintf (name, "%d", index); - } + if (cname) + *cname = xstrprintf ("%d", index + + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type))); + + if (cvalue && value) + { + int real_index = index + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type)); + struct value *indval = + value_from_longest (builtin_type_int, (LONGEST) real_index); + gdb_value_subscript (value, indval, cvalue); + } + + if (ctype) + *ctype = get_target_type (type); + break; case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: - string = TYPE_FIELD_NAME (type, index); - name = savestring (string, strlen (string)); + if (cname) + { + char *string = TYPE_FIELD_NAME (type, index); + *cname = savestring (string, strlen (string)); + } + + if (cvalue && value) + { + /* For C, varobj index is the same as type index. */ + *cvalue = value_struct_element_index (value, index); + } + + if (ctype) + *ctype = TYPE_FIELD_TYPE (type, index); + break; case TYPE_CODE_PTR: - switch (TYPE_CODE (target)) - { - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - string = TYPE_FIELD_NAME (target, index); - name = savestring (string, strlen (string)); - break; + if (cname) + *cname = xstrprintf ("*%s", parent->name); - default: - name = - (char *) xmalloc ((strlen (parent->name) + 2) * sizeof (char)); - sprintf (name, "*%s", parent->name); - break; - } + if (cvalue && value) + gdb_value_ind (value, cvalue); + + if (ctype) + *ctype = get_target_type (type); + break; default: /* This should not happen */ - name = xstrdup ("???"); + if (cname) + *cname = xstrdup ("???"); + /* Don't set value and type, we don't know then. */ } +} +static char * +c_name_of_child (struct varobj *parent, int index) +{ + char *name; + c_describe_child (parent, index, &name, NULL, NULL); return name; } static struct value * c_value_of_root (struct varobj **var_handle) { - struct value *new_val; + struct value *new_val = NULL; struct varobj *var = *var_handle; struct frame_info *fi; int within_scope; /* Only root variables can be updated... */ - if (var->root->rootvar != var) + if (!is_root_p (var)) /* Not a root var */ return NULL; @@ -1878,14 +1961,17 @@ c_value_of_root (struct varobj **var_handle) else { reinit_frame_cache (); - - - fi = find_frame_addr_in_frame_chain (var->root->frame); - + fi = frame_find_by_id (var->root->frame); within_scope = fi != NULL; /* FIXME: select_frame could fail */ - if (within_scope) - select_frame (fi, -1); + if (fi) + { + CORE_ADDR pc = get_frame_pc (fi); + if (pc < BLOCK_START (var->root->valid_block) || + pc >= BLOCK_END (var->root->valid_block)) + within_scope = 0; + select_frame (fi); + } } if (within_scope) @@ -1895,24 +1981,12 @@ c_value_of_root (struct varobj **var_handle) go on */ if (gdb_evaluate_expression (var->root->exp, &new_val)) { - if (VALUE_LAZY (new_val)) - { - /* We need to catch errors because if - value_fetch_lazy fails we still want to continue - (after making val->error = 1) */ - /* FIXME: Shouldn't be using VALUE_CONTENTS? The - comment on value_fetch_lazy() says it is only - called from the macro... */ - if (!gdb_value_fetch_lazy (new_val)) - var->error = 1; - else - var->error = 0; - } + var->error = 0; + release_value (new_val); } else var->error = 1; - release_value (new_val); return new_val; } @@ -1922,59 +1996,8 @@ c_value_of_root (struct varobj **var_handle) static struct value * c_value_of_child (struct varobj *parent, int index) { - struct value *value; - struct value *temp; - struct value *indval; - struct type *type, *target; - char *name; - - type = get_type (parent); - target = get_target_type (type); - name = name_of_child (parent, index); - temp = parent->value; - value = NULL; - - if (temp != NULL) - { - switch (TYPE_CODE (type)) - { - case TYPE_CODE_ARRAY: -#if 0 - /* This breaks if the array lives in a (vector) register. */ - value = value_slice (temp, index, 1); - temp = value_coerce_array (value); - gdb_value_ind (temp, &value); -#else - indval = value_from_longest (builtin_type_int, (LONGEST) index); - gdb_value_subscript (temp, indval, &value); -#endif - break; - - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - value = value_struct_elt (&temp, NULL, name, NULL, "vstructure"); - break; - - case TYPE_CODE_PTR: - switch (TYPE_CODE (target)) - { - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - value = - value_struct_elt (&temp, NULL, name, NULL, "vstructure"); - break; - - default: - gdb_value_ind (temp, &value); - break; - } - break; - - default: - break; - } - } - + struct value *value = NULL; + c_describe_child (parent, index, NULL, &value, NULL); if (value != NULL) release_value (value); @@ -1984,42 +2007,8 @@ c_value_of_child (struct varobj *parent, int index) static struct type * c_type_of_child (struct varobj *parent, int index) { - struct type *type; - char *name = name_of_child (parent, index); - - switch (TYPE_CODE (parent->type)) - { - case TYPE_CODE_ARRAY: - type = TYPE_TARGET_TYPE (parent->type); - break; - - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - type = lookup_struct_elt_type (parent->type, name, 0); - break; - - case TYPE_CODE_PTR: - switch (TYPE_CODE (TYPE_TARGET_TYPE (parent->type))) - { - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - type = lookup_struct_elt_type (parent->type, name, 0); - break; - - default: - type = TYPE_TARGET_TYPE (parent->type); - break; - } - break; - - default: - /* This should not happen as only the above types have children */ - warning ("Child of parent whose type does not allow children"); - /* FIXME: Can we still go on? */ - type = NULL; - break; - } - + struct type *type = NULL; + c_describe_child (parent, index, NULL, NULL, &type); return type; } @@ -2032,7 +2021,6 @@ c_variable_editable (struct varobj *var) case TYPE_CODE_UNION: case TYPE_CODE_ARRAY: case TYPE_CODE_FUNC: - case TYPE_CODE_MEMBER: case TYPE_CODE_METHOD: return 0; break; @@ -2046,21 +2034,15 @@ c_variable_editable (struct varobj *var) static char * c_value_of_variable (struct varobj *var) { - struct type *type; - struct value *val; + /* BOGUS: if val_print sees a struct/class, or a reference to one, + it will print out its children instead of "{...}". So we need to + catch that case explicitly. */ + struct type *type = get_type (var); - if (var->value != NULL) - val = var->value; - else - { - /* This can happen if we attempt to get the value of a struct - member when the parent is an invalid pointer. */ - return xstrdup ("???"); - } + /* Strip top-level references. */ + while (TYPE_CODE (type) == TYPE_CODE_REF) + type = check_typedef (TYPE_TARGET_TYPE (type)); - /* BOGUS: if val_print sees a struct/class, it will print out its - children instead of "{...}" */ - type = get_type (var); switch (TYPE_CODE (type)) { case TYPE_CODE_STRUCT: @@ -2070,29 +2052,28 @@ c_value_of_variable (struct varobj *var) case TYPE_CODE_ARRAY: { - char number[18]; - sprintf (number, "[%d]", var->num_children); - return xstrdup (number); + char *number; + number = xstrprintf ("[%d]", var->num_children); + return (number); } /* break; */ default: { - long dummy; - struct ui_file *stb = mem_fileopen (); - struct cleanup *old_chain = make_cleanup_ui_file_delete (stb); - char *thevalue; - - if (VALUE_LAZY (val)) - gdb_value_fetch_lazy (val); - val_print (VALUE_TYPE (val), VALUE_CONTENTS_RAW (val), 0, - VALUE_ADDRESS (val), - stb, format_code[(int) var->format], 1, 0, 0); - thevalue = ui_file_xstrdup (stb, &dummy); - do_cleanups (old_chain); - return thevalue; + if (var->value == NULL) + { + /* This can happen if we attempt to get the value of a struct + member when the parent is an invalid pointer. This is an + error condition, so we should tell the caller. */ + return NULL; + } + else + { + gdb_assert (varobj_value_is_changeable_p (var)); + gdb_assert (!value_lazy (var->value)); + return value_get_print_value (var->value, var->format); + } } - /* break; */ } } @@ -2139,9 +2120,9 @@ cplus_number_of_children (struct varobj *var) type = get_type_deref (var->parent); cplus_class_num_children (type, kids); - if (STREQ (var->name, "public")) + if (strcmp (var->name, "public") == 0) children = kids[v_public]; - else if (STREQ (var->name, "private")) + else if (strcmp (var->name, "private") == 0) children = kids[v_private]; else children = kids[v_protected]; @@ -2192,7 +2173,6 @@ cplus_name_of_child (struct varobj *parent, int index) { char *name; struct type *type; - int children[3]; if (CPLUS_FAKE_CHILD (parent)) { @@ -2207,48 +2187,97 @@ cplus_name_of_child (struct varobj *parent, int index) { case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: - cplus_class_num_children (type, children); - if (CPLUS_FAKE_CHILD (parent)) { - /* FIXME: This assumes that type orders - inherited, public, private, protected */ - int i = index + TYPE_N_BASECLASSES (type); - if (STREQ (parent->name, "private") - || STREQ (parent->name, "protected")) - i += children[v_public]; - if (STREQ (parent->name, "protected")) - i += children[v_private]; - - name = TYPE_FIELD_NAME (type, i); + /* The fields of the class type are ordered as they + appear in the class. We are given an index for a + particular access control type ("public","protected", + or "private"). We must skip over fields that don't + have the access control we are looking for to properly + find the indexed field. */ + int type_index = TYPE_N_BASECLASSES (type); + if (strcmp (parent->name, "private") == 0) + { + while (index >= 0) + { + if (TYPE_VPTR_BASETYPE (type) == type + && type_index == TYPE_VPTR_FIELDNO (type)) + ; /* ignore vptr */ + else if (TYPE_FIELD_PRIVATE (type, type_index)) + --index; + ++type_index; + } + --type_index; + } + else if (strcmp (parent->name, "protected") == 0) + { + while (index >= 0) + { + if (TYPE_VPTR_BASETYPE (type) == type + && type_index == TYPE_VPTR_FIELDNO (type)) + ; /* ignore vptr */ + else if (TYPE_FIELD_PROTECTED (type, type_index)) + --index; + ++type_index; + } + --type_index; + } + else + { + while (index >= 0) + { + if (TYPE_VPTR_BASETYPE (type) == type + && type_index == TYPE_VPTR_FIELDNO (type)) + ; /* ignore vptr */ + else if (!TYPE_FIELD_PRIVATE (type, type_index) && + !TYPE_FIELD_PROTECTED (type, type_index)) + --index; + ++type_index; + } + --type_index; + } + + name = TYPE_FIELD_NAME (type, type_index); } else if (index < TYPE_N_BASECLASSES (type)) + /* We are looking up the name of a base class */ name = TYPE_FIELD_NAME (type, index); else { + int children[3]; + cplus_class_num_children(type, children); + /* Everything beyond the baseclasses can - only be "public", "private", or "protected" */ + only be "public", "private", or "protected" + + The special "fake" children are always output by varobj in + this order. So if INDEX == 2, it MUST be "protected". */ index -= TYPE_N_BASECLASSES (type); switch (index) { case 0: - if (children[v_public] != 0) - { - name = "public"; - break; - } + if (children[v_public] > 0) + name = "public"; + else if (children[v_private] > 0) + name = "private"; + else + name = "protected"; + break; case 1: - if (children[v_private] != 0) + if (children[v_public] > 0) { - name = "private"; - break; + if (children[v_private] > 0) + name = "private"; + else + name = "protected"; } + else if (children[v_private] > 0) + name = "protected"; + break; case 2: - if (children[v_protected] != 0) - { - name = "protected"; - break; - } + /* Must be protected */ + name = "protected"; + break; default: /* error! */ break; @@ -2282,7 +2311,6 @@ cplus_value_of_child (struct varobj *parent, int index) { struct type *type; struct value *value; - char *name; if (CPLUS_FAKE_CHILD (parent)) type = get_type_deref (parent->parent); @@ -2290,17 +2318,25 @@ cplus_value_of_child (struct varobj *parent, int index) type = get_type_deref (parent); value = NULL; - name = name_of_child (parent, index); if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) || ((TYPE_CODE (type)) == TYPE_CODE_UNION)) { if (CPLUS_FAKE_CHILD (parent)) { + char *name; struct value *temp = parent->parent->value; - value = value_struct_elt (&temp, NULL, name, - NULL, "cplus_structure"); - release_value (value); + + if (temp == NULL) + return NULL; + + name = name_of_child (parent, index); + gdb_value_struct_elt (NULL, &value, &temp, NULL, name, NULL, + "cplus_structure"); + if (value != NULL) + release_value (value); + + xfree (name); } else if (index >= TYPE_N_BASECLASSES (type)) { @@ -2312,10 +2348,11 @@ cplus_value_of_child (struct varobj *parent, int index) /* Baseclass */ if (parent->value != NULL) { - struct value *temp; + struct value *temp = NULL; - if (TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_PTR - || TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_REF) + /* No special processing for references is needed -- + value_cast below handles references. */ + if (TYPE_CODE (value_type (parent->value)) == TYPE_CODE_PTR) { if (!gdb_value_ind (parent->value, &temp)) return NULL; @@ -2323,8 +2360,17 @@ cplus_value_of_child (struct varobj *parent, int index) else temp = parent->value; - value = value_cast (TYPE_FIELD_TYPE (type, index), temp); - release_value (value); + if (temp != NULL) + { + value = value_cast (TYPE_FIELD_TYPE (type, index), temp); + release_value (value); + } + else + { + /* We failed to evaluate the parent's value, so don't even + bother trying to evaluate this child. */ + return NULL; + } } } } @@ -2340,21 +2386,31 @@ cplus_type_of_child (struct varobj *parent, int index) { struct type *type, *t; - t = get_type_deref (parent); + if (CPLUS_FAKE_CHILD (parent)) + { + /* Looking for the type of a child of public, private, or protected. */ + t = get_type_deref (parent->parent); + } + else + t = get_type_deref (parent); + type = NULL; switch (TYPE_CODE (t)) { case TYPE_CODE_STRUCT: case TYPE_CODE_UNION: - if (index >= TYPE_N_BASECLASSES (t)) + if (CPLUS_FAKE_CHILD (parent)) { - /* special */ - return NULL; + char *name = cplus_name_of_child (parent, index); + type = lookup_struct_elt_type (t, name, 0); + xfree (name); } + else if (index < TYPE_N_BASECLASSES (t)) + type = TYPE_FIELD_TYPE (t, index); else { - /* Baseclass */ - type = TYPE_FIELD_TYPE (t, index); + /* special */ + return NULL; } break; @@ -2475,7 +2531,12 @@ _initialize_varobj (void) varobj_table = xmalloc (sizeof_table); memset (varobj_table, 0, sizeof_table); - add_show_from_set (add_set_cmd ("debugvarobj", class_maintenance, var_zinteger, (char *) &varobjdebug, "Set varobj debugging.\n\ -When non-zero, varobj debugging is enabled.", &setlist), - &showlist); + add_setshow_zinteger_cmd ("debugvarobj", class_maintenance, + &varobjdebug, _("\ +Set varobj debugging."), _("\ +Show varobj debugging."), _("\ +When non-zero, varobj debugging is enabled."), + NULL, + show_varobjdebug, + &setlist, &showlist); }