#if HAVE_STDINT_H
#include <stdint.h>
#endif
+#include "ax.h"
/* This file is built for both GDBserver, and the in-process
agent (IPA), a shared library that includes a tracing agent that is
va_start (ap, fmt);
vsprintf (buf, fmt, ap);
-#ifdef IN_PROCESS_AGENT
- fprintf (stderr, "ipa/tracepoint: %s\n", buf);
-#else
- fprintf (stderr, "gdbserver/tracepoint: %s\n", buf);
-#endif
+ fprintf (stderr, PROG "/tracepoint: %s\n", buf);
va_end (ap);
}
-#ifdef IN_PROCESS_AGENT
-#define debug_threads debug_agent
-#endif
-
#define trace_debug_1(level, fmt, args...) \
do { \
if (level <= debug_threads) \
GDBserver side. */
#ifdef IN_PROCESS_AGENT
-int debug_agent = 0;
-
int
read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
{
#endif
-/* This enum must exactly match what is documented in
- gdb/doc/agentexpr.texi, including all the numerical values. */
-
-enum gdb_agent_op
- {
-#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) \
- gdb_agent_op_ ## NAME = VALUE,
-#include "ax.def"
-#undef DEFOP
- gdb_agent_op_last
- };
-
-static const char *gdb_agent_op_names [gdb_agent_op_last] =
- {
- "?undef?"
-#define DEFOP(NAME, SIZE, DATA_SIZE, CONSUMED, PRODUCED, VALUE) , # NAME
-#include "ax.def"
-#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;
-
- unsigned char *bytes;
-};
-
/* Base action. Concrete actions inherit this. */
struct tracepoint_action
IP_AGENT_EXPORT int trace_buffer_is_full;
-/* Enumeration of the different kinds of things that can happen during
- agent expression evaluation. */
-
-enum eval_result_type
- {
- expr_eval_no_error,
- expr_eval_empty_expression,
- expr_eval_empty_stack,
- expr_eval_stack_overflow,
- expr_eval_stack_underflow,
- expr_eval_unhandled_opcode,
- expr_eval_unrecognized_opcode,
- expr_eval_divide_by_zero,
- expr_eval_invalid_goto
- };
-
static enum eval_result_type expr_eval_result = expr_eval_no_error;
#ifndef IN_PROCESS_AGENT
#endif
-#ifndef IN_PROCESS_AGENT
-static struct agent_expr *parse_agent_expr (char **actparm);
-static char *unparse_agent_expr (struct agent_expr *aexpr);
-#endif
-static enum eval_result_type eval_agent_expr (struct tracepoint_hit_ctx *ctx,
- struct traceframe *tframe,
- struct agent_expr *aexpr,
- ULONGEST *rslt);
-
-static int agent_mem_read (struct traceframe *tframe,
- unsigned char *to, CORE_ADDR from, ULONGEST len);
-static int agent_mem_read_string (struct traceframe *tframe,
- unsigned char *to, CORE_ADDR from,
- ULONGEST len);
-static int agent_tsv_read (struct traceframe *tframe, int n);
+static enum eval_result_type
+eval_tracepoint_agent_expr (struct tracepoint_hit_ctx *ctx,
+ struct traceframe *tframe,
+ struct agent_expr *aexpr,
+ ULONGEST *rslt);
#ifndef IN_PROCESS_AGENT
static CORE_ADDR traceframe_get_pc (struct traceframe *tframe);
action = &xaction->base;
trace_debug ("Want to evaluate expression");
- xaction->expr = parse_agent_expr (&act);
+ xaction->expr = gdb_parse_agent_expr (&act);
break;
}
default:
tsv->value = val;
}
+LONGEST
+agent_get_trace_state_variable_value (int num)
+{
+ return get_trace_state_variable_value (num);
+}
+
+void
+agent_set_trace_state_variable_value (int num, LONGEST val)
+{
+ set_trace_state_variable_value (num, val);
+}
+
static void
set_trace_state_variable_name (int num, const char *name)
{
else if (*packet == 'X')
{
actparm = (char *) packet;
- tpoint->cond = parse_agent_expr (&actparm);
+ tpoint->cond = gdb_parse_agent_expr (&actparm);
packet = actparm;
}
else if (*packet == '-')
if (tpoint->cond)
{
- buf = unparse_agent_expr (tpoint->cond);
+ buf = gdb_unparse_agent_expr (tpoint->cond);
sprintf (packet + strlen (packet), ":X%x,%s",
tpoint->cond->length, buf);
free (buf);
trace_debug ("Want to evaluate expression");
- err = eval_agent_expr (ctx, tframe, eaction->expr, NULL);
+ err = eval_tracepoint_agent_expr (ctx, tframe, eaction->expr, NULL);
if (err != expr_eval_no_error)
{
err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (ctx, &value);
else
#endif
- err = eval_agent_expr (ctx, NULL, tpoint->cond, &value);
+ err = eval_tracepoint_agent_expr (ctx, NULL, tpoint->cond, &value);
if (err != expr_eval_no_error)
{
return (value ? 1 : 0);
}
-#ifndef IN_PROCESS_AGENT
-
-/* The packet form of an agent expression consists of an 'X', number
- of bytes in expression, a comma, and then the bytes. */
-
-static struct agent_expr *
-parse_agent_expr (char **actparm)
-{
- char *act = *actparm;
- ULONGEST xlen;
- struct agent_expr *aexpr;
-
- ++act; /* skip the X */
- act = unpack_varlen_hex (act, &xlen);
- ++act; /* skip a comma */
- aexpr = xmalloc (sizeof (struct agent_expr));
- aexpr->length = xlen;
- aexpr->bytes = xmalloc (xlen);
- convert_ascii_to_int (act, aexpr->bytes, xlen);
- *actparm = act + (xlen * 2);
- return aexpr;
-}
-
-/* Convert the bytes of an agent expression back into hex digits, so
- they can be printed or uploaded. This allocates the buffer,
- callers should free when they are done with it. */
-
-static char *
-unparse_agent_expr (struct agent_expr *aexpr)
-{
- char *rslt;
-
- rslt = xmalloc (2 * aexpr->length + 1);
- convert_int_to_ascii (aexpr->bytes, rslt, aexpr->length);
- return rslt;
-}
-
-#endif
-
-/* A wrapper for gdb_agent_op_names that does some bounds-checking. */
-
-static const char *
-gdb_agent_op_name (int op)
-{
- if (op < 0 || op >= gdb_agent_op_last || gdb_agent_op_names[op] == NULL)
- return "?undef?";
- return gdb_agent_op_names[op];
-}
-
-/* The agent expression evaluator, as specified by the GDB docs. It
- returns 0 if everything went OK, and a nonzero error code
- otherwise. */
+/* Evaluates a tracepoint agent expression with context CTX,
+ traceframe TFRAME, agent expression AEXPR and store the
+ result in RSLT. */
static enum eval_result_type
-eval_agent_expr (struct tracepoint_hit_ctx *ctx,
- struct traceframe *tframe,
- struct agent_expr *aexpr,
- ULONGEST *rslt)
-{
- int pc = 0;
-#define STACK_MAX 100
- ULONGEST stack[STACK_MAX], top;
- int sp = 0;
- unsigned char op;
- int arg;
-
- /* This union is a convenient way to convert representations. For
- now, assume a standard architecture where the hardware integer
- types have 8, 16, 32, 64 bit types. A more robust solution would
- be to import stdint.h from gnulib. */
- union
- {
- union
- {
- unsigned char bytes[1];
- unsigned char val;
- } u8;
- union
- {
- unsigned char bytes[2];
- unsigned short val;
- } u16;
- union
- {
- unsigned char bytes[4];
- unsigned int val;
- } u32;
- union
- {
- unsigned char bytes[8];
- ULONGEST val;
- } u64;
- } cnv;
-
- if (aexpr->length == 0)
- {
- trace_debug ("empty agent expression");
- return expr_eval_empty_expression;
- }
-
- /* Cache the stack top in its own variable. Much of the time we can
- operate on this variable, rather than dinking with the stack. It
- needs to be copied to the stack when sp changes. */
- top = 0;
-
- while (1)
- {
- op = aexpr->bytes[pc++];
-
- trace_debug ("About to interpret byte 0x%x", op);
-
- switch (op)
- {
- case gdb_agent_op_add:
- top += stack[--sp];
- break;
-
- case gdb_agent_op_sub:
- top = stack[--sp] - top;
- break;
-
- case gdb_agent_op_mul:
- top *= stack[--sp];
- break;
-
- case gdb_agent_op_div_signed:
- if (top == 0)
- {
- trace_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = ((LONGEST) stack[--sp]) / ((LONGEST) top);
- break;
-
- case gdb_agent_op_div_unsigned:
- if (top == 0)
- {
- trace_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = stack[--sp] / top;
- break;
-
- case gdb_agent_op_rem_signed:
- if (top == 0)
- {
- trace_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = ((LONGEST) stack[--sp]) % ((LONGEST) top);
- break;
-
- case gdb_agent_op_rem_unsigned:
- if (top == 0)
- {
- trace_debug ("Attempted to divide by zero");
- return expr_eval_divide_by_zero;
- }
- top = stack[--sp] % top;
- break;
-
- case gdb_agent_op_lsh:
- top = stack[--sp] << top;
- break;
-
- case gdb_agent_op_rsh_signed:
- top = ((LONGEST) stack[--sp]) >> top;
- break;
-
- case gdb_agent_op_rsh_unsigned:
- top = stack[--sp] >> top;
- break;
-
- case gdb_agent_op_trace:
- agent_mem_read (tframe,
- NULL, (CORE_ADDR) stack[--sp], (ULONGEST) top);
- if (--sp >= 0)
- top = stack[sp];
- break;
-
- case gdb_agent_op_trace_quick:
- arg = aexpr->bytes[pc++];
- agent_mem_read (tframe, NULL, (CORE_ADDR) top, (ULONGEST) arg);
- break;
-
- case gdb_agent_op_log_not:
- top = !top;
- break;
-
- case gdb_agent_op_bit_and:
- top &= stack[--sp];
- break;
-
- case gdb_agent_op_bit_or:
- top |= stack[--sp];
- break;
-
- case gdb_agent_op_bit_xor:
- top ^= stack[--sp];
- break;
-
- case gdb_agent_op_bit_not:
- top = ~top;
- break;
-
- case gdb_agent_op_equal:
- top = (stack[--sp] == top);
- break;
-
- case gdb_agent_op_less_signed:
- top = (((LONGEST) stack[--sp]) < ((LONGEST) top));
- break;
-
- case gdb_agent_op_less_unsigned:
- top = (stack[--sp] < top);
- break;
-
- case gdb_agent_op_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- {
- LONGEST mask = 1 << (arg - 1);
- top &= ((LONGEST) 1 << arg) - 1;
- top = (top ^ mask) - mask;
- }
- break;
-
- case gdb_agent_op_ref8:
- agent_mem_read (tframe, cnv.u8.bytes, (CORE_ADDR) top, 1);
- top = cnv.u8.val;
- break;
-
- case gdb_agent_op_ref16:
- agent_mem_read (tframe, cnv.u16.bytes, (CORE_ADDR) top, 2);
- top = cnv.u16.val;
- break;
-
- case gdb_agent_op_ref32:
- agent_mem_read (tframe, cnv.u32.bytes, (CORE_ADDR) top, 4);
- top = cnv.u32.val;
- break;
-
- case gdb_agent_op_ref64:
- agent_mem_read (tframe, cnv.u64.bytes, (CORE_ADDR) top, 8);
- top = cnv.u64.val;
- break;
-
- case gdb_agent_op_if_goto:
- if (top)
- pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]);
- else
- pc += 2;
- if (--sp >= 0)
- top = stack[sp];
- break;
-
- case gdb_agent_op_goto:
- pc = (aexpr->bytes[pc] << 8) + (aexpr->bytes[pc + 1]);
- break;
-
- case gdb_agent_op_const8:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- break;
-
- case gdb_agent_op_const16:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- break;
-
- case gdb_agent_op_const32:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- break;
-
- case gdb_agent_op_const64:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- break;
-
- case gdb_agent_op_reg:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- {
- int regnum = arg;
- struct regcache *regcache;
-
- regcache = get_context_regcache (ctx);
-
- switch (register_size (regnum))
- {
- case 8:
- collect_register (regcache, regnum, cnv.u64.bytes);
- top = cnv.u64.val;
- break;
- case 4:
- collect_register (regcache, regnum, cnv.u32.bytes);
- top = cnv.u32.val;
- break;
- case 2:
- collect_register (regcache, regnum, cnv.u16.bytes);
- top = cnv.u16.val;
- break;
- case 1:
- collect_register (regcache, regnum, cnv.u8.bytes);
- top = cnv.u8.val;
- break;
- default:
- internal_error (__FILE__, __LINE__,
- "unhandled register size");
- }
- }
- break;
-
- case gdb_agent_op_end:
- trace_debug ("At end of expression, sp=%d, stack top cache=0x%s",
- sp, pulongest (top));
- if (rslt)
- {
- if (sp <= 0)
- {
- /* This should be an error */
- trace_debug ("Stack is empty, nothing to return");
- return expr_eval_empty_stack;
- }
- *rslt = top;
- }
- return expr_eval_no_error;
-
- case gdb_agent_op_dup:
- stack[sp++] = top;
- break;
-
- case gdb_agent_op_pop:
- if (--sp >= 0)
- top = stack[sp];
- break;
-
- case gdb_agent_op_pick:
- arg = aexpr->bytes[pc++];
- stack[sp] = top;
- top = stack[sp - arg];
- ++sp;
- break;
-
- case gdb_agent_op_rot:
- {
- ULONGEST tem = stack[sp - 1];
-
- stack[sp - 1] = stack[sp - 2];
- stack[sp - 2] = top;
- top = tem;
- }
- break;
-
- case gdb_agent_op_zero_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- top &= ((LONGEST) 1 << arg) - 1;
- break;
-
- case gdb_agent_op_swap:
- /* Interchange top two stack elements, making sure top gets
- copied back onto stack. */
- stack[sp] = top;
- top = stack[sp - 1];
- stack[sp - 1] = stack[sp];
- break;
-
- case gdb_agent_op_getv:
- /* Flush the cached stack top. */
- stack[sp++] = top;
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- top = get_trace_state_variable_value (arg);
- break;
-
- case gdb_agent_op_setv:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- set_trace_state_variable_value (arg, top);
- /* Note that we leave the value on the stack, for the
- benefit of later/enclosing expressions. */
- break;
-
- case gdb_agent_op_tracev:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- agent_tsv_read (tframe, arg);
- break;
-
- case gdb_agent_op_tracenz:
- agent_mem_read_string (tframe, NULL, (CORE_ADDR) stack[--sp],
- (ULONGEST) top);
- if (--sp >= 0)
- top = stack[sp];
- break;
-
- /* GDB never (currently) generates any of these ops. */
- case gdb_agent_op_float:
- case gdb_agent_op_ref_float:
- case gdb_agent_op_ref_double:
- case gdb_agent_op_ref_long_double:
- case gdb_agent_op_l_to_d:
- case gdb_agent_op_d_to_l:
- case gdb_agent_op_trace16:
- trace_debug ("Agent expression op 0x%x valid, but not handled",
- op);
- /* If ever GDB generates any of these, we don't have the
- option of ignoring. */
- return 1;
-
- default:
- trace_debug ("Agent expression op 0x%x not recognized", op);
- /* Don't struggle on, things will just get worse. */
- return expr_eval_unrecognized_opcode;
- }
-
- /* Check for stack badness. */
- if (sp >= (STACK_MAX - 1))
- {
- trace_debug ("Expression stack overflow");
- return expr_eval_stack_overflow;
- }
-
- if (sp < 0)
- {
- trace_debug ("Expression stack underflow");
- return expr_eval_stack_underflow;
- }
+eval_tracepoint_agent_expr (struct tracepoint_hit_ctx *ctx,
+ struct traceframe *tframe,
+ struct agent_expr *aexpr,
+ ULONGEST *rslt)
+{
+ struct regcache *regcache;
+ regcache = get_context_regcache (ctx);
- trace_debug ("Op %s -> sp=%d, top=0x%s",
- gdb_agent_op_name (op), sp, pulongest (top));
- }
+ return gdb_eval_agent_expr (regcache, tframe, aexpr, rslt);
}
/* Do memory copies for bytecodes. */
/* Do the recording of memory blocks for actions and bytecodes. */
-static int
+int
agent_mem_read (struct traceframe *tframe,
unsigned char *to, CORE_ADDR from, ULONGEST len)
{
return 0;
}
-static int
+int
agent_mem_read_string (struct traceframe *tframe,
unsigned char *to, CORE_ADDR from, ULONGEST len)
{
/* Record the value of a trace state variable. */
-static int
+int
agent_tsv_read (struct traceframe *tframe, int n)
{
unsigned char *vspace;
#ifndef IN_PROCESS_AGENT
-/* Bytecode compilation. */
-
-CORE_ADDR current_insn_ptr;
-
-int emit_error;
-
-struct bytecode_address
-{
- int pc;
- CORE_ADDR address;
- int goto_pc;
- /* Offset and size of field to be modified in the goto block. */
- int from_offset, from_size;
- struct bytecode_address *next;
-} *bytecode_address_table;
-
CORE_ADDR
get_raw_reg_func_addr (void)
{
return ipa_sym_addrs.addr_get_raw_reg;
}
-static void
-emit_prologue (void)
-{
- target_emit_ops ()->emit_prologue ();
-}
-
-static void
-emit_epilogue (void)
-{
- target_emit_ops ()->emit_epilogue ();
-}
-
-static void
-emit_add (void)
-{
- target_emit_ops ()->emit_add ();
-}
-
-static void
-emit_sub (void)
-{
- target_emit_ops ()->emit_sub ();
-}
-
-static void
-emit_mul (void)
-{
- target_emit_ops ()->emit_mul ();
-}
-
-static void
-emit_lsh (void)
-{
- target_emit_ops ()->emit_lsh ();
-}
-
-static void
-emit_rsh_signed (void)
-{
- target_emit_ops ()->emit_rsh_signed ();
-}
-
-static void
-emit_rsh_unsigned (void)
-{
- target_emit_ops ()->emit_rsh_unsigned ();
-}
-
-static void
-emit_ext (int arg)
-{
- target_emit_ops ()->emit_ext (arg);
-}
-
-static void
-emit_log_not (void)
-{
- target_emit_ops ()->emit_log_not ();
-}
-
-static void
-emit_bit_and (void)
-{
- target_emit_ops ()->emit_bit_and ();
-}
-
-static void
-emit_bit_or (void)
-{
- target_emit_ops ()->emit_bit_or ();
-}
-
-static void
-emit_bit_xor (void)
-{
- target_emit_ops ()->emit_bit_xor ();
-}
-
-static void
-emit_bit_not (void)
-{
- target_emit_ops ()->emit_bit_not ();
-}
-
-static void
-emit_equal (void)
-{
- target_emit_ops ()->emit_equal ();
-}
-
-static void
-emit_less_signed (void)
-{
- target_emit_ops ()->emit_less_signed ();
-}
-
-static void
-emit_less_unsigned (void)
-{
- target_emit_ops ()->emit_less_unsigned ();
-}
-
-static void
-emit_ref (int size)
-{
- target_emit_ops ()->emit_ref (size);
-}
-
-static void
-emit_if_goto (int *offset_p, int *size_p)
-{
- target_emit_ops ()->emit_if_goto (offset_p, size_p);
-}
-
-static void
-emit_goto (int *offset_p, int *size_p)
-{
- target_emit_ops ()->emit_goto (offset_p, size_p);
-}
-
-static void
-write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
-{
- target_emit_ops ()->write_goto_address (from, to, size);
-}
-
-static void
-emit_const (LONGEST num)
-{
- target_emit_ops ()->emit_const (num);
-}
-
-static void
-emit_reg (int reg)
-{
- target_emit_ops ()->emit_reg (reg);
-}
-
-static void
-emit_pop (void)
-{
- target_emit_ops ()->emit_pop ();
-}
-
-static void
-emit_stack_flush (void)
-{
- target_emit_ops ()->emit_stack_flush ();
-}
-
-static void
-emit_zero_ext (int arg)
-{
- target_emit_ops ()->emit_zero_ext (arg);
-}
-
-static void
-emit_swap (void)
-{
- target_emit_ops ()->emit_swap ();
-}
-
-static void
-emit_stack_adjust (int n)
-{
- target_emit_ops ()->emit_stack_adjust (n);
-}
-
-/* FN's prototype is `LONGEST(*fn)(int)'. */
-
-static void
-emit_int_call_1 (CORE_ADDR fn, int arg1)
-{
- target_emit_ops ()->emit_int_call_1 (fn, arg1);
-}
-
-/* FN's prototype is `void(*fn)(int,LONGEST)'. */
-
-static void
-emit_void_call_2 (CORE_ADDR fn, int arg1)
-{
- 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)
+CORE_ADDR
+get_get_tsv_func_addr (void)
{
- target_emit_ops ()->emit_gt_goto (offset_p, size_p);
+ return ipa_sym_addrs.addr_get_trace_state_variable_value;
}
-static void
-emit_le_goto (int *offset_p, int *size_p)
+CORE_ADDR
+get_set_tsv_func_addr (void)
{
- target_emit_ops ()->emit_le_goto (offset_p, size_p);
+ return ipa_sym_addrs.addr_set_trace_state_variable_value;
}
-static enum eval_result_type compile_bytecodes (struct agent_expr *aexpr);
-
static void
compile_tracepoint_condition (struct tracepoint *tpoint,
CORE_ADDR *jump_entry)
*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
-compile_bytecodes (struct agent_expr *aexpr)
-{
- int pc = 0;
- int done = 0;
- unsigned char op, next_op;
- int arg;
- /* This is only used to build 64-bit value for constants. */
- ULONGEST top;
- struct bytecode_address *aentry, *aentry2;
-
-#define UNHANDLED \
- do \
- { \
- trace_debug ("Cannot compile op 0x%x\n", op); \
- return expr_eval_unhandled_opcode; \
- } while (0)
-
- if (aexpr->length == 0)
- {
- trace_debug ("empty agent expression\n");
- return expr_eval_empty_expression;
- }
-
- bytecode_address_table = NULL;
-
- while (!done)
- {
- op = aexpr->bytes[pc];
-
- trace_debug ("About to compile op 0x%x, pc=%d\n", op, pc);
-
- /* Record the compiled-code address of the bytecode, for use by
- jump instructions. */
- aentry = xmalloc (sizeof (struct bytecode_address));
- aentry->pc = pc;
- aentry->address = current_insn_ptr;
- aentry->goto_pc = -1;
- aentry->from_offset = aentry->from_size = 0;
- aentry->next = bytecode_address_table;
- bytecode_address_table = aentry;
-
- ++pc;
-
- emit_error = 0;
-
- switch (op)
- {
- case gdb_agent_op_add:
- emit_add ();
- break;
-
- case gdb_agent_op_sub:
- emit_sub ();
- break;
-
- case gdb_agent_op_mul:
- emit_mul ();
- break;
-
- case gdb_agent_op_div_signed:
- UNHANDLED;
- break;
-
- case gdb_agent_op_div_unsigned:
- UNHANDLED;
- break;
-
- case gdb_agent_op_rem_signed:
- UNHANDLED;
- break;
-
- case gdb_agent_op_rem_unsigned:
- UNHANDLED;
- break;
-
- case gdb_agent_op_lsh:
- emit_lsh ();
- break;
-
- case gdb_agent_op_rsh_signed:
- emit_rsh_signed ();
- break;
-
- case gdb_agent_op_rsh_unsigned:
- emit_rsh_unsigned ();
- break;
-
- case gdb_agent_op_trace:
- UNHANDLED;
- break;
-
- case gdb_agent_op_trace_quick:
- UNHANDLED;
- break;
-
- case gdb_agent_op_log_not:
- emit_log_not ();
- break;
-
- case gdb_agent_op_bit_and:
- emit_bit_and ();
- break;
-
- case gdb_agent_op_bit_or:
- emit_bit_or ();
- break;
-
- case gdb_agent_op_bit_xor:
- emit_bit_xor ();
- break;
-
- case gdb_agent_op_bit_not:
- emit_bit_not ();
- break;
-
- case gdb_agent_op_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:
- 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:
- emit_less_unsigned ();
- break;
-
- case gdb_agent_op_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- emit_ext (arg);
- break;
-
- case gdb_agent_op_ref8:
- emit_ref (1);
- break;
-
- case gdb_agent_op_ref16:
- emit_ref (2);
- break;
-
- case gdb_agent_op_ref32:
- emit_ref (4);
- break;
-
- case gdb_agent_op_ref64:
- emit_ref (8);
- break;
-
- case gdb_agent_op_if_goto:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_if_goto (&(aentry->from_offset), &(aentry->from_size));
- break;
-
- case gdb_agent_op_goto:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- aentry->goto_pc = arg;
- emit_goto (&(aentry->from_offset), &(aentry->from_size));
- break;
-
- case gdb_agent_op_const8:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- emit_const (top);
- break;
-
- case gdb_agent_op_const16:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- emit_const (top);
- break;
-
- case gdb_agent_op_const32:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- emit_const (top);
- break;
-
- case gdb_agent_op_const64:
- emit_stack_flush ();
- top = aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- top = (top << 8) + aexpr->bytes[pc++];
- emit_const (top);
- break;
-
- case gdb_agent_op_reg:
- emit_stack_flush ();
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- emit_reg (arg);
- break;
-
- case gdb_agent_op_end:
- trace_debug ("At end of expression\n");
-
- /* Assume there is one stack element left, and that it is
- cached in "top" where emit_epilogue can get to it. */
- emit_stack_adjust (1);
-
- done = 1;
- break;
-
- case gdb_agent_op_dup:
- /* In our design, dup is equivalent to stack flushing. */
- emit_stack_flush ();
- break;
-
- case gdb_agent_op_pop:
- emit_pop ();
- break;
-
- case gdb_agent_op_zero_ext:
- arg = aexpr->bytes[pc++];
- if (arg < (sizeof (LONGEST) * 8))
- emit_zero_ext (arg);
- break;
-
- case gdb_agent_op_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:
- emit_stack_flush ();
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- emit_int_call_1 (ipa_sym_addrs.addr_get_trace_state_variable_value,
- arg);
- break;
-
- case gdb_agent_op_setv:
- arg = aexpr->bytes[pc++];
- arg = (arg << 8) + aexpr->bytes[pc++];
- emit_void_call_2 (ipa_sym_addrs.addr_set_trace_state_variable_value,
- arg);
- break;
-
- case gdb_agent_op_tracev:
- UNHANDLED;
- break;
-
- /* GDB never (currently) generates any of these ops. */
- case gdb_agent_op_float:
- case gdb_agent_op_ref_float:
- case gdb_agent_op_ref_double:
- case gdb_agent_op_ref_long_double:
- case gdb_agent_op_l_to_d:
- case gdb_agent_op_d_to_l:
- case gdb_agent_op_trace16:
- UNHANDLED;
- break;
-
- default:
- trace_debug ("Agent expression op 0x%x not recognized\n", op);
- /* Don't struggle on, things will just get worse. */
- return expr_eval_unrecognized_opcode;
- }
-
- /* This catches errors that occur in target-specific code
- emission. */
- if (emit_error)
- {
- trace_debug ("Error %d while emitting code for %s\n",
- emit_error, gdb_agent_op_name (op));
- return expr_eval_unhandled_opcode;
- }
-
- trace_debug ("Op %s compiled\n", gdb_agent_op_name (op));
- }
-
- /* Now fill in real addresses as goto destinations. */
- for (aentry = bytecode_address_table; aentry; aentry = aentry->next)
- {
- int written = 0;
-
- if (aentry->goto_pc < 0)
- continue;
-
- /* Find the location that we are going to, and call back into
- target-specific code to write the actual address or
- displacement. */
- for (aentry2 = bytecode_address_table; aentry2; aentry2 = aentry2->next)
- {
- if (aentry2->pc == aentry->goto_pc)
- {
- trace_debug ("Want to jump from %s to %s\n",
- paddress (aentry->address),
- paddress (aentry2->address));
- write_goto_address (aentry->address + aentry->from_offset,
- aentry2->address, aentry->from_size);
- written = 1;
- break;
- }
- }
-
- /* Error out if we didn't find a destination. */
- if (!written)
- {
- trace_debug ("Destination of goto %d not found\n",
- aentry->goto_pc);
- return expr_eval_invalid_goto;
- }
- }
-
- return expr_eval_no_error;
-}
-
/* We'll need to adjust these when we consider bi-arch setups, and big
endian machines. */