diff options
author | Stan Shebs <shebs@codesourcery.com> | 2011-09-15 22:54:13 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 2011-09-15 22:54:13 +0000 |
commit | 6b9801d456c0851563f41b87cfdf00b141257578 (patch) | |
tree | fd691b193012068d6a970e4a15bb0b582d7a0da4 /gdb/gdbserver/tracepoint.c | |
parent | 5af65ec072edf782b67169fd3ea1b91b8255d30f (diff) | |
download | gdb-6b9801d456c0851563f41b87cfdf00b141257578.zip gdb-6b9801d456c0851563f41b87cfdf00b141257578.tar.gz gdb-6b9801d456c0851563f41b87cfdf00b141257578.tar.bz2 |
* server.h (struct emit_ops): Add compare-goto fields.
* tracepoint.c (gdb_agent_op_sizes): New table.
(emit_eq_goto): New function.
(emit_ne_goto): New function.
(emit_lt_goto): New function.
(emit_le_goto): New function.
(emit_gt_goto): New function.
(emit_ge_goto): New function.
(is_goto_target): New function.
(compile_bytecodes): Recognize special cases of compare-goto
combinations and call specialized emitters for them.
* linux-x86-low.c (amd64_emit_eq_goto): New function.
(amd64_emit_ne_goto): New function.
(amd64_emit_lt_goto): New function.
(amd64_emit_le_goto): New function.
(amd64_emit_gt_goto): New function.
(amd64_emit_ge_goto): New function.
(amd64_emit_ops): Add the new functions.
(i386_emit_eq_goto): New function.
(i386_emit_ne_goto): New function.
(i386_emit_lt_goto): New function.
(i386_emit_le_goto): New function.
(i386_emit_gt_goto): New function.
(i386_emit_ge_goto): New function.
(i386_emit_ops): Add the new functions.
Diffstat (limited to 'gdb/gdbserver/tracepoint.c')
-rw-r--r-- | gdb/gdbserver/tracepoint.c | 160 |
1 files changed, 156 insertions, 4 deletions
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index 8cfb773..0a64104 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -483,6 +483,14 @@ static const char *gdb_agent_op_names [gdb_agent_op_last] = #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; @@ -5663,6 +5671,42 @@ 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) +{ + 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 @@ -5712,6 +5756,30 @@ compile_tracepoint_condition (struct tracepoint *tpoint, *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 @@ -5719,7 +5787,7 @@ compile_bytecodes (struct agent_expr *aexpr) { 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; @@ -5831,11 +5899,64 @@ compile_bytecodes (struct agent_expr *aexpr) 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: @@ -5946,7 +6067,38 @@ compile_bytecodes (struct agent_expr *aexpr) 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: |