/* Implementation of the GDB variable objects API.
- Copyright (C) 1999-2022 Free Software Foundation, Inc.
+ Copyright (C) 1999-2023 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
to symbols that do not exist anymore. */
bool is_valid = true;
+ /* Set to true if the varobj was created as tracking a global. */
+ bool global = false;
+
/* Language-related operations for this variable and its
children. */
const struct lang_varobj_ops *lang_ops = NULL;
/* Return the full FRAME which corresponds to the given CORE_ADDR
or NULL if no FRAME on the chain corresponds to CORE_ADDR. */
-static struct frame_info *
+static frame_info_ptr
find_frame_addr_in_frame_chain (CORE_ADDR frame_addr)
{
- struct frame_info *frame = NULL;
+ frame_info_ptr frame = NULL;
if (frame_addr == (CORE_ADDR) 0)
return NULL;
if (expression != NULL)
{
- struct frame_info *fi;
+ frame_info_ptr fi;
struct frame_id old_id = null_frame_id;
const struct block *block;
const char *p;
var->format = variable_default_display (var.get ());
var->root->valid_block =
var->root->floating ? NULL : tracker.block ();
+ var->root->global
+ = var->root->floating ? false : var->root->valid_block == nullptr;
var->name = expression;
/* For a root var, the name and the expr are the same. */
var->path_expr = expression;
select_frame (fi);
}
- /* We definitely need to catch errors here.
- If evaluate_expression succeeds we got the value we wanted.
- But if it fails, we still go on with a call to evaluate_type(). */
+ /* We definitely need to catch errors here. If evaluation of
+ the expression succeeds, we got the value we wanted. But if
+ it fails, we still go on with a call to evaluate_type(). */
try
{
- value = evaluate_expression (var->root->exp.get ());
+ value = var->root->exp->evaluate ();
}
catch (const gdb_exception_error &except)
{
/* Error getting the value. Try to at least get the
right type. */
- struct value *type_only_value = evaluate_type (var->root->exp.get ());
+ struct value *type_only_value = var->root->exp->evaluate_type ();
- var->type = value_type (type_only_value);
+ var->type = type_only_value->type ();
}
if (value != NULL)
}
if (varobj_value_is_changeable_p (var)
- && var->value != nullptr && !value_lazy (var->value.get ()))
+ && var->value != nullptr && !var->value->lazy ())
{
var->print_value = varobj_value_get_print_value (var->value.get (),
var->format, var);
}
}
-#if HAVE_PYTHON
-
-static bool
-dynamic_varobj_has_child_method (const struct varobj *var)
-{
- PyObject *printer = var->dynamic->pretty_printer;
-
- if (!gdb_python_initialized)
- return false;
-
- gdbpy_enter_varobj enter_py (var);
- return PyObject_HasAttr (printer, gdbpy_children_cst);
-}
-#endif
-
/* A factory for creating dynamic varobj's iterators. Returns an
iterator object suitable for iterating over VAR's children. */
We need to first construct a legal expression for this -- ugh! */
/* Does this cover all the bases? */
struct value *value = NULL; /* Initialize to keep gcc happy. */
- int saved_input_radix = input_radix;
const char *s = expression;
gdb_assert (varobj_editable_p (var));
- input_radix = 10; /* ALWAYS reset to decimal temporarily. */
+ /* ALWAYS reset to decimal temporarily. */
+ auto save_input_radix = make_scoped_restore (&input_radix, 10);
expression_up exp = parse_exp_1 (&s, 0, 0, 0);
try
{
- value = evaluate_expression (exp.get ());
+ value = exp->evaluate ();
}
catch (const gdb_exception_error &except)
gdb_assert (varobj_value_is_changeable_p (var));
/* The value of a changeable variable object must not be lazy. */
- gdb_assert (!value_lazy (var->value.get ()));
+ gdb_assert (!var->value->lazy ());
/* Need to coerce the input. We want to check if the
value of the variable object will be different
'updated' flag. There's no need to optimize that, because return value
of -var-update should be considered an approximation. */
var->updated = install_new_value (var, val, false /* Compare values. */);
- input_radix = saved_input_radix;
return true;
}
that is we'll be comparing values of this type, fetch the
value now. Otherwise, on the next update the old value
will be lazy, which means we've lost that old value. */
- if (need_to_fetch && value && value_lazy (value))
+ if (need_to_fetch && value && value->lazy ())
{
const struct varobj *parent = var->parent;
bool frozen = var->frozen;
try
{
- value_fetch_lazy (value);
+ value->fetch_lazy ();
}
catch (const gdb_exception_error &except)
lazy -- if it is, the code above has decided that the value
should not be fetched. */
std::string print_value;
- if (value != NULL && !value_lazy (value)
+ if (value != NULL && !value->lazy ()
&& var->dynamic->pretty_printer == NULL)
print_value = varobj_value_get_print_value (value, var->format, var);
{
/* Try to compare the values. That requires that both
values are non-lazy. */
- if (var->not_fetched && value_lazy (var->value.get ()))
+ if (var->not_fetched && var->value->lazy ())
{
/* This is a frozen varobj and the value was never read.
Presumably, UI shows some "never read" indicator.
}
else
{
- gdb_assert (!value_lazy (var->value.get ()));
- gdb_assert (!value_lazy (value));
+ gdb_assert (!var->value->lazy ());
+ gdb_assert (!value->lazy ());
gdb_assert (!var->print_value.empty () && !print_value.empty ());
if (var->print_value != print_value)
/* We must always keep the new value, since children depend on it. */
var->value = value_holder;
- if (value && value_lazy (value) && intentionally_not_fetched)
+ if (value && value->lazy () && intentionally_not_fetched)
var->not_fetched = true;
else
var->not_fetched = false;
}
var->print_value = print_value;
- gdb_assert (var->value == nullptr || value_type (var->value.get ()));
+ gdb_assert (var->value == nullptr || var->value->type ());
return changed;
}
if (update_type_if_necessary (v, newobj))
r.type_changed = true;
if (newobj)
- new_type = value_type (newobj);
+ new_type = newobj->type ();
else
new_type = v->root->lang_ops->type_of_child (v->parent, v->index);
struct type *type;
if (var->value != nullptr)
- type = value_type (var->value.get ());
+ type = var->value->type ();
else
type = var->type;
static bool
check_scope (const struct varobj *var)
{
- struct frame_info *fi;
+ frame_info_ptr fi;
bool scope;
fi = frame_find_by_id (var->root->frame);
expression fails we want to just return NULL. */
try
{
- new_val = evaluate_expression (var->root->exp.get ());
+ new_val = var->root->exp->evaluate ();
}
catch (const gdb_exception_error &except)
{
/* For root varobj-s, a NULL value indicates a scoping issue.
So, nothing to do in terms of checking for mutations. */
}
- else if (varobj_value_has_mutated (var, value, value_type (value)))
+ else if (varobj_value_has_mutated (var, value, value->type ()))
{
/* The type has mutated, so the children are no longer valid.
Just delete them, and tell our caller that the type has
enum varobj_display_formats format)
{
get_formatted_print_options (opts, format_code[(int) format]);
- opts->deref_ref = 0;
+ opts->deref_ref = false;
opts->raw = !pretty_printing;
}
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 "{...}";
-
if (PyObject_HasAttr (value_formatter, gdbpy_to_string_cst))
{
struct value *replacement;
&opts);
/* If we have string like output ... */
- if (output != NULL)
+ if (output != nullptr && output != Py_None)
{
/* If this is a lazy string, extract it. For lazy
strings we always print as a string, so set
thevalue = std::string (s.get ());
len = thevalue.size ();
- gdbarch = value_type (value)->arch ();
+ gdbarch = value->type ()->arch ();
type = builtin_type (gdbarch)->builtin_char;
if (!string_print)
if (replacement)
value = replacement;
}
+ else
+ {
+ /* No to_string method, so if there is a 'children'
+ method, return the default. */
+ if (PyObject_HasAttr (value_formatter, gdbpy_children_cst))
+ return "{...}";
+ }
}
}
#endif
struct type *type;
if (!(var->root->is_valid && var->value != nullptr
- && VALUE_LVAL (var->value.get ())))
+ && var->value->lval ()))
return false;
type = varobj_get_value_type (var);
}
}
-/* 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.
-
- This function is called after changing the symbol file, in this case the
- pointers to "struct type" stored by the varobj are no longer valid. All
- varobj must be either re-evaluated, or marked as invalid here. */
+/* Try to recreate the varobj VAR if it is a global or floating. This is a
+ helper function for varobj_re_set. */
static void
-varobj_invalidate_iter (struct varobj *var)
+varobj_re_set_iter (struct varobj *var)
{
- /* global and floating var must be re-evaluated. */
- if (var->root->floating || var->root->valid_block == NULL)
+ /* Invalidated global varobjs must be re-evaluated. */
+ if (!var->root->is_valid && var->root->global)
{
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.c_str (), (CORE_ADDR) 0,
+ and have a global replace the old varobj. */
+ tmp_var = varobj_create (nullptr, var->name.c_str (), (CORE_ADDR) 0,
USE_CURRENT_FRAME);
- if (tmp_var != NULL)
- {
+ if (tmp_var != nullptr && tmp_var->root->global)
+ {
tmp_var->obj_name = var->obj_name;
varobj_delete (var, 0);
install_variable (tmp_var);
}
- else
- var->root->is_valid = false;
}
- else /* locals must be invalidated. */
- var->root->is_valid = false;
}
-/* 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". */
+/* See varobj.h. */
void
-varobj_invalidate (void)
+varobj_re_set (void)
{
- all_root_varobjs (varobj_invalidate_iter);
+ all_root_varobjs (varobj_re_set_iter);
}
/* Ensure that no varobj keep references to OBJFILE. */
{
if (var->root->valid_block != nullptr)
{
- struct objfile *bl_objfile = block_objfile (var->root->valid_block);
+ struct objfile *bl_objfile = var->root->valid_block->objfile ();
if (bl_objfile->separate_debug_objfile_backlink != nullptr)
bl_objfile = bl_objfile->separate_debug_objfile_backlink;
{
/* The varobj is tied to a block which is going away. There is
no way to reconstruct something later, so invalidate the
- varobj completly and drop the reference to the block which is
+ varobj completely and drop the reference to the block which is
being freed. */
var->root->is_valid = false;
var->root->valid_block = nullptr;
}
}
- if (var->root->exp != nullptr
- && exp_uses_objfile (var->root->exp.get (), objfile))
+ if (var->root->exp != nullptr && var->root->exp->uses_objfile (objfile))
{
/* The varobj's current expression references the objfile. For
globals and floating, it is possible that when we try to
/* var->value->type and var->type might also reference the objfile.
This is taken care of in value.c:preserve_values which deals with
- making sure that objfile-owend types are replaced with
+ making sure that objfile-owned types are replaced with
gdbarch-owned equivalents. */
});
}