/* Tracepoint code for remote server for GDB.
- Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ Copyright (C) 2009-2015 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "server.h"
+#include "tracepoint.h"
+#include "gdbthread.h"
+#include "agent.h"
+#include "rsp-low.h"
+
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
-#include <sys/time.h>
-#include <stddef.h>
-#if HAVE_STDINT_H
-#include <stdint.h>
-#endif
+#include "gdb_sys_time.h"
+#include <inttypes.h>
#include "ax.h"
+#include "tdesc.h"
+
+#define DEFAULT_TRACE_BUFFER_SIZE 5242880 /* 5*1024*1024 */
/* This file is built for both GDBserver, and the in-process
agent (IPA), a shared library that includes a tracing agent that is
*/
-static void trace_vdebug (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+#ifdef IN_PROCESS_AGENT
+
+static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
static void
trace_vdebug (const char *fmt, ...)
trace_vdebug ((fmt), ##args); \
} while (0)
-#define trace_debug(FMT, args...) \
- trace_debug_1 (1, FMT, ##args)
-
-#if defined(__GNUC__)
-# define ATTR_USED __attribute__((used))
-# define ATTR_NOINLINE __attribute__((noinline))
-# define ATTR_CONSTRUCTOR __attribute__ ((constructor))
#else
-# define ATTR_USED
-# define ATTR_NOINLINE
-# define ATTR_CONSTRUCTOR
-#endif
-/* Make sure the functions the IPA needs to export (symbols GDBserver
- needs to query GDB about) are exported. */
+#define trace_debug_1(level, fmt, args...) \
+ do { \
+ if (level <= debug_threads) \
+ { \
+ debug_printf ((fmt), ##args); \
+ debug_printf ("\n"); \
+ } \
+ } while (0)
-#ifdef IN_PROCESS_AGENT
-# if defined _WIN32 || defined __CYGWIN__
-# define IP_AGENT_EXPORT __declspec(dllexport) ATTR_USED
-# else
-# if __GNUC__ >= 4
-# define IP_AGENT_EXPORT \
- __attribute__ ((visibility("default"))) ATTR_USED
-# else
-# define IP_AGENT_EXPORT ATTR_USED
-# endif
-# endif
-#else
-# define IP_AGENT_EXPORT
#endif
+#define trace_debug(FMT, args...) \
+ trace_debug_1 (1, FMT, ##args)
+
/* Prefix exported symbols, for good citizenship. All the symbols
- that need exporting are defined in this module. */
+ that need exporting are defined in this module. Note that all
+ these symbols must be tagged with IP_AGENT_EXPORT_*. */
#ifdef IN_PROCESS_AGENT
-# define gdb_tp_heap_buffer gdb_agent_gdb_tp_heap_buffer
-# define gdb_jump_pad_buffer gdb_agent_gdb_jump_pad_buffer
-# define gdb_jump_pad_buffer_end gdb_agent_gdb_jump_pad_buffer_end
-# define gdb_trampoline_buffer gdb_agent_gdb_trampoline_buffer
-# define gdb_trampoline_buffer_end gdb_agent_gdb_trampoline_buffer_end
-# define gdb_trampoline_buffer_error gdb_agent_gdb_trampoline_buffer_error
-# define collecting gdb_agent_collecting
-# define gdb_collect gdb_agent_gdb_collect
-# define stop_tracing gdb_agent_stop_tracing
-# define flush_trace_buffer gdb_agent_flush_trace_buffer
-# define about_to_request_buffer_space gdb_agent_about_to_request_buffer_space
-# define trace_buffer_is_full gdb_agent_trace_buffer_is_full
-# define stopping_tracepoint gdb_agent_stopping_tracepoint
-# define expr_eval_result gdb_agent_expr_eval_result
-# define error_tracepoint gdb_agent_error_tracepoint
-# define tracepoints gdb_agent_tracepoints
-# define tracing gdb_agent_tracing
-# define trace_buffer_ctrl gdb_agent_trace_buffer_ctrl
-# define trace_buffer_ctrl_curr gdb_agent_trace_buffer_ctrl_curr
-# define trace_buffer_lo gdb_agent_trace_buffer_lo
-# define trace_buffer_hi gdb_agent_trace_buffer_hi
-# define traceframe_read_count gdb_agent_traceframe_read_count
-# define traceframe_write_count gdb_agent_traceframe_write_count
-# define traceframes_created gdb_agent_traceframes_created
-# define trace_state_variables gdb_agent_trace_state_variables
-# define get_raw_reg gdb_agent_get_raw_reg
+# define gdb_tp_heap_buffer IPA_SYM_EXPORTED_NAME (gdb_tp_heap_buffer)
+# define gdb_jump_pad_buffer IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer)
+# define gdb_jump_pad_buffer_end IPA_SYM_EXPORTED_NAME (gdb_jump_pad_buffer_end)
+# define gdb_trampoline_buffer IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer)
+# define gdb_trampoline_buffer_end IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_end)
+# define gdb_trampoline_buffer_error IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_error)
+# define collecting IPA_SYM_EXPORTED_NAME (collecting)
+# define gdb_collect IPA_SYM_EXPORTED_NAME (gdb_collect)
+# define stop_tracing IPA_SYM_EXPORTED_NAME (stop_tracing)
+# define flush_trace_buffer IPA_SYM_EXPORTED_NAME (flush_trace_buffer)
+# define about_to_request_buffer_space IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space)
+# define trace_buffer_is_full IPA_SYM_EXPORTED_NAME (trace_buffer_is_full)
+# define stopping_tracepoint IPA_SYM_EXPORTED_NAME (stopping_tracepoint)
+# define expr_eval_result IPA_SYM_EXPORTED_NAME (expr_eval_result)
+# define error_tracepoint IPA_SYM_EXPORTED_NAME (error_tracepoint)
+# define tracepoints IPA_SYM_EXPORTED_NAME (tracepoints)
+# define tracing IPA_SYM_EXPORTED_NAME (tracing)
+# define trace_buffer_ctrl IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl)
+# define trace_buffer_ctrl_curr IPA_SYM_EXPORTED_NAME (trace_buffer_ctrl_curr)
+# define trace_buffer_lo IPA_SYM_EXPORTED_NAME (trace_buffer_lo)
+# define trace_buffer_hi IPA_SYM_EXPORTED_NAME (trace_buffer_hi)
+# define traceframe_read_count IPA_SYM_EXPORTED_NAME (traceframe_read_count)
+# define traceframe_write_count IPA_SYM_EXPORTED_NAME (traceframe_write_count)
+# define traceframes_created IPA_SYM_EXPORTED_NAME (traceframes_created)
+# define trace_state_variables IPA_SYM_EXPORTED_NAME (trace_state_variables)
+# define get_raw_reg IPA_SYM_EXPORTED_NAME (get_raw_reg)
# define get_trace_state_variable_value \
- gdb_agent_get_trace_state_variable_value
+ IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value)
# define set_trace_state_variable_value \
- gdb_agent_set_trace_state_variable_value
-# define ust_loaded gdb_agent_ust_loaded
-# define helper_thread_id gdb_agent_helper_thread_id
-# define cmd_buf gdb_agent_cmd_buf
+ IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value)
+# define ust_loaded IPA_SYM_EXPORTED_NAME (ust_loaded)
+# define helper_thread_id IPA_SYM_EXPORTED_NAME (helper_thread_id)
+# define cmd_buf IPA_SYM_EXPORTED_NAME (cmd_buf)
#endif
#ifndef IN_PROCESS_AGENT
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;
int offset;
- int required;
} symbol_list[] = {
IPA_SYM(gdb_tp_heap_buffer),
IPA_SYM(gdb_jump_pad_buffer),
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
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;
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;
{
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++)
if (look_up_one_symbol (symbol_list[i].name, addrp, 1) == 0)
{
if (debug_threads)
- fprintf (stderr, "symbol `%s' not found\n", symbol_list[i].name);
+ debug_printf ("symbol `%s' not found\n", symbol_list[i].name);
return;
}
}
- all_tracepoint_symbols_looked_up = 1;
+ agent_look_up_symbols (NULL);
}
#endif
# define UNKNOWN_SIDE_EFFECTS() do {} while (0)
#endif
-IP_AGENT_EXPORT void ATTR_USED ATTR_NOINLINE
+IP_AGENT_EXPORT_FUNC void
stop_tracing (void)
{
/* GDBserver places breakpoint here. */
UNKNOWN_SIDE_EFFECTS();
}
-IP_AGENT_EXPORT void ATTR_USED ATTR_NOINLINE
+IP_AGENT_EXPORT_FUNC void
flush_trace_buffer (void)
{
/* GDBserver places breakpoint here. */
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)
sizeof (*val));
}
+struct tracepoint;
+static int tracepoint_send_agent (struct tracepoint *tpoint);
+
static int
read_inferior_uinteger (CORE_ADDR symaddr, unsigned int *val)
{
return write_inferior_memory (symaddr, (unsigned char *) &val, sizeof (val));
}
+static CORE_ADDR target_malloc (ULONGEST size);
+static int write_inferior_data_ptr (CORE_ADDR where, CORE_ADDR ptr);
+
+#define COPY_FIELD_TO_BUF(BUF, OBJ, FIELD) \
+ do { \
+ memcpy (BUF, &(OBJ)->FIELD, sizeof ((OBJ)->FIELD)); \
+ BUF += sizeof ((OBJ)->FIELD); \
+ } while (0)
+
#endif
+/* Operations on various types of tracepoint actions. */
+
+struct tracepoint_action;
+
+struct tracepoint_action_ops
+{
+ /* Download tracepoint action ACTION to IPA. Return the address of action
+ in IPA/inferior. */
+ CORE_ADDR (*download) (const struct tracepoint_action *action);
+
+ /* 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;
};
ULONGEST addr;
ULONGEST len;
- int basereg;
+ int32_t basereg;
};
/* An 'R' (collect registers) 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. */
struct tracepoint_hit_ctx;
-typedef enum eval_result_type (*condfn) (struct tracepoint_hit_ctx *,
+typedef enum eval_result_type (*condfn) (unsigned char *,
ULONGEST *);
/* The definition of a 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. */
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;
/* 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;
#endif
+EXTERN_C_PUSH
+
/* The linked list of all tracepoints. Marked explicitly as used as
the in-process library doesn't use it for the fast tracepoints
support. */
-IP_AGENT_EXPORT struct tracepoint *tracepoints ATTR_USED;
-
-#ifndef IN_PROCESS_AGENT
-
-/* Pointer to the last tracepoint in the list, new tracepoints are
- linked in at the end. */
-
-static struct tracepoint *last_tracepoint;
-#endif
+IP_AGENT_EXPORT_VAR struct tracepoint *tracepoints;
/* The first tracepoint to exceed its pass count. */
-IP_AGENT_EXPORT struct tracepoint *stopping_tracepoint;
+IP_AGENT_EXPORT_VAR struct tracepoint *stopping_tracepoint;
/* True if the trace buffer is full or otherwise no longer usable. */
-IP_AGENT_EXPORT int trace_buffer_is_full;
+IP_AGENT_EXPORT_VAR int trace_buffer_is_full;
+
+/* The first error that occurred during expression evaluation. */
-static enum eval_result_type expr_eval_result = expr_eval_no_error;
+/* Stored as an int to avoid the IPA ABI being dependent on whatever
+ the compiler decides to use for the enum's underlying type. Holds
+ enum eval_result_type values. */
+IP_AGENT_EXPORT_VAR int expr_eval_result = expr_eval_no_error;
+
+EXTERN_C_POP
#ifndef IN_PROCESS_AGENT
+/* Pointer to the last tracepoint in the list, new tracepoints are
+ linked in at the end. */
+
+static struct tracepoint *last_tracepoint;
+
static const char *eval_result_names[] =
{
"terror:in the attic", /* this should never be reported */
/* The tracepoint in which the error occurred. */
-static struct tracepoint *error_tracepoint;
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR struct tracepoint *error_tracepoint;
+EXTERN_C_POP
struct trace_state_variable
{
struct trace_state_variable *alloced_trace_state_variables;
#endif
-IP_AGENT_EXPORT struct trace_state_variable *trace_state_variables;
+IP_AGENT_EXPORT_VAR struct trace_state_variable *trace_state_variables;
/* The results of tracing go into a fixed-size space known as the
"trace buffer". Because usage follows a limited number of
} ATTR_PACKED;
+/* The size of the EOB marker, in bytes. A traceframe with zeroed
+ fields (and no data) marks the end of trace data. */
+#define TRACEFRAME_EOB_MARKER_SIZE offsetof (struct traceframe, data)
+
/* The traceframe to be used as the source of data to send back to
GDB. A value of -1 means to get data from the live program. */
static int circular_trace_buffer;
#endif
+/* Size of the trace buffer. */
+
+static LONGEST trace_buffer_size;
+
+EXTERN_C_PUSH
+
/* Pointer to the block of memory that traceframes all go into. */
-static unsigned char *trace_buffer_lo;
+IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_lo;
/* Pointer to the end of the trace buffer, more precisely to the byte
after the end of the buffer. */
-static unsigned char *trace_buffer_hi;
+IP_AGENT_EXPORT_VAR unsigned char *trace_buffer_hi;
+
+EXTERN_C_POP
/* Control structure holding the read/write/etc. pointers into the
trace buffer. We need more than one of these to implement a
#define GDBSERVER_UPDATED_FLUSH_COUNT_BIT 0x80000000
#ifdef IN_PROCESS_AGENT
-IP_AGENT_EXPORT struct trace_buffer_control trace_buffer_ctrl[3];
-IP_AGENT_EXPORT unsigned int trace_buffer_ctrl_curr;
+IP_AGENT_EXPORT_VAR struct trace_buffer_control trace_buffer_ctrl[3];
+IP_AGENT_EXPORT_VAR unsigned int trace_buffer_ctrl_curr;
# define TRACE_BUFFER_CTRL_CURR \
(trace_buffer_ctrl_curr & ~GDBSERVER_FLUSH_COUNT_MASK)
of complete traceframes present in the trace buffer. The IP agent
writes to the write count, GDBserver writes to read count. */
-IP_AGENT_EXPORT unsigned int traceframe_write_count;
-IP_AGENT_EXPORT unsigned int traceframe_read_count;
+IP_AGENT_EXPORT_VAR unsigned int traceframe_write_count;
+IP_AGENT_EXPORT_VAR unsigned int traceframe_read_count;
/* Convenience macro. */
/* The count of all traceframes created in the current run, including
ones that were discarded to make room. */
-IP_AGENT_EXPORT int traceframes_created;
+IP_AGENT_EXPORT_VAR int traceframes_created;
#ifndef IN_PROCESS_AGENT
/* The global that controls tracing overall. */
-IP_AGENT_EXPORT int tracing;
+IP_AGENT_EXPORT_VAR int tracing;
#ifndef IN_PROCESS_AGENT
#endif
-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);
static int traceframe_read_tsv (int num, LONGEST *val);
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);
#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
#endif
static void
-init_trace_buffer (unsigned char *buf, int bufsize)
+init_trace_buffer (LONGEST bufsize)
{
- trace_buffer_lo = buf;
- trace_buffer_hi = trace_buffer_lo + bufsize;
+ size_t alloc_size;
+
+ trace_buffer_size = bufsize;
+
+ /* Make sure to internally allocate at least space for the EOB
+ marker. */
+ alloc_size = (bufsize < TRACEFRAME_EOB_MARKER_SIZE
+ ? TRACEFRAME_EOB_MARKER_SIZE : bufsize);
+ trace_buffer_lo = (unsigned char *) xrealloc (trace_buffer_lo, alloc_size);
+
+ trace_buffer_hi = trace_buffer_lo + trace_buffer_size;
clear_trace_buffer ();
}
#ifdef IN_PROCESS_AGENT
-IP_AGENT_EXPORT void ATTR_USED ATTR_NOINLINE
+IP_AGENT_EXPORT_FUNC void
about_to_request_buffer_space (void)
{
/* GDBserver places breakpoint here while it goes about to flush
(long) amt, (long) sizeof (struct traceframe));
/* Account for the EOB marker. */
- amt += sizeof (struct traceframe);
+ amt += TRACEFRAME_EOB_MARKER_SIZE;
#ifdef IN_PROCESS_AGENT
again:
{
struct tracepoint *tpoint, **tp_next;
- tpoint = xmalloc (sizeof (struct tracepoint));
+ tpoint = XNEW (struct tracepoint);
tpoint->number = num;
tpoint->address = addr;
tpoint->numactions = 0;
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
#endif
-static char *
-save_string (const char *str, size_t len)
-{
- char *s;
-
- s = xmalloc (len + 1);
- memcpy (s, str, len);
- s[len] = '\0';
-
- return s;
-}
-
/* Append another action to perform when the tracepoint triggers. */
static void
{
case 'M':
{
- struct collect_memory_action *maction;
+ struct collect_memory_action *maction =
+ XNEW (struct collect_memory_action);
ULONGEST basereg;
int is_neg;
- maction = xmalloc (sizeof *maction);
maction->base.type = *act;
+ maction->base.ops = &m_tracepoint_action_ops;
action = &maction->base;
++act;
}
case 'R':
{
- struct collect_registers_action *raction;
+ struct collect_registers_action *raction =
+ XNEW (struct collect_registers_action);
- raction = xmalloc (sizeof *raction);
raction->base.type = *act;
+ raction->base.ops = &r_tracepoint_action_ops;
action = &raction->base;
trace_debug ("Want to collect registers");
}
case 'L':
{
- struct collect_static_trace_data_action *raction;
+ struct collect_static_trace_data_action *raction =
+ XNEW (struct collect_static_trace_data_action);
- 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");
break;
case 'X':
{
- struct eval_expr_action *xaction;
+ struct eval_expr_action *xaction = XNEW (struct eval_expr_action);
- xaction = xmalloc (sizeof (*xaction));
xaction->base.type = *act;
+ xaction->base.ops = &x_tracepoint_action_ops;
action = &xaction->base;
trace_debug ("Want to evaluate expression");
tpoint->num_step_actions++;
tpoint->step_actions
- = xrealloc (tpoint->step_actions,
- (sizeof (*tpoint->step_actions)
- * tpoint->num_step_actions));
+ = XRESIZEVEC (struct tracepoint_action *, tpoint->step_actions,
+ tpoint->num_step_actions);
tpoint->step_actions_str
- = xrealloc (tpoint->step_actions_str,
- (sizeof (*tpoint->step_actions_str)
- * tpoint->num_step_actions));
+ = XRESIZEVEC (char *, tpoint->step_actions_str,
+ tpoint->num_step_actions);
tpoint->step_actions[tpoint->num_step_actions - 1] = action;
tpoint->step_actions_str[tpoint->num_step_actions - 1]
- = save_string (act_start, act - act_start);
+ = savestring (act_start, act - act_start);
}
else
{
tpoint->numactions++;
tpoint->actions
- = xrealloc (tpoint->actions,
- sizeof (*tpoint->actions) * tpoint->numactions);
+ = XRESIZEVEC (struct tracepoint_action *, tpoint->actions,
+ tpoint->numactions);
tpoint->actions_str
- = xrealloc (tpoint->actions_str,
- sizeof (*tpoint->actions_str) * tpoint->numactions);
+ = XRESIZEVEC (char *, tpoint->actions_str, tpoint->numactions);
tpoint->actions[tpoint->numactions - 1] = action;
tpoint->actions_str[tpoint->numactions - 1]
- = save_string (act_start, act - act_start);
+ = savestring (act_start, act - act_start);
}
}
}
return tsv;
/* Create a new variable. */
- tsv = xmalloc (sizeof (struct trace_state_variable));
+ tsv = XNEW (struct trace_state_variable);
tsv->number = num;
tsv->initial_value = 0;
tsv->value = 0;
return tsv;
}
-IP_AGENT_EXPORT LONGEST
+IP_AGENT_EXPORT_FUNC LONGEST
get_trace_state_variable_value (int num)
{
struct trace_state_variable *tsv;
return tsv->value;
}
-IP_AGENT_EXPORT void
+IP_AGENT_EXPORT_FUNC void
set_trace_state_variable_value (int num, LONGEST val)
{
struct trace_state_variable *tsv;
{
struct traceframe *tframe;
- tframe = trace_buffer_alloc (sizeof (struct traceframe));
+ tframe
+ = (struct traceframe *) trace_buffer_alloc (sizeof (struct traceframe));
if (tframe == NULL)
return NULL;
/* Add a block to the traceframe currently being worked on. */
static unsigned char *
-add_traceframe_block (struct traceframe *tframe, int amt)
+add_traceframe_block (struct traceframe *tframe,
+ struct tracepoint *tpoint, int amt)
{
unsigned char *block;
if (!tframe)
return NULL;
- block = trace_buffer_alloc (amt);
+ block = (unsigned char *) trace_buffer_alloc (amt);
if (!block)
return NULL;
+ gdb_assert (tframe->tpnum == tpoint->number);
+
tframe->data_size += amt;
+ tpoint->traceframe_usage += amt;
return block;
}
{
struct trace_state_variable *tsv, *prev, *next;
+ /* Can't do this command without a pid attached. */
+ if (current_thread == NULL)
+ {
+ write_enn (packet);
+ return;
+ }
+
/* Make sure we don't try to read from a trace frame. */
current_traceframe = -1;
+ stop_tracing ();
+
trace_debug ("Initializing the trace");
clear_installed_tracepoints ();
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
struct tracepoint *prev_stpoint;
pause_all (1);
- cancel_breakpoints ();
prev_stpoint = NULL;
switch (tpoint->type)
{
case trap_tracepoint:
- delete_breakpoint (tpoint->handle);
+ {
+ struct breakpoint *bp
+ = (struct breakpoint *) tpoint->handle;
+
+ delete_breakpoint (bp);
+ }
break;
case fast_tracepoint:
- delete_fast_tracepoint_jump (tpoint->handle);
+ {
+ struct fast_tracepoint_jump *jump
+ = (struct fast_tracepoint_jump *) tpoint->handle;
+
+ delete_fast_tracepoint_jump (jump);
+ }
break;
case static_tracepoint:
if (prev_stpoint != NULL
}
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,
trailing hyphen in QTDP packet. */
if (tracing && !trail_hyphen)
{
+ struct tracepoint *tp = NULL;
+
/* Pause all threads temporarily while we patch tracepoints. */
pause_all (0);
/* 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;
saved = packet;
packet = strchr (packet, ':');
- srctype = xmalloc (packet - saved + 1);
+ srctype = (char *) xmalloc (packet - saved + 1);
memcpy (srctype, saved, packet - saved);
srctype[packet - saved] = '\0';
++packet;
++packet; /* skip a colon */
packet = unpack_varlen_hex (packet, &slen);
++packet; /* skip a colon */
- src = xmalloc (slen + 1);
- nbytes = unhexify (src, packet, strlen (packet) / 2);
+ src = (char *) xmalloc (slen + 1);
+ nbytes = hex2bin (packet, (gdb_byte *) src, strlen (packet) / 2);
src[nbytes] = '\0';
- newlast = xmalloc (sizeof (struct source_string));
+ newlast = XNEW (struct source_string);
newlast->type = srctype;
newlast->str = src;
newlast->next = NULL;
++packet; /* skip a colon */
nbytes = strlen (packet) / 2;
- varname = xmalloc (nbytes + 1);
- nbytes = unhexify (varname, packet, nbytes);
+ varname = (char *) xmalloc (nbytes + 1);
+ nbytes = hex2bin (packet, (gdb_byte *) varname, nbytes);
varname[nbytes] = '\0';
tsv = create_trace_state_variable (num, 1);
cmd_qtv (char *own_buf)
{
ULONGEST num;
- LONGEST val;
+ LONGEST val = 0;
int err;
char *packet = own_buf;
packet = unpack_varlen_hex (packet, &start);
++packet; /* skip a comma */
packet = unpack_varlen_hex (packet, &end);
- roreg = xmalloc (sizeof (struct readonly_region));
+
+ roreg = XNEW (struct readonly_region);
roreg->start = start;
roreg->end = end;
roreg->next = readonly_regions;
return 0;
}
-/* The maximum size of a jump pad entry. */
-static const int max_jump_pad_size = 0x100;
-
static CORE_ADDR gdb_jump_pad_head;
/* Return the address of the next free jump space. */
{
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer,
&gdb_jump_pad_head))
- fatal ("error extracting jump_pad_buffer");
+ {
+ internal_error (__FILE__, __LINE__,
+ "error extracting jump_pad_buffer");
+ }
}
return gdb_jump_pad_head;
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer,
&trampoline_buffer_tail))
{
- fatal ("error extracting trampoline_buffer");
- return 0;
+ internal_error (__FILE__, __LINE__,
+ "error extracting trampoline_buffer");
}
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
&trampoline_buffer_head))
{
- fatal ("error extracting trampoline_buffer_end");
- return 0;
+ internal_error (__FILE__, __LINE__,
+ "error extracting trampoline_buffer_end");
}
}
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
&trampoline_end))
{
- fatal ("error extracting trampoline_buffer_end");
- return 0;
+ internal_error (__FILE__, __LINE__,
+ "error extracting trampoline_buffer_end");
}
if (buf)
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_error,
&errbuf))
{
- fatal ("error extracting errbuf");
- return 0;
+ internal_error (__FILE__, __LINE__,
+ "error extracting errbuf");
}
read_inferior_memory (errbuf, (unsigned char *) buf, 100);
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)
{
}
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.",
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.");
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;
- }
}
}
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");
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;
*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. */
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
/* 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");
+ {
+ internal_error (__FILE__, __LINE__,
+ "Error setting tracing variable in lib");
+ }
if (write_inferior_data_pointer (ipa_sym_addrs.addr_stopping_tracepoint,
0))
- fatal ("Error clearing stopping_tracepoint variable in lib");
+ {
+ internal_error (__FILE__, __LINE__,
+ "Error clearing stopping_tracepoint variable"
+ " in lib");
+ }
if (write_inferior_integer (ipa_sym_addrs.addr_trace_buffer_is_full, 0))
- fatal ("Error clearing trace_buffer_is_full variable in lib");
+ {
+ internal_error (__FILE__, __LINE__,
+ "Error clearing trace_buffer_is_full variable"
+ " in lib");
+ }
stop_tracing_bkpt = set_breakpoint_at (ipa_sym_addrs.addr_stop_tracing,
stop_tracing_handler);
We can't now, since we may be getting here due to the inferior
agent calling us. */
pause_all (1);
- /* Since we're removing breakpoints, cancel breakpoint hits,
- possibly related to the breakpoints we're about to delete. */
- cancel_breakpoints ();
/* 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");
+ {
+ internal_error (__FILE__, __LINE__,
+ "Error clearing tracing variable in lib");
+ }
}
tracing_stop_time = get_timestamp ();
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";
/* 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,
packet += strlen ("QTFrame:");
- if (strncmp (packet, "pc:", strlen ("pc:")) == 0)
+ if (startswith (packet, "pc:"))
{
packet += strlen ("pc:");
unpack_varlen_hex (packet, &pc);
trace_debug ("Want to find next traceframe at pc=0x%s", paddress (pc));
tframe = find_next_traceframe_in_range (pc, pc, 1, &tfnum);
}
- else if (strncmp (packet, "range:", strlen ("range:")) == 0)
+ else if (startswith (packet, "range:"))
{
packet += strlen ("range:");
packet = unpack_varlen_hex (packet, &lo);
paddress (lo), paddress (hi));
tframe = find_next_traceframe_in_range (lo, hi, 1, &tfnum);
}
- else if (strncmp (packet, "outside:", strlen ("outside:")) == 0)
+ else if (startswith (packet, "outside:"))
{
packet += strlen ("outside:");
packet = unpack_varlen_hex (packet, &lo);
paddress (lo), paddress (hi));
tframe = find_next_traceframe_in_range (lo, hi, 0, &tfnum);
}
- else if (strncmp (packet, "tdp:", strlen ("tdp:")) == 0)
+ else if (startswith (packet, "tdp:"))
{
packet += strlen ("tdp:");
unpack_varlen_hex (packet, &num);
cmd_qtstatus (char *packet)
{
char *stop_reason_rsp = NULL;
- char *buf1, *buf2, *buf3, *str;
+ char *buf1, *buf2, *buf3;
+ const char *str;
int slen;
/* Translate the plain text of the notes back into hex for
str = (tracing_user_name ? tracing_user_name : "");
slen = strlen (str);
buf1 = (char *) alloca (slen * 2 + 1);
- hexify (buf1, str, slen);
+ bin2hex ((gdb_byte *) str, buf1, slen);
str = (tracing_notes ? tracing_notes : "");
slen = strlen (str);
buf2 = (char *) alloca (slen * 2 + 1);
- hexify (buf2, str, slen);
+ bin2hex ((gdb_byte *) str, buf2, slen);
str = (tracing_stop_note ? tracing_stop_note : "");
slen = strlen (str);
buf3 = (char *) alloca (slen * 2 + 1);
- hexify (buf3, str, slen);
+ bin2hex ((gdb_byte *) str, buf3, slen);
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);
/* The user visible error string in terror needs to be hex encoded.
We leave it as plain string in `tracing_stop_reason' to ease
debugging. */
- if (strncmp (stop_reason_rsp, "terror:", strlen ("terror:")) == 0)
+ if (startswith (stop_reason_rsp, "terror:"))
{
const char *result_name;
int hexstr_len;
result_name = stop_reason_rsp + strlen ("terror:");
hexstr_len = strlen (result_name) * 2;
- p = stop_reason_rsp = alloca (strlen ("terror:") + hexstr_len + 1);
+ p = stop_reason_rsp
+ = (char *) alloca (strlen ("terror:") + hexstr_len + 1);
strcpy (p, "terror:");
p += strlen (p);
- convert_int_to_ascii ((gdb_byte *) result_name, p, strlen (result_name));
+ bin2hex ((gdb_byte *) result_name, p, strlen (result_name));
}
/* If this was a forced stop, include any stop note that was supplied. */
if (strcmp (stop_reason_rsp, "tstop") == 0)
{
- stop_reason_rsp = alloca (strlen ("tstop:") + strlen (buf3) + 1);
+ stop_reason_rsp = (char *) alloca (strlen ("tstop:") + strlen (buf3) + 1);
strcpy (stop_reason_rsp, "tstop:");
strcat (stop_reason_rsp, buf3);
}
"circular:%d;"
"disconn:%d;"
"starttime:%s;stoptime:%s;"
- "username:%s:;notes:%s:",
+ "username:%s;notes:%s:",
tracing ? 1 : 0,
stop_reason_rsp, tracing_stop_tpnum,
traceframe_count, traceframes_created,
free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
circular_trace_buffer,
disconnected_tracing,
- plongest (tracing_start_time), plongest (tracing_stop_time),
+ phex_nz (tracing_start_time, sizeof (tracing_start_time)),
+ phex_nz (tracing_stop_time, sizeof (tracing_stop_time)),
buf1, buf2);
}
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. */
static struct tracepoint *cur_tpoint;
-static int cur_action;
-static int cur_step_action;
+static unsigned int cur_action;
+static unsigned int cur_step_action;
static struct source_string *cur_source_string;
static struct trace_state_variable *cur_tsv;
{
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);
int len;
len = strlen (src->str);
- buf = alloca (len * 2 + 1);
- convert_int_to_ascii ((gdb_byte *) src->str, buf, len);
+ buf = (char *) alloca (len * 2 + 1);
+ bin2hex ((gdb_byte *) src->str, buf, len);
sprintf (packet, "Z%x:%s:%s:%x:%x:%s",
tpoint->number, paddress (tpoint->address),
trace_debug ("Returning first tracepoint definition piece");
cur_tpoint = tracepoints;
- cur_action = cur_step_action = -1;
+ cur_action = cur_step_action = 0;
cur_source_string = NULL;
if (cur_tpoint)
GDB misbehavior. */
strcpy (packet, "l");
}
- else if (cur_action < cur_tpoint->numactions - 1)
+ else if (cur_action < cur_tpoint->numactions)
{
- ++cur_action;
response_action (packet, cur_tpoint,
cur_tpoint->actions_str[cur_action], 0);
+ ++cur_action;
}
- else if (cur_step_action < cur_tpoint->num_step_actions - 1)
+ else if (cur_step_action < cur_tpoint->num_step_actions)
{
- ++cur_step_action;
response_action (packet, cur_tpoint,
cur_tpoint->step_actions_str[cur_step_action], 1);
+ ++cur_step_action;
}
else if ((cur_source_string
? cur_source_string->next
else
{
cur_tpoint = cur_tpoint->next;
- cur_action = cur_step_action = -1;
+ cur_action = cur_step_action = 0;
cur_source_string = NULL;
if (cur_tpoint)
response_tracepoint (packet, cur_tpoint);
if (tsv->name)
{
namelen = strlen (tsv->name);
- buf = alloca (namelen * 2 + 1);
- convert_int_to_ascii ((gdb_byte *) tsv->name, buf, namelen);
+ buf = (char *) alloca (namelen * 2 + 1);
+ bin2hex ((gdb_byte *) tsv->name, buf, namelen);
}
sprintf (packet, "%x:%s:%x:%s", tsv->number, phex_nz (tsv->initial_value, 0),
static void
cmd_qtsv (char *packet)
{
- trace_debug ("Returning first trace state variable definition");
+ trace_debug ("Returning additional trace state variable definition");
- if (!cur_tpoint)
- {
- /* This case would normally never occur, but be prepared for
- GDB misbehavior. */
- strcpy (packet, "l");
- }
- else if (cur_tsv)
+ if (cur_tsv)
{
cur_tsv = cur_tsv->next;
if (cur_tsv)
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. */
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.
cmd_qtstmat (char *packet)
{
if (!maybe_write_ipa_ust_not_loaded (packet))
- run_inferior_command (packet);
+ run_inferior_command (packet, strlen (packet) + 1);
+}
+
+/* Helper for gdb_agent_about_to_close.
+ Return non-zero if thread ENTRY is in the same process in DATA. */
+
+static int
+same_process_p (struct inferior_list_entry *entry, void *data)
+{
+ int *pid = (int *) data;
+
+ return ptid_get_pid (entry->id) == *pid;
+}
+
+/* Sent the agent a command to close it. */
+
+void
+gdb_agent_about_to_close (int pid)
+{
+ char buf[IPA_CMD_BUF_SIZE];
+
+ if (!maybe_write_ipa_not_loaded (buf))
+ {
+ struct thread_info *saved_thread;
+
+ saved_thread = current_thread;
+
+ /* Find any thread which belongs to process PID. */
+ current_thread = (struct thread_info *)
+ find_inferior (&all_threads, same_process_p, &pid);
+
+ strcpy (buf, "close");
+
+ run_inferior_command (buf, strlen (buf) + 1);
+
+ current_thread = saved_thread;
+ }
}
/* Return the minimum instruction size needed for fast tracepoints as a
static void
cmd_qtminftpilen (char *packet)
{
- if (current_inferior == NULL)
+ if (current_thread == NULL)
{
/* Indicate that the minimum length is currently unknown. */
strcpy (packet, "0");
unpack_varlen_hex (packet, &num);
trace_debug ("Want to get trace buffer, %d bytes at offset 0x%s",
- (int) num, pulongest (offset));
+ (int) num, phex_nz (offset, 0));
tot = (trace_buffer_hi - trace_buffer_lo) - free_space ();
if (num >= (PBUFSIZ - 16) / 2 )
num = (PBUFSIZ - 16) / 2;
- convert_int_to_ascii (tbp, own_buf, num);
- own_buf[num] = '\0';
+ bin2hex (tbp, own_buf, num);
}
static void
write_ok (own_buf);
}
+static void
+cmd_bigqtbuffer_size (char *own_buf)
+{
+ ULONGEST val;
+ LONGEST sval;
+ char *packet = own_buf;
+
+ /* Can't change the size during a tracing run. */
+ if (tracing)
+ {
+ write_enn (own_buf);
+ return;
+ }
+
+ packet += strlen ("QTBuffer:size:");
+
+ /* -1 is sent as literal "-1". */
+ if (strcmp (packet, "-1") == 0)
+ sval = DEFAULT_TRACE_BUFFER_SIZE;
+ else
+ {
+ unpack_varlen_hex (packet, &val);
+ sval = (LONGEST) val;
+ }
+
+ init_trace_buffer (sval);
+ trace_debug ("Trace buffer is now %s bytes",
+ plongest (trace_buffer_size));
+ write_ok (own_buf);
+}
+
static void
cmd_qtnotes (char *own_buf)
{
while (*packet)
{
- if (strncmp ("user:", packet, strlen ("user:")) == 0)
+ if (startswith (packet, "user:"))
{
packet += strlen ("user:");
saved = packet;
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
- user = xmalloc (nbytes + 1);
- nbytes = unhexify (user, saved, nbytes);
+ user = (char *) xmalloc (nbytes + 1);
+ nbytes = hex2bin (saved, (gdb_byte *) user, nbytes);
user[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("User is '%s'", user);
+ xfree (tracing_user_name);
tracing_user_name = user;
}
- else if (strncmp ("notes:", packet, strlen ("notes:")) == 0)
+ else if (startswith (packet, "notes:"))
{
packet += strlen ("notes:");
saved = packet;
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
- notes = xmalloc (nbytes + 1);
- nbytes = unhexify (notes, saved, nbytes);
+ notes = (char *) xmalloc (nbytes + 1);
+ nbytes = hex2bin (saved, (gdb_byte *) notes, nbytes);
notes[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("Notes is '%s'", notes);
+ xfree (tracing_notes);
tracing_notes = notes;
}
- else if (strncmp ("tstop:", packet, strlen ("tstop:")) == 0)
+ else if (startswith (packet, "tstop:"))
{
packet += strlen ("tstop:");
saved = packet;
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
- stopnote = xmalloc (nbytes + 1);
- nbytes = unhexify (stopnote, saved, nbytes);
+ stopnote = (char *) xmalloc (nbytes + 1);
+ nbytes = hex2bin (saved, (gdb_byte *) stopnote, nbytes);
stopnote[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("tstop note is '%s'", stopnote);
+ xfree (tracing_stop_note);
tracing_stop_note = stopnote;
}
else
cmd_qtinit (packet);
return 1;
}
- else if (strncmp ("QTDP:", packet, strlen ("QTDP:")) == 0)
+ else if (startswith (packet, "QTDP:"))
{
cmd_qtdp (packet);
return 1;
}
- else if (strncmp ("QTDPsrc:", packet, strlen ("QTDPsrc:")) == 0)
+ else if (startswith (packet, "QTDPsrc:"))
{
cmd_qtdpsrc (packet);
return 1;
}
- else if (strncmp ("QTEnable:", packet, strlen ("QTEnable:")) == 0)
+ else if (startswith (packet, "QTEnable:"))
{
cmd_qtenable_disable (packet, 1);
return 1;
}
- else if (strncmp ("QTDisable:", packet, strlen ("QTDisable:")) == 0)
+ else if (startswith (packet, "QTDisable:"))
{
cmd_qtenable_disable (packet, 0);
return 1;
}
- else if (strncmp ("QTDV:", packet, strlen ("QTDV:")) == 0)
+ else if (startswith (packet, "QTDV:"))
{
cmd_qtdv (packet);
return 1;
}
- else if (strncmp ("QTro:", packet, strlen ("QTro:")) == 0)
+ else if (startswith (packet, "QTro:"))
{
cmd_qtro (packet);
return 1;
cmd_qtstop (packet);
return 1;
}
- else if (strncmp ("QTDisconnected:", packet,
- strlen ("QTDisconnected:")) == 0)
+ else if (startswith (packet, "QTDisconnected:"))
{
cmd_qtdisconnected (packet);
return 1;
}
- else if (strncmp ("QTFrame:", packet, strlen ("QTFrame:")) == 0)
+ else if (startswith (packet, "QTFrame:"))
{
cmd_qtframe (packet);
return 1;
}
- else if (strncmp ("QTBuffer:circular:", packet, strlen ("QTBuffer:circular:")) == 0)
+ else if (startswith (packet, "QTBuffer:circular:"))
{
cmd_bigqtbuffer_circular (packet);
return 1;
}
- else if (strncmp ("QTNotes:", packet, strlen ("QTNotes:")) == 0)
+ else if (startswith (packet, "QTBuffer:size:"))
+ {
+ cmd_bigqtbuffer_size (packet);
+ return 1;
+ }
+ else if (startswith (packet, "QTNotes:"))
{
cmd_qtnotes (packet);
return 1;
cmd_qtstatus (packet);
return 1;
}
- else if (strncmp ("qTP:", packet, strlen ("qTP:")) == 0)
+ else if (startswith (packet, "qTP:"))
{
cmd_qtp (packet);
return 1;
cmd_qtsv (packet);
return 1;
}
- else if (strncmp ("qTV:", packet, strlen ("qTV:")) == 0)
+ else if (startswith (packet, "qTV:"))
{
cmd_qtv (packet);
return 1;
}
- else if (strncmp ("qTBuffer:", packet, strlen ("qTBuffer:")) == 0)
+ else if (startswith (packet, "qTBuffer:"))
{
cmd_qtbuffer (packet);
return 1;
cmd_qtsstm (packet);
return 1;
}
- else if (strncmp ("qTSTMat:", packet, strlen ("qTSTMat:")) == 0)
+ else if (startswith (packet, "qTSTMat:"))
{
cmd_qtstmat (packet);
return 1;
add_while_stepping_state (struct thread_info *tinfo,
int tp_number, CORE_ADDR tp_address)
{
- struct wstep_state *wstep;
+ struct wstep_state *wstep = XNEW (struct wstep_state);
- wstep = xmalloc (sizeof (*wstep));
wstep->next = tinfo->while_stepping;
wstep->tp_number = tp_number;
/* 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
/* 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 ();
&& 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);
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);
#endif
+#ifdef IN_PROCESS_AGENT
+/* The target description used by the IPA. Given that the IPA library
+ is built for a specific architecture that is loaded into the
+ inferior, there only needs to be one such description per
+ build. */
+const struct target_desc *ipa_tdesc;
+#endif
+
static struct regcache *
get_context_regcache (struct tracepoint_hit_ctx *ctx)
{
if (!fctx->regcache_initted)
{
fctx->regcache_initted = 1;
- init_register_cache (&fctx->regcache, fctx->regspace);
+ init_register_cache (&fctx->regcache, ipa_tdesc, fctx->regspace);
supply_regblock (&fctx->regcache, NULL);
supply_fast_tracepoint_registers (&fctx->regcache, fctx->regs);
}
if (!sctx->regcache_initted)
{
sctx->regcache_initted = 1;
- init_register_cache (&sctx->regcache, sctx->regspace);
+ init_register_cache (&sctx->regcache, ipa_tdesc, sctx->regspace);
supply_regblock (&sctx->regcache, NULL);
/* Pass down the tracepoint address, because REGS doesn't
include the PC, but we know what it must have been. */
case 'M':
{
struct collect_memory_action *maction;
+ struct eval_agent_expr_context ax_ctx;
maction = (struct collect_memory_action *) taction;
+ ax_ctx.regcache = NULL;
+ ax_ctx.tframe = tframe;
+ ax_ctx.tpoint = tpoint;
trace_debug ("Want to collect %s bytes at 0x%s (basereg %d)",
pulongest (maction->len),
paddress (maction->addr), maction->basereg);
/* (should use basereg) */
- agent_mem_read (tframe, NULL,
- (CORE_ADDR) maction->addr, maction->len);
+ agent_mem_read (&ax_ctx, NULL, (CORE_ADDR) maction->addr,
+ maction->len);
break;
}
case 'R':
unsigned char *regspace;
struct regcache tregcache;
struct regcache *context_regcache;
-
+ int regcache_size;
trace_debug ("Want to collect registers");
+ context_regcache = get_context_regcache (ctx);
+ regcache_size = register_cache_size (context_regcache->tdesc);
+
/* Collect all registers for now. */
- regspace = add_traceframe_block (tframe,
- 1 + register_cache_size ());
+ regspace = add_traceframe_block (tframe, tpoint, 1 + regcache_size);
if (regspace == NULL)
{
trace_debug ("Trace buffer block allocation failed, skipping");
/* Identify a register block. */
*regspace = 'R';
- context_regcache = get_context_regcache (ctx);
-
/* Wrap the regblock in a register cache (in the stack, we
don't want to malloc here). */
- init_register_cache (&tregcache, regspace + 1);
+ init_register_cache (&tregcache, context_regcache->tdesc,
+ regspace + 1);
/* Copy the register data to the regblock. */
regcache_cpy (&tregcache, context_regcache);
case 'X':
{
struct eval_expr_action *eaction;
+ struct eval_agent_expr_context ax_ctx;
eaction = (struct eval_expr_action *) taction;
+ ax_ctx.regcache = get_context_regcache (ctx);
+ ax_ctx.tframe = tframe;
+ ax_ctx.tpoint = tpoint;
trace_debug ("Want to evaluate expression");
- err = eval_tracepoint_agent_expr (ctx, tframe, eaction->expr, NULL);
+ err = gdb_eval_agent_expr (&ax_ctx, eaction->expr, NULL);
if (err != expr_eval_no_error)
{
used. */
#ifdef IN_PROCESS_AGENT
if (tpoint->compiled_cond)
- err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (ctx, &value);
+ {
+ struct fast_tracepoint_ctx *fctx = (struct fast_tracepoint_ctx *) ctx;
+ err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (fctx->regs, &value);
+ }
else
#endif
- err = eval_tracepoint_agent_expr (ctx, NULL, tpoint->cond, &value);
+ {
+ struct eval_agent_expr_context ax_ctx;
+
+ ax_ctx.regcache = get_context_regcache (ctx);
+ ax_ctx.tframe = NULL;
+ ax_ctx.tpoint = tpoint;
+ err = gdb_eval_agent_expr (&ax_ctx, tpoint->cond, &value);
+ }
if (err != expr_eval_no_error)
{
record_tracepoint_error (tpoint, "condition", err);
return (value ? 1 : 0);
}
-/* Evaluates a tracepoint agent expression with context CTX,
- traceframe TFRAME, agent expression AEXPR and store the
- result in RSLT. */
-
-static enum eval_result_type
-eval_tracepoint_agent_expr (struct tracepoint_hit_ctx *ctx,
- struct traceframe *tframe,
- struct agent_expr *aexpr,
- ULONGEST *rslt)
-{
- struct regcache *regcache;
- regcache = get_context_regcache (ctx);
-
- return gdb_eval_agent_expr (regcache, tframe, aexpr, rslt);
-}
-
/* Do memory copies for bytecodes. */
/* Do the recording of memory blocks for actions and bytecodes. */
int
-agent_mem_read (struct traceframe *tframe,
+agent_mem_read (struct eval_agent_expr_context *ctx,
unsigned char *to, CORE_ADDR from, ULONGEST len)
{
unsigned char *mspace;
blocklen = (remaining > 65535 ? 65535 : remaining);
sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen;
- mspace = add_traceframe_block (tframe, sp);
+ mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp);
if (mspace == NULL)
return 1;
/* Identify block as a memory block. */
}
int
-agent_mem_read_string (struct traceframe *tframe,
+agent_mem_read_string (struct eval_agent_expr_context *ctx,
unsigned char *to, CORE_ADDR from, ULONGEST len)
{
unsigned char *buf, *mspace;
}
}
sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen;
- mspace = add_traceframe_block (tframe, sp);
+ mspace = add_traceframe_block (ctx->tframe, ctx->tpoint, sp);
if (mspace == NULL)
{
xfree (buf);
/* Record the value of a trace state variable. */
int
-agent_tsv_read (struct traceframe *tframe, int n)
+agent_tsv_read (struct eval_agent_expr_context *ctx, int n)
{
unsigned char *vspace;
LONGEST val;
- vspace = add_traceframe_block (tframe,
+ vspace = add_traceframe_block (ctx->tframe, ctx->tpoint,
1 + sizeof (n) + sizeof (LONGEST));
if (vspace == NULL)
return 1;
static int
match_blocktype (char blocktype, unsigned char *dataptr, void *data)
{
- char *wantedp = data;
+ char *wantedp = (char *) data;
if (*wantedp == blocktype)
return 1;
{
case 'R':
/* Skip over the registers block. */
- dataptr += register_cache_size ();
+ dataptr += current_target_desc ()->registers_size;
break;
case 'M':
/* Skip over the memory block. */
{
struct regcache regcache;
unsigned char *dataptr;
+ const struct target_desc *tdesc = current_target_desc ();
dataptr = traceframe_find_regblock (tframe, -1);
if (dataptr == NULL)
return 0;
- init_register_cache (®cache, dataptr);
+ init_register_cache (®cache, tdesc, dataptr);
return regcache_read_pc (®cache);
}
unsigned char *database, *dataptr;
unsigned int datasize;
int vnum;
+ int found = 0;
trace_debug ("traceframe_read_tsv");
datasize = tframe->data_size;
database = dataptr = &tframe->data[0];
- /* Iterate through a traceframe's blocks, looking for the tsv. */
+ /* Iterate through a traceframe's blocks, looking for the last
+ matched tsv. */
while ((dataptr = traceframe_find_block_type (dataptr,
datasize
- (dataptr - database),
if (tsvnum == vnum)
{
memcpy (val, dataptr, sizeof (*val));
- return 0;
+ found = 1;
}
/* Skip over this block. */
dataptr += sizeof (LONGEST);
}
- trace_debug ("traceframe %d has no data for variable %d",
- tfnum, tsvnum);
- return 1;
+ if (!found)
+ trace_debug ("traceframe %d has no data for variable %d",
+ tfnum, tsvnum);
+ return !found;
}
/* Read a requested block of static tracepoint data from a trace
static int
build_traceframe_info_xml (char blocktype, unsigned char *dataptr, void *data)
{
- struct buffer *buffer = data;
+ struct buffer *buffer = (struct buffer *) data;
switch (blocktype)
{
break;
}
case 'V':
+ {
+ int vnum;
+
+ memcpy (&vnum, dataptr, sizeof (vnum));
+ buffer_xml_printf (buffer, "<tvar id=\"%d\"/>\n", vnum);
+ break;
+ }
case 'R':
case 'S':
{
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer,
&ipa_gdb_jump_pad_buffer))
- fatal ("error extracting `gdb_jump_pad_buffer'");
+ {
+ internal_error (__FILE__, __LINE__,
+ "error extracting `gdb_jump_pad_buffer'");
+ }
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_jump_pad_buffer_end,
&ipa_gdb_jump_pad_buffer_end))
- fatal ("error extracting `gdb_jump_pad_buffer_end'");
+ {
+ internal_error (__FILE__, __LINE__,
+ "error extracting `gdb_jump_pad_buffer_end'");
+ }
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer,
&ipa_gdb_trampoline_buffer))
- fatal ("error extracting `gdb_trampoline_buffer'");
+ {
+ internal_error (__FILE__, __LINE__,
+ "error extracting `gdb_trampoline_buffer'");
+ }
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end,
&ipa_gdb_trampoline_buffer_end))
- fatal ("error extracting `gdb_trampoline_buffer_end'");
+ {
+ internal_error (__FILE__, __LINE__,
+ "error extracting `gdb_trampoline_buffer_end'");
+ }
if (ipa_gdb_jump_pad_buffer <= stop_pc
&& stop_pc < ipa_gdb_jump_pad_buffer_end)
NULL if it isn't locked. Note that this lock *must* be set while
executing any *function other than the jump pad. See
fast_tracepoint_collecting. */
-static collecting_t * ATTR_USED collecting;
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR collecting_t *collecting;
+EXTERN_C_POP
/* This routine, called from the jump pad (in asm) is designed to be
called from the jump pads of fast tracepoints, thus it is on the
critical path. */
-IP_AGENT_EXPORT void ATTR_USED
+IP_AGENT_EXPORT_FUNC void
gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
{
struct fast_tracepoint_ctx ctx;
ctx.regcache_initted = 0;
/* Wrap the regblock in a register cache (in the stack, we don't
want to malloc here). */
- ctx.regspace = alloca (register_cache_size ());
+ ctx.regspace = (unsigned char *) alloca (ipa_tdesc->registers_size);
if (ctx.regspace == NULL)
{
trace_debug ("Trace buffer block allocation failed, skipping");
/* We have the pointer *address*, need what it points to. */
if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_tp_heap_buffer,
&target_tp_heap))
- fatal ("could get target heap head pointer");
+ {
+ internal_error (__FILE__, __LINE__,
+ "couldn't get target heap head pointer");
+ }
}
ptr = target_tp_heap;
/* 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
- (actions_array + i * sizeof (sizeof (*tpoint->actions)),
+ (actions_array + i * sizeof (*tpoint->actions),
ipa_action);
}
}
}
+#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 (!startswith (buf, "OK"))
+ 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)
{
if (read_inferior_data_pointer (tp_prev->obj_addr_on_target
+ offsetof (struct tracepoint, next),
&tp_prev_target_next_addr))
- fatal ("error reading `tp_prev->next'");
+ {
+ internal_error (__FILE__, __LINE__,
+ "error reading `tp_prev->next'");
+ }
/* tpoint->next = tp_prev->next */
write_inferior_data_ptr (tpoint->obj_addr_on_target
}
-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)
{
name_addr);
}
- if (tsv->getter != NULL)
- {
- fatal ("what to do with these?");
- }
+ gdb_assert (tsv->getter == NULL);
}
if (prev_ptr != 0)
error ("Uploading: couldn't read traceframe at %s\n", paddress (tf));
if (ipa_tframe.tpnum == 0)
- fatal ("Uploading: No (more) fast traceframes, but "
- "ipa_traceframe_count == %u??\n",
- ipa_traceframe_write_count - ipa_traceframe_read_count);
+ {
+ internal_error (__FILE__, __LINE__,
+ "Uploading: No (more) fast traceframes, but"
+ " ipa_traceframe_count == %u??\n",
+ ipa_traceframe_write_count
+ - ipa_traceframe_read_count);
+ }
/* Note that this will be incorrect for multi-location
tracepoints... */
{
/* Copy the whole set of blocks in one go for now. FIXME:
split this in smaller blocks. */
- block = add_traceframe_block (tframe, ipa_tframe.data_size);
+ block = add_traceframe_block (tframe, tpoint,
+ ipa_tframe.data_size);
if (block != NULL)
{
if (read_inferior_memory (tf
trace_debug ("Done uploading traceframes [%d]\n", curr_tbctrl_idx);
pause_all (1);
- cancel_breakpoints ();
delete_breakpoint (about_to_request_buffer_space_bkpt);
about_to_request_buffer_space_bkpt = NULL;
#ifdef IN_PROCESS_AGENT
-IP_AGENT_EXPORT int ust_loaded;
-IP_AGENT_EXPORT char cmd_buf[CMD_BUF_SIZE];
+IP_AGENT_EXPORT_VAR int ust_loaded;
+IP_AGENT_EXPORT_VAR char cmd_buf[IPA_CMD_BUF_SIZE];
#ifdef HAVE_UST
/* Wrap the regblock in a register cache (in the stack, we don't
want to malloc here). */
- ctx.regspace = alloca (register_cache_size ());
+ ctx.regspace = alloca (ipa_tdesc->registers_size);
if (ctx.regspace == NULL)
{
trace_debug ("Trace buffer block allocation failed, skipping");
trace_debug ("Want to collect ust data");
/* 'S' + size + string */
- bufspace = add_traceframe_block (tframe,
+ bufspace = add_traceframe_block (tframe, umd->tpoint,
1 + sizeof (blocklen) + size + 1);
if (bufspace == NULL)
{
#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
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;
+ int pid = ptid_get_pid (current_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);
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
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR int helper_thread_id;
+EXTERN_C_POP
static int
init_named_socket (const char *name)
return fd;
}
+static char agent_socket_name[UNIX_PATH_MAX];
+
static int
-gdb_ust_socket_init (void)
+gdb_agent_socket_init (void)
{
int result, fd;
- char name[UNIX_PATH_MAX];
- result = xsnprintf (name, UNIX_PATH_MAX, "%s/gdb_ust%d",
+ result = xsnprintf (agent_socket_name, UNIX_PATH_MAX, "%s/gdb_ust%d",
SOCK_DIR, getpid ());
if (result >= UNIX_PATH_MAX)
{
return -1;
}
- fd = init_named_socket (name);
+ fd = init_named_socket (agent_socket_name);
if (fd < 0)
warning ("Error initializing named socket (%s) for communication with the "
"ust helper thread. Check that directory exists and that it "
- "is writable.", name);
+ "is writable.", agent_socket_name);
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;
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);
+ bin2hex ((gdb_byte *) str, hexstr, len);
+ return hexstr;
+}
+
/* Compose packet that is the response to the qTsSTM/qTfSTM/qTSTMat
packets. */
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>
+static void
+gdb_agent_remove_socket (void)
+{
+ unlink (agent_socket_name);
+}
+
+/* Helper thread of agent. */
+
static void *
-gdb_ust_thread (void *arg)
+gdb_agent_helper_thread (void *arg)
{
int listen_fd;
+ atexit (gdb_agent_remove_socket);
+
while (1)
{
- listen_fd = gdb_ust_socket_init ();
+ listen_fd = gdb_agent_socket_init ();
if (helper_thread_id == 0)
helper_thread_id = syscall (SYS_gettid);
int fd;
char buf[1];
int ret;
+ int stop_loop = 0;
tmp = sizeof (sockaddr);
do
{
- fd = accept (listen_fd, &sockaddr, &tmp);
+ fd = accept (listen_fd, (struct sockaddr *) &sockaddr, &tmp);
}
/* It seems an ERESTARTSYS can escape out of accept. */
while (fd == -512 || (fd == -1 && errno == EINTR));
if (cmd_buf[0])
{
- if (strcmp ("qTfSTM", cmd_buf) == 0)
+ if (startswith (cmd_buf, "close"))
+ {
+ stop_loop = 1;
+ }
+#ifdef HAVE_UST
+ else if (strcmp ("qTfSTM", cmd_buf) == 0)
{
cmd_qtfstm (cmd_buf);
}
{
cmd_qtsstm (cmd_buf);
}
- else if (strncmp ("unprobe_marker_at:",
- cmd_buf,
- sizeof ("unprobe_marker_at:") - 1) == 0)
+ else if (startswith (cmd_buf, "unprobe_marker_at:"))
{
unprobe_marker_at (cmd_buf);
}
- else if (strncmp ("probe_marker_at:",
- cmd_buf,
- sizeof ("probe_marker_at:") - 1) == 0)
+ else if (startswith (cmd_buf, "probe_marker_at:"))
{
probe_marker_at (cmd_buf);
}
- else if (strncmp ("qTSTMat:",
- cmd_buf,
- sizeof ("qTSTMat:") - 1) == 0)
+ else if (startswith (cmd_buf, "qTSTMat:"))
{
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 */
}
/* Fix compiler's warning: ignoring return value of 'write'. */
ret = write (fd, buf, 1);
close (fd);
+
+ if (stop_loop)
+ {
+ close (listen_fd);
+ unlink (agent_socket_name);
+
+ /* Sleep endlessly to wait the whole inferior stops. This
+ thread can not exit because GDB or GDBserver may still need
+ 'current_thread' (representing this thread) to access
+ inferior memory. Otherwise, this thread exits earlier than
+ other threads, and 'current_thread' is set to NULL. */
+ while (1)
+ sleep (10);
+ }
}
}
}
#include <signal.h>
+#include <pthread.h>
+
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR int gdb_agent_capability = AGENT_CAPA_STATIC_TRACE;
+EXTERN_C_POP
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. */
sigfillset (&new_mask);
res = pthread_sigmask (SIG_SETMASK, &new_mask, &orig_mask);
if (res)
- fatal ("pthread_sigmask (1) failed: %s", strerror (res));
+ perror_with_name ("pthread_sigmask (1)");
res = pthread_create (&thread,
NULL,
- gdb_ust_thread,
+ gdb_agent_helper_thread,
NULL);
res = pthread_sigmask (SIG_SETMASK, &orig_mask, NULL);
if (res)
- fatal ("pthread_sigmask (2) failed: %s", strerror (res));
+ perror_with_name ("pthread_sigmask (2)");
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>
-IP_AGENT_EXPORT char *gdb_tp_heap_buffer;
-IP_AGENT_EXPORT char *gdb_jump_pad_buffer;
-IP_AGENT_EXPORT char *gdb_jump_pad_buffer_end;
-IP_AGENT_EXPORT char *gdb_trampoline_buffer;
-IP_AGENT_EXPORT char *gdb_trampoline_buffer_end;
-IP_AGENT_EXPORT char *gdb_trampoline_buffer_error;
+IP_AGENT_EXPORT_VAR char *gdb_tp_heap_buffer;
+IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer;
+IP_AGENT_EXPORT_VAR char *gdb_jump_pad_buffer_end;
+IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer;
+IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_end;
+IP_AGENT_EXPORT_VAR char *gdb_trampoline_buffer_error;
/* Record the result of getting buffer space for fast tracepoint
trampolines. Any error message is copied, since caller may not be
{
initialize_tracepoint ();
-#ifdef HAVE_UST
- gdb_ust_init ();
-#endif
+ gdb_agent_init ();
}
#endif /* IN_PROCESS_AGENT */
void
initialize_tracepoint (void)
{
- /* There currently no way to change the buffer size. */
- const int sizeOfBuffer = 5 * 1024 * 1024;
- unsigned char *buf = xmalloc (sizeOfBuffer);
- init_trace_buffer (buf, sizeOfBuffer);
+ /* Start with the default size. */
+ init_trace_buffer (DEFAULT_TRACE_BUFFER_SIZE);
/* Wire trace state variable 1 to be the timestamp. This will be
uploaded to GDB upon connection and become one of its trace state
pagesize = sysconf (_SC_PAGE_SIZE);
if (pagesize == -1)
- fatal ("sysconf");
+ perror_with_name ("sysconf");
- gdb_tp_heap_buffer = xmalloc (5 * 1024 * 1024);
+ gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
#define SCRATCH_BUFFER_NPAGES 20
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);
+ gdb_jump_pad_buffer
+ = (char *) 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;
}
if (addr == 0)
- fatal ("\
-initialize_tracepoint: mmap'ing jump pad buffer failed with %s",
- strerror (errno));
+ perror_with_name ("mmap");
gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + pagesize * SCRATCH_BUFFER_NPAGES;
}
buffer setup, but it can be mysterious, so create a channel to
report back on what went wrong, using a fixed size since we may
not be able to allocate space later when the problem occurs. */
- gdb_trampoline_buffer_error = xmalloc (IPA_BUFSIZ);
+ gdb_trampoline_buffer_error = (char *) xmalloc (IPA_BUFSIZ);
strcpy (gdb_trampoline_buffer_error, "No errors reported");