/* 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, 2007
+ 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
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 <math.h>
+#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[] =
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. */
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;
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. */
/* 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. A NULL value
+ indicates there was an error getting this value.
+ 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? */
- int error;
-
/* The number of (immediate) children this variable has */
int num_children;
/* 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
-{
+ /* Was this variable updated via a varobj_set_value operation */
+ int updated;
- /* 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 */
-
-struct vstack
-{
- struct varobj *var;
- struct vstack *next;
+ /* Last print value. */
+ char *print_value;
};
struct cpstack
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);
static struct type *get_type (struct varobj *var);
-static struct type *get_type_deref (struct varobj *var);
+static struct type *get_value_type (struct varobj *var);
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);
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 */
};
/* 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,
\f
/* 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)
{
char *p;
enum varobj_languages lang;
+ 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 = 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
+ ``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 */
block = NULL;
if (fi != NULL)
- block = get_frame_block (fi);
+ block = get_frame_block (fi, 0);
p = expression;
innermost_block = NULL;
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;
}
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 = get_selected_frame (NULL);
+ 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))
+ if (!gdb_evaluate_expression (var->root->exp, &value))
{
- /* no error */
- release_value (var->value);
- if (VALUE_LAZY (var->value))
- gdb_value_fetch_lazy (var->value);
+ /* 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->value = evaluate_type (var->root->exp);
+ else
+ var->type = value_type (value);
- var->type = VALUE_TYPE (var->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
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
cv = cv->next;
if (cv == NULL)
- error ("Variable object not found");
+ error (_("Variable object not found"));
return cv->var;
}
}
if (mycount || (*cp != NULL))
- warning ("varobj_delete: assertion failed - mycount(=%d) <> 0",
+ warning (_("varobj_delete: assertion failed - mycount(=%d) <> 0"),
mycount);
}
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);
+
+ 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) = child;
+ *((*childlist) + i) = existing;
}
/* End of list is marked by a NULL pointer */
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 ();
/* 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)
{
{
int attributes = 0;
- if (variable_editable (var))
+ if (var->root->is_valid && variable_editable (var))
/* FIXME: define masks for attributes */
attributes |= 0x00000001; /* Editable */
{
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! */
struct value *value;
int saved_input_radix = input_radix;
- if (variable_editable (var) && !var->error)
+ if (var->value != NULL && variable_editable (var))
{
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. */
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;
}
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;
+
+ /* 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))
+ {
+ /* 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;
+ }
+ }
+
+ /* 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)
+ 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)
+ {
+ xfree (var->print_value);
+ var->print_value = value_get_print_value (value, var->format);
+ 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)
+ {
+ xfree (var->print_value);
+ var->print_value = value_get_print_value (value, var->format);
+ 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);
+
+ gdb_assert (var->print_value != NULL && print_value != NULL);
+ 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
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...
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)
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;
+ /* sanity check: have we been passed a pointer? */
+ gdb_assert (changelist);
- /* Only root variables can be updated... */
- if ((*varp)->root->rootvar != *varp)
- /* Not a root var */
- return -1;
+ if (!is_root_p (*varp))
+ error (_("Only root variables can be updated"));
+
+ if (!(*varp)->root->is_valid)
+ return INVALID;
/* Save the selected stack frame, since we will need to change it
- in order to evaluate expressions. */
- old_fi = selected_frame;
+ 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. */
+ has changed. */
type_changed = 1;
new = value_of_root (varp, &type_changed);
- if (new == NULL)
- {
- (*varp)->error = 1;
- return -1;
- }
- /* Initialize a stack for temporary results */
- vpush (&result, NULL);
+ /* 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. */
+ them note that it's changed. */
if (type_changed)
+ VEC_safe_push (varobj_p, result, *varp);
+
+ if (install_new_value ((*varp), new, type_changed))
{
- vpush (&result, *varp);
- 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 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))
+
+ if (new == NULL)
{
- vpush (&result, *varp);
- changed++;
- /* error2 replaces var->error since this new value
- WILL replace the old one. */
- (*varp)->error = error2;
+ /* This means the varobj itself is out of scope.
+ Report it. */
+ VEC_free (varobj_p, result);
+ return NOT_IN_SCOPE;
}
- /* 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, stack, *varp);
- /* Push the root's children */
- if ((*varp)->children != NULL)
+ /* Walk through the children, reconstructing them all. */
+ while (!VEC_empty (varobj_p, stack))
{
- struct varobj_child *c;
- for (c = (*varp)->children; c != NULL; c = c->next)
- vpush (&stack, c->child);
- }
+ v = VEC_pop (varobj_p, stack);
- /* Walk through the children, reconstructing them all. */
- v = vpop (&stack);
- while (v != NULL)
- {
- /* Push any children */
- if (v->children != NULL)
+ /* 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)
{
- struct varobj_child *c;
- for (c = v->children; c != NULL; c = c->next)
- vpush (&stack, c->child);
+ 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);
}
- /* Update this variable */
- new = value_of_child (v->parent, v->index);
- if (type_changeable (v) && !my_value_equal (v->value, new, &error2))
- {
- /* Note that it's changed */
- vpush (&result, v);
- changed++;
+ /* 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;
+ }
}
- /* 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);
}
- /* Alloc (changed + 1) list entries */
- /* FIXME: add a cleanup for the allocated list(s)
- because one day the select_frame called below can longjump */
+ /* Alloc (changed + 1) list entries. */
+ 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;
+ cv = *changelist;
- /* Copy from result stack to list */
- vleft = changed;
- *cv = vpop (&result);
- while ((*cv != NULL) && (vleft > 0))
+ for (i = 0; i < changed; ++i)
{
- vleft--;
- cv++;
- *cv = vpop (&result);
+ *cv = VEC_index (varobj_p, result, i);
+ gdb_assert (*cv != NULL);
+ ++cv;
}
- if (vleft)
- warning ("varobj_update: assertion failed - vleft <> 0");
+ *cv = 0;
- if (changed > 1)
- {
- /* Now we revert the order. */
- for (i = 0; i < changed; i++)
- *(*changelist + i) = *(templist + changed - 1 - i);
- *(*changelist + changed) = NULL;
- }
-
- /* Restore selected frame */
- select_frame (old_fi, -1);
+ VEC_free (varobj_p, stack);
+ VEC_free (varobj_p, result);
if (type_changed)
- return -2;
+ return TYPE_CHANGED;
else
return changed;
}
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)
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)
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));
*(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)
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)
}
-/* 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);
-
- /* Note the type of this child */
- child->type = type_of_child (child);
-
- 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;
+ /* 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
- prev->next = vc->next;
+ /* Otherwise, we must compute the type. */
+ child->type = (*child->root->lang->type_of_child) (child->parent,
+ child->index);
+ install_new_value (child, value, 1);
+ return child;
}
\f
var->index = -1;
var->type = NULL;
var->value = NULL;
- var->error = 0;
var->num_children = -1;
var->parent = NULL;
var->children = NULL;
var->format = 0;
var->root = NULL;
+ var->updated = 0;
+ var->print_value = NULL;
return var;
}
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;
+ var->root->is_valid = 1;
return var;
}
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);
}
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. */
+/* Return the type of the value that's stored in VAR,
+ or that would have being stored there if the
+ value were accessible.
+
+ This differs from VAR->type in that VAR->type is always
+ the true type of the expession in the source language.
+ The return value of this function is the type we're
+ actually storing in varobj, and using for displaying
+ the values and for comparing previous and new values.
+
+ For example, top-level references are always stripped. */
static struct type *
-get_type_deref (struct varobj *var)
+get_value_type (struct varobj *var)
{
struct type *type;
- type = get_type (var);
+ if (var->value)
+ type = value_type (var->value);
+ else
+ type = var->type;
+
+ type = check_typedef (type);
- if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_PTR
- || TYPE_CODE (type) == TYPE_CODE_REF))
+ if (TYPE_CODE (type) == TYPE_CODE_REF)
type = get_target_type (type);
+ type = check_typedef (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;
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)
/* 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)
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
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 *
+value_get_print_value (struct value *value, enum varobj_display_formats format)
+{
+ long dummy;
+ struct ui_file *stb;
+ struct cleanup *old_chain;
+ char *thevalue;
+
+ if (value == NULL)
+ return NULL;
+
+ stb = mem_fileopen ();
+ old_chain = make_cleanup_ui_file_delete (stb);
+
+ common_val_print (value, stb, format_code[(int) format], 1, 0, 0);
+ thevalue = ui_file_xstrdup (stb, &dummy);
+
+ do_cleanups (old_chain);
+ return thevalue;
}
-/* Is VAR something that can change? Depending on language,
- some variable's values never change. For example,
- struct and unions never change values. */
+/* 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;
if (CPLUS_FAKE_CHILD (var))
return 0;
- type = get_type (var);
+ type = get_value_type (var);
switch (TYPE_CODE (type))
{
return r;
}
+/* Given the value and the type of a variable object,
+ adjust the value and type to those necessary
+ for getting children of the variable object.
+ This includes dereferencing top-level references
+ to all types and dereferencing pointers to
+ structures.
+
+ 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
+ value is not known. */
+static void
+adjust_value_for_child_access (struct value **value,
+ struct type **type)
+{
+ gdb_assert (type && *type);
+
+ *type = check_typedef (*type);
+
+ /* The type of value stored in varobj, that is passed
+ to us, is already supposed to be
+ reference-stripped. */
+
+ gdb_assert (TYPE_CODE (*type) != TYPE_CODE_REF);
+
+ /* Pointers to structures are treated just like
+ structures when accessing children. Don't
+ dererences pointers to other types. */
+ 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 && *value)
+ gdb_value_ind (*value, value);
+ *type = target_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. */
+}
+
/* C */
static int
c_number_of_children (struct varobj *var)
{
- struct type *type;
+ struct type *type = get_value_type (var);
+ int children = 0;
struct type *target;
- int children;
- type = get_type (var);
+ adjust_value_for_child_access (NULL, &type);
target = get_target_type (type);
- children = 0;
switch (TYPE_CODE (type))
{
&& 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:
break;
case TYPE_CODE_PTR:
- /* This is where things get compilcated. 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.
- We also don't dereference void* as we don't know what to show.
+ /* The type here is a pointer to non-struct. Typically, pointers
+ have one child, except for function ptrs, which have no children,
+ and except for 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
properly identify it: char* has TYPE_CODE == TYPE_CODE_INT and
TYPE_NAME == "char" */
-
- switch (TYPE_CODE (target))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- children = TYPE_NFIELDS (target);
- break;
-
- case TYPE_CODE_FUNC:
- case TYPE_CODE_VOID:
- children = 0;
- break;
-
- default:
- children = 1;
- }
+ if (TYPE_CODE (target) == TYPE_CODE_FUNC
+ || TYPE_CODE (target) == TYPE_CODE_VOID)
+ children = 0;
+ else
+ children = 1;
break;
default:
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_value_type (parent);
+
+ if (cname)
+ *cname = NULL;
+ if (cvalue)
+ *cvalue = NULL;
+ if (ctype)
+ *ctype = NULL;
+
+ adjust_value_for_child_access (&value, &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));
- break;
+ if (cname)
+ {
+ char *string = TYPE_FIELD_NAME (type, index);
+ *cname = savestring (string, strlen (string));
+ }
- case TYPE_CODE_PTR:
- switch (TYPE_CODE (target))
+ if (cvalue && value)
{
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- string = TYPE_FIELD_NAME (target, index);
- name = savestring (string, strlen (string));
- break;
-
- default:
- name =
- (char *) xmalloc ((strlen (parent->name) + 2) * sizeof (char));
- sprintf (name, "*%s", parent->name);
- break;
+ /* 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:
+ if (cname)
+ *cname = xstrprintf ("*%s", parent->name);
+
+ if (cvalue && value)
+ gdb_value_ind (value, cvalue);
+
+ /* Don't use get_target_type because it calls
+ check_typedef and here, we want to show the true
+ declared type of the variable. */
+ if (ctype)
+ *ctype = TYPE_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;
/* Determine whether the variable is still around. */
- if (var->root->valid_block == NULL)
+ if (var->root->valid_block == NULL || var->root->use_selected_frame)
within_scope = 1;
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;
+ else
+ select_frame (fi);
+ }
}
if (within_scope)
{
/* We need to catch errors here, because if evaluate
- expression fails we just want to make val->error = 1 and
- 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;
- }
- }
- else
- var->error = 1;
-
- release_value (new_val);
+ expression fails we want to just return NULL. */
+ gdb_evaluate_expression (var->root->exp, &new_val);
return new_val;
}
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:
- gdb_value_struct_elt (NULL, &value, &temp, NULL, name, NULL, "vstructure");
- break;
-
- case TYPE_CODE_PTR:
- switch (TYPE_CODE (target))
- {
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- gdb_value_struct_elt (NULL, &value, &temp, NULL, name, NULL, "vstructure");
- break;
-
- default:
- gdb_value_ind (temp, &value);
- break;
- }
- break;
-
- default:
- break;
- }
- }
-
- if (value != NULL)
- release_value (value);
+ struct value *value = NULL;
+ c_describe_child (parent, index, NULL, &value, NULL);
return value;
}
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;
}
static int
c_variable_editable (struct varobj *var)
{
- switch (TYPE_CODE (get_type (var)))
+ switch (TYPE_CODE (get_value_type (var)))
{
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
case TYPE_CODE_ARRAY:
case TYPE_CODE_FUNC:
- case TYPE_CODE_MEMBER:
case TYPE_CODE_METHOD:
return 0;
break;
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:
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; */
}
}
\f
if (!CPLUS_FAKE_CHILD (var))
{
- type = get_type_deref (var);
+ type = get_value_type (var);
+ adjust_value_for_child_access (NULL, &type);
if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
((TYPE_CODE (type)) == TYPE_CODE_UNION))
{
int kids[3];
- type = get_type_deref (var->parent);
+ type = get_value_type (var->parent);
+ adjust_value_for_child_access (NULL, &type);
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];
return c_name_of_variable (parent);
}
-static char *
-cplus_name_of_child (struct varobj *parent, int index)
+enum accessibility { private_field, protected_field, public_field };
+
+/* Check if field INDEX of TYPE has the specified accessibility.
+ Return 0 if so and 1 otherwise. */
+static int
+match_accessibility (struct type *type, int index, enum accessibility acc)
{
- char *name;
+ if (acc == private_field && TYPE_FIELD_PRIVATE (type, index))
+ return 1;
+ else if (acc == protected_field && TYPE_FIELD_PROTECTED (type, index))
+ return 1;
+ else if (acc == public_field && !TYPE_FIELD_PRIVATE (type, index)
+ && !TYPE_FIELD_PROTECTED (type, index))
+ return 1;
+ else
+ return 0;
+}
+
+static void
+cplus_describe_child (struct varobj *parent, int index,
+ char **cname, struct value **cvalue, struct type **ctype)
+{
+ char *name = 0;
+ struct value *value;
struct type *type;
- int children[3];
+
+ if (cname)
+ *cname = NULL;
+ if (cvalue)
+ *cvalue = NULL;
+ if (ctype)
+ *ctype = NULL;
+
if (CPLUS_FAKE_CHILD (parent))
{
- /* Looking for children of public, private, or protected. */
- type = get_type_deref (parent->parent);
+ value = parent->parent->value;
+ type = get_value_type (parent->parent);
}
else
- type = get_type_deref (parent);
-
- name = NULL;
- switch (TYPE_CODE (type))
{
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- cplus_class_num_children (type, children);
+ value = parent->value;
+ type = get_value_type (parent);
+ }
+
+ adjust_value_for_child_access (&value, &type);
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
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);
+ enum accessibility acc = public_field;
+ if (strcmp (parent->name, "private") == 0)
+ acc = private_field;
+ else if (strcmp (parent->name, "protected") == 0)
+ acc = protected_field;
+
+ while (index >= 0)
+ {
+ if (TYPE_VPTR_BASETYPE (type) == type
+ && type_index == TYPE_VPTR_FIELDNO (type))
+ ; /* ignore vptr */
+ else if (match_accessibility (type, type_index, acc))
+ --index;
+ ++type_index;
+ }
+ --type_index;
+
+ if (cname)
+ *cname = xstrdup (TYPE_FIELD_NAME (type, type_index));
+
+ if (cvalue && value)
+ *cvalue = value_struct_element_index (value, type_index);
+
+ if (ctype)
+ *ctype = TYPE_FIELD_TYPE (type, type_index);
}
else if (index < TYPE_N_BASECLASSES (type))
- name = TYPE_FIELD_NAME (type, index);
+ {
+ /* This is a baseclass. */
+ if (cname)
+ *cname = xstrdup (TYPE_FIELD_NAME (type, index));
+
+ if (cvalue && value)
+ {
+ *cvalue = value_cast (TYPE_FIELD_TYPE (type, index), value);
+ }
+
+ if (ctype)
+ {
+ *ctype = TYPE_FIELD_TYPE (type, index);
+ }
+ }
else
{
+ char *access = 0;
+ 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)
+ access = "public";
+ else if (children[v_private] > 0)
+ access = "private";
+ else
+ access = "protected";
+ break;
case 1:
- if (children[v_private] != 0)
+ if (children[v_public] > 0)
{
- name = "private";
- break;
+ if (children[v_private] > 0)
+ access = "private";
+ else
+ access = "protected";
}
+ else if (children[v_private] > 0)
+ access = "protected";
+ break;
case 2:
- if (children[v_protected] != 0)
- {
- name = "protected";
- break;
- }
+ /* Must be protected */
+ access = "protected";
+ break;
default:
/* error! */
break;
}
- }
- break;
+
+ if (cname)
+ *cname = xstrdup (access);
- default:
- break;
+ /* Value and type are null here. */
+ }
}
-
- if (name == NULL)
- return c_name_of_child (parent, index);
else
{
- if (name != NULL)
- name = savestring (name, strlen (name));
- }
+ c_describe_child (parent, index, cname, cvalue, ctype);
+ }
+}
+static char *
+cplus_name_of_child (struct varobj *parent, int index)
+{
+ char *name = NULL;
+ cplus_describe_child (parent, index, &name, NULL, NULL);
return name;
}
static struct value *
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);
- else
- 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))
- {
- struct value *temp = parent->parent->value;
-
- gdb_value_struct_elt (NULL, &value, &temp, NULL, name, NULL,
- "cplus_structure");
- if (value != NULL)
- release_value (value);
- }
- else if (index >= TYPE_N_BASECLASSES (type))
- {
- /* public, private, or protected */
- return NULL;
- }
- else
- {
- /* Baseclass */
- if (parent->value != NULL)
- {
- struct value *temp;
-
- if (TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_PTR
- || TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_REF)
- {
- if (!gdb_value_ind (parent->value, &temp))
- return NULL;
- }
- else
- temp = parent->value;
-
- value = value_cast (TYPE_FIELD_TYPE (type, index), temp);
- release_value (value);
- }
- }
- }
-
- if (value == NULL)
- return c_value_of_child (parent, index);
-
+ struct value *value = NULL;
+ cplus_describe_child (parent, index, NULL, &value, NULL);
return value;
}
static struct type *
cplus_type_of_child (struct varobj *parent, int index)
{
- struct type *type, *t;
-
- 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))
- {
- /* special */
- return NULL;
- }
- else
- {
- /* Baseclass */
- type = TYPE_FIELD_TYPE (t, index);
- }
- break;
-
- default:
- break;
- }
-
- if (type == NULL)
- return c_type_of_child (parent, index);
-
+ struct type *type = NULL;
+ cplus_describe_child (parent, index, NULL, NULL, &type);
return type;
}
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);
+}
+
+/* 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;
}