aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorMarkus Metzger <mmetzger@sourceware.org>2013-03-11 08:35:11 +0000
committerMarkus Metzger <mmetzger@sourceware.org>2013-03-11 08:35:11 +0000
commit9accd112a61b0eaee2724185171761707b4f53e1 (patch)
treeb013f3c141d0cc1e19ed02d848b90d215b89871f /gdb
parentPreserve a verbose error message of xfer functions if they return -3. (diff)
downloadbinutils-gdb-9accd112a61b0eaee2724185171761707b4f53e1.tar.gz
binutils-gdb-9accd112a61b0eaee2724185171761707b4f53e1.tar.bz2
binutils-gdb-9accd112a61b0eaee2724185171761707b4f53e1.zip
Add the gdb remote target operations for branch tracing.
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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog16
-rw-r--r--gdb/gdbserver/ChangeLog28
-rw-r--r--gdb/gdbserver/config.in3
-rwxr-xr-xgdb/gdbserver/configure6
-rw-r--r--gdb/gdbserver/configure.ac5
-rw-r--r--gdb/gdbserver/configure.srv6
-rw-r--r--gdb/gdbserver/gdbthread.h5
-rw-r--r--gdb/gdbserver/inferiors.c3
-rw-r--r--gdb/gdbserver/linux-low.c57
-rw-r--r--gdb/gdbserver/server.c161
-rw-r--r--gdb/gdbserver/target.h29
-rw-r--r--gdb/remote.c170
-rw-r--r--gdb/target.h2
13 files changed, 489 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 426d631a5a6..0dc837ec215 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,21 @@
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.
* Makefile.in (XMLFILES): Add btrace.dtd.
* btrace.h (parse_xml_btrace): New declaration.
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index b26f85bac9e..9a5ae02a4fb 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,33 @@
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
returned.
(qxfer): Document the -3 return value.
diff --git a/gdb/gdbserver/config.in b/gdb/gdbserver/config.in
index a7c5445c2f9..738c32224db 100644
--- a/gdb/gdbserver/config.in
+++ b/gdb/gdbserver/config.in
@@ -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
diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure
index f37f802d64c..da257bb76a2 100755
--- a/gdb/gdbserver/configure
+++ b/gdb/gdbserver/configure
@@ -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; }
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index 0b30858b0d9..f6227d1378a 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -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)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 0bda563be6b..271a0fee962 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -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"
diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index 85951d2a599..5d4955b5d15 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -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;
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index ba3c6cd5905..6953d0e170b 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -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);
}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 5f036284a92..b5084c93673 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -84,6 +84,10 @@
#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
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 9592c69e0a7..6bb36d87c37 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -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;
}
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index cc9a9102330..f257459b143 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -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);
diff --git a/gdb/remote.c b/gdb/remote.c
index 4978fca99db..8fc6b85fdef 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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
diff --git a/gdb/target.h b/gdb/target.h
index 05a3ad167b4..ceecca4f321 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -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, ... */
};