using the currently selected frame. */
int use_selected_frame;
+ /* Flag that indicates validity: set to 0 when this varobj_root refers
+ to symbols that do not exist anymore. */
+ int is_valid;
+
/* Language info for this variable and its children */
struct language_specific *lang;
/* Last print value. */
char *print_value;
+
+ /* Is this variable frozen. Frozen variables are never implicitly
+ updated by -var-update *
+ or -var-update <direct-or-indirect-parent>. */
+ int frozen;
+
+ /* Is the value of this variable intentionally not fetched? It is
+ not fetched if either the variable is frozen, or any parents is
+ frozen. */
+ int not_fetched;
};
struct cpstack
{
char *p;
enum varobj_languages lang;
- struct value *value;
+ struct value *value = NULL;
/* 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 = deprecated_selected_frame;
+ fi = deprecated_safe_get_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
if (fi != NULL)
{
var->root->frame = get_frame_id (fi);
- old_fi = deprecated_selected_frame;
+ old_fi = get_selected_frame (NULL);
select_frame (fi);
}
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, &value))
- /* Error getting the value. Try to at least get the
- right type. */
- value = evaluate_type (var->root->exp);
+ {
+ /* Error getting the value. Try to at least get the
+ right type. */
+ struct value *type_only_value = evaluate_type (var->root->exp);
+ var->type = value_type (type_only_value);
+ }
+ else
+ var->type = value_type (value);
- var->type = value_type (value);
install_new_value (var, value, 1 /* Initial assignment */);
/* Set language info */
return var->format;
}
+void
+varobj_set_frozen (struct varobj *var, int frozen)
+{
+ /* When a variable is unfrozen, we don't fetch its value.
+ The 'not_fetched' flag remains set, so next -var-update
+ won't complain.
+
+ We don't fetch the value, because for structures the client
+ should do -var-update anyway. It would be bad to have different
+ client-size logic for structure and other types. */
+ var->frozen = frozen;
+}
+
+int
+varobj_get_frozen (struct varobj *var)
+{
+ return var->frozen;
+}
+
+
int
varobj_get_num_children (struct varobj *var)
{
long length;
/* For the "fake" variables, do not return a type. (It's type is
- NULL, too.) */
- if (CPLUS_FAKE_CHILD (var))
+ NULL, too.)
+ Do not return a type for invalid variables as well. */
+ if (CPLUS_FAKE_CHILD (var) || !var->root->is_valid)
return NULL;
stb = mem_fileopen ();
{
int attributes = 0;
- if (variable_editable (var))
+ if (var->root->is_valid && variable_editable (var))
/* FIXME: define masks for attributes */
attributes |= 0x00000001; /* Editable */
int changeable;
int need_to_fetch;
int changed = 0;
+ int intentionally_not_fetched = 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
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))
+ struct varobj *parent = var->parent;
+ int frozen = var->frozen;
+ for (; !frozen && parent; parent = parent->parent)
+ frozen |= parent->frozen;
+
+ if (frozen && initial)
+ {
+ /* For variables that are frozen, or are children of frozen
+ variables, we don't do fetch on initial assignment.
+ For non-initial assignemnt we do the fetch, since it means we're
+ explicitly asked to compare the new value with the old one. */
+ intentionally_not_fetched = 1;
+ }
+ else if (!gdb_value_fetch_lazy (value))
{
/* Set the value to NULL, so that for the next -var-update,
we don't try to compare the new value with this value,
/* 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)
+ if (initial && changeable)
var->print_value = value_get_print_value (value, var->format);
else if (changeable)
{
{
/* Try to compare the values. That requires that both
values are non-lazy. */
-
- /* Quick comparison of NULL values. */
- if (var->value == NULL && value == NULL)
+ if (var->not_fetched && value_lazy (var->value))
+ {
+ /* This is a frozen varobj and the value was never read.
+ Presumably, UI shows some "never read" indicator.
+ Now that we've fetched the real value, we need to report
+ this varobj as changed so that UI can show the real
+ value. */
+ changed = 1;
+ }
+ else if (var->value == NULL && value == NULL)
/* Equal. */
;
else if (var->value == NULL || value == NULL)
}
/* We must always keep the new value, since children depend on it. */
- if (var->value != NULL)
+ if (var->value != NULL && var->value != value)
value_free (var->value);
var->value = value;
+ if (value && value_lazy (value) && intentionally_not_fetched)
+ var->not_fetched = 1;
+ else
+ var->not_fetched = 0;
var->updated = 0;
gdb_assert (!var->value || value_type (var->value));
expression to see if it's changed. Then go all the way
through its children, reconstructing them and noting if they've
changed.
- Return value:
- -1 if there was an error updating the varobj
- -2 if the type changed
- Otherwise it is the number of children + parent changed
+ Return value:
+ < 0 for error values, see varobj.h.
+ Otherwise it is the number of children + parent changed.
- Only root variables can be updated...
+ The EXPLICIT parameter specifies if this call is result
+ of MI request to update this specific variable, or
+ result of implicit -var-update *. For implicit request, we don't
+ update frozen variables.
NOTE: This function may delete the caller's varobj. If it
- returns -2, then it has done this and VARP will be modified
- to point to the new varobj. */
+ returns TYPE_CHANGED, then it has done this and VARP will be modified
+ to point to the new varobj. */
int
-varobj_update (struct varobj **varp, struct varobj ***changelist)
+varobj_update (struct varobj **varp, struct varobj ***changelist,
+ int explicit)
{
int changed = 0;
- int error = 0;
- int type_changed;
+ int type_changed = 0;
int i;
int vleft;
struct varobj *v;
struct frame_id old_fid;
struct frame_info *fi;
- /* sanity check: have we been passed a pointer? */
- if (changelist == NULL)
- return -1;
+ /* sanity check: have we been passed a pointer? */
+ gdb_assert (changelist);
- /* Only root variables can be updated... */
- if (!is_root_p (*varp))
- /* Not a root var */
- return -1;
+ /* Frozen means frozen -- we don't check for any change in
+ this varobj, including its going out of scope, or
+ changing type. One use case for frozen varobjs is
+ retaining previously evaluated expressions, and we don't
+ want them to be reevaluated at all. */
+ if (!explicit && (*varp)->frozen)
+ return 0;
- /* Save the selected stack frame, since we will need to change it
- in order to evaluate expressions. */
- 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
- the frame in which a local existed. We are letting the
- value_of_root variable dispose of the varobj if the type
- 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 this is a "use_selected_frame" varobj, and its type has changed,
- them note that it's changed. */
- if (type_changed)
- VEC_safe_push (varobj_p, result, *varp);
+ if (!(*varp)->root->is_valid)
+ return INVALID;
- if (install_new_value ((*varp), new, type_changed))
+ if ((*varp)->root->rootvar == *varp)
{
- /* 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);
- }
+ /* Save the selected stack frame, since we will need to change it
+ in order to evaluate expressions. */
+ old_fid = get_frame_id (deprecated_safe_get_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
+ the frame in which a local existed. We are letting the
+ value_of_root variable dispose of the varobj if the type
+ 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 this is a "use_selected_frame" varobj, and its type has changed,
+ them note that it's changed. */
+ if (type_changed)
+ VEC_safe_push (varobj_p, result, *varp);
+
+ if (install_new_value ((*varp), new, type_changed))
+ {
+ /* 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);
+ }
- if (new == NULL)
- {
- /* This means the varobj itself is out of scope.
- Report it. */
- VEC_free (varobj_p, result);
- return -1;
+ if (new == NULL)
+ {
+ /* This means the varobj itself is out of scope.
+ Report it. */
+ VEC_free (varobj_p, result);
+ return NOT_IN_SCOPE;
+ }
}
VEC_safe_push (varobj_p, stack, *varp);
- /* Walk through the children, reconstructing them all. */
+ /* Walk through the children, reconstructing them all. */
while (!VEC_empty (varobj_p, stack))
{
v = VEC_pop (varobj_p, stack);
{
varobj_p c = VEC_index (varobj_p, v->children, i);
/* Child may be NULL if explicitly deleted by -var-delete. */
- if (c != NULL)
+ if (c != NULL && !c->frozen)
VEC_safe_push (varobj_p, stack, c);
}
/* Update this variable, unless it's a root, which is already
updated. */
- if (v != *varp)
+ if (v->root->rootvar != v)
{
new = value_of_child (v->parent, v->index);
if (install_new_value (v, new, 0 /* type not changed */))
}
}
- /* Alloc (changed + 1) list entries */
+ /* Alloc (changed + 1) list entries. */
changed = VEC_length (varobj_p, result);
*changelist = xmalloc ((changed + 1) * sizeof (struct varobj *));
cv = *changelist;
}
*cv = 0;
+ VEC_free (varobj_p, stack);
+ VEC_free (varobj_p, result);
+
if (type_changed)
- return -2;
+ return TYPE_CHANGED;
else
return changed;
}
var->root = NULL;
var->updated = 0;
var->print_value = NULL;
+ var->frozen = 0;
+ var->not_fetched = 0;
return var;
}
var->root->frame = null_frame_id;
var->root->use_selected_frame = 0;
var->root->rootvar = NULL;
+ var->root->is_valid = 1;
return var;
}
static char *
my_value_of_variable (struct varobj *var)
{
- return (*var->root->lang->value_of_variable) (var);
+ if (var->root->is_valid)
+ return (*var->root->lang->value_of_variable) (var);
+ else
+ return NULL;
}
static char *
}
else
{
+ if (var->not_fetched && value_lazy (var->value))
+ /* Frozen variable and no value yet. We don't
+ implicitly fetch the value. MI response will
+ use empty string for the value, which is OK. */
+ return NULL;
+
gdb_assert (varobj_value_is_changeable_p (var));
gdb_assert (!value_lazy (var->value));
return value_get_print_value (var->value, var->format);
show_varobjdebug,
&setlist, &showlist);
}
+
+/* Invalidate the varobjs that are tied to locals and re-create the ones that
+ are defined on globals.
+ Invalidated varobjs will be always printed in_scope="invalid". */
+void
+varobj_invalidate (void)
+{
+ struct varobj **all_rootvarobj;
+ struct varobj **varp;
+
+ if (varobj_list (&all_rootvarobj) > 0)
+ {
+ varp = all_rootvarobj;
+ while (*varp != NULL)
+ {
+ /* global var must be re-evaluated. */
+ if ((*varp)->root->valid_block == NULL)
+ {
+ struct varobj *tmp_var;
+
+ /* Try to create a varobj with same expression. If we succeed replace
+ the old varobj, otherwise invalidate it. */
+ tmp_var = varobj_create (NULL, (*varp)->name, (CORE_ADDR) 0, USE_CURRENT_FRAME);
+ if (tmp_var != NULL)
+ {
+ tmp_var->obj_name = xstrdup ((*varp)->obj_name);
+ varobj_delete (*varp, NULL, 0);
+ install_variable (tmp_var);
+ }
+ else
+ (*varp)->root->is_valid = 0;
+ }
+ else /* locals must be invalidated. */
+ (*varp)->root->is_valid = 0;
+
+ varp++;
+ }
+ xfree (all_rootvarobj);
+ }
+ return;
+}