#include "vec.h"
#include "gdbthread.h"
#include "inferior.h"
+#include "ada-varobj.h"
+#include "ada-lang.h"
#if HAVE_PYTHON
#include "python/python.h"
static char *cppop (struct cpstack **pstack);
+static int update_type_if_necessary (struct varobj *var,
+ struct value *new_value);
+
static int install_new_value (struct varobj *var, struct value *value,
int initial);
#endif /* HAVE_PYTHON */
+static int default_value_is_changeable_p (struct varobj *var);
+
/* C implementation */
static int c_number_of_children (struct varobj *var);
static char *ada_value_of_variable (struct varobj *var,
enum varobj_display_formats format);
+static int ada_value_is_changeable_p (struct varobj *var);
+
+static int ada_value_has_mutated (struct varobj *var, struct value *new_val,
+ struct type *new_type);
+
/* The language specific vector */
struct language_specific
/* The current value of VAR. */
char *(*value_of_variable) (struct varobj * var,
enum varobj_display_formats format);
+
+ /* Return non-zero if changes in value of VAR must be detected and
+ reported by -var-update. Return zero if -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. */
+ int (*value_is_changeable_p) (struct varobj *var);
+
+ /* Return nonzero if the type of VAR has mutated.
+
+ VAR's value is still the varobj's previous value, while NEW_VALUE
+ is VAR's new value and NEW_TYPE is the var's new type. NEW_VALUE
+ may be NULL indicating that there is no value available (the varobj
+ may be out of scope, of may be the child of a null pointer, for
+ instance). NEW_TYPE, on the other hand, must never be NULL.
+
+ This function should also be able to assume that var's number of
+ children is set (not < 0).
+
+ Languages where types do not mutate can set this to NULL. */
+ int (*value_has_mutated) (struct varobj *var, struct value *new_value,
+ struct type *new_type);
};
/* Array of known source language routines. */
c_value_of_root,
c_value_of_child,
c_type_of_child,
- c_value_of_variable}
+ c_value_of_variable,
+ default_value_is_changeable_p,
+ NULL /* value_has_mutated */}
,
/* C */
{
c_value_of_root,
c_value_of_child,
c_type_of_child,
- c_value_of_variable}
+ c_value_of_variable,
+ default_value_is_changeable_p,
+ NULL /* value_has_mutated */}
,
/* C++ */
{
cplus_value_of_root,
cplus_value_of_child,
cplus_type_of_child,
- cplus_value_of_variable}
+ cplus_value_of_variable,
+ default_value_is_changeable_p,
+ NULL /* value_has_mutated */}
,
/* Java */
{
java_value_of_root,
java_value_of_child,
java_type_of_child,
- java_value_of_variable},
+ java_value_of_variable,
+ default_value_is_changeable_p,
+ NULL /* value_has_mutated */},
/* Ada */
{
vlang_ada,
ada_value_of_root,
ada_value_of_child,
ada_type_of_child,
- ada_value_of_variable}
+ ada_value_of_variable,
+ ada_value_is_changeable_p,
+ ada_value_has_mutated}
};
/* A little convenience enum for dealing with C++/Java. */
#ifdef HAVE_PYTHON
/* Helper function to install a Python environment suitable for
use during operations on VAR. */
-struct cleanup *
+static struct cleanup *
varobj_ensure_python_env (struct varobj *var)
{
return ensure_python_env (var->root->exp->gdbarch,
var->type = value_type (type_only_value);
}
- else
- var->type = value_type (value);
+ else
+ {
+ int real_type_found = 0;
- install_new_value (var, value, 1 /* Initial assignment */);
+ var->type = value_actual_type (value, 0, &real_type_found);
+ if (real_type_found)
+ value = value_cast (var->type, value);
+ }
/* Set language info */
lang = variable_language (var);
var->root->lang = &languages[lang];
+ install_new_value (var, value, 1 /* Initial assignment */);
+
/* Set ourselves as our root. */
var->root->rootvar = var;
static void
install_dynamic_child (struct varobj *var,
VEC (varobj_p) **changed,
+ VEC (varobj_p) **type_changed,
VEC (varobj_p) **new,
VEC (varobj_p) **unchanged,
int *cchanged,
{
varobj_p existing = VEC_index (varobj_p, var->children, index);
+ int type_updated = update_type_if_necessary (existing, value);
+ if (type_updated)
+ {
+ if (type_changed)
+ VEC_safe_push (varobj_p, *type_changed, existing);
+ }
if (install_new_value (existing, value, 0))
{
- if (changed)
+ if (!type_updated && changed)
VEC_safe_push (varobj_p, *changed, existing);
}
- else if (unchanged)
+ else if (!type_updated && unchanged)
VEC_safe_push (varobj_p, *unchanged, existing);
}
}
static int
update_dynamic_varobj_children (struct varobj *var,
VEC (varobj_p) **changed,
+ VEC (varobj_p) **type_changed,
VEC (varobj_p) **new,
VEC (varobj_p) **unchanged,
int *cchanged,
if (v == NULL)
gdbpy_print_stack ();
install_dynamic_child (var, can_mention ? changed : NULL,
+ can_mention ? type_changed : NULL,
can_mention ? new : NULL,
can_mention ? unchanged : NULL,
can_mention ? cchanged : NULL, i, name, v);
/* If we have a dynamic varobj, don't report -1 children.
So, try to fetch some children first. */
- update_dynamic_varobj_children (var, NULL, NULL, NULL, &dummy,
+ update_dynamic_varobj_children (var, NULL, NULL, NULL, NULL, &dummy,
0, 0, 0);
}
else
/* This, in theory, can result in the number of children changing without
frontend noticing. But well, calling -var-list-children on the same
varobj twice is not something a sane frontend would do. */
- update_dynamic_varobj_children (var, NULL, NULL, NULL, &children_changed,
- 0, 0, *to);
+ update_dynamic_varobj_children (var, NULL, NULL, NULL, NULL,
+ &children_changed, 0, 0, *to);
restrict_range (var->children, from, to);
return var->children;
}
#endif
}
+/* When using RTTI to determine variable type it may be changed in runtime when
+ the variable value is changed. This function checks whether type of varobj
+ VAR will change when a new value NEW_VALUE is assigned and if it is so
+ updates the type of VAR. */
+
+static int
+update_type_if_necessary (struct varobj *var, struct value *new_value)
+{
+ if (new_value)
+ {
+ struct value_print_options opts;
+
+ get_user_print_options (&opts);
+ if (opts.objectprint)
+ {
+ struct type *new_type;
+ char *curr_type_str, *new_type_str;
+
+ new_type = value_actual_type (new_value, 0, 0);
+ new_type_str = type_to_string (new_type);
+ curr_type_str = varobj_get_type (var);
+ if (strcmp (curr_type_str, new_type_str) != 0)
+ {
+ var->type = new_type;
+
+ /* This information may be not valid for a new type. */
+ varobj_delete (var, NULL, 1);
+ VEC_free (varobj_p, var->children);
+ var->num_children = -1;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
/* 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
#endif
}
+/* If NEW_VALUE is the new value of the given varobj (var), return
+ non-zero if var has mutated. In other words, if the type of
+ the new value is different from the type of the varobj's old
+ value.
+
+ NEW_VALUE may be NULL, if the varobj is now out of scope. */
+
+static int
+varobj_value_has_mutated (struct varobj *var, struct value *new_value,
+ struct type *new_type)
+{
+ /* If we haven't previously computed the number of children in var,
+ it does not matter from the front-end's perspective whether
+ the type has mutated or not. For all intents and purposes,
+ it has not mutated. */
+ if (var->num_children < 0)
+ return 0;
+
+ if (var->root->lang->value_has_mutated)
+ return var->root->lang->value_has_mutated (var, new_value, new_type);
+ else
+ return 0;
+}
+
/* 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
value_of_root variable dispose of the varobj if the type
has changed. */
new = value_of_root (varp, &type_changed);
+ if (update_type_if_necessary(*varp, new))
+ type_changed = 1;
r.varobj = *varp;
-
r.type_changed = type_changed;
if (install_new_value ((*varp), new, type_changed))
r.changed = 1;
/* Update this variable, unless it's a root, which is already
updated. */
if (!r.value_installed)
- {
+ {
+ struct type *new_type;
+
new = value_of_child (v->parent, v->index);
- if (install_new_value (v, new, 0 /* type not changed */))
+ if (update_type_if_necessary(v, new))
+ r.type_changed = 1;
+ if (new)
+ new_type = value_type (new);
+ else
+ new_type = v->root->lang->type_of_child (v->parent, v->index);
+
+ if (varobj_value_has_mutated (v, new, new_type))
+ {
+ /* The children are no longer valid; delete them now.
+ Report the fact that its type changed as well. */
+ varobj_delete (v, NULL, 1 /* only_children */);
+ v->num_children = -1;
+ v->to = -1;
+ v->from = -1;
+ v->type = new_type;
+ r.type_changed = 1;
+ }
+
+ if (install_new_value (v, new, r.type_changed))
{
r.changed = 1;
v->updated = 0;
invoked. */
if (v->pretty_printer)
{
- VEC (varobj_p) *changed = 0, *new = 0, *unchanged = 0;
+ VEC (varobj_p) *changed = 0, *type_changed = 0, *unchanged = 0;
+ VEC (varobj_p) *new = 0;
int i, children_changed = 0;
if (v->frozen)
it. */
if (!varobj_has_more (v, 0))
{
- update_dynamic_varobj_children (v, NULL, NULL, NULL,
+ update_dynamic_varobj_children (v, NULL, NULL, NULL, NULL,
&dummy, 0, 0, 0);
if (varobj_has_more (v, 0))
r.changed = 1;
/* If update_dynamic_varobj_children returns 0, then we have
a non-conforming pretty-printer, so we skip it. */
- if (update_dynamic_varobj_children (v, &changed, &new, &unchanged,
- &children_changed, 1,
+ if (update_dynamic_varobj_children (v, &changed, &type_changed, &new,
+ &unchanged, &children_changed, 1,
v->from, v->to))
{
if (children_changed || new)
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, type_changed) - 1; i >= 0; --i)
+ {
+ varobj_p tmp = VEC_index (varobj_p, type_changed, i);
+ varobj_update_result r = {0};
+
+ /* Type may change only if value was changed. */
+ r.varobj = tmp;
+ r.changed = 1;
+ r.type_changed = 1;
+ r.value_installed = 1;
+ VEC_safe_push (varobj_update_result, stack, &r);
+ }
for (i = VEC_length (varobj_p, changed) - 1; i >= 0; --i)
{
varobj_p tmp = VEC_index (varobj_p, changed, i);
if (r.changed || r.children_changed)
VEC_safe_push (varobj_update_result, result, &r);
- /* Free CHANGED and UNCHANGED, but not NEW, because NEW
- has been put into the result vector. */
+ /* Free CHANGED, TYPE_CHANGED and UNCHANGED, but not NEW,
+ because NEW has been put into the result vector. */
VEC_free (varobj_p, changed);
+ VEC_free (varobj_p, type_changed);
VEC_free (varobj_p, unchanged);
continue;
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);
+ child->type = value_actual_type (value, 0, NULL);
else
/* Otherwise, we must compute the type. */
child->type = (*child->root->lang->type_of_child) (child->parent,
*type_changed = 0;
}
- return (*var->root->lang->value_of_root) (var_handle);
+ {
+ struct value *value;
+
+ value = (*var->root->lang->value_of_root) (var_handle);
+ if (var->value == NULL || value == NULL)
+ {
+ /* For root varobj-s, a NULL value indicates a scoping issue.
+ So, nothing to do in terms of checking for mutations. */
+ }
+ else if (varobj_value_has_mutated (var, value, value_type (value)))
+ {
+ /* The type has mutated, so the children are no longer valid.
+ Just delete them, and tell our caller that the type has
+ changed. */
+ varobj_delete (var, NULL, 1 /* only_children */);
+ var->num_children = -1;
+ var->to = -1;
+ var->from = -1;
+ *type_changed = 1;
+ }
+ return value;
+ }
}
/* What is the ``struct value *'' for the INDEX'th child of PARENT? */
}
}
-/* 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++).
+/* Call VAR's value_is_changeable_p language-specific callback. */
- Return value of 0 means that gdb need not call value_fetch_lazy
- for the value of this variable object. */
static int
varobj_value_is_changeable_p (struct varobj *var)
{
- int r;
- struct type *type;
-
- if (CPLUS_FAKE_CHILD (var))
- return 0;
-
- type = get_value_type (var);
-
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- case TYPE_CODE_ARRAY:
- r = 0;
- break;
-
- default:
- r = 1;
- }
-
- return r;
+ return var->root->lang->value_is_changeable_p (var);
}
/* Return 1 if that varobj is floating, that is is always evaluated in the
to all types and dereferencing pointers to
structures.
+ If LOOKUP_ACTUAL_TYPE is set the enclosing type of the
+ value will be fetched and if it differs from static type
+ the value will be casted to it.
+
Both TYPE and *TYPE should be non-null. VALUE
can be null if we want to only translate type.
*VALUE can be null as well -- if the parent
static void
adjust_value_for_child_access (struct value **value,
struct type **type,
- int *was_ptr)
+ int *was_ptr,
+ int lookup_actual_type)
{
gdb_assert (type && *type);
/* The 'get_target_type' function calls check_typedef on
result, so we can immediately check type code. No
need to call check_typedef here. */
+
+ /* Access a real type of the value (if necessary and possible). */
+ if (value && *value && lookup_actual_type)
+ {
+ struct type *enclosing_type;
+ int real_type_found = 0;
+
+ enclosing_type = value_actual_type (*value, 1, &real_type_found);
+ if (real_type_found)
+ {
+ *type = enclosing_type;
+ *value = value_cast (enclosing_type, *value);
+ }
+ }
+}
+
+/* Implement the "value_is_changeable_p" varobj callback for most
+ languages. */
+
+static int
+default_value_is_changeable_p (struct varobj *var)
+{
+ int r;
+ struct type *type;
+
+ if (CPLUS_FAKE_CHILD (var))
+ return 0;
+
+ type = get_value_type (var);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ case TYPE_CODE_ARRAY:
+ r = 0;
+ break;
+
+ default:
+ r = 1;
+ }
+
+ return r;
}
/* C */
+
static int
c_number_of_children (struct varobj *var)
{
int children = 0;
struct type *target;
- adjust_value_for_child_access (NULL, &type, NULL);
+ adjust_value_for_child_access (NULL, &type, NULL, 0);
target = get_target_type (type);
switch (TYPE_CODE (type))
*cfull_expression = NULL;
parent_expression = varobj_get_path_expr (get_path_expr_parent (parent));
}
- adjust_value_for_child_access (&value, &type, &was_ptr);
+ adjust_value_for_child_access (&value, &type, &was_ptr, 0);
switch (TYPE_CODE (type))
{
static int
cplus_number_of_children (struct varobj *var)
{
+ struct value *value = NULL;
struct type *type;
int children, dont_know;
+ int lookup_actual_type = 0;
+ struct value_print_options opts;
dont_know = 1;
children = 0;
+ get_user_print_options (&opts);
+
if (!CPLUS_FAKE_CHILD (var))
{
type = get_value_type (var);
- adjust_value_for_child_access (NULL, &type, NULL);
+
+ /* It is necessary to access a real type (via RTTI). */
+ if (opts.objectprint)
+ {
+ value = var->value;
+ lookup_actual_type = (TYPE_CODE (var->type) == TYPE_CODE_REF
+ || TYPE_CODE (var->type) == TYPE_CODE_PTR);
+ }
+ adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
((TYPE_CODE (type)) == TYPE_CODE_UNION))
int kids[3];
type = get_value_type (var->parent);
- adjust_value_for_child_access (NULL, &type, NULL);
+
+ /* It is necessary to access a real type (via RTTI). */
+ if (opts.objectprint)
+ {
+ struct varobj *parent = var->parent;
+
+ value = parent->value;
+ lookup_actual_type = (TYPE_CODE (parent->type) == TYPE_CODE_REF
+ || TYPE_CODE (parent->type) == TYPE_CODE_PTR);
+ }
+ adjust_value_for_child_access (&value, &type, NULL, lookup_actual_type);
cplus_class_num_children (type, kids);
if (strcmp (var->name, "public") == 0)
struct value *value;
struct type *type;
int was_ptr;
+ int lookup_actual_type = 0;
char *parent_expression = NULL;
+ struct varobj *var;
+ struct value_print_options opts;
if (cname)
*cname = NULL;
if (cfull_expression)
*cfull_expression = NULL;
- if (CPLUS_FAKE_CHILD (parent))
- {
- value = parent->parent->value;
- type = get_value_type (parent->parent);
- if (cfull_expression)
- parent_expression
- = varobj_get_path_expr (get_path_expr_parent (parent->parent));
- }
- else
- {
- value = parent->value;
- type = get_value_type (parent);
- if (cfull_expression)
- parent_expression
- = varobj_get_path_expr (get_path_expr_parent (parent));
- }
+ get_user_print_options (&opts);
- adjust_value_for_child_access (&value, &type, &was_ptr);
+ var = (CPLUS_FAKE_CHILD (parent)) ? parent->parent : parent;
+ if (opts.objectprint)
+ lookup_actual_type = (TYPE_CODE (var->type) == TYPE_CODE_REF
+ || TYPE_CODE (var->type) == TYPE_CODE_PTR);
+ value = var->value;
+ type = get_value_type (var);
+ if (cfull_expression)
+ parent_expression = varobj_get_path_expr (get_path_expr_parent (var));
+
+ adjust_value_for_child_access (&value, &type, &was_ptr, lookup_actual_type);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
static int
ada_number_of_children (struct varobj *var)
{
- return c_number_of_children (var);
+ return ada_varobj_get_number_of_children (var->value, var->type);
}
static char *
static char *
ada_name_of_child (struct varobj *parent, int index)
{
- return c_name_of_child (parent, index);
+ return ada_varobj_get_name_of_child (parent->value, parent->type,
+ parent->name, index);
}
static char*
ada_path_expr_of_child (struct varobj *child)
{
- return c_path_expr_of_child (child);
+ struct varobj *parent = child->parent;
+ const char *parent_path_expr = varobj_get_path_expr (parent);
+
+ return ada_varobj_get_path_expr_of_child (parent->value,
+ parent->type,
+ parent->name,
+ parent_path_expr,
+ child->index);
}
static struct value *
static struct value *
ada_value_of_child (struct varobj *parent, int index)
{
- return c_value_of_child (parent, index);
+ return ada_varobj_get_value_of_child (parent->value, parent->type,
+ parent->name, index);
}
static struct type *
ada_type_of_child (struct varobj *parent, int index)
{
- return c_type_of_child (parent, index);
+ return ada_varobj_get_type_of_child (parent->value, parent->type,
+ index);
}
static char *
ada_value_of_variable (struct varobj *var, enum varobj_display_formats format)
{
- return c_value_of_variable (var, format);
+ struct value_print_options opts;
+
+ get_formatted_print_options (&opts, format_code[(int) format]);
+ opts.deref_ref = 0;
+ opts.raw = 1;
+
+ return ada_varobj_get_value_of_variable (var->value, var->type, &opts);
+}
+
+/* Implement the "value_is_changeable_p" routine for Ada. */
+
+static int
+ada_value_is_changeable_p (struct varobj *var)
+{
+ struct type *type = var->value ? value_type (var->value) : var->type;
+
+ if (ada_is_array_descriptor_type (type)
+ && TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+ {
+ /* This is in reality a pointer to an unconstrained array.
+ its value is changeable. */
+ return 1;
+ }
+
+ if (ada_is_string_type (type))
+ {
+ /* We display the contents of the string in the array's
+ "value" field. The contents can change, so consider
+ that the array is changeable. */
+ return 1;
+ }
+
+ return default_value_is_changeable_p (var);
+}
+
+/* Implement the "value_has_mutated" routine for Ada. */
+
+static int
+ada_value_has_mutated (struct varobj *var, struct value *new_val,
+ struct type *new_type)
+{
+ int i;
+ int from = -1;
+ int to = -1;
+
+ /* If the number of fields have changed, then for sure the type
+ has mutated. */
+ if (ada_varobj_get_number_of_children (new_val, new_type)
+ != var->num_children)
+ return 1;
+
+ /* If the number of fields have remained the same, then we need
+ to check the name of each field. If they remain the same,
+ then chances are the type hasn't mutated. This is technically
+ an incomplete test, as the child's type might have changed
+ despite the fact that the name remains the same. But we'll
+ handle this situation by saying that the child has mutated,
+ not this value.
+
+ If only part (or none!) of the children have been fetched,
+ then only check the ones we fetched. It does not matter
+ to the frontend whether a child that it has not fetched yet
+ has mutated or not. So just assume it hasn't. */
+
+ restrict_range (var->children, &from, &to);
+ for (i = from; i < to; i++)
+ if (strcmp (ada_varobj_get_name_of_child (new_val, new_type,
+ var->name, i),
+ VEC_index (varobj_p, var->children, i)->name) != 0)
+ return 1;
+
+ return 0;
}
/* Iterate all the existing _root_ VAROBJs and call the FUNC callback for them