/* GDB-specific functions for operating on agent expressions.
- Copyright (C) 1998-2021 Free Software Foundation, Inc.
+ Copyright (C) 1998-2022 Free Software Foundation, Inc.
This file is part of GDB.
/* Prototypes for local functions. */
/* There's a standard order to the arguments of these functions:
- union exp_element ** --- pointer into expression
struct agent_expr * --- agent expression buffer to generate code into
struct axs_value * --- describes value left on top of stack */
-static struct value *const_var_ref (struct symbol *var);
-static struct value *const_expr (union exp_element **pc);
-static struct value *maybe_const_expr (union exp_element **pc);
-
static void gen_traced_pop (struct agent_expr *, struct axs_value *);
static void gen_sign_extend (struct agent_expr *, struct type *);
const char *operand_name);
static void gen_static_field (struct agent_expr *ax, struct axs_value *value,
struct type *type, int fieldno);
-static void gen_repeat (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value);
-static void gen_sizeof (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value,
- struct type *size_type);
-static void gen_expr_binop_rest (struct expression *exp,
- enum exp_opcode op, union exp_element **pc,
- struct agent_expr *ax,
- struct axs_value *value,
- struct axs_value *value1,
- struct axs_value *value2);
static void gen_expr_binop_rest (struct expression *exp,
enum exp_opcode op,
struct agent_expr *ax,
struct axs_value *value,
struct axs_value *value1,
struct axs_value *value2);
-\f
-
-/* Detecting constant expressions. */
-
-/* If the variable reference at *PC is a constant, return its value.
- Otherwise, return zero.
-
- Hey, Wally! How can a variable reference be a constant?
-
- Well, Beav, this function really handles the OP_VAR_VALUE operator,
- not specifically variable references. GDB uses OP_VAR_VALUE to
- refer to any kind of symbolic reference: function names, enum
- elements, and goto labels are all handled through the OP_VAR_VALUE
- operator, even though they're constants. It makes sense given the
- situation.
-
- Gee, Wally, don'cha wonder sometimes if data representations that
- subvert commonly accepted definitions of terms in favor of heavily
- context-specific interpretations are really just a tool of the
- programming hegemony to preserve their power and exclude the
- proletariat? */
-
-static struct value *
-const_var_ref (struct symbol *var)
-{
- struct type *type = SYMBOL_TYPE (var);
-
- switch (SYMBOL_CLASS (var))
- {
- case LOC_CONST:
- return value_from_longest (type, (LONGEST) SYMBOL_VALUE (var));
-
- case LOC_LABEL:
- return value_from_pointer (type, (CORE_ADDR) SYMBOL_VALUE_ADDRESS (var));
-
- default:
- return 0;
- }
-}
-
-
-/* If the expression starting at *PC has a constant value, return it.
- Otherwise, return zero. If we return a value, then *PC will be
- advanced to the end of it. If we return zero, *PC could be
- anywhere. */
-static struct value *
-const_expr (union exp_element **pc)
-{
- enum exp_opcode op = (*pc)->opcode;
- struct value *v1;
- switch (op)
- {
- case OP_LONG:
- {
- struct type *type = (*pc)[1].type;
- LONGEST k = (*pc)[2].longconst;
-
- (*pc) += 4;
- return value_from_longest (type, k);
- }
-
- case OP_VAR_VALUE:
- {
- struct value *v = const_var_ref ((*pc)[2].symbol);
-
- (*pc) += 4;
- return v;
- }
-
- /* We could add more operators in here. */
-
- case UNOP_NEG:
- (*pc)++;
- v1 = const_expr (pc);
- if (v1)
- return value_neg (v1);
- else
- return 0;
-
- default:
- return 0;
- }
-}
-
-
-/* Like const_expr, but guarantee also that *PC is undisturbed if the
- expression is not constant. */
-static struct value *
-maybe_const_expr (union exp_element **pc)
-{
- union exp_element *tentative_pc = *pc;
- struct value *v = const_expr (&tentative_pc);
-
- /* If we got a value, then update the real PC. */
- if (v)
- *pc = tentative_pc;
-
- return v;
-}
\f
/* Generating bytecode from GDB expressions: general assumptions */
break;
case LOC_COMPUTED:
- gdb_assert_not_reached (_("LOC_COMPUTED variable missing a method"));
+ gdb_assert_not_reached ("LOC_COMPUTED variable missing a method");
case LOC_OPTIMIZED_OUT:
/* Flag this, but don't say anything; leave it up to callers to
gen_ptradd (struct agent_expr *ax, struct axs_value *value,
struct axs_value *value1, struct axs_value *value2)
{
- gdb_assert (pointer_type (value1->type));
+ gdb_assert (value1->type->is_pointer_or_reference ());
gdb_assert (value2->type->code () == TYPE_CODE_INT);
gen_scale (ax, aop_mul, value1->type);
gen_ptrsub (struct agent_expr *ax, struct axs_value *value,
struct axs_value *value1, struct axs_value *value2)
{
- gdb_assert (pointer_type (value1->type));
+ gdb_assert (value1->type->is_pointer_or_reference ());
gdb_assert (value2->type->code () == TYPE_CODE_INT);
gen_scale (ax, aop_mul, value1->type);
struct axs_value *value1, struct axs_value *value2,
struct type *result_type)
{
- gdb_assert (pointer_type (value1->type));
- gdb_assert (pointer_type (value2->type));
+ gdb_assert (value1->type->is_pointer_or_reference ());
+ gdb_assert (value2->type->is_pointer_or_reference ());
if (TYPE_LENGTH (TYPE_TARGET_TYPE (value1->type))
!= TYPE_LENGTH (TYPE_TARGET_TYPE (value2->type)))
struct axs_value *value1, struct axs_value *value2,
struct type *result_type)
{
- if (pointer_type (value1->type) || pointer_type (value2->type))
+ if (value1->type->is_pointer_or_reference () || value2->type->is_pointer_or_reference ())
ax_simple (ax, aop_equal);
else
gen_binop (ax, value, value1, value2,
struct axs_value *value1, struct axs_value *value2,
struct type *result_type)
{
- if (pointer_type (value1->type) || pointer_type (value2->type))
+ if (value1->type->is_pointer_or_reference () || value2->type->is_pointer_or_reference ())
ax_simple (ax, aop_less_unsigned);
else
gen_binop (ax, value, value1, value2,
{
/* The caller should check the type, because several operators use
this, and we don't know what error message to generate. */
- if (!pointer_type (value->type))
+ if (!value->type->is_pointer_or_reference ())
internal_error (__FILE__, __LINE__,
_("gen_deref: expected a pointer"));
if (TYPE_FIELD_PACKED (type, fieldno))
gen_bitfield_ref (ax, value, type->field (fieldno).type (),
(offset * TARGET_CHAR_BIT
- + TYPE_FIELD_BITPOS (type, fieldno)),
+ + type->field (fieldno).loc_bitpos ()),
(offset * TARGET_CHAR_BIT
- + TYPE_FIELD_BITPOS (type, fieldno)
+ + type->field (fieldno).loc_bitpos ()
+ TYPE_FIELD_BITSIZE (type, fieldno)));
else
{
gen_offset (ax, offset
- + TYPE_FIELD_BITPOS (type, fieldno) / TARGET_CHAR_BIT);
+ + type->field (fieldno).loc_bitpos () / TARGET_CHAR_BIT);
value->kind = axs_lvalue_memory;
value->type = type->field (fieldno).type ();
}
for (i = type->num_fields () - 1; i >= nbases; i--)
{
- const char *this_name = TYPE_FIELD_NAME (type, i);
+ const char *this_name = type->field (i).name ();
if (this_name)
{
/* Follow pointers until we reach a non-pointer. These aren't the C
semantics, but they're what the normal GDB evaluator does, so we
should at least be consistent. */
- while (pointer_type (value->type))
+ while (value->type->is_pointer_or_reference ())
{
require_rvalue (ax, value);
gen_deref (value);
gen_static_field (struct agent_expr *ax, struct axs_value *value,
struct type *type, int fieldno)
{
- if (TYPE_FIELD_LOC_KIND (type, fieldno) == FIELD_LOC_KIND_PHYSADDR)
+ if (type->field (fieldno).loc_kind () == FIELD_LOC_KIND_PHYSADDR)
{
- ax_const_l (ax, TYPE_FIELD_STATIC_PHYSADDR (type, fieldno));
+ ax_const_l (ax, type->field (fieldno).loc_physaddr ());
value->kind = axs_lvalue_memory;
value->type = type->field (fieldno).type ();
value->optimized_out = 0;
}
else
{
- const char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
+ const char *phys_name = type->field (fieldno).loc_physname ();
struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0).symbol;
if (sym)
for (i = t->num_fields () - 1; i >= TYPE_N_BASECLASSES (t); i--)
{
- const char *t_field_name = TYPE_FIELD_NAME (t, i);
+ const char *t_field_name = t->field (i).name ();
if (t_field_name && strcmp (t_field_name, fieldname) == 0)
{
return 0;
}
-/* Generate code for GDB's magical `repeat' operator.
- LVALUE @ INT creates an array INT elements long, and whose elements
- have the same type as LVALUE, located in memory so that LVALUE is
- its first element. For example, argv[0]@argc gives you the array
- of command-line arguments.
-
- Unfortunately, because we have to know the types before we actually
- have a value for the expression, we can't implement this perfectly
- without changing the type system, having values that occupy two
- stack slots, doing weird things with sizeof, etc. So we require
- the right operand to be a constant expression. */
-static void
-gen_repeat (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value)
-{
- struct axs_value value1;
-
- /* We don't want to turn this into an rvalue, so no conversions
- here. */
- gen_expr (exp, pc, ax, &value1);
- if (value1.kind != axs_lvalue_memory)
- error (_("Left operand of `@' must be an object in memory."));
-
- /* Evaluate the length; it had better be a constant. */
- {
- struct value *v = const_expr (pc);
- int length;
-
- if (!v)
- error (_("Right operand of `@' must be a "
- "constant, in agent expressions."));
- if (value_type (v)->code () != TYPE_CODE_INT)
- error (_("Right operand of `@' must be an integer."));
- length = value_as_long (v);
- if (length <= 0)
- error (_("Right operand of `@' must be positive."));
-
- /* The top of the stack is already the address of the object, so
- all we need to do is frob the type of the lvalue. */
- {
- /* FIXME-type-allocation: need a way to free this type when we are
- done with it. */
- struct type *array
- = lookup_array_range_type (value1.type, 0, length - 1);
-
- value->kind = axs_lvalue_memory;
- value->type = array;
- }
- }
-}
-
-
-/* Emit code for the `sizeof' operator.
- *PC should point at the start of the operand expression; we advance it
- to the first instruction after the operand. */
-static void
-gen_sizeof (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value,
- struct type *size_type)
-{
- /* We don't care about the value of the operand expression; we only
- care about its type. However, in the current arrangement, the
- only way to find an expression's type is to generate code for it.
- So we generate code for the operand, and then throw it away,
- replacing it with code that simply pushes its size. */
- int start = ax->len;
-
- gen_expr (exp, pc, ax, value);
-
- /* Throw away the code we just generated. */
- ax->len = start;
-
- ax_const_l (ax, TYPE_LENGTH (value->type));
- value->kind = axs_rvalue;
- value->type = size_type;
-}
\f
-/* Generate bytecode for a cast to TO_TYPE. Advance *PC over the
- subexpression. */
-
-static void
-gen_expr_for_cast (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value,
- struct type *to_type)
-{
- enum exp_opcode op = (*pc)[0].opcode;
-
- /* Don't let symbols be handled with gen_expr because that throws an
- "unknown type" error for no-debug data symbols. Instead, we want
- the cast to reinterpret such symbols. */
- if (op == OP_VAR_MSYM_VALUE || op == OP_VAR_VALUE)
- {
- if (op == OP_VAR_VALUE)
- {
- gen_var_ref (ax, value, (*pc)[2].symbol);
-
- if (value->optimized_out)
- error (_("`%s' has been optimized out, cannot use"),
- (*pc)[2].symbol->print_name ());
- }
- else
- gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
- if (value->type->code () == TYPE_CODE_ERROR)
- value->type = to_type;
- (*pc) += 4;
- }
- else
- gen_expr (exp, pc, ax, value);
- gen_cast (ax, value, to_type);
-}
-
-/* Generating bytecode from GDB expressions: general recursive thingy */
-
-/* XXX: i18n */
-/* A gen_expr function written by a Gen-X'er guy.
- Append code for the subexpression of EXPR starting at *POS_P to AX. */
-void
-gen_expr (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value)
-{
- /* Used to hold the descriptions of operand expressions. */
- struct axs_value value1, value2, value3;
- enum exp_opcode op = (*pc)[0].opcode, op2;
- int if1, go1, if2, go2, end;
- struct type *int_type = builtin_type (ax->gdbarch)->builtin_int;
-
- /* If we're looking at a constant expression, just push its value. */
- {
- struct value *v = maybe_const_expr (pc);
-
- if (v)
- {
- ax_const_l (ax, value_as_long (v));
- value->kind = axs_rvalue;
- value->type = check_typedef (value_type (v));
- return;
- }
- }
-
- /* Otherwise, go ahead and generate code for it. */
- switch (op)
- {
- /* Binary arithmetic operators. */
- case BINOP_ADD:
- case BINOP_SUB:
- case BINOP_MUL:
- case BINOP_DIV:
- case BINOP_REM:
- case BINOP_LSH:
- case BINOP_RSH:
- case BINOP_SUBSCRIPT:
- case BINOP_BITWISE_AND:
- case BINOP_BITWISE_IOR:
- case BINOP_BITWISE_XOR:
- case BINOP_EQUAL:
- case BINOP_NOTEQUAL:
- case BINOP_LESS:
- case BINOP_GTR:
- case BINOP_LEQ:
- case BINOP_GEQ:
- (*pc)++;
- gen_expr (exp, pc, ax, &value1);
- gen_usual_unary (ax, &value1);
- gen_expr_binop_rest (exp, op, pc, ax, value, &value1, &value2);
- break;
-
- case BINOP_LOGICAL_AND:
- (*pc)++;
- /* Generate the obvious sequence of tests and jumps. */
- gen_expr (exp, pc, ax, &value1);
- gen_usual_unary (ax, &value1);
- if1 = ax_goto (ax, aop_if_goto);
- go1 = ax_goto (ax, aop_goto);
- ax_label (ax, if1, ax->len);
- gen_expr (exp, pc, ax, &value2);
- gen_usual_unary (ax, &value2);
- if2 = ax_goto (ax, aop_if_goto);
- go2 = ax_goto (ax, aop_goto);
- ax_label (ax, if2, ax->len);
- ax_const_l (ax, 1);
- end = ax_goto (ax, aop_goto);
- ax_label (ax, go1, ax->len);
- ax_label (ax, go2, ax->len);
- ax_const_l (ax, 0);
- ax_label (ax, end, ax->len);
- value->kind = axs_rvalue;
- value->type = int_type;
- break;
-
- case BINOP_LOGICAL_OR:
- (*pc)++;
- /* Generate the obvious sequence of tests and jumps. */
- gen_expr (exp, pc, ax, &value1);
- gen_usual_unary (ax, &value1);
- if1 = ax_goto (ax, aop_if_goto);
- gen_expr (exp, pc, ax, &value2);
- gen_usual_unary (ax, &value2);
- if2 = ax_goto (ax, aop_if_goto);
- ax_const_l (ax, 0);
- end = ax_goto (ax, aop_goto);
- ax_label (ax, if1, ax->len);
- ax_label (ax, if2, ax->len);
- ax_const_l (ax, 1);
- ax_label (ax, end, ax->len);
- value->kind = axs_rvalue;
- value->type = int_type;
- break;
-
- case TERNOP_COND:
- (*pc)++;
- gen_expr (exp, pc, ax, &value1);
- gen_usual_unary (ax, &value1);
- /* For (A ? B : C), it's easiest to generate subexpression
- bytecodes in order, but if_goto jumps on true, so we invert
- the sense of A. Then we can do B by dropping through, and
- jump to do C. */
- gen_logical_not (ax, &value1, int_type);
- if1 = ax_goto (ax, aop_if_goto);
- gen_expr (exp, pc, ax, &value2);
- gen_usual_unary (ax, &value2);
- end = ax_goto (ax, aop_goto);
- ax_label (ax, if1, ax->len);
- gen_expr (exp, pc, ax, &value3);
- gen_usual_unary (ax, &value3);
- ax_label (ax, end, ax->len);
- /* This is arbitrary - what if B and C are incompatible types? */
- value->type = value2.type;
- value->kind = value2.kind;
- break;
-
- case BINOP_ASSIGN:
- (*pc)++;
- if ((*pc)[0].opcode == OP_INTERNALVAR)
- {
- const char *name = internalvar_name ((*pc)[1].internalvar);
- struct trace_state_variable *tsv;
-
- (*pc) += 3;
- gen_expr (exp, pc, ax, value);
- tsv = find_trace_state_variable (name);
- if (tsv)
- {
- ax_tsv (ax, aop_setv, tsv->number);
- if (ax->tracing)
- ax_tsv (ax, aop_tracev, tsv->number);
- }
- else
- error (_("$%s is not a trace state variable, "
- "may not assign to it"), name);
- }
- else
- error (_("May only assign to trace state variables"));
- break;
-
- case BINOP_ASSIGN_MODIFY:
- (*pc)++;
- op2 = (*pc)[0].opcode;
- (*pc)++;
- (*pc)++;
- if ((*pc)[0].opcode == OP_INTERNALVAR)
- {
- const char *name = internalvar_name ((*pc)[1].internalvar);
- struct trace_state_variable *tsv;
-
- (*pc) += 3;
- tsv = find_trace_state_variable (name);
- if (tsv)
- {
- /* The tsv will be the left half of the binary operation. */
- 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. */
- value1.kind = axs_rvalue;
- value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
- /* Now do right half of expression. */
- gen_expr_binop_rest (exp, op2, pc, ax, value, &value1, &value2);
- /* We have a result of the binary op, set the tsv. */
- ax_tsv (ax, aop_setv, tsv->number);
- if (ax->tracing)
- ax_tsv (ax, aop_tracev, tsv->number);
- }
- else
- error (_("$%s is not a trace state variable, "
- "may not assign to it"), name);
- }
- else
- error (_("May only assign to trace state variables"));
- break;
-
- /* Note that we need to be a little subtle about generating code
- for comma. In C, we can do some optimizations here because
- we know the left operand is only being evaluated for effect.
- However, if the tracing kludge is in effect, then we always
- need to evaluate the left hand side fully, so that all the
- variables it mentions get traced. */
- case BINOP_COMMA:
- (*pc)++;
- gen_expr (exp, pc, ax, &value1);
- /* Don't just dispose of the left operand. We might be tracing,
- in which case we want to emit code to trace it if it's an
- lvalue. */
- gen_traced_pop (ax, &value1);
- gen_expr (exp, pc, ax, value);
- /* It's the consumer's responsibility to trace the right operand. */
- break;
-
- case OP_LONG: /* some integer constant */
- {
- struct type *type = (*pc)[1].type;
- LONGEST k = (*pc)[2].longconst;
-
- (*pc) += 4;
- gen_int_literal (ax, value, k, type);
- }
- break;
-
- case OP_VAR_VALUE:
- gen_var_ref (ax, value, (*pc)[2].symbol);
-
- if (value->optimized_out)
- error (_("`%s' has been optimized out, cannot use"),
- (*pc)[2].symbol->print_name ());
-
- if (value->type->code () == TYPE_CODE_ERROR)
- error_unknown_type ((*pc)[2].symbol->print_name ());
-
- (*pc) += 4;
- break;
-
- case OP_VAR_MSYM_VALUE:
- gen_msym_var_ref (ax, value, (*pc)[2].msymbol, (*pc)[1].objfile);
-
- if (value->type->code () == TYPE_CODE_ERROR)
- error_unknown_type ((*pc)[2].msymbol->linkage_name ());
-
- (*pc) += 4;
- break;
-
- case OP_REGISTER:
- {
- const char *name = &(*pc)[2].string;
- int reg;
-
- (*pc) += 4 + BYTES_TO_EXP_ELEM ((*pc)[1].longconst + 1);
- reg = user_reg_map_name_to_regnum (ax->gdbarch, name, strlen (name));
- if (reg == -1)
- internal_error (__FILE__, __LINE__,
- _("Register $%s not available"), name);
- /* No support for tracing user registers yet. */
- if (reg >= gdbarch_num_cooked_regs (ax->gdbarch))
- error (_("'%s' is a user-register; "
- "GDB cannot yet trace user-register contents."),
- name);
- value->kind = axs_lvalue_register;
- value->u.reg = reg;
- value->type = register_type (ax->gdbarch, reg);
- }
- break;
-
- case OP_INTERNALVAR:
- {
- struct internalvar *var = (*pc)[1].internalvar;
- const char *name = internalvar_name (var);
- struct trace_state_variable *tsv;
-
- (*pc) += 3;
- tsv = find_trace_state_variable (name);
- if (tsv)
- {
- 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);
- }
- break;
-
- /* Weirdo operator: see comments for gen_repeat for details. */
- case BINOP_REPEAT:
- /* Note that gen_repeat handles its own argument evaluation. */
- (*pc)++;
- gen_repeat (exp, pc, ax, value);
- break;
-
- case UNOP_CAST:
- {
- struct type *type = (*pc)[1].type;
-
- (*pc) += 3;
- gen_expr_for_cast (exp, pc, ax, value, type);
- }
- break;
-
- case UNOP_CAST_TYPE:
- {
- int offset;
- struct value *val;
- struct type *type;
-
- ++*pc;
- offset = *pc - exp->elts;
- val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
- type = value_type (val);
- *pc = &exp->elts[offset];
- gen_expr_for_cast (exp, pc, ax, value, type);
- }
- break;
-
- case UNOP_MEMVAL:
- {
- struct type *type = check_typedef ((*pc)[1].type);
-
- (*pc) += 3;
- gen_expr (exp, pc, ax, value);
-
- /* If we have an axs_rvalue or an axs_lvalue_memory, then we
- already have the right value on the stack. For
- axs_lvalue_register, we must convert. */
- if (value->kind == axs_lvalue_register)
- require_rvalue (ax, value);
-
- value->type = type;
- value->kind = axs_lvalue_memory;
- }
- break;
-
- case UNOP_MEMVAL_TYPE:
- {
- int offset;
- struct value *val;
- struct type *type;
-
- ++*pc;
- offset = *pc - exp->elts;
- val = evaluate_subexp (NULL, exp, &offset, EVAL_AVOID_SIDE_EFFECTS);
- type = value_type (val);
- *pc = &exp->elts[offset];
-
- gen_expr (exp, pc, ax, value);
-
- /* If we have an axs_rvalue or an axs_lvalue_memory, then we
- already have the right value on the stack. For
- axs_lvalue_register, we must convert. */
- if (value->kind == axs_lvalue_register)
- require_rvalue (ax, value);
-
- value->type = type;
- value->kind = axs_lvalue_memory;
- }
- break;
-
- case UNOP_PLUS:
- (*pc)++;
- /* + FOO is equivalent to 0 + FOO, which can be optimized. */
- gen_expr (exp, pc, ax, value);
- gen_usual_unary (ax, value);
- break;
-
- case UNOP_NEG:
- (*pc)++;
- /* -FOO is equivalent to 0 - FOO. */
- gen_int_literal (ax, &value1, 0,
- builtin_type (ax->gdbarch)->builtin_int);
- gen_usual_unary (ax, &value1); /* shouldn't do much */
- gen_expr (exp, pc, ax, &value2);
- gen_usual_unary (ax, &value2);
- gen_usual_arithmetic (ax, &value1, &value2);
- gen_binop (ax, value, &value1, &value2, aop_sub, aop_sub, 1, "negation");
- break;
-
- case UNOP_LOGICAL_NOT:
- (*pc)++;
- gen_expr (exp, pc, ax, value);
- gen_usual_unary (ax, value);
- gen_logical_not (ax, value, int_type);
- break;
-
- case UNOP_COMPLEMENT:
- (*pc)++;
- gen_expr (exp, pc, ax, value);
- gen_usual_unary (ax, value);
- gen_integral_promotions (ax, value);
- gen_complement (ax, value);
- break;
-
- case UNOP_IND:
- (*pc)++;
- gen_expr (exp, pc, ax, value);
- gen_usual_unary (ax, value);
- if (!pointer_type (value->type))
- error (_("Argument of unary `*' is not a pointer."));
- gen_deref (value);
- break;
-
- case UNOP_ADDR:
- (*pc)++;
- gen_expr (exp, pc, ax, value);
- gen_address_of (value);
- break;
-
- case UNOP_SIZEOF:
- (*pc)++;
- /* Notice that gen_sizeof handles its own operand, unlike most
- of the other unary operator functions. This is because we
- have to throw away the code we generate. */
- gen_sizeof (exp, pc, ax, value,
- builtin_type (ax->gdbarch)->builtin_int);
- break;
-
- case STRUCTOP_STRUCT:
- case STRUCTOP_PTR:
- {
- int length = (*pc)[1].longconst;
- const char *name = &(*pc)[2].string;
-
- (*pc) += 4 + BYTES_TO_EXP_ELEM (length + 1);
- gen_expr (exp, pc, ax, value);
- if (op == STRUCTOP_STRUCT)
- gen_struct_ref (ax, value, name, ".", "structure or union");
- else if (op == STRUCTOP_PTR)
- gen_struct_ref (ax, value, name, "->",
- "pointer to a structure or union");
- else
- /* If this `if' chain doesn't handle it, then the case list
- shouldn't mention it, and we shouldn't be here. */
- internal_error (__FILE__, __LINE__,
- _("gen_expr: unhandled struct case"));
- }
- break;
-
- case OP_THIS:
- {
- struct symbol *sym, *func;
- const struct block *b;
- const struct language_defn *lang;
-
- b = block_for_pc (ax->scope);
- func = block_linkage_function (b);
- lang = language_def (func->language ());
-
- sym = lookup_language_this (lang, b).symbol;
- if (!sym)
- error (_("no `%s' found"), lang->name_of_this ());
-
- gen_var_ref (ax, value, sym);
-
- if (value->optimized_out)
- error (_("`%s' has been optimized out, cannot use"),
- sym->print_name ());
-
- (*pc) += 2;
- }
- break;
-
- case OP_SCOPE:
- {
- struct type *type = (*pc)[1].type;
- int length = longest_to_int ((*pc)[2].longconst);
- const char *name = &(*pc)[3].string;
- int found;
-
- found = gen_aggregate_elt_ref (ax, value, type, name);
- if (!found)
- error (_("There is no field named %s"), name);
- (*pc) += 5 + BYTES_TO_EXP_ELEM (length + 1);
- }
- break;
-
- case OP_TYPE:
- case OP_TYPEOF:
- case OP_DECLTYPE:
- error (_("Attempt to use a type name as an expression."));
-
- default:
- error (_("Unsupported operator %s (%d) in expression."),
- op_name (op), op);
- }
-}
-
namespace expr
{
struct axs_value *value,
struct type *cast_type)
{
- gen_msym_var_ref (ax, value, std::get<0> (m_storage),
- std::get<1> (m_storage));
+ const bound_minimal_symbol &b = std::get<0> (m_storage);
+ gen_msym_var_ref (ax, value, b.minsym, b.objfile);
if (value->type->code () == TYPE_CODE_ERROR)
{
if (cast_type == nullptr)
- error_unknown_type (std::get<0> (m_storage)->linkage_name ());
+ error_unknown_type (b.minsym->linkage_name ());
value->type = cast_type;
}
}
value->type = builtin_type (ax->gdbarch)->builtin_int;
}
+void
+unop_cast_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ std::get<0> (m_storage)->generate_ax (exp, ax, value,
+ std::get<1> (m_storage));
+}
+
void
unop_memval_operation::do_generate_ax (struct expression *exp,
struct agent_expr *ax,
"may not assign to it"), name);
}
+void
+assign_modify_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ operation *subop = std::get<1> (m_storage).get ();
+ if (subop->opcode () != OP_INTERNALVAR)
+ error (_("May only assign to trace state variables"));
+
+ internalvar_operation *ivarop
+ = dynamic_cast<internalvar_operation *> (subop);
+ gdb_assert (ivarop != nullptr);
+
+ const char *name = internalvar_name (ivarop->get_internalvar ());
+ struct trace_state_variable *tsv;
+
+ tsv = find_trace_state_variable (name);
+ if (tsv)
+ {
+ /* The tsv will be the left half of the binary operation. */
+ 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. */
+ struct axs_value value1, value2;
+ value1.kind = axs_rvalue;
+ value1.type = builtin_type (ax->gdbarch)->builtin_long_long;
+ /* Now do right half of expression. */
+ std::get<2> (m_storage)->generate_ax (exp, ax, &value2);
+ gen_expr_binop_rest (exp, std::get<0> (m_storage), ax,
+ value, &value1, &value2);
+ /* We have a result of the binary op, set the tsv. */
+ ax_tsv (ax, aop_setv, tsv->number);
+ if (ax->tracing)
+ ax_tsv (ax, aop_tracev, tsv->number);
+ }
+ else
+ error (_("$%s is not a trace state variable, "
+ "may not assign to it"), name);
+}
+
+void
+unop_cast_type_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ struct value *val
+ = std::get<0> (m_storage)->evaluate (nullptr, exp,
+ EVAL_AVOID_SIDE_EFFECTS);
+ std::get<1> (m_storage)->generate_ax (exp, ax, value, value_type (val));
+}
+
+void
+var_value_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ gen_var_ref (ax, value, std::get<0> (m_storage).symbol);
+
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ std::get<0> (m_storage).symbol->print_name ());
+
+ if (value->type->code () == TYPE_CODE_ERROR)
+ {
+ if (cast_type == nullptr)
+ error_unknown_type (std::get<0> (m_storage).symbol->print_name ());
+ value->type = cast_type;
+ }
+}
+
+void
+logical_and_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ struct axs_value value1, value2;
+ int if1, go1, if2, go2, end;
+
+ /* Generate the obvious sequence of tests and jumps. */
+ std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+ gen_usual_unary (ax, &value1);
+ if1 = ax_goto (ax, aop_if_goto);
+ go1 = ax_goto (ax, aop_goto);
+ ax_label (ax, if1, ax->len);
+ std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+ gen_usual_unary (ax, &value2);
+ if2 = ax_goto (ax, aop_if_goto);
+ go2 = ax_goto (ax, aop_goto);
+ ax_label (ax, if2, ax->len);
+ ax_const_l (ax, 1);
+ end = ax_goto (ax, aop_goto);
+ ax_label (ax, go1, ax->len);
+ ax_label (ax, go2, ax->len);
+ ax_const_l (ax, 0);
+ ax_label (ax, end, ax->len);
+ value->kind = axs_rvalue;
+ value->type = builtin_type (ax->gdbarch)->builtin_int;
+}
+
+void
+logical_or_operation::do_generate_ax (struct expression *exp,
+ struct agent_expr *ax,
+ struct axs_value *value,
+ struct type *cast_type)
+{
+ struct axs_value value1, value2;
+ int if1, if2, end;
+
+ /* Generate the obvious sequence of tests and jumps. */
+ std::get<0> (m_storage)->generate_ax (exp, ax, &value1);
+ gen_usual_unary (ax, &value1);
+ if1 = ax_goto (ax, aop_if_goto);
+ std::get<1> (m_storage)->generate_ax (exp, ax, &value2);
+ gen_usual_unary (ax, &value2);
+ if2 = ax_goto (ax, aop_if_goto);
+ ax_const_l (ax, 0);
+ end = ax_goto (ax, aop_goto);
+ ax_label (ax, if1, ax->len);
+ ax_label (ax, if2, ax->len);
+ ax_const_l (ax, 1);
+ ax_label (ax, end, ax->len);
+ value->kind = axs_rvalue;
+ value->type = builtin_type (ax->gdbarch)->builtin_int;
+}
+
}
/* This handles the middle-to-right-side of code generation for binary
{
case BINOP_ADD:
if (value1->type->code () == TYPE_CODE_INT
- && pointer_type (value2->type))
+ && value2->type->is_pointer_or_reference ())
{
/* Swap the values and proceed normally. */
ax_simple (ax, aop_swap);
gen_ptradd (ax, value, value2, value1);
}
- else if (pointer_type (value1->type)
+ else if (value1->type->is_pointer_or_reference ()
&& value2->type->code () == TYPE_CODE_INT)
gen_ptradd (ax, value, value1, value2);
else
aop_add, aop_add, 1, "addition");
break;
case BINOP_SUB:
- if (pointer_type (value1->type)
+ if (value1->type->is_pointer_or_reference ()
&& value2->type->code () == TYPE_CODE_INT)
gen_ptrsub (ax,value, value1, value2);
- else if (pointer_type (value1->type)
- && pointer_type (value2->type))
+ else if (value1->type->is_pointer_or_reference ()
+ && value2->type->is_pointer_or_reference ())
/* FIXME --- result type should be ptrdiff_t */
gen_ptrdiff (ax, value, value1, value2,
builtin_type (ax->gdbarch)->builtin_long);
}
}
-/* Variant of gen_expr_binop_rest that first generates the
- right-hand-side. */
-
-static void
-gen_expr_binop_rest (struct expression *exp,
- enum exp_opcode op, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value,
- struct axs_value *value1, struct axs_value *value2)
-{
- gen_expr (exp, pc, ax, value2);
- gen_expr_binop_rest (exp, op, ax, value, value1, value2);
-}
-
/* A helper function that emits a binop based on two operations. */
void
case UNOP_IND:
lhs->generate_ax (exp, ax, value);
gen_usual_unary (ax, value);
- if (!pointer_type (value->type))
+ if (!value->type->is_pointer_or_reference ())
error (_("Argument of unary `*' is not a pointer."));
gen_deref (value);
break;
int trace_string)
{
agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
- union exp_element *pc;
struct axs_value value;
- pc = expr->elts;
ax->tracing = 1;
ax->trace_string = trace_string;
value.optimized_out = 0;
- gen_expr (expr, &pc, ax.get (), &value);
+ expr->op->generate_ax (expr, ax.get (), &value);
/* Make sure we record the final object, and get rid of it. */
gen_traced_pop (ax.get (), &value);
gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
{
agent_expr_up ax (new agent_expr (expr->gdbarch, scope));
- union exp_element *pc;
struct axs_value value;
- pc = expr->elts;
ax->tracing = 0;
value.optimized_out = 0;
- gen_expr (expr, &pc, ax.get (), &value);
+ expr->op->generate_ax (expr, ax.get (), &value);
require_rvalue (ax.get (), &value);
int nargs, struct expression **exprs)
{
agent_expr_up ax (new agent_expr (gdbarch, scope));
- union exp_element *pc;
struct axs_value value;
int tem;
for simplicity of collecting them on the target side. */
for (tem = nargs - 1; tem >= 0; --tem)
{
- pc = exprs[tem]->elts;
value.optimized_out = 0;
- gen_expr (exprs[tem], &pc, ax.get (), &value);
+ exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
require_rvalue (ax.get (), &value);
}
}
static void
-agent_command_1 (const char *exp, int eval)
+maint_agent_command_1 (const char *exp, int eval)
{
/* We don't deal with overlay debugging at the moment. We need to
think more carefully about this. If you copy this code into
}
static void
-agent_command (const char *exp, int from_tty)
+maint_agent_command (const char *exp, int from_tty)
{
- agent_command_1 (exp, 0);
+ maint_agent_command_1 (exp, 0);
}
/* Parse the given expression, compile it into an agent expression
expression. */
static void
-agent_eval_command (const char *exp, int from_tty)
+maint_agent_eval_command (const char *exp, int from_tty)
{
- agent_command_1 (exp, 1);
+ maint_agent_command_1 (exp, 1);
}
/* Parse the given expression, compile it into an agent expression
void
_initialize_ax_gdb ()
{
- add_cmd ("agent", class_maintenance, agent_command,
+ add_cmd ("agent", class_maintenance, maint_agent_command,
_("\
Translate an expression into remote agent bytecode for tracing.\n\
Usage: maint agent [-at LOCATION,] EXPRESSION\n\
If not, generate remote agent bytecode for current frame pc address."),
&maintenancelist);
- add_cmd ("agent-eval", class_maintenance, agent_eval_command,
+ add_cmd ("agent-eval", class_maintenance, maint_agent_eval_command,
_("\
Translate an expression into remote agent bytecode for evaluation.\n\
Usage: maint agent-eval [-at LOCATION,] EXPRESSION\n\