mi_gdb_test "-var-update $name" $er $testname
}
+# Update a dynamic varobj named NAME. CHILDREN is a list of children,
+# in the same form as mi_list_varobj_children. TESTNAME is the name
+# of the test.
+proc mi_varobj_update_dynamic {name children testname} {
+ set children_exp_j [mi_child_regexp $children 0]
+
+ set er "\\^done,changelist=\\\["
+
+ append er "{name=\"$name\",in_scope=\"true\",type_changed=\"false\""
+ append er ",children=\\\[$children_exp_j.*\\\]}\\\]"
+
+ verbose -log "Expecting: $er"
+ mi_gdb_test "-var-update $name" $er $testname
+}
+
proc mi_check_varobj_value { name value testname } {
mi_gdb_test "-var-evaluate-expression $name" \
$testname
}
+# Helper proc which constructs a child regexp for
+# mi_list_varobj_children and mi_varobj_update_dynamic.
+proc mi_child_regexp {children add_child} {
+ set children_exp {}
+ set whatever "\"\[^\"\]+\""
+
+ if {$add_child} {
+ set pre "child="
+ } else {
+ set pre ""
+ }
+
+ foreach item $children {
+
+ set name [lindex $item 0]
+ set exp [lindex $item 1]
+ set numchild [lindex $item 2]
+ if {[llength $item] == 5} {
+ set type [lindex $item 3]
+ set value [lindex $item 4]
+
+ lappend children_exp\
+ "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
+ } elseif {[llength $item] == 4} {
+ set type [lindex $item 3]
+
+ lappend children_exp\
+ "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
+ } else {
+ lappend children_exp\
+ "$pre{name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}"
+ }
+ }
+ return [join $children_exp ","]
+}
+
# Check the results of the:
#
# -var-list-children VARNAME
# have no value.
#
proc mi_list_varobj_children { varname children testname } {
+ mi_list_varobj_children_range $varname [llength $children] $children \
+ $testname
+}
+# Like mi_list_varobj_children, but assumes that a subrange has been
+# selected with -var-set-child-range. NUMCHILDREN is the total number
+# of children.
+proc mi_list_varobj_children_range {varname numchildren children testname} {
set options ""
if {[llength $varname] == 2} {
set options [lindex $varname 1]
set varname [lindex $varname 0]
}
- set numchildren [llength $children]
- set children_exp {}
set whatever "\"\[^\"\]+\""
- foreach item $children {
-
- set name [lindex $item 0]
- set exp [lindex $item 1]
- set numchild [lindex $item 2]
- if {[llength $item] == 5} {
- set type [lindex $item 3]
- set value [lindex $item 4]
-
- lappend children_exp\
- "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",value=\"$value\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
- } elseif {[llength $item] == 4} {
- set type [lindex $item 3]
-
- lappend children_exp\
- "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\",type=\"$type\"\(,thread-id=\"\[0-9\]+\")?}"
- } else {
- lappend children_exp\
- "child={name=\"$name\",exp=\"$exp\",numchild=\"$numchild\"(,thread-id=\"\[0-9\]+\")?}"
- }
- }
- set children_exp_j [join $children_exp ","]
+ set children_exp_j [mi_child_regexp $children 1]
if {$numchildren} {
set expected "\\^done,numchild=\".*\",children=\\\[$children_exp_j.*\\\]"
} {
verbose -log "expecting: $pattern"
mi_gdb_test "-thread-info" $pattern $test
}
+
+# Return a list of MI features supported by this gdb.
+proc mi_get_features {} {
+ global expect_out mi_gdb_prompt
+
+ send_gdb "-list-features\n"
+
+ gdb_expect {
+ -re "\\^done,features=\\\[(.*)\\\]\r\n$mi_gdb_prompt$" {
+ regsub -all -- \" $expect_out(1,string) "" features
+ return [split $features ,]
+ }
+ -re ".*\r\n$mi_gdb_prompt$" {
+ verbose -log "got $expect_out(buffer)"
+ return ""
+ }
+ timeout {
+ verbose -log "timeout in mi_gdb_prompt"
+ return ""
+ }
+ }
+}
#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;
/* 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;
+
+ /* The pretty-printer that has been constructed. If NULL, then a
+ new printer object is needed, and one will be constructed. */
+ PyObject *pretty_printer;
};
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);
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);
enum varobj_display_formats format);
static char *value_get_print_value (struct value *value,
- enum varobj_display_formats format);
+ enum varobj_display_formats format,
+ PyObject *value_formatter);
static int varobj_value_is_changeable_p (struct varobj *var);
static int is_root_p (struct varobj *var);
+static struct varobj *
+varobj_add_child (struct varobj *var, const char *name, struct value *value);
+
/* C implementation */
static int c_number_of_children (struct varobj *var);
}
}
+ install_default_visualizer (var);
discard_cleanups (old_chain);
return var;
}
return delcount;
}
+/* 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;
+}
+
/* 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->pretty_printer);
}
return var->format;
return var->format;
}
+char *
+varobj_get_display_hint (struct varobj *var)
+{
+ char *result = NULL;
+
+#if HAVE_PYTHON
+ PyGILState_STATE state = PyGILState_Ensure ();
+ if (var->pretty_printer)
+ result = gdbpy_get_display_hint (var->pretty_printer);
+ PyGILState_Release (state);
+#endif
+
+ return result;
+}
+
/* 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;
}
+static int
+update_dynamic_varobj_children (struct varobj *var,
+ VEC (varobj_p) **changed,
+ VEC (varobj_p) **new_and_unchanged,
+ int *cchanged)
+
+{
+#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;
+ PyGILState_STATE state;
+
+ state = PyGILState_Ensure ();
+ back_to = make_cleanup_py_restore_gil (&state);
+
+ *cchanged = 0;
+ if (!PyObject_HasAttr (printer, gdbpy_children_cst))
+ {
+ do_cleanups (back_to);
+ return 0;
+ }
+
+ 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");
+
+ iterator = PyObject_GetIter (children);
+ if (!iterator)
+ {
+ gdbpy_print_stack ();
+ error ("Could not get children iterator");
+ }
+ make_cleanup_py_decref (iterator);
+
+ for (i = 0; ; ++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);
+
+ if (!PyArg_ParseTuple (item, "sO", &name, &py_v))
+ error ("Invalid item from the child list");
+
+ if (PyObject_TypeCheck (py_v, &value_object_type))
+ {
+ /* 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);
+ }
+ else
+ v = convert_value_from_python (py_v);
+
+ /* TODO: This assume the name of the i-th child never changes. */
+
+ /* Now see what to do here. */
+ if (VEC_length (varobj_p, var->children) < i + 1)
+ {
+ /* 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;
+ }
+ 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);
+ }
+ }
+
+ do_cleanups (inner);
+ }
+
+ 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);
+ }
+ VEC_truncate (varobj_p, var->children, i);
+ 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");
+#endif
+}
int
varobj_get_num_children (struct varobj *var)
{
if (var->num_children == -1)
- var->num_children = number_of_children (var);
+ {
+ int changed;
+ if (!var->pretty_printer
+ || !update_dynamic_varobj_children (var, NULL, NULL, &changed))
+ var->num_children = number_of_children (var);
+ }
return var->num_children;
}
{
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, &children_changed))
+ 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);
}
}
return var->children;
}
+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;
+}
+
/* Obtain the type of an object Variable as a string similar to the one gdb
prints on the console */
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
}
}
+
/* 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);
+ print_value = value_get_print_value (value, var->format,
+ var->pretty_printer);
/* 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
return changed;
}
+static void
+install_visualizer (struct varobj *var, PyObject *visualizer)
+{
+#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
+}
+
+static void
+install_default_visualizer (struct varobj *var)
+{
+#if HAVE_PYTHON
+ struct cleanup *cleanup;
+ PyGILState_STATE state;
+ PyObject *pretty_printer = NULL;
+
+ state = PyGILState_Ensure ();
+ cleanup = make_cleanup_py_restore_gil (&state);
+
+ 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
+}
+
+void
+varobj_set_visualizer (struct varobj *var, const char *visualizer)
+{
+#if HAVE_PYTHON
+ PyObject *mainmod, *globals, *pretty_printer, *constructor;
+ struct cleanup *back_to, *value;
+ PyGILState_STATE state;
+
+
+ state = PyGILState_Ensure ();
+ back_to = make_cleanup_py_restore_gil (&state);
+
+ 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);
+
+ /* 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)
+ {
+ gdbpy_print_stack ();
+ error ("Could not evaluate visualizer expression: %s", visualizer);
+ }
+
+ if (pretty_printer == Py_None)
+ {
+ Py_DECREF (pretty_printer);
+ pretty_printer = NULL;
+ }
+
+ install_visualizer (var, pretty_printer);
+
+ 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
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;
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;
+ {
+ VEC_safe_push (varobj_update_result, result, &r);
+ return result;
+ }
+
+ VEC_safe_push (varobj_update_result, stack, &r);
+ }
+ else
+ {
+ varobj_update_result r = {*varp};
+ VEC_safe_push (varobj_update_result, stack, &r);
}
-
- VEC_safe_push (varobj_p, stack, *varp);
/* 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. Presumably, such varobj is not yet expanded in the
+ UI, so we need not bother getting it. */
+ 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;
+
+ if (v->frozen)
+ 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 (children_changed)
+ r.children_changed = 1;
+ for (i = 0; VEC_iterate (varobj_p, changed, i, tmp); ++i)
+ {
+ varobj_update_result r = {tmp};
+ r.changed = 1;
+ r.value_installed = 1;
+ VEC_safe_push (varobj_update_result, stack, &r);
+ }
+ for (i = 0;
+ VEC_iterate (varobj_p, new_and_unchanged, i, tmp);
+ ++i)
+ {
+ 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);
+ continue;
+ }
+ }
/* Push any children. Use reverse order so that the first
child is popped from the work stack first, and so
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 = {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
/* 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->pretty_printer = 0;
return var;
}
xfree (var->root);
}
+#if HAVE_PYTHON
+ {
+ PyGILState_STATE state = PyGILState_Ensure ();
+ Py_XDECREF (var->pretty_printer);
+ PyGILState_Release (state);
+ }
+#endif
+
xfree (var->name);
xfree (var->obj_name);
xfree (var->print_value);
}
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,
+ PyObject *value_formatter)
{
long dummy;
struct ui_file *stb;
struct cleanup *old_chain;
- char *thevalue;
+ char *thevalue = NULL;
struct value_print_options opts;
if (value == NULL)
return NULL;
+#if HAVE_PYTHON
+ {
+ PyGILState_STATE state = PyGILState_Ensure ();
+ if (value_formatter && PyObject_HasAttr (value_formatter,
+ gdbpy_to_string_cst))
+ {
+ char *hint;
+ struct value *replacement;
+ int string_print = 0;
+
+ hint = gdbpy_get_display_hint (value_formatter);
+ if (hint)
+ {
+ if (!strcmp (hint, "string"))
+ string_print = 1;
+ xfree (hint);
+ }
+
+ thevalue = apply_varobj_pretty_printer (value_formatter,
+ &replacement);
+ if (thevalue && !string_print)
+ {
+ PyGILState_Release (state);
+ return thevalue;
+ }
+ if (replacement)
+ value = replacement;
+ }
+ PyGILState_Release (state);
+ }
+#endif
+
stb = mem_fileopen ();
old_chain = make_cleanup_ui_file_delete (stb);
get_formatted_print_options (&opts, format_code[(int) format]);
opts.deref_ref = 0;
- common_val_print (value, stb, 0, &opts, current_language);
+ opts.raw = 1;
+ if (thevalue)
+ {
+ make_cleanup (xfree, thevalue);
+ LA_PRINT_STRING (stb, builtin_type (current_gdbarch)->builtin_char,
+ (gdb_byte *) thevalue, strlen (thevalue),
+ 0, &opts);
+ }
+ else
+ common_val_print (value, stb, 0, &opts, current_language);
thevalue = ui_file_xstrdup (stb, &dummy);
do_cleanups (old_chain);
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,
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));
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->pretty_printer);
}
}
}