/* Tracepoint code for remote server for GDB.
- Copyright (C) 2009-2012 Free Software Foundation, Inc.
+ Copyright (C) 2009-2013 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 "gdbthread.h"
#include "agent.h"
#include <ctype.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
*/
-static void trace_vdebug (const char *, ...) ATTR_FORMAT (printf, 1, 2);
+static void trace_vdebug (const char *, ...) ATTRIBUTE_PRINTF (1, 2);
static void
trace_vdebug (const char *fmt, ...)
}
}
- agent_look_up_symbols ();
+ agent_look_up_symbols (NULL);
}
#endif
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. */
{
/* 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
-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);
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
maction = xmalloc (sizeof *maction);
maction->base.type = *act;
+ maction->base.ops = &m_tracepoint_action_ops;
action = &maction->base;
++act;
raction = xmalloc (sizeof *raction);
raction->base.type = *act;
+ raction->base.ops = &r_tracepoint_action_ops;
action = &raction->base;
trace_debug ("Want to collect registers");
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");
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[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
{
sizeof (*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);
}
}
}
/* 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 (!block)
return NULL;
+ gdb_assert (tframe->tpnum == tpoint->number);
+
tframe->data_size += amt;
+ tpoint->traceframe_usage += amt;
return block;
}
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
}
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;
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 (!agent_loaded_p ())
{
trace_debug ("Requested a %s tracepoint, but fast "
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");
/* Sync the fast tracepoints list in the inferior ftlib. */
if (agent_loaded_p ())
- {
- download_tracepoints ();
- download_trace_state_variables ();
- }
+ 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 (tpoint->type == fast_tracepoint)
{
- if (install_fast_tracepoint (tpoint, packet) == 0)
- prev_ftpoint = tpoint;
- }
- }
- else if (tpoint->type == static_tracepoint)
- {
- if (maybe_write_ipa_ust_not_loaded (packet))
- {
- 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
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";
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. */
{
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);
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);
+}
+
+/* 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 *save_inferior;
+ struct inferior_list_entry *inf = all_threads.head;
+
+ save_inferior = current_inferior;
+
+ /* Find a certain thread which belongs to process PID. */
+ while (inf != NULL)
+ {
+ if (ptid_get_pid (inf->id) == pid)
+ break;
+ inf = inf->next;
+ }
+
+ current_inferior = (struct thread_info *) inf;
+
+ strcpy (buf, "close");
+
+ run_inferior_command (buf, strlen (buf) + 1);
+
+ current_inferior = save_inferior;
+ }
}
/* Return the minimum instruction size needed for fast tracepoints as a
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 ();
num = (PBUFSIZ - 16) / 2;
convert_int_to_ascii (tbp, own_buf, num);
- own_buf[num] = '\0';
}
static void
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)
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)
stopnote[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("tstop note is '%s'", stopnote);
+ xfree (tracing_stop_note);
tracing_stop_note = stopnote;
}
else
&& 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);
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':
trace_debug ("Want to collect registers");
/* Collect all registers for now. */
- regspace = add_traceframe_block (tframe,
+ regspace = add_traceframe_block (tframe, tpoint,
1 + register_cache_size ());
if (regspace == NULL)
{
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)
{
err = ((condfn) (uintptr_t) (tpoint->compiled_cond)) (ctx, &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;
/* 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
}
}
+#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)
{
}
-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)
{
{
/* 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 ("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)
{
synchronization. */
static int
-run_inferior_command (char *cmd)
+run_inferior_command (char *cmd, int len)
{
int err = -1;
- int pid = ptid_get_pid (current_inferior->entry.id);
+ int pid = ptid_get_pid (current_ptid);
trace_debug ("run_inferior_command: running: %s", cmd);
pause_all (0);
uninsert_all_breakpoints ();
- err = agent_run_command (pid, (const char *) cmd);
+ err = agent_run_command (pid, (const char *) cmd, len);
reinsert_all_breakpoints ();
unpause_all (0);
return fd;
}
+static char agent_socket_name[UNIX_PATH_MAX];
+
static int
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;
}
#endif /* HAVE_UST */
#include <sys/syscall.h>
+#include <stdlib.h>
+
+static void
+gdb_agent_remove_socket (void)
+{
+ unlink (agent_socket_name);
+}
/* Helper thread of agent. */
{
int listen_fd;
+ atexit (gdb_agent_remove_socket);
+
while (1)
{
listen_fd = gdb_agent_socket_init ();
int fd;
char buf[1];
int ret;
+ int stop_loop = 0;
tmp = sizeof (sockaddr);
if (cmd_buf[0])
{
+ if (strncmp ("close", cmd_buf, 5) == 0)
+ {
+ stop_loop = 1;
+ }
#ifdef HAVE_UST
- if (strcmp ("qTfSTM", cmd_buf) == 0)
+ else if (strcmp ("qTfSTM", cmd_buf) == 0)
{
cmd_qtfstm (cmd_buf);
}
/* 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_inferior' (representing this thread) to access
+ inferior memory. Otherwise, this thread exits earlier than
+ other threads, and 'current_inferior' is set to NULL. */
+ while (1)
+ sleep (10);
+ }
}
}