#include "gdb_assert.h"
#include "gdb_string.h"
+#include "gdb_regex.h"
#include "varobj.h"
#include "vec.h"
/* 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
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 int install_new_value (struct varobj *var, struct value *value,
int initial);
-static void install_default_visualizer (struct varobj *var);
-
/* Language-specific routines. */
static enum varobj_languages variable_language (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 */
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);
}
}
- install_default_visualizer (var);
discard_cleanups (old_chain);
return var;
}
#if HAVE_PYTHON
PyObject *val_obj = NULL;
PyObject *printer;
- volatile struct gdb_exception except;
- TRY_CATCH (except, RETURN_MASK_ALL)
- {
- value = value_copy (value);
- }
- GDB_PY_HANDLE_EXCEPTION (except);
val_obj = value_to_value_object (value);
-
if (! val_obj)
return NULL;
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;
+ }
+}
+
+/* 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);
+ }
+}
+
+#if HAVE_PYTHON
+
+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_and_unchanged,
- int *cchanged)
-
+ VEC (varobj_p) **new,
+ VEC (varobj_p) **unchanged,
+ int *cchanged,
+ int update_children,
+ int from,
+ int to)
{
#if HAVE_PYTHON
- /* FIXME: we *might* want to provide this functionality as
- a standalone function, so that other interested parties
- than varobj code can benefit for this. */
struct cleanup *back_to;
PyObject *children;
- PyObject *iterator;
int i;
- int children_changed = 0;
PyObject *printer = var->pretty_printer;
back_to = varobj_ensure_python_env (var);
return 0;
}
- children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
- NULL);
-
- if (!children)
+ if (update_children || !var->child_iter)
{
- gdbpy_print_stack ();
- error (_("Null value returned for children"));
- }
+ children = PyObject_CallMethodObjArgs (printer, gdbpy_children_cst,
+ NULL);
+
+ if (!children)
+ {
+ gdbpy_print_stack ();
+ error (_("Null value returned for children"));
+ }
- make_cleanup_py_decref (children);
+ make_cleanup_py_decref (children);
- if (!PyIter_Check (children))
- error (_("Returned value is not iterable"));
+ if (!PyIter_Check (children))
+ error (_("Returned value is not iterable"));
- iterator = PyObject_GetIter (children);
- if (!iterator)
- {
- gdbpy_print_stack ();
- error (_("Could not get children iterator"));
+ 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;
}
- make_cleanup_py_decref (iterator);
+ else
+ i = VEC_length (varobj_p, var->children);
- for (i = 0; ; ++i)
+ /* 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 = PyIter_Next (iterator);
- PyObject *py_v;
- struct value *v;
- char *name;
- struct cleanup *inner;
-
- if (!item)
- break;
- inner = make_cleanup_py_decref (item);
+ PyObject *item;
- if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
- error (_("Invalid item from the child list"));
-
- if (PyObject_TypeCheck (py_v, &value_object_type))
+ /* See if there was a leftover from last time. */
+ if (var->saved_item)
{
- /* If we just call convert_value_from_python for this type,
- we won't know who owns the result. For this one case we
- need to copy the resulting value. */
- v = value_object_to_value (py_v);
- v = value_copy (v);
+ item = var->saved_item;
+ var->saved_item = NULL;
}
else
- v = convert_value_from_python (py_v);
+ item = PyIter_Next (var->child_iter);
- /* TODO: This assume the name of the i-th child never changes. */
+ if (!item)
+ break;
- /* Now see what to do here. */
- if (VEC_length (varobj_p, var->children) < i + 1)
+ /* We don't want to push the extra child on any report list. */
+ if (to < 0 || i < to)
{
- /* There's no child yet. */
- struct varobj *child = varobj_add_child (var, name, v);
- if (new_and_unchanged)
- VEC_safe_push (varobj_p, *new_and_unchanged, child);
- children_changed = 1;
+ 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
+ else
{
- varobj_p existing = VEC_index (varobj_p, var->children, i);
- if (install_new_value (existing, v, 0) && changed)
- {
- if (changed)
- VEC_safe_push (varobj_p, *changed, existing);
- }
- else
- {
- if (new_and_unchanged)
- VEC_safe_push (varobj_p, *new_and_unchanged, existing);
- }
- }
+ Py_XDECREF (var->saved_item);
+ var->saved_item = item;
- do_cleanups (inner);
+ /* We want to truncate the child list just before this
+ element. */
+ break;
+ }
}
if (i < VEC_length (varobj_p, var->children))
{
- int i;
- children_changed = 1;
- for (i = 0; i < VEC_length (varobj_p, var->children); ++i)
- varobj_delete (VEC_index (varobj_p, var->children, i), NULL, 0);
+ 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);
}
- 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);
- *cchanged = children_changed;
return 1;
#else
gdb_assert (0 && "should never be called if Python is not enabled");
{
if (var->num_children == -1)
{
- int changed;
- if (!var->pretty_printer
- || !update_dynamic_varobj_children (var, NULL, NULL, &changed))
+ 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;
var->children_requested = 1;
- if (var->pretty_printer
+ 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, &children_changed))
- return var->children;
+ 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);
name = name_of_child (var, i);
existing = create_child (var, i, name);
VEC_replace (varobj_p, var->children, i, existing);
- install_default_visualizer (existing);
}
}
+ restrict_range (var->children, from, to);
return var->children;
}
VEC_length (varobj_p, var->children),
name, value);
VEC_safe_push (varobj_p, var->children, v);
- install_default_visualizer (v);
return v;
}
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)
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;
- /* Alloc (rootcount + 1) entries for the result */
- *varlist = xmalloc ((rootcount + 1) * sizeof (struct varobj *));
+ Py_XDECREF (var->child_iter);
+ var->child_iter = NULL;
+}
- cv = *varlist;
- croot = rootlist;
- while ((croot != NULL) && (mycount > 0))
+/* Install the default visualizer for VAR. */
+
+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;
+}
+
+/* Instantiate and install a visualizer for VAR using CONSTRUCTOR to
+ make a new object. */
- if (mycount || (croot != NULL))
- warning
- ("varobj_list: assertion failed - wrong tally of root vars (%d:%d)",
- rootcount, mycount);
+static void
+construct_visualizer (struct varobj *var, PyObject *constructor)
+{
+ PyObject *pretty_printer;
+
+ 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);
+ }
- return rootcount;
+ 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;
+ PyObject *pretty_printer = NULL;
+
+ 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,
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
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))
+ 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.
{
changed = 1;
}
- else
+ else if (! var->pretty_printer)
{
/* Try to compare the values. That requires that both
values are non-lazy. */
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 || 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;
}
-static void
-install_visualizer (struct varobj *var, PyObject *visualizer)
+/* 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)
{
-#if HAVE_PYTHON
- /* If there are any children now, wipe them. */
- varobj_delete (var, NULL, 1 /* children only */);
- var->num_children = -1;
-
- Py_XDECREF (var->pretty_printer);
- var->pretty_printer = visualizer;
-
- install_new_value (var, var->value, 1);
-
- /* If we removed the visualizer, and the user ever requested the
- object's children, then we must compute the list of children.
- Note that we needn't do this when installing a visualizer,
- because updating will recompute dynamic children. */
- if (!visualizer && var->children_requested)
- varobj_list_children (var);
-#else
- error (_("Python support required"));
-#endif
+ *from = var->from;
+ *to = var->to;
}
-static void
-install_default_visualizer (struct varobj *var)
+/* 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)
{
-#if HAVE_PYTHON
- struct cleanup *cleanup;
- PyObject *pretty_printer = NULL;
-
- cleanup = varobj_ensure_python_env (var);
-
- 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, pretty_printer);
- do_cleanups (cleanup);
-#else
- /* No error is right as this function is inserted just as a hook. */
-#endif
+ var->from = from;
+ var->to = to;
}
void
make_cleanup_py_decref (globals);
constructor = PyRun_String (visualizer, Py_eval_input, globals, globals);
-
- /* Do not instantiate NoneType. */
- if (constructor == Py_None)
- {
- pretty_printer = Py_None;
- Py_INCREF (pretty_printer);
- }
- else
- pretty_printer = instantiate_pretty_printer (constructor, var->value);
-
- Py_XDECREF (constructor);
- if (! pretty_printer)
+ if (! constructor)
{
gdbpy_print_stack ();
error (_("Could not evaluate visualizer expression: %s"), visualizer);
}
- if (pretty_printer == Py_None)
- {
- Py_DECREF (pretty_printer);
- pretty_printer = NULL;
- }
+ construct_visualizer (var, constructor);
+ Py_XDECREF (constructor);
- install_visualizer (var, pretty_printer);
+ /* If there are any children now, wipe them. */
+ varobj_delete (var, NULL, 1 /* children only */);
+ var->num_children = -1;
do_cleanups (back_to);
#else
/* We probably should not get children of a varobj that has a
pretty-printer, but for which -var-list-children was never
- invoked. Presumably, such varobj is not yet expanded in the
- UI, so we need not bother getting it. */
+ invoked. */
if (v->pretty_printer)
{
- VEC (varobj_p) *changed = 0, *new_and_unchanged = 0;
- int i, children_changed;
- varobj_p tmp;
-
- if (!v->children_requested)
- continue;
+ 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_and_unchanged,
- &children_changed))
+ if (update_dynamic_varobj_children (v, &changed, &new, &unchanged,
+ &children_changed, 1,
+ v->from, v->to))
{
- if (children_changed)
- r.children_changed = 1;
- for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i)
+ if (children_changed || new)
{
- varobj_update_result r = {tmp};
- r.changed = 1;
- r.value_installed = 1;
- VEC_safe_push (varobj_update_result, stack, &r);
+ r.children_changed = 1;
+ r.new = new;
}
- for (i = 0;
- VEC_iterate (varobj_p, new_and_unchanged, i, tmp);
- ++i)
+ /* 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 = {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 = {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;
}
}
else
var->root->next = rootlist;
rootlist = var->root;
- rootcount++;
}
return 1; /* OK */
else
prer->next = cr->next;
}
- rootcount--;
}
}
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;
}
if (var->pretty_printer)
{
struct cleanup *cleanup = varobj_ensure_python_env (var);
- Py_DECREF (var->pretty_printer);
+ Py_XDECREF (var->constructor);
+ Py_XDECREF (var->pretty_printer);
+ Py_XDECREF (var->child_iter);
+ Py_XDECREF (var->saved_item);
do_cleanups (cleanup);
}
#endif
else
{
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;
}
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;
gdb_byte *thevalue = NULL;
struct cleanup *back_to = varobj_ensure_python_env (var);
PyObject *value_formatter = var->pretty_printer;
- if (value_formatter && PyObject_HasAttr (value_formatter,
- gdbpy_to_string_cst))
+ if (value_formatter)
{
- char *hint;
- struct value *replacement;
- int string_print = 0;
- PyObject *output = NULL;
+ /* 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 ("{...}");
- hint = gdbpy_get_display_hint (value_formatter);
- if (hint)
+ if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst))
{
- if (!strcmp (hint, "string"))
- string_print = 1;
- xfree (hint);
- }
+ 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)
- {
- 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);
- Py_DECREF (py_str);
+ output = apply_varobj_pretty_printer (value_formatter,
+ &replacement);
+ if (output)
+ {
+ 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);
+ Py_DECREF (py_str);
+ }
+ Py_DECREF (output);
}
- Py_DECREF (output);
- }
- if (thevalue && !string_print)
- {
- do_cleanups (back_to);
- return thevalue;
+ if (thevalue && !string_print)
+ {
+ do_cleanups (back_to);
+ return thevalue;
+ }
+ if (replacement)
+ value = replacement;
}
- if (replacement)
- value = replacement;
}
do_cleanups (back_to);
}
}
else
common_val_print (value, stb, 0, &opts, current_language);
- thevalue = ui_file_xstrdup (stb, &dummy);
+ thevalue = ui_file_xstrdup (stb, NULL);
do_cleanups (old_chain);
return thevalue;
{
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)
{
*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;
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))
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)
{
{
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 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". */
+/* 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. */
-void
-varobj_invalidate (void)
+static void
+varobj_invalidate_iter (struct varobj *var, void *unused)
{
- struct varobj **all_rootvarobj;
- struct varobj **varp;
+ /* 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;
- if (varobj_list (&all_rootvarobj) > 0)
+ /* global var must be re-evaluated. */
+ if (var->root->valid_block == NULL)
{
- for (varp = all_rootvarobj; *varp != NULL; varp++)
- {
- /* 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;
+ struct varobj *tmp_var;
- /* 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;
+ /* 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;
}
- xfree (all_rootvarobj);
- return;
+ 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)
+{
+ all_root_varobjs (varobj_invalidate_iter, NULL);
}