2006-11-28 Vladimir Prus <vladimir@codesourcery.com>
Fetch varobj values from memory in a single place, and only fetch the values that are really needed. * varobj.c (struct varobj): Clarify comment. (my_value_equal): Remove. (install_new_value): New function. (type_of_child): Remove. (varobj_create): Use install_new_value. (varobj_set_value): Use value_contents_equal, not my_value_equal. (varobj_update): Use install_new_value. (create_child): Likewise. Inline type_of_child here. (value_of_child): Don't fetch the value. (c_value_of_root): Likewise. (c_value_of_variable): Likewise. (type_changeable): Improve comments.
This commit is contained in:
parent
74ca34cea9
commit
acd65feb7e
|
@ -1,3 +1,21 @@
|
||||||
|
2006-11-28 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
|
Fetch varobj values from memory in a single place,
|
||||||
|
and only fetch the values that are really needed.
|
||||||
|
* varobj.c (struct varobj): Clarify comment.
|
||||||
|
(my_value_equal): Remove.
|
||||||
|
(install_new_value): New function.
|
||||||
|
(type_of_child): Remove.
|
||||||
|
(varobj_create): Use install_new_value.
|
||||||
|
(varobj_set_value): Use value_contents_equal, not
|
||||||
|
my_value_equal.
|
||||||
|
(varobj_update): Use install_new_value.
|
||||||
|
(create_child): Likewise. Inline type_of_child here.
|
||||||
|
(value_of_child): Don't fetch the value.
|
||||||
|
(c_value_of_root): Likewise.
|
||||||
|
(c_value_of_variable): Likewise.
|
||||||
|
(type_changeable): Improve comments.
|
||||||
|
|
||||||
2006-11-28 Daniel Jacobowitz <dan@codesourcery.com>
|
2006-11-28 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* remote.c (struct remote_arch_state): Doc fix.
|
* remote.c (struct remote_arch_state): Doc fix.
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
2006-11-28 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
|
* gdb.mi/mi-var-cmd.exp: Check -var-update after
|
||||||
|
assignement of arrays and function pointers.
|
||||||
|
* gdb.mi/var-cmd.c: Add declaration necessary for above
|
||||||
|
tests.
|
||||||
|
|
||||||
2006-11-27 Nathan Sidwell <nathan@codesourcery.com>
|
2006-11-27 Nathan Sidwell <nathan@codesourcery.com>
|
||||||
|
|
||||||
* gdb.base/break.c (main): Call malloc.
|
* gdb.base/break.c (main): Call malloc.
|
||||||
|
|
|
@ -382,6 +382,43 @@ mi_gdb_test "-var-assign lsimple.integer 333" \
|
||||||
"\\^done,value=\"333\"" \
|
"\\^done,value=\"333\"" \
|
||||||
"assign to lsimple.integer"
|
"assign to lsimple.integer"
|
||||||
|
|
||||||
|
mi_gdb_test "-var-update *" \
|
||||||
|
"\\^done,changelist=.*" \
|
||||||
|
"var update"
|
||||||
|
|
||||||
|
# Check that assignment of function and array values
|
||||||
|
# promotes the assigned value to function pointer/data
|
||||||
|
# pointer before comparing with the existing value,
|
||||||
|
# and does not incorrectly make the value as changed.
|
||||||
|
mi_gdb_test "-var-assign func do_block_tests" \
|
||||||
|
"\\^done,value=\"$hex <do_block_tests>\"" \
|
||||||
|
"assign same value to func"
|
||||||
|
|
||||||
|
mi_gdb_test "-var-update *" \
|
||||||
|
"\\^done,changelist=\\\[\\\]" \
|
||||||
|
"assign same value to func (update)"
|
||||||
|
|
||||||
|
mi_gdb_test "-var-create array_ptr * array_ptr" \
|
||||||
|
"\\^done,name=\"array_ptr\",numchild=\"1\",type=\"int \\*\"" \
|
||||||
|
"create global variable array_ptr"
|
||||||
|
|
||||||
|
mi_gdb_test "-var-assign array_ptr array2" \
|
||||||
|
"\\^done,value=\"$hex\"" \
|
||||||
|
"assign array to pointer"
|
||||||
|
|
||||||
|
mi_gdb_test "-var-update *" \
|
||||||
|
"\\^done,changelist=\\\[\{name=\"array_ptr\",in_scope=\"true\",type_changed=\"false\"\}\\\]" \
|
||||||
|
"assign array to pointer (update)"
|
||||||
|
|
||||||
|
mi_gdb_test "-var-assign array_ptr array2" \
|
||||||
|
"\\^done,value=\"$hex\"" \
|
||||||
|
"assign same array to pointer"
|
||||||
|
|
||||||
|
mi_gdb_test "-var-update *" \
|
||||||
|
"\\^done,changelist=\\\[\\\]" \
|
||||||
|
"assign same array to pointer (update)"
|
||||||
|
|
||||||
|
|
||||||
######
|
######
|
||||||
# End of assign tests
|
# End of assign tests
|
||||||
#####
|
#####
|
||||||
|
|
|
@ -106,6 +106,10 @@ void incr_a (char a)
|
||||||
b = a;
|
b = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int array[] = {1,2,3};
|
||||||
|
int array2[] = {4,5,6};
|
||||||
|
int *array_ptr = array;
|
||||||
|
|
||||||
void
|
void
|
||||||
do_locals_tests ()
|
do_locals_tests ()
|
||||||
{
|
{
|
||||||
|
|
297
gdb/varobj.c
297
gdb/varobj.c
|
@ -101,7 +101,9 @@ struct varobj
|
||||||
/* The type of this variable. This may NEVER be NULL. */
|
/* The type of this variable. This may NEVER be NULL. */
|
||||||
struct type *type;
|
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 type_changeable (this) is non-zero, the value is either
|
||||||
|
NULL, or not lazy. */
|
||||||
struct value *value;
|
struct value *value;
|
||||||
|
|
||||||
/* Did an error occur evaluating the expression or getting its value? */
|
/* Did an error occur evaluating the expression or getting its value? */
|
||||||
|
@ -202,8 +204,6 @@ static struct type *get_target_type (struct type *);
|
||||||
|
|
||||||
static enum varobj_display_formats variable_default_display (struct varobj *);
|
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 void vpush (struct vstack **pstack, struct varobj *var);
|
||||||
|
|
||||||
static struct varobj *vpop (struct vstack **pstack);
|
static struct varobj *vpop (struct vstack **pstack);
|
||||||
|
@ -212,6 +212,9 @@ static void cppush (struct cpstack **pstack, char *name);
|
||||||
|
|
||||||
static char *cppop (struct cpstack **pstack);
|
static char *cppop (struct cpstack **pstack);
|
||||||
|
|
||||||
|
static int install_new_value (struct varobj *var, struct value *value,
|
||||||
|
int initial);
|
||||||
|
|
||||||
/* Language-specific routines. */
|
/* Language-specific routines. */
|
||||||
|
|
||||||
static enum varobj_languages variable_language (struct varobj *var);
|
static enum varobj_languages variable_language (struct varobj *var);
|
||||||
|
@ -226,8 +229,6 @@ static struct value *value_of_root (struct varobj **var_handle, int *);
|
||||||
|
|
||||||
static struct value *value_of_child (struct varobj *parent, int index);
|
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 int variable_editable (struct varobj *var);
|
||||||
|
|
||||||
static char *my_value_of_variable (struct varobj *var);
|
static char *my_value_of_variable (struct varobj *var);
|
||||||
|
@ -445,6 +446,7 @@ varobj_create (char *objname,
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
enum varobj_languages lang;
|
enum varobj_languages lang;
|
||||||
|
struct value *value;
|
||||||
|
|
||||||
/* Parse and evaluate the expression, filling in as much
|
/* Parse and evaluate the expression, filling in as much
|
||||||
of the variable's data as possible */
|
of the variable's data as possible */
|
||||||
|
@ -505,17 +507,16 @@ varobj_create (char *objname,
|
||||||
/* We definitively need to catch errors here.
|
/* We definitively need to catch errors here.
|
||||||
If evaluate_expression succeeds we got the value we wanted.
|
If evaluate_expression succeeds we got the value we wanted.
|
||||||
But if it fails, we still go on with a call to evaluate_type() */
|
But if it fails, we still go on with a call to evaluate_type() */
|
||||||
if (gdb_evaluate_expression (var->root->exp, &var->value))
|
if (!gdb_evaluate_expression (var->root->exp, &value))
|
||||||
{
|
/* Error getting the value. Try to at least get the
|
||||||
/* no error */
|
right type. */
|
||||||
release_value (var->value);
|
value = evaluate_type (var->root->exp);
|
||||||
if (value_lazy (var->value))
|
|
||||||
gdb_value_fetch_lazy (var->value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
var->value = evaluate_type (var->root->exp);
|
|
||||||
|
|
||||||
var->type = value_type (var->value);
|
release_value (value);
|
||||||
|
|
||||||
|
var->type = value_type (value);
|
||||||
|
|
||||||
|
install_new_value (var, value, 1 /* Initial assignment */);
|
||||||
|
|
||||||
/* Set language info */
|
/* Set language info */
|
||||||
lang = variable_language (var);
|
lang = variable_language (var);
|
||||||
|
@ -825,8 +826,28 @@ varobj_set_value (struct varobj *var, char *expression)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!my_value_equal (var->value, value, &error))
|
/* All types that are editable must also be changeable. */
|
||||||
|
gdb_assert (type_changeable (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);
|
||||||
|
|
||||||
|
if (!value_contents_equal (var->value, value))
|
||||||
var->updated = 1;
|
var->updated = 1;
|
||||||
|
|
||||||
|
/* 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))
|
if (!gdb_value_assign (var->value, value, &val))
|
||||||
return 0;
|
return 0;
|
||||||
value_free (var->value);
|
value_free (var->value);
|
||||||
|
@ -870,6 +891,101 @@ varobj_list (struct varobj ***varlist)
|
||||||
return rootcount;
|
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. */
|
||||||
|
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 = type_changeable (var);
|
||||||
|
need_to_fetch = changeable;
|
||||||
|
|
||||||
|
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 && 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
|
||||||
|
{
|
||||||
|
gdb_assert (!value_lazy (var->value));
|
||||||
|
gdb_assert (!value_lazy (value));
|
||||||
|
|
||||||
|
if (!value_contents_equal (var->value, value))
|
||||||
|
changed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Update the values for a variable and its children. This is a
|
/* Update the values for a variable and its children. This is a
|
||||||
two-pronged attack. First, re-parse the value for the root's
|
two-pronged attack. First, re-parse the value for the root's
|
||||||
expression to see if it's changed. Then go all the way
|
expression to see if it's changed. Then go all the way
|
||||||
|
@ -939,23 +1055,15 @@ varobj_update (struct varobj **varp, struct varobj ***changelist)
|
||||||
vpush (&result, *varp);
|
vpush (&result, *varp);
|
||||||
changed++;
|
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) &&
|
|
||||||
((*varp)->updated || !my_value_equal ((*varp)->value, new, &error)))
|
|
||||||
{
|
|
||||||
vpush (&result, *varp);
|
|
||||||
(*varp)->updated = 0;
|
|
||||||
changed++;
|
|
||||||
/* Its value is going to be updated to NEW. */
|
|
||||||
(*varp)->error = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We must always keep around the new value for this root
|
if (install_new_value ((*varp), new, type_changed))
|
||||||
variable expression, or we lose the updated children! */
|
{
|
||||||
value_free ((*varp)->value);
|
/* If type_changed is 1, install_new_value will never return
|
||||||
(*varp)->value = new;
|
non-zero, so we'll never report the same variable twice. */
|
||||||
|
gdb_assert (!type_changed);
|
||||||
|
vpush (&result, (*varp));
|
||||||
|
changed++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize a stack */
|
/* Initialize a stack */
|
||||||
vpush (&stack, NULL);
|
vpush (&stack, NULL);
|
||||||
|
@ -982,21 +1090,13 @@ varobj_update (struct varobj **varp, struct varobj ***changelist)
|
||||||
|
|
||||||
/* Update this variable */
|
/* Update this variable */
|
||||||
new = value_of_child (v->parent, v->index);
|
new = value_of_child (v->parent, v->index);
|
||||||
if (type_changeable (v) &&
|
if (install_new_value (v, new, 0 /* type not changed */))
|
||||||
(v->updated || !my_value_equal (v->value, new, &error)))
|
{
|
||||||
{
|
|
||||||
/* Note that it's changed */
|
/* Note that it's changed */
|
||||||
vpush (&result, v);
|
vpush (&result, v);
|
||||||
v->updated = 0;
|
v->updated = 0;
|
||||||
changed++;
|
changed++;
|
||||||
}
|
}
|
||||||
/* Its value is going to be updated to NEW. */
|
|
||||||
v->error = error;
|
|
||||||
|
|
||||||
/* 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 */
|
/* Get next child */
|
||||||
v = vpop (&stack);
|
v = vpop (&stack);
|
||||||
|
@ -1257,15 +1357,14 @@ create_child (struct varobj *parent, int index, char *name)
|
||||||
{
|
{
|
||||||
struct varobj *child;
|
struct varobj *child;
|
||||||
char *childs_name;
|
char *childs_name;
|
||||||
|
struct value *value;
|
||||||
|
|
||||||
child = new_variable ();
|
child = new_variable ();
|
||||||
|
|
||||||
/* name is allocated by name_of_child */
|
/* name is allocated by name_of_child */
|
||||||
child->name = name;
|
child->name = name;
|
||||||
child->index = index;
|
child->index = index;
|
||||||
child->value = value_of_child (parent, index);
|
value = value_of_child (parent, index);
|
||||||
if ((!CPLUS_FAKE_CHILD (child) && child->value == NULL) || parent->error)
|
|
||||||
child->error = 1;
|
|
||||||
child->parent = parent;
|
child->parent = parent;
|
||||||
child->root = parent->root;
|
child->root = parent->root;
|
||||||
childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
|
childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
|
||||||
|
@ -1275,8 +1374,20 @@ create_child (struct varobj *parent, int index, char *name)
|
||||||
/* Save a pointer to this child in the parent */
|
/* Save a pointer to this child in the parent */
|
||||||
save_child_in_parent (parent, child);
|
save_child_in_parent (parent, child);
|
||||||
|
|
||||||
/* Note the type of this child */
|
/* Compute the type of the child. Must do this before
|
||||||
child->type = type_of_child (child);
|
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);
|
||||||
|
|
||||||
|
if ((!CPLUS_FAKE_CHILD (child) && child->value == NULL) || parent->error)
|
||||||
|
child->error = 1;
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
@ -1451,42 +1562,6 @@ variable_default_display (struct varobj *var)
|
||||||
return FORMAT_NATURAL;
|
return FORMAT_NATURAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is similar to GDB's value_contents_equal, except that
|
|
||||||
this one is "safe"; it never longjmps. It determines if the VAL1's
|
|
||||||
value is the same as VAL2. If for some reason the value of VAR2
|
|
||||||
can't be established, *ERROR2 is set to non-zero. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
my_value_equal (struct value *val1, struct value *volatile val2, int *error2)
|
|
||||||
{
|
|
||||||
volatile struct gdb_exception except;
|
|
||||||
|
|
||||||
/* As a special case, if both are null, we say they're equal. */
|
|
||||||
if (val1 == NULL && val2 == NULL)
|
|
||||||
return 1;
|
|
||||||
else if (val1 == NULL || val2 == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* The contents of VAL1 are supposed to be known. */
|
|
||||||
gdb_assert (!value_lazy (val1));
|
|
||||||
|
|
||||||
/* Make sure we also know the contents of VAL2. */
|
|
||||||
val2 = coerce_array (val2);
|
|
||||||
TRY_CATCH (except, RETURN_MASK_ERROR)
|
|
||||||
{
|
|
||||||
if (value_lazy (val2))
|
|
||||||
value_fetch_lazy (val2);
|
|
||||||
}
|
|
||||||
if (except.reason < 0)
|
|
||||||
{
|
|
||||||
*error2 = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
gdb_assert (!value_lazy (val2));
|
|
||||||
|
|
||||||
return value_contents_equal (val1, val2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: The following should be generic for any pointer */
|
/* FIXME: The following should be generic for any pointer */
|
||||||
static void
|
static void
|
||||||
vpush (struct vstack **pstack, struct varobj *var)
|
vpush (struct vstack **pstack, struct varobj *var)
|
||||||
|
@ -1678,33 +1753,9 @@ value_of_child (struct varobj *parent, int index)
|
||||||
|
|
||||||
value = (*parent->root->lang->value_of_child) (parent, 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))
|
|
||||||
{
|
|
||||||
/* If we fail to fetch the value of the child, return
|
|
||||||
NULL so that callers notice that we're leaving an
|
|
||||||
error message. */
|
|
||||||
if (!gdb_value_fetch_lazy (value))
|
|
||||||
value = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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
|
/* Is this variable editable? Use the variable's type to make
|
||||||
this determination. */
|
this determination. */
|
||||||
static int
|
static int
|
||||||
|
@ -1720,9 +1771,15 @@ my_value_of_variable (struct varobj *var)
|
||||||
return (*var->root->lang->value_of_variable) (var);
|
return (*var->root->lang->value_of_variable) (var);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is VAR something that can change? Depending on language,
|
/* Return non-zero if changes in value of VAR
|
||||||
some variable's values never change. For example,
|
must be detected and reported by -var-update.
|
||||||
struct and unions never change values. */
|
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
|
static int
|
||||||
type_changeable (struct varobj *var)
|
type_changeable (struct varobj *var)
|
||||||
{
|
{
|
||||||
|
@ -1898,24 +1955,12 @@ c_value_of_root (struct varobj **var_handle)
|
||||||
go on */
|
go on */
|
||||||
if (gdb_evaluate_expression (var->root->exp, &new_val))
|
if (gdb_evaluate_expression (var->root->exp, &new_val))
|
||||||
{
|
{
|
||||||
if (value_lazy (new_val))
|
var->error = 0;
|
||||||
{
|
release_value (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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
var->error = 1;
|
var->error = 1;
|
||||||
|
|
||||||
release_value (new_val);
|
|
||||||
return new_val;
|
return new_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2094,8 +2139,8 @@ c_value_of_variable (struct varobj *var)
|
||||||
struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
|
struct cleanup *old_chain = make_cleanup_ui_file_delete (stb);
|
||||||
char *thevalue;
|
char *thevalue;
|
||||||
|
|
||||||
if (value_lazy (var->value))
|
gdb_assert (type_changeable (var));
|
||||||
gdb_value_fetch_lazy (var->value);
|
gdb_assert (!value_lazy (var->value));
|
||||||
common_val_print (var->value, stb,
|
common_val_print (var->value, stb,
|
||||||
format_code[(int) var->format], 1, 0, 0);
|
format_code[(int) var->format], 1, 0, 0);
|
||||||
thevalue = ui_file_xstrdup (stb, &dummy);
|
thevalue = ui_file_xstrdup (stb, &dummy);
|
||||||
|
|
Loading…
Reference in New Issue