mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-27 01:28:46 +00:00
Remove union exp_element
This removes union exp_element functions that either create such elements or walk them. struct expression no longer holds exp_elements. A couple of language_defn methods are also removed, as they are obsolete. Note that this patch also removes the print_expression code. The only in-tree caller of this was from dump_prefix_expression, which is only called when expression debugging is enabled. Implementing this would involve a fair amount of code, and it seems to me that prefix dumping is preferable anyway, as it is unambiguous. So, I have not reimplemented this feature. gdb/ChangeLog 2021-03-08 Tom Tromey <tom@tromey.com> * value.h (evaluate_subexp_with_coercion): Don't declare. * parse.c (exp_descriptor_standard): Remove. (expr_builder::expr_builder, expr_builder::release): Update. (expression::expression): Remove size_t parameter. (expression::~expression): Simplify. (expression::resize): Remove. (write_exp_elt, write_exp_elt_opcode, write_exp_elt_sym) (write_exp_elt_msym, write_exp_elt_block, write_exp_elt_objfile) (write_exp_elt_longcst, write_exp_elt_floatcst) (write_exp_elt_type, write_exp_elt_intern, write_exp_string) (write_exp_string_vector, write_exp_bitstring): Remove. * p-lang.h (class pascal_language) <opcode_print_table, op_print_tab>: Remove. * p-lang.c (pascal_language::op_print_tab): Remove. * opencl-lang.c (class opencl_language) <opcode_print_table>: Remove. * objc-lang.c (objc_op_print_tab): Remove. (class objc_language) <opcode_print_table>: Remove. * m2-lang.h (class m2_language) <opcode_print_table, op_print_tab>: Remove. * m2-lang.c (m2_language::op_print_tab): Remove. * language.h (struct language_defn) <post_parser, expression_ops, opcode_print_table>: Remove. * language.c (language_defn::expression_ops) (auto_or_unknown_language::opcode_print_table): Remove. * go-lang.h (class go_language) <opcode_print_table, op_print_tab>: Remove. * go-lang.c (go_language::op_print_tab): Remove. * f-lang.h (class f_language) <opcode_print_table>: Remove <op_print_tab>: Remove. * f-lang.c (f_language::op_print_tab): Remove. * expression.h (union exp_element): Remove. (struct expression): Remove size_t parameter from constructor. <resize>: Remove. <first_opcode>: Update. <nelts, elts>: Remove. (EXP_ELEM_TO_BYTES, BYTES_TO_EXP_ELEM): Remove. (evaluate_subexp_standard, print_expression, op_string) (dump_raw_expression): Don't declare. * expprint.c (print_expression, print_subexp) (print_subexp_funcall, print_subexp_standard, op_string) (dump_raw_expression, dump_subexp, dump_subexp_body) (dump_subexp_body_funcall, dump_subexp_body_standard): Remove. (dump_prefix_expression): Update. * eval.c (evaluate_subexp): Remove. (evaluate_expression, evaluate_type): Update. (evaluate_subexpression_type): Remove. (fetch_subexp_value): Remove "pc" parameter. Update. (extract_field_op, evaluate_struct_tuple, evaluate_funcall) (evaluate_subexp_standard, evaluate_subexp_for_address) (evaluate_subexp_with_coercion, evaluate_subexp_for_sizeof) (evaluate_subexp_for_cast): Remove. (parse_and_eval_type): Update. * dtrace-probe.c (dtrace_probe::compile_to_ax): Update. * d-lang.c (d_op_print_tab): Remove. (class d_language) <opcode_print_table>: Remove. * c-lang.h (c_op_print_tab): Don't declare. * c-lang.c (c_op_print_tab): Remove. (class c_language, class cplus_language, class asm_language, class minimal_language) <opcode_print_table>: Remove. * breakpoint.c (update_watchpoint, watchpoint_check) (watchpoint_exp_is_const, watch_command_1): Update. * ax-gdb.h (union exp_element): Don't declare. * ax-gdb.c (const_var_ref, const_expr, maybe_const_expr) (gen_repeat, gen_sizeof, gen_expr_for_cast, gen_expr) (gen_expr_binop_rest): Remove. (gen_trace_for_expr, gen_eval_for_expr, gen_printf): Update. * ada-lang.c (ada_op_print_tab): Remove. (class ada_language) <post_parser, opcode_print_table>: Remove.
This commit is contained in:
735
gdb/ax-gdb.c
735
gdb/ax-gdb.c
@@ -70,14 +70,9 @@
|
||||
/* 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 *);
|
||||
@@ -148,123 +143,13 @@ static void gen_struct_ref (struct agent_expr *ax,
|
||||
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);
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
/* Generating bytecode from GDB expressions: general assumptions */
|
||||
@@ -1691,592 +1576,8 @@ gen_aggregate_elt_ref (struct agent_expr *ax, struct axs_value *value,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* 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
|
||||
{
|
||||
|
||||
@@ -2901,19 +2202,6 @@ gen_expr_binop_rest (struct expression *exp,
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -3057,17 +2345,12 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr,
|
||||
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;
|
||||
if (expr->op != nullptr)
|
||||
expr->op->generate_ax (expr, ax.get (), &value);
|
||||
else
|
||||
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);
|
||||
@@ -3089,16 +2372,11 @@ agent_expr_up
|
||||
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;
|
||||
if (expr->op != nullptr)
|
||||
expr->op->generate_ax (expr, ax.get (), &value);
|
||||
else
|
||||
gen_expr (expr, &pc, ax.get (), &value);
|
||||
expr->op->generate_ax (expr, ax.get (), &value);
|
||||
|
||||
require_rvalue (ax.get (), &value);
|
||||
|
||||
@@ -3140,7 +2418,6 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
|
||||
int nargs, struct expression **exprs)
|
||||
{
|
||||
agent_expr_up ax (new agent_expr (gdbarch, scope));
|
||||
union exp_element *pc;
|
||||
struct axs_value value;
|
||||
int tem;
|
||||
|
||||
@@ -3152,13 +2429,7 @@ gen_printf (CORE_ADDR scope, struct gdbarch *gdbarch,
|
||||
for (tem = nargs - 1; tem >= 0; --tem)
|
||||
{
|
||||
value.optimized_out = 0;
|
||||
if (exprs[tem]->op != nullptr)
|
||||
exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
|
||||
else
|
||||
{
|
||||
pc = exprs[tem]->elts;
|
||||
gen_expr (exprs[tem], &pc, ax.get (), &value);
|
||||
}
|
||||
exprs[tem]->op->generate_ax (exprs[tem], ax.get (), &value);
|
||||
require_rvalue (ax.get (), &value);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user