[PATCH v2 04/13] record btrace: add configuration struct

Markus Metzger markus.t.metzger@intel.com
Thu Nov 20 10:47:00 GMT 2014


Add a struct to describe the branch trace configuration and use it for
enabling branch tracing.

The user will be able to set configuration fields for each tracing format
to be used for new threads.

The actual configuration that is active for a given thread will be shown
in the "info record" command.

At the moment, the configuration struct only contains a format field
that is set to the only available format.

The format is the only configuration option that can not be set via set
commands.  It is given as argument to the "record btrace" command when
starting recording.

CC: Eli Zaretskii  <eliz@gnu.org>

2014-11-20  Markus Metzger  <markus.t.metzger@intel.com>

	* Makefile.in (XMLFILES): Add btrace-conf.dtd.
	* x86-linux-nat.c (x86_linux_enable_btrace): Update parameters.
	(x86_linux_btrace_conf): New.
	(x86_linux_create_target): Initialize to_btrace_conf.
	* nat/linux-btrace.c (linux_enable_btrace): Update parameters.
	Check format.  Split into this and ...
	(linux_enable_bts): ... this.
	(linux_btrace_conf): New.
	(perf_event_skip_record): Renamed into ...
	(perf_event_skip_bts_record): ... this.  Updated users.
	(linux_disable_btrace): Split into this and ...
	(linux_disable_bts): ... this.
	(linux_read_btrace): Check format.
	* nat/linux-btrace.h (linux_enable_btrace): Update parameters.
	(linux_btrace_conf): New.
	(btrace_target_info)<ptid>: Moved.
	(btrace_target_info)<conf>: New.
	(btrace_target_info): Split into this and ...
	(btrace_tinfo_bts): ... this.  Updated users.
	* btrace.c (btrace_enable): Update parameters.
	(btrace_conf, parse_xml_btrace_conf_bts, parse_xml_btrace_conf)
	(btrace_conf_children, btrace_conf_attributes)
	(btrace_conf_elements): New.
	* btrace.h (btrace_enable): Update parameters.
	(btrace_conf, parse_xml_btrace_conf): New.
	* common/btrace-common.h (btrace_config): New.
	* feature/btrace-conf.dtd: New.
	* record-btrace.c (record_btrace_conf): New.
	(record_btrace_cmdlist): New.
	(record_btrace_enable_warn, record_btrace_open): Pass
	&record_btrace_conf.
	(record_btrace_info): Print recording format.
	(cmd_record_btrace_bts_start): New.
	(cmd_record_btrace_start): Call cmd_record_btrace_bts_start.
	(_initialize_record_btrace): Add "record btrace bts" subcommand.
	Add "record bts" alias command.
	* remote.c (remote_state)<btrace_config>: New.
	(remote_btrace_reset, PACKET_qXfer_btrace_conf): New.
	(remote_protocol_features): Add qXfer:btrace-conf:read.
	(remote_open_1): Call remote_btrace_reset.
	(remote_xfer_partial): Handle TARGET_OBJECT_BTRACE_CONF.
	(btrace_target_info)<conf>: New.
	(btrace_sync_conf, btrace_read_config): New.
	(remote_enable_btrace): Update parameters.  Call btrace_sync_conf and
	btrace_read_conf.
	(remote_btrace_conf): New.
	(init_remote_ops): Initialize to_btrace_conf.
	(_initialize_remote): Add qXfer:btrace-conf packet.
	* target.c (target_enable_btrace): Update parameters.
	(target_btrace_conf): New.
	* target.h (target_enable_btrace): Update parameters.
	(target_btrace_conf): New.
	(target_object)<TARGET_OBJECT_BTRACE_CONF>: New.
	(target_ops)<to_enable_btrace>: Update parameters and comment.
	(target_ops)<to_btrace_conf>: New.
	* target-delegates: Regenerate.
	* target-debug.h (target_debug_print_const_struct_btrace_config_p)
	(target_debug_print_const_struct_btrace_target_info_p): New.
	NEWS: Announce new command and new packet.

doc/
	* gdb.texinfo (Process Record and Replay): Describe the "record
	btrace bts" command.
	(General Query Packets): Describe qXfer:btrace-conf:read packet.
	(Branch Trace Configuration Format): New.

gdbserver/
	* linux-low.c (linux_low_enable_btrace): Update parameters.
	(linux_low_btrace_conf): New.
	(linux_target_ops)<to_btrace_conf>: Initialize.
	* server.c (current_btrace_conf): New.
	(handle_btrace_enable): Rename to ...
	(handle_btrace_enable_bts): ... this.  Pass &current_btrace_conf
	to target_enable_btrace.  Update comment.  Update users.
	(handle_qxfer_btrace_conf): New.
    (qxfer_packets): Add btrace-conf entry.
	(handle_query): Report qXfer:btrace-conf:read as supported packet.
	* target.h (target_ops)<enable_btrace>: Update parameters and comment.
	(target_ops)<read_btrace_conf>: New.
	(target_enable_btrace): Update parameters.
	(target_read_btrace_conf): New.

testsuite/
	* gdb.btrace/delta.exp: Update "info record" output.
	* gdb.btrace/enable.exp: Update "info record" output.
	* gdb.btrace/finish.exp: Update "info record" output.
	* gdb.btrace/instruction_history.exp: Update "info record" output.
	* gdb.btrace/next.exp: Update "info record" output.
	* gdb.btrace/nexti.exp: Update "info record" output.
	* gdb.btrace/step.exp: Update "info record" output.
	* gdb.btrace/stepi.exp: Update "info record" output.
	* gdb.btrace/nohist.exp: Update "info record" output.
---
 gdb/Makefile.in                                  |   2 +-
 gdb/NEWS                                         |   9 ++
 gdb/btrace.c                                     |  71 +++++++++++-
 gdb/btrace.h                                     |  11 +-
 gdb/common/btrace-common.h                       |  11 ++
 gdb/doc/gdb.texinfo                              |  70 +++++++++++-
 gdb/features/btrace-conf.dtd                     |  10 ++
 gdb/gdbserver/linux-low.c                        |  35 +++++-
 gdb/gdbserver/server.c                           |  78 ++++++++++++-
 gdb/gdbserver/target.h                           |  19 ++-
 gdb/nat/linux-btrace.c                           | 140 +++++++++++++++++------
 gdb/nat/linux-btrace.h                           |  35 ++++--
 gdb/record-btrace.c                              |  69 +++++++++--
 gdb/remote.c                                     |  85 +++++++++++++-
 gdb/target-debug.h                               |   4 +
 gdb/target-delegates.c                           |  45 +++++++-
 gdb/target.c                                     |  12 +-
 gdb/target.h                                     |  24 +++-
 gdb/testsuite/gdb.btrace/delta.exp               |   4 +
 gdb/testsuite/gdb.btrace/enable.exp              |   4 +-
 gdb/testsuite/gdb.btrace/finish.exp              |   1 +
 gdb/testsuite/gdb.btrace/instruction_history.exp |   2 +-
 gdb/testsuite/gdb.btrace/next.exp                |   2 +
 gdb/testsuite/gdb.btrace/nexti.exp               |   2 +
 gdb/testsuite/gdb.btrace/nohist.exp              |   1 +
 gdb/testsuite/gdb.btrace/step.exp                |   2 +
 gdb/testsuite/gdb.btrace/stepi.exp               |   2 +
 gdb/x86-linux-nat.c                              |  16 ++-
 28 files changed, 676 insertions(+), 90 deletions(-)
 create mode 100644 gdb/features/btrace-conf.dtd

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 344ff94..e7181c4 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -581,7 +581,7 @@ XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
 	$(srcdir)/features/library-list-aix.dtd \
 	$(srcdir)/features/library-list-svr4.dtd $(srcdir)/features/osdata.dtd \
 	$(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd \
-	$(srcdir)/features/btrace.dtd
+	$(srcdir)/features/btrace.dtd $(srcdir)/features/btrace-conf.dtd
 
 # This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
 # interface to the serial port.  Hopefully if get ported to OS/2, VMS,
diff --git a/gdb/NEWS b/gdb/NEWS
index d6a8b61..689eaa1 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -27,6 +27,10 @@
 queue-signal signal-name-or-number
   Queue a signal to be delivered to the thread when it is resumed.
 
+record btrace bts
+record bts
+  Start branch trace recording using Intel(R) Branch Trace Store format.
+
 * On resume, GDB now always passes the signal the program had stopped
   for to the thread the signal was sent to, even if the user changed
   threads before resuming.  Previously GDB would often (but not
@@ -60,6 +64,11 @@ SGI Irix-6.x				mips-*-irix6*
 VAX running (4.2 - 4.3 Reno) BSD 	vax-*-bsd*
 VAX running Ultrix 			vax-*-ultrix*
 
+* New remote packets
+
+qXfer:btrace-conf:read
+  Return the branch trace configuration for the current thread.
+
 *** Changes in GDB 7.8
 
 * New command line options
diff --git a/gdb/btrace.c b/gdb/btrace.c
index d8dae56..6b50be7 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -726,17 +726,17 @@ btrace_add_pc (struct thread_info *tp)
 /* See btrace.h.  */
 
 void
-btrace_enable (struct thread_info *tp)
+btrace_enable (struct thread_info *tp, const struct btrace_config *conf)
 {
   if (tp->btrace.target != NULL)
     return;
 
-  if (!target_supports_btrace (BTRACE_FORMAT_BTS))
+  if (!target_supports_btrace (conf->format))
     error (_("Target does not support branch tracing."));
 
   DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
 
-  tp->btrace.target = target_enable_btrace (tp->ptid);
+  tp->btrace.target = target_enable_btrace (tp->ptid, conf);
 
   /* Add an entry for the current PC so we start tracing from where we
      enabled it.  */
@@ -746,6 +746,17 @@ btrace_enable (struct thread_info *tp)
 
 /* See btrace.h.  */
 
+const struct btrace_config *
+btrace_conf (const struct btrace_thread_info *btinfo)
+{
+  if (btinfo->target == NULL)
+    return NULL;
+
+  return target_btrace_conf (btinfo->target);
+}
+
+/* See btrace.h.  */
+
 void
 btrace_disable (struct thread_info *tp)
 {
@@ -1106,6 +1117,60 @@ parse_xml_btrace (struct btrace_data *btrace, const char *buffer)
 #endif  /* !defined (HAVE_LIBEXPAT) */
 }
 
+#if defined (HAVE_LIBEXPAT)
+
+/* Parse a btrace-conf "bts" xml record.  */
+
+static void
+parse_xml_btrace_conf_bts (struct gdb_xml_parser *parser,
+			  const struct gdb_xml_element *element,
+			  void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_config *conf;
+
+  conf = user_data;
+  conf->format = BTRACE_FORMAT_BTS;
+}
+
+static const struct gdb_xml_element btrace_conf_children[] = {
+  { "bts", NULL, NULL, GDB_XML_EF_OPTIONAL, parse_xml_btrace_conf_bts, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute btrace_conf_attributes[] = {
+  { "version", GDB_XML_AF_NONE, NULL, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_conf_elements[] = {
+  { "btrace-conf", btrace_conf_attributes, btrace_conf_children,
+    GDB_XML_EF_NONE, NULL, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+#endif /* defined (HAVE_LIBEXPAT) */
+
+/* See btrace.h.  */
+
+void
+parse_xml_btrace_conf (struct btrace_config *conf, const char *xml)
+{
+  int errcode;
+
+#if defined (HAVE_LIBEXPAT)
+
+  errcode = gdb_xml_parse_quick (_("btrace-conf"), "btrace-conf.dtd",
+				 btrace_conf_elements, xml, conf);
+  if (errcode != 0)
+    error (_("Error parsing branch trace configuration."));
+
+#else  /* !defined (HAVE_LIBEXPAT) */
+
+  error (_("XML parsing is not supported."));
+
+#endif  /* !defined (HAVE_LIBEXPAT) */
+}
+
 /* See btrace.h.  */
 
 const struct btrace_insn *
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 3954581..8656cda 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -215,7 +215,13 @@ struct btrace_thread_info
 };
 
 /* Enable branch tracing for a thread.  */
-extern void btrace_enable (struct thread_info *tp);
+extern void btrace_enable (struct thread_info *tp,
+			   const struct btrace_config *conf);
+
+/* Get the branch trace configuration for a thread.
+   Return NULL if branch tracing is not enabled for that thread.  */
+extern const struct btrace_config *
+  btrace_conf (const struct btrace_thread_info *);
 
 /* Disable branch tracing for a thread.
    This will also delete the current branch trace data.  */
@@ -238,6 +244,9 @@ extern void btrace_free_objfile (struct objfile *);
 /* Parse a branch trace xml document XML into DATA.  */
 extern void parse_xml_btrace (struct btrace_data *data, const char *xml);
 
+/* Parse a branch trace configuration xml document XML into CONF.  */
+extern void parse_xml_btrace_conf (struct btrace_config *conf, const char *xml);
+
 /* Dereference a branch trace instruction iterator.  Return a pointer to the
    instruction the iterator points to.  */
 extern const struct btrace_insn *
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 27e7a95..1e0e595 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -62,6 +62,17 @@ enum btrace_format
   BTRACE_FORMAT_BTS
 };
 
+/* A branch tracing configuration.
+
+   This describes the requested configuration as well as the actually
+   obtained configuration.  */
+
+struct btrace_config
+{
+  /* The branch tracing format.  */
+  enum btrace_format format;
+};
+
 /* Branch trace in BTS format.  */
 struct btrace_data_bts
 {
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 15c2908..121ae5b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6337,9 +6337,13 @@ For architecture environments that support process record and replay,
 @kindex record
 @kindex record full
 @kindex record btrace
+@kindex record btrace bts
+@kindex record bts
 @kindex rec
 @kindex rec full
 @kindex rec btrace
+@kindex rec btrace bts
+@kindex rec bts
 @item record @var{method}
 This command starts the process record and replay target.  The
 recording method can be specified as parameter.  Without a parameter
@@ -6352,13 +6356,24 @@ Full record/replay recording using @value{GDBN}'s software record and
 replay implementation.  This method allows replaying and reverse
 execution.
 
-@item btrace
+@item btrace @var{format}
 Hardware-supported instruction recording.  This method does not record
 data.  Further, the data is collected in a ring buffer so old data will
 be overwritten when the buffer is full.  It allows limited replay and
 reverse execution.
 
-This recording method may not be available on all processors.
+The recording format can be specified as parameter.  Without a parameter
+the command chooses the recording format.  The following recording
+formats are available:
+
+@table @code
+@item bts
+Use Intel's Branch Trace Store (BTS) recording format.  In this format,
+the processor stores a from/to record for each executed branch in the
+btrace ring buffer.
+@end table
+
+Not all recording formats may be available on all processors.
 @end table
 
 The process record and replay target can only debug a process that is
@@ -6536,9 +6551,9 @@ Maximum number of instructions that may be contained in the execution log.
 @end itemize
 
 @item btrace
-For the @code{btrace} recording method, it shows the number of
-instructions that have been recorded and the number of blocks of
-sequential control-flow that is formed by the recorded instructions.
+For the @code{btrace} recording method, it shows the recording format,
+the number of instructions that have been recorded and the number of blocks
+of sequential control-flow that is formed by the recorded instructions.
 @end table
 
 @kindex record delete
@@ -32699,7 +32714,8 @@ MS-Windows shared libraries (@pxref{Shared Libraries})
 @item
 Traceframe info (@pxref{Traceframe Info Format})
 @item
-Branch trace (@pxref{Branch Trace Format})
+Branch trace (@pxref{Branch Trace Format},
+@pxref{Branch Trace Configuration Format})
 @end itemize
 
 @item zlib
@@ -33677,6 +33693,7 @@ Show the current setting of the target wait timeout.
 * Thread List Format::
 * Traceframe Info Format::
 * Branch Trace Format::
+* Branch Trace Configuration Format::
 @end menu
 
 @node Overview
@@ -35349,6 +35366,11 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab Yes
 
+@item @samp{qXfer:btrace-conf:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
 @item @samp{qXfer:features:read}
 @tab No
 @tab @samp{-}
@@ -35533,6 +35555,10 @@ The remote stub understands the @samp{qXfer:auxv:read} packet
 The remote stub understands the @samp{qXfer:btrace:read}
 packet (@pxref{qXfer btrace read}).
 
+@item qXfer:btrace-conf:read
+The remote stub understands the @samp{qXfer:btrace-conf:read}
+packet (@pxref{qXfer btrace-conf read}).
+
 @item qXfer:features:read
 The remote stub understands the @samp{qXfer:features:read} packet
 (@pxref{qXfer target description read}).
@@ -35827,6 +35853,15 @@ If the trace buffer overflowed, returns an error indicating the overflow.
 This packet is not probed by default; the remote stub must request it
 by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
 
+@item qXfer:btrace-conf:read::@var{offset},@var{length}
+@anchor{qXfer btrace-conf read}
+
+Return a description of the current branch trace configuration.
+@xref{Branch Trace Configuration Format}.
+
+This packet is not probed by default; the remote stub must request it
+by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+
 @item qXfer:features:read:@var{annex}:@var{offset},@var{length}
 @anchor{qXfer target description read}
 Access the @dfn{target description}.  @xref{Target Descriptions}.  The
@@ -38631,6 +38666,29 @@ The formal DTD for the branch trace format is given below:
                        end    CDATA   #REQUIRED>
 @end smallexample
 
+@node Branch Trace Configuration Format
+@section Branch Trace Configuration Format
+@cindex branch trace configuration format
+
+For each inferior thread, @value{GDBN} can obtain the branch trace
+configuration using the @samp{qXfer:btrace-conf:read}
+(@pxref{qXfer btrace-conf read}) packet.
+
+The configuration describes the branch trace format and configuration
+settings for that format.
+
+@value{GDBN} must be linked with the Expat library to support XML
+branch trace configuration discovery.  @xref{Expat}.
+
+The formal DTD for the branch trace configuration format is given below:
+
+@smallexample
+<!ELEMENT btrace-conf	(bts?)>
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
+
+<!ELEMENT bts	EMPTY>
+@end smallexample
+
 @include agentexpr.texi
 
 @node Target Descriptions
diff --git a/gdb/features/btrace-conf.dtd b/gdb/features/btrace-conf.dtd
new file mode 100644
index 0000000..e9cb2ef
--- /dev/null
+++ b/gdb/features/btrace-conf.dtd
@@ -0,0 +1,10 @@
+<!-- Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!ELEMENT btrace-conf	(bts?)>
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
+
+<!ELEMENT bts	EMPTY>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index dcaa829..8a706a8 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5935,11 +5935,11 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
 /* See to_enable_btrace target method.  */
 
 static struct btrace_target_info *
-linux_low_enable_btrace (ptid_t ptid)
+linux_low_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
 {
   struct btrace_target_info *tinfo;
 
-  tinfo = linux_enable_btrace (ptid);
+  tinfo = linux_enable_btrace (ptid, conf);
 
   if (tinfo != NULL)
     {
@@ -6017,6 +6017,35 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
   btrace_data_fini (&btrace);
   return 0;
 }
+
+/* See to_btrace_conf target method.  */
+
+static int
+linux_low_btrace_conf (const struct btrace_target_info *tinfo,
+		       struct buffer *buffer)
+{
+  const struct btrace_config *conf;
+
+  buffer_grow_str (buffer, "<!DOCTYPE btrace-conf SYSTEM \"btrace-conf.dtd\">\n");
+  buffer_grow_str (buffer, "<btrace-conf version=\"1.0\">\n");
+
+  conf = linux_btrace_conf (tinfo);
+  if (conf != NULL)
+    {
+      switch (conf->format)
+	{
+	case BTRACE_FORMAT_NONE:
+	  break;
+
+	case BTRACE_FORMAT_BTS:
+	  buffer_xml_printf (buffer, "<bts/>\n");
+	  break;
+	}
+    }
+
+  buffer_grow_str0 (buffer, "</btrace-conf>\n");
+  return 0;
+}
 #endif /* HAVE_LINUX_BTRACE */
 
 static struct target_ops linux_target_ops = {
@@ -6091,11 +6120,13 @@ static struct target_ops linux_target_ops = {
   linux_low_enable_btrace,
   linux_low_disable_btrace,
   linux_low_read_btrace,
+  linux_low_btrace_conf,
 #else
   NULL,
   NULL,
   NULL,
   NULL,
+  NULL,
 #endif
   linux_supports_range_stepping,
 };
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index dae364d..b8359e6 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -122,6 +122,10 @@ struct vstop_notif
   struct target_waitstatus status;
 };
 
+/* The current btrace configuration.  This is gdbserver's mirror of GDB's
+   btrace configuration.  */
+static struct btrace_config current_btrace_conf;
+
 DEFINE_QUEUE_P (notif_event_p);
 
 /* Put a stop reply to the stop reply queue.  */
@@ -381,15 +385,17 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more)
 			       PBUFSIZ - 2) + 1;
 }
 
-/* Handle btrace enabling.  */
+/* Handle btrace enabling in BTS format.  */
 
 static const char *
-handle_btrace_enable (struct thread_info *thread)
+handle_btrace_enable_bts (struct thread_info *thread)
 {
   if (thread->btrace != NULL)
     return "E.Btrace already enabled.";
 
-  thread->btrace = target_enable_btrace (thread->entry.id);
+  current_btrace_conf.format = BTRACE_FORMAT_BTS;
+  thread->btrace = target_enable_btrace (thread->entry.id,
+					 &current_btrace_conf);
   if (thread->btrace == NULL)
     return "E.Could not enable btrace.";
 
@@ -443,7 +449,7 @@ handle_btrace_general_set (char *own_buf)
   err = NULL;
 
   if (strcmp (op, "bts") == 0)
-    err = handle_btrace_enable (thread);
+    err = handle_btrace_enable_bts (thread);
   else if (strcmp (op, "off") == 0)
     err = handle_btrace_disable (thread);
   else
@@ -1510,10 +1516,73 @@ handle_qxfer_btrace (const char *annex,
   return len;
 }
 
+/* Handle qXfer:btrace-conf:read.  */
+
+static int
+handle_qxfer_btrace_conf (const char *annex,
+			  gdb_byte *readbuf, const gdb_byte *writebuf,
+			  ULONGEST offset, LONGEST len)
+{
+  static struct buffer cache;
+  struct thread_info *thread;
+  int result;
+
+  if (the_target->read_btrace_conf == NULL || writebuf != NULL)
+    return -2;
+
+  if (annex[0] != '\0' || !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 (offset == 0)
+    {
+      buffer_free (&cache);
+
+      result = target_read_btrace_conf (thread->btrace, &cache);
+      if (result != 0)
+	{
+	  memcpy (own_buf, cache.buffer, cache.used_size);
+	  return -3;
+	}
+    }
+  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 },
+    { "btrace-conf", handle_qxfer_btrace_conf },
     { "fdpic", handle_qxfer_fdpic},
     { "features", handle_qxfer_features },
     { "libraries", handle_qxfer_libraries },
@@ -1698,6 +1767,7 @@ supported_btrace_packets (char *buf)
 
   strcat (buf, ";Qbtrace:off+");
   strcat (buf, ";qXfer:btrace:read+");
+  strcat (buf, ";qXfer:btrace-conf:read+");
 }
 
 /* Handle all of the extended 'q' packets.  */
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index dd5b07a..b877df8 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -360,9 +360,10 @@ struct target_ops
   /* Check whether the target supports branch tracing.  */
   int (*supports_btrace) (struct target_ops *, enum btrace_format);
 
-  /* 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);
+  /* Enable branch tracing for PTID based on CONF and allocate a branch trace
+     target information struct for reading and for disabling branch trace.  */
+  struct btrace_target_info *(*enable_btrace)
+    (ptid_t ptid, const struct btrace_config *conf);
 
   /* Disable branch tracing.
      Returns zero on success, non-zero otherwise.  */
@@ -374,6 +375,11 @@ struct target_ops
      otherwise.  */
   int (*read_btrace) (struct btrace_target_info *, struct buffer *, int type);
 
+  /* Read the branch trace configuration into BUFFER.
+     Return 0 on success; print an error message into BUFFER and return -1
+     otherwise.  */
+  int (*read_btrace_conf) (const struct btrace_target_info *, struct buffer *);
+
   /* Return true if target supports range stepping.  */
   int (*supports_range_stepping) (void);
 };
@@ -503,8 +509,8 @@ int kill_inferior (int);
   (the_target->supports_btrace				\
    ? (*the_target->supports_btrace) (the_target, format) : 0)
 
-#define target_enable_btrace(ptid) \
-  (*the_target->enable_btrace) (ptid)
+#define target_enable_btrace(ptid, conf) \
+  (*the_target->enable_btrace) (ptid, conf)
 
 #define target_disable_btrace(tinfo) \
   (*the_target->disable_btrace) (tinfo)
@@ -512,6 +518,9 @@ int kill_inferior (int);
 #define target_read_btrace(tinfo, buffer, type)	\
   (*the_target->read_btrace) (tinfo, buffer, type)
 
+#define target_read_btrace_conf(tinfo, buffer)	\
+  (*the_target->read_btrace_conf) (tinfo, buffer)
+
 #define target_supports_range_stepping() \
   (the_target->supports_range_stepping ? \
    (*the_target->supports_range_stepping) () : 0)
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 1976512..c369483 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -90,8 +90,8 @@ perf_event_is_kernel_addr (const struct btrace_target_info *tinfo,
 /* Check whether a perf event record should be skipped.  */
 
 static inline int
-perf_event_skip_record (const struct btrace_target_info *tinfo,
-			const struct perf_event_bts *bts)
+perf_event_skip_bts_record (const struct btrace_target_info *tinfo,
+			    const struct perf_event_bts *bts)
 {
   /* The hardware may report branches from kernel into user space.  Branches
      from user into kernel space will be suppressed.  We filter the former to
@@ -194,7 +194,7 @@ perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
 	  break;
 	}
 
-      if (perf_event_skip_record (tinfo, &psample->bts))
+      if (perf_event_skip_bts_record (tinfo, &psample->bts))
 	continue;
 
       /* We found a valid sample, so we can complete the current block.  */
@@ -395,39 +395,42 @@ linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
   internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
 }
 
-/* See linux-btrace.h.  */
+/* Enable branch tracing in BTS format.  */
 
-struct btrace_target_info *
-linux_enable_btrace (ptid_t ptid)
+static struct btrace_target_info *
+linux_enable_bts (ptid_t ptid, const struct btrace_config *conf)
 {
   struct perf_event_mmap_page *header;
   struct btrace_target_info *tinfo;
+  struct btrace_tinfo_bts *bts;
   int pid, pg;
 
   tinfo = xzalloc (sizeof (*tinfo));
   tinfo->ptid = ptid;
+  tinfo->ptr_bits = 0;
 
-  tinfo->attr.size = sizeof (tinfo->attr);
-  tinfo->attr.type = PERF_TYPE_HARDWARE;
-  tinfo->attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
-  tinfo->attr.sample_period = 1;
+  tinfo->conf.format = BTRACE_FORMAT_BTS;
+  bts = &tinfo->variant.bts;
 
-  /* We sample from and to address.  */
-  tinfo->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
+  bts->attr.size = sizeof (bts->attr);
+  bts->attr.type = PERF_TYPE_HARDWARE;
+  bts->attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS;
+  bts->attr.sample_period = 1;
 
-  tinfo->attr.exclude_kernel = 1;
-  tinfo->attr.exclude_hv = 1;
-  tinfo->attr.exclude_idle = 1;
+  /* We sample from and to address.  */
+  bts->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
 
-  tinfo->ptr_bits = 0;
+  bts->attr.exclude_kernel = 1;
+  bts->attr.exclude_hv = 1;
+  bts->attr.exclude_idle = 1;
 
   pid = ptid_get_lwp (ptid);
   if (pid == 0)
     pid = ptid_get_pid (ptid);
 
   errno = 0;
-  tinfo->file = syscall (SYS_perf_event_open, &tinfo->attr, pid, -1, -1, 0);
-  if (tinfo->file < 0)
+  bts->file = syscall (SYS_perf_event_open, &bts->attr, pid, -1, -1, 0);
+  if (bts->file < 0)
     goto err;
 
   /* We try to allocate as much buffer as we can get.
@@ -437,7 +440,7 @@ linux_enable_btrace (ptid_t ptid)
     {
       /* The number of pages we request needs to be a power of two.  */
       header = mmap (NULL, ((1 << pg) + 1) * PAGE_SIZE, PROT_READ, MAP_SHARED,
-		     tinfo->file, 0);
+		     bts->file, 0);
       if (header != MAP_FAILED)
 	break;
     }
@@ -445,17 +448,17 @@ linux_enable_btrace (ptid_t ptid)
   if (header == MAP_FAILED)
     goto err_file;
 
-  tinfo->header = header;
-  tinfo->bts.mem = ((const uint8_t *) header) + PAGE_SIZE;
-  tinfo->bts.size = (1 << pg) * PAGE_SIZE;
-  tinfo->bts.data_head = &header->data_head;
-  tinfo->bts.last_head = 0;
+  bts->header = header;
+  bts->bts.mem = ((const uint8_t *) header) + PAGE_SIZE;
+  bts->bts.size = (1 << pg) * PAGE_SIZE;
+  bts->bts.data_head = &header->data_head;
+  bts->bts.last_head = 0;
 
   return tinfo;
 
  err_file:
   /* We were not able to allocate any buffer.  */
-  close (tinfo->file);
+  close (bts->file);
 
  err:
   xfree (tinfo);
@@ -464,16 +467,60 @@ linux_enable_btrace (ptid_t ptid)
 
 /* See linux-btrace.h.  */
 
-enum btrace_error
-linux_disable_btrace (struct btrace_target_info *tinfo)
+struct btrace_target_info *
+linux_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
+{
+  struct btrace_target_info *tinfo;
+
+  tinfo = NULL;
+  switch (conf->format)
+    {
+    case BTRACE_FORMAT_NONE:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      tinfo = linux_enable_bts (ptid, conf);
+      break;
+    }
+
+  return tinfo;
+}
+
+/* Disable BTS tracing.  */
+
+static enum btrace_error
+linux_disable_bts (struct btrace_tinfo_bts *tinfo)
 {
   munmap((void *) tinfo->header, tinfo->bts.size + PAGE_SIZE);
   close (tinfo->file);
-  xfree (tinfo);
 
   return BTRACE_ERR_NONE;
 }
 
+/* See linux-btrace.h.  */
+
+enum btrace_error
+linux_disable_btrace (struct btrace_target_info *tinfo)
+{
+  enum btrace_error errcode;
+
+  errcode = BTRACE_ERR_NOT_SUPPORTED;
+  switch (tinfo->conf.format)
+    {
+    case BTRACE_FORMAT_NONE:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      errcode = linux_disable_bts (&tinfo->variant.bts);
+      break;
+    }
+
+  if (errcode == BTRACE_ERR_NONE)
+    xfree (tinfo);
+
+  return errcode;
+}
+
 /* Read branch trace data in BTS format for the thread given by TINFO into
    BTRACE using the TYPE reading method.  */
 
@@ -487,7 +534,7 @@ linux_read_bts (struct btrace_data_bts *btrace,
   unsigned long long data_head, data_tail, buffer_size, size;
   size_t retries = 5;
 
-  pevent = &tinfo->bts;
+  pevent = &tinfo->variant.bts.bts;
 
   /* For delta reads, we return at least the partial last block containing
      the current PC.  */
@@ -570,11 +617,28 @@ linux_read_btrace (struct btrace_data *btrace,
 		   struct btrace_target_info *tinfo,
 		   enum btrace_read_type type)
 {
-  /* We read btrace in BTS format.  */
-  btrace->format = BTRACE_FORMAT_BTS;
-  btrace->variant.bts.blocks = NULL;
+  switch (tinfo->conf.format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return BTRACE_ERR_NOT_SUPPORTED;
+
+    case BTRACE_FORMAT_BTS:
+      /* We read btrace in BTS format.  */
+      btrace->format = BTRACE_FORMAT_BTS;
+      btrace->variant.bts.blocks = NULL;
+
+      return linux_read_bts (&btrace->variant.bts, tinfo, type);
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
+
+/* See linux-btrace.h.  */
 
-  return linux_read_bts (&btrace->variant.bts, tinfo, type);
+const struct btrace_config *
+linux_btrace_conf (const struct btrace_target_info *tinfo)
+{
+  return &tinfo->conf;
 }
 
 #else /* !HAVE_LINUX_PERF_EVENT_H */
@@ -590,7 +654,7 @@ linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
 /* See linux-btrace.h.  */
 
 struct btrace_target_info *
-linux_enable_btrace (ptid_t ptid)
+linux_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
 {
   return NULL;
 }
@@ -613,4 +677,12 @@ linux_read_btrace (struct btrace_data *btrace,
   return BTRACE_ERR_NOT_SUPPORTED;
 }
 
+/* See linux-btrace.h.  */
+
+const struct btrace_config *
+linux_btrace_conf (const struct btrace_target_info *tinfo)
+{
+  return NULL;
+}
+
 #endif /* !HAVE_LINUX_PERF_EVENT_H */
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index 01ef934..1e9af88 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -48,18 +48,13 @@ struct perf_event_buffer
   /* The data_head value from the last read.  */
   unsigned long long last_head;
 };
-#endif /* HAVE_LINUX_PERF_EVENT_H */
 
-/* Branch trace target information per thread.  */
-struct btrace_target_info
+/* Branch trace target information for BTS tracing.  */
+struct btrace_tinfo_bts
 {
-#if HAVE_LINUX_PERF_EVENT_H
   /* The Linux perf_event configuration for collecting the branch trace.  */
   struct perf_event_attr attr;
 
-  /* The ptid of this thread.  */
-  ptid_t ptid;
-
   /* The perf event file.  */
   int file;
 
@@ -68,6 +63,25 @@ struct btrace_target_info
 
   /* The BTS perf event buffer.  */
   struct perf_event_buffer bts;
+};
+#endif /* HAVE_LINUX_PERF_EVENT_H */
+
+/* Branch trace target information per thread.  */
+struct btrace_target_info
+{
+  /* The ptid of this thread.  */
+  ptid_t ptid;
+
+  /* The obtained branch trace configuration.  */
+  struct btrace_config conf;
+
+#if HAVE_LINUX_PERF_EVENT_H
+  /* The branch tracing format specific information.  */
+  union
+  {
+    /* CONF.FORMAT == BTRACE_FORMAT_BTS.  */
+    struct btrace_tinfo_bts bts;
+  } variant;
 #endif /* HAVE_LINUX_PERF_EVENT_H */
 
   /* The size of a pointer in bits for this thread.
@@ -80,7 +94,8 @@ struct btrace_target_info
 extern int linux_supports_btrace (struct target_ops *, enum btrace_format);
 
 /* See to_enable_btrace in target.h.  */
-extern struct btrace_target_info *linux_enable_btrace (ptid_t ptid);
+extern struct btrace_target_info *
+  linux_enable_btrace (ptid_t ptid, const struct btrace_config *conf);
 
 /* See to_disable_btrace in target.h.  */
 extern enum btrace_error linux_disable_btrace (struct btrace_target_info *ti);
@@ -90,4 +105,8 @@ extern enum btrace_error linux_read_btrace (struct btrace_data *btrace,
 					    struct btrace_target_info *btinfo,
 					    enum btrace_read_type type);
 
+/* See to_btrace_conf in target.h.  */
+extern const struct btrace_config *
+  linux_btrace_conf (const struct btrace_target_info *);
+
 #endif /* LINUX_BTRACE_H */
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 6bc1d15..d9ad9d4 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -70,6 +70,12 @@ static struct async_event_handler *record_btrace_async_inferior_event_handler;
 /* A flag indicating that we are currently generating a core file.  */
 static int record_btrace_generating_corefile;
 
+/* The current branch trace configuration.  */
+static struct btrace_config record_btrace_conf;
+
+/* Command list for "record btrace".  */
+static struct cmd_list_element *record_btrace_cmdlist;
+
 /* Print a record-btrace debug message.  Use do ... while (0) to avoid
    ambiguities when used in if statements.  */
 
@@ -132,7 +138,7 @@ record_btrace_enable_warn (struct thread_info *tp)
   volatile struct gdb_exception error;
 
   TRY_CATCH (error, RETURN_MASK_ERROR)
-    btrace_enable (tp);
+    btrace_enable (tp, &record_btrace_conf);
 
   if (error.message != NULL)
     warning ("%s", error.message);
@@ -208,7 +214,7 @@ record_btrace_open (const char *args, int from_tty)
   ALL_NON_EXITED_THREADS (tp)
     if (args == NULL || *args == 0 || number_is_in_list (args, tp->num))
       {
-	btrace_enable (tp);
+	btrace_enable (tp, &record_btrace_conf);
 
 	make_cleanup (record_btrace_disable_callback, tp);
       }
@@ -269,6 +275,7 @@ static void
 record_btrace_info (struct target_ops *self)
 {
   struct btrace_thread_info *btinfo;
+  const struct btrace_config *conf;
   struct thread_info *tp;
   unsigned int insns, calls;
 
@@ -278,13 +285,18 @@ record_btrace_info (struct target_ops *self)
   if (tp == NULL)
     error (_("No thread."));
 
+  btinfo = &tp->btrace;
+
+  conf = btrace_conf (btinfo);
+  if (conf != NULL)
+    printf_unfiltered (_("Recording format: %s.\n"),
+		       btrace_format_string (conf->format));
+
   btrace_fetch (tp);
 
   insns = 0;
   calls = 0;
 
-  btinfo = &tp->btrace;
-
   if (!btrace_is_empty (tp))
     {
       struct btrace_call_iterator call;
@@ -1974,15 +1986,48 @@ init_record_btrace_ops (void)
   ops->to_magic = OPS_MAGIC;
 }
 
+/* Start recording in BTS format.  */
+
+static void
+cmd_record_btrace_bts_start (char *args, int from_tty)
+{
+  volatile struct gdb_exception exception;
+
+  if (args != NULL && *args != 0)
+    error (_("Invalid argument."));
+
+  record_btrace_conf.format = BTRACE_FORMAT_BTS;
+
+  TRY_CATCH (exception, RETURN_MASK_ALL)
+    execute_command ("target record-btrace", from_tty);
+
+  if (exception.error != 0)
+    {
+      record_btrace_conf.format = BTRACE_FORMAT_NONE;
+      throw_exception (exception);
+    }
+}
+
 /* Alias for "target record".  */
 
 static void
 cmd_record_btrace_start (char *args, int from_tty)
 {
+  volatile struct gdb_exception exception;
+
   if (args != NULL && *args != 0)
     error (_("Invalid argument."));
 
-  execute_command ("target record-btrace", from_tty);
+  record_btrace_conf.format = BTRACE_FORMAT_BTS;
+
+  TRY_CATCH (exception, RETURN_MASK_ALL)
+    execute_command ("target record-btrace", from_tty);
+
+  if (exception.error == 0)
+    return;
+
+  record_btrace_conf.format = BTRACE_FORMAT_NONE;
+  throw_exception (exception);
 }
 
 /* The "set record btrace" command.  */
@@ -2018,11 +2063,19 @@ void _initialize_record_btrace (void);
 void
 _initialize_record_btrace (void)
 {
-  add_cmd ("btrace", class_obscure, cmd_record_btrace_start,
-	   _("Start branch trace recording."),
-	   &record_cmdlist);
+  add_prefix_cmd ("btrace", class_obscure, cmd_record_btrace_start,
+		  _("Start branch trace recording."), &record_btrace_cmdlist,
+		  "record btrace ", 0, &record_cmdlist);
   add_alias_cmd ("b", "btrace", class_obscure, 1, &record_cmdlist);
 
+  add_cmd ("bts", class_obscure, cmd_record_btrace_bts_start,
+	   _("\
+Start branch trace recording in Intel(R) Branch Trace Store (BTS) format.\n\n\
+The processor stores a from/to record for each branch into a cyclic buffer.\n\
+This format may not be available on all processors."),
+	   &record_btrace_cmdlist);
+  add_alias_cmd ("bts", "btrace bts", class_obscure, 1, &record_cmdlist);
+
   add_prefix_cmd ("btrace", class_support, cmd_set_record_btrace,
 		  _("Set record options"), &set_record_btrace_cmdlist,
 		  "set record btrace ", 0, &set_record_cmdlist);
diff --git a/gdb/remote.c b/gdb/remote.c
index e31698f..16cb60f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -221,6 +221,8 @@ static int remote_supports_cond_breakpoints (struct target_ops *self);
 
 static int remote_can_run_breakpoint_commands (struct target_ops *self);
 
+static void remote_btrace_reset (void);
+
 /* For "remote".  */
 
 static struct cmd_list_element *remote_cmdlist;
@@ -371,6 +373,9 @@ struct remote_state
 
   /* The state of remote notification.  */
   struct remote_notif_state *notif_state;
+
+  /* The branch trace configuration.  */
+  struct btrace_config btrace_config;
 };
 
 /* Private data that we'll store in (struct thread_info)->private.  */
@@ -1327,6 +1332,9 @@ enum {
   /* Support for qXfer:libraries-svr4:read with a non-empty annex.  */
   PACKET_augmented_libraries_svr4_read_feature,
 
+  /* Support for the qXfer:btrace-conf:read packet.  */
+  PACKET_qXfer_btrace_conf,
+
   PACKET_MAX
 };
 
@@ -4010,7 +4018,9 @@ static const struct protocol_feature remote_protocol_features[] = {
   { "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 }
+    PACKET_qXfer_btrace },
+  { "qXfer:btrace-conf:read", PACKET_DISABLE, remote_supported_packet,
+    PACKET_qXfer_btrace_conf }
 };
 
 static char *remote_support_xml;
@@ -4358,6 +4368,8 @@ remote_open_1 (const char *name, int from_tty,
       }
   }
 
+  remote_btrace_reset ();
+
   if (target_async_permitted)
     wait_forever_enabled_p = 1;
 }
@@ -8945,6 +8957,11 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
 				xfered_len,
         &remote_protocol_packets[PACKET_qXfer_btrace]);
 
+    case TARGET_OBJECT_BTRACE_CONF:
+      return remote_read_qxfer (ops, "btrace-conf", annex, readbuf, offset,
+				len, xfered_len,
+	&remote_protocol_packets[PACKET_qXfer_btrace_conf]);
+
     default:
       return TARGET_XFER_E_IO;
     }
@@ -11319,8 +11336,21 @@ struct btrace_target_info
 {
   /* The ptid of the traced thread.  */
   ptid_t ptid;
+
+  /* The obtained branch trace configuration.  */
+  struct btrace_config conf;
 };
 
+/* Reset our idea of our target's btrace configuration.  */
+
+static void
+remote_btrace_reset (void)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  memset (&rs->btrace_config, 0, sizeof (rs->btrace_config));
+}
+
 /* Check whether the target supports branch tracing.  */
 
 static int
@@ -11343,20 +11373,52 @@ remote_supports_btrace (struct target_ops *self, enum btrace_format format)
   internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
 }
 
+/* Synchronize the configuration with the target.  */
+
+static void
+btrace_sync_conf (const struct btrace_config *conf)
+{
+  /* Nothing to do for now.  */
+}
+
+/* Read the current thread's btrace configuration from the target and
+   store it into CONF.  */
+
+static void
+btrace_read_config (struct btrace_config *conf)
+{
+  char *xml;
+
+  xml = target_read_stralloc (&current_target,
+                              TARGET_OBJECT_BTRACE_CONF, "");
+  if (xml != NULL)
+    {
+      struct cleanup *cleanup;
+
+      cleanup = make_cleanup (xfree, xml);
+      parse_xml_btrace_conf (conf, xml);
+      do_cleanups (cleanup);
+    }
+}
+
 /* Enable branch tracing.  */
 
 static struct btrace_target_info *
-remote_enable_btrace (struct target_ops *self, ptid_t ptid)
+remote_enable_btrace (struct target_ops *self, ptid_t ptid,
+		      const struct btrace_config *conf)
 {
   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 ();
+  volatile struct gdb_exception err;
 
   if (packet_config_support (packet) != PACKET_ENABLE)
     error (_("Target does not support branch tracing."));
 
+  btrace_sync_conf (conf);
+
   set_general_thread (ptid);
 
   buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
@@ -11376,6 +11438,14 @@ remote_enable_btrace (struct target_ops *self, ptid_t ptid)
   tinfo = xzalloc (sizeof (*tinfo));
   tinfo->ptid = ptid;
 
+  /* If we fail to read the configuration, we lose some information, but the
+     tracing itself is not impacted.  */
+  TRY_CATCH (err, RETURN_MASK_ERROR)
+    btrace_read_config (&tinfo->conf);
+
+  if (err.message != NULL)
+    warning ("%s", err.message);
+
   return tinfo;
 }
 
@@ -11472,6 +11542,13 @@ remote_read_btrace (struct target_ops *self,
   return BTRACE_ERR_NONE;
 }
 
+static const struct btrace_config *
+remote_btrace_conf (struct target_ops *self,
+		    const struct btrace_target_info *tinfo)
+{
+  return &tinfo->conf;
+}
+
 static int
 remote_augmented_libraries_svr4_read (struct target_ops *self)
 {
@@ -11608,6 +11685,7 @@ Specify the serial device it is connected to\n\
   remote_ops.to_disable_btrace = remote_disable_btrace;
   remote_ops.to_teardown_btrace = remote_teardown_btrace;
   remote_ops.to_read_btrace = remote_read_btrace;
+  remote_ops.to_btrace_conf = remote_btrace_conf;
   remote_ops.to_augmented_libraries_svr4_read =
     remote_augmented_libraries_svr4_read;
 }
@@ -12198,6 +12276,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
        "qXfer:btrace", "read-btrace", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace_conf],
+       "qXfer:btrace-conf", "read-btrace-conf", 0);
+
   /* Assert that we've registered commands for all packet configs.  */
   {
     int i;
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
index d243ad6..d73b795 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -148,6 +148,10 @@
   target_debug_do_print (host_address_to_string (X))
 #define target_debug_print_enum_btrace_format(X)	\
   target_debug_do_print (plongest (X))
+#define target_debug_print_const_struct_btrace_config_p(X)	\
+  target_debug_do_print (host_address_to_string (X))
+#define target_debug_print_const_struct_btrace_target_info_p(X)	\
+  target_debug_do_print (host_address_to_string (X))
 
 static void
 target_debug_print_struct_target_waitstatus_p (struct target_waitstatus *status)
diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c
index 9cdb31e..e026179 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -3114,28 +3114,30 @@ debug_supports_btrace (struct target_ops *self, enum btrace_format arg1)
 }
 
 static struct btrace_target_info *
-delegate_enable_btrace (struct target_ops *self, ptid_t arg1)
+delegate_enable_btrace (struct target_ops *self, ptid_t arg1, const struct btrace_config *arg2)
 {
   self = self->beneath;
-  return self->to_enable_btrace (self, arg1);
+  return self->to_enable_btrace (self, arg1, arg2);
 }
 
 static struct btrace_target_info *
-tdefault_enable_btrace (struct target_ops *self, ptid_t arg1)
+tdefault_enable_btrace (struct target_ops *self, ptid_t arg1, const struct btrace_config *arg2)
 {
   tcomplain ();
 }
 
 static struct btrace_target_info *
-debug_enable_btrace (struct target_ops *self, ptid_t arg1)
+debug_enable_btrace (struct target_ops *self, ptid_t arg1, const struct btrace_config *arg2)
 {
   struct btrace_target_info * result;
   fprintf_unfiltered (gdb_stdlog, "-> %s->to_enable_btrace (...)\n", debug_target.to_shortname);
-  result = debug_target.to_enable_btrace (&debug_target, arg1);
+  result = debug_target.to_enable_btrace (&debug_target, arg1, arg2);
   fprintf_unfiltered (gdb_stdlog, "<- %s->to_enable_btrace (", debug_target.to_shortname);
   target_debug_print_struct_target_ops_p (&debug_target);
   fputs_unfiltered (", ", gdb_stdlog);
   target_debug_print_ptid_t (arg1);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_const_struct_btrace_config_p (arg2);
   fputs_unfiltered (") = ", gdb_stdlog);
   target_debug_print_struct_btrace_target_info_p (result);
   fputs_unfiltered ("\n", gdb_stdlog);
@@ -3225,6 +3227,35 @@ debug_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct btr
   return result;
 }
 
+static const struct btrace_config *
+delegate_btrace_conf (struct target_ops *self, const struct btrace_target_info *arg1)
+{
+  self = self->beneath;
+  return self->to_btrace_conf (self, arg1);
+}
+
+static const struct btrace_config *
+tdefault_btrace_conf (struct target_ops *self, const struct btrace_target_info *arg1)
+{
+  return NULL;
+}
+
+static const struct btrace_config *
+debug_btrace_conf (struct target_ops *self, const struct btrace_target_info *arg1)
+{
+  const struct btrace_config * result;
+  fprintf_unfiltered (gdb_stdlog, "-> %s->to_btrace_conf (...)\n", debug_target.to_shortname);
+  result = debug_target.to_btrace_conf (&debug_target, arg1);
+  fprintf_unfiltered (gdb_stdlog, "<- %s->to_btrace_conf (", debug_target.to_shortname);
+  target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_const_struct_btrace_target_info_p (arg1);
+  fputs_unfiltered (") = ", gdb_stdlog);
+  target_debug_print_const_struct_btrace_config_p (result);
+  fputs_unfiltered ("\n", gdb_stdlog);
+  return result;
+}
+
 static void
 delegate_stop_recording (struct target_ops *self)
 {
@@ -3972,6 +4003,8 @@ install_delegators (struct target_ops *ops)
     ops->to_teardown_btrace = delegate_teardown_btrace;
   if (ops->to_read_btrace == NULL)
     ops->to_read_btrace = delegate_read_btrace;
+  if (ops->to_btrace_conf == NULL)
+    ops->to_btrace_conf = delegate_btrace_conf;
   if (ops->to_stop_recording == NULL)
     ops->to_stop_recording = delegate_stop_recording;
   if (ops->to_info_record == NULL)
@@ -4135,6 +4168,7 @@ install_dummy_methods (struct target_ops *ops)
   ops->to_disable_btrace = tdefault_disable_btrace;
   ops->to_teardown_btrace = tdefault_teardown_btrace;
   ops->to_read_btrace = tdefault_read_btrace;
+  ops->to_btrace_conf = tdefault_btrace_conf;
   ops->to_stop_recording = tdefault_stop_recording;
   ops->to_info_record = tdefault_info_record;
   ops->to_save_record = tdefault_save_record;
@@ -4278,6 +4312,7 @@ init_debug_target (struct target_ops *ops)
   ops->to_disable_btrace = debug_disable_btrace;
   ops->to_teardown_btrace = debug_teardown_btrace;
   ops->to_read_btrace = debug_read_btrace;
+  ops->to_btrace_conf = debug_btrace_conf;
   ops->to_stop_recording = debug_stop_recording;
   ops->to_info_record = debug_info_record;
   ops->to_save_record = debug_save_record;
diff --git a/gdb/target.c b/gdb/target.c
index c847276..10fcab4 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3364,9 +3364,9 @@ target_supports_btrace (enum btrace_format format)
 /* See target.h.  */
 
 struct btrace_target_info *
-target_enable_btrace (ptid_t ptid)
+target_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
 {
-  return current_target.to_enable_btrace (&current_target, ptid);
+  return current_target.to_enable_btrace (&current_target, ptid, conf);
 }
 
 /* See target.h.  */
@@ -3397,6 +3397,14 @@ target_read_btrace (struct btrace_data *btrace,
 
 /* See target.h.  */
 
+const struct btrace_config *
+target_btrace_conf (const struct btrace_target_info *btinfo)
+{
+  return current_target.to_btrace_conf (&current_target, btinfo);
+}
+
+/* See target.h.  */
+
 void
 target_stop_recording (void)
 {
diff --git a/gdb/target.h b/gdb/target.h
index 1654df2..bd22151 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -200,7 +200,9 @@ enum target_object
   /* OpenVMS Unwind Information Block.  */
   TARGET_OBJECT_OPENVMS_UIB,
   /* Branch trace data, in XML format.  */
-  TARGET_OBJECT_BTRACE
+  TARGET_OBJECT_BTRACE,
+  /* Branch trace configuration, in XML format.  */
+  TARGET_OBJECT_BTRACE_CONF
   /* Possible future objects: TARGET_OBJECT_FILE, ...  */
 };
 
@@ -1002,10 +1004,12 @@ struct target_ops
     int (*to_supports_btrace) (struct target_ops *, enum btrace_format)
       TARGET_DEFAULT_RETURN (0);
 
-    /* Enable branch tracing for PTID and allocate a branch trace target
-       information struct for reading and for disabling branch trace.  */
+    /* Enable branch tracing for PTID using CONF configuration.
+       Return a branch trace target information struct for reading and for
+       disabling branch trace.  */
     struct btrace_target_info *(*to_enable_btrace) (struct target_ops *,
-						    ptid_t ptid)
+						    ptid_t ptid,
+						    const struct btrace_config *conf)
       TARGET_DEFAULT_NORETURN (tcomplain ());
 
     /* Disable branch tracing and deallocate TINFO.  */
@@ -1029,6 +1033,11 @@ struct target_ops
 					 enum btrace_read_type type)
       TARGET_DEFAULT_NORETURN (tcomplain ());
 
+    /* Get the branch trace configuration.  */
+    const struct btrace_config *(*to_btrace_conf) (struct target_ops *self,
+						   const struct btrace_target_info *)
+      TARGET_DEFAULT_RETURN (NULL);
+
     /* Stop trace recording.  */
     void (*to_stop_recording) (struct target_ops *)
       TARGET_DEFAULT_IGNORE ();
@@ -2214,7 +2223,8 @@ extern void update_target_permissions (void);
 extern int target_supports_btrace (enum btrace_format);
 
 /* See to_enable_btrace in struct target_ops.  */
-extern struct btrace_target_info *target_enable_btrace (ptid_t ptid);
+extern struct btrace_target_info *
+  target_enable_btrace (ptid_t ptid, const struct btrace_config *);
 
 /* See to_disable_btrace in struct target_ops.  */
 extern void target_disable_btrace (struct btrace_target_info *btinfo);
@@ -2227,6 +2237,10 @@ extern enum btrace_error target_read_btrace (struct btrace_data *,
 					     struct btrace_target_info *,
 					     enum btrace_read_type);
 
+/* See to_btrace_conf in struct target_ops.  */
+extern const struct btrace_config *
+  target_btrace_conf (const struct btrace_target_info *);
+
 /* See to_stop_recording in struct target_ops.  */
 extern void target_stop_recording (void);
 
diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp
index 5c3505c..71ccf07 100644
--- a/gdb/testsuite/gdb.btrace/delta.exp
+++ b/gdb/testsuite/gdb.btrace/delta.exp
@@ -39,6 +39,7 @@ gdb_test_no_output "record btrace"
 with_test_prefix "no trace" {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 0 instructions in 0 functions for .*" \
     ] "\r\n"]
   gdb_test "record instruction-history" "No trace\."
@@ -51,6 +52,7 @@ gdb_test "stepi"
 proc check_trace {} {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 1 instructions in 1 functions for .*" \
     ] "\r\n"]
   gdb_test "record instruction-history /f 1" \
@@ -71,6 +73,7 @@ with_test_prefix "twice" {
 gdb_test "reverse-stepi"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 1 instructions in 1 functions for .*" \
   "Replay in progress\.  At instruction 1\." \
   ] "\r\n"] "reverse-stepi"
@@ -79,5 +82,6 @@ gdb_test "info record" [join [list \
 gdb_test "stepi"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 1 instructions in 1 functions for .*" \
   ] "\r\n"] "and back"
diff --git a/gdb/testsuite/gdb.btrace/enable.exp b/gdb/testsuite/gdb.btrace/enable.exp
index 78c7e53..2926c0f 100644
--- a/gdb/testsuite/gdb.btrace/enable.exp
+++ b/gdb/testsuite/gdb.btrace/enable.exp
@@ -56,7 +56,9 @@ gdb_test "record btrace" "The process is already being recorded\\.  Use \"record
 gdb_test "record full" "The process is already being recorded\\.  Use \"record stop\" to stop recording first\\." "record full cannot be enabled"
 
 # no trace recorded yet
-gdb_test "info record" "Active record target: record-btrace\r\nRecorded 0 instructions in 0 functions for thread 1.*\\." "info record without trace"
+gdb_test "info record" "Active record target: record-btrace\r
+.*\r
+Recorded 0 instructions in 0 functions for thread 1.*\\." "info record without trace"
 
 # stop btrace record
 gdb_test "record stop" "Process record is stopped and all execution logs are deleted\\." "record stop"
diff --git a/gdb/testsuite/gdb.btrace/finish.exp b/gdb/testsuite/gdb.btrace/finish.exp
index a27082e..593055b 100644
--- a/gdb/testsuite/gdb.btrace/finish.exp
+++ b/gdb/testsuite/gdb.btrace/finish.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
diff --git a/gdb/testsuite/gdb.btrace/instruction_history.exp b/gdb/testsuite/gdb.btrace/instruction_history.exp
index 29102c4..5a77357 100644
--- a/gdb/testsuite/gdb.btrace/instruction_history.exp
+++ b/gdb/testsuite/gdb.btrace/instruction_history.exp
@@ -50,7 +50,7 @@ gdb_continue_to_breakpoint "cont to $bp_location" ".*$srcfile2:$bp_location.*"
 set traced {}
 set testname "determine number of recorded instructions"
 gdb_test_multiple "info record" $testname {
-    -re "Active record target: record-btrace\r\nRecorded \(\[0-9\]*\) instructions in \(\[0-9\]*\) functions for thread 1 .*\\.\r\n$gdb_prompt $" {
+    -re "Active record target: record-btrace\r\n.*\r\nRecorded \(\[0-9\]*\) instructions in \(\[0-9\]*\) functions for thread 1 .*\\.\r\n$gdb_prompt $" {
         set traced $expect_out(1,string)
         pass $testname
     }
diff --git a/gdb/testsuite/gdb.btrace/next.exp b/gdb/testsuite/gdb.btrace/next.exp
index b39eb79..1bc8125 100644
--- a/gdb/testsuite/gdb.btrace/next.exp
+++ b/gdb/testsuite/gdb.btrace/next.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -55,6 +56,7 @@ with_test_prefix "reverse-next - 2" { check_replay_at 1 }
 gdb_test "next" ".*main\.3.*"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "next back"
 
diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp
index fd94df6..a263607 100644
--- a/gdb/testsuite/gdb.btrace/nexti.exp
+++ b/gdb/testsuite/gdb.btrace/nexti.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -55,6 +56,7 @@ with_test_prefix "reverse-nexti - 1" { check_replay_at 1 }
 gdb_test "nexti" ".*main\.3.*" "next, 1.5"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "nexti back"
 
diff --git a/gdb/testsuite/gdb.btrace/nohist.exp b/gdb/testsuite/gdb.btrace/nohist.exp
index c0a1a87..4c1d875 100644
--- a/gdb/testsuite/gdb.btrace/nohist.exp
+++ b/gdb/testsuite/gdb.btrace/nohist.exp
@@ -33,6 +33,7 @@ if ![runto_main] {
 proc check_not_replaying {} {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
 	"Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
     ] "\r\n"]
 }
diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp
index 7c34d25..483166b 100644
--- a/gdb/testsuite/gdb.btrace/step.exp
+++ b/gdb/testsuite/gdb.btrace/step.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -85,5 +86,6 @@ with_test_prefix "step to 39" { check_replay_at 39 }
 gdb_test "step" ".*main\.3.*"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "step to live"
diff --git a/gdb/testsuite/gdb.btrace/stepi.exp b/gdb/testsuite/gdb.btrace/stepi.exp
index fb12e28..cce41e6 100644
--- a/gdb/testsuite/gdb.btrace/stepi.exp
+++ b/gdb/testsuite/gdb.btrace/stepi.exp
@@ -35,6 +35,7 @@ if ![runto_main] {
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -59,6 +60,7 @@ with_test_prefix "stepi to 40" { check_replay_at 40 }
 gdb_test "stepi" ".*main\.3.*"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "stepi to live"
 
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index d9ba33e..1548f67 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -427,13 +427,14 @@ x86_linux_read_description (struct target_ops *ops)
 /* Enable branch tracing.  */
 
 static struct btrace_target_info *
-x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid)
+x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid,
+			 const struct btrace_config *conf)
 {
   struct btrace_target_info *tinfo;
   struct gdbarch *gdbarch;
 
   errno = 0;
-  tinfo = linux_enable_btrace (ptid);
+  tinfo = linux_enable_btrace (ptid, conf);
 
   if (tinfo == NULL)
     error (_("Could not enable branch tracing for %s: %s."),
@@ -476,6 +477,16 @@ x86_linux_read_btrace (struct target_ops *self,
 {
   return linux_read_btrace (data, btinfo, type);
 }
+
+/* See to_btrace_conf in target.h.  */
+
+static const struct btrace_config *
+x86_linux_btrace_conf (struct target_ops *self,
+		       const struct btrace_target_info *btinfo)
+{
+  return linux_btrace_conf (btinfo);
+}
+
 
 
 /* Helper for ps_get_thread_area.  Sets BASE_ADDR to a pointer to
@@ -550,6 +561,7 @@ x86_linux_create_target (void)
   t->to_disable_btrace = x86_linux_disable_btrace;
   t->to_teardown_btrace = x86_linux_teardown_btrace;
   t->to_read_btrace = x86_linux_read_btrace;
+  t->to_btrace_conf = x86_linux_btrace_conf;
 
   return t;
 }
-- 
1.8.3.1



More information about the Gdb-patches mailing list