#include "remote-fileio.h"
#include "gdb/fileio.h"
#include "gdb_stat.h"
+#include "xml-support.h"
#include "memory-map.h"
+#include "tracepoint.h"
+#include "ax.h"
+#include "ax-gdb.h"
+
+/* temp hacks for tracepoint encoding migration */
+static char *target_buf;
+static long target_buf_size;
+/*static*/ void
+encode_actions (struct breakpoint *t, char ***tdp_actions,
+ char ***stepping_actions);
+
/* The size to align memory write packets, when practical. The protocol
does not guarantee any alignment, and gdb will generate short
writes and unaligned writes, but even as a best-effort attempt this
static int fromhex (int a);
-static int hex2bin (const char *hex, gdb_byte *bin, int count);
+extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-static int bin2hex (const gdb_byte *bin, char *hex, int count);
+extern int bin2hex (const gdb_byte *bin, char *hex, int count);
static int putpkt_binary (char *buf, int cnt);
static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
static ptid_t read_ptid (char *buf, char **obuf);
+struct remote_state;
+static int remote_get_trace_status (struct trace_status *ts);
+
+static int remote_upload_tracepoints (struct uploaded_tp **utpp);
+
+static int remote_upload_trace_state_variables (struct uploaded_tsv **utsvp);
+
static void remote_query_supported (void);
static void remote_check_symbols (struct objfile *objfile);
/* True if the stub reports support for fast tracepoints. */
int fast_tracepoints;
+ /* True if the stub can continue running a trace while GDB is
+ disconnected. */
+ int disconnected_tracing;
+
/* Nonzero if the user has pressed Ctrl-C, but the target hasn't
responded to that. */
int ctrlc_pending_p;
+
+ /* GDBARCH associated with this target. */
+ struct gdbarch *gdbarch;
};
+/* Private data that we'll store in (struct thread_info)->private. */
+struct private_thread_info
+{
+ char *extra;
+ int core;
+};
+
+static void
+free_private_thread_info (struct private_thread_info *info)
+{
+ xfree (info->extra);
+ xfree (info);
+}
+
/* Returns true if the multi-process extensions are in effect. */
static int
remote_multi_process_p (struct remote_state *rs)
long remote_packet_size;
};
+long sizeof_pkt = 2000;
+
+/* Utility: generate error from an incoming stub packet. */
+static void
+trace_error (char *buf)
+{
+ if (*buf++ != 'E')
+ return; /* not an error msg */
+ switch (*buf)
+ {
+ case '1': /* malformed packet error */
+ if (*++buf == '0') /* general case: */
+ error (_("remote.c: error in outgoing packet."));
+ else
+ error (_("remote.c: error in outgoing packet at field #%ld."),
+ strtol (buf, NULL, 16));
+ case '2':
+ error (_("trace API error 0x%s."), ++buf);
+ default:
+ error (_("Target returns error code '%s'."), buf);
+ }
+}
+
+/* Utility: wait for reply from stub, while accepting "O" packets. */
+static char *
+remote_get_noisy_reply (char **buf_p,
+ long *sizeof_buf)
+{
+ do /* Loop on reply from remote stub. */
+ {
+ char *buf;
+ QUIT; /* allow user to bail out with ^C */
+ getpkt (buf_p, sizeof_buf, 0);
+ buf = *buf_p;
+ if (buf[0] == 0)
+ error (_("Target does not support this command."));
+ else if (buf[0] == 'E')
+ trace_error (buf);
+ else if (buf[0] == 'O' &&
+ buf[1] != 'K')
+ remote_console_output (buf + 1); /* 'O' message from stub */
+ else
+ return buf; /* here's the actual reply */
+ }
+ while (1);
+}
/* Handle for retreving the remote protocol data from gdbarch. */
static struct gdbarch_data *remote_gdbarch_data_handle;
rs->buf = xrealloc (rs->buf, rs->buf_size);
}
+ /* Record our GDBARCH. */
+ rs->gdbarch = gdbarch;
+
return rsa;
}
PACKET_qXfer_spu_read,
PACKET_qXfer_spu_write,
PACKET_qXfer_osdata,
+ PACKET_qXfer_threads,
PACKET_qGetTLSAddr,
PACKET_qSupported,
PACKET_QPassSignals,
remote_add_thread (currthread, running);
inferior_ptid = currthread;
}
- return;
+ return;
}
if (ptid_equal (magic_null_ptid, inferior_ptid))
doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
- thread_change_ptid (inferior_ptid, currthread);
+ thread_change_ptid (inferior_ptid, currthread);
return;
}
}
}
+/* Return the private thread data, creating it if necessary. */
+
+struct private_thread_info *
+demand_private_info (ptid_t ptid)
+{
+ struct thread_info *info = find_thread_ptid (ptid);
+
+ gdb_assert (info);
+
+ if (!info->private)
+ {
+ info->private = xmalloc (sizeof (*(info->private)));
+ info->private_dtor = free_private_thread_info;
+ info->private->core = -1;
+ info->private->extra = 0;
+ }
+
+ return info->private;
+}
+
/* Call this function as a result of
1) A halt indication (T packet) containing a thread id
2) A direct query of currthread
record_currthread (ptid_t currthread)
{
general_thread = currthread;
-
- if (ptid_equal (currthread, minus_one_ptid))
- /* We're just invalidating the local thread mirror. */
- return;
-
- remote_notice_new_inferior (currthread, 0);
}
static char *last_pass_packet;
CRAZY_MAX_THREADS);
}
+#if defined(HAVE_LIBEXPAT)
+
+typedef struct thread_item
+{
+ ptid_t ptid;
+ char *extra;
+ int core;
+} thread_item_t;
+DEF_VEC_O(thread_item_t);
+
+struct threads_parsing_context
+{
+ VEC (thread_item_t) *items;
+};
+
+static void
+start_thread (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ struct threads_parsing_context *data = user_data;
+
+ struct thread_item item;
+ char *id;
+
+ id = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+ item.ptid = read_ptid (id, NULL);
+
+ if (VEC_length (gdb_xml_value_s, attributes) > 1)
+ item.core = *(ULONGEST *) VEC_index (gdb_xml_value_s, attributes, 1)->value;
+ else
+ item.core = -1;
+
+ item.extra = 0;
+
+ VEC_safe_push (thread_item_t, data->items, &item);
+}
+
+static void
+end_thread (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, const char *body_text)
+{
+ struct threads_parsing_context *data = user_data;
+
+ if (body_text && *body_text)
+ VEC_last (thread_item_t, data->items)->extra = strdup (body_text);
+}
+
+const struct gdb_xml_attribute thread_attributes[] = {
+ { "id", GDB_XML_AF_NONE, NULL, NULL },
+ { "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_element thread_children[] = {
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_element threads_children[] = {
+ { "thread", thread_attributes, thread_children,
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+ start_thread, end_thread },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+const struct gdb_xml_element threads_elements[] = {
+ { "threads", NULL, threads_children,
+ GDB_XML_EF_NONE, NULL, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+#endif
+
/*
* Find all threads for info threads command.
* Uses new thread protocol contributed by Cisco.
if (remote_desc == 0) /* paranoia */
error (_("Command can only be used when connected to the remote target."));
+#if defined(HAVE_LIBEXPAT)
+ if (remote_protocol_packets[PACKET_qXfer_threads].support == PACKET_ENABLE)
+ {
+ char *xml = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_THREADS, NULL);
+
+ struct cleanup *back_to = make_cleanup (xfree, xml);
+ if (xml && *xml)
+ {
+ struct gdb_xml_parser *parser;
+ struct threads_parsing_context context;
+ struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+
+ context.items = 0;
+ parser = gdb_xml_create_parser_and_cleanup (_("threads"),
+ threads_elements,
+ &context);
+
+ gdb_xml_use_dtd (parser, "threads.dtd");
+
+ if (gdb_xml_parse (parser, xml) == 0)
+ {
+ int i;
+ struct thread_item *item;
+
+ for (i = 0; VEC_iterate (thread_item_t, context.items, i, item); ++i)
+ {
+ if (!ptid_equal (item->ptid, null_ptid))
+ {
+ struct private_thread_info *info;
+ /* In non-stop mode, we assume new found threads
+ are running until proven otherwise with a
+ stop reply. In all-stop, we can only get
+ here if all threads are stopped. */
+ int running = non_stop ? 1 : 0;
+
+ remote_notice_new_inferior (item->ptid, running);
+
+ info = demand_private_info (item->ptid);
+ info->core = item->core;
+ info->extra = item->extra;
+ item->extra = 0;
+ }
+ xfree (item->extra);
+ }
+ }
+
+ VEC_free (thread_item_t, context.items);
+ }
+
+ do_cleanups (back_to);
+ return;
+ }
+#endif
+
if (use_threadinfo_query)
{
putpkt ("qfThreadInfo");
server doesn't know about it. */
return NULL;
+ if (remote_protocol_packets[PACKET_qXfer_threads].support == PACKET_ENABLE)
+ {
+ struct thread_info *info = find_thread_ptid (tp->ptid);
+ if (info && info->private)
+ return info->private->extra;
+ else
+ return NULL;
+ }
+
if (use_threadextra_query)
{
char *b = rs->buf;
remote_check_symbols (symfile_objfile);
}
+ /* Possibly the target has been engaged in a trace run started
+ previously; find out where things are at. */
+ if (rs->disconnected_tracing)
+ {
+ struct uploaded_tp *uploaded_tps = NULL;
+ struct uploaded_tsv *uploaded_tsvs = NULL;
+
+ remote_get_trace_status (current_trace_status ());
+ if (current_trace_status ()->running)
+ printf_filtered (_("Trace is already running on the target.\n"));
+
+ /* Get trace state variables first, they may be checked when
+ parsing uploaded commands. */
+
+ remote_upload_trace_state_variables (&uploaded_tsvs);
+
+ merge_uploaded_trace_state_variables (&uploaded_tsvs);
+
+ remote_upload_tracepoints (&uploaded_tps);
+
+ merge_uploaded_tracepoints (&uploaded_tps);
+ }
+
/* If breakpoints are global, insert them now. */
if (gdbarch_has_global_breakpoints (target_gdbarch)
&& breakpoints_always_inserted_mode ())
rs->fast_tracepoints = (support == PACKET_ENABLE);
}
+static void
+remote_disconnected_tracing_feature (const struct protocol_feature *feature,
+ enum packet_support support,
+ const char *value)
+{
+ struct remote_state *rs = get_remote_state ();
+ rs->disconnected_tracing = (support == PACKET_ENABLE);
+}
+
static struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_spu_write },
{ "qXfer:osdata:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_osdata },
+ { "qXfer:threads:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_threads },
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QPassSignals },
{ "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
PACKET_ConditionalTracepoints },
{ "FastTracepoints", PACKET_DISABLE, remote_fast_tracepoint_feature,
PACKET_FastTracepoints },
+ { "DisconnectedTracing", PACKET_DISABLE, remote_disconnected_tracing_feature,
+ -1 },
{ "ReverseContinue", PACKET_DISABLE, remote_supported_packet,
PACKET_bc },
{ "ReverseStep", PACKET_DISABLE, remote_supported_packet,
rs->buf[0] = 0;
if (remote_protocol_packets[PACKET_qSupported].support != PACKET_DISABLE)
{
- if (rs->extended)
- putpkt ("qSupported:multiprocess+");
+ const char *qsupported = gdbarch_qsupported (rs->gdbarch);
+ if (qsupported)
+ {
+ char *q;
+ if (rs->extended)
+ q = concat ("qSupported:multiprocess+;", qsupported, NULL);
+ else
+ q = concat ("qSupported:", qsupported, NULL);
+ putpkt (q);
+ xfree (q);
+ }
else
- putpkt ("qSupported");
+ {
+ if (rs->extended)
+ putpkt ("qSupported:multiprocess+");
+ else
+ putpkt ("qSupported");
+ }
getpkt (&rs->buf, &rs->buf_size, 0);
error (_("Reply contains invalid hex digit %d"), a);
}
-static int
+int
hex2bin (const char *hex, gdb_byte *bin, int count)
{
int i;
return 'a' + nib - 10;
}
-static int
+int
bin2hex (const gdb_byte *bin, char *hex, int count)
{
int i;
int solibs_changed;
int replay_event;
+
+ int core;
};
/* The list of already fetched and acknowledged stop events. */
event->replay_event = 0;
event->stopped_by_watchpoint_p = 0;
event->regcache = NULL;
+ event->core = -1;
switch (buf[0])
{
/* If this packet is an awatch packet, don't parse the 'a'
as a register number. */
- if (strncmp (p, "awatch", strlen("awatch")) != 0)
+ if (strncmp (p, "awatch", strlen("awatch")) != 0
+ && strncmp (p, "core", strlen ("core") != 0))
{
/* Read the ``P'' register number. */
pnum = strtol (p, &p_temp, 16);
if (p_temp)
p = p_temp;
}
+ else if (strncmp (p, "core", p1 - p) == 0)
+ {
+ ULONGEST c;
+ p = unpack_varlen_hex (++p1, &c);
+ event->core = c;
+ }
else
{
/* Silently skip unknown optional info. */
struct target_waitstatus *status)
{
ptid_t ptid;
+ struct thread_info *info;
*status = stop_reply->ws;
ptid = stop_reply->ptid;
remote_watch_data_address = stop_reply->watch_data_address;
remote_notice_new_inferior (ptid, 0);
+ demand_private_info (ptid)->core = stop_reply->core;
}
stop_reply_xfree (stop_reply);
char *p;
int bpsize;
- gdbarch_breakpoint_from_pc (gdbarch, &addr, &bpsize);
+ gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
rs = get_remote_state ();
p = rs->buf;
/* The length field should be set to the size of a breakpoint
instruction, even though we aren't inserting one ourselves. */
- gdbarch_breakpoint_from_pc
+ gdbarch_remote_breakpoint_from_pc
(gdbarch, &bp_tgt->placed_address, &bp_tgt->placed_size);
if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
(ops, "osdata", annex, readbuf, offset, len,
&remote_protocol_packets[PACKET_qXfer_osdata]);
+ case TARGET_OBJECT_THREADS:
+ gdb_assert (annex == NULL);
+ return remote_read_qxfer (ops, "threads", annex, readbuf, offset, len,
+ &remote_protocol_packets[PACKET_qXfer_threads]);
+
default:
return -1;
}
{
char *buf;
- /* XXX - see also tracepoint.c:remote_get_noisy_reply(). */
+ /* XXX - see also remote_get_noisy_reply(). */
rs->buf[0] = '\0';
getpkt (&rs->buf, &rs->buf_size, 0);
buf = rs->buf;
return rs->fast_tracepoints;
}
+static void
+remote_trace_init ()
+{
+ putpkt ("QTinit");
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (strcmp (target_buf, "OK"))
+ error (_("Target does not support this command."));
+}
+
+static void free_actions_list (char **actions_list);
+static void free_actions_list_cleanup_wrapper (void *);
+static void
+free_actions_list_cleanup_wrapper (void *al)
+{
+ free_actions_list (al);
+}
+
+static void
+free_actions_list (char **actions_list)
+{
+ int ndx;
+
+ if (actions_list == 0)
+ return;
+
+ for (ndx = 0; actions_list[ndx]; ndx++)
+ xfree (actions_list[ndx]);
+
+ xfree (actions_list);
+}
+
+static void
+remote_download_tracepoint (struct breakpoint *t)
+{
+ CORE_ADDR tpaddr;
+ char tmp[40];
+ char buf[2048];
+ char **tdp_actions;
+ char **stepping_actions;
+ int ndx;
+ struct cleanup *old_chain = NULL;
+ struct agent_expr *aexpr;
+ struct cleanup *aexpr_chain = NULL;
+ char *pkt;
+
+ encode_actions (t, &tdp_actions, &stepping_actions);
+ old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
+ tdp_actions);
+ (void) make_cleanup (free_actions_list_cleanup_wrapper, stepping_actions);
+
+ tpaddr = t->loc->address;
+ sprintf_vma (tmp, (t->loc ? tpaddr : 0));
+ sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", t->number,
+ tmp, /* address */
+ (t->enable_state == bp_enabled ? 'E' : 'D'),
+ t->step_count, t->pass_count);
+ /* Fast tracepoints are mostly handled by the target, but we can
+ tell the target how big of an instruction block should be moved
+ around. */
+ if (t->type == bp_fast_tracepoint)
+ {
+ /* Only test for support at download time; we may not know
+ target capabilities at definition time. */
+ if (remote_supports_fast_tracepoints ())
+ {
+ int isize;
+
+ if (gdbarch_fast_tracepoint_valid_at (target_gdbarch,
+ tpaddr, &isize, NULL))
+ sprintf (buf + strlen (buf), ":F%x", isize);
+ else
+ /* If it passed validation at definition but fails now,
+ something is very wrong. */
+ internal_error (__FILE__, __LINE__,
+ "Fast tracepoint not valid during download");
+ }
+ else
+ /* Fast tracepoints are functionally identical to regular
+ tracepoints, so don't take lack of support as a reason to
+ give up on the trace run. */
+ warning (_("Target does not support fast tracepoints, downloading %d as regular tracepoint"), t->number);
+ }
+ /* If the tracepoint has a conditional, make it into an agent
+ expression and append to the definition. */
+ if (t->loc->cond)
+ {
+ /* Only test support at download time, we may not know target
+ capabilities at definition time. */
+ if (remote_supports_cond_tracepoints ())
+ {
+ aexpr = gen_eval_for_expr (t->loc->address, t->loc->cond);
+ aexpr_chain = make_cleanup_free_agent_expr (aexpr);
+ sprintf (buf + strlen (buf), ":X%x,", aexpr->len);
+ pkt = buf + strlen (buf);
+ for (ndx = 0; ndx < aexpr->len; ++ndx)
+ pkt = pack_hex_byte (pkt, aexpr->buf[ndx]);
+ *pkt = '\0';
+ do_cleanups (aexpr_chain);
+ }
+ else
+ warning (_("Target does not support conditional tracepoints, ignoring tp %d cond"), t->number);
+ }
+
+ if (t->actions || *default_collect)
+ strcat (buf, "-");
+ putpkt (buf);
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (strcmp (target_buf, "OK"))
+ error (_("Target does not support tracepoints."));
+
+ if (!t->actions && !*default_collect)
+ return;
+
+ /* do_single_steps (t); */
+ if (tdp_actions)
+ {
+ for (ndx = 0; tdp_actions[ndx]; ndx++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ sprintf (buf, "QTDP:-%x:%s:%s%c",
+ t->number, tmp, /* address */
+ tdp_actions[ndx],
+ ((tdp_actions[ndx + 1] || stepping_actions)
+ ? '-' : 0));
+ putpkt (buf);
+ remote_get_noisy_reply (&target_buf,
+ &target_buf_size);
+ if (strcmp (target_buf, "OK"))
+ error (_("Error on target while setting tracepoints."));
+ }
+ }
+ if (stepping_actions)
+ {
+ for (ndx = 0; stepping_actions[ndx]; ndx++)
+ {
+ QUIT; /* allow user to bail out with ^C */
+ sprintf (buf, "QTDP:-%x:%s:%s%s%s",
+ t->number, tmp, /* address */
+ ((ndx == 0) ? "S" : ""),
+ stepping_actions[ndx],
+ (stepping_actions[ndx + 1] ? "-" : ""));
+ putpkt (buf);
+ remote_get_noisy_reply (&target_buf,
+ &target_buf_size);
+ if (strcmp (target_buf, "OK"))
+ error (_("Error on target while setting tracepoints."));
+ }
+ }
+ do_cleanups (old_chain);
+ return;
+}
+
+static void
+remote_download_trace_state_variable (struct trace_state_variable *tsv)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p;
+
+ sprintf (rs->buf, "QTDV:%x:%s:%x:",
+ tsv->number, phex ((ULONGEST) tsv->initial_value, 8), tsv->builtin);
+ p = rs->buf + strlen (rs->buf);
+ if ((p - rs->buf) + strlen (tsv->name) * 2 >= get_remote_packet_size ())
+ error (_("Trace state variable name too long for tsv definition packet"));
+ p += 2 * bin2hex ((gdb_byte *) (tsv->name), p, 0);
+ *p++ = '\0';
+ putpkt (rs->buf);
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+}
+
+static void
+remote_trace_set_readonly_regions ()
+{
+ asection *s;
+ bfd_size_type size;
+ bfd_vma lma;
+ int anysecs = 0;
+
+ if (!exec_bfd)
+ return; /* No information to give. */
+
+ strcpy (target_buf, "QTro");
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ char tmp1[40], tmp2[40];
+
+ if ((s->flags & SEC_LOAD) == 0 ||
+ /* (s->flags & SEC_CODE) == 0 || */
+ (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ anysecs = 1;
+ lma = s->lma;
+ size = bfd_get_section_size (s);
+ sprintf_vma (tmp1, lma);
+ sprintf_vma (tmp2, lma + size);
+ sprintf (target_buf + strlen (target_buf),
+ ":%s,%s", tmp1, tmp2);
+ }
+ if (anysecs)
+ {
+ putpkt (target_buf);
+ getpkt (&target_buf, &target_buf_size, 0);
+ }
+}
+
+static void
+remote_trace_start ()
+{
+ putpkt ("QTStart");
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (strcmp (target_buf, "OK"))
+ error (_("Bogus reply from target: %s"), target_buf);
+}
+
+static int
+remote_get_trace_status (struct trace_status *ts)
+{
+ char *p, *p1, *p_temp;
+ ULONGEST val;
+ /* FIXME we need to get register block size some other way */
+ extern int trace_regblock_size;
+ trace_regblock_size = get_remote_arch_state ()->sizeof_g_packet;
+
+ putpkt ("qTStatus");
+ getpkt (&target_buf, &target_buf_size, 0);
+ /* FIXME should handle more variety of replies */
+
+ p = target_buf;
+
+ /* If the remote target doesn't do tracing, flag it. */
+ if (*p == '\0')
+ return -1;
+
+ /* We're working with a live target. */
+ ts->from_file = 0;
+
+ /* Set some defaults. */
+ ts->running_known = 0;
+ ts->stop_reason = trace_stop_reason_unknown;
+ ts->traceframe_count = -1;
+ ts->buffer_free = 0;
+
+ if (*p++ != 'T')
+ error (_("Bogus trace status reply from target: %s"), target_buf);
+
+ parse_trace_status (p, ts);
+
+ return ts->running;
+}
+
+static void
+remote_trace_stop ()
+{
+ putpkt ("QTStop");
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (strcmp (target_buf, "OK"))
+ error (_("Bogus reply from target: %s"), target_buf);
+}
+
+static int
+remote_trace_find (enum trace_find_type type, int num,
+ ULONGEST addr1, ULONGEST addr2,
+ int *tpp)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p, *reply;
+ int target_frameno = -1, target_tracept = -1;
+
+ p = rs->buf;
+ strcpy (p, "QTFrame:");
+ p = strchr (p, '\0');
+ switch (type)
+ {
+ case tfind_number:
+ sprintf (p, "%x", num);
+ break;
+ case tfind_pc:
+ sprintf (p, "pc:%s", phex_nz (addr1, 0));
+ break;
+ case tfind_tp:
+ sprintf (p, "tdp:%x", num);
+ break;
+ case tfind_range:
+ sprintf (p, "range:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0));
+ break;
+ case tfind_outside:
+ sprintf (p, "outside:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0));
+ break;
+ default:
+ error ("Unknown trace find type %d", type);
+ }
+
+ putpkt (rs->buf);
+ reply = remote_get_noisy_reply (&(rs->buf), &sizeof_pkt);
+
+ while (reply && *reply)
+ switch (*reply)
+ {
+ case 'F':
+ if ((target_frameno = (int) strtol (++reply, &reply, 16)) == -1)
+ error (_("Target failed to find requested trace frame."));
+ break;
+ case 'T':
+ if ((target_tracept = (int) strtol (++reply, &reply, 16)) == -1)
+ error (_("Target failed to find requested trace frame."));
+ break;
+ case 'O': /* "OK"? */
+ if (reply[1] == 'K' && reply[2] == '\0')
+ reply += 2;
+ else
+ error (_("Bogus reply from target: %s"), reply);
+ break;
+ default:
+ error (_("Bogus reply from target: %s"), reply);
+ }
+ if (tpp)
+ *tpp = target_tracept;
+ return target_frameno;
+}
+
+static int
+remote_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *reply;
+ ULONGEST uval;
+
+ sprintf (rs->buf, "qTV:%x", tsvnum);
+ putpkt (rs->buf);
+ reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (reply && *reply)
+ {
+ if (*reply == 'V')
+ {
+ unpack_varlen_hex (reply + 1, &uval);
+ *val = (LONGEST) uval;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+remote_save_trace_data (char *filename)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p, *reply;
+
+ p = rs->buf;
+ strcpy (p, "QTSave:");
+ p += strlen (p);
+ if ((p - rs->buf) + strlen (filename) * 2 >= get_remote_packet_size ())
+ error (_("Remote file name too long for trace save packet"));
+ p += 2 * bin2hex ((gdb_byte *) filename, p, 0);
+ *p++ = '\0';
+ putpkt (rs->buf);
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+ return 0;
+}
+
+/* This is basically a memory transfer, but needs to be its own packet
+ because we don't know how the target actually organizes its trace
+ memory, plus we want to be able to ask for as much as possible, but
+ not be unhappy if we don't get as much as we ask for. */
+
+static LONGEST
+remote_get_raw_trace_data (gdb_byte *buf, ULONGEST offset, LONGEST len)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *reply;
+ char *p;
+ int rslt;
+
+ p = rs->buf;
+ strcpy (p, "qTBuffer:");
+ p += strlen (p);
+ p += hexnumstr (p, offset);
+ *p++ = ',';
+ p += hexnumstr (p, len);
+ *p++ = '\0';
+
+ putpkt (rs->buf);
+ reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (reply && *reply)
+ {
+ /* 'l' by itself means we're at the end of the buffer and
+ there is nothing more to get. */
+ if (*reply == 'l')
+ return 0;
+
+ /* Convert the reply into binary. Limit the number of bytes to
+ convert according to our passed-in buffer size, rather than
+ what was returned in the packet; if the target is
+ unexpectedly generous and gives us a bigger reply than we
+ asked for, we don't want to crash. */
+ rslt = hex2bin (target_buf, buf, len);
+ return rslt;
+ }
+
+ /* Something went wrong, flag as an error. */
+ return -1;
+}
+
+static void
+remote_set_disconnected_tracing (int val)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ sprintf (rs->buf, "QTDisconnected:%x", val);
+ putpkt (rs->buf);
+ remote_get_noisy_reply (&target_buf, &target_buf_size);
+ if (strcmp (target_buf, "OK"))
+ error (_("Target does not support this command."));
+}
+
+static int
+remote_core_of_thread (struct target_ops *ops, ptid_t ptid)
+{
+ struct thread_info *info = find_thread_ptid (ptid);
+ if (info && info->private)
+ return info->private->core;
+ return -1;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_terminal_ours = remote_terminal_ours;
remote_ops.to_supports_non_stop = remote_supports_non_stop;
remote_ops.to_supports_multi_process = remote_supports_multi_process;
+ remote_ops.to_trace_init = remote_trace_init;
+ remote_ops.to_download_tracepoint = remote_download_tracepoint;
+ remote_ops.to_download_trace_state_variable = remote_download_trace_state_variable;
+ remote_ops.to_trace_set_readonly_regions = remote_trace_set_readonly_regions;
+ remote_ops.to_trace_start = remote_trace_start;
+ remote_ops.to_get_trace_status = remote_get_trace_status;
+ remote_ops.to_trace_stop = remote_trace_stop;
+ remote_ops.to_trace_find = remote_trace_find;
+ remote_ops.to_get_trace_state_variable_value = remote_get_trace_state_variable_value;
+ remote_ops.to_save_trace_data = remote_save_trace_data;
+ remote_ops.to_upload_tracepoints = remote_upload_tracepoints;
+ remote_ops.to_upload_trace_state_variables = remote_upload_trace_state_variables;
+ remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data;
+ remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
+ remote_ops.to_core_of_thread = remote_core_of_thread;
}
/* Set up the extended remote vector by making a copy of the standard
remote_check_symbols (objfile);
}
+/* Pull all the tracepoints defined on the target and create local
+ data structures representing them. We don't want to create real
+ tracepoints yet, we don't want to mess up the user's existing
+ collection. */
+
+static int
+remote_upload_tracepoints (struct uploaded_tp **utpp)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p;
+
+ /* Ask for a first packet of tracepoint definition. */
+ putpkt ("qTfP");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ p = rs->buf;
+ while (*p && *p != 'l')
+ {
+ parse_tracepoint_definition (p, utpp);
+ /* Ask for another packet of tracepoint definition. */
+ putpkt ("qTsP");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ p = rs->buf;
+ }
+ return 0;
+}
+
+static int
+remote_upload_trace_state_variables (struct uploaded_tsv **utsvp)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p;
+
+ /* Ask for a first packet of variable definition. */
+ putpkt ("qTfV");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ p = rs->buf;
+ while (*p && *p != 'l')
+ {
+ parse_tsv_definition (p, utsvp);
+ /* Ask for another packet of variable definition. */
+ putpkt ("qTsV");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ p = rs->buf;
+ }
+ return 0;
+}
+
void
_initialize_remote (void)
{
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_osdata],
"qXfer:osdata:read", "osdata", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_threads],
+ "qXfer:threads:read", "threads", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_read],
"qXfer:siginfo:read", "read-siginfo-object", 0);
magic_null_ptid = ptid_build (42000, 1, -1);
not_sent_ptid = ptid_build (42000, 1, -2);
any_thread_ptid = ptid_build (42000, 1, 0);
+
+ target_buf_size = 2048;
+ target_buf = xmalloc (target_buf_size);
}