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,
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,
{
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;
+
+/* 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)
{
if (trace_kludge)
switch (value->kind)
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);
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));
}
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))
{
/* 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))
{
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:
static 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_UNION:
return;
- /* If the value is an enum, call it an integer. */
+ /* If the value is an enum or a bool, call it an integer. */
case TYPE_CODE_ENUM:
+ case TYPE_CODE_BOOL:
value->type = builtin_type (exp->gdbarch)->builtin_int;
break;
}
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
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
{
/* 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
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;
}
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);
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)
{
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))
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;
}
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);
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. */
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);
{
char *name = internalvar_name ((*pc)[1].internalvar);
struct trace_state_variable *tsv;
+
(*pc) += 3;
tsv = find_trace_state_variable (name);
if (tsv)
/* 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)
{
const char *name = internalvar_name ((*pc)[1].internalvar);
struct trace_state_variable *tsv;
+
(*pc) += 3;
tsv = find_trace_state_variable (name);
if (tsv)
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
(*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:
error (_("no `%s' found"), this_name);
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;
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);
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);
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