+struct btrace_target_info
+{
+ /* The ptid of the traced thread. */
+ ptid_t ptid;
+};
+
+/* Check whether the target supports branch tracing. */
+
+static int
+remote_supports_btrace (void)
+{
+ if (remote_protocol_packets[PACKET_Qbtrace_off].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_Qbtrace_bts].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_qXfer_btrace].support != PACKET_ENABLE)
+ return 0;
+
+ return 1;
+}
+
+/* Enable branch tracing. */
+
+static struct btrace_target_info *
+remote_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo = NULL;
+ struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_bts];
+ struct remote_state *rs = get_remote_state ();
+ char *buf = rs->buf;
+ char *endbuf = rs->buf + get_remote_packet_size ();
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+ set_general_thread (ptid);
+
+ buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, packet) == PACKET_ERROR)
+ {
+ if (rs->buf[0] == 'E' && rs->buf[1] == '.')
+ error (_("Could not enable branch tracing for %s: %s"),
+ target_pid_to_str (ptid), rs->buf + 2);
+ else
+ error (_("Could not enable branch tracing for %s."),
+ target_pid_to_str (ptid));
+ }
+
+ tinfo = xzalloc (sizeof (*tinfo));
+ tinfo->ptid = ptid;
+
+ return tinfo;
+}
+
+/* Disable branch tracing. */
+
+static void
+remote_disable_btrace (struct btrace_target_info *tinfo)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_off];
+ struct remote_state *rs = get_remote_state ();
+ char *buf = rs->buf;
+ char *endbuf = rs->buf + get_remote_packet_size ();
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+ set_general_thread (tinfo->ptid);
+
+ buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, packet) == PACKET_ERROR)
+ {
+ if (rs->buf[0] == 'E' && rs->buf[1] == '.')
+ error (_("Could not disable branch tracing for %s: %s"),
+ target_pid_to_str (tinfo->ptid), rs->buf + 2);
+ else
+ error (_("Could not disable branch tracing for %s."),
+ target_pid_to_str (tinfo->ptid));
+ }
+
+ xfree (tinfo);
+}
+
+/* Teardown branch tracing. */
+
+static void
+remote_teardown_btrace (struct btrace_target_info *tinfo)
+{
+ /* We must not talk to the target during teardown. */
+ xfree (tinfo);
+}
+
+/* Read the branch trace. */
+
+static VEC (btrace_block_s) *
+remote_read_btrace (struct btrace_target_info *tinfo,
+ enum btrace_read_type type)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
+ struct remote_state *rs = get_remote_state ();
+ VEC (btrace_block_s) *btrace = NULL;
+ const char *annex;
+ char *xml;
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+#if !defined(HAVE_LIBEXPAT)
+ error (_("Cannot process branch tracing result. XML parsing not supported."));
+#endif
+
+ switch (type)
+ {
+ case btrace_read_all:
+ annex = "all";
+ break;
+ case btrace_read_new:
+ annex = "new";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Bad branch tracing read type: %u."),
+ (unsigned int) type);
+ }
+
+ xml = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_BTRACE, annex);
+ if (xml != NULL)
+ {
+ struct cleanup *cleanup = make_cleanup (xfree, xml);
+
+ btrace = parse_xml_btrace (xml);
+ do_cleanups (cleanup);
+ }
+
+ return btrace;
+}
+