@@ -534,8 +534,16 @@ class ada_assign_operation
assignment. */
value *eval_for_resolution (struct expression *exp)
{
- return std::get<0> (m_storage)->evaluate (nullptr, exp,
- EVAL_AVOID_SIDE_EFFECTS);
+ operation *lhs_op = std::get<0> (m_storage).get ();
+
+ /* If the operation is an internalvar that was not initialized at
+ parse time, ensure that it exists. */
+ auto *uninit_var_op = dynamic_cast<uninit_internalvar_operation *>
+ (lhs_op);
+ if (uninit_var_op != nullptr)
+ lookup_internalvar (uninit_var_op->get_name ());
+
+ return lhs_op->evaluate (nullptr, exp, EVAL_AVOID_SIDE_EFFECTS);
}
/* The parser must construct the assignment node before parsing the
@@ -1668,6 +1668,33 @@ register_operation::do_generate_ax (struct expression *exp,
value->type = register_type (ax->gdbarch, reg);
}
+/* Generate remote agent bytecode for the operation that accesses a
+ yet-to-be-initialized internalvar. */
+void
+uninit_internalvar_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ const char *name = get_name ();
+ struct internalvar *var = lookup_only_internalvar (name);
+ struct trace_state_variable *tsv;
+
+ tsv = find_trace_state_variable (name);
+ if (tsv != nullptr)
+ {
+ ax_tsv (ax, aop_getv, tsv->number);
+ if (ax->tracing)
+ ax_tsv (ax, aop_tracev, tsv->number);
+ /* Trace state variables are always 64-bit integers. */
+ value->kind = axs_rvalue;
+ value->type = builtin_type (ax->gdbarch)->builtin_long_long;
+ }
+ else if (!compile_internalvar_to_ax (var, ax, value))
+ error (_("$%s is not a trace state variable; GDB agent "
+ "expressions cannot use convenience variables."), name);
+}
+
void
internalvar_operation::do_generate_ax (struct expression *exp,
struct agent_expr *ax,
@@ -1679,7 +1706,7 @@ internalvar_operation::do_generate_ax (struct expression *exp,
struct trace_state_variable *tsv;
tsv = find_trace_state_variable (name);
- if (tsv)
+ if (tsv != nullptr)
{
ax_tsv (ax, aop_getv, tsv->number);
if (ax->tracing)
@@ -1688,7 +1715,7 @@ internalvar_operation::do_generate_ax (struct expression *exp,
value->kind = axs_rvalue;
value->type = builtin_type (ax->gdbarch)->builtin_long_long;
}
- else if (! compile_internalvar_to_ax (var, ax, value))
+ else if (!compile_internalvar_to_ax (var, ax, value))
error (_("$%s is not a trace state variable; GDB agent "
"expressions cannot use convenience variables."), name);
}
@@ -1911,6 +1938,26 @@ op_this_operation::do_generate_ax (struct expression *exp,
sym->print_name ());
}
+/* Get the name of the internalvar referenced by an operation, or
+ nullptr if the operation does not reference an internalvar. */
+static const char *
+internalvar_op_name (operation *op)
+{
+ gdb_assert (op->opcode () == OP_INTERNALVAR);
+
+ internalvar_operation *ivar_op
+ = dynamic_cast<internalvar_operation *> (op);
+ if (ivar_op != nullptr)
+ return internalvar_name (ivar_op->get_internalvar ());
+
+ uninit_internalvar_operation *uninit_ivar_op
+ = dynamic_cast<uninit_internalvar_operation *> (op);
+ if (uninit_ivar_op != nullptr)
+ return uninit_ivar_op->get_name ();
+
+ return nullptr;
+}
+
void
assign_operation::do_generate_ax (struct expression *exp,
struct agent_expr *ax,
@@ -1921,10 +1968,7 @@ assign_operation::do_generate_ax (struct expression *exp,
if (subop->opcode () != OP_INTERNALVAR)
error (_("May only assign to trace state variables"));
- internalvar_operation *ivarop
- = gdb::checked_static_cast<internalvar_operation *> (subop);
-
- const char *name = internalvar_name (ivarop->get_internalvar ());
+ const char *name = internalvar_op_name (subop);
struct trace_state_variable *tsv;
std::get<1> (m_storage)->generate_ax (exp, ax, value);
@@ -1950,10 +1994,7 @@ assign_modify_operation::do_generate_ax (struct expression *exp,
if (subop->opcode () != OP_INTERNALVAR)
error (_("May only assign to trace state variables"));
- internalvar_operation *ivarop
- = gdb::checked_static_cast<internalvar_operation *> (subop);
-
- const char *name = internalvar_name (ivarop->get_internalvar ());
+ const char *name = internalvar_op_name (subop);
struct trace_state_variable *tsv;
tsv = find_trace_state_variable (name);
@@ -49,7 +49,7 @@ get_ulongest (const char **pp, int trailer)
while (isalnum (*p) || *p == '_')
p++;
std::string varname (start, p - start);
- if (!get_internalvar_integer (lookup_internalvar (varname.c_str ()),
+ if (!get_internalvar_integer (lookup_only_internalvar (varname.c_str ()),
&retval))
error (_("Convenience variable $%s does not have integer value."),
varname.c_str ());
@@ -878,6 +878,42 @@ class bool_operation
{ return true; }
};
+/* Reference to a variable that had not been defined at parse time. */
+class uninit_internalvar_operation
+ : public tuple_holding_operation<std::string>
+{
+public:
+
+ using tuple_holding_operation::tuple_holding_operation;
+
+ value *evaluate (struct type *expect_type,
+ struct expression *exp,
+ enum noside noside) override
+ {
+ internalvar *iv = lookup_only_internalvar (std::get<0> (m_storage).c_str ());
+ if (iv == nullptr)
+ return value::allocate (builtin_type (exp->gdbarch)->builtin_void);
+
+ return value_of_internalvar (exp->gdbarch, iv);
+ }
+
+ const char *get_name () const
+ {
+ return std::get<0> (m_storage).c_str ();
+ }
+
+ enum exp_opcode opcode () const override
+ { return OP_INTERNALVAR; }
+
+protected:
+
+ void do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+ override;
+};
+
class internalvar_operation
: public tuple_holding_operation<internalvar *>
{
@@ -1891,7 +1927,16 @@ class assign_operation
struct expression *exp,
enum noside noside) override
{
- value *lhs = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
+ operation *lhs_op = std::get<0> (m_storage).get ();
+
+ /* If the operation is an internalvar that was not initialized at
+ parse time, ensure that it exists. */
+ auto *uninit_var_op = dynamic_cast<uninit_internalvar_operation *> (lhs_op);
+ if (uninit_var_op != nullptr)
+ lookup_internalvar (uninit_var_op->get_name ());
+
+ value *lhs = lhs_op->evaluate (nullptr, exp, noside);
+
/* Special-case assignments where the left-hand-side is a
convenience variable -- in these, don't bother setting an
expected type. This avoids a weird case where re-assigning a
@@ -1940,6 +1985,14 @@ class assign_modify_operation
struct expression *exp,
enum noside noside) override
{
+ operation *lhs_op = std::get<1> (m_storage).get ();
+
+ /* If the operation is an internalvar that was not initialized at
+ parse time, ensure that it exists. */
+ auto *uninit_var_op = dynamic_cast<uninit_internalvar_operation *> (lhs_op);
+ if (uninit_var_op != nullptr)
+ lookup_internalvar (uninit_var_op->get_name ());
+
value *lhs = std::get<1> (m_storage)->evaluate (nullptr, exp, noside);
value *rhs = std::get<2> (m_storage)->evaluate (expect_type, exp, noside);
return eval_binop_assign_modify (expect_type, exp, noside,
@@ -240,10 +240,9 @@ parser_state::push_dollar (struct stoken str)
return;
}
- /* Any other names are assumed to be debugger internal variables. */
-
- push_new<expr::internalvar_operation>
- (create_internalvar (copy.c_str () + 1));
+ /* Any other names are assumed to be debugger internal variables which
+ have not yet been initialized. */
+ push_new<expr::uninit_internalvar_operation> (copy.c_str () + 1);
}
/* See parser-defs.h. */