| 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;
|
|
|