Add the gdb remote target operations for branch tracing.
authorMarkus Metzger <mmetzger@sourceware.org>
Mon, 11 Mar 2013 08:35:11 +0000 (08:35 +0000)
committerMarkus Metzger <mmetzger@sourceware.org>
Mon, 11 Mar 2013 08:35:11 +0000 (08:35 +0000)
We define the following packets:

  Qbtrace:bts         enable branch tracing for the current thread
                      returns "OK" or "Enn"

  Qbtrace:off         disable branch tracing for the current thread
                      returns "OK" or "Enn"

  qXfer:btrace:read   read the full branch trace data for the current thread

gdb/
* target.h (enum target_object): Add TARGET_OBJECT_BTRACE.
* remote.c: Include btrace.h.
(struct btrace_target_info): New struct.
(remote_supports_btrace): New function.
(send_Qbtrace): New function.
(remote_enable_btrace): New function.
(remote_disable_btrace): New function.
(remote_teardown_btrace): New function.
(remote_read_btrace): New function.
(init_remote_ops): Add btrace ops.
(enum <unnamed>): Add btrace packets.
(struct protocol_feature remote_protocol_features[]): Add btrace packets.
(_initialize_remote): Add packet configuration for branch tracing.

gdbserver/
* target.h (struct target_ops): Add btrace ops.
(target_supports_btrace): New macro.
(target_enable_btrace): New macro.
(target_disable_btrace): New macro.
(target_read_btrace): New macro.
* gdbthread.h (struct thread_info): Add btrace field.
* server.c: Include btrace-common.h.
(handle_btrace_general_set): New function.
(handle_btrace_enable): New function.
(handle_btrace_disable): New function.
(handle_general_set): Call handle_btrace_general_set.
(handle_qxfer_btrace): New function.
(struct qxfer qxfer_packets[]): Add btrace entry.
* inferiors.c (remove_thread): Disable btrace.
* linux-low: Include linux-btrace.h.
(linux_low_enable_btrace): New function.
(linux_low_read_btrace): New function.
(linux_target_ops): Add btrace ops.
* configure.srv (i[34567]86-*-linux*): Add linux-btrace.o.
Add srv_linux_btrace=yes.
(x86_64-*-linux*): Add linux-btrace.o.
Add srv_linux_btrace=yes.
* configure.ac: Define HAVE_LINUX_BTRACE.
* config.in: Regenerated.
* configure: Regenerated.

13 files changed:
gdb/ChangeLog
gdb/gdbserver/ChangeLog
gdb/gdbserver/config.in
gdb/gdbserver/configure
gdb/gdbserver/configure.ac
gdb/gdbserver/configure.srv
gdb/gdbserver/gdbthread.h
gdb/gdbserver/inferiors.c
gdb/gdbserver/linux-low.c
gdb/gdbserver/server.c
gdb/gdbserver/target.h
gdb/remote.c
gdb/target.h

index 426d631a5a627cd18053ab67950b0ea8b3ae77e6..0dc837ec2153e393f50f017730721199a0f2d90f 100644 (file)
@@ -1,3 +1,19 @@
+2013-03-11  Markus Metzger  <markus.t.metzger@intel.com>
+
+       * target.h (enum target_object): Add TARGET_OBJECT_BTRACE.
+       * remote.c: Include btrace.h.
+       (struct btrace_target_info): New struct.
+       (remote_supports_btrace): New function.
+       (send_Qbtrace): New function.
+       (remote_enable_btrace): New function.
+       (remote_disable_btrace): New function.
+       (remote_teardown_btrace): New function.
+       (remote_read_btrace): New function.
+       (init_remote_ops): Add btrace ops.
+       (enum <unnamed>): Add btrace packets.
+       (struct protocol_feature remote_protocol_features[]): Add btrace packets.
+       (_initialize_remote): Add packet configuration for branch tracing.
+
 2013-03-11  Markus Metzger  <markus.t.metzger@intel.com>
 
        * features/btrace.dtd: New file.
index b26f85bac9eb4c618bf921f986965dea0c2b19c2..9a5ae02a4fb9f83fcfffe3eb24f7a2de266b7022 100644 (file)
@@ -1,3 +1,31 @@
+2013-03-11  Markus Metzger  <markus.t.metzger@intel.com>
+
+       * target.h (struct target_ops): Add btrace ops.
+       (target_supports_btrace): New macro.
+       (target_enable_btrace): New macro.
+       (target_disable_btrace): New macro.
+       (target_read_btrace): New macro.
+       * gdbthread.h (struct thread_info): Add btrace field.
+       * server.c: Include btrace-common.h.
+       (handle_btrace_general_set): New function.
+       (handle_btrace_enable): New function.
+       (handle_btrace_disable): New function.
+       (handle_general_set): Call handle_btrace_general_set.
+       (handle_qxfer_btrace): New function.
+       (struct qxfer qxfer_packets[]): Add btrace entry.
+       * inferiors.c (remove_thread): Disable btrace.
+       * linux-low: Include linux-btrace.h.
+       (linux_low_enable_btrace): New function.
+       (linux_low_read_btrace): New function.
+       (linux_target_ops): Add btrace ops.
+       * configure.srv (i[34567]86-*-linux*): Add linux-btrace.o.
+       Add srv_linux_btrace=yes.
+       (x86_64-*-linux*): Add linux-btrace.o.
+       Add srv_linux_btrace=yes.
+       * configure.ac: Define HAVE_LINUX_BTRACE.
+       * config.in: Regenerated.
+       * configure: Regenerated.
+
 2013-03-11  Markus Metzger  <markus.t.metzger@intel.com>
 
        * server.c (handle_qxfer): Preserve error message if -3 is
index a7c5445c2f986cc50a9b4cd0bc185a1881b4a209..738c32224dbd072b20d689ff2aaa9f3d0ea1aad6 100644 (file)
@@ -73,6 +73,9 @@
 /* Define to 1 if you have the `dl' library (-ldl). */
 #undef HAVE_LIBDL
 
+/* Define if the target supports branch tracing. */
+#undef HAVE_LINUX_BTRACE
+
 /* Define to 1 if you have the <linux/elf.h> header file. */
 #undef HAVE_LINUX_ELF_H
 
index f37f802d64cdd4b2a092f15f1b12c4cb632aa399..da257bb76a283669f3c4f0cf72f166ee56815b06 100755 (executable)
@@ -5344,6 +5344,12 @@ $as_echo "#define HAVE_PTRACE_GETFPXREGS 1" >>confdefs.h
   fi
 fi
 
+if test "${srv_linux_btrace}" = "yes"; then
+
+$as_echo "#define HAVE_LINUX_BTRACE 1" >>confdefs.h
+
+fi
+
 if test "$ac_cv_header_sys_procfs_h" = yes; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lwpid_t in sys/procfs.h" >&5
 $as_echo_n "checking for lwpid_t in sys/procfs.h... " >&6; }
index 0b30858b0d9b4e42e308f14ec53bd5cfa60b2254..f6227d1378aa8c0c3c8894a460bc658632d79576 100644 (file)
@@ -292,6 +292,11 @@ if test "${srv_linux_regsets}" = "yes"; then
   fi
 fi
 
+if test "${srv_linux_btrace}" = "yes"; then
+  AC_DEFINE(HAVE_LINUX_BTRACE, 1,
+           [Define if the target supports branch tracing.])
+fi
+
 if test "$ac_cv_header_sys_procfs_h" = yes; then
   BFD_HAVE_SYS_PROCFS_TYPE(lwpid_t)
   BFD_HAVE_SYS_PROCFS_TYPE(psaddr_t)
index 0bda563be6bc2a5b74f3ae5440c1be8bcee59c13..271a0fee9624246445a43581e34dbaef19f235e9 100644 (file)
@@ -112,10 +112,11 @@ case "${target}" in
                            srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles"
                        fi
                        srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
-                       srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+                       srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o"
                        srv_linux_usrregs=yes
                        srv_linux_regsets=yes
                        srv_linux_thread_db=yes
+                       srv_linux_btrace=yes
                        ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
                        ;;
   i[34567]86-*-lynxos*)        srv_regobj="i386.o"
@@ -314,11 +315,12 @@ case "${target}" in
                        ;;
   x86_64-*-linux*)     srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj"
                        srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o"
-                       srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+                       srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o"
                        srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles"
                        srv_linux_usrregs=yes # This is for i386 progs.
                        srv_linux_regsets=yes
                        srv_linux_thread_db=yes
+                       srv_linux_btrace=yes
                        ipa_obj="${ipa_amd64_linux_regobj} linux-amd64-ipa.o"
                        ;;
   x86_64-*-mingw*)     srv_regobj="$srv_amd64_regobj"
index 85951d2a59968281616ce58b06993eb90f255fc1..5d4955b5d154687050c542920715e2d82fb0b054 100644 (file)
@@ -21,6 +21,8 @@
 
 #include "server.h"
 
+struct btrace_target_info;
+
 struct thread_info
 {
   struct inferior_list_entry entry;
@@ -57,6 +59,9 @@ struct thread_info
    Each item in the list holds the current step of the while-stepping
    action.  */
   struct wstep_state *while_stepping;
+
+  /* Branch trace target information for this thread.  */
+  struct btrace_target_info *btrace;
 };
 
 extern struct inferior_list all_threads;
index ba3c6cd5905bf4d18af9ce7b65da267cda18b62d..6953d0e170bc751996ab0e572e3e36fb208ce424 100644 (file)
@@ -161,6 +161,9 @@ free_one_thread (struct inferior_list_entry *inf)
 void
 remove_thread (struct thread_info *thread)
 {
+  if (thread->btrace != NULL)
+    target_disable_btrace (thread->btrace);
+
   remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
   free_one_thread (&thread->entry);
 }
index 5f036284a92719f9dcfda3556036ce5af3ab4e3a..b5084c93673b1c045e9f146cccb40d46fd9a7491 100644 (file)
 #endif
 #endif
 
+#ifdef HAVE_LINUX_BTRACE
+# include "linux-btrace.h"
+#endif
+
 #ifndef HAVE_ELF32_AUXV_T
 /* Copied from glibc's elf.h.  */
 typedef struct
@@ -5821,6 +5825,47 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
   return len;
 }
 
+#ifdef HAVE_LINUX_BTRACE
+
+/* Enable branch tracing.  */
+
+static struct btrace_target_info *
+linux_low_enable_btrace (ptid_t ptid)
+{
+  struct btrace_target_info *tinfo;
+
+  tinfo = linux_enable_btrace (ptid);
+  if (tinfo != NULL)
+    tinfo->ptr_bits = register_size (0) * 8;
+
+  return tinfo;
+}
+
+/* Read branch trace data as btrace xml document.  */
+
+static void
+linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
+                      int type)
+{
+  VEC (btrace_block_s) *btrace;
+  struct btrace_block *block;
+  int i;
+
+  btrace = linux_read_btrace (tinfo, type);
+
+  buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
+  buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
+
+  for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++)
+    buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
+                      paddress (block->begin), paddress (block->end));
+
+  buffer_grow_str (buffer, "</btrace>\n");
+
+  VEC_free (btrace_block_s, btrace);
+}
+#endif /* HAVE_LINUX_BTRACE */
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_attach,
@@ -5885,6 +5930,18 @@ static struct target_ops linux_target_ops = {
   linux_get_min_fast_tracepoint_insn_len,
   linux_qxfer_libraries_svr4,
   linux_supports_agent,
+#ifdef HAVE_LINUX_BTRACE
+  linux_supports_btrace,
+  linux_low_enable_btrace,
+  linux_disable_btrace,
+  linux_low_read_btrace,
+#else
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+#endif
 };
 
 static void
index 9592c69e0a7a8652f8ce451e9413e65927e755f4..6bb36d87c3761c6f045bbb5ff5dacae27652e5af 100644 (file)
@@ -28,6 +28,7 @@
 #include <signal.h>
 #endif
 #include "gdb_wait.h"
+#include "btrace-common.h"
 
 /* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
    `vCont'.  Note the multi-process extensions made `vCont' a
@@ -396,6 +397,88 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more)
                               PBUFSIZ - 2) + 1;
 }
 
+/* Handle btrace enabling.  */
+
+static const char *
+handle_btrace_enable (struct thread_info *thread)
+{
+  if (thread->btrace != NULL)
+    return "E.Btrace already enabled.";
+
+  thread->btrace = target_enable_btrace (thread->entry.id);
+  if (thread->btrace == NULL)
+    return "E.Could not enable btrace.";
+
+  return NULL;
+}
+
+/* Handle btrace disabling.  */
+
+static const char *
+handle_btrace_disable (struct thread_info *thread)
+{
+
+  if (thread->btrace == NULL)
+    return "E.Branch tracing not enabled.";
+
+  if (target_disable_btrace (thread->btrace) != 0)
+    return "E.Could not disable branch tracing.";
+
+  thread->btrace = NULL;
+  return NULL;
+}
+
+/* Handle the "Qbtrace" packet.  */
+
+static int
+handle_btrace_general_set (char *own_buf)
+{
+  struct thread_info *thread;
+  const char *err;
+  char *op;
+
+  if (strncmp ("Qbtrace:", own_buf, strlen ("Qbtrace:")) != 0)
+    return 0;
+
+  op = own_buf + strlen ("Qbtrace:");
+
+  if (!target_supports_btrace ())
+    {
+      strcpy (own_buf, "E.Target does not support branch tracing.");
+      return -1;
+    }
+
+  if (ptid_equal (general_thread, null_ptid)
+      || ptid_equal (general_thread, minus_one_ptid))
+    {
+      strcpy (own_buf, "E.Must select a single thread.");
+      return -1;
+    }
+
+  thread = find_thread_ptid (general_thread);
+  if (thread == NULL)
+    {
+      strcpy (own_buf, "E.No such thread.");
+      return -1;
+    }
+
+  err = NULL;
+
+  if (strcmp (op, "bts") == 0)
+    err = handle_btrace_enable (thread);
+  else if (strcmp (op, "off") == 0)
+    err = handle_btrace_disable (thread);
+  else
+    err = "E.Bad Qbtrace operation. Use bts or off.";
+
+  if (err != 0)
+    strcpy (own_buf, err);
+  else
+    write_ok (own_buf);
+
+  return 1;
+}
+
 /* Handle all of the extended 'Q' packets.  */
 
 static void
@@ -552,6 +635,9 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (handle_btrace_general_set (own_buf))
+    return;
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -1251,9 +1337,77 @@ handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf,
   return (*the_target->read_loadmap) (annex, offset, readbuf, len);
 }
 
+/* Handle qXfer:btrace:read.  */
+
+static int
+handle_qxfer_btrace (const char *annex,
+                    gdb_byte *readbuf, const gdb_byte *writebuf,
+                    ULONGEST offset, LONGEST len)
+{
+  static struct buffer cache;
+  struct thread_info *thread;
+  int type;
+
+  if (the_target->read_btrace == NULL || writebuf != NULL)
+    return -2;
+
+  if (!target_running ())
+    return -1;
+
+  if (ptid_equal (general_thread, null_ptid)
+      || ptid_equal (general_thread, minus_one_ptid))
+    {
+      strcpy (own_buf, "E.Must select a single thread.");
+      return -3;
+    }
+
+  thread = find_thread_ptid (general_thread);
+  if (thread == NULL)
+    {
+      strcpy (own_buf, "E.No such thread.");
+      return -3;
+    }
+
+  if (thread->btrace == NULL)
+    {
+      strcpy (own_buf, "E.Btrace not enabled.");
+      return -3;
+    }
+
+  if (strcmp (annex, "all") == 0)
+    type = btrace_read_all;
+  else if (strcmp (annex, "new") == 0)
+    type = btrace_read_new;
+  else
+    {
+      strcpy (own_buf, "E.Bad annex.");
+      return -3;
+    }
+
+  if (offset == 0)
+    {
+      buffer_free (&cache);
+
+      target_read_btrace (thread->btrace, &cache, type);
+    }
+  else if (offset > cache.used_size)
+    {
+      buffer_free (&cache);
+      return -3;
+    }
+
+  if (len > cache.used_size - offset)
+    len = cache.used_size - offset;
+
+  memcpy (readbuf, cache.buffer + offset, len);
+
+  return len;
+}
+
 static const struct qxfer qxfer_packets[] =
   {
     { "auxv", handle_qxfer_auxv },
+    { "btrace", handle_qxfer_btrace },
     { "fdpic", handle_qxfer_fdpic},
     { "features", handle_qxfer_features },
     { "libraries", handle_qxfer_libraries },
@@ -1656,6 +1810,13 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (target_supports_agent ())
        strcat (own_buf, ";QAgent+");
 
+      if (target_supports_btrace ())
+       {
+         strcat (own_buf, ";Qbtrace:bts+");
+         strcat (own_buf, ";Qbtrace:off+");
+         strcat (own_buf, ";qXfer:btrace:read+");
+       }
+
       return;
     }
 
index cc9a91023309ef9665c46b8474c6ac2dc53c1624..f257459b143555122454ad9c1cd5907869e54956 100644 (file)
@@ -22,6 +22,8 @@
 #define TARGET_H
 
 struct emit_ops;
+struct btrace_target_info;
+struct buffer;
 
 /* Ways to "resume" a thread.  */
 
@@ -397,6 +399,21 @@ struct target_ops
 
   /* Return true if target supports debugging agent.  */
   int (*supports_agent) (void);
+
+  /* Check whether the target supports branch tracing.  */
+  int (*supports_btrace) (void);
+
+  /* Enable branch tracing for @ptid and allocate a branch trace target
+     information struct for reading and for disabling branch trace.  */
+  struct btrace_target_info *(*enable_btrace) (ptid_t ptid);
+
+  /* Disable branch tracing.  */
+  int (*disable_btrace) (struct btrace_target_info *tinfo);
+
+  /* Read branch trace data into buffer.  We use an int to specify the type
+     to break a cyclic dependency.  */
+  void (*read_btrace) (struct btrace_target_info *, struct buffer *, int type);
+
 };
 
 extern struct target_ops *the_target;
@@ -520,6 +537,18 @@ int kill_inferior (int);
   (the_target->supports_agent ? \
    (*the_target->supports_agent) () : 0)
 
+#define target_supports_btrace() \
+  (the_target->supports_btrace ? (*the_target->supports_btrace) () : 0)
+
+#define target_enable_btrace(ptid) \
+  (*the_target->enable_btrace) (ptid)
+
+#define target_disable_btrace(tinfo) \
+  (*the_target->disable_btrace) (tinfo)
+
+#define target_read_btrace(tinfo, buffer, type)        \
+  (*the_target->read_btrace) (tinfo, buffer, type)
+
 /* Start non-stop mode, returns 0 on success, -1 on failure.   */
 
 int start_non_stop (int nonstop);
index 4978fca99db4b2518f6c955cebf5341555716925..8fc6b85fdef759105644730a11c94647e3ac92f8 100644 (file)
@@ -68,6 +68,7 @@
 #include "ax.h"
 #include "ax-gdb.h"
 #include "agent.h"
+#include "btrace.h"
 
 /* Temp hacks for tracepoint encoding migration.  */
 static char *target_buf;
@@ -1281,6 +1282,9 @@ enum {
   PACKET_QDisableRandomization,
   PACKET_QAgent,
   PACKET_QTBuffer_size,
+  PACKET_Qbtrace_off,
+  PACKET_Qbtrace_bts,
+  PACKET_qXfer_btrace,
   PACKET_MAX
 };
 
@@ -3994,6 +3998,10 @@ static struct protocol_feature remote_protocol_features[] = {
     remote_supported_packet, PACKET_QTBuffer_size},
   { "tracenz", PACKET_DISABLE,
     remote_string_tracing_feature, -1 },
+  { "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
+  { "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
+  { "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
+    PACKET_qXfer_btrace }
 };
 
 static char *remote_support_xml;
@@ -8795,6 +8803,10 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
       return remote_read_qxfer (ops, "uib", annex, readbuf, offset, len,
                                &remote_protocol_packets[PACKET_qXfer_uib]);
 
+    case TARGET_OBJECT_BTRACE:
+      return remote_read_qxfer (ops, "btrace", annex, readbuf, offset, len,
+        &remote_protocol_packets[PACKET_qXfer_btrace]);
+
     default:
       return -1;
     }
@@ -11146,6 +11158,150 @@ remote_can_use_agent (void)
   return (remote_protocol_packets[PACKET_QAgent].support != PACKET_DISABLE);
 }
 
+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 (&current_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;
+}
+
 static void
 init_remote_ops (void)
 {
@@ -11263,6 +11419,11 @@ Specify the serial device it is connected to\n\
   remote_ops.to_traceframe_info = remote_traceframe_info;
   remote_ops.to_use_agent = remote_use_agent;
   remote_ops.to_can_use_agent = remote_can_use_agent;
+  remote_ops.to_supports_btrace = remote_supports_btrace;
+  remote_ops.to_enable_btrace = remote_enable_btrace;
+  remote_ops.to_disable_btrace = remote_disable_btrace;
+  remote_ops.to_teardown_btrace = remote_teardown_btrace;
+  remote_ops.to_read_btrace = remote_read_btrace;
 }
 
 /* Set up the extended remote vector by making a copy of the standard
@@ -11790,6 +11951,15 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_QTBuffer_size],
                         "QTBuffer:size", "trace-buffer-size", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_off],
+       "Qbtrace:off", "disable-btrace", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_bts],
+       "Qbtrace:bts", "enable-btrace", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
+       "qXfer:btrace", "read-btrace", 0);
+
   /* Keep the old ``set remote Z-packet ...'' working.  Each individual
      Z sub-packet has its own set and show commands, but users may
      have sets to this variable in their .gdbinit files (or in their
index 05a3ad167b4b542ecb95041056707d5bd6982389..ceecca4f321d2c776fd33b253b27f50266a0b467 100644 (file)
@@ -288,6 +288,8 @@ enum target_object
   TARGET_OBJECT_DARWIN_DYLD_INFO,
   /* OpenVMS Unwind Information Block.  */
   TARGET_OBJECT_OPENVMS_UIB,
+  /* Branch trace data, in XML format.  */
+  TARGET_OBJECT_BTRACE
   /* Possible future objects: TARGET_OBJECT_FILE, ...  */
 };