/* Implementation of the GDB variable objects API.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009, 2010 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
#include "wrapper.h"
#include "gdbcmd.h"
#include "block.h"
+#include "valprint.h"
#include "gdb_assert.h"
#include "gdb_string.h"
+#include "gdb_regex.h"
#include "varobj.h"
#include "vec.h"
#include "gdbthread.h"
#include "inferior.h"
+#if HAVE_PYTHON
+#include "python/python.h"
+#include "python/python-internal.h"
+#else
+typedef int PyObject;
+#endif
+
/* Non-zero if we want to see trace of varobj level stuff. */
int varobjdebug = 0;
/* String representations of gdb's known languages */
char *varobj_language_string[] = { "unknown", "C", "C++", "Java" };
+/* True if we want to allow Python-based pretty-printing. */
+static int pretty_printing = 0;
+
+void
+varobj_enable_pretty_printing (void)
+{
+ pretty_printing = 1;
+}
+
/* Data structures */
/* Every root variable has one of these structures saved in its
/* Children of this object. */
VEC (varobj_p) *children;
+ /* Whether the children of this varobj were requested. This field is
+ used to decide if dynamic varobj should recompute their children.
+ In the event that the frontend never asked for the children, we
+ can avoid that. */
+ int children_requested;
+
/* Description of the root variable. Points to root variable for children. */
struct varobj_root *root;
not fetched if either the variable is frozen, or any parents is
frozen. */
int not_fetched;
+
+ /* Sub-range of children which the MI consumer has requested. If
+ FROM < 0 or TO < 0, means that all children have been
+ requested. */
+ int from;
+ int to;
+
+ /* The pretty-printer constructor. If NULL, then the default
+ pretty-printer will be looked up. If None, then no
+ pretty-printer will be installed. */
+ PyObject *constructor;
+
+ /* The pretty-printer that has been constructed. If NULL, then a
+ new printer object is needed, and one will be constructed. */
+ PyObject *pretty_printer;
+
+ /* The iterator returned by the printer's 'children' method, or NULL
+ if not available. */
+ PyObject *child_iter;
+
+ /* We request one extra item from the iterator, so that we can
+ report to the caller whether there are more items than we have
+ already reported. However, we don't want to install this value
+ when we read it, because that will mess up future updates. So,
+ we stash it here instead. */
+ PyObject *saved_item;
};
struct cpstack
static struct varobj *create_child (struct varobj *, int, char *);
+static struct varobj *
+create_child_with_value (struct varobj *parent, int index, const char *name,
+ struct value *value);
+
/* Utility routines */
static struct varobj *new_variable (void);
enum varobj_display_formats format);
static char *value_get_print_value (struct value *value,
- enum varobj_display_formats format);
+ enum varobj_display_formats format,
+ struct varobj *var);
static int varobj_value_is_changeable_p (struct varobj *var);
static int is_root_p (struct varobj *var);
+#if HAVE_PYTHON
+
+static struct varobj *
+varobj_add_child (struct varobj *var, const char *name, struct value *value);
+
+#endif /* HAVE_PYTHON */
+
/* C implementation */
static int c_number_of_children (struct varobj *var);
/* 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 */
return (var->root->rootvar == var);
}
+#ifdef HAVE_PYTHON
+/* Helper function to install a Python environment suitable for
+ use during operations on VAR. */
+struct cleanup *
+varobj_ensure_python_env (struct varobj *var)
+{
+ return ensure_python_env (var->root->exp->gdbarch,
+ var->root->exp->language_defn);
+}
+#endif
+
/* Creates a varobj (not its children) */
/* Return the full FRAME which corresponds to the given CORE_ADDR
if (frame_addr == (CORE_ADDR) 0)
return NULL;
- while (1)
+ for (frame = get_current_frame ();
+ frame != NULL;
+ frame = get_prev_frame (frame))
{
- frame = get_prev_frame (frame);
- if (frame == NULL)
- return NULL;
- if (get_frame_base_address (frame) == frame_addr)
+ /* The CORE_ADDR we get as argument was parsed from a string GDB
+ output as $fp. This output got truncated to gdbarch_addr_bit.
+ Truncate the frame base address in the same manner before
+ comparing it against our argument. */
+ CORE_ADDR frame_base = get_frame_base_address (frame);
+ int addr_bit = gdbarch_addr_bit (get_frame_arch (frame));
+
+ if (addr_bit < (sizeof (CORE_ADDR) * HOST_CHAR_BIT))
+ frame_base &= ((CORE_ADDR) 1 << addr_bit) - 1;
+
+ if (frame_base == frame_addr)
return frame;
}
+
+ return NULL;
}
struct varobj *
char *p;
enum varobj_languages lang;
struct value *value = NULL;
- int expr_len;
- /* Parse and evaluate the expression, filling in as much
- of the variable's data as possible */
+ /* Parse and evaluate the expression, filling in as much of the
+ variable's data as possible. */
- /* Allow creator to specify context of variable */
- if ((type == USE_CURRENT_FRAME) || (type == USE_SELECTED_FRAME))
- fi = deprecated_safe_get_selected_frame ();
+ if (has_stack_frames ())
+ {
+ /* Allow creator to specify context of variable */
+ if ((type == USE_CURRENT_FRAME) || (type == USE_SELECTED_FRAME))
+ fi = get_selected_frame (NULL);
+ 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);
+ }
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);
+ fi = NULL;
/* frame = -2 means always use selected frame */
if (type == USE_SELECTED_FRAME)
var->format = variable_default_display (var);
var->root->valid_block = innermost_block;
- expr_len = strlen (expression);
- var->name = savestring (expression, expr_len);
+ var->name = xstrdup (expression);
/* For a root var, the name and the expr are the same. */
- var->path_expr = savestring (expression, expr_len);
+ var->path_expr = xstrdup (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 (innermost_block && fi != NULL)
+ if (innermost_block)
{
+ /* User could specify explicit FRAME-ADDR which was not found but
+ EXPRESSION is frame specific and we would not be able to evaluate
+ it correctly next time. With VALID_BLOCK set we must also set
+ FRAME and THREAD_ID. */
+ if (fi == NULL)
+ error (_("Failed to find the specified frame"));
+
var->root->frame = get_frame_id (fi);
var->root->thread_id = pid_to_thread_id (inferior_ptid);
old_fi = get_selected_frame (NULL);
/* 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->root->rootvar = var;
/* Reset the selected frame */
- if (fi != NULL)
+ if (old_fi != NULL)
select_frame (old_fi);
}
if ((var != NULL) && (objname != NULL))
{
- var->obj_name = savestring (objname, strlen (objname));
+ var->obj_name = xstrdup (objname);
/* If a varobj name is duplicated, the install will fail so
we must clenup */
return obj_name;
}
-/* Given an "objname", returns the pointer to the corresponding varobj
- or NULL if not found */
+/* Given an OBJNAME, returns the pointer to the corresponding varobj. Call
+ error if OBJNAME cannot be found. */
struct varobj *
varobj_get_handle (char *objname)
return delcount;
}
+#if HAVE_PYTHON
+
+/* Convenience function for varobj_set_visualizer. Instantiate a
+ pretty-printer for a given value. */
+static PyObject *
+instantiate_pretty_printer (PyObject *constructor, struct value *value)
+{
+ PyObject *val_obj = NULL;
+ PyObject *printer;
+
+ val_obj = value_to_value_object (value);
+ if (! val_obj)
+ return NULL;
+
+ printer = PyObject_CallFunctionObjArgs (constructor, val_obj, NULL);
+ Py_DECREF (val_obj);
+ return printer;
+ return NULL;
+}
+
+#endif
+
/* Set/Get variable object display format */
enum varobj_display_formats
&& var->value && !value_lazy (var->value))
{
xfree (var->print_value);
- var->print_value = value_get_print_value (var->value, var->format);
+ var->print_value = value_get_print_value (var->value, var->format, var);
}
return var->format;
return var->format;
}
+char *
+varobj_get_display_hint (struct varobj *var)
+{
+ char *result = NULL;
+
+#if HAVE_PYTHON
+ struct cleanup *back_to = varobj_ensure_python_env (var);
+
+ if (var->pretty_printer)
+ result = gdbpy_get_display_hint (var->pretty_printer);
+
+ do_cleanups (back_to);
+#endif
+
+ return result;
+}
+
+/* Return true if the varobj has items after TO, false otherwise. */
+
+int
+varobj_has_more (struct varobj *var, int to)
+{
+ if (VEC_length (varobj_p, var->children) > to)
+ return 1;
+ return ((to == -1 || VEC_length (varobj_p, var->children) == to)
+ && var->saved_item != NULL);
+}
+
/* If the variable object is bound to a specific thread, that
is its evaluation can always be done in context of a frame
inside that thread, returns GDB id of the thread -- which
return var->frozen;
}
+/* A helper function that restricts a range to what is actually
+ available in a VEC. This follows the usual rules for the meaning
+ of FROM and TO -- if either is negative, the entire range is
+ used. */
+
+static void
+restrict_range (VEC (varobj_p) *children, int *from, int *to)
+{
+ if (*from < 0 || *to < 0)
+ {
+ *from = 0;
+ *to = VEC_length (varobj_p, children);
+ }
+ else
+ {
+ if (*from > VEC_length (varobj_p, children))
+ *from = VEC_length (varobj_p, children);
+ if (*to > VEC_length (varobj_p, children))
+ *to = VEC_length (varobj_p, children);
+ if (*from > *to)
+ *from = *to;
+ }
+}
+
+#if HAVE_PYTHON
+
+/* A helper for update_dynamic_varobj_children that installs a new
+ child when needed. */
+
+static void
+install_dynamic_child (struct varobj *var,
+ VEC (varobj_p) **changed,
+ VEC (varobj_p) **new,
+ VEC (varobj_p) **unchanged,
+ int *cchanged,
+ int index,
+ const char *name,
+ struct value *value)
+{
+ if (VEC_length (varobj_p, var->children) < index + 1)
+ {
+ /* There's no child yet. */
+ struct varobj *child = varobj_add_child (var, name, value);
+
+ if (new)
+ {
+ VEC_safe_push (varobj_p, *new, child);
+ *cchanged = 1;
+ }
+ }
+ else
+ {
+ varobj_p existing = VEC_index (varobj_p, var->children, index);
+
+ if (install_new_value (existing, value, 0))
+ {
+ if (changed)
+ VEC_safe_push (varobj_p, *changed, existing);
+ }
+ else if (unchanged)
+ VEC_safe_push (varobj_p, *unchanged, existing);
+ }
+}
+
+static int
+dynamic_varobj_has_child_method (struct varobj *var)
+{
+ struct cleanup *back_to;
+ PyObject *printer = var->pretty_printer;
+ int result;
+
+ back_to = varobj_ensure_python_env (var);
+ result = PyObject_HasAttr (printer, gdbpy_children_cst);
+ do_cleanups (back_to);
+ return result;
+}
+
+#endif
+
+static int
+update_dynamic_varobj_children (struct varobj *var,
+ VEC (varobj_p) **changed,
+ VEC (varobj_p) **new,
+ VEC (varobj_p) **unchanged,
+ int *cchanged,
+ int update_children,
+ int from,
+ int to)
+{
+#if HAVE_PYTHON
+ struct cleanup *back_to;
+ PyObject *children;
+ int i;
+ PyObject *printer = var->pretty_printer;
+
+ back_to = varobj_ensure_python_env (var);
+
+ *cchanged = 0;
+ if (!PyObject_HasAttr (printer, gdbpy_children_cst))
+ {
+ do_cleanups (back_to);
+ return 0;
+ }
+
+ if (update_children || !var->child_iter)
+ {
+ children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
+ NULL);
+
+ if (!children)
+ {
+ gdbpy_print_stack ();
+ error (_("Null value returned for children"));
+ }
+
+ make_cleanup_py_decref (children);
+
+ if (!PyIter_Check (children))
+ error (_("Returned value is not iterable"));
+
+ Py_XDECREF (var->child_iter);
+ var->child_iter = PyObject_GetIter (children);
+ if (!var->child_iter)
+ {
+ gdbpy_print_stack ();
+ error (_("Could not get children iterator"));
+ }
+
+ Py_XDECREF (var->saved_item);
+ var->saved_item = NULL;
+
+ i = 0;
+ }
+ else
+ i = VEC_length (varobj_p, var->children);
+
+ /* We ask for one extra child, so that MI can report whether there
+ are more children. */
+ for (; to < 0 || i < to + 1; ++i)
+ {
+ PyObject *item;
+
+ /* See if there was a leftover from last time. */
+ if (var->saved_item)
+ {
+ item = var->saved_item;
+ var->saved_item = NULL;
+ }
+ else
+ item = PyIter_Next (var->child_iter);
+
+ if (!item)
+ break;
+
+ /* We don't want to push the extra child on any report list. */
+ if (to < 0 || i < to)
+ {
+ PyObject *py_v;
+ char *name;
+ struct value *v;
+ struct cleanup *inner;
+ int can_mention = from < 0 || i >= from;
+
+ inner = make_cleanup_py_decref (item);
+
+ if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
+ error (_("Invalid item from the child list"));
+
+ v = convert_value_from_python (py_v);
+ install_dynamic_child (var, can_mention ? changed : NULL,
+ can_mention ? new : NULL,
+ can_mention ? unchanged : NULL,
+ can_mention ? cchanged : NULL, i, name, v);
+ do_cleanups (inner);
+ }
+ else
+ {
+ Py_XDECREF (var->saved_item);
+ var->saved_item = item;
+
+ /* We want to truncate the child list just before this
+ element. */
+ break;
+ }
+ }
+
+ if (i < VEC_length (varobj_p, var->children))
+ {
+ int j;
+
+ *cchanged = 1;
+ for (j = i; j < VEC_length (varobj_p, var->children); ++j)
+ varobj_delete (VEC_index (varobj_p, var->children, j), NULL, 0);
+ VEC_truncate (varobj_p, var->children, i);
+ }
+
+ /* If there are fewer children than requested, note that the list of
+ children changed. */
+ if (to >= 0 && VEC_length (varobj_p, var->children) < to)
+ *cchanged = 1;
+
+ var->num_children = VEC_length (varobj_p, var->children);
+
+ do_cleanups (back_to);
+
+ return 1;
+#else
+ gdb_assert (0 && "should never be called if Python is not enabled");
+#endif
+}
int
varobj_get_num_children (struct varobj *var)
{
if (var->num_children == -1)
- var->num_children = number_of_children (var);
+ {
+ if (var->pretty_printer)
+ {
+ int dummy;
+
+ /* If we have a dynamic varobj, don't report -1 children.
+ So, try to fetch some children first. */
+ update_dynamic_varobj_children (var, NULL, NULL, NULL, &dummy,
+ 0, 0, 0);
+ }
+ else
+ var->num_children = number_of_children (var);
+ }
- return var->num_children;
+ return var->num_children >= 0 ? var->num_children : 0;
}
/* Creates a list of the immediate children of a variable object;
the return code is the number of such children or -1 on error */
VEC (varobj_p)*
-varobj_list_children (struct varobj *var)
+varobj_list_children (struct varobj *var, int *from, int *to)
{
- struct varobj *child;
char *name;
- int i;
+ int i, children_changed;
+
+ var->children_requested = 1;
+
+ if (var->pretty_printer)
+ {
+ /* This, in theory, can result in the number of children changing without
+ frontend noticing. But well, calling -var-list-children on the same
+ varobj twice is not something a sane frontend would do. */
+ update_dynamic_varobj_children (var, NULL, NULL, NULL, &children_changed,
+ 0, 0, *to);
+ restrict_range (var->children, from, to);
+ return var->children;
+ }
if (var->num_children == -1)
var->num_children = number_of_children (var);
}
}
+ restrict_range (var->children, from, to);
return var->children;
}
+#if HAVE_PYTHON
+
+static struct varobj *
+varobj_add_child (struct varobj *var, const char *name, struct value *value)
+{
+ varobj_p v = create_child_with_value (var,
+ VEC_length (varobj_p, var->children),
+ name, value);
+
+ VEC_safe_push (varobj_p, var->children, v);
+ return v;
+}
+
+#endif /* HAVE_PYTHON */
+
/* 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)
{
- struct value *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.)
Do not return a type for invalid variables as well. */
if (CPLUS_FAKE_CHILD (var) || !var->root->is_valid)
return NULL;
- stb = mem_fileopen ();
- old_chain = make_cleanup_ui_file_delete (stb);
-
- /* 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);
-
- thetype = ui_file_xstrdup (stb, &length);
- do_cleanups (old_chain);
- return thetype;
+ return type_to_string (var->type);
}
/* Obtain the type of an object variable. */
return attributes;
}
+int
+varobj_pretty_printed_p (struct varobj *var)
+{
+ return var->pretty_printer != NULL;
+}
+
char *
varobj_get_formatted_value (struct varobj *var,
enum varobj_display_formats format)
varobj_set_value (struct varobj *var, char *expression)
{
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;
char *s = expression;
- int i;
gdb_assert (varobj_editable_p (var));
return 1;
}
-/* Returns a malloc'ed list with all root variable objects */
-int
-varobj_list (struct varobj ***varlist)
+#if HAVE_PYTHON
+
+/* A helper function to install a constructor function and visualizer
+ in a varobj. */
+
+static void
+install_visualizer (struct varobj *var, PyObject *constructor,
+ PyObject *visualizer)
{
- struct varobj **cv;
- struct varobj_root *croot;
- int mycount = rootcount;
+ Py_XDECREF (var->constructor);
+ var->constructor = constructor;
+
+ Py_XDECREF (var->pretty_printer);
+ var->pretty_printer = visualizer;
+
+ Py_XDECREF (var->child_iter);
+ var->child_iter = NULL;
+}
- /* Alloc (rootcount + 1) entries for the result */
- *varlist = xmalloc ((rootcount + 1) * sizeof (struct varobj *));
+/* Install the default visualizer for VAR. */
- cv = *varlist;
- croot = rootlist;
- while ((croot != NULL) && (mycount > 0))
+static void
+install_default_visualizer (struct varobj *var)
+{
+ if (pretty_printing)
{
- *cv = croot->rootvar;
- mycount--;
- cv++;
- croot = croot->next;
+ PyObject *pretty_printer = NULL;
+
+ if (var->value)
+ {
+ pretty_printer = gdbpy_get_varobj_pretty_printer (var->value);
+ if (! pretty_printer)
+ {
+ gdbpy_print_stack ();
+ error (_("Cannot instantiate printer for default visualizer"));
+ }
+ }
+
+ if (pretty_printer == Py_None)
+ {
+ Py_DECREF (pretty_printer);
+ pretty_printer = NULL;
+ }
+
+ install_visualizer (var, NULL, pretty_printer);
}
- /* 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);
+/* Instantiate and install a visualizer for VAR using CONSTRUCTOR to
+ make a new object. */
+
+static void
+construct_visualizer (struct varobj *var, PyObject *constructor)
+{
+ PyObject *pretty_printer;
- return rootcount;
+ Py_INCREF (constructor);
+ if (constructor == Py_None)
+ pretty_printer = NULL;
+ else
+ {
+ pretty_printer = instantiate_pretty_printer (constructor, var->value);
+ if (! pretty_printer)
+ {
+ gdbpy_print_stack ();
+ Py_DECREF (constructor);
+ constructor = Py_None;
+ Py_INCREF (constructor);
+ }
+
+ if (pretty_printer == Py_None)
+ {
+ Py_DECREF (pretty_printer);
+ pretty_printer = NULL;
+ }
+ }
+
+ install_visualizer (var, constructor, pretty_printer);
+}
+
+#endif /* HAVE_PYTHON */
+
+/* A helper function for install_new_value. This creates and installs
+ a visualizer for VAR, if appropriate. */
+
+static void
+install_new_value_visualizer (struct varobj *var)
+{
+#if HAVE_PYTHON
+ /* If the constructor is None, then we want the raw value. If VAR
+ does not have a value, just skip this. */
+ if (var->constructor != Py_None && var->value)
+ {
+ struct cleanup *cleanup;
+
+ cleanup = varobj_ensure_python_env (var);
+
+ if (!var->constructor)
+ install_default_visualizer (var);
+ else
+ construct_visualizer (var, var->constructor);
+
+ do_cleanups (cleanup);
+ }
+#else
+ /* Do nothing. */
+#endif
}
/* 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.
+ Otherwise, assign the new value, and return 1 if the value is different
+ from the current one, 0 otherwise. The comparison is done on textual
+ representation of value. Therefore, some types need not be compared. E.g.
+ for structures the reported value is always "{...}", so no comparison is
+ necessary here. If the old value was NULL and new one is not, or vice versa,
+ we always return 1.
The VALUE parameter should not be released -- the function will
take care of releasing it when needed. */
a type. */
gdb_assert (var->type || CPLUS_FAKE_CHILD (var));
changeable = varobj_value_is_changeable_p (var);
+
+ /* If the type has custom visualizer, we consider it to be always
+ changeable. FIXME: need to make sure this behaviour will not
+ mess up read-sensitive values. */
+ if (var->pretty_printer)
+ changeable = 1;
+
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);
- }
+ value = coerce_ref (value);
if (var->type && TYPE_CODE (var->type) == TYPE_CODE_UNION)
/* For unions, we need to fetch the value implicitly because
{
struct varobj *parent = var->parent;
int frozen = var->frozen;
+
for (; !frozen && parent; parent = parent->parent)
frozen |= parent->frozen;
}
}
+
/* Below, we'll be comparing string rendering of old and new
values. Don't get string rendering if the value is
lazy -- if it is, the code above has decided that the value
should not be fetched. */
- if (value && !value_lazy (value))
- print_value = value_get_print_value (value, var->format);
+ if (value && !value_lazy (value) && !var->pretty_printer)
+ print_value = value_get_print_value (value, var->format, var);
/* 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
{
changed = 1;
}
- else
+ else if (! var->pretty_printer)
{
/* Try to compare the values. That requires that both
values are non-lazy. */
}
}
+ if (!initial && !changeable)
+ {
+ /* For values that are not changeable, we don't compare the values.
+ However, we want to notice if a value was not NULL and now is NULL,
+ or vise versa, so that we report when top-level varobjs come in scope
+ and leave the scope. */
+ changed = (var->value != NULL) != (value != NULL);
+ }
+
/* We must always keep the new value, since children depend on it. */
if (var->value != NULL && var->value != value)
value_free (var->value);
var->value = value;
- if (var->print_value)
- xfree (var->print_value);
- var->print_value = print_value;
+ if (value != NULL)
+ value_incref (value);
if (value && value_lazy (value) && intentionally_not_fetched)
var->not_fetched = 1;
else
var->not_fetched = 0;
var->updated = 0;
+ install_new_value_visualizer (var);
+
+ /* If we installed a pretty-printer, re-compare the printed version
+ to see if the variable changed. */
+ if (var->pretty_printer)
+ {
+ xfree (print_value);
+ print_value = value_get_print_value (var->value, var->format, var);
+ if ((var->print_value == NULL && print_value != NULL)
+ || (var->print_value != NULL && print_value == NULL)
+ || (var->print_value != NULL && print_value != NULL
+ && strcmp (var->print_value, print_value) != 0))
+ changed = 1;
+ }
+ if (var->print_value)
+ xfree (var->print_value);
+ var->print_value = print_value;
+
gdb_assert (!var->value || value_type (var->value));
return changed;
}
+/* Return the requested range for a varobj. VAR is the varobj. FROM
+ and TO are out parameters; *FROM and *TO will be set to the
+ selected sub-range of VAR. If no range was selected using
+ -var-set-update-range, then both will be -1. */
+void
+varobj_get_child_range (struct varobj *var, int *from, int *to)
+{
+ *from = var->from;
+ *to = var->to;
+}
+
+/* Set the selected sub-range of children of VAR to start at index
+ FROM and end at index TO. If either FROM or TO is less than zero,
+ this is interpreted as a request for all children. */
+void
+varobj_set_child_range (struct varobj *var, int from, int to)
+{
+ var->from = from;
+ var->to = to;
+}
+
+void
+varobj_set_visualizer (struct varobj *var, const char *visualizer)
+{
+#if HAVE_PYTHON
+ PyObject *mainmod, *globals, *constructor;
+ struct cleanup *back_to;
+
+ back_to = varobj_ensure_python_env (var);
+
+ mainmod = PyImport_AddModule ("__main__");
+ globals = PyModule_GetDict (mainmod);
+ Py_INCREF (globals);
+ make_cleanup_py_decref (globals);
+
+ constructor = PyRun_String (visualizer, Py_eval_input, globals, globals);
+
+ if (! constructor)
+ {
+ gdbpy_print_stack ();
+ error (_("Could not evaluate visualizer expression: %s"), visualizer);
+ }
+
+ construct_visualizer (var, constructor);
+ Py_XDECREF (constructor);
+
+ /* If there are any children now, wipe them. */
+ varobj_delete (var, NULL, 1 /* children only */);
+ var->num_children = -1;
+
+ do_cleanups (back_to);
+#else
+ error (_("Python support required"));
+#endif
+}
+
/* 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
int changed = 0;
int type_changed = 0;
int i;
- int vleft;
- struct varobj *v;
- struct varobj **cv;
- struct varobj **templist = NULL;
struct value *new;
- VEC (varobj_p) *stack = NULL;
+ VEC (varobj_update_result) *stack = NULL;
VEC (varobj_update_result) *result = NULL;
- struct frame_info *fi;
/* Frozen means frozen -- we don't check for any change in
this varobj, including its going out of scope, or
if (!(*varp)->root->is_valid)
{
- varobj_update_result r = {*varp};
+ varobj_update_result r = {0};
+
+ r.varobj = *varp;
r.status = VAROBJ_INVALID;
VEC_safe_push (varobj_update_result, result, &r);
return result;
if ((*varp)->root->rootvar == *varp)
{
- varobj_update_result r = {*varp};
+ varobj_update_result r = {0};
+
+ r.varobj = *varp;
r.status = VAROBJ_IN_SCOPE;
/* Update the root variable. value_of_root can return NULL
if (new == NULL)
r.status = VAROBJ_NOT_IN_SCOPE;
-
- if (r.type_changed || r.changed)
- VEC_safe_push (varobj_update_result, result, &r);
+ r.value_installed = 1;
if (r.status == VAROBJ_NOT_IN_SCOPE)
- return result;
+ {
+ if (r.type_changed || r.changed)
+ VEC_safe_push (varobj_update_result, result, &r);
+ return result;
+ }
+
+ VEC_safe_push (varobj_update_result, stack, &r);
}
+ else
+ {
+ varobj_update_result r = {0};
- VEC_safe_push (varobj_p, stack, *varp);
+ r.varobj = *varp;
+ VEC_safe_push (varobj_update_result, stack, &r);
+ }
/* Walk through the children, reconstructing them all. */
- while (!VEC_empty (varobj_p, stack))
+ while (!VEC_empty (varobj_update_result, stack))
{
- v = VEC_pop (varobj_p, stack);
+ varobj_update_result r = *(VEC_last (varobj_update_result, stack));
+ struct varobj *v = r.varobj;
+
+ VEC_pop (varobj_update_result, stack);
+
+ /* Update this variable, unless it's a root, which is already
+ updated. */
+ if (!r.value_installed)
+ {
+ new = value_of_child (v->parent, v->index);
+ if (install_new_value (v, new, 0 /* type not changed */))
+ {
+ r.changed = 1;
+ v->updated = 0;
+ }
+ }
+
+ /* We probably should not get children of a varobj that has a
+ pretty-printer, but for which -var-list-children was never
+ invoked. */
+ if (v->pretty_printer)
+ {
+ VEC (varobj_p) *changed = 0, *new = 0, *unchanged = 0;
+ int i, children_changed = 0;
+
+ if (v->frozen)
+ continue;
+
+ if (!v->children_requested)
+ {
+ int dummy;
+
+ /* If we initially did not have potential children, but
+ now we do, consider the varobj as changed.
+ Otherwise, if children were never requested, consider
+ it as unchanged -- presumably, such varobj is not yet
+ expanded in the UI, so we need not bother getting
+ it. */
+ if (!varobj_has_more (v, 0))
+ {
+ update_dynamic_varobj_children (v, NULL, NULL, NULL,
+ &dummy, 0, 0, 0);
+ if (varobj_has_more (v, 0))
+ r.changed = 1;
+ }
+
+ if (r.changed)
+ VEC_safe_push (varobj_update_result, result, &r);
+
+ continue;
+ }
+
+ /* If update_dynamic_varobj_children returns 0, then we have
+ a non-conforming pretty-printer, so we skip it. */
+ if (update_dynamic_varobj_children (v, &changed, &new, &unchanged,
+ &children_changed, 1,
+ v->from, v->to))
+ {
+ if (children_changed || new)
+ {
+ r.children_changed = 1;
+ r.new = new;
+ }
+ /* Push in 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, changed) - 1; i >= 0; --i)
+ {
+ varobj_p tmp = VEC_index (varobj_p, changed, i);
+ varobj_update_result r = {0};
+
+ r.varobj = tmp;
+ r.changed = 1;
+ r.value_installed = 1;
+ VEC_safe_push (varobj_update_result, stack, &r);
+ }
+ for (i = VEC_length (varobj_p, unchanged) - 1; i >= 0; --i)
+ {
+ varobj_p tmp = VEC_index (varobj_p, unchanged, i);
+
+ if (!tmp->frozen)
+ {
+ varobj_update_result r = {0};
+
+ r.varobj = tmp;
+ r.value_installed = 1;
+ VEC_safe_push (varobj_update_result, stack, &r);
+ }
+ }
+ if (r.changed || r.children_changed)
+ VEC_safe_push (varobj_update_result, result, &r);
+
+ /* Free CHANGED and UNCHANGED, but not NEW, because NEW
+ has been put into the result vector. */
+ VEC_free (varobj_p, changed);
+ VEC_free (varobj_p, unchanged);
+
+ continue;
+ }
+ }
/* Push any children. Use reverse order so that the first
child is popped from the work stack first, and so
for (i = VEC_length (varobj_p, v->children)-1; i >= 0; --i)
{
varobj_p c = VEC_index (varobj_p, v->children, i);
+
/* Child may be NULL if explicitly deleted by -var-delete. */
if (c != NULL && !c->frozen)
- VEC_safe_push (varobj_p, stack, c);
- }
-
- /* Update this variable, unless it's a root, which is already
- updated. */
- if (v->root->rootvar != v)
- {
- new = value_of_child (v->parent, v->index);
- if (install_new_value (v, new, 0 /* type not changed */))
{
- /* Note that it's changed */
- varobj_update_result r = {v};
- r.changed = 1;
- VEC_safe_push (varobj_update_result, result, &r);
- v->updated = 0;
+ varobj_update_result r = {0};
+
+ r.varobj = c;
+ VEC_safe_push (varobj_update_result, stack, &r);
}
}
+
+ if (r.changed || r.type_changed)
+ VEC_safe_push (varobj_update_result, result, &r);
}
- VEC_free (varobj_p, stack);
+ VEC_free (varobj_update_result, stack);
+
return result;
}
\f
for (i = 0; i < VEC_length (varobj_p, var->children); ++i)
{
varobj_p child = VEC_index (varobj_p, var->children, i);
+
if (!child)
continue;
if (!remove_from_parent_p)
else
var->root->next = rootlist;
rootlist = var->root;
- rootcount++;
}
return 1; /* OK */
else
prer->next = cr->next;
}
- rootcount--;
}
}
/* Create and install a child of the parent of the given name */
static struct varobj *
create_child (struct varobj *parent, int index, char *name)
+{
+ return create_child_with_value (parent, index, name,
+ value_of_child (parent, index));
+}
+
+static struct varobj *
+create_child_with_value (struct varobj *parent, int index, const char *name,
+ struct value *value)
{
struct varobj *child;
char *childs_name;
- struct value *value;
child = new_variable ();
/* name is allocated by name_of_child */
- child->name = name;
+ /* FIXME: xstrdup should not be here. */
+ child->name = xstrdup (name);
child->index = index;
- value = value_of_child (parent, index);
child->parent = parent;
child->root = parent->root;
childs_name = xstrprintf ("%s.%s", parent->obj_name, name);
var->print_value = NULL;
var->frozen = 0;
var->not_fetched = 0;
+ var->children_requested = 0;
+ var->from = -1;
+ var->to = -1;
+ var->constructor = 0;
+ var->pretty_printer = 0;
+ var->child_iter = 0;
+ var->saved_item = 0;
return var;
}
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;
static void
free_variable (struct varobj *var)
{
+#if HAVE_PYTHON
+ if (var->pretty_printer)
+ {
+ struct cleanup *cleanup = varobj_ensure_python_env (var);
+ Py_XDECREF (var->constructor);
+ Py_XDECREF (var->pretty_printer);
+ Py_XDECREF (var->child_iter);
+ Py_XDECREF (var->saved_item);
+ do_cleanups (cleanup);
+ }
+#endif
+
+ value_free (var->value);
+
/* Free the expression if this is a root variable. */
if (is_root_p (var))
{
- free_current_contents (&var->root->exp);
+ xfree (var->root->exp);
xfree (var->root);
}
get_type (struct varobj *var)
{
struct type *type;
- type = var->type;
+ type = var->type;
if (type != NULL)
type = check_typedef (type);
correct in other frames, so update the expression. */
struct expression *tmp_exp = var->root->exp;
+
var->root->exp = tmp_var->root->exp;
tmp_var->root->exp = tmp_exp;
}
else
{
- tmp_var->obj_name =
- savestring (var->obj_name, strlen (var->obj_name));
+ tmp_var->obj_name = xstrdup (var->obj_name);
+ tmp_var->from = var->from;
+ tmp_var->to = var->to;
varobj_delete (var, NULL, 0);
install_variable (tmp_var);
my_value_of_variable (struct varobj *var, enum varobj_display_formats format)
{
if (var->root->is_valid)
- return (*var->root->lang->value_of_variable) (var, format);
+ {
+ if (var->pretty_printer)
+ return value_get_print_value (var->value, var->format, var);
+ return (*var->root->lang->value_of_variable) (var, format);
+ }
else
return NULL;
}
static char *
-value_get_print_value (struct value *value, enum varobj_display_formats format)
+value_get_print_value (struct value *value, enum varobj_display_formats format,
+ struct varobj *var)
{
- long dummy;
struct ui_file *stb;
struct cleanup *old_chain;
- char *thevalue;
+ gdb_byte *thevalue = NULL;
+ struct value_print_options opts;
+ struct type *type = NULL;
+ long len = 0;
+ char *encoding = NULL;
+ struct gdbarch *gdbarch = NULL;
if (value == NULL)
return NULL;
+ gdbarch = get_type_arch (value_type (value));
+#if HAVE_PYTHON
+ {
+ struct cleanup *back_to = varobj_ensure_python_env (var);
+ PyObject *value_formatter = var->pretty_printer;
+
+ if (value_formatter)
+ {
+ /* First check to see if we have any children at all. If so,
+ we simply return {...}. */
+ if (dynamic_varobj_has_child_method (var))
+ return xstrdup ("{...}");
+
+ if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst))
+ {
+ char *hint;
+ struct value *replacement;
+ int string_print = 0;
+ PyObject *output = NULL;
+
+ hint = gdbpy_get_display_hint (value_formatter);
+ if (hint)
+ {
+ if (!strcmp (hint, "string"))
+ string_print = 1;
+ xfree (hint);
+ }
+
+ output = apply_varobj_pretty_printer (value_formatter,
+ &replacement);
+ if (output)
+ {
+ if (gdbpy_is_lazy_string (output))
+ {
+ thevalue = gdbpy_extract_lazy_string (output, &type,
+ &len, &encoding);
+ string_print = 1;
+ }
+ else
+ {
+ PyObject *py_str
+ = python_string_to_target_python_string (output);
+
+ if (py_str)
+ {
+ char *s = PyString_AsString (py_str);
+
+ len = PyString_Size (py_str);
+ thevalue = xmemdup (s, len + 1, len + 1);
+ type = builtin_type (gdbarch)->builtin_char;
+ Py_DECREF (py_str);
+ }
+ }
+ Py_DECREF (output);
+ }
+ if (thevalue && !string_print)
+ {
+ do_cleanups (back_to);
+ xfree (encoding);
+ return thevalue;
+ }
+ if (replacement)
+ value = replacement;
+ }
+ }
+ do_cleanups (back_to);
+ }
+#endif
+
stb = mem_fileopen ();
old_chain = make_cleanup_ui_file_delete (stb);
- common_val_print (value, stb, format_code[(int) format], 1, 0, 0,
- current_language);
- thevalue = ui_file_xstrdup (stb, &dummy);
+ get_formatted_print_options (&opts, format_code[(int) format]);
+ opts.deref_ref = 0;
+ opts.raw = 1;
+ if (thevalue)
+ {
+ make_cleanup (xfree, thevalue);
+ make_cleanup (xfree, encoding);
+ LA_PRINT_STRING (stb, type, thevalue, len, encoding, 0, &opts);
+ }
+ else
+ common_val_print (value, stb, 0, &opts, current_language);
+ thevalue = ui_file_xstrdup (stb, NULL);
do_cleanups (old_chain);
return thevalue;
varobj_editable_p (struct varobj *var)
{
struct type *type;
- struct value *value;
if (!(var->root->is_valid && var->value && VALUE_LVAL (var->value)))
return 0;
value is not known.
If WAS_PTR is not NULL, set *WAS_PTR to 0 or 1
- depending on whether pointer was deferenced
+ depending on whether pointer was dereferenced
in this function. */
static void
adjust_value_for_child_access (struct value **value,
{
if (value && *value)
{
- int success = gdb_value_ind (*value, value);
+ int success = gdb_value_ind (*value, value);
+
if (!success)
*value = NULL;
}
{
case TYPE_CODE_ARRAY:
if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (target) > 0
- && TYPE_ARRAY_UPPER_BOUND_TYPE (type) != BOUND_CANNOT_BE_DETERMINED)
+ && !TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (type))
children = TYPE_LENGTH (type) / TYPE_LENGTH (target);
else
/* If we don't know how many elements there are, don't display
static char *
c_name_of_variable (struct varobj *parent)
{
- return savestring (parent->name, strlen (parent->name));
+ return xstrdup (parent->name);
}
/* Return the value of element TYPE_INDEX of a structure
{
struct value *result = NULL;
volatile struct gdb_exception e;
-
struct type *type = value_type (value);
+
type = check_typedef (type);
gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT
TRY_CATCH (e, RETURN_MASK_ERROR)
{
- if (TYPE_FIELD_STATIC (type, type_index))
+ if (field_is_static (&TYPE_FIELD (type, type_index)))
result = value_static_field (type, type_index);
else
result = value_primitive_field (value, 0, type_index, type);
{
case TYPE_CODE_ARRAY:
if (cname)
- *cname = xstrprintf ("%d", index
- + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type)));
+ *cname = xstrdup (int_string (index
+ + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type)),
+ 10, 1, 0, 0));
if (cvalue && value)
{
int real_index = index + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type));
- struct value *indval =
- value_from_longest (builtin_type_int32, (LONGEST) real_index);
- gdb_value_subscript (value, indval, cvalue);
+
+ gdb_value_subscript (value, real_index, cvalue);
}
if (ctype)
*ctype = get_target_type (type);
if (cfull_expression)
- *cfull_expression = xstrprintf ("(%s)[%d]", parent_expression,
- index
- + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type)));
+ *cfull_expression =
+ xstrprintf ("(%s)[%s]", parent_expression,
+ int_string (index
+ + TYPE_LOW_BOUND (TYPE_INDEX_TYPE (type)),
+ 10, 1, 0, 0));
break;
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
if (cname)
- {
- char *string = TYPE_FIELD_NAME (type, index);
- *cname = savestring (string, strlen (string));
- }
+ *cname = xstrdup (TYPE_FIELD_NAME (type, index));
if (cvalue && value)
{
if (cfull_expression)
{
char *join = was_ptr ? "->" : ".";
+
*cfull_expression = xstrprintf ("(%s)%s%s", parent_expression, join,
TYPE_FIELD_NAME (type, index));
}
if (cvalue && value)
{
int success = gdb_value_ind (value, cvalue);
+
if (!success)
*cvalue = NULL;
}
c_name_of_child (struct varobj *parent, int index)
{
char *name;
+
c_describe_child (parent, index, &name, NULL, NULL, NULL);
return name;
}
if (fi)
{
CORE_ADDR pc = get_frame_pc (fi);
+
if (pc < BLOCK_START (var->root->valid_block) ||
pc >= BLOCK_END (var->root->valid_block))
scope = 0;
{
struct value *new_val = NULL;
struct varobj *var = *var_handle;
- struct frame_info *fi;
int within_scope = 0;
struct cleanup *back_to;
c_value_of_child (struct varobj *parent, int index)
{
struct value *value = NULL;
- c_describe_child (parent, index, NULL, &value, NULL, NULL);
+ c_describe_child (parent, index, NULL, &value, NULL, NULL);
return value;
}
c_type_of_child (struct varobj *parent, int index)
{
struct type *type = NULL;
+
c_describe_child (parent, index, NULL, NULL, &type, NULL);
return type;
}
catch that case explicitly. */
struct type *type = get_type (var);
+ /* If we have a custom formatter, return whatever string it has
+ produced. */
+ if (var->pretty_printer && var->print_value)
+ return xstrdup (var->print_value);
+
/* Strip top-level references. */
while (TYPE_CODE (type) == TYPE_CODE_REF)
type = check_typedef (TYPE_TARGET_TYPE (type));
case TYPE_CODE_ARRAY:
{
char *number;
+
number = xstrprintf ("[%d]", var->num_children);
return (number);
}
if (format == var->format)
return xstrdup (var->print_value);
else
- return value_get_print_value (var->value, format);
+ return value_get_print_value (var->value, format, var);
}
}
}
static void
cplus_class_num_children (struct type *type, int children[3])
{
- int i;
+ int i, vptr_fieldno;
+ struct type *basetype = NULL;
children[v_public] = 0;
children[v_private] = 0;
children[v_protected] = 0;
+ vptr_fieldno = get_vptr_fieldno (type, &basetype);
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)
+ /* If we have a virtual table pointer, omit it. Even if virtual
+ table pointers are not specifically marked in the debug info,
+ they should be artificial. */
+ if ((type == basetype && i == vptr_fieldno)
+ || TYPE_FIELD_ARTIFICIAL (type, i))
continue;
if (TYPE_FIELD_PROTECTED (type, i))
char **cname, struct value **cvalue, struct type **ctype,
char **cfull_expression)
{
- char *name = NULL;
struct value *value;
struct type *type;
int was_ptr;
|| TYPE_CODE (type) == TYPE_CODE_UNION)
{
char *join = was_ptr ? "->" : ".";
+
if (CPLUS_FAKE_CHILD (parent))
{
/* The fields of the class type are ordered as they
find the indexed field. */
int type_index = TYPE_N_BASECLASSES (type);
enum accessibility acc = public_field;
+ int vptr_fieldno;
+ struct type *basetype = NULL;
+
+ vptr_fieldno = get_vptr_fieldno (type, &basetype);
if (strcmp (parent->name, "private") == 0)
acc = private_field;
else if (strcmp (parent->name, "protected") == 0)
while (index >= 0)
{
- if (TYPE_VPTR_BASETYPE (type) == type
- && type_index == TYPE_VPTR_FIELDNO (type))
+ if ((type == basetype && type_index == vptr_fieldno)
+ || TYPE_FIELD_ARTIFICIAL (type, type_index))
; /* ignore vptr */
else if (match_accessibility (type, type_index, acc))
--index;
*cname = xstrdup (TYPE_FIELD_NAME (type, index));
if (cvalue && value)
- {
- *cvalue = value_cast (TYPE_FIELD_TYPE (type, index), value);
- release_value (*cvalue);
- }
+ *cvalue = value_cast (TYPE_FIELD_TYPE (type, index), value);
if (ctype)
{
if (cfull_expression)
{
char *ptr = was_ptr ? "*" : "";
+
/* Cast the parent to the base' type. Note that in gdb,
expression like
(Base1)d
{
char *access = NULL;
int children[3];
+
cplus_class_num_children (type, children);
/* Everything beyond the baseclasses can
cplus_name_of_child (struct varobj *parent, int index)
{
char *name = NULL;
+
cplus_describe_child (parent, index, &name, NULL, NULL, NULL);
return name;
}
cplus_value_of_child (struct varobj *parent, int index)
{
struct value *value = NULL;
+
cplus_describe_child (parent, index, NULL, &value, NULL, NULL);
return value;
}
cplus_type_of_child (struct varobj *parent, int index)
{
struct type *type = NULL;
+
cplus_describe_child (parent, index, NULL, NULL, &type, NULL);
return type;
}
static char *
-cplus_value_of_variable (struct varobj *var, enum varobj_display_formats format)
+cplus_value_of_variable (struct varobj *var,
+ enum varobj_display_formats format)
{
/* If we have one of our special types, don't print out
{
return cplus_value_of_variable (var, format);
}
+
+/* Iterate all the existing _root_ VAROBJs and call the FUNC callback for them
+ with an arbitrary caller supplied DATA pointer. */
+
+void
+all_root_varobjs (void (*func) (struct varobj *var, void *data), void *data)
+{
+ struct varobj_root *var_root, *var_root_next;
+
+ /* Iterate "safely" - handle if the callee deletes its passed VAROBJ. */
+
+ for (var_root = rootlist; var_root != NULL; var_root = var_root_next)
+ {
+ var_root_next = var_root->next;
+
+ (*func) (var_root->rootvar, data);
+ }
+}
\f
extern void _initialize_varobj (void);
void
&setlist, &showlist);
}
+/* Invalidate varobj VAR if it is tied to locals and re-create it if it is
+ defined on globals. It is a helper for varobj_invalidate. */
+
+static void
+varobj_invalidate_iter (struct varobj *var, void *unused)
+{
+ /* Floating varobjs are reparsed on each stop, so we don't care if the
+ presently parsed expression refers to something that's gone. */
+ if (var->root->floating)
+ return;
+
+ /* global var must be re-evaluated. */
+ if (var->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, var->name, (CORE_ADDR) 0,
+ USE_CURRENT_FRAME);
+ if (tmp_var != NULL)
+ {
+ tmp_var->obj_name = xstrdup (var->obj_name);
+ varobj_delete (var, NULL, 0);
+ install_variable (tmp_var);
+ }
+ else
+ var->root->is_valid = 0;
+ }
+ else /* locals must be invalidated. */
+ var->root->is_valid = 0;
+}
+
/* 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)
- {
- /* Floating varobjs are reparsed on each stop, so we don't care if
- the presently parsed expression refers to something that's gone. */
- if ((*varp)->root->floating)
- continue;
-
- /* 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;
+ all_root_varobjs (varobj_invalidate_iter, NULL);
}