/* Implementation of the GDB variable objects API.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- 2009 Free Software Foundation, Inc.
+ 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 "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);
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);
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;
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
}
}
- install_default_visualizer (var);
discard_cleanups (old_chain);
return var;
}
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)
{
-#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;
printer = PyObject_CallFunctionObjArgs (constructor, val_obj, NULL);
Py_DECREF (val_obj);
return printer;
-#endif
return NULL;
}
+#endif
+
/* Set/Get variable object display format */
enum varobj_display_formats
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_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);
- make_cleanup_py_decref (children);
+ if (!children)
+ {
+ gdbpy_print_stack ();
+ error (_("Null value returned for children"));
+ }
- if (!PyIter_Check (children))
- error (_("Returned value is not iterable"));
+ make_cleanup_py_decref (children);
- iterator = PyObject_GetIter (children);
- if (!iterator)
- {
- gdbpy_print_stack ();
- error (_("Could not get children iterator"));
+ 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;
}
- 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"));
-
- v = convert_value_from_python (py_v);
+ /* 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);
- /* 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;
int i, children_changed;
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;
}
+#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);
- install_default_visualizer (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 */
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;
}
+#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)
+{
+ 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;
+}
+
+/* Install the default visualizer for VAR. */
+
+static void
+install_default_visualizer (struct varobj *var)
+{
+ if (pretty_printing)
+ {
+ 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);
+ }
+}
+
+/* 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;
+
+ 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
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;
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 == 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;
}
-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
varobj_set_visualizer (struct varobj *var, const char *visualizer)
{
#if HAVE_PYTHON
- PyObject *mainmod, *globals, *pretty_printer, *constructor;
- struct cleanup *back_to, *value;
+ PyObject *mainmod, *globals, *constructor;
+ struct cleanup *back_to;
back_to = varobj_ensure_python_env (var);
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
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_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
}
else
{
- varobj_update_result r = {*varp};
+ varobj_update_result r = {0};
+
+ r.varobj = *varp;
VEC_safe_push (varobj_update_result, stack, &r);
}
/* 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_update_result r = {tmp};
+ 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;
}
}
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)
{
- varobj_update_result r = {c};
+ varobj_update_result r = {0};
+
+ r.varobj = c;
VEC_safe_push (varobj_update_result, stack, &r);
}
}
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)
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;
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
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 = 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 value_print_options opts;
- int len = 0;
+ 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 && 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)
+ {
+ 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);
}
- Py_DECREF (output);
- }
- if (thevalue && !string_print)
- {
- do_cleanups (back_to);
- return thevalue;
+ if (thevalue && !string_print)
+ {
+ do_cleanups (back_to);
+ xfree (encoding);
+ return thevalue;
+ }
+ if (replacement)
+ value = replacement;
}
- if (replacement)
- value = replacement;
}
do_cleanups (back_to);
}
opts.raw = 1;
if (thevalue)
{
- struct gdbarch *gdbarch = get_type_arch (value_type (value));
make_cleanup (xfree, thevalue);
- LA_PRINT_STRING (stb, builtin_type (gdbarch)->builtin_char,
- thevalue, len, 0, &opts);
+ 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, &dummy);
+ 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;
{
if (value && *value)
{
- int success = gdb_value_ind (*value, value);
+ int success = gdb_value_ind (*value, value);
+
if (!success)
*value = NULL;
}
{
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
{
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));
+
gdb_value_subscript (value, real_index, cvalue);
}
*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;
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;
}
case TYPE_CODE_ARRAY:
{
char *number;
+
number = xstrprintf ("[%d]", var->num_children);
return (number);
}
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