+2010-04-23 Stan Shebs <stan@codesourcery.com>
+
+ * ax.h (struct agent_expr): Merge in agent_reqs fields, add some
+ comments.
+ (struct agent_reqs): Remove.
+ (ax_reg_mask): Declare.
+ * ax-general.c (new_agent_expr): Add gdbarch argument, set new fields.
+ (free_agent_expr): Free reg_mask.
+ (ax_print): Add scope and register mask info.
+ (ax_reqs): Remove agent_reqs argument, use agent expression
+ fields, and move part of register mask computation to...
+ (ax_reg_mask): New function.
+ * ax-gdb.c (gen_trace_static_fields): Call it.
+ (gen_traced_pop): Ditto.
+ (is_nontrivial_conversion): Add dummy gdbarch to new_agent_expr.
+ (gen_trace_for_var): Pass gdbarch to new_agent_expr.
+ (gen_trace_for_expr): Ditto, and clear optimized_out flag.
+ (gen_eval_for_expr): Ditto, and require an rvalue.
+ (agent_command): Call ax_reqs.
+ (agent_eval_command): Ditto.
+ * tracepoint.c (report_agent_reqs_errors): Use agent expression fields.
+ (validate_action_line): Ditto.
+ (collect_symbol): Ditto.
+ (encode_actions_1): Ditto.
+
2010-04-23 Daniel Jacobowitz <dan@codesourcery.com>
Paul Pluzhnikov <ppluzhnikov@google.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
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);
+ /* 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;
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
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
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);
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_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
/* Allocate a new, empty agent expression. */
struct agent_expr *
-new_agent_expr (CORE_ADDR scope)
+new_agent_expr (struct gdbarch *gdbarch, CORE_ADDR scope)
{
struct agent_expr *x = xmalloc (sizeof (*x));
+
x->len = 0;
x->size = 1; /* Change this to a larger value once
reallocation code is tested. */
x->buf = xmalloc (x->size);
+
+ x->gdbarch = gdbarch;
x->scope = scope;
+ /* Bit vector for registers used. */
+ x->reg_mask_len = 1;
+ x->reg_mask = xmalloc (x->reg_mask_len * sizeof (x->reg_mask[0]));
+ memset (x->reg_mask, 0, x->reg_mask_len * sizeof (x->reg_mask[0]));
+
return x;
}
free_agent_expr (struct agent_expr *x)
{
xfree (x->buf);
+ xfree (x->reg_mask);
xfree (x);
}
int i;
int is_float = 0;
+ fprintf_filtered (f, _("Scope: %s\n"), paddress (x->gdbarch, x->scope));
+ fprintf_filtered (f, _("Reg mask:"));
+ for (i = 0; i < x->reg_mask_len; ++i)
+ fprintf_filtered (f, _(" %02x"), x->reg_mask[i]);
+ fprintf_filtered (f, _("\n"));
+
/* Check the size of the name array against the number of entries in
the enum, to catch additions that people didn't sync. */
if ((sizeof (aop_map) / sizeof (aop_map[0]))
}
}
+/* Add register REG to the register mask for expression AX. */
+void
+ax_reg_mask (struct agent_expr *ax, int reg)
+{
+ int byte = reg / 8;
-/* Given an agent expression AX, fill in an agent_reqs structure REQS
- describing it. */
+ /* Grow the bit mask if necessary. */
+ if (byte >= ax->reg_mask_len)
+ {
+ /* It's not appropriate to double here. This isn't a
+ string buffer. */
+ int new_len = byte + 1;
+ unsigned char *new_reg_mask = xrealloc (ax->reg_mask,
+ new_len * sizeof (ax->reg_mask[0]));
+ memset (new_reg_mask + ax->reg_mask_len, 0,
+ (new_len - ax->reg_mask_len) * sizeof (ax->reg_mask[0]));
+ ax->reg_mask_len = new_len;
+ ax->reg_mask = new_reg_mask;
+ }
+
+ ax->reg_mask[byte] |= 1 << (reg % 8);
+}
+
+/* Given an agent expression AX, fill in requirements and other descriptive
+ bits. */
void
-ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs)
+ax_reqs (struct agent_expr *ax)
{
int i;
int height;
- /* Bit vector for registers used. */
- int reg_mask_len = 1;
- unsigned char *reg_mask = xmalloc (reg_mask_len * sizeof (reg_mask[0]));
-
/* Jump target table. targets[i] is non-zero iff we have found a
jump to offset i. */
char *targets = (char *) alloca (ax->len * sizeof (targets[0]));
/* Pointer to a description of the present op. */
struct aop_map *op;
- memset (reg_mask, 0, reg_mask_len * sizeof (reg_mask[0]));
memset (targets, 0, ax->len * sizeof (targets[0]));
memset (boundary, 0, ax->len * sizeof (boundary[0]));
- reqs->max_height = reqs->min_height = height = 0;
- reqs->flaw = agent_flaw_none;
- reqs->max_data_size = 0;
+ ax->max_height = ax->min_height = height = 0;
+ ax->flaw = agent_flaw_none;
+ ax->max_data_size = 0;
for (i = 0; i < ax->len; i += 1 + op->op_size)
{
if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
{
- reqs->flaw = agent_flaw_bad_instruction;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_bad_instruction;
return;
}
if (!op->name)
{
- reqs->flaw = agent_flaw_bad_instruction;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_bad_instruction;
return;
}
if (i + 1 + op->op_size > ax->len)
{
- reqs->flaw = agent_flaw_incomplete_instruction;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_incomplete_instruction;
return;
}
source? */
if (targets[i] && (heights[i] != height))
{
- reqs->flaw = agent_flaw_height_mismatch;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_height_mismatch;
return;
}
heights[i] = height;
height -= op->consumed;
- if (height < reqs->min_height)
- reqs->min_height = height;
+ if (height < ax->min_height)
+ ax->min_height = height;
height += op->produced;
- if (height > reqs->max_height)
- reqs->max_height = height;
+ if (height > ax->max_height)
+ ax->max_height = height;
- if (op->data_size > reqs->max_data_size)
- reqs->max_data_size = op->data_size;
+ if (op->data_size > ax->max_data_size)
+ ax->max_data_size = op->data_size;
/* For jump instructions, check that the target is a valid
offset. If it is, record the fact that that location is a
int target = read_const (ax, i + 1, 2);
if (target < 0 || target >= ax->len)
{
- reqs->flaw = agent_flaw_bad_jump;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_bad_jump;
return;
}
{
if (heights[target] != height)
{
- reqs->flaw = agent_flaw_height_mismatch;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_height_mismatch;
return;
}
}
{
if (!targets[i + 3])
{
- reqs->flaw = agent_flaw_hole;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_hole;
return;
}
if (aop_reg == op - aop_map)
{
int reg = read_const (ax, i + 1, 2);
- int byte = reg / 8;
-
- /* Grow the bit mask if necessary. */
- if (byte >= reg_mask_len)
- {
- /* It's not appropriate to double here. This isn't a
- string buffer. */
- int new_len = byte + 1;
- reg_mask = xrealloc (reg_mask,
- new_len * sizeof (reg_mask[0]));
- memset (reg_mask + reg_mask_len, 0,
- (new_len - reg_mask_len) * sizeof (reg_mask[0]));
- reg_mask_len = new_len;
- }
- reg_mask[byte] |= 1 << (reg % 8);
+ ax_reg_mask (ax, reg);
}
}
for (i = 0; i < ax->len; i++)
if (targets[i] && !boundary[i])
{
- reqs->flaw = agent_flaw_bad_jump;
- xfree (reg_mask);
+ ax->flaw = agent_flaw_bad_jump;
return;
}
- reqs->final_height = height;
- reqs->reg_mask_len = reg_mask_len;
- reqs->reg_mask = reg_mask;
+ ax->final_height = height;
}
to the host GDB. */
\f
+/* Different kinds of flaws an agent expression might have, as
+ detected by ax_reqs. */
+enum agent_flaws
+ {
+ agent_flaw_none = 0, /* code is good */
+
+ /* There is an invalid instruction in the stream. */
+ agent_flaw_bad_instruction,
+
+ /* There is an incomplete instruction at the end of the expression. */
+ agent_flaw_incomplete_instruction,
+
+ /* ax_reqs was unable to prove that every jump target is to a
+ valid offset. Valid offsets are within the bounds of the
+ expression, and to a valid instruction boundary. */
+ agent_flaw_bad_jump,
+
+ /* ax_reqs was unable to prove to its satisfaction that, for each
+ jump target location, the stack will have the same height whether
+ that location is reached via a jump or by straight execution. */
+ agent_flaw_height_mismatch,
+
+ /* ax_reqs was unable to prove that every instruction following
+ an unconditional jump was the target of some other jump. */
+ agent_flaw_hole
+ };
+
/* Agent expression data structures. */
/* The type of an element of the agent expression stack.
/* A buffer containing a agent expression. */
struct agent_expr
{
+ /* The bytes of the expression. */
unsigned char *buf;
- int len; /* number of characters used */
- int size; /* allocated size */
+
+ /* The number of bytecode in the expression. */
+ int len;
+
+ /* Allocated space available currently. */
+ int size;
+
+ /* The target architecture assumed to be in effect. */
+ struct gdbarch *gdbarch;
+
+ /* The address to which the expression applies. */
CORE_ADDR scope;
- };
+ /* If the following is not equal to agent_flaw_none, the rest of the
+ information in this structure is suspect. */
+ enum agent_flaws flaw;
+
+ /* Number of elements left on stack at end; may be negative if expr
+ only consumes elements. */
+ int final_height;
+
+ /* Maximum and minimum stack height, relative to initial height. */
+ int max_height, min_height;
+
+ /* Largest `ref' or `const' opcode used, in bits. Zero means the
+ expression has no such instructions. */
+ int max_data_size;
+
+ /* Bit vector of registers needed. Register R is needed iff
+ reg_mask[R / 8] & (1 << (R % 8))
+ is non-zero. Note! You may not assume that this bitmask is long
+ enough to hold bits for all the registers of the machine; the
+ agent expression code has no idea how many registers the machine
+ has. However, the bitmask is reg_mask_len bytes long, so the
+ valid register numbers run from 0 to reg_mask_len * 8 - 1.
+
+ Also note that this mask may contain registers that are needed
+ for the original collection expression to work, but that are
+ not referenced by any bytecode. This could, for example, occur
+ when collecting a local variable allocated to a register; the
+ compiler sets the mask bit and skips generating a bytecode whose
+ result is going to be discarded anyway.
+ */
+ int reg_mask_len;
+ unsigned char *reg_mask;
+ };
/* The actual values of the various bytecode operations.
/* Functions for building expressions. */
/* Allocate a new, empty agent expression. */
-extern struct agent_expr *new_agent_expr (CORE_ADDR);
+extern struct agent_expr *new_agent_expr (struct gdbarch *, CORE_ADDR);
/* Free a agent expression. */
extern void free_agent_expr (struct agent_expr *);
stack. */
extern void ax_reg (struct agent_expr *EXPR, int REG);
+/* Add the given register to the register mask of the expression. */
+extern void ax_reg_mask (struct agent_expr *ax, int reg);
+
/* Assemble code to operate on a trace state variable. */
extern void ax_tsv (struct agent_expr *expr, enum agent_op op, int num);
\f
/* Map of the bytecodes, indexed by bytecode number. */
extern struct aop_map aop_map[];
-/* Different kinds of flaws an agent expression might have, as
- detected by agent_reqs. */
-enum agent_flaws
- {
- agent_flaw_none = 0, /* code is good */
-
- /* There is an invalid instruction in the stream. */
- agent_flaw_bad_instruction,
-
- /* There is an incomplete instruction at the end of the expression. */
- agent_flaw_incomplete_instruction,
-
- /* agent_reqs was unable to prove that every jump target is to a
- valid offset. Valid offsets are within the bounds of the
- expression, and to a valid instruction boundary. */
- agent_flaw_bad_jump,
-
- /* agent_reqs was unable to prove to its satisfaction that, for each
- jump target location, the stack will have the same height whether
- that location is reached via a jump or by straight execution. */
- agent_flaw_height_mismatch,
-
- /* agent_reqs was unable to prove that every instruction following
- an unconditional jump was the target of some other jump. */
- agent_flaw_hole
- };
-
-/* Structure describing the requirements of a bytecode expression. */
-struct agent_reqs
- {
-
- /* If the following is not equal to agent_flaw_none, the rest of the
- information in this structure is suspect. */
- enum agent_flaws flaw;
-
- /* Number of elements left on stack at end; may be negative if expr
- only consumes elements. */
- int final_height;
-
- /* Maximum and minimum stack height, relative to initial height. */
- int max_height, min_height;
-
- /* Largest `ref' or `const' opcode used, in bits. Zero means the
- expression has no such instructions. */
- int max_data_size;
-
- /* Bit vector of registers used. Register R is used iff
-
- reg_mask[R / 8] & (1 << (R % 8))
-
- is non-zero. Note! You may not assume that this bitmask is long
- enough to hold bits for all the registers of the machine; the
- agent expression code has no idea how many registers the machine
- has. However, the bitmask is reg_mask_len bytes long, so the
- valid register numbers run from 0 to reg_mask_len * 8 - 1.
-
- We're assuming eight-bit bytes. So sue me.
-
- The caller should free reg_list when done. */
- int reg_mask_len;
- unsigned char *reg_mask;
- };
-
+/* Given an agent expression AX, analyze and update its requirements. */
-/* Given an agent expression AX, fill in an agent_reqs structure REQS
- describing it. */
-extern void ax_reqs (struct agent_expr *ax, struct agent_reqs *reqs);
+extern void ax_reqs (struct agent_expr *ax);
#endif /* AGENTEXPR_H */
internal errors. */
static void
-report_agent_reqs_errors (struct agent_expr *aexpr, struct agent_reqs *areqs)
+report_agent_reqs_errors (struct agent_expr *aexpr)
{
/* All of the "flaws" are serious bytecode generation issues that
should never occur. */
- if (areqs->flaw != agent_flaw_none)
+ if (aexpr->flaw != agent_flaw_none)
internal_error (__FILE__, __LINE__, _("expression is malformed"));
/* If analysis shows a stack underflow, GDB must have done something
badly wrong in its bytecode generation. */
- if (areqs->min_height < 0)
+ if (aexpr->min_height < 0)
internal_error (__FILE__, __LINE__,
_("expression has min height < 0"));
depth roughly corresponds to parenthesization, so a limit of 20
amounts to 20 levels of expression nesting, which is actually
a pretty big hairy expression. */
- if (areqs->max_height > 20)
+ if (aexpr->max_height > 20)
error (_("Expression is too complicated."));
}
char *p, *tmp_p;
struct bp_location *loc;
struct agent_expr *aexpr;
- struct agent_reqs areqs;
/* if EOF is typed, *line is NULL */
if (*line == NULL)
if (aexpr->len > MAX_AGENT_EXPR_LEN)
error (_("Expression is too complicated."));
- ax_reqs (aexpr, &areqs);
- (void) make_cleanup (xfree, areqs.reg_mask);
+ ax_reqs (aexpr);
- report_agent_reqs_errors (aexpr, &areqs);
+ report_agent_reqs_errors (aexpr);
do_cleanups (old_chain);
}
if (aexpr->len > MAX_AGENT_EXPR_LEN)
error (_("Expression is too complicated."));
- ax_reqs (aexpr, &areqs);
- (void) make_cleanup (xfree, areqs.reg_mask);
-
- report_agent_reqs_errors (aexpr, &areqs);
+ ax_reqs (aexpr);
+ report_agent_reqs_errors (aexpr);
do_cleanups (old_chain);
}
{
struct agent_expr *aexpr;
struct cleanup *old_chain1 = NULL;
- struct agent_reqs areqs;
aexpr = gen_trace_for_var (scope, gdbarch, sym);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
- ax_reqs (aexpr, &areqs);
+ ax_reqs (aexpr);
- report_agent_reqs_errors (aexpr, &areqs);
+ report_agent_reqs_errors (aexpr);
discard_cleanups (old_chain1);
add_aexpr (collect, aexpr);
/* take care of the registers */
- if (areqs.reg_mask_len > 0)
+ if (aexpr->reg_mask_len > 0)
{
int ndx1, ndx2;
- for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+ for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
{
QUIT; /* allow user to bail out with ^C */
- if (areqs.reg_mask[ndx1] != 0)
+ if (aexpr->reg_mask[ndx1] != 0)
{
/* assume chars have 8 bits */
for (ndx2 = 0; ndx2 < 8; ndx2++)
- if (areqs.reg_mask[ndx1] & (1 << ndx2))
+ if (aexpr->reg_mask[ndx1] & (1 << ndx2))
/* it's used -- record it */
add_register (collect, ndx1 * 8 + ndx2);
}
unsigned long addr, len;
struct cleanup *old_chain = NULL;
struct cleanup *old_chain1 = NULL;
- struct agent_reqs areqs;
exp = parse_exp_1 (&action_exp,
block_for_pc (tloc->address), 1);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
- ax_reqs (aexpr, &areqs);
+ ax_reqs (aexpr);
- report_agent_reqs_errors (aexpr, &areqs);
+ report_agent_reqs_errors (aexpr);
discard_cleanups (old_chain1);
add_aexpr (collect, aexpr);
/* take care of the registers */
- if (areqs.reg_mask_len > 0)
+ if (aexpr->reg_mask_len > 0)
{
int ndx1;
int ndx2;
- for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++)
+ for (ndx1 = 0; ndx1 < aexpr->reg_mask_len; ndx1++)
{
QUIT; /* allow user to bail out with ^C */
- if (areqs.reg_mask[ndx1] != 0)
+ if (aexpr->reg_mask[ndx1] != 0)
{
/* assume chars have 8 bits */
for (ndx2 = 0; ndx2 < 8; ndx2++)
- if (areqs.reg_mask[ndx1] & (1 << ndx2))
+ if (aexpr->reg_mask[ndx1] & (1 << ndx2))
/* it's used -- record it */
add_register (collect,
ndx1 * 8 + ndx2);
unsigned long addr, len;
struct cleanup *old_chain = NULL;
struct cleanup *old_chain1 = NULL;
- struct agent_reqs areqs;
exp = parse_exp_1 (&action_exp,
block_for_pc (tloc->address), 1);
aexpr = gen_eval_for_expr (tloc->address, exp);
old_chain1 = make_cleanup_free_agent_expr (aexpr);
- ax_reqs (aexpr, &areqs);
-
- report_agent_reqs_errors (aexpr, &areqs);
+ ax_reqs (aexpr);
+ report_agent_reqs_errors (aexpr);
discard_cleanups (old_chain1);
/* Even though we're not officially collecting, add