/* GDB-specific functions for operating on agent expressions.
- Copyright (C) 1998, 1999, 2000, 2001, 2003, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 1998-2001, 2003, 2007-2012 Free Software Foundation,
+ Inc.
This file is part of GDB.
#include "breakpoint.h"
#include "tracepoint.h"
#include "cp-support.h"
+#include "arch-utils.h"
+
+#include "valprint.h"
+#include "c-lang.h"
/* To make sense of this file, you should read doc/agentexpr.texi.
Then look at the types and enums in ax-gdb.h. For the code itself,
\f
-/* Prototypes for local functions. */
+/* Prototypes for local functions. */
/* There's a standard order to the arguments of these functions:
union exp_element ** --- pointer into expression
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_traced_pop (struct gdbarch *, struct agent_expr *,
+ struct axs_value *);
static void gen_sign_extend (struct agent_expr *, struct type *);
static void gen_extend (struct agent_expr *, struct type *);
struct axs_value *value,
LONGEST k, struct type *type);
-
-static void require_rvalue (struct agent_expr *ax, struct axs_value *value);
static void gen_usual_unary (struct expression *exp, struct agent_expr *ax,
struct axs_value *value);
static int type_wider_than (struct type *type1, struct type *type2);
struct axs_value *value,
char *field,
char *operator_name, char *operand_name);
-static void gen_static_field (struct expression *exp,
+static void gen_static_field (struct gdbarch *gdbarch,
struct agent_expr *ax, struct axs_value *value,
struct type *type, int fieldno);
static void gen_repeat (struct expression *exp, union exp_element **pc,
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 (struct expression *exp, union exp_element **pc,
- struct agent_expr *ax, struct axs_value *value);
static void gen_expr_binop_rest (struct expression *exp,
enum exp_opcode op, union exp_element **pc,
struct agent_expr *ax,
{
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;
}
Setting the flag trace_kludge to non-zero enables the code that
emits the trace bytecodes at the appropriate points. */
-static int trace_kludge;
+int trace_kludge;
+
+/* Inspired by trace_kludge, this indicates that pointers to chars
+ should get an added tracenz bytecode to record nonzero bytes, up to
+ a length that is the value of trace_string_kludge. */
+int trace_string_kludge;
+
+/* Scan for all static fields in the given class, including any base
+ classes, and generate tracing bytecodes for each. */
+
+static void
+gen_trace_static_fields (struct gdbarch *gdbarch,
+ struct agent_expr *ax,
+ struct type *type)
+{
+ int i, nbases = TYPE_N_BASECLASSES (type);
+ struct axs_value value;
+
+ CHECK_TYPEDEF (type);
+
+ for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
+ {
+ if (field_is_static (&TYPE_FIELD (type, i)))
+ {
+ gen_static_field (gdbarch, ax, &value, type, i);
+ if (value.optimized_out)
+ continue;
+ switch (value.kind)
+ {
+ case axs_lvalue_memory:
+ {
+ int length = TYPE_LENGTH (check_typedef (value.type));
+
+ ax_const_l (ax, length);
+ ax_simple (ax, aop_trace);
+ }
+ break;
+
+ case axs_lvalue_register:
+ /* We don't actually need the register's value to be pushed,
+ just note that we need it to be collected. */
+ ax_reg_mask (ax, value.u.reg);
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /* Now scan through base classes recursively. */
+ for (i = 0; i < nbases; i++)
+ {
+ struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
+
+ gen_trace_static_fields (gdbarch, ax, basetype);
+ }
+}
/* Trace the lvalue on the stack, if it needs it. In either case, pop
the value. Useful on the left side of a comma, and at the end of
an expression being used for tracing. */
static void
-gen_traced_pop (struct agent_expr *ax, struct axs_value *value)
+gen_traced_pop (struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value)
{
+ int string_trace = 0;
+ if (trace_string_kludge
+ && TYPE_CODE (value->type) == TYPE_CODE_PTR
+ && c_textual_element_type (check_typedef (TYPE_TARGET_TYPE (value->type)),
+ 's'))
+ string_trace = 1;
+
if (trace_kludge)
switch (value->kind)
{
case axs_rvalue:
- /* We don't trace rvalues, just the lvalues necessary to
- produce them. So just dispose of this value. */
- ax_simple (ax, aop_pop);
+ if (string_trace)
+ {
+ ax_const_l (ax, trace_string_kludge);
+ ax_simple (ax, aop_tracenz);
+ }
+ else
+ /* We don't trace rvalues, just the lvalues necessary to
+ produce them. So just dispose of this value. */
+ ax_simple (ax, aop_pop);
break;
case axs_lvalue_memory:
{
int length = TYPE_LENGTH (check_typedef (value->type));
+ if (string_trace)
+ ax_simple (ax, aop_dup);
+
/* There's no point in trying to use a trace_quick bytecode
here, since "trace_quick SIZE pop" is three bytes, whereas
"const8 SIZE trace" is also three bytes, does the same
work correctly for objects with large sizes. */
ax_const_l (ax, length);
ax_simple (ax, aop_trace);
+
+ if (string_trace)
+ {
+ ax_simple (ax, aop_ref32);
+ ax_const_l (ax, trace_string_kludge);
+ ax_simple (ax, aop_tracenz);
+ }
}
break;
case axs_lvalue_register:
- /* We need to mention the register somewhere in the bytecode,
- so ax_reqs will pick it up and add it to the mask of
- registers used. */
- ax_reg (ax, value->u.reg);
- ax_simple (ax, aop_pop);
+ /* We don't actually need the register's value to be on the
+ stack, and the target will get heartburn if the register is
+ larger than will fit in a stack, so just mark it for
+ collection and be done with it. */
+ ax_reg_mask (ax, value->u.reg);
+
+ /* But if the register points to a string, assume the value
+ will fit on the stack and push it anyway. */
+ if (string_trace)
+ {
+ ax_reg (ax, value->u.reg);
+ ax_const_l (ax, trace_string_kludge);
+ ax_simple (ax, aop_tracenz);
+ }
break;
}
else
/* If we're not tracing, just pop the value. */
ax_simple (ax, aop_pop);
+
+ /* To trace C++ classes with static fields stored elsewhere. */
+ if (trace_kludge
+ && (TYPE_CODE (value->type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (value->type) == TYPE_CODE_UNION))
+ gen_trace_static_fields (gdbarch, ax, value->type);
}
\f
gen_extend (struct agent_expr *ax, struct type *type)
{
int bits = TYPE_LENGTH (type) * TARGET_CHAR_BIT;
+
/* I just had to. */
((TYPE_UNSIGNED (type) ? ax_zero_ext : ax_ext) (ax, bits));
}
ax_trace_quick (ax, TYPE_LENGTH (type));
}
+ if (TYPE_CODE (type) == TYPE_CODE_RANGE)
+ type = TYPE_TARGET_TYPE (type);
+
switch (TYPE_CODE (type))
{
case TYPE_CODE_PTR:
case TYPE_CODE_ENUM:
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
/* It's a scalar value, so we know how to dereference it. How
many bytes long is it? */
switch (TYPE_LENGTH (type))
break;
default:
- /* Either our caller shouldn't have asked us to dereference that
- pointer (other code's fault), or we're not implementing
- something we should be (this code's fault). In any case,
- it's a bug the user shouldn't see. */
- internal_error (__FILE__, __LINE__,
- _("gen_fetch: bad type code"));
+ /* Our caller requested us to dereference a pointer from an unsupported
+ type. Error out and give callers a chance to handle the failure
+ gracefully. */
+ error (_("gen_fetch: Unsupported type code `%s'."),
+ TYPE_NAME (type));
}
}
gen_var_ref (struct gdbarch *gdbarch, struct agent_expr *ax,
struct axs_value *value, struct symbol *var)
{
- /* Dereference any typedefs. */
+ /* Dereference any typedefs. */
value->type = check_typedef (SYMBOL_TYPE (var));
+ value->optimized_out = 0;
/* I'm imitating the code in read_var_value. */
switch (SYMBOL_CLASS (var))
case LOC_CONST_BYTES:
internal_error (__FILE__, __LINE__,
- _("gen_var_ref: LOC_CONST_BYTES symbols are not supported"));
+ _("gen_var_ref: LOC_CONST_BYTES "
+ "symbols are not supported"));
/* Variable at a fixed location in memory. Easy. */
case LOC_STATIC:
{
struct minimal_symbol *msym
= lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (var), NULL, NULL);
+
if (!msym)
error (_("Couldn't resolve symbol `%s'."), SYMBOL_PRINT_NAME (var));
break;
case LOC_OPTIMIZED_OUT:
- error (_("The variable `%s' has been optimized out."),
- SYMBOL_PRINT_NAME (var));
+ /* Flag this, but don't say anything; leave it up to callers to
+ warn the user. */
+ value->optimized_out = 1;
break;
default:
/* Take what's on the top of the stack (as described by VALUE), and
try to make an rvalue out of it. Signal an error if we can't do
that. */
-static void
+void
require_rvalue (struct agent_expr *ax, struct axs_value *value)
{
+ /* Only deal with scalars, structs and such may be too large
+ to fit in a stack entry. */
+ value->type = check_typedef (value->type);
+ if (TYPE_CODE (value->type) == TYPE_CODE_ARRAY
+ || TYPE_CODE (value->type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (value->type) == TYPE_CODE_UNION
+ || TYPE_CODE (value->type) == TYPE_CODE_FUNC)
+ error (_("Value not scalar: cannot be an rvalue."));
+
switch (value->kind)
{
case axs_rvalue:
case TYPE_CODE_ARRAY:
{
struct type *elements = TYPE_TARGET_TYPE (value->type);
+
value->type = lookup_pointer_type (elements);
value->kind = axs_rvalue;
/* We don't need to generate any code; the address of the array
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
return;
-
- /* If the value is an enum, call it an integer. */
- case TYPE_CODE_ENUM:
- value->type = builtin_type (exp->gdbarch)->builtin_int;
- break;
}
/* If the value is an lvalue, dereference it. */
static int
is_nontrivial_conversion (struct type *from, struct type *to)
{
- struct agent_expr *ax = new_agent_expr (0);
+ struct agent_expr *ax = new_agent_expr (NULL, 0);
int nontrivial;
/* Actually generate the code, and see if anything came out. At the
/* GCC does allow casts to yield lvalues, so this should be fixed
before merging these changes into the trunk. */
require_rvalue (ax, value);
- /* Dereference typedefs. */
+ /* Dereference typedefs. */
type = check_typedef (type);
switch (TYPE_CODE (type))
error (_("Invalid type cast: intended type must be scalar."));
case TYPE_CODE_ENUM:
+ case TYPE_CODE_BOOL:
/* We don't have to worry about the size of the value, because
all our integral values are fully sign-extended, and when
casting pointers we can do anything we like. Is there any
value->kind = axs_rvalue;
}
+static void
+gen_equal (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2,
+ struct type *result_type)
+{
+ if (pointer_type (value1->type) || pointer_type (value2->type))
+ ax_simple (ax, aop_equal);
+ else
+ gen_binop (ax, value, value1, value2,
+ aop_equal, aop_equal, 0, "equal");
+ value->type = result_type;
+ value->kind = axs_rvalue;
+}
+
+static void
+gen_less (struct agent_expr *ax, struct axs_value *value,
+ struct axs_value *value1, struct axs_value *value2,
+ struct type *result_type)
+{
+ if (pointer_type (value1->type) || pointer_type (value2->type))
+ ax_simple (ax, aop_less_unsigned);
+ else
+ gen_binop (ax, value, value1, value2,
+ aop_less_signed, aop_less_unsigned, 0, "less than");
+ value->type = result_type;
+ value->kind = axs_rvalue;
+}
/* Generate code for a binary operator that doesn't do pointer magic.
We set VALUE to describe the result value; we assume VALUE1 and
operator, used in error messages */
static void
gen_binop (struct agent_expr *ax, struct axs_value *value,
- struct axs_value *value1, struct axs_value *value2, enum agent_op op,
- enum agent_op op_unsigned, int may_carry, char *name)
+ struct axs_value *value1, struct axs_value *value2,
+ enum agent_op op, enum agent_op op_unsigned,
+ int may_carry, char *name)
{
/* We only handle INT op INT. */
if ((TYPE_CODE (value1->type) != TYPE_CODE_INT)
{
/* Note that ops[i] fetches 8 << i bits. */
static enum agent_op ops[]
- =
- {aop_ref8, aop_ref16, aop_ref32, aop_ref64};
+ = {aop_ref8, aop_ref16, aop_ref32, aop_ref64};
static int num_ops = (sizeof (ops) / sizeof (ops[0]));
/* We don't want to touch any byte that the bitfield doesn't
equal to the number of `one' bits in bytesize, but who cares? */
int fragment_count;
- /* Dereference any typedefs. */
+ /* Dereference any typedefs. */
type = check_typedef (type);
/* Can we fetch the number of bits requested at all? */
for (i = TYPE_NFIELDS (type) - 1; i >= nbases; i--)
{
- char *this_name = TYPE_FIELD_NAME (type, i);
+ const char *this_name = TYPE_FIELD_NAME (type, i);
if (this_name)
{
being handled as a global. */
if (field_is_static (&TYPE_FIELD (type, i)))
{
- gen_static_field (exp, ax, value, type, i);
+ gen_static_field (exp->gdbarch, ax, value, type, i);
+ if (value->optimized_out)
+ error (_("static field `%s' has been "
+ "optimized out, cannot use"),
+ field);
return 1;
}
struct type *basetype = check_typedef (TYPE_BASECLASS (type, i));
rslt = gen_struct_ref_recursive (exp, ax, value, field,
- offset + TYPE_BASECLASS_BITPOS (type, i) / TARGET_CHAR_BIT,
+ offset + TYPE_BASECLASS_BITPOS (type, i)
+ / TARGET_CHAR_BIT,
basetype);
if (rslt)
return 1;
const struct type *curtype, char *name);
static void
-gen_static_field (struct expression *exp,
+gen_static_field (struct gdbarch *gdbarch,
struct agent_expr *ax, struct axs_value *value,
struct type *type, int fieldno)
{
ax_const_l (ax, TYPE_FIELD_STATIC_PHYSADDR (type, fieldno));
value->kind = axs_lvalue_memory;
value->type = TYPE_FIELD_TYPE (type, fieldno);
+ value->optimized_out = 0;
}
else
{
- char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
+ const char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, fieldno);
struct symbol *sym = lookup_symbol (phys_name, 0, VAR_DOMAIN, 0);
- if (sym == NULL)
- error (_("symbol not found"));
- gen_var_ref (exp->gdbarch, ax, value, sym);
+ if (sym)
+ {
+ gen_var_ref (gdbarch, ax, value, sym);
+
+ /* Don't error if the value was optimized out, we may be
+ scanning all static fields and just want to pass over this
+ and continue with the rest. */
+ }
+ else
+ {
+ /* Silently assume this was optimized out; class printing
+ will let the user know why the data is missing. */
+ value->optimized_out = 1;
+ }
}
}
{
struct type *t = type;
int i;
- struct value *v, *result;
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
&& TYPE_CODE (t) != TYPE_CODE_UNION)
for (i = TYPE_NFIELDS (t) - 1; i >= TYPE_N_BASECLASSES (t); i--)
{
- char *t_field_name = TYPE_FIELD_NAME (t, i);
+ const char *t_field_name = TYPE_FIELD_NAME (t, i);
if (t_field_name && strcmp (t_field_name, fieldname) == 0)
{
if (field_is_static (&TYPE_FIELD (t, i)))
{
- gen_static_field (exp, ax, value, t, i);
+ gen_static_field (exp->gdbarch, ax, value, t, i);
+ if (value->optimized_out)
+ error (_("static field `%s' has been "
+ "optimized out, cannot use"),
+ fieldname);
return 1;
}
if (TYPE_FIELD_PACKED (t, i))
sym = cp_lookup_symbol_namespace (namespace_name, name,
block_for_pc (ax->scope),
- VAR_DOMAIN, 0);
+ VAR_DOMAIN);
if (sym == NULL)
return 0;
gen_var_ref (exp->gdbarch, ax, value, sym);
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ SYMBOL_PRINT_NAME (sym));
+
return 1;
}
return 0;
}
-/* Generate code for GDB's magical `repeat' operator.
+/* 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
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);
int length;
if (!v)
- error (_("Right operand of `@' must be a constant, in agent expressions."));
+ error (_("Right operand of `@' must be a "
+ "constant, in agent expressions."));
if (TYPE_CODE (value_type (v)) != TYPE_CODE_INT)
error (_("Right operand of `@' must be an integer."));
length = value_as_long (v);
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. */
/* 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. */
-static void
+void
gen_expr (struct expression *exp, union exp_element **pc,
struct agent_expr *ax, struct axs_value *value)
{
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 (exp->gdbarch)->builtin_int;
/* If we're looking at a constant expression, just push its value. */
{
ax_const_l (ax, 0);
ax_label (ax, end, ax->len);
value->kind = axs_rvalue;
- value->type = language_bool_type (exp->language_defn, exp->gdbarch);
+ value->type = int_type;
break;
case BINOP_LOGICAL_OR:
ax_const_l (ax, 1);
ax_label (ax, end, ax->len);
value->kind = axs_rvalue;
- value->type = language_bool_type (exp->language_defn, exp->gdbarch);
+ value->type = int_type;
break;
case TERNOP_COND:
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,
- language_bool_type (exp->language_defn, exp->gdbarch));
+ gen_logical_not (ax, &value1, int_type);
if1 = ax_goto (ax, aop_if_goto);
gen_expr (exp, pc, ax, &value2);
gen_usual_unary (exp, ax, &value2);
{
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);
ax_tsv (ax, aop_tracev, tsv->number);
}
else
- error (_("$%s is not a trace state variable, may not assign to it"), name);
+ error (_("$%s is not a trace state variable, "
+ "may not assign to it"), name);
}
else
error (_("May only assign to trace state variables"));
{
char *name = internalvar_name ((*pc)[1].internalvar);
struct trace_state_variable *tsv;
+
(*pc) += 3;
tsv = find_trace_state_variable (name);
if (tsv)
ax_tsv (ax, aop_tracev, tsv->number);
}
else
- error (_("$%s is not a trace state variable, may not assign to it"), name);
+ error (_("$%s is not a trace state variable, "
+ "may not assign to it"), name);
}
else
error (_("May only assign to trace state variables"));
/* 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_traced_pop (exp->gdbarch, ax, &value1);
gen_expr (exp, pc, ax, value);
/* It's the consumer's responsibility to trace the right operand. */
break;
{
struct type *type = (*pc)[1].type;
LONGEST k = (*pc)[2].longconst;
+
(*pc) += 4;
gen_int_literal (ax, value, k, type);
}
case OP_VAR_VALUE:
gen_var_ref (exp->gdbarch, ax, value, (*pc)[2].symbol);
+
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ SYMBOL_PRINT_NAME ((*pc)[2].symbol));
+
(*pc) += 4;
break;
{
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 (exp->gdbarch, name, strlen (name));
if (reg == -1)
internal_error (__FILE__, __LINE__,
_("Register $%s not available"), name);
- if (reg >= gdbarch_num_regs (exp->gdbarch))
- error (_("'%s' is a pseudo-register; "
- "GDB cannot yet trace pseudoregister contents."),
+ /* No support for tracing user registers yet. */
+ if (reg >= gdbarch_num_regs (exp->gdbarch)
+ + gdbarch_num_pseudo_regs (exp->gdbarch))
+ error (_("'%s' is a user-register; "
+ "GDB cannot yet trace user-register contents."),
name);
value->kind = axs_lvalue_register;
value->u.reg = reg;
case OP_INTERNALVAR:
{
- const char *name = internalvar_name ((*pc)[1].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)
value->kind = axs_rvalue;
value->type = builtin_type (exp->gdbarch)->builtin_long_long;
}
- else
- error (_("$%s is not a trace state variable; GDB agent expressions cannot use convenience variables."), name);
+ 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;
case UNOP_CAST:
{
struct type *type = (*pc)[1].type;
+
(*pc) += 3;
gen_expr (exp, pc, ax, value);
gen_cast (ax, value, type);
case UNOP_MEMVAL:
{
struct type *type = check_typedef ((*pc)[1].type);
+
(*pc) += 3;
gen_expr (exp, pc, ax, value);
- /* I'm not sure I understand UNOP_MEMVAL entirely. I think
- it's just a hack for dealing with minsyms; you take some
- integer constant, pretend it's the address of an lvalue of
- the given type, and dereference it. */
- if (value->kind != axs_rvalue)
- /* This would be weird. */
- internal_error (__FILE__, __LINE__,
- _("gen_expr: OP_MEMVAL operand isn't an rvalue???"));
+
+ /* 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;
}
case UNOP_PLUS:
(*pc)++;
- /* + FOO is equivalent to 0 + FOO, which can be optimized. */
+ /* + FOO is equivalent to 0 + FOO, which can be optimized. */
gen_expr (exp, pc, ax, value);
gen_usual_unary (exp, ax, value);
break;
(*pc)++;
gen_expr (exp, pc, ax, value);
gen_usual_unary (exp, ax, value);
- gen_logical_not (ax, value,
- language_bool_type (exp->language_defn, exp->gdbarch));
+ gen_logical_not (ax, value, int_type);
break;
case UNOP_COMPLEMENT:
case OP_THIS:
{
char *this_name;
- struct symbol *func, *sym;
+ struct symbol *sym, *func;
struct block *b;
+ const struct language_defn *lang;
- func = block_linkage_function (block_for_pc (ax->scope));
- this_name = language_def (SYMBOL_LANGUAGE (func))->la_name_of_this;
- b = SYMBOL_BLOCK_VALUE (func);
+ b = block_for_pc (ax->scope);
+ func = block_linkage_function (b);
+ lang = language_def (SYMBOL_LANGUAGE (func));
- /* Calling lookup_block_symbol is necessary to get the LOC_REGISTER
- symbol instead of the LOC_ARG one (if both exist). */
- sym = lookup_block_symbol (b, this_name, VAR_DOMAIN);
+ sym = lookup_language_this (lang, b);
if (!sym)
- error (_("no `%s' found"), this_name);
+ error (_("no `%s' found"), lang->la_name_of_this);
gen_var_ref (exp->gdbarch, ax, value, sym);
+
+ if (value->optimized_out)
+ error (_("`%s' has been optimized out, cannot use"),
+ SYMBOL_PRINT_NAME (sym));
+
(*pc) += 2;
}
break;
default:
error (_("Unsupported operator %s (%d) in expression."),
- op_string (op), op);
+ op_name (exp, op), op);
}
}
struct agent_expr *ax, struct axs_value *value,
struct axs_value *value1, struct axs_value *value2)
{
+ struct type *int_type = builtin_type (exp->gdbarch)->builtin_int;
+
gen_expr (exp, pc, ax, value2);
gen_usual_unary (exp, ax, value2);
gen_usual_arithmetic (exp, ax, value1, value2);
if (binop_types_user_defined_p (op, value1->type, value2->type))
{
- error (_("\
-cannot subscript requested type: cannot call user defined functions"));
+ error (_("cannot subscript requested type: "
+ "cannot call user defined functions"));
}
else
{
}
if (!is_integral_type (value2->type))
- error (_("Argument to arithmetic operation not a number or boolean."));
+ error (_("Argument to arithmetic operation "
+ "not a number or boolean."));
gen_ptradd (ax, value, value1, value2);
gen_deref (ax, value);
break;
case BINOP_EQUAL:
- gen_binop (ax, value, value1, value2,
- aop_equal, aop_equal, 0, "equal");
+ gen_equal (ax, value, value1, value2, int_type);
break;
case BINOP_NOTEQUAL:
- gen_binop (ax, value, value1, value2,
- aop_equal, aop_equal, 0, "equal");
- gen_logical_not (ax, value,
- language_bool_type (exp->language_defn,
- exp->gdbarch));
+ gen_equal (ax, value, value1, value2, int_type);
+ gen_logical_not (ax, value, int_type);
break;
case BINOP_LESS:
- gen_binop (ax, value, value1, value2,
- aop_less_signed, aop_less_unsigned, 0, "less than");
+ gen_less (ax, value, value1, value2, int_type);
break;
case BINOP_GTR:
ax_simple (ax, aop_swap);
- gen_binop (ax, value, value1, value2,
- aop_less_signed, aop_less_unsigned, 0, "less than");
+ gen_less (ax, value, value1, value2, int_type);
break;
case BINOP_LEQ:
ax_simple (ax, aop_swap);
- gen_binop (ax, value, value1, value2,
- aop_less_signed, aop_less_unsigned, 0, "less than");
- gen_logical_not (ax, value,
- language_bool_type (exp->language_defn,
- exp->gdbarch));
+ gen_less (ax, value, value1, value2, int_type);
+ gen_logical_not (ax, value, int_type);
break;
case BINOP_GEQ:
- gen_binop (ax, value, value1, value2,
- aop_less_signed, aop_less_unsigned, 0, "less than");
- gen_logical_not (ax, value,
- language_bool_type (exp->language_defn,
- exp->gdbarch));
+ gen_less (ax, value, value1, value2, int_type);
+ gen_logical_not (ax, value, int_type);
break;
default:
name comes from a list of local variables of a function. */
struct agent_expr *
-gen_trace_for_var (CORE_ADDR scope, struct symbol *var)
+gen_trace_for_var (CORE_ADDR scope, struct gdbarch *gdbarch,
+ struct symbol *var)
{
struct cleanup *old_chain = 0;
- struct agent_expr *ax = new_agent_expr (scope);
+ struct agent_expr *ax = new_agent_expr (gdbarch, scope);
struct axs_value value;
old_chain = make_cleanup_free_agent_expr (ax);
trace_kludge = 1;
- gen_var_ref (NULL, ax, &value, var);
+ gen_var_ref (gdbarch, ax, &value, var);
+
+ /* If there is no actual variable to trace, flag it by returning
+ an empty agent expression. */
+ if (value.optimized_out)
+ {
+ do_cleanups (old_chain);
+ return NULL;
+ }
/* Make sure we record the final object, and get rid of it. */
- gen_traced_pop (ax, &value);
+ gen_traced_pop (gdbarch, ax, &value);
/* Oh, and terminate. */
ax_simple (ax, aop_end);
gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
{
struct cleanup *old_chain = 0;
- struct agent_expr *ax = new_agent_expr (scope);
+ struct agent_expr *ax = new_agent_expr (expr->gdbarch, scope);
union exp_element *pc;
struct axs_value value;
pc = expr->elts;
trace_kludge = 1;
+ value.optimized_out = 0;
gen_expr (expr, &pc, ax, &value);
/* Make sure we record the final object, and get rid of it. */
- gen_traced_pop (ax, &value);
+ gen_traced_pop (expr->gdbarch, ax, &value);
/* Oh, and terminate. */
ax_simple (ax, aop_end);
gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
{
struct cleanup *old_chain = 0;
- struct agent_expr *ax = new_agent_expr (scope);
+ struct agent_expr *ax = new_agent_expr (expr->gdbarch, scope);
union exp_element *pc;
struct axs_value value;
pc = expr->elts;
trace_kludge = 0;
+ value.optimized_out = 0;
gen_expr (expr, &pc, ax, &value);
+ require_rvalue (ax, &value);
+
+ /* Oh, and terminate. */
+ ax_simple (ax, aop_end);
+
+ /* We have successfully built the agent expr, so cancel the cleanup
+ request. If we add more cleanups that we always want done, this
+ will have to get more complicated. */
+ discard_cleanups (old_chain);
+ return ax;
+}
+
+struct agent_expr *
+gen_trace_for_return_address (CORE_ADDR scope, struct gdbarch *gdbarch)
+{
+ struct cleanup *old_chain = 0;
+ struct agent_expr *ax = new_agent_expr (gdbarch, scope);
+ struct axs_value value;
+
+ old_chain = make_cleanup_free_agent_expr (ax);
+
+ trace_kludge = 1;
+
+ gdbarch_gen_return_address (gdbarch, ax, &value, scope);
+
+ /* Make sure we record the final object, and get rid of it. */
+ gen_traced_pop (gdbarch, ax, &value);
+
/* Oh, and terminate. */
ax_simple (ax, aop_end);
if (exp == 0)
error_no_arg (_("expression to translate"));
- expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
- agent = gen_trace_for_expr (get_frame_pc (fi), expr);
- make_cleanup_free_agent_expr (agent);
+ trace_string_kludge = 0;
+ if (*exp == '/')
+ exp = decode_agent_options (exp);
+
+ /* Recognize the return address collection directive specially. Note
+ that it is not really an expression of any sort. */
+ if (strcmp (exp, "$_ret") == 0)
+ {
+ agent = gen_trace_for_return_address (get_frame_pc (fi),
+ get_current_arch ());
+ old_chain = make_cleanup_free_agent_expr (agent);
+ }
+ else
+ {
+ expr = parse_expression (exp);
+ old_chain = make_cleanup (free_current_contents, &expr);
+ agent = gen_trace_for_expr (get_frame_pc (fi), expr);
+ make_cleanup_free_agent_expr (agent);
+ }
+
+ ax_reqs (agent);
ax_print (gdb_stdout, agent);
/* It would be nice to call ax_reqs here to gather some general info
old_chain = make_cleanup (free_current_contents, &expr);
agent = gen_eval_for_expr (get_frame_pc (fi), expr);
make_cleanup_free_agent_expr (agent);
+ ax_reqs (agent);
ax_print (gdb_stdout, agent);
/* It would be nice to call ax_reqs here to gather some general info
_initialize_ax_gdb (void)
{
add_cmd ("agent", class_maintenance, agent_command,
- _("Translate an expression into remote agent bytecode for tracing."),
+ _("Translate an expression into "
+ "remote agent bytecode for tracing."),
&maintenancelist);
add_cmd ("agent-eval", class_maintenance, agent_eval_command,
- _("Translate an expression into remote agent bytecode for evaluation."),
+ _("Translate an expression into remote "
+ "agent bytecode for evaluation."),
&maintenancelist);
}