#undef DEFOP
};
+static const unsigned char gdb_agent_op_sizes [gdb_agent_op_last] =
+ {
+ 0
+#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , SIZE
+#include "ax.def"
+#undef DEFOP
+ };
+
struct agent_expr
{
int length;
target_emit_ops ()->emit_void_call_2 (fn, arg1);
}
+static void
+emit_eq_goto (int *offset_p, int *size_p)
+{
+ target_emit_ops ()->emit_eq_goto (offset_p, size_p);
+}
+
+static void
+emit_ne_goto (int *offset_p, int *size_p)
+{
+ target_emit_ops ()->emit_ne_goto (offset_p, size_p);
+}
+
+static void
+emit_lt_goto (int *offset_p, int *size_p)
+{
+ target_emit_ops ()->emit_lt_goto (offset_p, size_p);
+}
+
+static void
+emit_ge_goto (int *offset_p, int *size_p)
+{
+ target_emit_ops ()->emit_ge_goto (offset_p, size_p);
+}
+
+static void
+emit_gt_goto (int *offset_p, int *size_p)
+{
+ target_emit_ops ()->emit_gt_goto (offset_p, size_p);
+}
+
+static void
+emit_le_goto (int *offset_p, int *size_p)
+{
+ target_emit_ops ()->emit_le_goto (offset_p, size_p);
+}
+
static enum eval_result_type compile_bytecodes (struct agent_expr *aexpr);
static void
*jump_entry += 16;
}
+/* Scan an agent expression for any evidence that the given PC is the
+ target of a jump bytecode in the expression. */
+
+int
+is_goto_target (struct agent_expr *aexpr, int pc)
+{
+ int i;
+ unsigned char op;
+
+ for (i = 0; i < aexpr->length; i += 1 + gdb_agent_op_sizes[op])
+ {
+ op = aexpr->bytes[i];
+
+ if (op == gdb_agent_op_goto || op == gdb_agent_op_if_goto)
+ {
+ int target = (aexpr->bytes[i + 1] << 8) + aexpr->bytes[i + 2];
+ if (target == pc)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* Given an agent expression, turn it into native code. */
static enum eval_result_type
{
int pc = 0;
int done = 0;
- unsigned char op;
+ unsigned char op, next_op;
int arg;
/* This is only used to build 64-bit value for constants. */
ULONGEST top;
break;
case gdb_agent_op_equal:
- emit_equal ();
+ next_op = aexpr->bytes[pc];
+ if (next_op == gdb_agent_op_if_goto
+ && !is_goto_target (aexpr, pc)
+ && target_emit_ops ()->emit_eq_goto)
+ {
+ trace_debug ("Combining equal & if_goto");
+ pc += 1;
+ aentry->pc = pc;
+ arg = aexpr->bytes[pc++];
+ arg = (arg << 8) + aexpr->bytes[pc++];
+ aentry->goto_pc = arg;
+ emit_eq_goto (&(aentry->from_offset), &(aentry->from_size));
+ }
+ else if (next_op == gdb_agent_op_log_not
+ && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
+ && !is_goto_target (aexpr, pc + 1)
+ && target_emit_ops ()->emit_ne_goto)
+ {
+ trace_debug ("Combining equal & log_not & if_goto");
+ pc += 2;
+ aentry->pc = pc;
+ arg = aexpr->bytes[pc++];
+ arg = (arg << 8) + aexpr->bytes[pc++];
+ aentry->goto_pc = arg;
+ emit_ne_goto (&(aentry->from_offset), &(aentry->from_size));
+ }
+ else
+ emit_equal ();
break;
case gdb_agent_op_less_signed:
- emit_less_signed ();
+ next_op = aexpr->bytes[pc];
+ if (next_op == gdb_agent_op_if_goto
+ && !is_goto_target (aexpr, pc))
+ {
+ trace_debug ("Combining less_signed & if_goto");
+ pc += 1;
+ aentry->pc = pc;
+ arg = aexpr->bytes[pc++];
+ arg = (arg << 8) + aexpr->bytes[pc++];
+ aentry->goto_pc = arg;
+ emit_lt_goto (&(aentry->from_offset), &(aentry->from_size));
+ }
+ else if (next_op == gdb_agent_op_log_not
+ && !is_goto_target (aexpr, pc)
+ && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
+ && !is_goto_target (aexpr, pc + 1))
+ {
+ trace_debug ("Combining less_signed & log_not & if_goto");
+ pc += 2;
+ aentry->pc = pc;
+ arg = aexpr->bytes[pc++];
+ arg = (arg << 8) + aexpr->bytes[pc++];
+ aentry->goto_pc = arg;
+ emit_ge_goto (&(aentry->from_offset), &(aentry->from_size));
+ }
+ else
+ emit_less_signed ();
break;
case gdb_agent_op_less_unsigned:
break;
case gdb_agent_op_swap:
- emit_swap ();
+ next_op = aexpr->bytes[pc];
+ /* Detect greater-than comparison sequences. */
+ if (next_op == gdb_agent_op_less_signed
+ && !is_goto_target (aexpr, pc)
+ && (aexpr->bytes[pc + 1] == gdb_agent_op_if_goto)
+ && !is_goto_target (aexpr, pc + 1))
+ {
+ trace_debug ("Combining swap & less_signed & if_goto");
+ pc += 2;
+ aentry->pc = pc;
+ arg = aexpr->bytes[pc++];
+ arg = (arg << 8) + aexpr->bytes[pc++];
+ aentry->goto_pc = arg;
+ emit_gt_goto (&(aentry->from_offset), &(aentry->from_size));
+ }
+ else if (next_op == gdb_agent_op_less_signed
+ && !is_goto_target (aexpr, pc)
+ && (aexpr->bytes[pc + 1] == gdb_agent_op_log_not)
+ && !is_goto_target (aexpr, pc + 1)
+ && (aexpr->bytes[pc + 2] == gdb_agent_op_if_goto)
+ && !is_goto_target (aexpr, pc + 2))
+ {
+ trace_debug ("Combining swap & less_signed & log_not & if_goto");
+ pc += 3;
+ aentry->pc = pc;
+ arg = aexpr->bytes[pc++];
+ arg = (arg << 8) + aexpr->bytes[pc++];
+ aentry->goto_pc = arg;
+ emit_le_goto (&(aentry->from_offset), &(aentry->from_size));
+ }
+ else
+ emit_swap ();
break;
case gdb_agent_op_getv: