From 9accd112a61b0eaee2724185171761707b4f53e1 Mon Sep 17 00:00:00 2001 From: Markus Metzger Date: Mon, 11 Mar 2013 08:35:11 +0000 Subject: [PATCH] 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 ): 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. --- gdb/ChangeLog | 16 ++++ gdb/gdbserver/ChangeLog | 28 ++++++ gdb/gdbserver/config.in | 3 + gdb/gdbserver/configure | 6 ++ gdb/gdbserver/configure.ac | 5 ++ gdb/gdbserver/configure.srv | 6 +- gdb/gdbserver/gdbthread.h | 5 ++ gdb/gdbserver/inferiors.c | 3 + gdb/gdbserver/linux-low.c | 57 ++++++++++++ gdb/gdbserver/server.c | 161 ++++++++++++++++++++++++++++++++++ gdb/gdbserver/target.h | 29 ++++++ gdb/remote.c | 170 ++++++++++++++++++++++++++++++++++++ gdb/target.h | 2 + 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,3 +1,19 @@ +2013-03-11 Markus Metzger + + * 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 ): 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 * features/btrace.dtd: New file. diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index b26f85bac9e..9a5ae02a4fb 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,31 @@ +2013-03-11 Markus Metzger + + * 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 * server.c (handle_qxfer): Preserve error message if -3 is 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 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, "\n"); + buffer_grow_str (buffer, "\n"); + + for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++) + buffer_xml_printf (buffer, "\n", + paddress (block->begin), paddress (block->end)); + + buffer_grow_str (buffer, "\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 #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 (¤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; +} + 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, ... */ }; -- 2.39.2