Index: gdb/gdbserver/tracepoint.c |
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c |
index 37a02dab81fe512799160a6e596c193a92582181..f103dfce81a8ffe54d468554deb43e19a195074b 100644 |
--- a/gdb/gdbserver/tracepoint.c |
+++ b/gdb/gdbserver/tracepoint.c |
@@ -17,14 +17,18 @@ |
along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
#include "server.h" |
+#include "gdbthread.h" |
+#include "agent.h" |
+ |
#include <ctype.h> |
#include <fcntl.h> |
#include <unistd.h> |
#include <sys/time.h> |
#include <stddef.h> |
-#if HAVE_STDINT_H |
+#include <inttypes.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 |
@@ -63,13 +67,13 @@ trace_vdebug (const char *fmt, ...) |
va_start (ap, fmt); |
vsprintf (buf, fmt, ap); |
- fprintf (stderr, "gdbserver/tracepoint: %s\n", buf); |
+ fprintf (stderr, PROG "/tracepoint: %s\n", buf); |
va_end (ap); |
} |
#define trace_debug_1(level, fmt, args...) \ |
do { \ |
- if (level <= debug_threads) \ |
+ if (level <= debug_threads) \ |
trace_vdebug ((fmt), ##args); \ |
} while (0) |
@@ -177,18 +181,8 @@ struct ipa_sym_addresses |
CORE_ADDR addr_get_trace_state_variable_value; |
CORE_ADDR addr_set_trace_state_variable_value; |
CORE_ADDR addr_ust_loaded; |
- CORE_ADDR addr_helper_thread_id; |
- CORE_ADDR addr_cmd_buf; |
}; |
-#define STRINGIZE_1(STR) #STR |
-#define STRINGIZE(STR) STRINGIZE_1(STR) |
-#define IPA_SYM(SYM) \ |
- { \ |
- STRINGIZE (gdb_agent_ ## SYM), \ |
- offsetof (struct ipa_sym_addresses, addr_ ## SYM) \ |
- } |
- |
static struct |
{ |
const char *name; |
@@ -224,43 +218,41 @@ static struct |
IPA_SYM(get_trace_state_variable_value), |
IPA_SYM(set_trace_state_variable_value), |
IPA_SYM(ust_loaded), |
- IPA_SYM(helper_thread_id), |
- IPA_SYM(cmd_buf), |
}; |
-struct ipa_sym_addresses ipa_sym_addrs; |
- |
-int all_tracepoint_symbols_looked_up; |
- |
-int |
-in_process_agent_loaded (void) |
-{ |
- return all_tracepoint_symbols_looked_up; |
-} |
+static struct ipa_sym_addresses ipa_sym_addrs; |
static int read_inferior_integer (CORE_ADDR symaddr, int *val); |
/* Returns true if both the in-process agent library and the static |
- tracepoints libraries are loaded in the inferior. */ |
+ tracepoints libraries are loaded in the inferior, and agent has |
+ capability on static tracepoints. */ |
static int |
-in_process_agent_loaded_ust (void) |
+in_process_agent_supports_ust (void) |
{ |
int loaded = 0; |
- if (!in_process_agent_loaded ()) |
+ if (!agent_loaded_p ()) |
{ |
warning ("In-process agent not loaded"); |
return 0; |
} |
- if (read_inferior_integer (ipa_sym_addrs.addr_ust_loaded, &loaded)) |
+ if (agent_capability_check (AGENT_CAPA_STATIC_TRACE)) |
{ |
- warning ("Error reading ust_loaded in lib"); |
- return 0; |
- } |
+ /* Agent understands static tracepoint, then check whether UST is in |
+ fact loaded in the inferior. */ |
+ if (read_inferior_integer (ipa_sym_addrs.addr_ust_loaded, &loaded)) |
+ { |
+ warning ("Error reading ust_loaded in lib"); |
+ return 0; |
+ } |
- return loaded; |
+ return loaded; |
+ } |
+ else |
+ return 0; |
} |
static void |
@@ -292,7 +284,7 @@ write_e_ust_not_loaded (char *buffer) |
static int |
maybe_write_ipa_not_loaded (char *buffer) |
{ |
- if (!in_process_agent_loaded ()) |
+ if (!agent_loaded_p ()) |
{ |
write_e_ipa_not_loaded (buffer); |
return 1; |
@@ -307,12 +299,12 @@ maybe_write_ipa_not_loaded (char *buffer) |
static int |
maybe_write_ipa_ust_not_loaded (char *buffer) |
{ |
- if (!in_process_agent_loaded ()) |
+ if (!agent_loaded_p ()) |
{ |
write_e_ipa_not_loaded (buffer); |
return 1; |
} |
- else if (!in_process_agent_loaded_ust ()) |
+ else if (!in_process_agent_supports_ust ()) |
{ |
write_e_ust_not_loaded (buffer); |
return 1; |
@@ -331,7 +323,7 @@ tracepoint_look_up_symbols (void) |
{ |
int i; |
- if (all_tracepoint_symbols_looked_up) |
+ if (agent_loaded_p ()) |
return; |
for (i = 0; i < sizeof (symbol_list) / sizeof (symbol_list[0]); i++) |
@@ -347,7 +339,7 @@ tracepoint_look_up_symbols (void) |
} |
} |
- all_tracepoint_symbols_looked_up = 1; |
+ agent_look_up_symbols (NULL); |
} |
#endif |
@@ -366,8 +358,6 @@ tracepoint_look_up_symbols (void) |
GDBserver side. */ |
#ifdef IN_PROCESS_AGENT |
-int debug_threads = 0; |
- |
int |
read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) |
{ |
@@ -419,11 +409,10 @@ static int stop_tracing_handler (CORE_ADDR); |
struct breakpoint *flush_trace_buffer_bkpt; |
static int flush_trace_buffer_handler (CORE_ADDR); |
-static void download_tracepoints (void); |
static void download_trace_state_variables (void); |
static void upload_fast_traceframes (void); |
-static int run_inferior_command (char *cmd); |
+static int run_inferior_command (char *cmd, int len); |
static int |
read_inferior_integer (CORE_ADDR symaddr, int *val) |
@@ -432,6 +421,9 @@ read_inferior_integer (CORE_ADDR symaddr, int *val) |
sizeof (*val)); |
} |
+struct tracepoint; |
+static int tracepoint_send_agent (struct tracepoint *tpoint); |
+ |
static int |
read_inferior_uinteger (CORE_ADDR symaddr, unsigned int *val) |
{ |
@@ -470,47 +462,39 @@ write_inferior_uinteger (CORE_ADDR symaddr, unsigned int val) |
return write_inferior_memory (symaddr, (unsigned char *) &val, sizeof (val)); |
} |
-#endif |
+static CORE_ADDR target_malloc (ULONGEST size); |
+static int write_inferior_data_ptr (CORE_ADDR where, CORE_ADDR ptr); |
-/* This enum must exactly match what is documented in |
- gdb/doc/agentexpr.texi, including all the numerical values. */ |
+#define COPY_FIELD_TO_BUF(BUF, OBJ, FIELD) \ |
+ do { \ |
+ memcpy (BUF, &(OBJ)->FIELD, sizeof ((OBJ)->FIELD)); \ |
+ BUF += sizeof ((OBJ)->FIELD); \ |
+ } while (0) |
-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 |
- }; |
+#endif |
-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 |
- }; |
+/* Operations on various types of tracepoint actions. */ |
-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 tracepoint_action; |
-struct agent_expr |
+struct tracepoint_action_ops |
{ |
- int length; |
+ /* Download tracepoint action ACTION to IPA. Return the address of action |
+ in IPA/inferior. */ |
+ CORE_ADDR (*download) (const struct tracepoint_action *action); |
- unsigned char *bytes; |
+ /* Send ACTION to agent via command buffer started from BUFFER. Return |
+ updated head of command buffer. */ |
+ char* (*send) (char *buffer, const struct tracepoint_action *action); |
}; |
/* Base action. Concrete actions inherit this. */ |
struct tracepoint_action |
{ |
+#ifndef IN_PROCESS_AGENT |
+ const struct tracepoint_action_ops *ops; |
+#endif |
char type; |
}; |
@@ -521,7 +505,7 @@ struct collect_memory_action |
ULONGEST addr; |
ULONGEST len; |
- int basereg; |
+ int32_t basereg; |
}; |
/* An 'R' (collect registers) action. */ |
@@ -546,6 +530,147 @@ struct collect_static_trace_data_action |
struct tracepoint_action base; |
}; |
+#ifndef IN_PROCESS_AGENT |
+static CORE_ADDR |
+m_tracepoint_action_download (const struct tracepoint_action *action) |
+{ |
+ int size_in_ipa = (sizeof (struct collect_memory_action) |
+ - offsetof (struct tracepoint_action, type)); |
+ CORE_ADDR ipa_action = target_malloc (size_in_ipa); |
+ |
+ write_inferior_memory (ipa_action, (unsigned char *) &action->type, |
+ size_in_ipa); |
+ |
+ return ipa_action; |
+} |
+static char * |
+m_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) |
+{ |
+ struct collect_memory_action *maction |
+ = (struct collect_memory_action *) action; |
+ |
+ COPY_FIELD_TO_BUF (buffer, maction, addr); |
+ COPY_FIELD_TO_BUF (buffer, maction, len); |
+ COPY_FIELD_TO_BUF (buffer, maction, basereg); |
+ |
+ return buffer; |
+} |
+ |
+static const struct tracepoint_action_ops m_tracepoint_action_ops = |
+{ |
+ m_tracepoint_action_download, |
+ m_tracepoint_action_send, |
+}; |
+ |
+static CORE_ADDR |
+r_tracepoint_action_download (const struct tracepoint_action *action) |
+{ |
+ int size_in_ipa = (sizeof (struct collect_registers_action) |
+ - offsetof (struct tracepoint_action, type)); |
+ CORE_ADDR ipa_action = target_malloc (size_in_ipa); |
+ |
+ write_inferior_memory (ipa_action, (unsigned char *) &action->type, |
+ size_in_ipa); |
+ |
+ return ipa_action; |
+} |
+ |
+static char * |
+r_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) |
+{ |
+ return buffer; |
+} |
+ |
+static const struct tracepoint_action_ops r_tracepoint_action_ops = |
+{ |
+ r_tracepoint_action_download, |
+ r_tracepoint_action_send, |
+}; |
+ |
+static CORE_ADDR download_agent_expr (struct agent_expr *expr); |
+ |
+static CORE_ADDR |
+x_tracepoint_action_download (const struct tracepoint_action *action) |
+{ |
+ int size_in_ipa = (sizeof (struct eval_expr_action) |
+ - offsetof (struct tracepoint_action, type)); |
+ CORE_ADDR ipa_action = target_malloc (size_in_ipa); |
+ CORE_ADDR expr; |
+ |
+ write_inferior_memory (ipa_action, (unsigned char *) &action->type, |
+ size_in_ipa); |
+ expr = download_agent_expr (((struct eval_expr_action *)action)->expr); |
+ write_inferior_data_ptr (ipa_action + offsetof (struct eval_expr_action, expr) |
+ - offsetof (struct tracepoint_action, type), |
+ expr); |
+ |
+ return ipa_action; |
+} |
+ |
+/* Copy agent expression AEXPR to buffer pointed by P. If AEXPR is NULL, |
+ copy 0 to P. Return updated header of buffer. */ |
+ |
+static char * |
+agent_expr_send (char *p, const struct agent_expr *aexpr) |
+{ |
+ /* Copy the length of condition first, and then copy its |
+ content. */ |
+ if (aexpr == NULL) |
+ { |
+ memset (p, 0, 4); |
+ p += 4; |
+ } |
+ else |
+ { |
+ memcpy (p, &aexpr->length, 4); |
+ p +=4; |
+ |
+ memcpy (p, aexpr->bytes, aexpr->length); |
+ p += aexpr->length; |
+ } |
+ return p; |
+} |
+ |
+static char * |
+x_tracepoint_action_send ( char *buffer, const struct tracepoint_action *action) |
+{ |
+ struct eval_expr_action *eaction = (struct eval_expr_action *) action; |
+ |
+ return agent_expr_send (buffer, eaction->expr); |
+} |
+ |
+static const struct tracepoint_action_ops x_tracepoint_action_ops = |
+{ |
+ x_tracepoint_action_download, |
+ x_tracepoint_action_send, |
+}; |
+ |
+static CORE_ADDR |
+l_tracepoint_action_download (const struct tracepoint_action *action) |
+{ |
+ int size_in_ipa = (sizeof (struct collect_static_trace_data_action) |
+ - offsetof (struct tracepoint_action, type)); |
+ CORE_ADDR ipa_action = target_malloc (size_in_ipa); |
+ |
+ write_inferior_memory (ipa_action, (unsigned char *) &action->type, |
+ size_in_ipa); |
+ |
+ return ipa_action; |
+} |
+ |
+static char * |
+l_tracepoint_action_send (char *buffer, const struct tracepoint_action *action) |
+{ |
+ return buffer; |
+} |
+ |
+static const struct tracepoint_action_ops l_tracepoint_action_ops = |
+{ |
+ l_tracepoint_action_download, |
+ l_tracepoint_action_send, |
+}; |
+#endif |
+ |
/* This structure describes a piece of the source-level definition of |
the tracepoint. The contents are not interpreted by the target, |
but preserved verbatim for uploading upon reconnection. */ |
@@ -600,7 +725,7 @@ struct tracepoint |
{ |
/* The number of the tracepoint, as specified by GDB. Several |
tracepoint objects here may share a number. */ |
- int number; |
+ uint32_t number; |
/* Address at which the tracepoint is supposed to trigger. Several |
tracepoints may share an address. */ |
@@ -610,30 +735,30 @@ struct tracepoint |
enum tracepoint_type type; |
/* True if the tracepoint is currently enabled. */ |
- int enabled; |
+ int8_t enabled; |
/* The number of single steps that will be performed after each |
tracepoint hit. */ |
- long step_count; |
+ uint64_t step_count; |
/* The number of times the tracepoint may be hit before it will |
terminate the entire tracing run. */ |
- long pass_count; |
+ uint64_t pass_count; |
/* Pointer to the agent expression that is the tracepoint's |
conditional, or NULL if the tracepoint is unconditional. */ |
struct agent_expr *cond; |
/* The list of actions to take when the tracepoint triggers. */ |
- int numactions; |
+ uint32_t numactions; |
struct tracepoint_action **actions; |
/* Count of the times we've hit this tracepoint during the run. |
Note that while-stepping steps are not counted as "hits". */ |
- long hit_count; |
+ uint64_t hit_count; |
/* Cached sum of the sizes of traceframes created by this point. */ |
- long traceframe_usage; |
+ uint64_t traceframe_usage; |
CORE_ADDR compiled_cond; |
@@ -653,7 +778,7 @@ struct tracepoint |
/* The number of bytes displaced by fast tracepoints. It may subsume |
multiple instructions, for multi-byte fast tracepoints. This |
field is only valid for fast tracepoints. */ |
- int orig_size; |
+ uint32_t orig_size; |
/* Only for fast tracepoints. */ |
CORE_ADDR obj_addr_on_target; |
@@ -738,22 +863,6 @@ IP_AGENT_EXPORT struct tracepoint *stopping_tracepoint; |
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 |
@@ -1237,21 +1346,11 @@ struct trap_tracepoint_ctx |
#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); |
@@ -1288,6 +1387,8 @@ static struct tracepoint *fast_tracepoint_from_ipa_tpoint_address (CORE_ADDR); |
static void install_tracepoint (struct tracepoint *, char *own_buf); |
static void download_tracepoint (struct tracepoint *); |
static int install_fast_tracepoint (struct tracepoint *, char *errbuf); |
+static void clone_fast_tracepoint (struct tracepoint *to, |
+ const struct tracepoint *from); |
#endif |
static LONGEST get_timestamp (void); |
@@ -1304,10 +1405,6 @@ static LONGEST get_timestamp (void); |
#define cmpxchg(mem, oldval, newval) \ |
__sync_val_compare_and_swap (mem, oldval, newval) |
-/* The size in bytes of the buffer used to talk to the IPA helper |
- thread. */ |
-#define CMD_BUF_SIZE 1024 |
- |
/* Record that an error occurred during expression evaluation. */ |
static void |
@@ -1760,6 +1857,28 @@ find_tracepoint (int id, CORE_ADDR addr) |
return NULL; |
} |
+/* Remove TPOINT from global list. */ |
+ |
+static void |
+remove_tracepoint (struct tracepoint *tpoint) |
+{ |
+ struct tracepoint *tp, *tp_prev; |
+ |
+ for (tp = tracepoints, tp_prev = NULL; tp && tp != tpoint; |
+ tp_prev = tp, tp = tp->next) |
+ ; |
+ |
+ if (tp) |
+ { |
+ if (tp_prev) |
+ tp_prev->next = tp->next; |
+ else |
+ tracepoints = tp->next; |
+ |
+ xfree (tp); |
+ } |
+} |
+ |
/* There may be several tracepoints with the same number (because they |
are "locations", in GDB parlance); return the next one after the |
given tracepoint, or search from the beginning of the list if the |
@@ -1825,6 +1944,7 @@ add_tracepoint_action (struct tracepoint *tpoint, char *packet) |
maction = xmalloc (sizeof *maction); |
maction->base.type = *act; |
+ maction->base.ops = &m_tracepoint_action_ops; |
action = &maction->base; |
++act; |
@@ -1850,6 +1970,7 @@ add_tracepoint_action (struct tracepoint *tpoint, char *packet) |
raction = xmalloc (sizeof *raction); |
raction->base.type = *act; |
+ raction->base.ops = &r_tracepoint_action_ops; |
action = &raction->base; |
trace_debug ("Want to collect registers"); |
@@ -1865,6 +1986,7 @@ add_tracepoint_action (struct tracepoint *tpoint, char *packet) |
raction = xmalloc (sizeof *raction); |
raction->base.type = *act; |
+ raction->base.ops = &l_tracepoint_action_ops; |
action = &raction->base; |
trace_debug ("Want to collect static trace data"); |
@@ -1881,10 +2003,11 @@ add_tracepoint_action (struct tracepoint *tpoint, char *packet) |
xaction = xmalloc (sizeof (*xaction)); |
xaction->base.type = *act; |
+ xaction->base.ops = &x_tracepoint_action_ops; |
action = &xaction->base; |
trace_debug ("Want to evaluate expression"); |
- xaction->expr = parse_agent_expr (&act); |
+ xaction->expr = gdb_parse_agent_expr (&act); |
break; |
} |
default: |
@@ -2028,6 +2151,18 @@ set_trace_state_variable_value (int num, LONGEST val) |
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) |
{ |
@@ -2267,10 +2402,10 @@ cmd_qtinit (char *packet) |
static void |
unprobe_marker_at (CORE_ADDR address) |
{ |
- char cmd[CMD_BUF_SIZE]; |
+ char cmd[IPA_CMD_BUF_SIZE]; |
sprintf (cmd, "unprobe_marker_at:%s", paddress (address)); |
- run_inferior_command (cmd); |
+ run_inferior_command (cmd, strlen (cmd) + 1); |
} |
/* Restore the program to its pre-tracing state. This routine may be called |
@@ -2404,7 +2539,7 @@ cmd_qtdp (char *own_buf) |
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 == '-') |
@@ -2421,9 +2556,9 @@ cmd_qtdp (char *own_buf) |
} |
trace_debug ("Defined %stracepoint %d at 0x%s, " |
- "enabled %d step %ld pass %ld", |
+ "enabled %d step %" PRIu64 " pass %" PRIu64, |
tpoint->type == fast_tracepoint ? "fast " |
- : "", |
+ : tpoint->type == static_tracepoint ? "static " : "", |
tpoint->number, paddress (tpoint->address), tpoint->enabled, |
tpoint->step_count, tpoint->pass_count); |
} |
@@ -2443,6 +2578,8 @@ cmd_qtdp (char *own_buf) |
trailing hyphen in QTDP packet. */ |
if (tracing && !trail_hyphen) |
{ |
+ struct tracepoint *tp = NULL; |
+ |
/* Pause all threads temporarily while we patch tracepoints. */ |
pause_all (0); |
@@ -2453,8 +2590,52 @@ cmd_qtdp (char *own_buf) |
/* Freeze threads. */ |
pause_all (1); |
- download_tracepoint (tpoint); |
- install_tracepoint (tpoint, own_buf); |
+ |
+ if (tpoint->type != trap_tracepoint) |
+ { |
+ /* Find another fast or static tracepoint at the same address. */ |
+ for (tp = tracepoints; tp; tp = tp->next) |
+ { |
+ if (tp->address == tpoint->address && tp->type == tpoint->type |
+ && tp->number != tpoint->number) |
+ break; |
+ } |
+ |
+ /* TPOINT is installed at the same address as TP. */ |
+ if (tp) |
+ { |
+ if (tpoint->type == fast_tracepoint) |
+ clone_fast_tracepoint (tpoint, tp); |
+ else if (tpoint->type == static_tracepoint) |
+ tpoint->handle = (void *) -1; |
+ } |
+ } |
+ |
+ if (use_agent && tpoint->type == fast_tracepoint |
+ && agent_capability_check (AGENT_CAPA_FAST_TRACE)) |
+ { |
+ /* Download and install fast tracepoint by agent. */ |
+ if (tracepoint_send_agent (tpoint) == 0) |
+ write_ok (own_buf); |
+ else |
+ { |
+ write_enn (own_buf); |
+ remove_tracepoint (tpoint); |
+ } |
+ } |
+ else |
+ { |
+ download_tracepoint (tpoint); |
+ |
+ if (tpoint->type == trap_tracepoint || tp == NULL) |
+ { |
+ install_tracepoint (tpoint, own_buf); |
+ if (strcmp (own_buf, "OK") != 0) |
+ remove_tracepoint (tpoint); |
+ } |
+ else |
+ write_ok (own_buf); |
+ } |
unpause_all (1); |
return; |
@@ -2841,11 +3022,11 @@ have_fast_tracepoint_trampoline_buffer (char *buf) |
static int |
probe_marker_at (CORE_ADDR address, char *errout) |
{ |
- char cmd[CMD_BUF_SIZE]; |
+ char cmd[IPA_CMD_BUF_SIZE]; |
int err; |
sprintf (cmd, "probe_marker_at:%s", paddress (address)); |
- err = run_inferior_command (cmd); |
+ err = run_inferior_command (cmd, strlen (cmd) + 1); |
if (err == 0) |
{ |
@@ -2958,9 +3139,7 @@ install_tracepoint (struct tracepoint *tpoint, char *own_buf) |
} |
else if (tpoint->type == fast_tracepoint || tpoint->type == static_tracepoint) |
{ |
- struct tracepoint *tp; |
- |
- if (!in_process_agent_loaded ()) |
+ if (!agent_loaded_p ()) |
{ |
trace_debug ("Requested a %s tracepoint, but fast " |
"tracepoints aren't supported.", |
@@ -2968,7 +3147,8 @@ install_tracepoint (struct tracepoint *tpoint, char *own_buf) |
write_e_ipa_not_loaded (own_buf); |
return; |
} |
- if (tpoint->type == static_tracepoint && !in_process_agent_loaded_ust ()) |
+ if (tpoint->type == static_tracepoint |
+ && !in_process_agent_supports_ust ()) |
{ |
trace_debug ("Requested a static tracepoint, but static " |
"tracepoints are not supported."); |
@@ -2976,30 +3156,12 @@ install_tracepoint (struct tracepoint *tpoint, char *own_buf) |
return; |
} |
- /* Find another fast or static tracepoint at the same address. */ |
- for (tp = tracepoints; tp; tp = tp->next) |
- { |
- if (tp->address == tpoint->address && tp->type == tpoint->type |
- && tp->number != tpoint->number) |
- break; |
- } |
- |
if (tpoint->type == fast_tracepoint) |
- { |
- if (tp) /* TPOINT is installed at the same address as TP. */ |
- clone_fast_tracepoint (tpoint, tp); |
- else |
- install_fast_tracepoint (tpoint, own_buf); |
- } |
+ install_fast_tracepoint (tpoint, own_buf); |
else |
{ |
- if (tp) |
+ if (probe_marker_at (tpoint->address, own_buf) == 0) |
tpoint->handle = (void *) -1; |
- else |
- { |
- if (probe_marker_at (tpoint->address, own_buf) == 0) |
- tpoint->handle = (void *) -1; |
- } |
} |
} |
@@ -3015,10 +3177,13 @@ install_tracepoint (struct tracepoint *tpoint, char *own_buf) |
write_ok (own_buf); |
} |
+static void download_tracepoint_1 (struct tracepoint *tpoint); |
+ |
static void |
cmd_qtstart (char *packet) |
{ |
struct tracepoint *tpoint, *prev_ftpoint, *prev_stpoint; |
+ CORE_ADDR tpptr = 0, prev_tpptr = 0; |
trace_debug ("Starting the trace"); |
@@ -3035,11 +3200,8 @@ cmd_qtstart (char *packet) |
pause_all (1); |
/* Sync the fast tracepoints list in the inferior ftlib. */ |
- if (in_process_agent_loaded ()) |
- { |
- download_tracepoints (); |
- download_trace_state_variables (); |
- } |
+ if (agent_loaded_p ()) |
+ download_trace_state_variables (); |
/* No previous fast tpoint yet. */ |
prev_ftpoint = NULL; |
@@ -3049,7 +3211,11 @@ cmd_qtstart (char *packet) |
*packet = '\0'; |
- /* Install tracepoints. */ |
+ /* Start out empty. */ |
+ if (agent_loaded_p ()) |
+ write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, 0); |
+ |
+ /* Download and install tracepoints. */ |
for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) |
{ |
/* Ensure all the hit counts start at zero. */ |
@@ -3065,48 +3231,89 @@ cmd_qtstart (char *packet) |
tpoint->handle = set_breakpoint_at (tpoint->address, |
tracepoint_handler); |
} |
- else if (tpoint->type == fast_tracepoint) |
+ else if (tpoint->type == fast_tracepoint |
+ || tpoint->type == static_tracepoint) |
{ |
if (maybe_write_ipa_not_loaded (packet)) |
{ |
- trace_debug ("Requested a fast tracepoint, but fast " |
- "tracepoints aren't supported."); |
+ trace_debug ("Requested a %s tracepoint, but fast " |
+ "tracepoints aren't supported.", |
+ tpoint->type == static_tracepoint |
+ ? "static" : "fast"); |
break; |
} |
- if (prev_ftpoint != NULL && prev_ftpoint->address == tpoint->address) |
- clone_fast_tracepoint (tpoint, prev_ftpoint); |
- else |
- { |
- if (install_fast_tracepoint (tpoint, packet) == 0) |
- prev_ftpoint = tpoint; |
- } |
- } |
- else if (tpoint->type == static_tracepoint) |
- { |
- if (maybe_write_ipa_ust_not_loaded (packet)) |
+ if (tpoint->type == fast_tracepoint) |
{ |
- trace_debug ("Requested a static tracepoint, but static " |
- "tracepoints are not supported."); |
- break; |
- } |
+ int use_agent_p |
+ = use_agent && agent_capability_check (AGENT_CAPA_FAST_TRACE); |
- /* Can only probe a given marker once. */ |
- if (prev_stpoint != NULL && prev_stpoint->address == tpoint->address) |
- { |
- tpoint->handle = (void *) -1; |
+ if (prev_ftpoint != NULL |
+ && prev_ftpoint->address == tpoint->address) |
+ { |
+ if (use_agent_p) |
+ tracepoint_send_agent (tpoint); |
+ else |
+ download_tracepoint_1 (tpoint); |
+ |
+ clone_fast_tracepoint (tpoint, prev_ftpoint); |
+ } |
+ else |
+ { |
+ /* Tracepoint is installed successfully? */ |
+ int installed = 0; |
+ |
+ /* Download and install fast tracepoint by agent. */ |
+ if (use_agent_p) |
+ installed = !tracepoint_send_agent (tpoint); |
+ else |
+ { |
+ download_tracepoint_1 (tpoint); |
+ installed = !install_fast_tracepoint (tpoint, packet); |
+ } |
+ |
+ if (installed) |
+ prev_ftpoint = tpoint; |
+ } |
} |
else |
{ |
- if (probe_marker_at (tpoint->address, packet) == 0) |
+ if (!in_process_agent_supports_ust ()) |
{ |
- tpoint->handle = (void *) -1; |
+ trace_debug ("Requested a static tracepoint, but static " |
+ "tracepoints are not supported."); |
+ break; |
+ } |
- /* So that we can handle multiple static tracepoints |
- at the same address easily. */ |
- prev_stpoint = tpoint; |
+ download_tracepoint_1 (tpoint); |
+ /* Can only probe a given marker once. */ |
+ if (prev_stpoint != NULL |
+ && prev_stpoint->address == tpoint->address) |
+ tpoint->handle = (void *) -1; |
+ else |
+ { |
+ if (probe_marker_at (tpoint->address, packet) == 0) |
+ { |
+ tpoint->handle = (void *) -1; |
+ |
+ /* So that we can handle multiple static tracepoints |
+ at the same address easily. */ |
+ prev_stpoint = tpoint; |
+ } |
} |
} |
+ |
+ prev_tpptr = tpptr; |
+ tpptr = tpoint->obj_addr_on_target; |
+ |
+ if (tpoint == tracepoints) |
+ /* First object in list, set the head pointer in the |
+ inferior. */ |
+ write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, tpptr); |
+ else |
+ write_inferior_data_ptr (prev_tpptr + offsetof (struct tracepoint, |
+ next), |
+ tpptr); |
} |
/* Any failure in the inner loop is sufficient cause to give |
@@ -3136,7 +3343,7 @@ cmd_qtstart (char *packet) |
/* Tracing is now active, hits will now start being logged. */ |
tracing = 1; |
- if (in_process_agent_loaded ()) |
+ if (agent_loaded_p ()) |
{ |
if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 1)) |
fatal ("Error setting tracing variable in lib"); |
@@ -3195,7 +3402,7 @@ stop_tracing (void) |
/* Stop logging. Tracepoints can still be hit, but they will not be |
recorded. */ |
tracing = 0; |
- if (in_process_agent_loaded ()) |
+ if (agent_loaded_p ()) |
{ |
if (write_inferior_integer (ipa_sym_addrs.addr_tracing, 0)) |
fatal ("Error clearing tracing variable in lib"); |
@@ -3207,7 +3414,7 @@ stop_tracing (void) |
if (stopping_tracepoint) |
{ |
trace_debug ("Stopping the trace because " |
- "tracepoint %d was hit %ld times", |
+ "tracepoint %d was hit %" PRIu64 " times", |
stopping_tracepoint->number, |
stopping_tracepoint->pass_count); |
tracing_stop_reason = "tpasscount"; |
@@ -3243,7 +3450,7 @@ stop_tracing (void) |
/* Clear out the tracepoints. */ |
clear_installed_tracepoints (); |
- if (in_process_agent_loaded ()) |
+ if (agent_loaded_p ()) |
{ |
/* Pull in fast tracepoint trace frames from the inferior lib |
buffer into our buffer, even if our buffer is already full, |
@@ -3406,7 +3613,7 @@ cmd_qtstatus (char *packet) |
trace_debug ("Returning trace status as %d, stop reason %s", |
tracing, tracing_stop_reason); |
- if (in_process_agent_loaded ()) |
+ if (agent_loaded_p ()) |
{ |
pause_all (1); |
@@ -3485,7 +3692,8 @@ cmd_qtp (char *own_buf) |
return; |
} |
- sprintf (own_buf, "V%lx:%lx", tpoint->hit_count, tpoint->traceframe_usage); |
+ sprintf (own_buf, "V%" PRIu64 ":%" PRIu64 "", tpoint->hit_count, |
+ tpoint->traceframe_usage); |
} |
/* State variables to help return all the tracepoint bits. */ |
@@ -3503,7 +3711,7 @@ response_tracepoint (char *packet, struct tracepoint *tpoint) |
{ |
char *buf; |
- sprintf (packet, "T%x:%s:%c:%lx:%lx", tpoint->number, |
+ sprintf (packet, "T%x:%s:%c:%" PRIx64 ":%" PRIx64, tpoint->number, |
paddress (tpoint->address), |
(tpoint->enabled ? 'E' : 'D'), tpoint->step_count, |
tpoint->pass_count); |
@@ -3514,7 +3722,7 @@ response_tracepoint (char *packet, struct tracepoint *tpoint) |
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); |
@@ -3693,7 +3901,7 @@ static void |
cmd_qtfstm (char *packet) |
{ |
if (!maybe_write_ipa_ust_not_loaded (packet)) |
- run_inferior_command (packet); |
+ run_inferior_command (packet, strlen (packet) + 1); |
} |
/* Return additional static tracepoints markers. */ |
@@ -3702,7 +3910,7 @@ static void |
cmd_qtsstm (char *packet) |
{ |
if (!maybe_write_ipa_ust_not_loaded (packet)) |
- run_inferior_command (packet); |
+ run_inferior_command (packet, strlen (packet) + 1); |
} |
/* Return the definition of the static tracepoint at a given address. |
@@ -3712,7 +3920,7 @@ static void |
cmd_qtstmat (char *packet) |
{ |
if (!maybe_write_ipa_ust_not_loaded (packet)) |
- run_inferior_command (packet); |
+ run_inferior_command (packet, strlen (packet) + 1); |
} |
/* Return the minimum instruction size needed for fast tracepoints as a |
@@ -3721,6 +3929,13 @@ cmd_qtstmat (char *packet) |
static void |
cmd_qtminftpilen (char *packet) |
{ |
+ if (current_inferior == NULL) |
+ { |
+ /* Indicate that the minimum length is currently unknown. */ |
+ strcpy (packet, "0"); |
+ return; |
+ } |
+ |
sprintf (packet, "%x", target_get_min_fast_tracepoint_insn_len ()); |
} |
@@ -3779,24 +3994,18 @@ cmd_qtbuffer (char *own_buf) |
} |
static void |
-cmd_bigqtbuffer (char *own_buf) |
+cmd_bigqtbuffer_circular (char *own_buf) |
{ |
ULONGEST val; |
char *packet = own_buf; |
- packet += strlen ("QTBuffer:"); |
+ packet += strlen ("QTBuffer:circular:"); |
- if (strncmp ("circular:", packet, strlen ("circular:")) == 0) |
- { |
- packet += strlen ("circular:"); |
- unpack_varlen_hex (packet, &val); |
- circular_trace_buffer = val; |
- trace_debug ("Trace buffer is now %s", |
- circular_trace_buffer ? "circular" : "linear"); |
- write_ok (own_buf); |
- } |
- else |
- write_enn (own_buf); |
+ unpack_varlen_hex (packet, &val); |
+ circular_trace_buffer = val; |
+ trace_debug ("Trace buffer is now %s", |
+ circular_trace_buffer ? "circular" : "linear"); |
+ write_ok (own_buf); |
} |
static void |
@@ -3915,9 +4124,9 @@ handle_tracepoint_general_set (char *packet) |
cmd_qtframe (packet); |
return 1; |
} |
- else if (strncmp ("QTBuffer:", packet, strlen ("QTBuffer:")) == 0) |
+ else if (strncmp ("QTBuffer:circular:", packet, strlen ("QTBuffer:circular:")) == 0) |
{ |
- cmd_bigqtbuffer (packet); |
+ cmd_bigqtbuffer_circular (packet); |
return 1; |
} |
else if (strncmp ("QTNotes:", packet, strlen ("QTNotes:")) == 0) |
@@ -4073,7 +4282,7 @@ tracepoint_finished_step (struct thread_info *tinfo, CORE_ADDR stop_pc) |
/* Pull in fast tracepoint trace frames from the inferior lib buffer into |
our buffer. */ |
- if (in_process_agent_loaded ()) |
+ if (agent_loaded_p ()) |
upload_fast_traceframes (); |
/* Check if we were indeed collecting data for one of more |
@@ -4174,7 +4383,7 @@ handle_tracepoint_bkpts (struct thread_info *tinfo, CORE_ADDR stop_pc) |
/* Pull in fast tracepoint trace frames from the inferior in-process |
agent's buffer into our buffer. */ |
- if (!in_process_agent_loaded ()) |
+ if (!agent_loaded_p ()) |
return 0; |
upload_fast_traceframes (); |
@@ -4268,8 +4477,12 @@ tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc) |
{ |
/* Note that we collect fast tracepoints here as well. We'll |
step over the fast tracepoint jump later, which avoids the |
- double collect. */ |
- if (tpoint->enabled && stop_pc == tpoint->address) |
+ double collect. However, we don't collect for static |
+ tracepoints here, because UST markers are compiled in program, |
+ and probes will be executed in program. So static tracepoints |
+ are collected there. */ |
+ if (tpoint->enabled && stop_pc == tpoint->address |
+ && tpoint->type != static_tracepoint) |
{ |
trace_debug ("Thread %s at address of tracepoint %d at 0x%s", |
target_pid_to_str (tinfo->entry.id), |
@@ -4309,8 +4522,6 @@ tracepoint_was_hit (struct thread_info *tinfo, CORE_ADDR stop_pc) |
#if defined IN_PROCESS_AGENT && defined HAVE_UST |
struct ust_marker_data; |
static void collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, |
- CORE_ADDR stop_pc, |
- struct tracepoint *tpoint, |
struct traceframe *tframe); |
#endif |
@@ -4337,7 +4548,7 @@ collect_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, CORE_ADDR stop_pc, |
&& stopping_tracepoint == NULL) |
stopping_tracepoint = tpoint; |
- trace_debug ("Making new traceframe for tracepoint %d at 0x%s, hit %ld", |
+ trace_debug ("Making new traceframe for tracepoint %d at 0x%s, hit %" PRIu64, |
tpoint->number, paddress (tpoint->address), tpoint->hit_count); |
tframe = add_traceframe (tpoint); |
@@ -4374,7 +4585,7 @@ collect_data_at_step (struct tracepoint_hit_ctx *ctx, |
int acti; |
trace_debug ("Making new step traceframe for " |
- "tracepoint %d at 0x%s, step %d of %ld, hit %ld", |
+ "tracepoint %d at 0x%s, step %d of %" PRIu64 ", hit %" PRIu64, |
tpoint->number, paddress (tpoint->address), |
current_step, tpoint->step_count, |
tpoint->hit_count); |
@@ -4520,7 +4731,7 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, |
preemptively), since the PC had already been adjusted to |
contain the tracepoint's address by the jump pad. */ |
trace_debug ("Storing stop pc (0x%s) in regblock", |
- paddress (tpoint->address)); |
+ paddress (stop_pc)); |
/* This changes the regblock, not the thread's |
regcache. */ |
@@ -4536,7 +4747,7 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, |
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) |
{ |
@@ -4549,8 +4760,7 @@ do_action_at_tracepoint (struct tracepoint_hit_ctx *ctx, |
{ |
#if defined IN_PROCESS_AGENT && defined HAVE_UST |
trace_debug ("Want to collect static trace data"); |
- collect_ust_data_at_tracepoint (ctx, stop_pc, |
- tpoint, tframe); |
+ collect_ust_data_at_tracepoint (ctx, tframe); |
#else |
trace_debug ("warning: collecting static trace data, " |
"but static tracepoints are not supported"); |
@@ -4589,7 +4799,7 @@ condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx, |
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) |
{ |
@@ -4604,481 +4814,44 @@ condition_true_at_tracepoint (struct tracepoint_hit_ctx *ctx, |
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. */ |
+/* Evaluates a tracepoint agent expression with context CTX, |
+ traceframe TFRAME, agent expression AEXPR and store the |
+ result in RSLT. */ |
-static char * |
-unparse_agent_expr (struct agent_expr *aexpr) |
+static enum eval_result_type |
+eval_tracepoint_agent_expr (struct tracepoint_hit_ctx *ctx, |
+ struct traceframe *tframe, |
+ struct agent_expr *aexpr, |
+ ULONGEST *rslt) |
{ |
- char *rslt; |
+ struct regcache *regcache; |
+ regcache = get_context_regcache (ctx); |
- rslt = xmalloc (2 * aexpr->length + 1); |
- convert_int_to_ascii (aexpr->bytes, rslt, aexpr->length); |
- return rslt; |
+ return gdb_eval_agent_expr (regcache, tframe, aexpr, rslt); |
} |
-#endif |
- |
-/* A wrapper for gdb_agent_op_names that does some bounds-checking. */ |
+/* Do memory copies for bytecodes. */ |
+/* Do the recording of memory blocks for actions and bytecodes. */ |
-static const char * |
-gdb_agent_op_name (int op) |
+int |
+agent_mem_read (struct traceframe *tframe, |
+ unsigned char *to, CORE_ADDR from, ULONGEST len) |
{ |
- 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. */ |
- |
-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; |
+ unsigned char *mspace; |
+ ULONGEST remaining = len; |
+ unsigned short blocklen; |
- if (aexpr->length == 0) |
+ /* If a 'to' buffer is specified, use it. */ |
+ if (to != NULL) |
{ |
- trace_debug ("empty agent expression"); |
- return expr_eval_empty_expression; |
+ read_inferior_memory (from, to, len); |
+ return 0; |
} |
- /* 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) |
+ /* Otherwise, create a new memory block in the trace buffer. */ |
+ while (remaining > 0) |
{ |
- 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; |
- } |
- |
- trace_debug ("Op %s -> sp=%d, top=0x%s", |
- gdb_agent_op_name (op), sp, pulongest (top)); |
- } |
-} |
- |
-/* Do memory copies for bytecodes. */ |
-/* Do the recording of memory blocks for actions and bytecodes. */ |
- |
-static int |
-agent_mem_read (struct traceframe *tframe, |
- unsigned char *to, CORE_ADDR from, ULONGEST len) |
-{ |
- unsigned char *mspace; |
- ULONGEST remaining = len; |
- unsigned short blocklen; |
- |
- /* If a 'to' buffer is specified, use it. */ |
- if (to != NULL) |
- { |
- read_inferior_memory (from, to, len); |
- return 0; |
- } |
- |
- /* Otherwise, create a new memory block in the trace buffer. */ |
- while (remaining > 0) |
- { |
- size_t sp; |
+ size_t sp; |
blocklen = (remaining > 65535 ? 65535 : remaining); |
sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen; |
@@ -5102,7 +4875,7 @@ agent_mem_read (struct traceframe *tframe, |
return 0; |
} |
-static int |
+int |
agent_mem_read_string (struct traceframe *tframe, |
unsigned char *to, CORE_ADDR from, ULONGEST len) |
{ |
@@ -5164,7 +4937,7 @@ agent_mem_read_string (struct traceframe *tframe, |
/* Record the value of a trace state variable. */ |
-static int |
+int |
agent_tsv_read (struct traceframe *tframe, int n) |
{ |
unsigned char *vspace; |
@@ -5957,250 +5730,24 @@ 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 (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) |
@@ -6230,452 +5777,22 @@ compile_tracepoint_condition (struct tracepoint *tpoint, |
} |
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; |
-} |
- |
-/* 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; |
+ /* Leave the unfinished code in situ, but don't point to it. */ |
- /* 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; |
- } |
- } |
+ tpoint->compiled_cond = 0; |
- /* 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; |
- } |
+ trace_debug ("Condition compilation for tracepoint %d failed, " |
+ "error code %d", |
+ tpoint->number, err); |
} |
- return expr_eval_no_error; |
+ /* 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; |
} |
/* We'll need to adjust these when we consider bi-arch setups, and big |
@@ -6808,55 +5925,8 @@ download_tracepoint_1 (struct tracepoint *tpoint) |
/* Now for each pointer, download the action. */ |
for (i = 0; i < tpoint->numactions; i++) |
{ |
- CORE_ADDR ipa_action = 0; |
struct tracepoint_action *action = tpoint->actions[i]; |
- |
- switch (action->type) |
- { |
- case 'M': |
- ipa_action |
- = target_malloc (sizeof (struct collect_memory_action)); |
- write_inferior_memory (ipa_action, |
- (unsigned char *) action, |
- sizeof (struct collect_memory_action)); |
- break; |
- case 'R': |
- ipa_action |
- = target_malloc (sizeof (struct collect_registers_action)); |
- write_inferior_memory (ipa_action, |
- (unsigned char *) action, |
- sizeof (struct collect_registers_action)); |
- break; |
- case 'X': |
- { |
- CORE_ADDR expr; |
- struct eval_expr_action *eaction |
- = (struct eval_expr_action *) action; |
- |
- ipa_action = target_malloc (sizeof (*eaction)); |
- write_inferior_memory (ipa_action, |
- (unsigned char *) eaction, |
- sizeof (*eaction)); |
- |
- expr = download_agent_expr (eaction->expr); |
- write_inferior_data_ptr |
- (ipa_action + offsetof (struct eval_expr_action, expr), |
- expr); |
- break; |
- } |
- case 'L': |
- ipa_action = target_malloc |
- (sizeof (struct collect_static_trace_data_action)); |
- write_inferior_memory |
- (ipa_action, |
- (unsigned char *) action, |
- sizeof (struct collect_static_trace_data_action)); |
- break; |
- default: |
- trace_debug ("unknown trace action '%c', ignoring", |
- action->type); |
- break; |
- } |
+ CORE_ADDR ipa_action = action->ops->download (action); |
if (ipa_action != 0) |
write_inferior_data_ptr |
@@ -6866,6 +5936,91 @@ download_tracepoint_1 (struct tracepoint *tpoint) |
} |
} |
+#define IPA_PROTO_FAST_TRACE_FLAG 0 |
+#define IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET 2 |
+#define IPA_PROTO_FAST_TRACE_JUMP_PAD 10 |
+#define IPA_PROTO_FAST_TRACE_FJUMP_SIZE 18 |
+#define IPA_PROTO_FAST_TRACE_FJUMP_INSN 22 |
+ |
+/* Send a command to agent to download and install tracepoint TPOINT. */ |
+ |
+static int |
+tracepoint_send_agent (struct tracepoint *tpoint) |
+{ |
+ char buf[IPA_CMD_BUF_SIZE]; |
+ char *p; |
+ int i, ret; |
+ |
+ p = buf; |
+ strcpy (p, "FastTrace:"); |
+ p += 10; |
+ |
+ COPY_FIELD_TO_BUF (p, tpoint, number); |
+ COPY_FIELD_TO_BUF (p, tpoint, address); |
+ COPY_FIELD_TO_BUF (p, tpoint, type); |
+ COPY_FIELD_TO_BUF (p, tpoint, enabled); |
+ COPY_FIELD_TO_BUF (p, tpoint, step_count); |
+ COPY_FIELD_TO_BUF (p, tpoint, pass_count); |
+ COPY_FIELD_TO_BUF (p, tpoint, numactions); |
+ COPY_FIELD_TO_BUF (p, tpoint, hit_count); |
+ COPY_FIELD_TO_BUF (p, tpoint, traceframe_usage); |
+ COPY_FIELD_TO_BUF (p, tpoint, compiled_cond); |
+ COPY_FIELD_TO_BUF (p, tpoint, orig_size); |
+ |
+ /* condition */ |
+ p = agent_expr_send (p, tpoint->cond); |
+ |
+ /* tracepoint_action */ |
+ for (i = 0; i < tpoint->numactions; i++) |
+ { |
+ struct tracepoint_action *action = tpoint->actions[i]; |
+ |
+ p[0] = action->type; |
+ p = action->ops->send (&p[1], action); |
+ } |
+ |
+ get_jump_space_head (); |
+ /* Copy the value of GDB_JUMP_PAD_HEAD to command buffer, so that |
+ agent can use jump pad from it. */ |
+ if (tpoint->type == fast_tracepoint) |
+ { |
+ memcpy (p, &gdb_jump_pad_head, 8); |
+ p += 8; |
+ } |
+ |
+ ret = run_inferior_command (buf, (int) (ptrdiff_t) (p - buf)); |
+ if (ret) |
+ return ret; |
+ |
+ if (strncmp (buf, "OK", 2) != 0) |
+ return 1; |
+ |
+ /* The value of tracepoint's target address is stored in BUF. */ |
+ memcpy (&tpoint->obj_addr_on_target, |
+ &buf[IPA_PROTO_FAST_TRACE_ADDR_ON_TARGET], 8); |
+ |
+ if (tpoint->type == fast_tracepoint) |
+ { |
+ unsigned char *insn |
+ = (unsigned char *) &buf[IPA_PROTO_FAST_TRACE_FJUMP_INSN]; |
+ int fjump_size; |
+ |
+ trace_debug ("agent: read from cmd_buf 0x%x 0x%x\n", |
+ (unsigned int) tpoint->obj_addr_on_target, |
+ (unsigned int) gdb_jump_pad_head); |
+ |
+ memcpy (&gdb_jump_pad_head, &buf[IPA_PROTO_FAST_TRACE_JUMP_PAD], 8); |
+ |
+ /* This has been done in agent. We should also set up record for it. */ |
+ memcpy (&fjump_size, &buf[IPA_PROTO_FAST_TRACE_FJUMP_SIZE], 4); |
+ /* Wire it in. */ |
+ tpoint->handle |
+ = set_fast_tracepoint_jump (tpoint->address, insn, fjump_size); |
+ } |
+ |
+ return 0; |
+} |
+ |
static void |
download_tracepoint (struct tracepoint *tpoint) |
{ |
@@ -6914,42 +6069,6 @@ download_tracepoint (struct tracepoint *tpoint) |
} |
static void |
-download_tracepoints (void) |
-{ |
- CORE_ADDR tpptr = 0, prev_tpptr = 0; |
- struct tracepoint *tpoint; |
- |
- /* Start out empty. */ |
- write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, 0); |
- |
- for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) |
- { |
- if (tpoint->type != fast_tracepoint |
- && tpoint->type != static_tracepoint) |
- continue; |
- |
- prev_tpptr = tpptr; |
- |
- download_tracepoint_1 (tpoint); |
- |
- tpptr = tpoint->obj_addr_on_target; |
- |
- if (tpoint == tracepoints) |
- { |
- /* First object in list, set the head pointer in the |
- inferior. */ |
- write_inferior_data_ptr (ipa_sym_addrs.addr_tracepoints, tpptr); |
- } |
- else |
- { |
- write_inferior_data_ptr (prev_tpptr + offsetof (struct tracepoint, |
- next), |
- tpptr); |
- } |
- } |
-} |
- |
-static void |
download_trace_state_variables (void) |
{ |
CORE_ADDR ptr = 0, prev_ptr = 0; |
@@ -7285,7 +6404,7 @@ upload_fast_traceframes (void) |
#ifdef IN_PROCESS_AGENT |
IP_AGENT_EXPORT int ust_loaded; |
-IP_AGENT_EXPORT char cmd_buf[CMD_BUF_SIZE]; |
+IP_AGENT_EXPORT char cmd_buf[IPA_CMD_BUF_SIZE]; |
#ifdef HAVE_UST |
@@ -7478,8 +6597,6 @@ gdb_probe (const struct marker *mdata, void *probe_private, |
static void |
collect_ust_data_at_tracepoint (struct tracepoint_hit_ctx *ctx, |
- CORE_ADDR stop_pc, |
- struct tracepoint *tpoint, |
struct traceframe *tframe) |
{ |
struct static_tracepoint_ctx *umd = (struct static_tracepoint_ctx *) ctx; |
@@ -7536,94 +6653,8 @@ static struct ltt_available_probe gdb_ust_probe = |
#endif /* HAVE_UST */ |
#endif /* IN_PROCESS_AGENT */ |
-#ifdef HAVE_UST |
- |
-#include <sys/socket.h> |
-#include <sys/un.h> |
- |
-#ifndef UNIX_PATH_MAX |
-#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) |
-#endif |
- |
-/* Where we put the socked used for synchronization. */ |
-#define SOCK_DIR P_tmpdir |
- |
-#endif /* HAVE_UST */ |
- |
#ifndef IN_PROCESS_AGENT |
-#ifdef HAVE_UST |
- |
-static int |
-gdb_ust_connect_sync_socket (int pid) |
-{ |
- struct sockaddr_un addr; |
- int res, fd; |
- char path[UNIX_PATH_MAX]; |
- |
- res = xsnprintf (path, UNIX_PATH_MAX, "%s/gdb_ust%d", SOCK_DIR, pid); |
- if (res >= UNIX_PATH_MAX) |
- { |
- trace_debug ("string overflow allocating socket name"); |
- return -1; |
- } |
- |
- res = fd = socket (PF_UNIX, SOCK_STREAM, 0); |
- if (res == -1) |
- { |
- warning ("error opening sync socket: %s\n", strerror (errno)); |
- return -1; |
- } |
- |
- addr.sun_family = AF_UNIX; |
- |
- res = xsnprintf (addr.sun_path, UNIX_PATH_MAX, "%s", path); |
- if (res >= UNIX_PATH_MAX) |
- { |
- warning ("string overflow allocating socket name\n"); |
- close (fd); |
- return -1; |
- } |
- |
- res = connect (fd, (struct sockaddr *) &addr, sizeof (addr)); |
- if (res == -1) |
- { |
- warning ("error connecting sync socket (%s): %s. " |
- "Make sure the directory exists and that it is writable.", |
- path, strerror (errno)); |
- close (fd); |
- return -1; |
- } |
- |
- return fd; |
-} |
- |
-/* Resume thread PTID. */ |
- |
-static void |
-resume_thread (ptid_t ptid) |
-{ |
- struct thread_resume resume_info; |
- |
- resume_info.thread = ptid; |
- resume_info.kind = resume_continue; |
- resume_info.sig = TARGET_SIGNAL_0; |
- (*the_target->resume) (&resume_info, 1); |
-} |
- |
-/* Stop thread PTID. */ |
- |
-static void |
-stop_thread (ptid_t ptid) |
-{ |
- struct thread_resume resume_info; |
- |
- resume_info.thread = ptid; |
- resume_info.kind = resume_stop; |
- resume_info.sig = TARGET_SIGNAL_0; |
- (*the_target->resume) (&resume_info, 1); |
-} |
- |
/* Ask the in-process agent to run a command. Since we don't want to |
have to handle the IPA hitting breakpoints while running the |
command, we pause all threads, remove all breakpoints, and then set |
@@ -7632,94 +6663,17 @@ stop_thread (ptid_t ptid) |
synchronization. */ |
static int |
-run_inferior_command (char *cmd) |
+run_inferior_command (char *cmd, int len) |
{ |
int err = -1; |
- int fd = -1; |
int pid = ptid_get_pid (current_inferior->entry.id); |
- int tid; |
- ptid_t ptid = null_ptid; |
trace_debug ("run_inferior_command: running: %s", cmd); |
pause_all (0); |
uninsert_all_breakpoints (); |
- if (read_inferior_integer (ipa_sym_addrs.addr_helper_thread_id, &tid)) |
- { |
- warning ("Error reading helper thread's id in lib"); |
- goto out; |
- } |
- |
- if (tid == 0) |
- { |
- warning ("helper thread not initialized yet"); |
- goto out; |
- } |
- |
- if (write_inferior_memory (ipa_sym_addrs.addr_cmd_buf, |
- (unsigned char *) cmd, strlen (cmd) + 1)) |
- { |
- warning ("Error writing command"); |
- goto out; |
- } |
- |
- ptid = ptid_build (pid, tid, 0); |
- |
- resume_thread (ptid); |
- |
- fd = gdb_ust_connect_sync_socket (pid); |
- if (fd >= 0) |
- { |
- char buf[1] = ""; |
- int ret; |
- |
- trace_debug ("signalling helper thread"); |
- |
- do |
- { |
- ret = write (fd, buf, 1); |
- } while (ret == -1 && errno == EINTR); |
- |
- trace_debug ("waiting for helper thread's response"); |
- |
- do |
- { |
- ret = read (fd, buf, 1); |
- } while (ret == -1 && errno == EINTR); |
- |
- close (fd); |
- |
- trace_debug ("helper thread's response received"); |
- } |
- |
- out: |
- |
- /* Need to read response with the inferior stopped. */ |
- if (!ptid_equal (ptid, null_ptid)) |
- { |
- int was_non_stop = non_stop; |
- struct target_waitstatus status; |
- |
- stop_thread (ptid); |
- non_stop = 1; |
- mywait (ptid, &status, 0, 0); |
- non_stop = was_non_stop; |
- } |
- |
- if (fd >= 0) |
- { |
- if (read_inferior_memory (ipa_sym_addrs.addr_cmd_buf, |
- (unsigned char *) cmd, CMD_BUF_SIZE)) |
- { |
- warning ("Error reading command response"); |
- } |
- else |
- { |
- err = 0; |
- trace_debug ("run_inferior_command: response: %s", cmd); |
- } |
- } |
+ err = agent_run_command (pid, (const char *) cmd, len); |
reinsert_all_breakpoints (); |
unpause_all (0); |
@@ -7727,24 +6681,22 @@ run_inferior_command (char *cmd) |
return err; |
} |
-#else /* HAVE_UST */ |
+#else /* !IN_PROCESS_AGENT */ |
-static int |
-run_inferior_command (char *cmd) |
-{ |
- return -1; |
-} |
+#include <sys/socket.h> |
+#include <sys/un.h> |
-#endif /* HAVE_UST */ |
+#ifndef UNIX_PATH_MAX |
+#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) NULL)->sun_path) |
+#endif |
-#else /* !IN_PROCESS_AGENT */ |
+/* Where we put the socked used for synchronization. */ |
+#define SOCK_DIR P_tmpdir |
/* Thread ID of the helper thread. GDBserver reads this to know which |
is the help thread. This is an LWP id on Linux. */ |
int helper_thread_id; |
-#ifdef HAVE_UST |
- |
static int |
init_named_socket (const char *name) |
{ |
@@ -7797,7 +6749,7 @@ init_named_socket (const char *name) |
} |
static int |
-gdb_ust_socket_init (void) |
+gdb_agent_socket_init (void) |
{ |
int result, fd; |
char name[UNIX_PATH_MAX]; |
@@ -7819,17 +6771,7 @@ gdb_ust_socket_init (void) |
return fd; |
} |
-/* Return an hexstr version of the STR C string, fit for sending to |
- GDB. */ |
- |
-static char * |
-cstr_to_hexstr (const char *str) |
-{ |
- int len = strlen (str); |
- char *hexstr = xmalloc (len * 2 + 1); |
- convert_int_to_ascii ((gdb_byte *) str, hexstr, len); |
- return hexstr; |
-} |
+#ifdef HAVE_UST |
/* The next marker to be returned on a qTsSTM command. */ |
static const struct marker *next_st; |
@@ -7869,6 +6811,18 @@ next_marker (const struct marker *m) |
return NULL; |
} |
+/* Return an hexstr version of the STR C string, fit for sending to |
+ GDB. */ |
+ |
+static char * |
+cstr_to_hexstr (const char *str) |
+{ |
+ int len = strlen (str); |
+ char *hexstr = xmalloc (len * 2 + 1); |
+ convert_int_to_ascii ((gdb_byte *) str, hexstr, len); |
+ return hexstr; |
+} |
+ |
/* Compose packet that is the response to the qTsSTM/qTfSTM/qTSTMat |
packets. */ |
@@ -8029,19 +6983,32 @@ cmd_qtstmat (char *packet) |
return -1; |
} |
+static void |
+gdb_ust_init (void) |
+{ |
+ if (!dlsym_ust ()) |
+ return; |
+ |
+ USTF(ltt_probe_register) (&gdb_ust_probe); |
+} |
+ |
+#endif /* HAVE_UST */ |
+ |
+#include <sys/syscall.h> |
+ |
+/* Helper thread of agent. */ |
+ |
static void * |
-gdb_ust_thread (void *arg) |
+gdb_agent_helper_thread (void *arg) |
{ |
int listen_fd; |
while (1) |
{ |
- listen_fd = gdb_ust_socket_init (); |
+ listen_fd = gdb_agent_socket_init (); |
-#ifdef SYS_gettid |
if (helper_thread_id == 0) |
helper_thread_id = syscall (SYS_gettid); |
-#endif |
if (listen_fd == -1) |
{ |
@@ -8088,6 +7055,7 @@ gdb_ust_thread (void *arg) |
if (cmd_buf[0]) |
{ |
+#ifdef HAVE_UST |
if (strcmp ("qTfSTM", cmd_buf) == 0) |
{ |
cmd_qtfstm (cmd_buf); |
@@ -8114,15 +7082,11 @@ gdb_ust_thread (void *arg) |
{ |
cmd_qtstmat (cmd_buf); |
} |
- else if (strcmp (cmd_buf, "help") == 0) |
- { |
- strcpy (cmd_buf, "for help, press F1\n"); |
- } |
- else |
- strcpy (cmd_buf, ""); |
+#endif /* HAVE_UST */ |
} |
- write (fd, buf, 1); |
+ /* Fix compiler's warning: ignoring return value of 'write'. */ |
+ ret = write (fd, buf, 1); |
close (fd); |
} |
} |
@@ -8131,18 +7095,18 @@ gdb_ust_thread (void *arg) |
} |
#include <signal.h> |
+#include <pthread.h> |
+ |
+IP_AGENT_EXPORT int gdb_agent_capability = AGENT_CAPA_STATIC_TRACE; |
static void |
-gdb_ust_init (void) |
+gdb_agent_init (void) |
{ |
int res; |
pthread_t thread; |
sigset_t new_mask; |
sigset_t orig_mask; |
- if (!dlsym_ust ()) |
- return; |
- |
/* We want the helper thread to be as transparent as possible, so |
have it inherit an all-signals-blocked mask. */ |
@@ -8153,7 +7117,7 @@ gdb_ust_init (void) |
res = pthread_create (&thread, |
NULL, |
- gdb_ust_thread, |
+ gdb_agent_helper_thread, |
NULL); |
res = pthread_sigmask (SIG_SETMASK, &orig_mask, NULL); |
@@ -8163,11 +7127,11 @@ gdb_ust_init (void) |
while (helper_thread_id == 0) |
usleep (1); |
- USTF(ltt_probe_register) (&gdb_ust_probe); |
+#ifdef HAVE_UST |
+ gdb_ust_init (); |
+#endif |
} |
-#endif /* HAVE_UST */ |
- |
#include <sys/mman.h> |
#include <fcntl.h> |
@@ -8198,9 +7162,7 @@ initialize_tracepoint_ftlib (void) |
{ |
initialize_tracepoint (); |
-#ifdef HAVE_UST |
- gdb_ust_init (); |
-#endif |
+ gdb_agent_init (); |
} |
#endif /* IN_PROCESS_AGENT */ |
@@ -8238,23 +7200,35 @@ initialize_tracepoint (void) |
#ifdef IN_PROCESS_AGENT |
{ |
+ uintptr_t addr; |
int pagesize; |
+ |
pagesize = sysconf (_SC_PAGE_SIZE); |
if (pagesize == -1) |
fatal ("sysconf"); |
gdb_tp_heap_buffer = xmalloc (5 * 1024 * 1024); |
- /* Allocate scratch buffer aligned on a page boundary. */ |
- gdb_jump_pad_buffer = memalign (pagesize, pagesize * 20); |
- gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + pagesize * 20; |
+#define SCRATCH_BUFFER_NPAGES 20 |
+ |
+ /* Allocate scratch buffer aligned on a page boundary, at a low |
+ address (close to the main executable's code). */ |
+ for (addr = pagesize; addr != 0; addr += pagesize) |
+ { |
+ gdb_jump_pad_buffer = mmap ((void *) addr, pagesize * SCRATCH_BUFFER_NPAGES, |
+ PROT_READ | PROT_WRITE | PROT_EXEC, |
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, |
+ -1, 0); |
+ if (gdb_jump_pad_buffer != MAP_FAILED) |
+ break; |
+ } |
- /* Make it writable and executable. */ |
- if (mprotect (gdb_jump_pad_buffer, pagesize * 20, |
- PROT_READ | PROT_WRITE | PROT_EXEC) != 0) |
+ if (addr == 0) |
fatal ("\ |
-initialize_tracepoint: mprotect(%p, %d, PROT_READ|PROT_EXEC) failed with %s", |
- gdb_jump_pad_buffer, pagesize * 20, strerror (errno)); |
+initialize_tracepoint: mmap'ing jump pad buffer failed with %s", |
+ strerror (errno)); |
+ |
+ gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + pagesize * SCRATCH_BUFFER_NPAGES; |
} |
gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0; |