forked from Imagelibrary/binutils-gdb
gdb/
2010-06-14 Pedro Alves <pedro@codesourcery.com> * NEWS: Mention GDBserver's JIT compilation of tracepoint bytecode. gdb/gdbserver/ 2010-06-14 Stan Shebs <stan@codesourcery.com> Pedro Alves <pedro@codesourcery.com> Bytecode compiler. * linux-x86-low.c: Include limits.h. (add_insns): New. (always_true): New. (EMIT_ASM): New. (EMIT_ASM32): New. (amd64_emit_prologue, amd64_emit_epilogue, amd64_emit_add) (amd64_emit_sub, amd64_emit_mul, amd64_emit_lsh) (amd64_emit_rsh_signed, amd64_emit_rsh_unsigned, amd64_emit_ext, (amd64_emit_log_not, amd64_emit_bit_and, amd64_emit_bit_or) (amd64_emit_bit_xor, amd64_emit_bit_not, amd64_emit_equal, (amd64_emit_less_signed, amd64_emit_less_unsigned, amd64_emit_ref, (amd64_emit_if_goto, amd64_emit_goto, amd64_write_goto_address) (amd64_emit_const, amd64_emit_call, amd64_emit_reg) (amd64_emit_pop, amd64_emit_stack_flush, amd64_emit_zero_ext) (amd64_emit_swap, amd64_emit_stack_adjust, amd64_emit_int_call_1) (amd64_emit_void_call_2): New. (amd64_emit_ops): New. (i386_emit_prologue, i386_emit_epilogue, i386_emit_add) (i386_emit_sub,i386_emit_mul, i386_emit_lsh, i386_emit_rsh_signed) (i386_emit_rsh_unsigned, i386_emit_ext, i386_emit_log_not) (i386_emit_bit_and, i386_emit_bit_or, i386_emit_bit_xor) (i386_emit_bit_not, i386_emit_equal, i386_emit_less_signed) (i386_emit_less_unsigned, i386_emit_ref, i386_emit_if_goto) (i386_emit_goto, i386_write_goto_address, i386_emit_const) (i386_emit_call, i386_emit_reg, i386_emit_pop) (i386_emit_stack_flush, i386_emit_zero_ext, i386_emit_swap) (i386_emit_stack_adjust, i386_emit_int_call_1) (i386_emit_void_call_2): New. (i386_emit_ops): New. (x86_emit_ops): New. (the_low_target): Install x86_emit_ops. * server.h (struct emit_ops): New. (get_raw_reg_func_addr): Declare. (current_insn_ptr, emit_error): Declare. * tracepoint.c (get_raw_reg, get_trace_state_variable_value) (set_trace_state_variable_value): New defines. (struct ipa_sym_addresses): New fields addr_get_raw_reg, addr_get_trace_state_variable_value and addr_set_trace_state_variable_value. (symbol_list): New fields for get_raw_reg, get_trace_state_variable_value and set_trace_state_variable_value. (condfn): New typedef. (struct tracepoint): New field `compiled_cond'. (do_action_at_tracepoint): Clear compiled_cond. (get_trace_state_variable_value, set_trace_state_variable_value): Export in the IPA. (condition_true_at_tracepoint): If there's a compiled condition, run that. (current_insn_ptr, emit_error): New globals. (struct bytecode_address): New. (get_raw_reg_func_addr): New. (emit_prologue, emit_epilogue, emit_add, emit_sub, emit_mul) (emit_lsh, emit_rsh_signed, emit_rsh_unsigned, emit_ext) (emit_log_not, emit_bit_and, emit_bit_or, emit_bit_xor) (emit_bit_not, emit_equal, emit_less_signed, emit_less_unsigned) (emit_ref, emit_if_goto, emit_goto, write_goto_address, emit_const) (emit_reg, emit_pop, emit_stack_flush, emit_zero_ext, emit_swap) (emit_stack_adjust, emit_int_call_1, emit_void_call_2): New. (compile_tracepoint_condition, compile_bytecodes): New. * target.h (emit_ops): Forward declare. (struct target_ops): New field emit_ops. (target_emit_ops): New. * linux-amd64-ipa.c (gdb_agent_get_raw_reg): New. * linux-i386-ipa.c (gdb_agent_get_raw_reg): New. * linux-low.c (linux_emit_ops): New. (linux_target_ops): Install it. * linux-low.h (struct linux_target_ops): New field emit_ops.
This commit is contained in:
@@ -132,6 +132,9 @@ trace_vdebug (const char *fmt, ...)
|
||||
# define traceframe_write_count gdb_agent_traceframe_write_count
|
||||
# define traceframes_created gdb_agent_traceframes_created
|
||||
# define trace_state_variables gdb_agent_trace_state_variables
|
||||
# define get_raw_reg gdb_agent_get_raw_reg
|
||||
# define get_trace_state_variable_value gdb_agent_get_trace_state_variable_value
|
||||
# define set_trace_state_variable_value gdb_agent_set_trace_state_variable_value
|
||||
#endif
|
||||
|
||||
#ifndef IN_PROCESS_AGENT
|
||||
@@ -162,6 +165,9 @@ struct ipa_sym_addresses
|
||||
CORE_ADDR addr_traceframe_write_count;
|
||||
CORE_ADDR addr_traceframes_created;
|
||||
CORE_ADDR addr_trace_state_variables;
|
||||
CORE_ADDR addr_get_raw_reg;
|
||||
CORE_ADDR addr_get_trace_state_variable_value;
|
||||
CORE_ADDR addr_set_trace_state_variable_value;
|
||||
};
|
||||
|
||||
#define STRINGIZE_1(STR) #STR
|
||||
@@ -200,6 +206,9 @@ static struct
|
||||
IPA_SYM(traceframe_write_count),
|
||||
IPA_SYM(traceframes_created),
|
||||
IPA_SYM(trace_state_variables),
|
||||
IPA_SYM(get_raw_reg),
|
||||
IPA_SYM(get_trace_state_variable_value),
|
||||
IPA_SYM(set_trace_state_variable_value),
|
||||
};
|
||||
|
||||
struct ipa_sym_addresses ipa_sym_addrs;
|
||||
@@ -564,6 +573,9 @@ enum tracepoint_type
|
||||
|
||||
struct tracepoint_hit_ctx;
|
||||
|
||||
typedef enum eval_result_type (*condfn) (struct tracepoint_hit_ctx *,
|
||||
ULONGEST *);
|
||||
|
||||
/* The definition of a tracepoint. */
|
||||
|
||||
/* Tracepoints may have multiple locations, each at a different
|
||||
@@ -612,6 +624,8 @@ struct tracepoint
|
||||
Note that while-stepping steps are not counted as "hits". */
|
||||
long hit_count;
|
||||
|
||||
CORE_ADDR compiled_cond;
|
||||
|
||||
/* Link to the next tracepoint in the list. */
|
||||
struct tracepoint *next;
|
||||
|
||||
@@ -1189,6 +1203,8 @@ static void collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
||||
static void collect_data_at_step (struct tracepoint_hit_ctx *ctx,
|
||||
CORE_ADDR stop_pc,
|
||||
struct tracepoint *tpoint, int current_step);
|
||||
static void compile_tracepoint_condition (struct tracepoint *tpoint,
|
||||
CORE_ADDR *jump_entry);
|
||||
#endif
|
||||
static void do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
||||
CORE_ADDR stop_pc,
|
||||
@@ -1610,6 +1626,7 @@ add_tracepoint (int num, CORE_ADDR addr)
|
||||
tpoint->type = trap_tracepoint;
|
||||
tpoint->orig_size = -1;
|
||||
tpoint->source_strings = NULL;
|
||||
tpoint->compiled_cond = 0;
|
||||
tpoint->handle = NULL;
|
||||
tpoint->next = NULL;
|
||||
|
||||
@@ -1854,7 +1871,7 @@ create_trace_state_variable (int num, int gdb)
|
||||
return tsv;
|
||||
}
|
||||
|
||||
static LONGEST
|
||||
IP_AGENT_EXPORT LONGEST
|
||||
get_trace_state_variable_value (int num)
|
||||
{
|
||||
struct trace_state_variable *tsv;
|
||||
@@ -1880,7 +1897,7 @@ get_trace_state_variable_value (int num)
|
||||
return tsv->value;
|
||||
}
|
||||
|
||||
static void
|
||||
IP_AGENT_EXPORT void
|
||||
set_trace_state_variable_value (int num, LONGEST val)
|
||||
{
|
||||
struct trace_state_variable *tsv;
|
||||
@@ -3906,7 +3923,10 @@ condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx,
|
||||
ULONGEST value = 0;
|
||||
enum eval_result_type err;
|
||||
|
||||
err = eval_agent_expr (ctx, NULL, tpoint->cond, &value);
|
||||
if (tpoint->compiled_cond)
|
||||
err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (ctx, &value);
|
||||
else
|
||||
err = eval_agent_expr (ctx, NULL, tpoint->cond, &value);
|
||||
|
||||
if (err != expr_eval_no_error)
|
||||
{
|
||||
@@ -4944,6 +4964,582 @@ gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
|
||||
|
||||
#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 (int64_t 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,int64_t)'. */
|
||||
|
||||
static void
|
||||
emit_void_call_2 (CORE_ADDR fn, int arg1)
|
||||
{
|
||||
target_emit_ops ()->emit_void_call_2 (fn, arg1);
|
||||
}
|
||||
|
||||
static enum eval_result_type compile_bytecodes (struct agent_expr *aexpr);
|
||||
|
||||
static void
|
||||
compile_tracepoint_condition (struct tracepoint *tpoint, CORE_ADDR *jump_entry)
|
||||
{
|
||||
CORE_ADDR entry_point = *jump_entry;
|
||||
enum eval_result_type err;
|
||||
|
||||
trace_debug ("Starting condition compilation for tracepoint %d\n",
|
||||
tpoint->number);
|
||||
|
||||
/* Initialize the global pointer to the code being built. */
|
||||
current_insn_ptr = *jump_entry;
|
||||
|
||||
emit_prologue ();
|
||||
|
||||
err = compile_bytecodes (tpoint->cond);
|
||||
|
||||
if (err == expr_eval_no_error)
|
||||
{
|
||||
emit_epilogue ();
|
||||
|
||||
/* Record the beginning of the compiled code. */
|
||||
tpoint->compiled_cond = entry_point;
|
||||
|
||||
trace_debug ("Condition compilation for tracepoint %d complete\n",
|
||||
tpoint->number);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Leave the unfinished code in situ, but don't point to it. */
|
||||
|
||||
tpoint->compiled_cond = 0;
|
||||
|
||||
trace_debug ("Condition compilation for tracepoint %d failed, "
|
||||
"error code %d",
|
||||
tpoint->number, err);
|
||||
}
|
||||
|
||||
/* Update the code pointer passed in. Note that we do this even if
|
||||
the compile fails, so that we can look at the partial results
|
||||
instead of letting them be overwritten. */
|
||||
*jump_entry = current_insn_ptr;
|
||||
|
||||
/* Leave a gap, to aid dump decipherment. */
|
||||
*jump_entry += 16;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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:
|
||||
emit_equal ();
|
||||
break;
|
||||
|
||||
case gdb_agent_op_less_signed:
|
||||
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:
|
||||
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_names[op]);
|
||||
return expr_eval_unhandled_opcode;
|
||||
}
|
||||
|
||||
trace_debug ("Op %s compiled\n", gdb_agent_op_names[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. */
|
||||
|
||||
@@ -5022,6 +5618,28 @@ download_tracepoints (void)
|
||||
if (tpoint->type != fast_tracepoint)
|
||||
continue;
|
||||
|
||||
/* Maybe download a compiled condition. */
|
||||
if (tpoint->cond != NULL && target_emit_ops () != NULL)
|
||||
{
|
||||
CORE_ADDR jentry, jump_entry;
|
||||
|
||||
jentry = jump_entry = get_jump_space_head ();
|
||||
|
||||
if (tpoint->cond != NULL)
|
||||
{
|
||||
/* Pad to 8-byte alignment. (needed?) */
|
||||
/* Actually this should be left for the target to
|
||||
decide. */
|
||||
jentry = UALIGN (jentry, 8);
|
||||
|
||||
compile_tracepoint_condition (tpoint, &jentry);
|
||||
}
|
||||
|
||||
/* Pad to 8-byte alignment. */
|
||||
jentry = UALIGN (jentry, 8);
|
||||
claim_jump_space (jentry - jump_entry);
|
||||
}
|
||||
|
||||
target_tracepoint = *tpoint;
|
||||
|
||||
prev_tpptr = tpptr;
|
||||
|
||||
Reference in New Issue
Block a user