aboutsummaryrefslogtreecommitdiff
path: root/gdb/varobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/varobj.c')
-rw-r--r--gdb/varobj.c2421
1 files changed, 2421 insertions, 0 deletions
diff --git a/gdb/varobj.c b/gdb/varobj.c
new file mode 100644
index 0000000..f0740c6
--- /dev/null
+++ b/gdb/varobj.c
@@ -0,0 +1,2421 @@
+/* Implementation of the GDB variable objects API.
+ Copyright 1999, 2000 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ 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. */
+
+#include "defs.h"
+#include "value.h"
+#include "expression.h"
+#include "frame.h"
+#include "valprint.h"
+#include "language.h"
+#include "wrapper.h"
+#include "gdbcmd.h"
+#include <math.h>
+
+#include "varobj.h"
+
+/* Non-zero if we want to see trace of varobj level stuff. */
+
+int varobjdebug = 0;
+
+/* String representations of gdb's format codes */
+char *varobj_format_string[] =
+{"natural", "binary", "decimal", "hexadecimal", "octal"};
+
+/* String representations of gdb's known languages */
+char *varobj_language_string[] =
+{"unknown", "C", "C++", "Java"};
+
+/* Data structures */
+
+/* Every root variable has one of these structures saved in its
+ varobj. Members which must be free'd are noted. */
+struct varobj_root
+ {
+
+ /* Alloc'd expression for this parent. */
+ struct expression *exp;
+
+ /* Block for which this expression is valid */
+ struct block *valid_block;
+
+ /* The frame for this expression */
+ CORE_ADDR frame;
+
+ /* Language info for this variable and its children */
+ struct language_specific *lang;
+
+ /* The varobj for this root node. */
+ struct varobj *rootvar;
+
+ /* Next root variable */
+ struct varobj_root *next;
+ };
+
+/* 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. */
+struct varobj
+ {
+
+ /* Alloc'd name of the variable for this object.. If this variable is a
+ child, then this name will be the child's source name.
+ (bar, not foo.bar) */
+ /* NOTE: This is the "expression" */
+ char *name;
+
+ /* The alloc'd name for this variable's object. This is here for
+ convenience when constructing this object's children. */
+ char *obj_name;
+
+ /* Index of this variable in its parent or -1 */
+ int index;
+
+ /* The type of this variable. This may NEVER be NULL. */
+ struct type *type;
+
+ /* The value of this expression or subexpression. This may be NULL. */
+ value_ptr 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;
+
+ /* Description of the root variable. Points to root variable for children. */
+ struct varobj_root *root;
+
+ /* The format of the output for this object */
+ enum varobj_display_formats format;
+ };
+
+/* Every variable keeps a linked list of its children, described
+ by the following structure. */
+/* FIXME: Deprecated. All should use vlist instead */
+
+struct varobj_child
+ {
+
+ /* Pointer to the child's data */
+ struct varobj *child;
+
+ /* Pointer to the next child */
+ struct varobj_child *next;
+ };
+
+/* A stack of varobjs */
+/* FIXME: Deprecated. All should use vlist instead */
+
+struct vstack
+ {
+ struct varobj *var;
+ struct vstack *next;
+ };
+
+struct cpstack
+ {
+ char *name;
+ struct cpstack *next;
+ };
+
+/* A list of varobjs */
+
+struct vlist
+ {
+ struct varobj *var;
+ struct vlist *next;
+ };
+
+/* Private function prototypes */
+
+/* Helper functions for the above subcommands. */
+
+static int delete_variable PARAMS ((struct cpstack **, struct varobj *, int));
+
+static void delete_variable_1 PARAMS ((struct cpstack **, int *,
+ struct varobj *, int, int));
+
+static int install_variable PARAMS ((struct varobj *));
+
+static void uninstall_variable PARAMS ((struct varobj *));
+
+static struct varobj *child_exists PARAMS ((struct varobj *, char *));
+
+static struct varobj *create_child PARAMS ((struct varobj *, int, char *));
+
+static void save_child_in_parent PARAMS ((struct varobj *, struct varobj *));
+
+static void remove_child_from_parent PARAMS ((struct varobj *, struct varobj *));
+
+/* Utility routines */
+
+static struct varobj *new_variable PARAMS ((void));
+
+static struct varobj *new_root_variable PARAMS ((void));
+
+static void free_variable PARAMS ((struct varobj * var));
+
+static struct type *get_type PARAMS ((struct varobj * var));
+
+static struct type *get_type_deref PARAMS ((struct varobj * var));
+
+static struct type *get_target_type PARAMS ((struct type *));
+
+static enum varobj_display_formats variable_default_display PARAMS ((struct varobj *));
+
+static int my_value_equal PARAMS ((value_ptr, value_ptr, int *));
+
+static void vpush PARAMS ((struct vstack ** pstack, struct varobj * var));
+
+static struct varobj *vpop PARAMS ((struct vstack ** pstack));
+
+static void cppush PARAMS ((struct cpstack ** pstack, char *name));
+
+static char *cppop PARAMS ((struct cpstack ** pstack));
+
+/* Language-specific routines. */
+
+static enum varobj_languages variable_language PARAMS ((struct varobj * var));
+
+static int number_of_children PARAMS ((struct varobj *));
+
+static char *name_of_variable PARAMS ((struct varobj *));
+
+static char *name_of_child PARAMS ((struct varobj *, int));
+
+static value_ptr value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *type_of_child PARAMS ((struct varobj * var));
+
+static int variable_editable PARAMS ((struct varobj * var));
+
+static char *my_value_of_variable PARAMS ((struct varobj * var));
+
+static int type_changeable PARAMS ((struct varobj * var));
+
+/* C implementation */
+
+static int c_number_of_children PARAMS ((struct varobj * var));
+
+static char *c_name_of_variable PARAMS ((struct varobj * parent));
+
+static char *c_name_of_child PARAMS ((struct varobj * parent, int index));
+
+static value_ptr c_value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr c_value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *c_type_of_child PARAMS ((struct varobj * parent, int index));
+
+static int c_variable_editable PARAMS ((struct varobj * var));
+
+static char *c_value_of_variable PARAMS ((struct varobj * var));
+
+/* C++ implementation */
+
+static int cplus_number_of_children PARAMS ((struct varobj * var));
+
+static void cplus_class_num_children PARAMS ((struct type * type, int children[3]));
+
+static char *cplus_name_of_variable PARAMS ((struct varobj * parent));
+
+static char *cplus_name_of_child PARAMS ((struct varobj * parent, int index));
+
+static value_ptr cplus_value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr cplus_value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *cplus_type_of_child PARAMS ((struct varobj * parent, int index));
+
+static int cplus_variable_editable PARAMS ((struct varobj * var));
+
+static char *cplus_value_of_variable PARAMS ((struct varobj * var));
+
+/* Java implementation */
+
+static int java_number_of_children PARAMS ((struct varobj * var));
+
+static char *java_name_of_variable PARAMS ((struct varobj * parent));
+
+static char *java_name_of_child PARAMS ((struct varobj * parent, int index));
+
+static value_ptr java_value_of_root PARAMS ((struct varobj * var));
+
+static value_ptr java_value_of_child PARAMS ((struct varobj * parent, int index));
+
+static struct type *java_type_of_child PARAMS ((struct varobj * parent, int index));
+
+static int java_variable_editable PARAMS ((struct varobj * var));
+
+static char *java_value_of_variable PARAMS ((struct varobj * var));
+
+/* The language specific vector */
+
+struct language_specific
+ {
+
+ /* The language of this variable */
+ enum varobj_languages language;
+
+ /* The number of children of PARENT. */
+ int (*number_of_children) PARAMS ((struct varobj * parent));
+
+ /* The name (expression) of a root varobj. */
+ char *(*name_of_variable) PARAMS ((struct varobj * parent));
+
+ /* The name of the INDEX'th child of PARENT. */
+ char *(*name_of_child) PARAMS ((struct varobj * parent, int index));
+
+ /* The value_ptr of the root variable ROOT. */
+ value_ptr (*value_of_root) PARAMS ((struct varobj * root));
+
+ /* The value_ptr of the INDEX'th child of PARENT. */
+ value_ptr (*value_of_child) PARAMS ((struct varobj * parent, int index));
+
+ /* The type of the INDEX'th child of PARENT. */
+ struct type *(*type_of_child) PARAMS ((struct varobj * parent, int index));
+
+ /* Is VAR editable? */
+ int (*variable_editable) PARAMS ((struct varobj * var));
+
+ /* The current value of VAR. */
+ char *(*value_of_variable) PARAMS ((struct varobj * var));
+ };
+
+/* Array of known source language routines. */
+static struct language_specific
+ languages[vlang_end][sizeof (struct language_specific)] =
+{
+ /* Unknown (try treating as C */
+ {
+ vlang_unknown,
+ c_number_of_children,
+ c_name_of_variable,
+ c_name_of_child,
+ c_value_of_root,
+ c_value_of_child,
+ c_type_of_child,
+ c_variable_editable,
+ c_value_of_variable
+ }
+ ,
+ /* C */
+ {
+ vlang_c,
+ c_number_of_children,
+ c_name_of_variable,
+ c_name_of_child,
+ c_value_of_root,
+ c_value_of_child,
+ c_type_of_child,
+ c_variable_editable,
+ c_value_of_variable
+ }
+ ,
+ /* C++ */
+ {
+ vlang_cplus,
+ cplus_number_of_children,
+ cplus_name_of_variable,
+ cplus_name_of_child,
+ cplus_value_of_root,
+ cplus_value_of_child,
+ cplus_type_of_child,
+ cplus_variable_editable,
+ cplus_value_of_variable
+ }
+ ,
+ /* Java */
+ {
+ vlang_java,
+ java_number_of_children,
+ java_name_of_variable,
+ java_name_of_child,
+ java_value_of_root,
+ java_value_of_child,
+ java_type_of_child,
+ java_variable_editable,
+ java_value_of_variable
+ }
+};
+
+/* A little convenience enum for dealing with C++/Java */
+enum vsections
+ {
+ v_public = 0, v_private, v_protected
+ };
+
+/* Private data */
+
+/* Mappings of varobj_display_formats enums to gdb's format codes */
+static int format_code[] =
+{0, 't', 'd', 'x', 'o'};
+
+/* Header of the list of root variable objects */
+static struct varobj_root *rootlist;
+static int rootcount = 0; /* number of root varobjs in the list */
+
+/* Prime number indicating the number of buckets in the hash table */
+/* A prime large enough to avoid too many colisions */
+#define VAROBJ_TABLE_SIZE 227
+
+/* Pointer to the varobj hash table (built at run time) */
+static struct vlist **varobj_table;
+
+#if defined(FREEIF)
+#undef FREEIF
+#endif
+#define FREEIF(x) if (x != NULL) free((char *) (x))
+
+/* Is the variable X one of our "fake" children? */
+#define CPLUS_FAKE_CHILD(x) \
+((x) != NULL && (x)->type == NULL && (x)->value == NULL)
+
+
+/* API Implementation */
+
+/* Creates a varobj (not its children) */
+
+struct varobj *
+varobj_create (char *objname,
+ char *expression, CORE_ADDR frame)
+{
+ struct varobj *var;
+ struct frame_info *fi, *old_fi;
+ struct block *block;
+ struct cleanup *old_chain;
+
+ /* Fill out a varobj structure for the (root) variable being constructed. */
+ var = new_root_variable ();
+ old_chain = make_cleanup ((make_cleanup_func) free_variable, var);
+
+ if (expression != NULL)
+ {
+ char *p;
+ enum varobj_languages lang;
+
+ /* Parse and evaluate the expression, filling in as much
+ of the variable's data as possible */
+
+ /* Allow creator to specify context of variable */
+ if (frame == (CORE_ADDR) -1)
+ fi = selected_frame;
+ else
+ fi = find_frame_addr_in_frame_chain (frame);
+
+ block = NULL;
+ if (fi != NULL)
+ block = get_frame_block (fi);
+
+ p = expression;
+ innermost_block = NULL;
+ /* Callee may longjump */
+ var->root->exp = parse_exp_1 (&p, block, 0);
+
+ /* Don't allow variables to be created for types. */
+ 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.");
+ return NULL;
+ }
+
+ var->format = variable_default_display (var);
+ var->root->valid_block = innermost_block;
+ var->name = savestring (expression, strlen (expression));
+
+ /* When the frame is different from the current frame,
+ we must select the appropriate frame before parsing
+ the expression, otherwise the value will not be current.
+ 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);
+ }
+
+ /* We definitively need to catch errors here.
+ If evaluate_expression succeeds we got the value we wanted.
+ But if it fails, we still go on with a call to evaluate_type() */
+ if (gdb_evaluate_expression (var->root->exp, &var->value))
+ {
+ /* no error */
+ release_value (var->value);
+ if (VALUE_LAZY (var->value))
+ gdb_value_fetch_lazy (var->value);
+ }
+ else
+ var->value = evaluate_type (var->root->exp);
+
+ var->type = VALUE_TYPE (var->value);
+
+ /* Set language info */
+ lang = variable_language (var);
+ 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);
+ }
+
+ if (var != NULL)
+ {
+ var->obj_name = savestring (objname, strlen (objname));
+
+ /* If a varobj name is duplicated, the install will fail so
+ we must clenup */
+ if (!install_variable (var))
+ {
+ do_cleanups (old_chain);
+ return NULL;
+ }
+ }
+
+ discard_cleanups (old_chain);
+ return var;
+}
+
+/* Generates an unique name that can be used for a varobj */
+
+char *
+varobj_gen_name (void)
+{
+ static int id = 0;
+ char obj_name[31];
+
+ /* generate a name for this object */
+ id++;
+ sprintf (obj_name, "var%d", id);
+
+ return xstrdup (obj_name);
+}
+
+/* Given an "objname", returns the pointer to the corresponding varobj
+ or NULL if not found */
+
+struct varobj *
+varobj_get_handle (char *objname)
+{
+ struct vlist *cv;
+ const char *chp;
+ unsigned int index = 0;
+ unsigned int i = 1;
+
+ for (chp = objname; *chp; chp++)
+ {
+ index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+ }
+
+ cv = *(varobj_table + index);
+ while ((cv != NULL) && (strcmp (cv->var->obj_name, objname) != 0))
+ cv = cv->next;
+
+ if (cv == NULL)
+ error ("Variable object not found");
+
+ return cv->var;
+}
+
+/* Given the handle, return the name of the object */
+
+char *
+varobj_get_objname (struct varobj *var)
+{
+ return var->obj_name;
+}
+
+/* Given the handle, return the expression represented by the object */
+
+char *
+varobj_get_expression (struct varobj *var)
+{
+ return name_of_variable (var);
+}
+
+/* Deletes a varobj and all its children if only_children == 0,
+ otherwise deletes only the children; returns a malloc'ed list of all the
+ (malloc'ed) names of the variables that have been deleted (NULL terminated) */
+
+int
+varobj_delete (struct varobj *var, char ***dellist, int only_children)
+{
+ int delcount;
+ int mycount;
+ struct cpstack *result = NULL;
+ char **cp;
+
+ /* Initialize a stack for temporary results */
+ cppush (&result, NULL);
+
+ if (only_children)
+ /* Delete only the variable children */
+ delcount = delete_variable (&result, var, 1 /* only the children */ );
+ else
+ /* Delete the variable and all its children */
+ delcount = delete_variable (&result, var, 0 /* parent+children */ );
+
+ /* We may have been asked to return a list of what has been deleted */
+ if (dellist != NULL)
+ {
+ *dellist = xmalloc ((delcount + 1) * sizeof (char *));
+
+ cp = *dellist;
+ mycount = delcount;
+ *cp = cppop (&result);
+ while ((*cp != NULL) && (mycount > 0))
+ {
+ mycount--;
+ cp++;
+ *cp = cppop (&result);
+ }
+
+ if (mycount || (*cp != NULL))
+ warning ("varobj_delete: assertion failed - mycount(=%d) <> 0", mycount);
+ }
+
+ return delcount;
+}
+
+/* Set/Get variable object display format */
+
+enum varobj_display_formats
+varobj_set_display_format (struct varobj *var,
+ enum varobj_display_formats format)
+{
+ switch (format)
+ {
+ case FORMAT_NATURAL:
+ case FORMAT_BINARY:
+ case FORMAT_DECIMAL:
+ case FORMAT_HEXADECIMAL:
+ case FORMAT_OCTAL:
+ var->format = format;
+ break;
+
+ default:
+ var->format = variable_default_display (var);
+ }
+
+ return var->format;
+}
+
+enum varobj_display_formats
+varobj_get_display_format (struct varobj *var)
+{
+ return var->format;
+}
+
+int
+varobj_get_num_children (struct varobj *var)
+{
+ if (var->num_children == -1)
+ var->num_children = number_of_children (var);
+
+ return var->num_children;
+}
+
+/* Creates a list of the immediate children of a variable object;
+ the return code is the number of such children or -1 on error */
+
+int
+varobj_list_children (struct varobj *var, struct varobj ***childlist)
+{
+ struct varobj *child;
+ char *name;
+ int i;
+
+ /* sanity check: have we been passed a pointer? */
+ if (childlist == NULL)
+ return -1;
+
+ *childlist = NULL;
+
+ if (var->num_children == -1)
+ var->num_children = number_of_children (var);
+
+ /* List of children */
+ *childlist = xmalloc ((var->num_children + 1) * sizeof (struct varobj *));
+
+ for (i = 0; i < var->num_children; i++)
+ {
+ /* 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);
+
+ *((*childlist) + i) = child;
+ }
+
+ /* End of list is marked by a NULL pointer */
+ *((*childlist) + i) = NULL;
+
+ return var->num_children;
+}
+
+/* Obtain the type of an object Variable as a string similar to the one gdb
+ prints on the console */
+
+char *
+varobj_get_type (struct varobj *var)
+{
+ value_ptr val;
+ struct cleanup *old_chain;
+ struct ui_file *stb;
+ char *thetype;
+ long length;
+
+ /* For the "fake" variables, do not return a type. (It's type is
+ NULL, too.) */
+ if (CPLUS_FAKE_CHILD (var))
+ return NULL;
+
+ stb = mem_fileopen ();
+ old_chain = make_cleanup_ui_file_delete (stb);
+
+ /* To print the type, we simply create a zero value_ptr 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);
+
+ thetype = ui_file_xstrdup (stb, &length);
+ do_cleanups (old_chain);
+ return thetype;
+}
+
+enum varobj_languages
+varobj_get_language (struct varobj *var)
+{
+ return variable_language (var);
+}
+
+int
+varobj_get_attributes (struct varobj *var)
+{
+ int attributes = 0;
+
+ if (variable_editable (var))
+ /* FIXME: define masks for attributes */
+ attributes |= 0x00000001; /* Editable */
+
+ return attributes;
+}
+
+char *
+varobj_get_value (struct varobj *var)
+{
+ return my_value_of_variable (var);
+}
+
+/* Set the value of an object variable (if it is editable) to the
+ value of the given expression */
+/* Note: Invokes functions that can call error() */
+
+int
+varobj_set_value (struct varobj *var, char *expression)
+{
+ value_ptr val;
+ int offset = 0;
+
+ /* The argument "expression" contains the variable's new value.
+ We need to first construct a legal expression for this -- ugh! */
+ /* Does this cover all the bases? */
+ struct expression *exp;
+ value_ptr value;
+ int saved_input_radix = input_radix;
+
+ if (variable_editable (var) && !var->error)
+ {
+ char *s = expression;
+ int i;
+ value_ptr temp;
+
+ input_radix = 10; /* ALWAYS reset to decimal temporarily */
+ /* FIXME: Callee may longjump */
+ exp = parse_exp_1 (&s, 0, 0);
+ if (!gdb_evaluate_expression (exp, &value))
+ {
+ /* We cannot proceed without a valid expression. */
+ FREEIF (exp);
+ 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;
+ val = value_assign (temp, value);
+ VALUE_ADDRESS (val) -= offset;
+ value_free (var->value);
+ release_value (val);
+ var->value = val;
+ input_radix = saved_input_radix;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns a malloc'ed list with all root variable objects */
+int
+varobj_list (struct varobj ***varlist)
+{
+ struct varobj **cv;
+ struct varobj_root *croot;
+ int mycount = rootcount;
+
+ /* Alloc (rootcount + 1) entries for the result */
+ *varlist = xmalloc ((rootcount + 1) * sizeof (struct varobj *));
+
+ cv = *varlist;
+ croot = rootlist;
+ while ((croot != NULL) && (mycount > 0))
+ {
+ *cv = croot->rootvar;
+ mycount--;
+ cv++;
+ croot = croot->next;
+ }
+ /* Mark the end of the list */
+ *cv = NULL;
+
+ if (mycount || (croot != NULL))
+ warning ("varobj_list: assertion failed - wrong tally of root vars (%d:%d)",
+ rootcount, mycount);
+
+ return rootcount;
+}
+
+/* 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.
+
+ Only root variables can be updated... */
+
+int
+varobj_update (struct varobj *var, struct varobj ***changelist)
+{
+ int changed = 0;
+ int i;
+ int vleft;
+ int error2;
+ struct varobj *v;
+ struct varobj **cv;
+ struct varobj **templist;
+ value_ptr new;
+ struct vstack *stack = NULL;
+ struct vstack *result = NULL;
+ struct frame_info *old_fi;
+
+ /* sanity check: have we been passed a pointer? */
+ if (changelist == NULL)
+ return -1;
+
+ /* Only root variables can be updated... */
+ if (var->root->rootvar != var)
+ /* Not a root var */
+ return -1;
+
+ /* Save the selected stack frame, since we will need to change it
+ in order to evaluate expressions. */
+ old_fi = selected_frame;
+
+ /* 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. */
+ new = value_of_root (var);
+ if (new == NULL)
+ return -1;
+
+ /* Initialize a stack for temporary results */
+ vpush (&result, NULL);
+
+ if (!my_value_equal (var->value, new, &error2))
+ {
+ /* Note that it's changed There a couple of exceptions here,
+ though. We don't want some types to be reported as "changed". */
+ if (type_changeable (var))
+ {
+ vpush (&result, var);
+ changed++;
+ }
+ }
+ /* error2 replaces var->error since this new value
+ WILL replace the old one. */
+ var->error = error2;
+
+ /* We must always keep around the new value for this root
+ variable expression, or we lose the updated children! */
+ value_free (var->value);
+ var->value = new;
+
+ /* Initialize a stack */
+ vpush (&stack, NULL);
+
+ /* Push the root's children */
+ if (var->children != NULL)
+ {
+ struct varobj_child *c;
+ for (c = var->children; c != NULL; c = c->next)
+ vpush (&stack, c->child);
+ }
+
+ /* Walk through the children, reconstructing them all. */
+ v = vpop (&stack);
+ while (v != NULL)
+ {
+ /* Push any children */
+ if (v->children != NULL)
+ {
+ struct varobj_child *c;
+ for (c = v->children; c != NULL; c = c->next)
+ vpush (&stack, c->child);
+ }
+
+ /* 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++;
+ }
+ /* 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 */
+ *changelist = xmalloc ((changed + 1) * sizeof (struct varobj *));
+ if (changed > 1)
+ {
+ templist = xmalloc ((changed + 1) * sizeof (struct varobj *));
+ cv = templist;
+ }
+ else
+ cv = *changelist;
+
+ /* Copy from result stack to list */
+ vleft = changed;
+ *cv = vpop (&result);
+ while ((*cv != NULL) && (vleft > 0))
+ {
+ vleft--;
+ cv++;
+ *cv = vpop (&result);
+ }
+ if (vleft)
+ warning ("varobj_update: assertion failed - vleft <> 0");
+
+ 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);
+
+ return changed;
+}
+
+
+/* Helper functions */
+
+/*
+ * Variable object construction/destruction
+ */
+
+static int
+delete_variable (resultp, var, only_children_p)
+ struct cpstack **resultp;
+ struct varobj *var;
+ int only_children_p;
+{
+ int delcount = 0;
+
+ delete_variable_1 (resultp, &delcount, var,
+ only_children_p, 1 /* remove_from_parent_p */ );
+
+ return delcount;
+}
+
+/* Delete the variable object VAR and its children */
+/* IMPORTANT NOTE: If we delete a variable which is a child
+ and the parent is not removed we dump core. It must be always
+ initially called with remove_from_parent_p set */
+static void
+delete_variable_1 (resultp, delcountp, var,
+ only_children_p, remove_from_parent_p)
+ struct cpstack **resultp;
+ int *delcountp;
+ struct varobj *var;
+ int only_children_p;
+ int remove_from_parent_p;
+{
+ struct varobj_child *vc;
+ struct varobj_child *next;
+
+ /* Delete any children of this variable, too. */
+ for (vc = var->children; vc != NULL; vc = next)
+ {
+ if (!remove_from_parent_p)
+ vc->child->parent = NULL;
+ delete_variable_1 (resultp, delcountp, vc->child, 0, only_children_p);
+ next = vc->next;
+ free (vc);
+ }
+
+ /* if we were called to delete only the children we are done here */
+ if (only_children_p)
+ return;
+
+ /* Otherwise, add it to the list of deleted ones and proceed to do so */
+ if (var->obj_name == NULL)
+ warning ("Assertion failed: NULL var->obj_name unexpectdly found");
+ else
+ {
+ cppush (resultp, strdup (var->obj_name));
+ *delcountp = *delcountp + 1;
+ }
+
+ /* If this variable has a parent, remove it from its parent's list */
+ /* OPTIMIZATION: if the parent of this variable is also being deleted,
+ (as indicated by remove_from_parent_p) we don't bother doing an
+ expensive list search to find the element to remove when we are
+ discarding the list afterwards */
+ if ((remove_from_parent_p) &&
+ (var->parent != NULL))
+ {
+ remove_child_from_parent (var->parent, var);
+ }
+
+ uninstall_variable (var);
+
+ /* Free memory associated with this variable */
+ free_variable (var);
+}
+
+/* Install the given variable VAR with the object name VAR->OBJ_NAME. */
+static int
+install_variable (var)
+ struct varobj *var;
+{
+ struct vlist *cv;
+ struct vlist *newvl;
+ const char *chp;
+ unsigned int index = 0;
+ unsigned int i = 1;
+
+ for (chp = var->obj_name; *chp; chp++)
+ {
+ index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+ }
+
+ cv = *(varobj_table + index);
+ while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0))
+ cv = cv->next;
+
+ if (cv != NULL)
+ error ("Duplicate variable object name");
+
+ /* Add varobj to hash table */
+ newvl = xmalloc (sizeof (struct vlist));
+ newvl->next = *(varobj_table + index);
+ newvl->var = var;
+ *(varobj_table + index) = newvl;
+
+ /* If root, add varobj to root list */
+ if (var->root->rootvar == var)
+ {
+ /* Add to list of root variables */
+ if (rootlist == NULL)
+ var->root->next = NULL;
+ else
+ var->root->next = rootlist;
+ rootlist = var->root;
+ rootcount++;
+ }
+
+ return 1; /* OK */
+}
+
+/* Unistall the object VAR. */
+static void
+uninstall_variable (var)
+ struct varobj *var;
+{
+ struct vlist *cv;
+ struct vlist *prev;
+ struct varobj_root *cr;
+ struct varobj_root *prer;
+ const char *chp;
+ unsigned int index = 0;
+ unsigned int i = 1;
+
+ /* Remove varobj from hash table */
+ for (chp = var->obj_name; *chp; chp++)
+ {
+ index = (index + (i++ * (unsigned int) *chp)) % VAROBJ_TABLE_SIZE;
+ }
+
+ cv = *(varobj_table + index);
+ prev = NULL;
+ while ((cv != NULL) && (strcmp (cv->var->obj_name, var->obj_name) != 0))
+ {
+ prev = cv;
+ cv = cv->next;
+ }
+
+ if (varobjdebug)
+ fprintf_unfiltered (gdb_stdlog, "Deleting %s\n", var->obj_name);
+
+ if (cv == NULL)
+ {
+ warning ("Assertion failed: Could not find variable object \"%s\" to delete", var->obj_name);
+ return;
+ }
+
+ if (prev == NULL)
+ *(varobj_table + index) = cv->next;
+ else
+ prev->next = cv->next;
+
+ free (cv);
+
+ /* If root, remove varobj from root list */
+ if (var->root->rootvar == var)
+ {
+ /* Remove from list of root variables */
+ if (rootlist == var->root)
+ rootlist = var->root->next;
+ else
+ {
+ prer = NULL;
+ cr = rootlist;
+ while ((cr != NULL) && (cr->rootvar != var))
+ {
+ prer = cr;
+ cr = cr->next;
+ }
+ if (cr == NULL)
+ {
+ warning ("Assertion failed: Could not find varobj \"%s\" in root list", var->obj_name);
+ return;
+ }
+ if (prer == NULL)
+ rootlist = NULL;
+ else
+ prer->next = cr->next;
+ }
+ rootcount--;
+ }
+
+}
+
+/* Does a child with the name NAME exist in VAR? If so, return its data.
+ If not, return NULL. */
+static struct varobj *
+child_exists (var, name)
+ struct varobj *var; /* Parent */
+ char *name; /* name of child */
+{
+ 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 (parent, index, name)
+ struct varobj *parent;
+ int index;
+ char *name;
+{
+ struct varobj *child;
+ char *childs_name;
+
+ 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;
+ 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);
+ 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 (parent, child)
+ 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 (parent, child)
+ struct varobj *parent;
+ struct varobj *child;
+{
+ struct varobj_child *vc, *prev;
+
+ /* Find the child in the parent's list */
+ prev = NULL;
+ for (vc = parent->children; vc != NULL;)
+ {
+ if (vc->child == child)
+ break;
+ prev = vc;
+ vc = vc->next;
+ }
+
+ if (prev == NULL)
+ parent->children = vc->next;
+ else
+ prev->next = vc->next;
+
+}
+
+
+/*
+ * Miscellaneous utility functions.
+ */
+
+/* Allocate memory and initialize a new variable */
+static struct varobj *
+new_variable (void)
+{
+ struct varobj *var;
+
+ var = (struct varobj *) xmalloc (sizeof (struct varobj));
+ var->name = NULL;
+ var->obj_name = NULL;
+ 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;
+
+ return var;
+}
+
+/* Allocate memory and initialize a new root variable */
+static struct varobj *
+new_root_variable (void)
+{
+ struct varobj *var = new_variable ();
+ var->root = (struct varobj_root *) xmalloc (sizeof (struct varobj_root));;
+ var->root->lang = NULL;
+ var->root->exp = NULL;
+ var->root->valid_block = NULL;
+ var->root->frame = (CORE_ADDR) -1;
+ var->root->rootvar = NULL;
+
+ return var;
+}
+
+/* Free any allocated memory associated with VAR. */
+static void
+free_variable (var)
+ struct varobj *var;
+{
+ /* Free the expression if this is a root variable. */
+ if (var->root->rootvar == var)
+ {
+ free_current_contents ((char **) &var->root->exp);
+ FREEIF (var->root);
+ }
+
+ FREEIF (var->name);
+ FREEIF (var->obj_name);
+ FREEIF (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. */
+static struct type *
+get_type (var)
+ struct varobj *var;
+{
+ struct type *type;
+ type = var->type;
+
+ while (type != NULL && TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+ type = TYPE_TARGET_TYPE (type);
+
+ return type;
+}
+
+/* This returns the type of the variable, dereferencing pointers, too. */
+static struct type *
+get_type_deref (var)
+ struct varobj *var;
+{
+ struct type *type;
+
+ type = get_type (var);
+
+ if (type != NULL && (TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_REF))
+ type = get_target_type (type);
+
+ return type;
+}
+
+/* This returns the target type (or NULL) of TYPE, also skipping
+ past typedefs, just like get_type (). */
+static struct type *
+get_target_type (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);
+ }
+
+ return type;
+}
+
+/* What is the default display for this variable? We assume that
+ everything is "natural". Any exceptions? */
+static enum varobj_display_formats
+variable_default_display (var)
+ struct varobj *var;
+{
+ return FORMAT_NATURAL;
+}
+
+/* This function is similar to gdb's value_equal, except that this
+ one is "safe" -- it NEVER longjmps. It determines if the VAR's
+ value is the same as VAL2. */
+static int
+my_value_equal (val1, val2, error2)
+ value_ptr val1;
+ value_ptr 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 (pstack, var)
+ 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 (pstack)
+ 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;
+ free (s);
+
+ return v;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static void
+cppush (pstack, name)
+ struct cpstack **pstack;
+ char *name;
+{
+ struct cpstack *s;
+
+ s = (struct cpstack *) xmalloc (sizeof (struct cpstack));
+ s->name = name;
+ s->next = *pstack;
+ *pstack = s;
+}
+
+/* FIXME: The following should be generic for any pointer */
+static char *
+cppop (pstack)
+ struct cpstack **pstack;
+{
+ struct cpstack *s;
+ char *v;
+
+ if ((*pstack)->name == NULL && (*pstack)->next == NULL)
+ return NULL;
+
+ s = *pstack;
+ v = s->name;
+ *pstack = (*pstack)->next;
+ free (s);
+
+ return v;
+}
+
+/*
+ * Language-dependencies
+ */
+
+/* Common entry points */
+
+/* Get the language of variable VAR. */
+static enum varobj_languages
+variable_language (var)
+ struct varobj *var;
+{
+ enum varobj_languages lang;
+
+ switch (var->root->exp->language_defn->la_language)
+ {
+ default:
+ case language_c:
+ lang = vlang_c;
+ break;
+ case language_cplus:
+ lang = vlang_cplus;
+ break;
+ case language_java:
+ lang = vlang_java;
+ break;
+ }
+
+ return lang;
+}
+
+/* Return the number of children for a given variable.
+ The result of this function is defined by the language
+ implementation. The number of children returned by this function
+ is the number of children that the user will see in the variable
+ display. */
+static int
+number_of_children (var)
+ struct varobj *var;
+{
+ return (*var->root->lang->number_of_children) (var);;
+}
+
+/* What is the expression for the root varobj VAR? Returns a malloc'd string. */
+static char *
+name_of_variable (var)
+ struct varobj *var;
+{
+ return (*var->root->lang->name_of_variable) (var);
+}
+
+/* What is the name of the INDEX'th child of VAR? Returns a malloc'd string. */
+static char *
+name_of_child (var, index)
+ struct varobj *var;
+ int index;
+{
+ return (*var->root->lang->name_of_child) (var, index);
+}
+
+/* What is the value_ptr of the root variable VAR? */
+static value_ptr
+value_of_root (var)
+ struct varobj *var;
+{
+ return (*var->root->lang->value_of_root) (var);
+}
+
+/* What is the value_ptr for the INDEX'th child of PARENT? */
+static value_ptr
+value_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ value_ptr value;
+
+ 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 (var)
+ 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
+variable_editable (var)
+ struct varobj *var;
+{
+ return (*var->root->lang->variable_editable) (var);
+}
+
+/* GDB already has a command called "value_of_variable". Sigh. */
+static char *
+my_value_of_variable (var)
+ struct varobj *var;
+{
+ return (*var->root->lang->value_of_variable) (var);
+}
+
+/* Is VAR something that can change? Depending on language,
+ some variable's values never change. For example,
+ struct and unions never change values. */
+static int
+type_changeable (var)
+ struct varobj *var;
+{
+ int r;
+ struct type *type;
+
+ if (CPLUS_FAKE_CHILD (var))
+ return 0;
+
+ type = get_type (var);
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ r = 0;
+ break;
+
+ default:
+ r = 1;
+ }
+
+ return r;
+}
+
+/* C */
+static int
+c_number_of_children (var)
+ struct varobj *var;
+{
+ struct type *type;
+ struct type *target;
+ int children;
+
+ type = get_type (var);
+ target = get_target_type (type);
+ children = 0;
+
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_ARRAY:
+ if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (target) > 0
+ && TYPE_ARRAY_UPPER_BOUND_TYPE (type) != BOUND_CANNOT_BE_DETERMINED)
+ children = TYPE_LENGTH (type) / TYPE_LENGTH (target);
+ else
+ children = -1;
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ children = TYPE_NFIELDS (type);
+ 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. */
+ switch (TYPE_CODE (target))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ children = TYPE_NFIELDS (target);
+ break;
+
+ case TYPE_CODE_FUNC:
+ children = 0;
+ break;
+
+ default:
+ /* Don't dereference char* or void*. */
+ if (TYPE_NAME (target) != NULL
+ && (STREQ (TYPE_NAME (target), "char")
+ || STREQ (TYPE_NAME (target), "void")))
+ children = 0;
+ else
+ children = 1;
+ }
+ break;
+
+ default:
+ /* Other types have no children */
+ break;
+ }
+
+ return children;
+}
+
+static char *
+c_name_of_variable (parent)
+ struct varobj *parent;
+{
+ return savestring (parent->name, strlen (parent->name));
+}
+
+static char *
+c_name_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ struct type *type;
+ struct type *target;
+ char *name;
+ char *string;
+
+ type = get_type (parent);
+ target = get_target_type (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);
+ }
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ string = TYPE_FIELD_NAME (type, index);
+ name = savestring (string, strlen (string));
+ break;
+
+ case TYPE_CODE_PTR:
+ switch (TYPE_CODE (target))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ string = TYPE_FIELD_NAME (target, index);
+ name = savestring (string, strlen (string));
+ break;
+
+ default:
+ name = (char *) xmalloc ((strlen (parent->name) + 2) * sizeof (char));
+ sprintf (name, "*%s", parent->name);
+ break;
+ }
+ break;
+
+ default:
+ /* This should not happen */
+ name = xstrdup ("???");
+ }
+
+ return name;
+}
+
+static value_ptr
+c_value_of_root (var)
+ struct varobj *var;
+{
+ value_ptr new_val;
+ struct frame_info *fi;
+ int within_scope;
+
+ /* Determine whether the variable is still around. */
+ if (var->root->valid_block == NULL)
+ within_scope = 1;
+ else
+ {
+ reinit_frame_cache ();
+ fi = find_frame_addr_in_frame_chain (var->root->frame);
+ within_scope = fi != NULL;
+ /* FIXME: select_frame could fail */
+ if (within_scope)
+ select_frame (fi, -1);
+ }
+
+ 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);
+ return new_val;
+ }
+
+ return NULL;
+}
+
+static value_ptr
+c_value_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ value_ptr value, temp;
+ 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:
+ value = value_slice (temp, index, 1);
+ temp = value_coerce_array (value);
+ gdb_value_ind (temp, &value);
+ break;
+
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ value = value_struct_elt (&temp, NULL, name, NULL, "vstructure");
+ break;
+
+ case TYPE_CODE_PTR:
+ switch (TYPE_CODE (target))
+ {
+ case TYPE_CODE_STRUCT:
+ case TYPE_CODE_UNION:
+ value = value_struct_elt (&temp, NULL, name, NULL, "vstructure");
+ break;
+
+ default:
+ gdb_value_ind (temp, &value);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (value != NULL)
+ release_value (value);
+
+ return value;
+}
+
+static struct type *
+c_type_of_child (parent, index)
+ 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;
+ }
+
+ return type;
+}
+
+static int
+c_variable_editable (var)
+ struct varobj *var;
+{
+ switch (TYPE_CODE (get_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;
+
+ default:
+ return 1;
+ break;
+ }
+}
+
+static char *
+c_value_of_variable (var)
+ struct varobj *var;
+{
+ struct type *type;
+ value_ptr val;
+
+ 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 ("???");
+ }
+
+ /* 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_UNION:
+ return xstrdup ("{...}");
+ /* break; */
+
+ case TYPE_CODE_ARRAY:
+ {
+ char number[18];
+ sprintf (number, "[%d]", var->num_children);
+ return xstrdup (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;
+ }
+ /* break; */
+ }
+}
+
+
+/* C++ */
+
+static int
+cplus_number_of_children (var)
+ struct varobj *var;
+{
+ struct type *type;
+ int children, dont_know;
+
+ dont_know = 1;
+ children = 0;
+
+ if (!CPLUS_FAKE_CHILD (var))
+ {
+ type = get_type_deref (var);
+
+ if (((TYPE_CODE (type)) == TYPE_CODE_STRUCT) ||
+ ((TYPE_CODE (type)) == TYPE_CODE_UNION))
+ {
+ int kids[3];
+
+ cplus_class_num_children (type, kids);
+ if (kids[v_public] != 0)
+ children++;
+ if (kids[v_private] != 0)
+ children++;
+ if (kids[v_protected] != 0)
+ children++;
+
+ /* Add any baseclasses */
+ children += TYPE_N_BASECLASSES (type);
+ dont_know = 0;
+
+ /* FIXME: save children in var */
+ }
+ }
+ else
+ {
+ int kids[3];
+
+ type = get_type_deref (var->parent);
+
+ cplus_class_num_children (type, kids);
+ if (STREQ (var->name, "public"))
+ children = kids[v_public];
+ else if (STREQ (var->name, "private"))
+ children = kids[v_private];
+ else
+ children = kids[v_protected];
+ dont_know = 0;
+ }
+
+ if (dont_know)
+ children = c_number_of_children (var);
+
+ return children;
+}
+
+/* Compute # of public, private, and protected variables in this class.
+ That means we need to descend into all baseclasses and find out
+ how many are there, too. */
+static void
+cplus_class_num_children (type, children)
+ struct type *type;
+ int children[3];
+{
+ int i;
+
+ children[v_public] = 0;
+ children[v_private] = 0;
+ children[v_protected] = 0;
+
+ for (i = TYPE_N_BASECLASSES (type); i < TYPE_NFIELDS (type); i++)
+ {
+ /* If we have a virtual table pointer, omit it. */
+ if (TYPE_VPTR_BASETYPE (type) == type
+ && TYPE_VPTR_FIELDNO (type) == i)
+ continue;
+
+ if (TYPE_FIELD_PROTECTED (type, i))
+ children[v_protected]++;
+ else if (TYPE_FIELD_PRIVATE (type, i))
+ children[v_private]++;
+ else
+ children[v_public]++;
+ }
+}
+
+static char *
+cplus_name_of_variable (parent)
+ struct varobj *parent;
+{
+ return c_name_of_variable (parent);
+}
+
+static char *
+cplus_name_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ char *name;
+ struct type *type;
+ int children[3];
+
+ if (CPLUS_FAKE_CHILD (parent))
+ {
+ /* Looking for children of public, private, or protected. */
+ type = get_type_deref (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);
+
+ 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);
+ }
+ else if (index < TYPE_N_BASECLASSES (type))
+ name = TYPE_FIELD_NAME (type, index);
+ else
+ {
+ /* Everything beyond the baseclasses can
+ only be "public", "private", or "protected" */
+ index -= TYPE_N_BASECLASSES (type);
+ switch (index)
+ {
+ case 0:
+ if (children[v_public] != 0)
+ {
+ name = "public";
+ break;
+ }
+ case 1:
+ if (children[v_private] != 0)
+ {
+ name = "private";
+ break;
+ }
+ case 2:
+ if (children[v_protected] != 0)
+ {
+ name = "protected";
+ break;
+ }
+ default:
+ /* error! */
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (name == NULL)
+ return c_name_of_child (parent, index);
+ else
+ {
+ if (name != NULL)
+ name = savestring (name, strlen (name));
+ }
+
+ return name;
+}
+
+static value_ptr
+cplus_value_of_root (var)
+ struct varobj *var;
+{
+ return c_value_of_root (var);
+}
+
+static value_ptr
+cplus_value_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ struct type *type;
+ value_ptr 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))
+ {
+ value_ptr temp = parent->parent->value;
+ value = value_struct_elt (&temp, NULL, name,
+ NULL, "cplus_structure");
+ release_value (value);
+ }
+ else if (index >= TYPE_N_BASECLASSES (type))
+ {
+ /* public, private, or protected */
+ return NULL;
+ }
+ else
+ {
+ /* Baseclass */
+ if (parent->value != NULL)
+ {
+ value_ptr temp;
+
+ if (TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_PTR
+ || TYPE_CODE (VALUE_TYPE (parent->value)) == TYPE_CODE_REF)
+ gdb_value_ind (parent->value, &temp);
+ 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);
+
+ return value;
+}
+
+static struct type *
+cplus_type_of_child (parent, index)
+ 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);
+
+ return type;
+}
+
+static int
+cplus_variable_editable (var)
+ struct varobj *var;
+{
+ if (CPLUS_FAKE_CHILD (var))
+ return 0;
+
+ return c_variable_editable (var);
+}
+
+static char *
+cplus_value_of_variable (var)
+ struct varobj *var;
+{
+
+ /* If we have one of our special types, don't print out
+ any value. */
+ if (CPLUS_FAKE_CHILD (var))
+ return xstrdup ("");
+
+ return c_value_of_variable (var);
+}
+
+/* Java */
+
+static int
+java_number_of_children (var)
+ struct varobj *var;
+{
+ return cplus_number_of_children (var);
+}
+
+static char *
+java_name_of_variable (parent)
+ struct varobj *parent;
+{
+ char *p, *name;
+
+ name = cplus_name_of_variable (parent);
+ /* If the name has "-" in it, it is because we
+ needed to escape periods in the name... */
+ p = name;
+
+ while (*p != '\000')
+ {
+ if (*p == '-')
+ *p = '.';
+ p++;
+ }
+
+ return name;
+}
+
+static char *
+java_name_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ char *name, *p;
+
+ name = cplus_name_of_child (parent, index);
+ /* Escape any periods in the name... */
+ p = name;
+
+ while (*p != '\000')
+ {
+ if (*p == '.')
+ *p = '-';
+ p++;
+ }
+
+ return name;
+}
+
+static value_ptr
+java_value_of_root (var)
+ struct varobj *var;
+{
+ return cplus_value_of_root (var);
+}
+
+static value_ptr
+java_value_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ return cplus_value_of_child (parent, index);
+}
+
+static struct type *
+java_type_of_child (parent, index)
+ struct varobj *parent;
+ int index;
+{
+ return cplus_type_of_child (parent, index);
+}
+
+static int
+java_variable_editable (var)
+ struct varobj *var;
+{
+ return cplus_variable_editable (var);
+}
+
+static char *
+java_value_of_variable (var)
+ struct varobj *var;
+{
+ return cplus_value_of_variable (var);
+}
+
+extern void _initialize_varobj (void);
+void
+_initialize_varobj (void)
+{
+ int sizeof_table = sizeof (struct vlist *) * VAROBJ_TABLE_SIZE;
+
+ 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);
+}