public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 00/15] record btrace: prepare for a new trace format
@ 2015-01-29 16:28 Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 05/15] record-btrace: add bts buffer size configuration option Markus Metzger
                   ` (15 more replies)
  0 siblings, 16 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:28 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Changes to v2:

  - patch "btrace: use the new cpu identifier" has been squashed into
    patch "btrace: identify cpu".  Addressed Pedro's layering comments.

  - new patches to fix test fails for 32-bit inferiors reported by Jan
    "btrace: work around _dl_runtime_resolve returning to resolved function"
    "btrace: support 32-bit inferior on 64-bit host"
    "btrace: increase buffer size for exception test"

    I put them on top of this series since it was easier to fix
    "btrace: work around _dl_runtime_resolve returning to resolved function"
    after some prework in "btrace: extend struct btrace_insn" and others.

  - a trivial new standalone patch "btrace: less debug output"

  - fixed some bugs I found in "record-btrace: indicate gaps" that I ran
    into while investigating the above mentioned issues.

  - Addressed Pedro's feedback on v2.


This is the first part of a patch series that adds support for a new trace
format.  The entire series consists of three parts:

  - preparation (this)
  - support live inferior tracing
  - support trace in core files


Besides preparing for an additional trace format, this first part adds the
following functionality:

  - allow the trace buffer size to be configured
  - indicate errors as gaps in the trace


And it fixes a few test fails with 32-bit inferiors reported by Jan Kratochvil.

In order to motivate some patches (e.g. identifying the cpu or changing the
btrace_compute_ftrace parameters), I also send a work-in-progress version of the
second part that adds support for the new trace format.  This patch is functional
but not part of the review since the kernel changes are still under review.


Markus Metzger (15):
  btrace: add struct btrace_data
  btrace: add format argument to supports_btrace
  btrace, linux: add perf event buffer abstraction
  record btrace: add configuration struct
  record-btrace: add bts buffer size configuration option
  btrace: update btrace_compute_ftrace parameters
  btrace: extend struct btrace_insn
  btrace: identify cpu
  record-btrace: indicate gaps
  btrace: less debug output
  btrace: work around _dl_runtime_resolve returning to resolved function
  btrace: support 32-bit inferior on 64-bit host
  btrace: increase buffer size for exception test
  configure: check for libipt
  [wip] btrace: support Intel(R) Processor Trace

 gdb/Makefile.in                                  |  14 +-
 gdb/NEWS                                         |  35 +
 gdb/btrace.c                                     | 965 ++++++++++++++++++++---
 gdb/btrace.h                                     |  98 ++-
 gdb/common/btrace-common.c                       |  93 +++
 gdb/common/btrace-common.h                       | 138 +++-
 gdb/config.in                                    |   3 +
 gdb/configure                                    | 498 ++++++++++++
 gdb/configure.ac                                 |  20 +
 gdb/doc/gdb.texinfo                              | 255 +++++-
 gdb/features/btrace-conf.dtd                     |  14 +
 gdb/features/btrace.dtd                          |  16 +-
 gdb/gdbserver/Makefile.in                        |   8 +-
 gdb/gdbserver/linux-low.c                        | 149 +++-
 gdb/gdbserver/server.c                           | 212 ++++-
 gdb/gdbserver/target.h                           |  27 +-
 gdb/nat/linux-btrace.c                           | 783 +++++++++++++++---
 gdb/nat/linux-btrace.h                           |  84 +-
 gdb/record-btrace.c                              | 517 +++++++++++-
 gdb/remote.c                                     | 203 ++++-
 gdb/target-debug.h                               |   8 +
 gdb/target-delegates.c                           |  65 +-
 gdb/target.c                                     |  22 +-
 gdb/target.h                                     |  37 +-
 gdb/testsuite/gdb.btrace/buffer-size.exp         |  57 ++
 gdb/testsuite/gdb.btrace/delta.exp               |  12 +-
 gdb/testsuite/gdb.btrace/enable.exp              |   4 +-
 gdb/testsuite/gdb.btrace/exception.exp           |   2 +
 gdb/testsuite/gdb.btrace/finish.exp              |   3 +-
 gdb/testsuite/gdb.btrace/instruction_history.exp |   2 +-
 gdb/testsuite/gdb.btrace/next.exp                |   6 +-
 gdb/testsuite/gdb.btrace/nexti.exp               |   6 +-
 gdb/testsuite/gdb.btrace/nohist.exp              |   3 +-
 gdb/testsuite/gdb.btrace/step.exp                |   6 +-
 gdb/testsuite/gdb.btrace/stepi.exp               |   6 +-
 gdb/x86-linux-nat.c                              |  26 +-
 36 files changed, 3962 insertions(+), 435 deletions(-)
 create mode 100644 gdb/common/btrace-common.c
 create mode 100644 gdb/features/btrace-conf.dtd
 create mode 100644 gdb/testsuite/gdb.btrace/buffer-size.exp

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 02/15] btrace: add format argument to supports_btrace
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (4 preceding siblings ...)
  2015-01-29 16:29 ` [PATCH v3 13/15] btrace: increase buffer size for exception test Markus Metzger
@ 2015-01-29 16:29 ` Markus Metzger
  2015-01-29 16:30 ` [PATCH v3 01/15] btrace: add struct btrace_data Markus Metzger
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:29 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Add a format argument to the various supports_btrace functions to check
for support of a specific btrace format.  This is to prepare for a new
format.

Removed two redundant calls.  The check will be made in the subsequent
btrace_enable call.

2015-01-29  Markus Metzger <markus.t.metzger@intel.com>

	* btrace.c (btrace_enable): Pass BTRACE_FORMAT_BTS.
	* record-btrace.c (record_btrace_open): Remove call to
	target_supports_btrace.
	* remote.c (remote_supports_btrace): Update parameters.
	* target.c (target_supports_btrace): Update parameters.
	* target.h (to_supports_btrace, target_supports_btrace): Update
	parameters.
	* target-delegates.c: Regenerate.
	* target-debug.h (target_debug_print_enum_btrace_format): New.
	* nat/linux-btrace.c
	(kernel_supports_btrace): Rename into ...
	(kernel_supports_bts): ... this.  Update users.  Update warning text.
	(intel_supports_btrace): Rename into ...
	(intel_supports_bts): ... this.  Update users.
	(cpu_supports_btrace): Rename into ...
	(cpu_supports_bts): ... this.  Update users.
	(linux_supports_btrace): Update parameters.  Split into this and ...
	(linux_supports_bts): ... this.
	* nat/linux-btrace.h (linux_supports_btrace): Update parameters.

gdbserver/
	* server.c (handle_btrace_general_set): Remove call to
	target_supports_btrace.
	(supported_btrace_packets): New.
	(handle_query): Call supported_btrace_packets.
	* target.h: include btrace-common.h.
	(btrace_target_info): Removed.
	(supports_btrace, target_supports_btrace): Update parameters.
---
 gdb/btrace.c           |  2 +-
 gdb/gdbserver/server.c | 27 +++++++++++++-----------
 gdb/gdbserver/target.h |  8 +++----
 gdb/nat/linux-btrace.c | 57 ++++++++++++++++++++++++++++++++------------------
 gdb/nat/linux-btrace.h |  2 +-
 gdb/record-btrace.c    |  3 ---
 gdb/remote.c           | 15 +++++++++----
 gdb/target-debug.h     |  2 ++
 gdb/target-delegates.c | 12 ++++++-----
 gdb/target.c           |  8 +++++++
 gdb/target.h           |  5 ++---
 11 files changed, 88 insertions(+), 53 deletions(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 3b20981..4e32bdc 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -731,7 +731,7 @@ btrace_enable (struct thread_info *tp)
   if (tp->btrace.target != NULL)
     return;
 
-  if (!target_supports_btrace ())
+  if (!target_supports_btrace (BTRACE_FORMAT_BTS))
     error (_("Target does not support branch tracing."));
 
   DEBUG ("enable thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 0e72cf1..1756a1f 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -426,12 +426,6 @@ handle_btrace_general_set (char *own_buf)
 
   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))
     {
@@ -1692,6 +1686,20 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
   return (unsigned long long) crc;
 }
 
+/* Add supported btrace packets to BUF.  */
+
+static void
+supported_btrace_packets (char *buf)
+{
+  if (target_supports_btrace (BTRACE_FORMAT_BTS))
+    strcat (buf, ";Qbtrace:bts+");
+  else
+    return;
+
+  strcat (buf, ";Qbtrace:off+");
+  strcat (buf, ";qXfer:btrace:read+");
+}
+
 /* Handle all of the extended 'q' packets.  */
 
 void
@@ -1923,12 +1931,7 @@ 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+");
-	}
+      supported_btrace_packets (own_buf);
 
       return;
     }
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index bbb0567..ed57886 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -26,9 +26,9 @@
 #include "target/wait.h"
 #include "target/waitstatus.h"
 #include "mem-break.h"
+#include "btrace-common.h"
 
 struct emit_ops;
-struct btrace_target_info;
 struct buffer;
 struct process_info;
 
@@ -355,7 +355,7 @@ struct target_ops
   int (*supports_agent) (void);
 
   /* Check whether the target supports branch tracing.  */
-  int (*supports_btrace) (struct target_ops *);
+  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.  */
@@ -489,9 +489,9 @@ int kill_inferior (int);
   (the_target->supports_agent ? \
    (*the_target->supports_agent) () : 0)
 
-#define target_supports_btrace()			\
+#define target_supports_btrace(format)			\
   (the_target->supports_btrace				\
-   ? (*the_target->supports_btrace) (the_target) : 0)
+   ? (*the_target->supports_btrace) (the_target, format) : 0)
 
 #define target_enable_btrace(ptid) \
   (*the_target->enable_btrace) (ptid)
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 6cec5d0..08eb49b 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -248,10 +248,10 @@ perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
   return btrace;
 }
 
-/* Check whether the kernel supports branch tracing.  */
+/* Check whether the kernel supports BTS.  */
 
 static int
-kernel_supports_btrace (void)
+kernel_supports_bts (void)
 {
   struct perf_event_attr attr;
   pid_t child, pid;
@@ -262,14 +262,14 @@ kernel_supports_btrace (void)
   switch (child)
     {
     case -1:
-      warning (_("test branch tracing: cannot fork: %s."), strerror (errno));
+      warning (_("test bts: cannot fork: %s."), strerror (errno));
       return 0;
 
     case 0:
       status = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
       if (status != 0)
 	{
-	  warning (_("test branch tracing: cannot PTRACE_TRACEME: %s."),
+	  warning (_("test bts: cannot PTRACE_TRACEME: %s."),
 		   strerror (errno));
 	  _exit (1);
 	}
@@ -277,7 +277,7 @@ kernel_supports_btrace (void)
       status = raise (SIGTRAP);
       if (status != 0)
 	{
-	  warning (_("test branch tracing: cannot raise SIGTRAP: %s."),
+	  warning (_("test bts: cannot raise SIGTRAP: %s."),
 		   strerror (errno));
 	  _exit (1);
 	}
@@ -288,14 +288,14 @@ kernel_supports_btrace (void)
       pid = waitpid (child, &status, 0);
       if (pid != child)
 	{
-	  warning (_("test branch tracing: bad pid %ld, error: %s."),
+	  warning (_("test bts: bad pid %ld, error: %s."),
 		   (long) pid, strerror (errno));
 	  return 0;
 	}
 
       if (!WIFSTOPPED (status))
 	{
-	  warning (_("test branch tracing: expected stop. status: %d."),
+	  warning (_("test bts: expected stop. status: %d."),
 		   status);
 	  return 0;
 	}
@@ -320,10 +320,10 @@ kernel_supports_btrace (void)
       pid = waitpid (child, &status, 0);
       if (pid != child)
 	{
-	  warning (_("test branch tracing: bad pid %ld, error: %s."),
+	  warning (_("test bts: bad pid %ld, error: %s."),
 		   (long) pid, strerror (errno));
 	  if (!WIFSIGNALED (status))
-	    warning (_("test branch tracing: expected killed. status: %d."),
+	    warning (_("test bts: expected killed. status: %d."),
 		     status);
 	}
 
@@ -331,10 +331,10 @@ kernel_supports_btrace (void)
     }
 }
 
-/* Check whether an Intel cpu supports branch tracing.  */
+/* Check whether an Intel cpu supports BTS.  */
 
 static int
-intel_supports_btrace (void)
+intel_supports_bts (void)
 {
   unsigned int cpuid, model, family;
 
@@ -372,10 +372,10 @@ intel_supports_btrace (void)
   return 1;
 }
 
-/* Check whether the cpu supports branch tracing.  */
+/* Check whether the cpu supports BTS.  */
 
 static int
-cpu_supports_btrace (void)
+cpu_supports_bts (void)
 {
   unsigned int ebx, ecx, edx;
 
@@ -384,24 +384,24 @@ cpu_supports_btrace (void)
 
   if (ebx == signature_INTEL_ebx && ecx == signature_INTEL_ecx
       && edx == signature_INTEL_edx)
-    return intel_supports_btrace ();
+    return intel_supports_bts ();
 
   /* Don't know about others.  Let's assume they do.  */
   return 1;
 }
 
-/* See linux-btrace.h.  */
+/* Check whether the linux target supports BTS.  */
 
-int
-linux_supports_btrace (struct target_ops *ops)
+static int
+linux_supports_bts (void)
 {
   static int cached;
 
   if (cached == 0)
     {
-      if (!kernel_supports_btrace ())
+      if (!kernel_supports_bts ())
 	cached = -1;
-      else if (!cpu_supports_btrace ())
+      else if (!cpu_supports_bts ())
 	cached = -1;
       else
 	cached = 1;
@@ -412,6 +412,23 @@ linux_supports_btrace (struct target_ops *ops)
 
 /* See linux-btrace.h.  */
 
+int
+linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
+{
+  switch (format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return 0;
+
+    case BTRACE_FORMAT_BTS:
+      return linux_supports_bts ();
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
+}
+
+/* See linux-btrace.h.  */
+
 struct btrace_target_info *
 linux_enable_btrace (ptid_t ptid)
 {
@@ -602,7 +619,7 @@ linux_read_btrace (struct btrace_data *btrace,
 /* See linux-btrace.h.  */
 
 int
-linux_supports_btrace (struct target_ops *ops)
+linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
 {
   return 0;
 }
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index 1b11aba..24e06e8 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -61,7 +61,7 @@ struct btrace_target_info
 };
 
 /* See to_supports_btrace in target.h.  */
-extern int linux_supports_btrace (struct target_ops *);
+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);
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 3b7ef5c..04249bf 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -199,9 +199,6 @@ record_btrace_open (const char *args, int from_tty)
   if (!target_has_execution)
     error (_("The program is not being run."));
 
-  if (!target_supports_btrace ())
-    error (_("Target does not support branch tracing."));
-
   if (non_stop)
     error (_("Record btrace can't debug inferior in non-stop mode."));
 
diff --git a/gdb/remote.c b/gdb/remote.c
index e73cdde..9931a6a 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11324,16 +11324,23 @@ struct btrace_target_info
 /* Check whether the target supports branch tracing.  */
 
 static int
-remote_supports_btrace (struct target_ops *self)
+remote_supports_btrace (struct target_ops *self, enum btrace_format format)
 {
   if (packet_support (PACKET_Qbtrace_off) != PACKET_ENABLE)
     return 0;
-  if (packet_support (PACKET_Qbtrace_bts) != PACKET_ENABLE)
-    return 0;
   if (packet_support (PACKET_qXfer_btrace) != PACKET_ENABLE)
     return 0;
 
-  return 1;
+  switch (format)
+    {
+      case BTRACE_FORMAT_NONE:
+	return 0;
+
+      case BTRACE_FORMAT_BTS:
+	return (packet_support (PACKET_Qbtrace_bts) == PACKET_ENABLE);
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
 }
 
 /* Enable branch tracing.  */
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
index 8a32810..61cc3a5 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -146,6 +146,8 @@
   target_debug_do_print (host_address_to_string (X))
 #define target_debug_print_struct_btrace_data_p(X)	\
   target_debug_do_print (host_address_to_string (X))
+#define target_debug_print_enum_btrace_format(X)	\
+  target_debug_do_print (plongest (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 00956ba..9cdb31e 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -3085,26 +3085,28 @@ debug_can_use_agent (struct target_ops *self)
 }
 
 static int
-delegate_supports_btrace (struct target_ops *self)
+delegate_supports_btrace (struct target_ops *self, enum btrace_format arg1)
 {
   self = self->beneath;
-  return self->to_supports_btrace (self);
+  return self->to_supports_btrace (self, arg1);
 }
 
 static int
-tdefault_supports_btrace (struct target_ops *self)
+tdefault_supports_btrace (struct target_ops *self, enum btrace_format arg1)
 {
   return 0;
 }
 
 static int
-debug_supports_btrace (struct target_ops *self)
+debug_supports_btrace (struct target_ops *self, enum btrace_format arg1)
 {
   int result;
   fprintf_unfiltered (gdb_stdlog, "-> %s->to_supports_btrace (...)\n", debug_target.to_shortname);
-  result = debug_target.to_supports_btrace (&debug_target);
+  result = debug_target.to_supports_btrace (&debug_target, arg1);
   fprintf_unfiltered (gdb_stdlog, "<- %s->to_supports_btrace (", debug_target.to_shortname);
   target_debug_print_struct_target_ops_p (&debug_target);
+  fputs_unfiltered (", ", gdb_stdlog);
+  target_debug_print_enum_btrace_format (arg1);
   fputs_unfiltered (") = ", gdb_stdlog);
   target_debug_print_int (result);
   fputs_unfiltered ("\n", gdb_stdlog);
diff --git a/gdb/target.c b/gdb/target.c
index 763ddcb..d2f0050 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3389,6 +3389,14 @@ target_ranged_break_num_registers (void)
 
 /* See target.h.  */
 
+int
+target_supports_btrace (enum btrace_format format)
+{
+  return current_target.to_supports_btrace (&current_target, format);
+}
+
+/* See target.h.  */
+
 struct btrace_target_info *
 target_enable_btrace (ptid_t ptid)
 {
diff --git a/gdb/target.h b/gdb/target.h
index 36fa3c6..803ef28 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -999,7 +999,7 @@ struct target_ops
       TARGET_DEFAULT_RETURN (0);
 
     /* Check whether the target supports branch tracing.  */
-    int (*to_supports_btrace) (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
@@ -2215,8 +2215,7 @@ extern void update_target_permissions (void);
 /* Imported from machine dependent code.  */
 
 /* See to_supports_btrace in struct target_ops.  */
-#define target_supports_btrace() \
-  (current_target.to_supports_btrace (&current_target))
+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);
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 12/15] btrace: support 32-bit inferior on 64-bit host
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 05/15] record-btrace: add bts buffer size configuration option Markus Metzger
@ 2015-01-29 16:29 ` Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 08/15] btrace: identify cpu Markus Metzger
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:29 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Jan Kratochvil

The heuristic for filtering out kernel addressess in BTS trace checks the
most significant bit in each address.  This works fine for 32-bit and 64-bit
mode.

For 32-bit compatibility mode, i.e. a 32-bit inferior running on 64-bit
host, we need to check bit 63 (or any bit bigger than 31), not bit 31.

Use the machine field in struct utsname provided by a uname call to
determine whether we are running on a 64-bit host.

Thanks to Jan Kratochvil for reporting the issue.

CC: Jan Kratochvil <jan.kratochvil@redhat.com>

2015-01-29  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* nat/linux-btrace.c: Include sys/utsname.h.
	(linux_determine_ptr_bits): New.
	(linux_enable_bts): Call linux_determine_ptr_bits.
	* x86-linux-nat.c (x86_linux_enable_btrace): Do not overwrite non-zero
	ptr_bits.

gdbserver/
	* linux-low.c (linux_low_enable_btrace): Do not overwrite non-zero
	ptr_bits.
---
 gdb/gdbserver/linux-low.c |  2 +-
 gdb/nat/linux-btrace.c    | 29 ++++++++++++++++++++++++++++-
 gdb/x86-linux-nat.c       |  8 +++++---
 3 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 62be7aa..6dca61e 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5931,7 +5931,7 @@ linux_low_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
 
   tinfo = linux_enable_btrace (ptid, conf);
 
-  if (tinfo != NULL)
+  if (tinfo != NULL && tinfo->ptr_bits == 0)
     {
       struct thread_info *thread = find_thread_ptid (ptid);
       struct regcache *regcache = get_thread_regcache (thread, 0);
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 3376a0f..c5c05a2 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -38,6 +38,7 @@
 #include <sys/ptrace.h>
 #include <sys/types.h>
 #include <signal.h>
+#include <sys/utsname.h>
 
 /* A branch trace record in perf_event.  */
 struct perf_event_bts
@@ -102,6 +103,32 @@ perf_event_new_data (const struct perf_event_buffer *pev)
   return *pev->data_head != pev->last_head;
 }
 
+/* Try to determine the size of a pointer in bits for the OS.
+ *
+ * This is the same as the size of a pointer for the inferior process
+ * except when a 32-bit inferior is running on a 64-bit OS.
+ */
+
+static int
+linux_determine_ptr_bits (void)
+{
+  struct utsname utsn;
+  int errcode;
+
+  memset (&utsn, 0, sizeof (utsn));
+
+  errcode = uname (&utsn);
+  if (errcode < 0)
+    return 0;
+
+  /* We only need to handle the 64-bit host case, here.  For 32-bit host,
+     the pointer size can be filled in later based on the inferior.  */
+  if (strcmp (utsn.machine, "x86_64") == 0)
+    return 64;
+
+  return 0;
+}
+
 /* Check whether an address is in the kernel.  */
 
 static inline int
@@ -434,7 +461,7 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
 
   tinfo = xzalloc (sizeof (*tinfo));
   tinfo->ptid = ptid;
-  tinfo->ptr_bits = 0;
+  tinfo->ptr_bits = linux_determine_ptr_bits ();
 
   tinfo->conf.format = BTRACE_FORMAT_BTS;
   bts = &tinfo->variant.bts;
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index 9d82be2..0bf564a 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -441,9 +441,11 @@ x86_linux_enable_btrace (struct target_ops *self, ptid_t ptid,
 	   target_pid_to_str (ptid), safe_strerror (errno));
 
   /* Fill in the size of a pointer in bits.  */
-  gdbarch = target_thread_architecture (ptid);
-  tinfo->ptr_bits = gdbarch_ptr_bit (gdbarch);
-
+  if (tinfo->ptr_bits == 0)
+    {
+      gdbarch = target_thread_architecture (ptid);
+      tinfo->ptr_bits = gdbarch_ptr_bit (gdbarch);
+    }
   return tinfo;
 }
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 07/15] btrace: extend struct btrace_insn
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (2 preceding siblings ...)
  2015-01-29 16:29 ` [PATCH v3 08/15] btrace: identify cpu Markus Metzger
@ 2015-01-29 16:29 ` Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 13/15] btrace: increase buffer size for exception test Markus Metzger
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:29 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Add the instruction's size as well as a coarse classification to struct
btrace_insn.  Use the information in ftrace_update_function and
ftrace_find_call.

2015-01-29  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.h (btrace_insn_class): New.
	(btrace_insn) <size, iclass>: New.
	* btrace.c (ftrace_find_call): Update parameters.  Update users.
	Use instruction classification.
	(ftrace_new_return): Update parameters.  Update users.
	(ftrace_update_function): Update parameters.  Update users.  Use
	instruction classification.
	(ftrace_update_insns): Update parameters.  Update users.
	(ftrace_classify_insn): New.
	(btrace_compute_ftrace_bts): Fill in new btrace_insn fields.  Add
	TRY_CATCH around call to gdb_insn_length.
---
 gdb/btrace.c | 111 ++++++++++++++++++++++++++++++++---------------------------
 gdb/btrace.h |  22 ++++++++++++
 2 files changed, 83 insertions(+), 50 deletions(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index e96499e..72e8567 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -330,20 +330,18 @@ ftrace_find_caller (struct btrace_function *bfun,
    tail calls ending with a jump).  */
 
 static struct btrace_function *
-ftrace_find_call (struct gdbarch *gdbarch, struct btrace_function *bfun)
+ftrace_find_call (struct btrace_function *bfun)
 {
   for (; bfun != NULL; bfun = bfun->up)
     {
       struct btrace_insn *last;
-      CORE_ADDR pc;
 
       /* We do not allow empty function segments.  */
       gdb_assert (!VEC_empty (btrace_insn_s, bfun->insn));
 
       last = VEC_last (btrace_insn_s, bfun->insn);
-      pc = last->pc;
 
-      if (gdbarch_insn_is_call (gdbarch, pc))
+      if (last->iclass == BTRACE_INSN_CALL)
 	break;
     }
 
@@ -355,8 +353,7 @@ ftrace_find_call (struct gdbarch *gdbarch, struct btrace_function *bfun)
    MFUN and FUN are the symbol information we have for this function.  */
 
 static struct btrace_function *
-ftrace_new_return (struct gdbarch *gdbarch,
-		   struct btrace_function *prev,
+ftrace_new_return (struct btrace_function *prev,
 		   struct minimal_symbol *mfun,
 		   struct symbol *fun)
 {
@@ -391,7 +388,7 @@ ftrace_new_return (struct gdbarch *gdbarch,
 	 wrong or that the call is simply not included in the trace.  */
 
       /* Let's search for some actual call.  */
-      caller = ftrace_find_call (gdbarch, prev->up);
+      caller = ftrace_find_call (prev->up);
       if (caller == NULL)
 	{
 	  /* There is no call in PREV's back trace.  We assume that the
@@ -454,8 +451,7 @@ ftrace_new_switch (struct btrace_function *prev,
    Return the chronologically latest function segment, never NULL.  */
 
 static struct btrace_function *
-ftrace_update_function (struct gdbarch *gdbarch,
-			struct btrace_function *bfun, CORE_ADDR pc)
+ftrace_update_function (struct btrace_function *bfun, CORE_ADDR pc)
 {
   struct bound_minimal_symbol bmfun;
   struct minimal_symbol *mfun;
@@ -485,24 +481,29 @@ ftrace_update_function (struct gdbarch *gdbarch,
 
   if (last != NULL)
     {
-      CORE_ADDR lpc;
+      switch (last->iclass)
+	{
+	case BTRACE_INSN_RETURN:
+	  return ftrace_new_return (bfun, mfun, fun);
 
-      lpc = last->pc;
+	case BTRACE_INSN_CALL:
+	  /* Ignore calls to the next instruction.  They are used for PIC.  */
+	  if (last->pc + last->size == pc)
+	    break;
 
-      /* Check for returns.  */
-      if (gdbarch_insn_is_ret (gdbarch, lpc))
-	return ftrace_new_return (gdbarch, bfun, mfun, fun);
+	  return ftrace_new_call (bfun, mfun, fun);
 
-      /* Check for calls.  */
-      if (gdbarch_insn_is_call (gdbarch, lpc))
-	{
-	  int size;
+	case BTRACE_INSN_JUMP:
+	  {
+	    CORE_ADDR start;
 
-	  size = gdb_insn_length (gdbarch, lpc);
+	    start = get_pc_function_start (pc);
 
-	  /* Ignore calls to the next instruction.  They are used for PIC.  */
-	  if (lpc + size != pc)
-	    return ftrace_new_call (bfun, mfun, fun);
+	    /* If we can't determine the function for PC, we treat a jump at
+	       the end of the block as tail call.  */
+	    if (start == 0 || start == pc)
+	      return ftrace_new_tailcall (bfun, mfun, fun);
+	  }
 	}
     }
 
@@ -514,24 +515,6 @@ ftrace_update_function (struct gdbarch *gdbarch,
 		    ftrace_print_function_name (bfun),
 		    ftrace_print_filename (bfun));
 
-      if (last != NULL)
-	{
-	  CORE_ADDR start, lpc;
-
-	  start = get_pc_function_start (pc);
-
-	  /* If we can't determine the function for PC, we treat a jump at
-	     the end of the block as tail call.  */
-	  if (start == 0)
-	    start = pc;
-
-	  lpc = last->pc;
-
-	  /* Jumps indicate optimized tail calls.  */
-	  if (start == pc && gdbarch_insn_is_jump (gdbarch, lpc))
-	    return ftrace_new_tailcall (bfun, mfun, fun);
-	}
-
       return ftrace_new_switch (bfun, mfun, fun);
     }
 
@@ -574,17 +557,37 @@ ftrace_update_lines (struct btrace_function *bfun, CORE_ADDR pc)
 /* Add the instruction at PC to BFUN's instructions.  */
 
 static void
-ftrace_update_insns (struct btrace_function *bfun, CORE_ADDR pc)
+ftrace_update_insns (struct btrace_function *bfun,
+		     const struct btrace_insn *insn)
 {
-  struct btrace_insn *insn;
-
-  insn = VEC_safe_push (btrace_insn_s, bfun->insn, NULL);
-  insn->pc = pc;
+  VEC_safe_push (btrace_insn_s, bfun->insn, insn);
 
   if (record_debug > 1)
     ftrace_debug (bfun, "update insn");
 }
 
+/* Classify the instruction at PC.  */
+
+static enum btrace_insn_class
+ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  volatile struct gdb_exception error;
+  enum btrace_insn_class iclass;
+
+  iclass = BTRACE_INSN_OTHER;
+  TRY_CATCH (error, RETURN_MASK_ERROR)
+    {
+      if (gdbarch_insn_is_call (gdbarch, pc))
+	iclass = BTRACE_INSN_CALL;
+      else if (gdbarch_insn_is_ret (gdbarch, pc))
+	iclass = BTRACE_INSN_RETURN;
+      else if (gdbarch_insn_is_jump (gdbarch, pc))
+	iclass = BTRACE_INSN_JUMP;
+    }
+
+  return iclass;
+}
+
 /* Compute the function branch trace from BTS trace.  */
 
 static void
@@ -616,6 +619,8 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 
       for (;;)
 	{
+	  volatile struct gdb_exception error;
+	  struct btrace_insn insn;
 	  int size;
 
 	  /* We should hit the end of the block.  Warn if we went too far.  */
@@ -626,7 +631,7 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 	      break;
 	    }
 
-	  end = ftrace_update_function (gdbarch, end, pc);
+	  end = ftrace_update_function (end, pc);
 	  if (begin == NULL)
 	    begin = end;
 
@@ -635,16 +640,22 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 	  if (blk != 0)
 	    level = min (level, end->level);
 
-	  ftrace_update_insns (end, pc);
+	  size = 0;
+	  TRY_CATCH (error, RETURN_MASK_ERROR)
+	    size = gdb_insn_length (gdbarch, pc);
+
+	  insn.pc = pc;
+	  insn.size = size;
+	  insn.iclass = ftrace_classify_insn (gdbarch, pc);
+
+	  ftrace_update_insns (end, &insn);
 	  ftrace_update_lines (end, pc);
 
 	  /* We're done once we pushed the instruction at the end.  */
 	  if (block->end == pc)
 	    break;
 
-	  size = gdb_insn_length (gdbarch, pc);
-
-	  /* Make sure we terminate if we fail to compute the size.  */
+	  /* We can't continue if we fail to compute the size.  */
 	  if (size <= 0)
 	    {
 	      warning (_("Recorded trace may be incomplete around %s."),
diff --git a/gdb/btrace.h b/gdb/btrace.h
index fde0619..694d504 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -31,6 +31,22 @@
 struct thread_info;
 struct btrace_function;
 
+/* A coarse instruction classification.  */
+enum btrace_insn_class
+{
+  /* The instruction is something not listed below.  */
+  BTRACE_INSN_OTHER,
+
+  /* The instruction is a function call.  */
+  BTRACE_INSN_CALL,
+
+  /* The instruction is a function return.  */
+  BTRACE_INSN_RETURN,
+
+  /* The instruction is an unconditional jump.  */
+  BTRACE_INSN_JUMP
+};
+
 /* A branch trace instruction.
 
    This represents a single instruction in a branch trace.  */
@@ -38,6 +54,12 @@ struct btrace_insn
 {
   /* The address of this instruction.  */
   CORE_ADDR pc;
+
+  /* The size of this instruction in bytes.  */
+  gdb_byte size;
+
+  /* The instruction class of this instruction.  */
+  enum btrace_insn_class iclass;
 };
 
 /* A vector of branch trace instructions.  */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 08/15] btrace: identify cpu
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 05/15] record-btrace: add bts buffer size configuration option Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 12/15] btrace: support 32-bit inferior on 64-bit host Markus Metzger
@ 2015-01-29 16:29 ` Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 07/15] btrace: extend struct btrace_insn Markus Metzger
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:29 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Add a struct for identifying a processor and use it in linux-btrace.c when
identifying the processor we're running on.

We will need this feature for the new btrace format.

2015-01-29  Markus Metzger  <markus.t.metzger@intel.com>

gdb/
	* common/btrace-common.h (btrace_cpu_vendor, btrace_cpu): New.
	* nat/linux-btrace.c: Include x86-cpuid.h.
	(btrace_this_cpu): New.
	(cpu_supports_bts): Call btrace_this_cpu.
	(intel_supports_bts): Add cpu parameter.
---
 gdb/common/btrace-common.h | 28 +++++++++++++++++++
 gdb/nat/linux-btrace.c     | 70 +++++++++++++++++++++++++++++++---------------
 2 files changed, 76 insertions(+), 22 deletions(-)

diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 69e223c..5e67e52 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -61,6 +61,34 @@ enum btrace_format
   BTRACE_FORMAT_BTS
 };
 
+/* An enumeration of cpu vendors.  */
+
+enum btrace_cpu_vendor
+{
+  /* We do not know this vendor.  */
+  CV_UNKNOWN,
+
+  /* Intel.  */
+  CV_INTEL
+};
+
+/* A cpu identifier.  */
+
+struct btrace_cpu
+{
+  /* The processor vendor.  */
+  enum btrace_cpu_vendor vendor;
+
+  /* The cpu family.  */
+  unsigned short family;
+
+  /* The cpu model.  */
+  unsigned char model;
+
+  /* The cpu stepping.  */
+  unsigned char stepping;
+};
+
 /* A BTS configuration.  */
 
 struct btrace_config_bts
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index c7db313..3376a0f 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -59,6 +59,41 @@ struct perf_event_sample
   struct perf_event_bts bts;
 };
 
+/* Identify the cpu we're running on.  */
+static struct btrace_cpu
+btrace_this_cpu (void)
+{
+  struct btrace_cpu cpu;
+  unsigned int eax, ebx, ecx, edx;
+  int ok;
+
+  memset (&cpu, 0, sizeof (cpu));
+
+  ok = x86_cpuid (0, &eax, &ebx, &ecx, &edx);
+  if (ok != 0)
+    {
+      if (ebx == signature_INTEL_ebx && ecx == signature_INTEL_ecx
+	  && edx == signature_INTEL_edx)
+	{
+	  unsigned int cpuid, ignore;
+
+	  ok = x86_cpuid (1, &cpuid, &ignore, &ignore, &ignore);
+	  if (ok != 0)
+	    {
+	      cpu.vendor = CV_INTEL;
+
+	      cpu.family = (cpuid >> 8) & 0xf;
+	      cpu.model = (cpuid >> 4) & 0xf;
+
+	      if (cpu.family == 0x6)
+		cpu.model += (cpuid >> 12) & 0xf0;
+	    }
+	}
+    }
+
+  return cpu;
+}
+
 /* Return non-zero if there is new data in PEVENT; zero otherwise.  */
 
 static int
@@ -302,22 +337,12 @@ kernel_supports_bts (void)
 /* Check whether an Intel cpu supports BTS.  */
 
 static int
-intel_supports_bts (void)
+intel_supports_bts (const struct btrace_cpu *cpu)
 {
-  unsigned int cpuid, model, family;
-
-  if (!x86_cpuid (1, &cpuid, NULL, NULL, NULL))
-    return 0;
-
-  family = (cpuid >> 8) & 0xf;
-  model = (cpuid >> 4) & 0xf;
-
-  switch (family)
+  switch (cpu->family)
     {
     case 0x6:
-      model += (cpuid >> 12) & 0xf0;
-
-      switch (model)
+      switch (cpu->model)
 	{
 	case 0x1a: /* Nehalem */
 	case 0x1f:
@@ -345,17 +370,18 @@ intel_supports_bts (void)
 static int
 cpu_supports_bts (void)
 {
-  unsigned int ebx, ecx, edx;
+  struct btrace_cpu cpu;
 
-  if (!x86_cpuid (0, NULL, &ebx, &ecx, &edx))
-    return 0;
-
-  if (ebx == signature_INTEL_ebx && ecx == signature_INTEL_ecx
-      && edx == signature_INTEL_edx)
-    return intel_supports_bts ();
+  cpu = btrace_this_cpu ();
+  switch (cpu.vendor)
+    {
+    default:
+      /* Don't know about others.  Let's assume they do.  */
+      return 1;
 
-  /* Don't know about others.  Let's assume they do.  */
-  return 1;
+    case CV_INTEL:
+      return intel_supports_bts (&cpu);
+    }
 }
 
 /* Check whether the linux target supports BTS.  */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 05/15] record-btrace: add bts buffer size configuration option
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
@ 2015-01-29 16:29 ` Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 12/15] btrace: support 32-bit inferior on 64-bit host Markus Metzger
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:29 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Allow the size of the branch trace ring buffer to be defined by the
user.  The specified buffer size will be used when BTS tracing is
enabled for new threads.

The obtained buffer size may differ from the requested size.  The
actual buffer size for the current thread is shown in the "info record"
command.

Bigger buffers mean longer traces, but also longer processing time.

2015-01-29  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.c (parse_xml_btrace_conf_bts): Add size.
	(btrace_conf_bts_attributes): New.
	(btrace_conf_children): Add attributes.
	* common/btrace-common.h (btrace_config_bts): New.
	(btrace_config)<bts>: New.
	(btrace_config): Update comment.
	* nat/linux-btrace.c (linux_enable_btrace): Use config.
	* features/btrace-conf.dtd: Increment version.  Add size
	attribute to bts element.
	* record-btrace.c (set_record_btrace_bts_cmdlist,
	show_record_btrace_bts_cmdlist): New.
	(record_btrace_adjust_size, record_btrace_print_bts_conf,
	record_btrace_print_conf, cmd_set_record_btrace_bts,
	cmd_show_record_btrace_bts): New.
	(record_btrace_info): Call record_btrace_print_conf.
	(_initialize_record_btrace): Add commands.
	* remote.c: Add PACKET_Qbtrace_conf_bts_size enum.
	(remote_protocol_features): Add Qbtrace-conf:bts:size packet.
	(btrace_sync_conf): Synchronize bts size.
	(_initialize_remote): Add Qbtrace-conf:bts:size packet.
	* NEWS: Announce new commands and new packets.

doc/
	* gdb.texinfo (Branch Trace Configuration Format): Add size.
	(Process Record and Replay): Describe new set|show commands.
	(General Query Packets): Describe Qbtrace-conf:bts:size packet.

testsuite/
	* gdb.btrace/buffer-size: New.

gdbserver/
	* linux-low.c (linux_low_btrace_conf): Print size.
	* server.c (handle_btrace_conf_general_set): New.
	(hanle_general_set): Call handle_btrace_conf_general_set.
	(handle_query): Report Qbtrace-conf:bts:size as supported.
---
 gdb/NEWS                                 |  14 ++++
 gdb/btrace.c                             |  14 +++-
 gdb/common/btrace-common.h               |  15 +++-
 gdb/doc/gdb.texinfo                      |  77 ++++++++++++++++++--
 gdb/features/btrace-conf.dtd             |   1 +
 gdb/gdbserver/linux-low.c                |   4 +-
 gdb/gdbserver/server.c                   |  60 +++++++++++++++-
 gdb/nat/linux-btrace.c                   |  34 ++++++---
 gdb/record-btrace.c                      | 120 ++++++++++++++++++++++++++++++-
 gdb/remote.c                             |  40 ++++++++++-
 gdb/testsuite/gdb.btrace/buffer-size.exp |  57 +++++++++++++++
 11 files changed, 416 insertions(+), 20 deletions(-)
 create mode 100644 gdb/testsuite/gdb.btrace/buffer-size.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 08d604d..4844f33 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -14,6 +14,12 @@
 * The command 'thread apply all' can now support new option '-ascending'
   to call its specified command for all threads in ascending order.
 
+set|show record btrace bts buffer-size
+  Set and show the size of the ring buffer used for branch tracing in
+  BTS format.
+  The obtained size may differ from the requested size.  Use "info
+  record" to see the obtained buffer size.
+
 * New commands
 
 record btrace bts
@@ -25,6 +31,14 @@ record bts
 qXfer:btrace-conf:read
   Return the branch trace configuration for the current thread.
 
+Qbtrace-conf:bts:size
+  Set the requested ring buffer size for branch tracing in BTS format.
+
+* The info record command now shows the recording format and the
+  branch tracing configuration for the current thread when using
+  the btrace record target.
+  For the BTS format, it shows the ring buffer size.
+
 *** Changes in GDB 7.9
 
 * GDB now supports hardware watchpoints on x86 GNU Hurd.
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 8930c3c..c7932bb 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -1127,13 +1127,25 @@ parse_xml_btrace_conf_bts (struct gdb_xml_parser *parser,
 			  void *user_data, VEC (gdb_xml_value_s) *attributes)
 {
   struct btrace_config *conf;
+  struct gdb_xml_value *size;
 
   conf = user_data;
   conf->format = BTRACE_FORMAT_BTS;
+  conf->bts.size = 0;
+
+  size = xml_find_attribute (attributes, "size");
+  if (size != NULL)
+    conf->bts.size = (unsigned int) * (ULONGEST *) size->value;
 }
 
+static const struct gdb_xml_attribute btrace_conf_bts_attributes[] = {
+  { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_element btrace_conf_children[] = {
-  { "bts", NULL, NULL, GDB_XML_EF_OPTIONAL, parse_xml_btrace_conf_bts, NULL },
+  { "bts", btrace_conf_bts_attributes, NULL, GDB_XML_EF_OPTIONAL,
+    parse_xml_btrace_conf_bts, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 7d30952..69e223c 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -61,15 +61,28 @@ enum btrace_format
   BTRACE_FORMAT_BTS
 };
 
+/* A BTS configuration.  */
+
+struct btrace_config_bts
+{
+  /* The size of the branch trace buffer in bytes.  */
+  unsigned int size;
+};
+
 /* A branch tracing configuration.
 
    This describes the requested configuration as well as the actually
-   obtained configuration.  */
+   obtained configuration.
+   We describe the configuration for all different formats so we can
+   easily switch between formats.  */
 
 struct btrace_config
 {
   /* The branch tracing format.  */
   enum btrace_format format;
+
+  /* The BTS format configuration.  */
+  struct btrace_config_bts bts;
 };
 
 /* Branch trace in BTS format.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 11e7f0f..2e9805a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6528,6 +6528,29 @@ position.
 @item show record btrace replay-memory-access
 Show the current setting of @code{replay-memory-access}.
 
+@kindex set record btrace bts
+@item set record btrace bts buffer-size @var{size}
+@itemx set record btrace bts buffer-size unlimited
+Set the requested ring buffer size for branch tracing in BTS format.
+Default is 64KB.
+
+If @var{size} is a positive number, then @value{GDBN} will try to
+allocate a buffer of at least @var{size} bytes for each new thread
+that uses the btrace recording method and the BTS format.  The actually
+obtained buffer size may differ from the requested @var{size}. Use the
+@code{info record} command to see the actual buffer size for each
+thread that uses the btrace recording method and the BTS format.
+
+If @var{limit} is @code{unlimited} or zero, @value{GDBN} will try to
+allocate a buffer of 4MB.
+
+Bigger buffers mean longer traces.  On the other hand, @value{GDBN} will
+also need longer to process the branch trace data before it can be used.
+
+@item show record btrace bts buffer-size @var{size}
+Show the current setting of the requested ring buffer size for branch
+tracing in BTS format.
+
 @kindex info record
 @item info record
 Show various statistics about the recording depending on the recording
@@ -6554,9 +6577,25 @@ 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 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.
+For the @code{btrace} recording method, it shows:
+
+@itemize @bullet
+@item
+Recording format.
+@item
+Number of instructions that have been recorded.
+@item
+Number of blocks of sequential control-flow formed by the recorded
+instructions.
+@item
+Whether in record mode or replay mode.
+@end itemize
+
+For the @code{bts} recording format, it also shows:
+@itemize @bullet
+@item
+Size of the perf ring buffer.
+@end itemize
 @end table
 
 @kindex record delete
@@ -35708,6 +35747,11 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab Yes
 
+@item @samp{Qbtrace-conf:bts:size}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
 @item @samp{QNonStop}
 @tab No
 @tab @samp{-}
@@ -35965,6 +36009,9 @@ The remote stub understands the @samp{Qbtrace:off} packet.
 @item Qbtrace:bts
 The remote stub understands the @samp{Qbtrace:bts} packet.
 
+@item Qbtrace-conf:bts:size
+The remote stub understands the @samp{Qbtrace-conf:bts:size} packet.
+
 @end table
 
 @item qSymbol::
@@ -36404,6 +36451,18 @@ Branch tracing has been disabled.
 A badly formed request or an error was encountered.
 @end table
 
+@item Qbtrace-conf:bts:size=@var{value}
+Set the requested ring buffer size for new threads that use the
+btrace recording method in bts format.
+
+Reply:
+@table @samp
+@item OK
+The ring buffer size has been set.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
 @end table
 
 @node Architecture-Specific Protocol Details
@@ -38932,7 +38991,16 @@ 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.
+settings for that format.  The following information is described:
+
+@table @code
+@item bts
+This thread uses the Branch Trace Store (BTS) format.
+@table @code
+@item size
+The size of the BTS ring buffer in bytes.
+@end table
+@end table
 
 @value{GDBN} must be linked with the Expat library to support XML
 branch trace configuration discovery.  @xref{Expat}.
@@ -38944,6 +39012,7 @@ The formal DTD for the branch trace configuration format is given below:
 <!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
 
 <!ELEMENT bts	EMPTY>
+<!ATTLIST bts	size	CDATA	#IMPLIED>
 @end smallexample
 
 @include agentexpr.texi
diff --git a/gdb/features/btrace-conf.dtd b/gdb/features/btrace-conf.dtd
index e9cb2ef..907816c 100644
--- a/gdb/features/btrace-conf.dtd
+++ b/gdb/features/btrace-conf.dtd
@@ -8,3 +8,4 @@
 <!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
 
 <!ELEMENT bts	EMPTY>
+<!ATTLIST bts	size	CDATA	#IMPLIED>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 3d07e5d..62be7aa 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -6028,7 +6028,9 @@ linux_low_btrace_conf (const struct btrace_target_info *tinfo,
 	  break;
 
 	case BTRACE_FORMAT_BTS:
-	  buffer_xml_printf (buffer, "<bts/>\n");
+	  buffer_xml_printf (buffer, "<bts");
+	  buffer_xml_printf (buffer, " size=\"0x%x\"", conf->bts.size);
+	  buffer_xml_printf (buffer, " />\n");
 	  break;
 	}
     }
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 17ee5e1..156fcc8 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -463,6 +463,58 @@ handle_btrace_general_set (char *own_buf)
   return 1;
 }
 
+/* Handle the "Qbtrace-conf" packet.  */
+
+static int
+handle_btrace_conf_general_set (char *own_buf)
+{
+  struct thread_info *thread;
+  char *op;
+
+  if (strncmp ("Qbtrace-conf:", own_buf, strlen ("Qbtrace-conf:")) != 0)
+    return 0;
+
+  op = own_buf + strlen ("Qbtrace-conf:");
+
+  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;
+    }
+
+  if (strncmp (op, "bts:size=", strlen ("bts:size=")) == 0)
+    {
+      unsigned long size;
+      char *endp = NULL;
+
+      errno = 0;
+      size = strtoul (op + strlen ("bts:size="), &endp, 16);
+      if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX)
+	{
+	  strcpy (own_buf, "E.Bad size value.");
+	  return -1;
+	}
+
+      current_btrace_conf.bts.size = (unsigned int) size;
+    }
+  else
+    {
+      strcpy (own_buf, "E.Bad Qbtrace configuration option.");
+      return -1;
+    }
+
+  write_ok (own_buf);
+  return 1;
+}
+
 /* Handle all of the extended 'Q' packets.  */
 
 static void
@@ -622,6 +674,9 @@ handle_general_set (char *own_buf)
   if (handle_btrace_general_set (own_buf))
     return;
 
+  if (handle_btrace_conf_general_set (own_buf))
+    return;
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -1761,7 +1816,10 @@ static void
 supported_btrace_packets (char *buf)
 {
   if (target_supports_btrace (BTRACE_FORMAT_BTS))
-    strcat (buf, ";Qbtrace:bts+");
+    {
+      strcat (buf, ";Qbtrace:bts+");
+      strcat (buf, ";Qbtrace-conf:bts:size+");
+    }
   else
     return;
 
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index e827e92..c7db313 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -398,11 +398,12 @@ linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
 /* Enable branch tracing in BTS format.  */
 
 static struct btrace_target_info *
-linux_enable_bts (ptid_t ptid, const struct btrace_config *conf)
+linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
 {
   struct perf_event_mmap_page *header;
   struct btrace_target_info *tinfo;
   struct btrace_tinfo_bts *bts;
+  unsigned int pages, size;
   int pid, pg;
 
   tinfo = xzalloc (sizeof (*tinfo));
@@ -428,18 +429,34 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config *conf)
   if (pid == 0)
     pid = ptid_get_pid (ptid);
 
+  /* Cast to ULONGEST to avoid overflows before we divide by PAGE_SIZE.  */
+  size = (unsigned int) (((ULONGEST) conf->size + PAGE_SIZE - 1) / PAGE_SIZE);
+  if (size == 0)
+    {
+      errno = EINVAL;
+      goto err;
+    }
+
   errno = 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.
-     We could allow the user to specify the size of the buffer, but then
-     we'd leave this search for the maximum buffer size to him.  */
-  for (pg = 4; pg >= 0; --pg)
+  /* The buffer size can be requested in powers of two pages.
+     We track the number of pages we request in PAGES and its base-2 log
+     in PG.  */
+
+  /* Adjust size to the next power of two.  */
+  for (pg = 0, pages = 1; pages != size; ++pg, pages = (1u << pg))
+    if ((pages & size) != 0)
+      size += pages;
+
+  /* We try to allocate the requested size.
+     If that fails, try to get as much as we can.  */
+  for (; size > 0; size >>= 1)
     {
       /* 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,
+      header = mmap (NULL, (size + 1) * PAGE_SIZE, PROT_READ, MAP_SHARED,
 		     bts->file, 0);
       if (header != MAP_FAILED)
 	break;
@@ -450,10 +467,11 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config *conf)
 
   bts->header = header;
   bts->bts.mem = ((const uint8_t *) header) + PAGE_SIZE;
-  bts->bts.size = (1 << pg) * PAGE_SIZE;
+  bts->bts.size = size * PAGE_SIZE;
   bts->bts.data_head = &header->data_head;
   bts->bts.last_head = 0;
 
+  tinfo->conf.bts.size = bts->bts.size;
   return tinfo;
 
  err_file:
@@ -479,7 +497,7 @@ linux_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
       break;
 
     case BTRACE_FORMAT_BTS:
-      tinfo = linux_enable_bts (ptid, conf);
+      tinfo = linux_enable_bts (ptid, &conf->bts);
       break;
     }
 
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 9fa1182..957da8d 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -76,6 +76,14 @@ static struct btrace_config record_btrace_conf;
 /* Command list for "record btrace".  */
 static struct cmd_list_element *record_btrace_cmdlist;
 
+/* Command lists for "set/show record btrace".  */
+static struct cmd_list_element *set_record_btrace_cmdlist;
+static struct cmd_list_element *show_record_btrace_cmdlist;
+
+/* Command lists for "set/show record btrace bts".  */
+static struct cmd_list_element *set_record_btrace_bts_cmdlist;
+static struct cmd_list_element *show_record_btrace_bts_cmdlist;
+
 /* Print a record-btrace debug message.  Use do ... while (0) to avoid
    ambiguities when used in if statements.  */
 
@@ -269,6 +277,71 @@ record_btrace_close (struct target_ops *self)
     btrace_teardown (tp);
 }
 
+/* Adjusts the size and returns a human readable size suffix.  */
+
+static const char *
+record_btrace_adjust_size (unsigned int *size)
+{
+  unsigned int sz;
+
+  sz = *size;
+
+  if ((sz & ((1u << 30) - 1)) == 0)
+    {
+      *size = sz >> 30;
+      return "GB";
+    }
+  else if ((sz & ((1u << 20) - 1)) == 0)
+    {
+      *size = sz >> 20;
+      return "MB";
+    }
+  else if ((sz & ((1u << 10) - 1)) == 0)
+    {
+      *size = sz >> 10;
+      return "kB";
+    }
+  else
+    return "";
+}
+
+/* Print a BTS configuration.  */
+
+static void
+record_btrace_print_bts_conf (const struct btrace_config_bts *conf)
+{
+  const char *suffix;
+  unsigned int size;
+
+  size = conf->size;
+  if (size > 0)
+    {
+      suffix = record_btrace_adjust_size (&size);
+      printf_unfiltered (_("Buffer size: %u%s.\n"), size, suffix);
+    }
+}
+
+/* Print a branch tracing configuration.  */
+
+static void
+record_btrace_print_conf (const struct btrace_config *conf)
+{
+  printf_unfiltered (_("Recording format: %s.\n"),
+		     btrace_format_string (conf->format));
+
+  switch (conf->format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return;
+
+    case BTRACE_FORMAT_BTS:
+      record_btrace_print_bts_conf (&conf->bts);
+      return;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
+
 /* The to_info_record method of target record-btrace.  */
 
 static void
@@ -289,8 +362,7 @@ record_btrace_info (struct target_ops *self)
 
   conf = btrace_conf (btinfo);
   if (conf != NULL)
-    printf_unfiltered (_("Recording format: %s.\n"),
-		       btrace_format_string (conf->format));
+    record_btrace_print_conf (conf);
 
   btrace_fetch (tp);
 
@@ -2056,6 +2128,25 @@ cmd_show_replay_memory_access (struct ui_file *file, int from_tty,
 		    replay_memory_access);
 }
 
+/* The "set record btrace bts" command.  */
+
+static void
+cmd_set_record_btrace_bts (char *args, int from_tty)
+{
+  printf_unfiltered (_("\"set record btrace bts\" must be followed "
+		       "by an apporpriate subcommand.\n"));
+  help_list (set_record_btrace_bts_cmdlist, "set record btrace bts ",
+	     all_commands, gdb_stdout);
+}
+
+/* The "show record btrace bts" command.  */
+
+static void
+cmd_show_record_btrace_bts (char *args, int from_tty)
+{
+  cmd_show_list (show_record_btrace_bts_cmdlist, from_tty, "");
+}
+
 void _initialize_record_btrace (void);
 
 /* Initialize btrace commands.  */
@@ -2099,9 +2190,34 @@ replay."),
 			   &set_record_btrace_cmdlist,
 			   &show_record_btrace_cmdlist);
 
+  add_prefix_cmd ("bts", class_support, cmd_set_record_btrace_bts,
+		  _("Set record btrace bts options"),
+		  &set_record_btrace_bts_cmdlist,
+		  "set record btrace bts ", 0, &set_record_btrace_cmdlist);
+
+  add_prefix_cmd ("bts", class_support, cmd_show_record_btrace_bts,
+		  _("Show record btrace bts options"),
+		  &show_record_btrace_bts_cmdlist,
+		  "show record btrace bts ", 0, &show_record_btrace_cmdlist);
+
+  add_setshow_uinteger_cmd ("buffer-size", no_class,
+			    &record_btrace_conf.bts.size,
+			    _("Set the record/replay bts buffer size."),
+			    _("Show the record/replay bts buffer size."), _("\
+When starting recording request a trace buffer of this size.  \
+The actual buffer size may differ from the requested size.  \
+Use \"info record\" to see the actual buffer size.\n\n\
+Bigger buffers allow longer recording but also take more time to process \
+the recorded execution trace.\n\n\
+The trace buffer size may not be changed while recording."), NULL, NULL,
+			    &set_record_btrace_bts_cmdlist,
+			    &show_record_btrace_bts_cmdlist);
+
   init_record_btrace_ops ();
   add_target (&record_btrace_ops);
 
   bfcache = htab_create_alloc (50, bfcache_hash, bfcache_eq, NULL,
 			       xcalloc, xfree);
+
+  record_btrace_conf.bts.size = 64 * 1024;
 }
diff --git a/gdb/remote.c b/gdb/remote.c
index d2eaa10..b78b848 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1335,6 +1335,9 @@ enum {
   /* Support for the qXfer:btrace-conf:read packet.  */
   PACKET_qXfer_btrace_conf,
 
+  /* Support for the Qbtrace-conf:bts:size packet.  */
+  PACKET_Qbtrace_conf_bts_size,
+
   PACKET_MAX
 };
 
@@ -4020,7 +4023,9 @@ static const struct protocol_feature remote_protocol_features[] = {
   { "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_btrace },
   { "qXfer:btrace-conf:read", PACKET_DISABLE, remote_supported_packet,
-    PACKET_qXfer_btrace_conf }
+    PACKET_qXfer_btrace_conf },
+  { "Qbtrace-conf:bts:size", PACKET_DISABLE, remote_supported_packet,
+    PACKET_Qbtrace_conf_bts_size }
 };
 
 static char *remote_support_xml;
@@ -11378,7 +11383,35 @@ remote_supports_btrace (struct target_ops *self, enum btrace_format format)
 static void
 btrace_sync_conf (const struct btrace_config *conf)
 {
-  /* Nothing to do for now.  */
+  struct packet_config *packet;
+  struct remote_state *rs;
+  char *buf, *pos, *endbuf;
+
+  rs = get_remote_state ();
+  buf = rs->buf;
+  endbuf = buf + get_remote_packet_size ();
+
+  packet = &remote_protocol_packets[PACKET_Qbtrace_conf_bts_size];
+  if (packet_config_support (packet) == PACKET_ENABLE
+      && conf->bts.size != rs->btrace_config.bts.size)
+    {
+      pos = buf;
+      pos += xsnprintf (pos, endbuf - pos, "%s=0x%x", packet->name,
+                        conf->bts.size);
+
+      putpkt (buf);
+      getpkt (&buf, &rs->buf_size, 0);
+
+      if (packet_ok (buf, packet) == PACKET_ERROR)
+	{
+	  if (buf[0] == 'E' && buf[1] == '.')
+	    error (_("Failed to configure the BTS buffer size: %s"), buf + 2);
+	  else
+	    error (_("Failed to configure the BTS buffer size."));
+	}
+
+      rs->btrace_config.bts.size = conf->bts.size;
+    }
 }
 
 /* Read the current thread's btrace configuration from the target and
@@ -12279,6 +12312,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_conf],
        "qXfer:btrace-conf", "read-btrace-conf", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_bts_size],
+       "Qbtrace-conf:bts:size", "btrace-conf-bts-size", 0);
+
   /* Assert that we've registered commands for all packet configs.  */
   {
     int i;
diff --git a/gdb/testsuite/gdb.btrace/buffer-size.exp b/gdb/testsuite/gdb.btrace/buffer-size.exp
new file mode 100644
index 0000000..9d36361
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/buffer-size.exp
@@ -0,0 +1,57 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2013-2014 Free Software Foundation, Inc.
+#
+# Contributed by Intel Corp. <markus.t.metzger@intel.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# check for btrace support
+if { [skip_btrace_tests] } { return -1 }
+
+# start inferior
+standard_testfile x86-record_goto.S
+if [prepare_for_testing $testfile.exp $testfile $srcfile] {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set record btrace bts buffer-size 1"
+gdb_test "show record btrace bts buffer-size" "The record/replay bts buffer size is 1\.\r" "bts buffer size before recording"
+
+gdb_test_no_output "record btrace bts"
+gdb_test "show record btrace bts buffer-size" "The record/replay bts buffer size is 1\.\r" "bts buffer size while recording"
+gdb_test "info record" [join [list \
+  "Active record target: record-btrace" \
+  "Recording format: Intel\\\(R\\\) Branch Trace Store\." \
+  "Buffer size: 4kB\." \
+  "Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
+  ] "\r\n"] "info record with small bts buffer"
+gdb_test "record stop" ".*" "stop recording with small bts buffer"
+
+gdb_test_no_output "set record btrace bts buffer-size 0"
+gdb_test "show record btrace bts buffer-size" "The record/replay bts buffer size is unlimited\.\r" "unlimited bts buffer size before recording"
+
+gdb_test_no_output "record btrace bts"
+gdb_test "show record btrace bts buffer-size" "The record/replay bts buffer size is unlimited\.\r" "unlimited bts buffer size while recording"
+gdb_test "info record" [join [list \
+  "Active record target: record-btrace" \
+  "Recording format: Intel\\\(R\\\) Branch Trace Store\." \
+  "Buffer size: .*\." \
+  "Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
+  ] "\r\n"] "info record with unlimited bts buffer"
+gdb_test "record stop" ".*" "stop recording with unlimited bts buffer"
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 13/15] btrace: increase buffer size for exception test
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (3 preceding siblings ...)
  2015-01-29 16:29 ` [PATCH v3 07/15] btrace: extend struct btrace_insn Markus Metzger
@ 2015-01-29 16:29 ` Markus Metzger
  2015-01-29 16:29 ` [PATCH v3 02/15] btrace: add format argument to supports_btrace Markus Metzger
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:29 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Jan Kratochvil

The trace for throwing and catching an exception can be quite big.
Increase the buffer size to avoid spurious fails.

CC: Jan Kratochvil <jan.kratochvil@redhat.com>

2015-01-29  Markus Metzger <markus.t.metzger@intel.com>

testsuite/
	* gdb.btrace/exception.exp: Increase BTS buffer size.
---
 gdb/testsuite/gdb.btrace/exception.exp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/gdb/testsuite/gdb.btrace/exception.exp b/gdb/testsuite/gdb.btrace/exception.exp
index 9148eb1..0c43273 100755
--- a/gdb/testsuite/gdb.btrace/exception.exp
+++ b/gdb/testsuite/gdb.btrace/exception.exp
@@ -40,6 +40,8 @@ gdb_breakpoint $bp_2
 
 # trace the code between the two breakpoints
 gdb_continue_to_breakpoint "cont to bp.1" ".*$srcfile:$bp_1\r\n.*"
+# increase the BTS buffer size - the trace can be quite big
+gdb_test_no_output "set record btrace bts buffer-size 128000"
 gdb_test_no_output "record btrace"
 gdb_continue_to_breakpoint "cont to bp.2" ".*$srcfile:$bp_2\r\n.*"
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 09/15] record-btrace: indicate gaps
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (8 preceding siblings ...)
  2015-01-29 16:30 ` [PATCH v3 14/15] configure: check for libipt Markus Metzger
@ 2015-01-29 16:30 ` Markus Metzger
  2015-01-29 16:33 ` [PATCH v3 11/15] btrace: work around _dl_runtime_resolve returning to resolved function Markus Metzger
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:30 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Indicate gaps in the trace due to decode errors.  Internally, a gap is
represented as a btrace function segment without instructions and with a
non-zero format-specific error code.

Show the gap when traversing the instruction or function call history.
Also indicate gaps in "info record".

It looks like this:

  (gdb) info record
  Active record target: record-btrace
  Recording format: Intel(R) Branch Trace Store.
  Buffer size: 64KB.
  Recorded 32 instructions in 5 functions (1 gaps) for thread 1 (process 7182).
  (gdb) record function-call-history /cli
  1	fib	inst 1,9	at src/fib.c:9,14
  2	  fib	inst 10,20	at src/fib.c:6,14
  3	[decode error (1): instruction overflow]
  4	fib	inst 21,28	at src/fib.c:11,14
  5	  fib	inst 29,33	at src/fib.c:6,9
  (gdb) record instruction-history 20,22
  20	   0x000000000040062f <fib+47>:	sub    $0x1,%rax
  [decode error (1): instruction overflow]
  21	   0x0000000000400613 <fib+19>:	add    $0x1,%rax
  22	   0x0000000000400617 <fib+23>:	mov    %rax,0x200a3a(%rip)
  (gdb)

Gaps are ignored during reverse execution and replay.

2015-01-29  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.c (ftrace_find_call): Skip gaps.
	(ftrace_new_function): Initialize level.
	(ftrace_new_call, ftrace_new_tailcall, ftrace_new_return)
	(ftrace_new_switch): Update
	level computation.
	(ftrace_new_gap): New.
	(ftrace_update_function): Create new function after gap.
	(btrace_compute_ftrace_bts): Create gap on error.
	(btrace_stitch_bts): Update parameters.  Clear trace if it
	becomes empty.
	(btrace_stitch_trace): Update parameters.  Update callers.
	(btrace_clear): Reset the number of gaps.
	(btrace_insn_get): Return NULL if the iterator points to a gap.
	(btrace_insn_number): Return zero if the iterator points to a gap.
	(btrace_insn_end): Allow gaps at the end.
	(btrace_insn_next, btrace_insn_prev, btrace_insn_cmp): Handle gaps.
	(btrace_find_insn_by_number): Assert that the found iterator does
	not point to a gap.
	(btrace_call_next, btrace_call_prev): Assert that the last function
	is not a gap.
	* btrace.h (btrace_bts_error): New.
	(btrace_function): Update comment.
	(btrace_function) <insn, insn_offset, number>: Update comment.
	(btrace_function) <errcode>: New.
	(btrace_thread_info) <ngaps>: New.
	(btrace_thread_info) <replay>: Update comment.
	(btrace_insn_get): Update comment.
	* record-btrace.c (btrace_ui_out_decode_error): New.
	(record_btrace_info): Print number of gaps.
	(btrace_insn_history, btrace_call_history): Call
	btrace_ui_out_decode_error for gaps.
	(record_btrace_step_thread, record_btrace_start_replaying): Skip gaps.

testsuite/
	* gdb.btrace/buffer-size.exp: Update "info record" output.
	* 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/btrace.c                                     | 196 ++++++++++++++++++----
 gdb/btrace.h                                     |  40 ++++-
 gdb/record-btrace.c                              | 200 +++++++++++++++++++----
 gdb/testsuite/gdb.btrace/buffer-size.exp         |   4 +-
 gdb/testsuite/gdb.btrace/delta.exp               |   8 +-
 gdb/testsuite/gdb.btrace/enable.exp              |   2 +-
 gdb/testsuite/gdb.btrace/finish.exp              |   2 +-
 gdb/testsuite/gdb.btrace/instruction_history.exp |   2 +-
 gdb/testsuite/gdb.btrace/next.exp                |   4 +-
 gdb/testsuite/gdb.btrace/nexti.exp               |   4 +-
 gdb/testsuite/gdb.btrace/nohist.exp              |   2 +-
 gdb/testsuite/gdb.btrace/step.exp                |   4 +-
 gdb/testsuite/gdb.btrace/stepi.exp               |   4 +-
 13 files changed, 386 insertions(+), 86 deletions(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 72e8567..206e692 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -223,6 +223,7 @@ ftrace_new_function (struct btrace_function *prev,
       bfun->number = prev->number + 1;
       bfun->insn_offset = (prev->insn_offset
 			   + VEC_length (btrace_insn_s, prev->insn));
+      bfun->level = prev->level;
     }
 
   return bfun;
@@ -276,7 +277,7 @@ ftrace_new_call (struct btrace_function *caller,
 
   bfun = ftrace_new_function (caller, mfun, fun);
   bfun->up = caller;
-  bfun->level = caller->level + 1;
+  bfun->level += 1;
 
   ftrace_debug (bfun, "new call");
 
@@ -296,7 +297,7 @@ ftrace_new_tailcall (struct btrace_function *caller,
 
   bfun = ftrace_new_function (caller, mfun, fun);
   bfun->up = caller;
-  bfun->level = caller->level + 1;
+  bfun->level += 1;
   bfun->flags |= BFUN_UP_LINKS_TO_TAILCALL;
 
   ftrace_debug (bfun, "new tail call");
@@ -336,8 +337,9 @@ ftrace_find_call (struct btrace_function *bfun)
     {
       struct btrace_insn *last;
 
-      /* We do not allow empty function segments.  */
-      gdb_assert (!VEC_empty (btrace_insn_s, bfun->insn));
+      /* Skip gaps.  */
+      if (bfun->errcode != 0)
+	continue;
 
       last = VEC_last (btrace_insn_s, bfun->insn);
 
@@ -438,14 +440,34 @@ ftrace_new_switch (struct btrace_function *prev,
      be wrong at this point.  */
   bfun = ftrace_new_function (prev, mfun, fun);
 
-  /* We keep the function level.  */
-  bfun->level = prev->level;
-
   ftrace_debug (bfun, "new switch");
 
   return bfun;
 }
 
+/* Add a new function segment for a gap in the trace due to a decode error.
+   PREV is the chronologically preceding function segment.
+   ERRCODE is the format-specific error code.  */
+
+static struct btrace_function *
+ftrace_new_gap (struct btrace_function *prev, int errcode)
+{
+  struct btrace_function *bfun;
+
+  /* We hijack prev if it was empty.  */
+  if (prev != NULL && prev->errcode == 0
+      && VEC_empty (btrace_insn_s, prev->insn))
+    bfun = prev;
+  else
+    bfun = ftrace_new_function (prev, NULL, NULL);
+
+  bfun->errcode = errcode;
+
+  ftrace_debug (bfun, "new gap");
+
+  return bfun;
+}
+
 /* Update BFUN with respect to the instruction at PC.  This may create new
    function segments.
    Return the chronologically latest function segment, never NULL.  */
@@ -468,8 +490,8 @@ ftrace_update_function (struct btrace_function *bfun, CORE_ADDR pc)
   if (fun == NULL && mfun == NULL)
     DEBUG_FTRACE ("no symbol at %s", core_addr_to_string_nz (pc));
 
-  /* If we didn't have a function before, we create one.  */
-  if (bfun == NULL)
+  /* If we didn't have a function or if we had a gap before, we create one.  */
+  if (bfun == NULL || bfun->errcode != 0)
     return ftrace_new_function (bfun, mfun, fun);
 
   /* Check the last instruction, if we have one.
@@ -597,13 +619,14 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
   struct btrace_thread_info *btinfo;
   struct btrace_function *begin, *end;
   struct gdbarch *gdbarch;
-  unsigned int blk;
+  unsigned int blk, ngaps;
   int level;
 
   gdbarch = target_gdbarch ();
   btinfo = &tp->btrace;
   begin = btinfo->begin;
   end = btinfo->end;
+  ngaps = btinfo->ngaps;
   level = begin != NULL ? -btinfo->level : INT_MAX;
   blk = VEC_length (btrace_block_s, btrace->blocks);
 
@@ -626,8 +649,16 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 	  /* We should hit the end of the block.  Warn if we went too far.  */
 	  if (block->end < pc)
 	    {
-	      warning (_("Recorded trace may be corrupted around %s."),
-		       core_addr_to_string_nz (pc));
+	      /* Indicate the gap in the trace - unless we're at the
+		 beginning.  */
+	      if (begin != NULL)
+		{
+		  warning (_("Recorded trace may be corrupted around %s."),
+			   core_addr_to_string_nz (pc));
+
+		  end = ftrace_new_gap (end, BDE_BTS_OVERFLOW);
+		  ngaps += 1;
+		}
 	      break;
 	    }
 
@@ -660,6 +691,12 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 	    {
 	      warning (_("Recorded trace may be incomplete around %s."),
 		       core_addr_to_string_nz (pc));
+
+	      /* Indicate the gap in the trace.  We just added INSN so we're
+		 not at the beginning.  */
+	      end = ftrace_new_gap (end, BDE_BTS_INSN_SIZE);
+	      ngaps += 1;
+
 	      break;
 	    }
 
@@ -678,6 +715,7 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 
   btinfo->begin = begin;
   btinfo->end = end;
+  btinfo->ngaps = ngaps;
 
   /* LEVEL is the minimal function level of all btrace function segments.
      Define the global level offset to -LEVEL so all function levels are
@@ -808,20 +846,30 @@ btrace_teardown (struct thread_info *tp)
 /* Stitch branch trace in BTS format.  */
 
 static int
-btrace_stitch_bts (struct btrace_data_bts *btrace,
-		   const struct btrace_thread_info *btinfo)
+btrace_stitch_bts (struct btrace_data_bts *btrace, struct thread_info *tp)
 {
+  struct btrace_thread_info *btinfo;
   struct btrace_function *last_bfun;
   struct btrace_insn *last_insn;
   btrace_block_s *first_new_block;
 
+  btinfo = &tp->btrace;
   last_bfun = btinfo->end;
   gdb_assert (last_bfun != NULL);
+  gdb_assert (!VEC_empty (btrace_block_s, btrace->blocks));
+
+  /* If the existing trace ends with a gap, we just glue the traces
+     together.  We need to drop the last (i.e. chronologically first) block
+     of the new trace,  though, since we can't fill in the start address.*/
+  if (VEC_empty (btrace_insn_s, last_bfun->insn))
+    {
+      VEC_pop (btrace_block_s, btrace->blocks);
+      return 0;
+    }
 
   /* Beware that block trace starts with the most recent block, so the
      chronologically first block in the new trace is the last block in
      the new trace's block vector.  */
-  gdb_assert (!VEC_empty (btrace_block_s, btrace->blocks));
   first_new_block = VEC_last (btrace_block_s, btrace->blocks);
   last_insn = VEC_last (btrace_insn_s, last_bfun->insn);
 
@@ -869,18 +917,25 @@ btrace_stitch_bts (struct btrace_data_bts *btrace,
      been the only instruction in this function segment.
      This violates the invariant but will be remedied shortly by
      btrace_compute_ftrace when we add the new trace.  */
+
+  /* The only case where this would hurt is if the entire trace consisted
+     of just that one instruction.  If we remove it, we might turn the now
+     empty btrace function segment into a gap.  But we don't want gaps at
+     the beginning.  To avoid this, we remove the entire old trace.  */
+  if (last_bfun == btinfo->begin && VEC_empty (btrace_insn_s, last_bfun->insn))
+    btrace_clear (tp);
+
   return 0;
 }
 
 /* Adjust the block trace in order to stitch old and new trace together.
    BTRACE is the new delta trace between the last and the current stop.
-   BTINFO is the old branch trace until the last stop.
-   May modifx BTRACE as well as the existing trace in BTINFO.
+   TP is the traced thread.
+   May modifx BTRACE as well as the existing trace in TP.
    Return 0 on success, -1 otherwise.  */
 
 static int
-btrace_stitch_trace (struct btrace_data *btrace,
-		     const struct btrace_thread_info *btinfo)
+btrace_stitch_trace (struct btrace_data *btrace, struct thread_info *tp)
 {
   /* If we don't have trace, there's nothing to do.  */
   if (btrace_data_empty (btrace))
@@ -892,7 +947,7 @@ btrace_stitch_trace (struct btrace_data *btrace,
       return 0;
 
     case BTRACE_FORMAT_BTS:
-      return btrace_stitch_bts (&btrace->variant.bts, btinfo);
+      return btrace_stitch_bts (&btrace->variant.bts, tp);
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -946,7 +1001,7 @@ btrace_fetch (struct thread_info *tp)
       if (errcode == 0)
 	{
 	  /* Success.  Let's try to stitch the traces together.  */
-	  errcode = btrace_stitch_trace (&btrace, btinfo);
+	  errcode = btrace_stitch_trace (&btrace, tp);
 	}
       else
 	{
@@ -1009,6 +1064,7 @@ btrace_clear (struct thread_info *tp)
 
   btinfo->begin = NULL;
   btinfo->end = NULL;
+  btinfo->ngaps = 0;
 
   btrace_clear_history (btinfo);
 }
@@ -1206,6 +1262,10 @@ btrace_insn_get (const struct btrace_insn_iterator *it)
   index = it->index;
   bfun = it->function;
 
+  /* Check if the iterator points to a gap in the trace.  */
+  if (bfun->errcode != 0)
+    return NULL;
+
   /* The index is within the bounds of this function's instruction vector.  */
   end = VEC_length (btrace_insn_s, bfun->insn);
   gdb_assert (0 < end);
@@ -1222,6 +1282,11 @@ btrace_insn_number (const struct btrace_insn_iterator *it)
   const struct btrace_function *bfun;
 
   bfun = it->function;
+
+  /* Return zero if the iterator points to a gap in the trace.  */
+  if (bfun->errcode != 0)
+    return 0;
+
   return bfun->insn_offset + it->index;
 }
 
@@ -1254,12 +1319,16 @@ btrace_insn_end (struct btrace_insn_iterator *it,
   if (bfun == NULL)
     error (_("No trace."));
 
-  /* The last instruction in the last function is the current instruction.
-     We point to it - it is one past the end of the execution trace.  */
   length = VEC_length (btrace_insn_s, bfun->insn);
 
+  /* The last function may either be a gap or it contains the current
+     instruction, which is one past the end of the execution trace; ignore
+     it.  */
+  if (length > 0)
+    length -= 1;
+
   it->function = bfun;
-  it->index = length - 1;
+  it->index = length;
 }
 
 /* See btrace.h.  */
@@ -1280,6 +1349,25 @@ btrace_insn_next (struct btrace_insn_iterator *it, unsigned int stride)
 
       end = VEC_length (btrace_insn_s, bfun->insn);
 
+      /* An empty function segment represents a gap in the trace.  We count
+	 it as one instruction.  */
+      if (end == 0)
+	{
+	  const struct btrace_function *next;
+
+	  next = bfun->flow.next;
+	  if (next == NULL)
+	    break;
+
+	  stride -= 1;
+	  steps += 1;
+
+	  bfun = next;
+	  index = 0;
+
+	  continue;
+	}
+
       gdb_assert (0 < end);
       gdb_assert (index < end);
 
@@ -1354,12 +1442,20 @@ btrace_insn_prev (struct btrace_insn_iterator *it, unsigned int stride)
 	  bfun = prev;
 	  index = VEC_length (btrace_insn_s, bfun->insn);
 
-	  /* There is at least one instruction in this function segment.  */
-	  gdb_assert (index > 0);
+	  /* An empty function segment represents a gap in the trace.  We count
+	     it as one instruction.  */
+	  if (index == 0)
+	    {
+	      stride -= 1;
+	      steps += 1;
+
+	      continue;
+	    }
 	}
 
       /* Advance the iterator as far as possible within this segment.  */
       adv = min (index, stride);
+
       stride -= adv;
       index -= adv;
       steps += adv;
@@ -1386,6 +1482,37 @@ btrace_insn_cmp (const struct btrace_insn_iterator *lhs,
   lnum = btrace_insn_number (lhs);
   rnum = btrace_insn_number (rhs);
 
+  /* A gap has an instruction number of zero.  Things are getting more
+     complicated if gaps are involved.
+
+     We take the instruction number offset from the iterator's function.
+     This is the number of the first instruction after the gap.
+
+     This is OK as long as both lhs and rhs point to gaps.  If only one of
+     them does, we need to adjust the number based on the other's regular
+     instruction number.  Otherwise, a gap might compare equal to an
+     instruction.  */
+
+  if (lnum == 0 && rnum == 0)
+    {
+      lnum = lhs->function->insn_offset;
+      rnum = rhs->function->insn_offset;
+    }
+  else if (lnum == 0)
+    {
+      lnum = lhs->function->insn_offset;
+
+      if (lnum == rnum)
+	lnum -= 1;
+    }
+  else if (rnum == 0)
+    {
+      rnum = rhs->function->insn_offset;
+
+      if (rnum == lnum)
+	rnum -= 1;
+    }
+
   return (int) (lnum - rnum);
 }
 
@@ -1397,16 +1524,25 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
 			    unsigned int number)
 {
   const struct btrace_function *bfun;
-  unsigned int end;
+  unsigned int end, length;
 
   for (bfun = btinfo->end; bfun != NULL; bfun = bfun->flow.prev)
-    if (bfun->insn_offset <= number)
-      break;
+    {
+      /* Skip gaps. */
+      if (bfun->errcode != 0)
+	continue;
+
+      if (bfun->insn_offset <= number)
+	break;
+    }
 
   if (bfun == NULL)
     return 0;
 
-  end = bfun->insn_offset + VEC_length (btrace_insn_s, bfun->insn);
+  length = VEC_length (btrace_insn_s, bfun->insn);
+  gdb_assert (length > 0);
+
+  end = bfun->insn_offset + length;
   if (end <= number)
     return 0;
 
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 694d504..0ddd4c1 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -86,12 +86,25 @@ enum btrace_function_flag
   BFUN_UP_LINKS_TO_TAILCALL = (1 << 1)
 };
 
+/* Decode errors for the BTS recording format.  */
+enum btrace_bts_error
+{
+  /* The instruction trace overflowed the end of the trace block.  */
+  BDE_BTS_OVERFLOW = 1,
+
+  /* The instruction size could not be determined.  */
+  BDE_BTS_INSN_SIZE
+};
+
 /* A branch trace function segment.
 
    This represents a function segment in a branch trace, i.e. a consecutive
    number of instructions belonging to the same function.
 
-   We do not allow function segments without any instructions.  */
+   In case of decode errors, we add an empty function segment to indicate
+   the gap in the trace.
+
+   We do not allow function segments without instructions otherwise.  */
 struct btrace_function
 {
   /* The full and minimal symbol for the function.  Both may be NULL.  */
@@ -110,14 +123,23 @@ struct btrace_function
   struct btrace_function *up;
 
   /* The instructions in this function segment.
-     The instruction vector will never be empty.  */
+     The instruction vector will be empty if the function segment
+     represents a decode error.  */
   VEC (btrace_insn_s) *insn;
 
+  /* The error code of a decode error that led to a gap.
+     Must be zero unless INSN is empty; non-zero otherwise.  */
+  int errcode;
+
   /* The instruction number offset for the first instruction in this
-     function segment.  */
+     function segment.
+     If INSN is empty this is the insn_offset of the succeding function
+     segment in control-flow order.  */
   unsigned int insn_offset;
 
-  /* The function number in control-flow order.  */
+  /* The function number in control-flow order.
+     If INSN is empty indicating a gap in the trace due to a decode error,
+     we still count the gap as a function.  */
   unsigned int number;
 
   /* The function level in a back trace across the entire branch trace.
@@ -223,6 +245,9 @@ struct btrace_thread_info
      becomes zero.  */
   int level;
 
+  /* The number of gaps in the trace.  */
+  unsigned int ngaps;
+
   /* A bit-vector of btrace_thread_flag.  */
   enum btrace_thread_flag flags;
 
@@ -232,7 +257,9 @@ struct btrace_thread_info
   /* The function call history iterator.  */
   struct btrace_call_history *call_history;
 
-  /* The current replay position.  NULL if not replaying.  */
+  /* The current replay position.  NULL if not replaying.
+     Gaps are skipped during replay, so REPLAY always points to a valid
+     instruction.  */
   struct btrace_insn_iterator *replay;
 };
 
@@ -270,7 +297,8 @@ extern void parse_xml_btrace (struct btrace_data *data, const char *xml);
 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.  */
+   instruction the iterator points to.
+   May return NULL if the iterator points to a gap in the trace.  */
 extern const struct btrace_insn *
   btrace_insn_get (const struct btrace_insn_iterator *);
 
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 957da8d..b3e3c3b 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -350,7 +350,7 @@ 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;
+  unsigned int insns, calls, gaps;
 
   DEBUG ("info");
 
@@ -368,6 +368,7 @@ record_btrace_info (struct target_ops *self)
 
   insns = 0;
   calls = 0;
+  gaps = 0;
 
   if (!btrace_is_empty (tp))
     {
@@ -379,19 +380,86 @@ record_btrace_info (struct target_ops *self)
       calls = btrace_call_number (&call);
 
       btrace_insn_end (&insn, btinfo);
-      btrace_insn_prev (&insn, 1);
+
       insns = btrace_insn_number (&insn);
+      if (insns != 0)
+	{
+	  /* The last instruction does not really belong to the trace.  */
+	  insns -= 1;
+	}
+      else
+	{
+	  unsigned int steps;
+
+	  /* Skip gaps at the end.  */
+	  do
+	    {
+	      steps = btrace_insn_prev (&insn, 1);
+	      if (steps == 0)
+		break;
+
+	      insns = btrace_insn_number (&insn);
+	    }
+	  while (insns == 0);
+	}
+
+      gaps = btinfo->ngaps;
     }
 
-  printf_unfiltered (_("Recorded %u instructions in %u functions for thread "
-		       "%d (%s).\n"), insns, calls, tp->num,
-		     target_pid_to_str (tp->ptid));
+  printf_unfiltered (_("Recorded %u instructions in %u functions (%u gaps) "
+		       "for thread %d (%s).\n"), insns, calls, gaps,
+		     tp->num, target_pid_to_str (tp->ptid));
 
   if (btrace_is_replaying (tp))
     printf_unfiltered (_("Replay in progress.  At instruction %u.\n"),
 		       btrace_insn_number (btinfo->replay));
 }
 
+/* Print a decode error.  */
+
+static void
+btrace_ui_out_decode_error (struct ui_out *uiout, int errcode,
+			    enum btrace_format format)
+{
+  const char *errstr;
+  int is_error;
+
+  errstr = _("unknown");
+  is_error = 1;
+
+  switch (format)
+    {
+    default:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      switch (errcode)
+	{
+	default:
+	  break;
+
+	case BDE_BTS_OVERFLOW:
+	  errstr = _("instruction overflow");
+	  break;
+
+	case BDE_BTS_INSN_SIZE:
+	  errstr = _("unknown instruction");
+	  break;
+	}
+      break;
+    }
+
+  ui_out_text (uiout, _("["));
+  if (is_error)
+    {
+      ui_out_text (uiout, _("decode error ("));
+      ui_out_field_int (uiout, "errcode", errcode);
+      ui_out_text (uiout, _("): "));
+    }
+  ui_out_text (uiout, errstr);
+  ui_out_text (uiout, _("]\n"));
+}
+
 /* Print an unsigned int.  */
 
 static void
@@ -404,6 +472,7 @@ ui_out_field_uint (struct ui_out *uiout, const char *fld, unsigned int val)
 
 static void
 btrace_insn_history (struct ui_out *uiout,
+		     const struct btrace_thread_info *btinfo,
 		     const struct btrace_insn_iterator *begin,
 		     const struct btrace_insn_iterator *end, int flags)
 {
@@ -421,13 +490,30 @@ btrace_insn_history (struct ui_out *uiout,
 
       insn = btrace_insn_get (&it);
 
-      /* Print the instruction index.  */
-      ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
-      ui_out_text (uiout, "\t");
+      /* A NULL instruction indicates a gap in the trace.  */
+      if (insn == NULL)
+	{
+	  const struct btrace_config *conf;
+
+	  conf = btrace_conf (btinfo);
 
-      /* Disassembly with '/m' flag may not produce the expected result.
-	 See PR gdb/11833.  */
-      gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc, insn->pc + 1);
+	  /* We have trace so we must have a configuration.  */
+	  gdb_assert (conf != NULL);
+
+	  btrace_ui_out_decode_error (uiout, it.function->errcode,
+				      conf->format);
+	}
+      else
+	{
+	  /* Print the instruction index.  */
+	  ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
+	  ui_out_text (uiout, "\t");
+
+	  /* Disassembly with '/m' flag may not produce the expected result.
+	     See PR gdb/11833.  */
+	  gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc,
+			   insn->pc + 1);
+	}
     }
 }
 
@@ -504,7 +590,7 @@ record_btrace_insn_history (struct target_ops *self, int size, int flags)
     }
 
   if (covered > 0)
-    btrace_insn_history (uiout, &begin, &end, flags);
+    btrace_insn_history (uiout, btinfo, &begin, &end, flags);
   else
     {
       if (size < 0)
@@ -564,7 +650,7 @@ record_btrace_insn_history_range (struct target_ops *self,
       btrace_insn_next (&end, 1);
     }
 
-  btrace_insn_history (uiout, &begin, &end, flags);
+  btrace_insn_history (uiout, btinfo, &begin, &end, flags);
   btrace_set_insn_history (btinfo, &begin, &end);
 
   do_cleanups (uiout_cleanup);
@@ -705,6 +791,21 @@ btrace_call_history (struct ui_out *uiout,
       ui_out_field_uint (uiout, "index", bfun->number);
       ui_out_text (uiout, "\t");
 
+      /* Indicate gaps in the trace.  */
+      if (bfun->errcode != 0)
+	{
+	  const struct btrace_config *conf;
+
+	  conf = btrace_conf (btinfo);
+
+	  /* We have trace so we must have a configuration.  */
+	  gdb_assert (conf != NULL);
+
+	  btrace_ui_out_decode_error (uiout, bfun->errcode, conf->format);
+
+	  continue;
+	}
+
       if ((flags & RECORD_PRINT_INDENT_CALLS) != 0)
 	{
 	  int level = bfun->level + btinfo->level, i;
@@ -1518,6 +1619,16 @@ record_btrace_start_replaying (struct thread_info *tp)
       replay = xmalloc (sizeof (*replay));
       btrace_insn_end (replay, btinfo);
 
+      /* Skip gaps at the end of the trace.  */
+      while (btrace_insn_get (replay) == NULL)
+	{
+	  unsigned int steps;
+
+	  steps = btrace_insn_prev (replay, 1);
+	  if (steps == 0)
+	    error (_("No trace."));
+	}
+
       /* We're not replaying, yet.  */
       gdb_assert (btinfo->replay == NULL);
       btinfo->replay = replay;
@@ -1713,9 +1824,17 @@ record_btrace_step_thread (struct thread_info *tp)
       if (replay == NULL)
 	return btrace_step_no_history ();
 
-      /* We are always able to step at least once.  */
-      steps = btrace_insn_next (replay, 1);
-      gdb_assert (steps == 1);
+      /* Skip gaps during replay.  */
+      do
+	{
+	  steps = btrace_insn_next (replay, 1);
+	  if (steps == 0)
+	    {
+	      record_btrace_stop_replaying (tp);
+	      return btrace_step_no_history ();
+	    }
+	}
+      while (btrace_insn_get (replay) == NULL);
 
       /* Determine the end of the instruction trace.  */
       btrace_insn_end (&end, btinfo);
@@ -1731,10 +1850,16 @@ record_btrace_step_thread (struct thread_info *tp)
       if (replay == NULL)
 	replay = record_btrace_start_replaying (tp);
 
-      /* If we can't step any further, we reached the end of the history.  */
-      steps = btrace_insn_prev (replay, 1);
-      if (steps == 0)
-	return btrace_step_no_history ();
+      /* If we can't step any further, we reached the end of the history.
+	 Skip gaps during replay.  */
+      do
+	{
+	  steps = btrace_insn_prev (replay, 1);
+	  if (steps == 0)
+	    return btrace_step_no_history ();
+
+	}
+      while (btrace_insn_get (replay) == NULL);
 
       return btrace_step_stopped ();
 
@@ -1753,9 +1878,19 @@ record_btrace_step_thread (struct thread_info *tp)
 	{
 	  const struct btrace_insn *insn;
 
-	  /* We are always able to step at least once.  */
-	  steps = btrace_insn_next (replay, 1);
-	  gdb_assert (steps == 1);
+	  /* Skip gaps during replay.  */
+	  do
+	    {
+	      steps = btrace_insn_next (replay, 1);
+	      if (steps == 0)
+		{
+		  record_btrace_stop_replaying (tp);
+		  return btrace_step_no_history ();
+		}
+
+	      insn = btrace_insn_get (replay);
+	    }
+	  while (insn == NULL);
 
 	  /* We stop replaying if we reached the end of the trace.  */
 	  if (btrace_insn_cmp (replay, &end) == 0)
@@ -1764,9 +1899,6 @@ record_btrace_step_thread (struct thread_info *tp)
 	      return btrace_step_no_history ();
 	    }
 
-	  insn = btrace_insn_get (replay);
-	  gdb_assert (insn);
-
 	  DEBUG ("stepping %d (%s) ... %s", tp->num,
 		 target_pid_to_str (tp->ptid),
 		 core_addr_to_string_nz (insn->pc));
@@ -1787,13 +1919,17 @@ record_btrace_step_thread (struct thread_info *tp)
 	{
 	  const struct btrace_insn *insn;
 
-	  /* If we can't step any further, we're done.  */
-	  steps = btrace_insn_prev (replay, 1);
-	  if (steps == 0)
-	    return btrace_step_no_history ();
+	  /* If we can't step any further, we reached the end of the history.
+	     Skip gaps during replay.  */
+	  do
+	    {
+	      steps = btrace_insn_prev (replay, 1);
+	      if (steps == 0)
+		return btrace_step_no_history ();
 
-	  insn = btrace_insn_get (replay);
-	  gdb_assert (insn);
+	      insn = btrace_insn_get (replay);
+	    }
+	  while (insn == NULL);
 
 	  DEBUG ("reverse-stepping %d (%s) ... %s", tp->num,
 		 target_pid_to_str (tp->ptid),
diff --git a/gdb/testsuite/gdb.btrace/buffer-size.exp b/gdb/testsuite/gdb.btrace/buffer-size.exp
index 9d36361..51d861c 100644
--- a/gdb/testsuite/gdb.btrace/buffer-size.exp
+++ b/gdb/testsuite/gdb.btrace/buffer-size.exp
@@ -39,7 +39,7 @@ gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
   "Recording format: Intel\\\(R\\\) Branch Trace Store\." \
   "Buffer size: 4kB\." \
-  "Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
+  "Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
   ] "\r\n"] "info record with small bts buffer"
 gdb_test "record stop" ".*" "stop recording with small bts buffer"
 
@@ -52,6 +52,6 @@ gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
   "Recording format: Intel\\\(R\\\) Branch Trace Store\." \
   "Buffer size: .*\." \
-  "Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
+  "Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
   ] "\r\n"] "info record with unlimited bts buffer"
 gdb_test "record stop" ".*" "stop recording with unlimited bts buffer"
diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp
index 59959bc..38b6e26 100644
--- a/gdb/testsuite/gdb.btrace/delta.exp
+++ b/gdb/testsuite/gdb.btrace/delta.exp
@@ -40,7 +40,7 @@ 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 .*" \
+    "Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for .*" \
     ] "\r\n"]
   gdb_test "record instruction-history" "No trace\."
   gdb_test "record function-call-history" "No trace\."
@@ -53,7 +53,7 @@ proc check_trace {} {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
     "Recording format: .*" \
-    "Recorded 1 instructions in 1 functions for .*" \
+    "Recorded 1 instructions in 1 functions \\\(0 gaps\\\) for .*" \
     ] "\r\n"]
   gdb_test "record instruction-history /f 1" \
     "1\t   0x\[0-9a-f\]+ <\\+\[0-9\]+>:\tmov *\\\$0x0,%eax\r"
@@ -74,7 +74,7 @@ gdb_test "reverse-stepi"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
   "Recording format: .*" \
-  "Recorded 1 instructions in 1 functions for .*" \
+  "Recorded 1 instructions in 1 functions \\\(0 gaps\\\) for .*" \
   "Replay in progress\.  At instruction 1\." \
   ] "\r\n"] "reverse-stepi"
 
@@ -83,5 +83,5 @@ gdb_test "stepi"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
   "Recording format: .*" \
-  "Recorded 1 instructions in 1 functions for .*" \
+  "Recorded 1 instructions in 1 functions \\\(0 gaps\\\) for .*" \
   ] "\r\n"] "and back"
diff --git a/gdb/testsuite/gdb.btrace/enable.exp b/gdb/testsuite/gdb.btrace/enable.exp
index 1122884..d447bd9 100644
--- a/gdb/testsuite/gdb.btrace/enable.exp
+++ b/gdb/testsuite/gdb.btrace/enable.exp
@@ -58,7 +58,7 @@ gdb_test "record full" "The process is already being recorded\\.  Use \"record s
 # no trace recorded yet
 gdb_test "info record" "Active record target: record-btrace\r
 .*\r
-Recorded 0 instructions in 0 functions for thread 1.*\\." "info record without trace"
+Recorded 0 instructions in 0 functions \\\(0 gaps\\\) 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 3857c10..6881e3b 100644
--- a/gdb/testsuite/gdb.btrace/finish.exp
+++ b/gdb/testsuite/gdb.btrace/finish.exp
@@ -38,7 +38,7 @@ 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 .*" \
+    "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) 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 63d902b..a7b57e5 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\n.*\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 \\\(0 gaps\\\) 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 88bd8af..3d2fa10 100644
--- a/gdb/testsuite/gdb.btrace/next.exp
+++ b/gdb/testsuite/gdb.btrace/next.exp
@@ -38,7 +38,7 @@ 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 .*" \
+    "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
 }
@@ -57,7 +57,7 @@ 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\]*" \
+  "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
   ] "\r\n"] "next back"
 
 # let's go somewhere where we can step some more
diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp
index 76ca0a6..911ad86 100644
--- a/gdb/testsuite/gdb.btrace/nexti.exp
+++ b/gdb/testsuite/gdb.btrace/nexti.exp
@@ -38,7 +38,7 @@ 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 .*" \
+    "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
 }
@@ -57,7 +57,7 @@ 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\]*" \
+  "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
   ] "\r\n"] "nexti back"
 
 # let's go somewhere where we can step some more
diff --git a/gdb/testsuite/gdb.btrace/nohist.exp b/gdb/testsuite/gdb.btrace/nohist.exp
index f53870b..f267250 100644
--- a/gdb/testsuite/gdb.btrace/nohist.exp
+++ b/gdb/testsuite/gdb.btrace/nohist.exp
@@ -34,7 +34,7 @@ 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\]*" \
+	"Recorded 0 instructions in 0 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
     ] "\r\n"]
 }
 
diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp
index e3febe1..22aded8 100644
--- a/gdb/testsuite/gdb.btrace/step.exp
+++ b/gdb/testsuite/gdb.btrace/step.exp
@@ -38,7 +38,7 @@ 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 .*" \
+    "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
 }
@@ -87,5 +87,5 @@ 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\]*" \
+  "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) 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 0276f72..a663f87 100644
--- a/gdb/testsuite/gdb.btrace/stepi.exp
+++ b/gdb/testsuite/gdb.btrace/stepi.exp
@@ -36,7 +36,7 @@ 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 .*" \
+    "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
 }
@@ -61,7 +61,7 @@ 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\]*" \
+  "Recorded 40 instructions in 16 functions \\\(0 gaps\\\) for \[^\\\r\\\n\]*" \
   ] "\r\n"] "stepi to live"
 
 # let's step from a goto position somewhere in the middle
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 01/15] btrace: add struct btrace_data
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (5 preceding siblings ...)
  2015-01-29 16:29 ` [PATCH v3 02/15] btrace: add format argument to supports_btrace Markus Metzger
@ 2015-01-29 16:30 ` Markus Metzger
  2015-01-29 16:30 ` [PATCH v3 06/15] btrace: update btrace_compute_ftrace parameters Markus Metzger
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:30 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Add a structure to hold the branch trace data and an enum to describe
the format of that data.  So far, only BTS is supported.  Also added
a NONE format to indicate that no branch trace data is available.

This will make it easier to support different branch trace formats in
the future.

2015-01-29  Markus Metzger  <markus.t.metzger@intel.com>

	* Makefile.in (SFILES): Add common/btrace-common.c.
	(COMMON_OBS): Add common/btrace-common.o.
	(btrace-common.o): Add build rules.
	* btrace.c (parse_xml_btrace): Update parameters.
	(parse_xml_btrace_block): Set format field.
	(btrace_add_pc, btrace_fetch): Use struct btrace_data.
	(do_btrace_data_cleanup, make_cleanup_btrace_data): New.
	(btrace_compute_ftrace): Split into this and...
	(btrace_compute_ftrace_bts): ...this.
	(btrace_stitch_trace): Split into this and...
	(btrace_stitch_bts): ...this.
	* btrace.h (parse_xml_btrace): Update parameters.
	(make_cleanup_btrace_data): New.
	* common/btrace-common.c: New.
	* common/btrace-common.h: Include common-defs.h.
	(btrace_block_s): Update comment.
	(btrace_format): New.
	(btrace_format_string): New.
	(btrace_data_bts): New.
	(btrace_data): New.
	(btrace_data_init, btrace_data_fini, btrace_data_empty): New.
	* remote.c (remote_read_btrace): Update parameters.
	* target.c (target_read_btrace): Update parameters.
	* target.h (target_read_btrace): Update parameters.
	(target_ops)<to_read_btrace>: Update parameters.
	* x86-linux-nat.c (x86_linux_read_btrace): Update parameters.
	* target-delegates.c: Regenerate.
	* target-debug (target_debug_print_struct_btrace_data_p): New.

nat/
	* linux-btrace.c (linux_read_btrace): Split into this and...
	(linux_read_bts): ...this.
	* linux-btrace.h (linux_read_btrace): Update parameters.

gdbserver/
	* Makefile.in (SFILES): Add common/btrace-common.c.
	(OBS): Add common/btrace-common.o.
	(btrace-common.o): Add build rules.
	* linux-low: Include btrace-common.h.
	(linux_low_read_btrace): Use struct btrace_data.  Call
	btrace_data_init and btrace_data_fini.
---
 gdb/Makefile.in            |   7 ++-
 gdb/btrace.c               | 154 ++++++++++++++++++++++++++++++++-------------
 gdb/btrace.h               |   6 +-
 gdb/common/btrace-common.c |  83 ++++++++++++++++++++++++
 gdb/common/btrace-common.h |  49 +++++++++++++--
 gdb/gdbserver/Makefile.in  |   8 ++-
 gdb/gdbserver/linux-low.c  |  37 ++++++++---
 gdb/nat/linux-btrace.c     |  36 ++++++++---
 gdb/nat/linux-btrace.h     |   2 +-
 gdb/remote.c               |   4 +-
 gdb/target-debug.h         |   2 +
 gdb/target-delegates.c     |   8 +--
 gdb/target.c               |   2 +-
 gdb/target.h               |   8 +--
 gdb/x86-linux-nat.c        |   2 +-
 15 files changed, 324 insertions(+), 84 deletions(-)
 create mode 100644 gdb/common/btrace-common.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 8addef4..bfebf61 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -873,6 +873,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	common/format.c common/filestuff.c btrace.c record-btrace.c ctf.c \
 	target/waitstatus.c common/print-utils.c common/rsp-low.c \
 	common/errors.c common/common-debug.c common/common-exceptions.c \
+	common/btrace-common.c \
 	$(SUBDIR_GCC_COMPILE_SRCS)
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -1060,7 +1061,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
 	format.o registry.o btrace.o record-btrace.o waitstatus.o \
 	print-utils.o rsp-low.o errors.o common-debug.o debug.o \
-	common-exceptions.o \
+	common-exceptions.o btrace-common.o \
 	$(SUBDIR_GCC_COMPILE_OBS)
 
 TSOBS = inflow.o
@@ -2234,6 +2235,10 @@ mingw-strerror.o: ${srcdir}/common/mingw-strerror.c
 	$(COMPILE) $(srcdir)/common/mingw-strerror.c
 	$(POSTCOMPILE)
 
+btrace-common.o: ${srcdir}/common/btrace-common.c
+	$(COMPILE) $(srcdir)/common/btrace-common.c
+	$(POSTCOMPILE)
+
 #
 # gdb/target/ dependencies
 #
diff --git a/gdb/btrace.c b/gdb/btrace.c
index b6e6bf7..3b20981 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -585,25 +585,22 @@ ftrace_update_insns (struct btrace_function *bfun, CORE_ADDR pc)
     ftrace_debug (bfun, "update insn");
 }
 
-/* Compute the function branch trace from a block branch trace BTRACE for
-   a thread given by BTINFO.  */
+/* Compute the function branch trace from BTS trace.  */
 
 static void
-btrace_compute_ftrace (struct btrace_thread_info *btinfo,
-		       VEC (btrace_block_s) *btrace)
+btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
+			   const struct btrace_data_bts *btrace)
 {
   struct btrace_function *begin, *end;
   struct gdbarch *gdbarch;
   unsigned int blk;
   int level;
 
-  DEBUG ("compute ftrace");
-
   gdbarch = target_gdbarch ();
   begin = btinfo->begin;
   end = btinfo->end;
   level = begin != NULL ? -btinfo->level : INT_MAX;
-  blk = VEC_length (btrace_block_s, btrace);
+  blk = VEC_length (btrace_block_s, btrace->blocks);
 
   while (blk != 0)
     {
@@ -612,7 +609,7 @@ btrace_compute_ftrace (struct btrace_thread_info *btinfo,
 
       blk -= 1;
 
-      block = VEC_index (btrace_block_s, btrace, blk);
+      block = VEC_index (btrace_block_s, btrace->blocks, blk);
       pc = block->begin;
 
       for (;;)
@@ -675,12 +672,34 @@ btrace_compute_ftrace (struct btrace_thread_info *btinfo,
   btinfo->level = -level;
 }
 
+/* Compute the function branch trace from a block branch trace BTRACE for
+   a thread given by BTINFO.  */
+
+static void
+btrace_compute_ftrace (struct btrace_thread_info *btinfo,
+		       struct btrace_data *btrace)
+{
+  DEBUG ("compute ftrace");
+
+  switch (btrace->format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return;
+
+    case BTRACE_FORMAT_BTS:
+      btrace_compute_ftrace_bts (btinfo, &btrace->variant.bts);
+      return;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
+
 /* Add an entry for the current PC.  */
 
 static void
 btrace_add_pc (struct thread_info *tp)
 {
-  VEC (btrace_block_s) *btrace;
+  struct btrace_data btrace;
   struct btrace_block *block;
   struct regcache *regcache;
   struct cleanup *cleanup;
@@ -689,14 +708,17 @@ btrace_add_pc (struct thread_info *tp)
   regcache = get_thread_regcache (tp->ptid);
   pc = regcache_read_pc (regcache);
 
-  btrace = NULL;
-  cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
+  btrace_data_init (&btrace);
+  btrace.format = BTRACE_FORMAT_BTS;
+  btrace.variant.bts.blocks = NULL;
 
-  block = VEC_safe_push (btrace_block_s, btrace, NULL);
+  cleanup = make_cleanup_btrace_data (&btrace);
+
+  block = VEC_safe_push (btrace_block_s, btrace.variant.bts.blocks, NULL);
   block->begin = pc;
   block->end = pc;
 
-  btrace_compute_ftrace (&tp->btrace, btrace);
+  btrace_compute_ftrace (&tp->btrace, &btrace);
 
   do_cleanups (cleanup);
 }
@@ -760,31 +782,24 @@ btrace_teardown (struct thread_info *tp)
   btrace_clear (tp);
 }
 
-/* Adjust the block trace in order to stitch old and new trace together.
-   BTRACE is the new delta trace between the last and the current stop.
-   BTINFO is the old branch trace until the last stop.
-   May modify BTRACE as well as the existing trace in BTINFO.
-   Return 0 on success, -1 otherwise.  */
+/* Stitch branch trace in BTS format.  */
 
 static int
-btrace_stitch_trace (VEC (btrace_block_s) **btrace,
-		     const struct btrace_thread_info *btinfo)
+btrace_stitch_bts (struct btrace_data_bts *btrace,
+		   const struct btrace_thread_info *btinfo)
 {
   struct btrace_function *last_bfun;
   struct btrace_insn *last_insn;
   btrace_block_s *first_new_block;
 
-  /* If we don't have trace, there's nothing to do.  */
-  if (VEC_empty (btrace_block_s, *btrace))
-    return 0;
-
   last_bfun = btinfo->end;
   gdb_assert (last_bfun != NULL);
 
   /* Beware that block trace starts with the most recent block, so the
      chronologically first block in the new trace is the last block in
      the new trace's block vector.  */
-  first_new_block = VEC_last (btrace_block_s, *btrace);
+  gdb_assert (!VEC_empty (btrace_block_s, btrace->blocks));
+  first_new_block = VEC_last (btrace_block_s, btrace->blocks);
   last_insn = VEC_last (btrace_insn_s, last_bfun->insn);
 
   /* If the current PC at the end of the block is the same as in our current
@@ -796,9 +811,9 @@ btrace_stitch_trace (VEC (btrace_block_s) **btrace,
      In the second case, the delta trace vector should contain exactly one
      entry for the partial block containing the current PC.  Remove it.  */
   if (first_new_block->end == last_insn->pc
-      && VEC_length (btrace_block_s, *btrace) == 1)
+      && VEC_length (btrace_block_s, btrace->blocks) == 1)
     {
-      VEC_pop (btrace_block_s, *btrace);
+      VEC_pop (btrace_block_s, btrace->blocks);
       return 0;
     }
 
@@ -834,6 +849,32 @@ btrace_stitch_trace (VEC (btrace_block_s) **btrace,
   return 0;
 }
 
+/* Adjust the block trace in order to stitch old and new trace together.
+   BTRACE is the new delta trace between the last and the current stop.
+   BTINFO is the old branch trace until the last stop.
+   May modifx BTRACE as well as the existing trace in BTINFO.
+   Return 0 on success, -1 otherwise.  */
+
+static int
+btrace_stitch_trace (struct btrace_data *btrace,
+		     const struct btrace_thread_info *btinfo)
+{
+  /* If we don't have trace, there's nothing to do.  */
+  if (btrace_data_empty (btrace))
+    return 0;
+
+  switch (btrace->format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return 0;
+
+    case BTRACE_FORMAT_BTS:
+      return btrace_stitch_bts (&btrace->variant.bts, btinfo);
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
+
 /* Clear the branch trace histories in BTINFO.  */
 
 static void
@@ -855,13 +896,12 @@ btrace_fetch (struct thread_info *tp)
 {
   struct btrace_thread_info *btinfo;
   struct btrace_target_info *tinfo;
-  VEC (btrace_block_s) *btrace;
+  struct btrace_data btrace;
   struct cleanup *cleanup;
   int errcode;
 
   DEBUG ("fetch thread %d (%s)", tp->num, target_pid_to_str (tp->ptid));
 
-  btrace = NULL;
   btinfo = &tp->btrace;
   tinfo = btinfo->target;
   if (tinfo == NULL)
@@ -873,7 +913,8 @@ btrace_fetch (struct thread_info *tp)
   if (btinfo->replay != NULL)
     return;
 
-  cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
+  btrace_data_init (&btrace);
+  cleanup = make_cleanup_btrace_data (&btrace);
 
   /* Let's first try to extend the trace we already have.  */
   if (btinfo->end != NULL)
@@ -890,7 +931,7 @@ btrace_fetch (struct thread_info *tp)
 	  errcode = target_read_btrace (&btrace, tinfo, BTRACE_READ_NEW);
 
 	  /* If we got any new trace, discard what we have.  */
-	  if (errcode == 0 && !VEC_empty (btrace_block_s, btrace))
+	  if (errcode == 0 && !btrace_data_empty (&btrace))
 	    btrace_clear (tp);
 	}
 
@@ -909,10 +950,10 @@ btrace_fetch (struct thread_info *tp)
     error (_("Failed to read branch trace."));
 
   /* Compute the trace, provided we have any.  */
-  if (!VEC_empty (btrace_block_s, btrace))
+  if (!btrace_data_empty (&btrace))
     {
       btrace_clear_history (btinfo);
-      btrace_compute_ftrace (btinfo, btrace);
+      btrace_compute_ftrace (btinfo, &btrace);
     }
 
   do_cleanups (cleanup);
@@ -984,16 +1025,30 @@ parse_xml_btrace_block (struct gdb_xml_parser *parser,
 			const struct gdb_xml_element *element,
 			void *user_data, VEC (gdb_xml_value_s) *attributes)
 {
-  VEC (btrace_block_s) **btrace;
+  struct btrace_data *btrace;
   struct btrace_block *block;
   ULONGEST *begin, *end;
 
   btrace = user_data;
-  block = VEC_safe_push (btrace_block_s, *btrace, NULL);
+
+  switch (btrace->format)
+    {
+    case BTRACE_FORMAT_BTS:
+      break;
+
+    case BTRACE_FORMAT_NONE:
+      btrace->format = BTRACE_FORMAT_BTS;
+      btrace->variant.bts.blocks = NULL;
+      break;
+
+    default:
+      gdb_xml_error (parser, _("Btrace format error."));
+    }
 
   begin = xml_find_attribute (attributes, "begin")->value;
   end = xml_find_attribute (attributes, "end")->value;
 
+  block = VEC_safe_push (btrace_block_s, btrace->variant.bts.blocks, NULL);
   block->begin = *begin;
   block->end = *end;
 }
@@ -1025,18 +1080,19 @@ static const struct gdb_xml_element btrace_elements[] = {
 
 /* See btrace.h.  */
 
-VEC (btrace_block_s) *
-parse_xml_btrace (const char *buffer)
+void
+parse_xml_btrace (struct btrace_data *btrace, const char *buffer)
 {
-  VEC (btrace_block_s) *btrace = NULL;
   struct cleanup *cleanup;
   int errcode;
 
 #if defined (HAVE_LIBEXPAT)
 
-  cleanup = make_cleanup (VEC_cleanup (btrace_block_s), &btrace);
+  btrace->format = BTRACE_FORMAT_NONE;
+
+  cleanup = make_cleanup_btrace_data (btrace);
   errcode = gdb_xml_parse_quick (_("btrace"), "btrace.dtd", btrace_elements,
-				 buffer, &btrace);
+				 buffer, btrace);
   if (errcode != 0)
     error (_("Error parsing branch trace."));
 
@@ -1048,8 +1104,6 @@ parse_xml_btrace (const char *buffer)
   error (_("Cannot process branch trace.  XML parsing is not supported."));
 
 #endif  /* !defined (HAVE_LIBEXPAT) */
-
-  return btrace;
 }
 
 /* See btrace.h.  */
@@ -1526,3 +1580,19 @@ btrace_is_empty (struct thread_info *tp)
 
   return btrace_insn_cmp (&begin, &end) == 0;
 }
+
+/* Forward the cleanup request.  */
+
+static void
+do_btrace_data_cleanup (void *arg)
+{
+  btrace_data_fini (arg);
+}
+
+/* See btrace.h.  */
+
+struct cleanup *
+make_cleanup_btrace_data (struct btrace_data *data)
+{
+  return make_cleanup (do_btrace_data_cleanup, data);
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
index e3a2419..730cb5f 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -235,8 +235,8 @@ extern void btrace_clear (struct thread_info *);
 /* Clear the branch trace for all threads when an object file goes away.  */
 extern void btrace_free_objfile (struct objfile *);
 
-/* Parse a branch trace xml document into a block vector.  */
-extern VEC (btrace_block_s) *parse_xml_btrace (const char*);
+/* Parse a branch trace xml document XML into DATA.  */
+extern void parse_xml_btrace (struct btrace_data *data, const char *xml);
 
 /* Dereference a branch trace instruction iterator.  Return a pointer to the
    instruction the iterator points to.  */
@@ -339,5 +339,7 @@ extern int btrace_is_replaying (struct thread_info *tp);
 /* Return non-zero if the branch trace for TP is empty; zero otherwise.  */
 extern int btrace_is_empty (struct thread_info *tp);
 
+/* Create a cleanup for DATA.  */
+extern struct cleanup *make_cleanup_btrace_data (struct btrace_data *data);
 
 #endif /* BTRACE_H */
diff --git a/gdb/common/btrace-common.c b/gdb/common/btrace-common.c
new file mode 100644
index 0000000..878cfed
--- /dev/null
+++ b/gdb/common/btrace-common.c
@@ -0,0 +1,83 @@
+/* Copyright (C) 2014 Free Software Foundation, Inc.
+
+   Contributed by Intel Corp. <markus.t.metzger@intel.com>
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "btrace-common.h"
+
+
+/* See btrace-common.h.  */
+
+const char *
+btrace_format_string (enum btrace_format format)
+{
+  switch (format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return _("No or unknown format");
+
+    case BTRACE_FORMAT_BTS:
+      return _("Intel(R) Branch Trace Store");
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
+}
+
+/* See btrace-common.h.  */
+
+void
+btrace_data_init (struct btrace_data *data)
+{
+  data->format = BTRACE_FORMAT_NONE;
+}
+
+/* See btrace-common.h.  */
+
+void
+btrace_data_fini (struct btrace_data *data)
+{
+  switch (data->format)
+    {
+    case BTRACE_FORMAT_NONE:
+      /* Nothing to do.  */
+      return;
+
+    case BTRACE_FORMAT_BTS:
+      VEC_free (btrace_block_s, data->variant.bts.blocks);
+      return;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
+
+/* See btrace-common.h.  */
+
+int
+btrace_data_empty (struct btrace_data *data)
+{
+  switch (data->format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return 1;
+
+    case BTRACE_FORMAT_BTS:
+      return VEC_empty (btrace_block_s, data->variant.bts.blocks);
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 6118c0d..a289e8a 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -45,13 +45,42 @@ struct btrace_block
   CORE_ADDR end;
 };
 
-/* Branch trace is represented as a vector of branch trace blocks starting with
-   the most recent block.  */
-typedef struct btrace_block btrace_block_s;
-
 /* Define functions operating on a vector of branch trace blocks.  */
+typedef struct btrace_block btrace_block_s;
 DEF_VEC_O (btrace_block_s);
 
+/* Enumeration of btrace formats.  */
+
+enum btrace_format
+{
+  /* No branch trace format.  */
+  BTRACE_FORMAT_NONE,
+
+  /* Branch trace is in Branch Trace Store format.
+     Actually, the format is a sequence of blocks derived from BTS.  */
+  BTRACE_FORMAT_BTS
+};
+
+/* Branch trace in BTS format.  */
+struct btrace_data_bts
+{
+  /* Branch trace is represented as a vector of branch trace blocks starting
+     with the most recent block.  */
+  VEC (btrace_block_s) *blocks;
+};
+
+/* The branch trace data.  */
+struct btrace_data
+{
+  enum btrace_format format;
+
+  union
+  {
+    /* Format == BTRACE_FORMAT_BTS.  */
+    struct btrace_data_bts bts;
+  } variant;
+};
+
 /* Target specific branch trace information.  */
 struct btrace_target_info;
 
@@ -87,4 +116,16 @@ enum btrace_error
   BTRACE_ERR_OVERFLOW
 };
 
+/* Return a string representation of FORMAT.  */
+extern const char *btrace_format_string (enum btrace_format format);
+
+/* Initialize DATA.  */
+extern void btrace_data_init (struct btrace_data *data);
+
+/* Cleanup DATA.  */
+extern void btrace_data_fini (struct btrace_data *data);
+
+/* Return non-zero if DATA is empty; zero otherwise.  */
+extern int btrace_data_empty (struct btrace_data *data);
+
 #endif /* BTRACE_COMMON_H */
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index b455c5b..e479c7c 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -173,7 +173,8 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/nat/mips-linux-watch.c $(srcdir)/common/print-utils.c \
 	$(srcdir)/common/rsp-low.c $(srcdir)/common/errors.c \
 	$(srcdir)/common/common-debug.c $(srcdir)/common/cleanups.c \
-	$(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c
+	$(srcdir)/common/common-exceptions.c $(srcdir)/symbol.c \
+	$(srcdir)/common/btrace-common.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -187,7 +188,7 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
       mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \
       common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
       tdesc.o print-utils.o rsp-low.o errors.o common-debug.o cleanups.o \
-      common-exceptions.o symbol.o \
+      common-exceptions.o symbol.o btrace-common.o \
       $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
 GDBREPLAY_OBS = gdbreplay.o version.o
 GDBSERVER_LIBS = @GDBSERVER_LIBS@
@@ -594,6 +595,9 @@ ppc-linux.o: ../nat/ppc-linux.c
 linux-personality.o: ../nat/linux-personality.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+btrace-common.o: ../common/btrace-common.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 
 aarch64.c : $(srcdir)/../regformats/aarch64.dat $(regdat_sh)
 	$(SHELL) $(regdat_sh) $(srcdir)/../regformats/aarch64.dat aarch64.c
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 5e37dd5..c82e563 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -103,6 +103,7 @@
 
 #ifdef HAVE_LINUX_BTRACE
 # include "nat/linux-btrace.h"
+# include "btrace-common.h"
 #endif
 
 #ifndef HAVE_ELF32_AUXV_T
@@ -5958,12 +5959,13 @@ static int
 linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
 		       int type)
 {
-  VEC (btrace_block_s) *btrace;
+  struct btrace_data btrace;
   struct btrace_block *block;
   enum btrace_error err;
   int i;
 
-  btrace = NULL;
+  btrace_data_init (&btrace);
+
   err = linux_read_btrace (&btrace, tinfo, type);
   if (err != BTRACE_ERR_NONE)
     {
@@ -5972,20 +5974,37 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
       else
 	buffer_grow_str0 (buffer, "E.Generic Error.");
 
+      btrace_data_fini (&btrace);
       return -1;
     }
 
-  buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
-  buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
+  switch (btrace.format)
+    {
+    case BTRACE_FORMAT_NONE:
+      buffer_grow_str0 (buffer, "E.No Trace.");
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      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));
+      for (i = 0;
+	   VEC_iterate (btrace_block_s, btrace.variant.bts.blocks, i, block);
+	   i++)
+	buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
+			   paddress (block->begin), paddress (block->end));
 
-  buffer_grow_str0 (buffer, "</btrace>\n");
+      buffer_grow_str0 (buffer, "</btrace>\n");
+      break;
+
+    default:
+      buffer_grow_str0 (buffer, "E.Unknown Trace Format.");
 
-  VEC_free (btrace_block_s, btrace);
+      btrace_data_fini (&btrace);
+      return -1;
+    }
 
+  btrace_data_fini (&btrace);
   return 0;
 }
 #endif /* HAVE_LINUX_BTRACE */
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 1181a4c..6cec5d0 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -495,12 +495,13 @@ linux_btrace_has_changed (struct btrace_target_info *tinfo)
   return header->data_head != tinfo->data_head;
 }
 
-/* See linux-btrace.h.  */
+/* Read branch trace data in BTS format for the thread given by TINFO into
+   BTRACE using the TYPE reading method.  */
 
-enum btrace_error
-linux_read_btrace (VEC (btrace_block_s) **btrace,
-		   struct btrace_target_info *tinfo,
-		   enum btrace_read_type type)
+static enum btrace_error
+linux_read_bts (struct btrace_data_bts *btrace,
+		struct btrace_target_info *tinfo,
+		enum btrace_read_type type)
 {
   volatile struct perf_event_mmap_page *header;
   const uint8_t *begin, *end, *start;
@@ -522,7 +523,7 @@ linux_read_btrace (VEC (btrace_block_s) **btrace,
       data_head = header->data_head;
 
       /* Delete any leftover trace from the previous iteration.  */
-      VEC_free (btrace_block_s, *btrace);
+      VEC_free (btrace_block_s, btrace->blocks);
 
       if (type == BTRACE_READ_DELTA)
 	{
@@ -559,7 +560,7 @@ linux_read_btrace (VEC (btrace_block_s) **btrace,
       else
 	end = perf_event_buffer_end (tinfo);
 
-      *btrace = perf_event_read_bts (tinfo, begin, end, start, size);
+      btrace->blocks = perf_event_read_bts (tinfo, begin, end, start, size);
 
       /* The stopping thread notifies its ptracer before it is scheduled out.
 	 On multi-core systems, the debugger might therefore run while the
@@ -575,12 +576,27 @@ linux_read_btrace (VEC (btrace_block_s) **btrace,
   /* Prune the incomplete last block (i.e. the first one of inferior execution)
      if we're not doing a delta read.  There is no way of filling in its zeroed
      BEGIN element.  */
-  if (!VEC_empty (btrace_block_s, *btrace) && type != BTRACE_READ_DELTA)
-    VEC_pop (btrace_block_s, *btrace);
+  if (!VEC_empty (btrace_block_s, btrace->blocks)
+      && type != BTRACE_READ_DELTA)
+    VEC_pop (btrace_block_s, btrace->blocks);
 
   return BTRACE_ERR_NONE;
 }
 
+/* See linux-btrace.h.  */
+
+enum btrace_error
+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;
+
+  return linux_read_bts (&btrace->variant.bts, tinfo, type);
+}
+
 #else /* !HAVE_LINUX_PERF_EVENT_H */
 
 /* See linux-btrace.h.  */
@@ -610,7 +626,7 @@ linux_disable_btrace (struct btrace_target_info *tinfo)
 /* See linux-btrace.h.  */
 
 enum btrace_error
-linux_read_btrace (VEC (btrace_block_s) **btrace,
+linux_read_btrace (struct btrace_data *btrace,
 		   struct btrace_target_info *tinfo,
 		   enum btrace_read_type type)
 {
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index 3bfb798..1b11aba 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -70,7 +70,7 @@ extern struct btrace_target_info *linux_enable_btrace (ptid_t ptid);
 extern enum btrace_error linux_disable_btrace (struct btrace_target_info *ti);
 
 /* See to_read_btrace in target.h.  */
-extern enum btrace_error linux_read_btrace (VEC (btrace_block_s) **btrace,
+extern enum btrace_error linux_read_btrace (struct btrace_data *btrace,
 					    struct btrace_target_info *btinfo,
 					    enum btrace_read_type type);
 
diff --git a/gdb/remote.c b/gdb/remote.c
index c4d09ba..e73cdde 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11419,7 +11419,7 @@ remote_teardown_btrace (struct target_ops *self,
 
 static enum btrace_error
 remote_read_btrace (struct target_ops *self,
-		    VEC (btrace_block_s) **btrace,
+		    struct btrace_data *btrace,
 		    struct btrace_target_info *tinfo,
 		    enum btrace_read_type type)
 {
@@ -11459,7 +11459,7 @@ remote_read_btrace (struct target_ops *self,
     return BTRACE_ERR_UNKNOWN;
 
   cleanup = make_cleanup (xfree, xml);
-  *btrace = parse_xml_btrace (xml);
+  parse_xml_btrace (btrace, xml);
   do_cleanups (cleanup);
 
   return BTRACE_ERR_NONE;
diff --git a/gdb/target-debug.h b/gdb/target-debug.h
index 65db5d9..8a32810 100644
--- a/gdb/target-debug.h
+++ b/gdb/target-debug.h
@@ -144,6 +144,8 @@
   target_debug_do_print (host_address_to_string (X))
 #define target_debug_print_const_struct_frame_unwind_p(X)	\
   target_debug_do_print (host_address_to_string (X))
+#define target_debug_print_struct_btrace_data_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 9beb5ff..00956ba 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -3191,20 +3191,20 @@ debug_teardown_btrace (struct target_ops *self, struct btrace_target_info *arg1)
 }
 
 static enum btrace_error
-delegate_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
+delegate_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
 {
   self = self->beneath;
   return self->to_read_btrace (self, arg1, arg2, arg3);
 }
 
 static enum btrace_error
-tdefault_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
+tdefault_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
 {
   tcomplain ();
 }
 
 static enum btrace_error
-debug_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
+debug_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct btrace_target_info *arg2, enum btrace_read_type arg3)
 {
   enum btrace_error result;
   fprintf_unfiltered (gdb_stdlog, "-> %s->to_read_btrace (...)\n", debug_target.to_shortname);
@@ -3212,7 +3212,7 @@ debug_read_btrace (struct target_ops *self, VEC (btrace_block_s) **arg1, struct
   fprintf_unfiltered (gdb_stdlog, "<- %s->to_read_btrace (", debug_target.to_shortname);
   target_debug_print_struct_target_ops_p (&debug_target);
   fputs_unfiltered (", ", gdb_stdlog);
-  target_debug_print_VEC__btrace_block_s__pp (arg1);
+  target_debug_print_struct_btrace_data_p (arg1);
   fputs_unfiltered (", ", gdb_stdlog);
   target_debug_print_struct_btrace_target_info_p (arg2);
   fputs_unfiltered (", ", gdb_stdlog);
diff --git a/gdb/target.c b/gdb/target.c
index 5f0ed6f..763ddcb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3414,7 +3414,7 @@ target_teardown_btrace (struct btrace_target_info *btinfo)
 /* See target.h.  */
 
 enum btrace_error
-target_read_btrace (VEC (btrace_block_s) **btrace,
+target_read_btrace (struct btrace_data *btrace,
 		    struct btrace_target_info *btinfo,
 		    enum btrace_read_type type)
 {
diff --git a/gdb/target.h b/gdb/target.h
index 2a40cd1..36fa3c6 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1022,11 +1022,9 @@ struct target_ops
       TARGET_DEFAULT_NORETURN (tcomplain ());
 
     /* Read branch trace data for the thread indicated by BTINFO into DATA.
-       DATA is cleared before new trace is added.
-       The branch trace will start with the most recent block and continue
-       towards older blocks.  */
+       DATA is cleared before new trace is added.  */
     enum btrace_error (*to_read_btrace) (struct target_ops *self,
-					 VEC (btrace_block_s) **data,
+					 struct btrace_data *data,
 					 struct btrace_target_info *btinfo,
 					 enum btrace_read_type type)
       TARGET_DEFAULT_NORETURN (tcomplain ());
@@ -2230,7 +2228,7 @@ extern void target_disable_btrace (struct btrace_target_info *btinfo);
 extern void target_teardown_btrace (struct btrace_target_info *btinfo);
 
 /* See to_read_btrace in struct target_ops.  */
-extern enum btrace_error target_read_btrace (VEC (btrace_block_s) **,
+extern enum btrace_error target_read_btrace (struct btrace_data *,
 					     struct btrace_target_info *,
 					     enum btrace_read_type);
 
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index f7e9037..78b547b 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -470,7 +470,7 @@ x86_linux_teardown_btrace (struct target_ops *self,
 
 static enum btrace_error
 x86_linux_read_btrace (struct target_ops *self,
-		       VEC (btrace_block_s) **data,
+		       struct btrace_data *data,
 		       struct btrace_target_info *btinfo,
 		       enum btrace_read_type type)
 {
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 14/15] configure: check for libipt
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (7 preceding siblings ...)
  2015-01-29 16:30 ` [PATCH v3 06/15] btrace: update btrace_compute_ftrace parameters Markus Metzger
@ 2015-01-29 16:30 ` Markus Metzger
  2015-01-29 16:30 ` [PATCH v3 09/15] record-btrace: indicate gaps Markus Metzger
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:30 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

2015-01-29  Markus Metzger  <markus.t.metzger@intel.com>

	* configure.ac: Check for libipt
	* configure: Regenerate.
	* config.in: Regenerate.
	* Makefile.in (LIBIPT): New.
	(CLIBS): Add $LIBIPT.
---
 gdb/Makefile.in  |   5 +-
 gdb/config.in    |   3 +
 gdb/configure    | 498 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/configure.ac |  20 +++
 4 files changed, 525 insertions(+), 1 deletion(-)

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 00fb2cd..da5a62f 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -163,6 +163,9 @@ LIBLZMA = @LIBLZMA@
 # available.
 LIBBABELTRACE = @LIBBABELTRACE@
 
+# Where is libipt?  This will be empty if libipt was not available.
+LIBIPT = @LIBIPT@
+
 WARN_CFLAGS = @WARN_CFLAGS@
 WERROR_CFLAGS = @WERROR_CFLAGS@
 GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -577,7 +580,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
 CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
-	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
+	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
 	$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
 CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/config.in b/gdb/config.in
index 806cbac..c8555c8 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -189,6 +189,9 @@
 /* Define to 1 if you have the `libiconvlist' function. */
 #undef HAVE_LIBICONVLIST
 
+/* Define if you have the ipt library. */
+#undef HAVE_LIBIPT
+
 /* Define if you have the lzma library. */
 #undef HAVE_LIBLZMA
 
diff --git a/gdb/configure b/gdb/configure
index 9632f9a..7aa563b 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -658,6 +658,9 @@ TARGET_SYSTEM_ROOT
 CONFIG_LDFLAGS
 RDYNAMIC
 ALLOCA
+LTLIBIPT
+LIBIPT
+HAVE_LIBIPT
 HAVE_GUILE_FALSE
 HAVE_GUILE_TRUE
 GUILE_LIBS
@@ -824,6 +827,8 @@ with_libexpat_prefix
 with_python
 with_guile
 enable_libmcheck
+with_intel_pt
+with_libipt_prefix
 with_included_regex
 with_sysroot
 with_system_gdbinit
@@ -1542,6 +1547,9 @@ Optional Packages:
                           (auto/yes/no/<python-program>)
   --with-guile[=GUILE]    include guile support
                           (auto/yes/no/<guile-version>/<pkg-config-program>)
+  --with-intel-pt         include Intel Processor Trace support (auto/yes/no)
+  --with-libipt-prefix[=DIR]  search for libipt in DIR/include and DIR/lib
+  --without-libipt-prefix     don't search for libipt in includedir and libdir
   --without-included-regex
                           don't use included regex; this is the default on
                           systems with version 2 of the GNU C library (use
@@ -9366,6 +9374,496 @@ if test "$ENABLE_LIBMCHECK" = "yes" \
 $as_echo "$as_me: WARNING: --enable-libmcheck may lead to spurious crashes if threads are used in python" >&2;}
 fi
 
+
+# Check whether --with-intel_pt was given.
+if test "${with_intel_pt+set}" = set; then :
+  withval=$with_intel_pt;
+else
+  with_intel_pt=auto
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use intel pt" >&5
+$as_echo_n "checking whether to use intel pt... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_intel_pt" >&5
+$as_echo "$with_intel_pt" >&6; }
+
+if test "${with_intel_pt}" = no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Intel(R) Processor Trace support disabled; some features may be unavailable." >&5
+$as_echo "$as_me: WARNING: Intel(R) Processor Trace support disabled; some features may be unavailable." >&2;}
+  HAVE_LIBIPT=no
+else
+
+
+
+
+
+
+
+
+    use_additional=yes
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+
+# Check whether --with-libipt-prefix was given.
+if test "${with_libipt_prefix+set}" = set; then :
+  withval=$with_libipt_prefix;
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/lib"
+      fi
+    fi
+
+fi
+
+      LIBIPT=
+  LTLIBIPT=
+  INCIPT=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='ipt '
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+                        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIBIPT="${LIBIPT}${LIBIPT:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }$value"
+          else
+                                    :
+          fi
+        else
+                              found_dir=
+          found_la=
+          found_so=
+          found_a=
+          if test $use_additional = yes; then
+            if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+              found_dir="$additional_libdir"
+              found_so="$additional_libdir/lib$name.$shlibext"
+              if test -f "$additional_libdir/lib$name.la"; then
+                found_la="$additional_libdir/lib$name.la"
+              fi
+            else
+              if test -f "$additional_libdir/lib$name.$libext"; then
+                found_dir="$additional_libdir"
+                found_a="$additional_libdir/lib$name.$libext"
+                if test -f "$additional_libdir/lib$name.la"; then
+                  found_la="$additional_libdir/lib$name.la"
+                fi
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIBIPT; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+                    found_dir="$dir"
+                    found_so="$dir/lib$name.$shlibext"
+                    if test -f "$dir/lib$name.la"; then
+                      found_la="$dir/lib$name.la"
+                    fi
+                  else
+                    if test -f "$dir/lib$name.$libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/lib$name.$libext"
+                      if test -f "$dir/lib$name.la"; then
+                        found_la="$dir/lib$name.la"
+                      fi
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+                        LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+                                                        if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+                                LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so"
+              else
+                                                                                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                                if test "$hardcode_direct" = yes; then
+                                                      LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so"
+                else
+                  if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+                                                            LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so"
+                                                            haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                                                                                haveit=
+                    for x in $LDFLAGS $LIBIPT; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIBIPT="${LIBIPT}${LIBIPT:+ }-L$found_dir"
+                    fi
+                    if test "$hardcode_minus_L" != no; then
+                                                                                        LIBIPT="${LIBIPT}${LIBIPT:+ }$found_so"
+                    else
+                                                                                                                                                                                LIBIPT="${LIBIPT}${LIBIPT:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                                LIBIPT="${LIBIPT}${LIBIPT:+ }$found_a"
+              else
+                                                LIBIPT="${LIBIPT}${LIBIPT:+ }-L$found_dir -l$name"
+              fi
+            fi
+                        additional_includedir=
+            case "$found_dir" in
+              */lib | */lib/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+                                                                                                                if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux*) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INCIPT; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                                            INCIPT="${INCIPT}${INCIPT:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+                        if test -n "$found_la"; then
+                                                        save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+                            for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                                                                                                                                                                if test "X$additional_libdir" != "X/usr/lib"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/lib"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux*) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIBIPT; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LIBIPT="${LIBIPT}${LIBIPT:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIBIPT; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                                                        LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                                                                  haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                                                                  haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                                        names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                                                                                names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                                        LIBIPT="${LIBIPT}${LIBIPT:+ }$dep"
+                    LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+                                                            LIBIPT="${LIBIPT}${LIBIPT:+ }-l$name"
+            LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-l$name"
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$hardcode_libdir_separator"; then
+                        alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+      done
+            acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIBIPT="${LIBIPT}${LIBIPT:+ }$flag"
+    else
+            for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIBIPT="${LIBIPT}${LIBIPT:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+            for found_dir in $ltrpathdirs; do
+      LTLIBIPT="${LTLIBIPT}${LTLIBIPT:+ }-R$found_dir"
+    done
+  fi
+
+
+        ac_save_CPPFLAGS="$CPPFLAGS"
+
+  for element in $INCIPT; do
+    haveit=
+    for x in $CPPFLAGS; do
+
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  eval x=\"$x\"
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+    fi
+  done
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libipt" >&5
+$as_echo_n "checking for libipt... " >&6; }
+if test "${ac_cv_libipt+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS $LIBIPT"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include "intel-pt.h"
+int
+main ()
+{
+pt_configure (0);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_libipt=yes
+else
+  ac_cv_libipt=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libipt" >&5
+$as_echo "$ac_cv_libipt" >&6; }
+  if test "$ac_cv_libipt" = yes; then
+    HAVE_LIBIPT=yes
+
+$as_echo "#define HAVE_LIBIPT 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libipt" >&5
+$as_echo_n "checking how to link with libipt... " >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBIPT" >&5
+$as_echo "$LIBIPT" >&6; }
+  else
+    HAVE_LIBIPT=no
+            CPPFLAGS="$ac_save_CPPFLAGS"
+    LIBIPT=
+    LTLIBIPT=
+  fi
+
+
+
+
+
+
+  if test "$HAVE_LIBIPT" != yes; then
+    if test "$with_intel_pt" = yes; then
+      as_fn_error "libipt is missing or unusable" "$LINENO" 5
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: libipt is missing or unusable; some features may be unavailable." >&5
+$as_echo "$as_me: WARNING: libipt is missing or unusable; some features may be unavailable." >&2;}
+    fi
+  fi
+fi
+
 # ------------------------- #
 # Checks for header files.  #
 # ------------------------- #
diff --git a/gdb/configure.ac b/gdb/configure.ac
index dfc6947..d8bf021 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1235,6 +1235,26 @@ if test "$ENABLE_LIBMCHECK" = "yes" \
   AC_MSG_WARN(--enable-libmcheck may lead to spurious crashes if threads are used in python)
 fi
 
+AC_ARG_WITH(intel_pt,
+  AS_HELP_STRING([--with-intel-pt], [include Intel Processor Trace support (auto/yes/no)]),
+  [], [with_intel_pt=auto])
+AC_MSG_CHECKING([whether to use intel pt])
+AC_MSG_RESULT([$with_intel_pt])
+
+if test "${with_intel_pt}" = no; then
+  AC_MSG_WARN([Intel(R) Processor Trace support disabled; some features may be unavailable.])
+  HAVE_LIBIPT=no
+else
+  AC_LIB_HAVE_LINKFLAGS([ipt], [], [#include "intel-pt.h"], [pt_configure (0);])
+  if test "$HAVE_LIBIPT" != yes; then
+    if test "$with_intel_pt" = yes; then
+      AC_MSG_ERROR([libipt is missing or unusable])
+    else
+      AC_MSG_WARN([libipt is missing or unusable; some features may be unavailable.])
+    fi
+  fi
+fi
+
 # ------------------------- #
 # Checks for header files.  #
 # ------------------------- #
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 06/15] btrace: update btrace_compute_ftrace parameters
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (6 preceding siblings ...)
  2015-01-29 16:30 ` [PATCH v3 01/15] btrace: add struct btrace_data Markus Metzger
@ 2015-01-29 16:30 ` Markus Metzger
  2015-01-29 16:30 ` [PATCH v3 14/15] configure: check for libipt Markus Metzger
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:30 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Pass thread_info instead of btrace_thread_info to btrace_compute_ftrace.
We will need the thread_info in subsequent patches.

2015-01-29  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.c (btrace_compute_ftrace_bts, btrace_compute_ftrace):
	Update parameters.  Update users.
---
 gdb/btrace.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index c7932bb..e96499e 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -588,15 +588,17 @@ ftrace_update_insns (struct btrace_function *bfun, CORE_ADDR pc)
 /* Compute the function branch trace from BTS trace.  */
 
 static void
-btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
+btrace_compute_ftrace_bts (struct thread_info *tp,
 			   const struct btrace_data_bts *btrace)
 {
+  struct btrace_thread_info *btinfo;
   struct btrace_function *begin, *end;
   struct gdbarch *gdbarch;
   unsigned int blk;
   int level;
 
   gdbarch = target_gdbarch ();
+  btinfo = &tp->btrace;
   begin = btinfo->begin;
   end = btinfo->end;
   level = begin != NULL ? -btinfo->level : INT_MAX;
@@ -676,8 +678,7 @@ btrace_compute_ftrace_bts (struct btrace_thread_info *btinfo,
    a thread given by BTINFO.  */
 
 static void
-btrace_compute_ftrace (struct btrace_thread_info *btinfo,
-		       struct btrace_data *btrace)
+btrace_compute_ftrace (struct thread_info *tp, struct btrace_data *btrace)
 {
   DEBUG ("compute ftrace");
 
@@ -687,7 +688,7 @@ btrace_compute_ftrace (struct btrace_thread_info *btinfo,
       return;
 
     case BTRACE_FORMAT_BTS:
-      btrace_compute_ftrace_bts (btinfo, &btrace->variant.bts);
+      btrace_compute_ftrace_bts (tp, &btrace->variant.bts);
       return;
     }
 
@@ -718,7 +719,7 @@ btrace_add_pc (struct thread_info *tp)
   block->begin = pc;
   block->end = pc;
 
-  btrace_compute_ftrace (&tp->btrace, &btrace);
+  btrace_compute_ftrace (tp, &btrace);
 
   do_cleanups (cleanup);
 }
@@ -964,7 +965,7 @@ btrace_fetch (struct thread_info *tp)
   if (!btrace_data_empty (&btrace))
     {
       btrace_clear_history (btinfo);
-      btrace_compute_ftrace (btinfo, &btrace);
+      btrace_compute_ftrace (tp, &btrace);
     }
 
   do_cleanups (cleanup);
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 11/15] btrace: work around _dl_runtime_resolve returning to resolved function
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (9 preceding siblings ...)
  2015-01-29 16:30 ` [PATCH v3 09/15] record-btrace: indicate gaps Markus Metzger
@ 2015-01-29 16:33 ` Markus Metzger
  2015-01-29 17:11 ` [PATCH v3 10/15] btrace: less debug output Markus Metzger
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 16:33 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Jan Kratochvil

On some systems, _dl_runtime_resolve returns to the resolved function
instead of jumping to it.  Since btrace will not find the function in
the current stack back trace, it will start a new back trace on the
same level.  It will look the same to the user via the backtrace
command but the frames will have different id's which confuses stepping.

This fixes a test fail on 32-bit systems reported by Jan Kratochvil.

CC: Jan Kratochvil <jan.kratochvil@redhat.com>

2015-01-29  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* btrace.c (ftrace_update_function): Treat return as tailcall for
	"_dl_runtime_resolve".
---
 gdb/btrace.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index b29e0b2..45e9035 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -506,7 +506,24 @@ ftrace_update_function (struct btrace_function *bfun, CORE_ADDR pc)
       switch (last->iclass)
 	{
 	case BTRACE_INSN_RETURN:
-	  return ftrace_new_return (bfun, mfun, fun);
+	  {
+	    const char *fname;
+
+	    /* On some systems, _dl_runtime_resolve returns to the resolved
+	       function instead of jumping to it.  From our perspective,
+	       however, this is a tailcall.
+	       If we treated it as return, we wouldn't be able to find the
+	       resolved function in our stack back trace.  Hence, we would
+	       lose the current stack back trace and start anew with an empty
+	       back trace.  When the resolved function returns, we would then
+	       create a stack back trace with the same function names but
+	       different frame id's.  This will confuse stepping.  */
+	    fname = ftrace_print_function_name (bfun);
+	    if (strcmp (fname, "_dl_runtime_resolve") == 0)
+	      return ftrace_new_tailcall (bfun, mfun, fun);
+
+	    return ftrace_new_return (bfun, mfun, fun);
+	  }
 
 	case BTRACE_INSN_CALL:
 	  /* Ignore calls to the next instruction.  They are used for PIC.  */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 10/15] btrace: less debug output
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (10 preceding siblings ...)
  2015-01-29 16:33 ` [PATCH v3 11/15] btrace: work around _dl_runtime_resolve returning to resolved function Markus Metzger
@ 2015-01-29 17:11 ` Markus Metzger
  2015-01-29 17:11 ` [PATCH v3 03/15] btrace, linux: add perf event buffer abstraction Markus Metzger
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 17:11 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

For some programs, "set debug record 1" will print tons of "no lines at
0x..." messages.  This is not always helpful.

Change it to only print those messages for values bigger than 1.

2015-01-29  Markus Metzger <markus.t.metzger@intel.com>

gdb/
	* btrace.c (ftrace_update_lines): Add record_debug check.
---
 gdb/btrace.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 206e692..b29e0b2 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -554,7 +554,8 @@ ftrace_update_lines (struct btrace_function *bfun, CORE_ADDR pc)
   sal = find_pc_line (pc, 0);
   if (sal.symtab == NULL || sal.line == 0)
     {
-      DEBUG_FTRACE ("no lines at %s", core_addr_to_string_nz (pc));
+      if (record_debug > 1)
+	DEBUG_FTRACE ("no lines at %s", core_addr_to_string_nz (pc));
       return;
     }
 
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 03/15] btrace, linux: add perf event buffer abstraction
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (11 preceding siblings ...)
  2015-01-29 17:11 ` [PATCH v3 10/15] btrace: less debug output Markus Metzger
@ 2015-01-29 17:11 ` Markus Metzger
  2015-01-29 18:35 ` [PATCH v3 04/15] record btrace: add configuration struct Markus Metzger
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 17:11 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Collect perf event buffer related fields from btrace_target_info into
a new struct perf_event_buffer.  Update functions that operated on the
buffer to take a struct perf_event_buffer pointer rather than a
btrace_target_info pointer.

2015-01-29  Markus Metzger <markus.t.metzger@intel.com>

	* nat/linux-btrace.h (perf_event_buffer): New.
	(btrace_target_info) <buffer, size, data_head>: Replace with ...
	<bts>: ... this.
	* nat/linux-btrace.c (perf_event_header, perf_event_mmap_size)
	(perf_event_buffer_size, perf_event_buffer_begin)
	(perf_event_buffer_end, linux_btrace_has_changed): Removed.
	Updated users.
	(perf_event_new_data): New.
---
 gdb/nat/linux-btrace.c | 113 +++++++++++++++++--------------------------------
 gdb/nat/linux-btrace.h |  34 +++++++++++----
 2 files changed, 63 insertions(+), 84 deletions(-)

diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 08eb49b..5b22661 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -59,45 +59,12 @@ struct perf_event_sample
   struct perf_event_bts bts;
 };
 
-/* Get the perf_event header.  */
+/* Return non-zero if there is new data in PEVENT; zero otherwise.  */
 
-static inline volatile struct perf_event_mmap_page *
-perf_event_header (struct btrace_target_info* tinfo)
-{
-  return tinfo->buffer;
-}
-
-/* Get the size of the perf_event mmap buffer.  */
-
-static inline size_t
-perf_event_mmap_size (const struct btrace_target_info *tinfo)
-{
-  /* The branch trace buffer is preceded by a configuration page.  */
-  return (tinfo->size + 1) * PAGE_SIZE;
-}
-
-/* Get the size of the perf_event buffer.  */
-
-static inline size_t
-perf_event_buffer_size (struct btrace_target_info* tinfo)
-{
-  return tinfo->size * PAGE_SIZE;
-}
-
-/* Get the start address of the perf_event buffer.  */
-
-static inline const uint8_t *
-perf_event_buffer_begin (struct btrace_target_info* tinfo)
-{
-  return ((const uint8_t *) tinfo->buffer) + PAGE_SIZE;
-}
-
-/* Get the end address of the perf_event buffer.  */
-
-static inline const uint8_t *
-perf_event_buffer_end (struct btrace_target_info* tinfo)
+static int
+perf_event_new_data (const struct perf_event_buffer *pev)
 {
-  return perf_event_buffer_begin (tinfo) + perf_event_buffer_size (tinfo);
+  return *pev->data_head != pev->last_head;
 }
 
 /* Check whether an address is in the kernel.  */
@@ -162,11 +129,12 @@ perf_event_sample_ok (const struct perf_event_sample *sample)
 
 static VEC (btrace_block_s) *
 perf_event_read_bts (struct btrace_target_info* tinfo, const uint8_t *begin,
-		     const uint8_t *end, const uint8_t *start, size_t size)
+		     const uint8_t *end, const uint8_t *start,
+		     unsigned long long size)
 {
   VEC (btrace_block_s) *btrace = NULL;
   struct perf_event_sample sample;
-  size_t read = 0;
+  unsigned long long read = 0;
   struct btrace_block block = { 0, 0 };
   struct regcache *regcache;
 
@@ -432,6 +400,7 @@ linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
 struct btrace_target_info *
 linux_enable_btrace (ptid_t ptid)
 {
+  struct perf_event_mmap_page *header;
   struct btrace_target_info *tinfo;
   int pid, pg;
 
@@ -467,15 +436,24 @@ linux_enable_btrace (ptid_t ptid)
   for (pg = 4; pg >= 0; --pg)
     {
       /* The number of pages we request needs to be a power of two.  */
-      tinfo->size = 1 << pg;
-      tinfo->buffer = mmap (NULL, perf_event_mmap_size (tinfo),
-			    PROT_READ, MAP_SHARED, tinfo->file, 0);
-      if (tinfo->buffer == MAP_FAILED)
-	continue;
-
-      return tinfo;
+      header = mmap (NULL, ((1 << pg) + 1) * PAGE_SIZE, PROT_READ, MAP_SHARED,
+		     tinfo->file, 0);
+      if (header != MAP_FAILED)
+	break;
     }
 
+  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;
+
+  return tinfo;
+
+ err_file:
   /* We were not able to allocate any buffer.  */
   close (tinfo->file);
 
@@ -489,29 +467,13 @@ linux_enable_btrace (ptid_t ptid)
 enum btrace_error
 linux_disable_btrace (struct btrace_target_info *tinfo)
 {
-  int errcode;
-
-  errno = 0;
-  errcode = munmap (tinfo->buffer, perf_event_mmap_size (tinfo));
-  if (errcode != 0)
-    return BTRACE_ERR_UNKNOWN;
-
+  munmap((void *) tinfo->header, tinfo->bts.size + PAGE_SIZE);
   close (tinfo->file);
   xfree (tinfo);
 
   return BTRACE_ERR_NONE;
 }
 
-/* Check whether the branch trace has changed.  */
-
-static int
-linux_btrace_has_changed (struct btrace_target_info *tinfo)
-{
-  volatile struct perf_event_mmap_page *header = perf_event_header (tinfo);
-
-  return header->data_head != tinfo->data_head;
-}
-
 /* Read branch trace data in BTS format for the thread given by TINFO into
    BTRACE using the TYPE reading method.  */
 
@@ -520,24 +482,25 @@ linux_read_bts (struct btrace_data_bts *btrace,
 		struct btrace_target_info *tinfo,
 		enum btrace_read_type type)
 {
-  volatile struct perf_event_mmap_page *header;
+  struct perf_event_buffer *pevent;
   const uint8_t *begin, *end, *start;
-  unsigned long data_head, data_tail, retries = 5;
-  size_t buffer_size, size;
+  unsigned long long data_head, data_tail, buffer_size, size;
+  unsigned int retries = 5;
+
+  pevent = &tinfo->bts;
 
   /* For delta reads, we return at least the partial last block containing
      the current PC.  */
-  if (type == BTRACE_READ_NEW && !linux_btrace_has_changed (tinfo))
+  if (type == BTRACE_READ_NEW && !perf_event_new_data (pevent))
     return BTRACE_ERR_NONE;
 
-  header = perf_event_header (tinfo);
-  buffer_size = perf_event_buffer_size (tinfo);
-  data_tail = tinfo->data_head;
+  buffer_size = pevent->size;
+  data_tail = pevent->last_head;
 
   /* We may need to retry reading the trace.  See below.  */
   while (retries--)
     {
-      data_head = header->data_head;
+      data_head = *pevent->data_head;
 
       /* Delete any leftover trace from the previous iteration.  */
       VEC_free (btrace_block_s, btrace->blocks);
@@ -569,13 +532,13 @@ linux_read_bts (struct btrace_data_bts *btrace,
 	}
 
       /* Data_head keeps growing; the buffer itself is circular.  */
-      begin = perf_event_buffer_begin (tinfo);
+      begin = pevent->mem;
       start = begin + data_head % buffer_size;
 
       if (data_head <= buffer_size)
 	end = start;
       else
-	end = perf_event_buffer_end (tinfo);
+	end = begin + pevent->size;
 
       btrace->blocks = perf_event_read_bts (tinfo, begin, end, start, size);
 
@@ -584,11 +547,11 @@ linux_read_bts (struct btrace_data_bts *btrace,
 	 kernel might be writing the last branch trace records.
 
 	 Let's check whether the data head moved while we read the trace.  */
-      if (data_head == header->data_head)
+      if (data_head == *pevent->data_head)
 	break;
     }
 
-  tinfo->data_head = data_head;
+  pevent->last_head = data_head;
 
   /* Prune the incomplete last block (i.e. the first one of inferior execution)
      if we're not doing a delta read.  There is no way of filling in its zeroed
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index 24e06e8..602a571 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -32,6 +32,24 @@
 
 struct target_ops;
 
+#if HAVE_LINUX_PERF_EVENT_H
+/* A Linux perf event buffer.  */
+struct perf_event_buffer
+{
+  /* The mapped memory.  */
+  const uint8_t *mem;
+
+  /* The size of the mapped memory in bytes.  */
+  unsigned long long size;
+
+  /* A pointer to the data_head field for this buffer. */
+  volatile unsigned long long *data_head;
+
+  /* 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
 {
@@ -42,16 +60,14 @@ struct btrace_target_info
   /* The ptid of this thread.  */
   ptid_t ptid;
 
-  /* The mmap configuration mapping the branch trace perf_event buffer.
-
-     file      .. the file descriptor
-     buffer    .. the mmapped memory buffer
-     size      .. the buffer's size in pages without the configuration page
-     data_head .. the data head from the last read  */
+  /* The perf event file.  */
   int file;
-  void *buffer;
-  size_t size;
-  unsigned long data_head;
+
+  /* The perf event configuration page. */
+  volatile struct perf_event_mmap_page *header;
+
+  /* The BTS perf event buffer.  */
+  struct perf_event_buffer bts;
 #endif /* HAVE_LINUX_PERF_EVENT_H */
 
   /* The size of a pointer in bits for this thread.
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 04/15] record btrace: add configuration struct
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (12 preceding siblings ...)
  2015-01-29 17:11 ` [PATCH v3 03/15] btrace, linux: add perf event buffer abstraction Markus Metzger
@ 2015-01-29 18:35 ` Markus Metzger
  2015-01-29 19:29   ` Eli Zaretskii
  2015-01-29 19:28 ` [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace Markus Metzger
  2015-02-04  8:25 ` [PATCH v3 00/15] record btrace: prepare for a new trace format Metzger, Markus T
  15 siblings, 1 reply; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 18:35 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

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.

2015-01-29  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                                         |  11 ++
 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, 678 insertions(+), 90 deletions(-)
 create mode 100644 gdb/features/btrace-conf.dtd

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index bfebf61..00fb2cd 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -601,7 +601,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 bd85967..08d604d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -14,6 +14,17 @@
 * The command 'thread apply all' can now support new option '-ascending'
   to call its specified command for all threads in ascending order.
 
+* New commands
+
+record btrace bts
+record bts
+  Start branch trace recording using Intel(R) Branch Trace Store format.
+
+* New remote packets
+
+qXfer:btrace-conf:read
+  Return the branch trace configuration for the current thread.
+
 *** Changes in GDB 7.9
 
 * GDB now supports hardware watchpoints on x86 GNU Hurd.
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 4e32bdc..8930c3c 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 730cb5f..fde0619 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 a289e8a..7d30952 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -61,6 +61,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 277df25..11e7f0f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6340,9 +6340,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
@@ -6355,13 +6359,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
@@ -6539,9 +6554,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
@@ -32949,7 +32964,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
@@ -33934,6 +33950,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
@@ -35606,6 +35623,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{-}
@@ -35790,6 +35812,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}).
@@ -36084,6 +36110,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
@@ -38888,6 +38923,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 c82e563..3d07e5d 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5925,11 +5925,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)
     {
@@ -6007,6 +6007,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 = {
@@ -6080,11 +6109,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 1756a1f..17ee5e1 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 ed57886..05feb36 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -357,9 +357,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.  */
@@ -371,6 +372,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);
 };
@@ -493,8 +499,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)
@@ -502,6 +508,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 5b22661..e827e92 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;
   unsigned int 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 602a571..12cdcde 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 04249bf..9fa1182 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 9931a6a..d2eaa10 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 61cc3a5..63ce12c 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 d2f0050..569c999 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3398,9 +3398,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.  */
@@ -3431,6 +3431,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 803ef28..fb60123 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 ();
@@ -2218,7 +2227,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);
@@ -2231,6 +2241,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 480fd1f..59959bc 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 79799b6..1122884 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 918232f..3857c10 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 6c0b9d9..63d902b 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 d48c092..88bd8af 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 e68be1d..76ca0a6 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 0377053..f53870b 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 0f2fe5b..e3febe1 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 585be21..0276f72 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 78b547b..9d82be2 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);
+}
+
 \f
 
 /* 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

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (13 preceding siblings ...)
  2015-01-29 18:35 ` [PATCH v3 04/15] record btrace: add configuration struct Markus Metzger
@ 2015-01-29 19:28 ` Markus Metzger
  2015-01-29 19:28   ` Eli Zaretskii
  2015-02-04  8:25 ` [PATCH v3 00/15] record btrace: prepare for a new trace format Metzger, Markus T
  15 siblings, 1 reply; 20+ messages in thread
From: Markus Metzger @ 2015-01-29 19:28 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Adds a new command "record btrace pt" to configure the kernel to use
Intel Processor Trace instead of Intel Branch Trace Strore.

The "record btrace" command chooses the tracing format automatically.

Intel Processor Trace support further requires kernel support

    https://lkml.org/lkml/2014/11/14/292

and a separate decoder library

    https://github.com/01org/processor-trace

2015-01-29  Markus Metzger <markus.t.metzger@intel.com>
---
 gdb/NEWS                     |  10 ++
 gdb/btrace.c                 | 418 ++++++++++++++++++++++++++++++++++++++++++-
 gdb/btrace.h                 |  19 ++
 gdb/common/btrace-common.c   |  10 ++
 gdb/common/btrace-common.h   |  39 +++-
 gdb/doc/gdb.texinfo          | 120 ++++++++++++-
 gdb/features/btrace-conf.dtd |   7 +-
 gdb/features/btrace.dtd      |  16 +-
 gdb/gdbserver/linux-low.c    |  85 ++++++++-
 gdb/gdbserver/server.c       |  51 +++++-
 gdb/nat/linux-btrace.c       | 404 ++++++++++++++++++++++++++++++++++++++++-
 gdb/nat/linux-btrace.h       |  19 ++
 gdb/record-btrace.c          | 129 +++++++++++++
 gdb/remote.c                 |  67 ++++++-
 14 files changed, 1361 insertions(+), 33 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 4844f33..aac22bd 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -20,12 +20,22 @@ set|show record btrace bts buffer-size
   The obtained size may differ from the requested size.  Use "info
   record" to see the obtained buffer size.
 
+set|show record btrace pt buffer-size
+  Set and show the size of the ring buffer used for branch tracing in
+  Intel(R) Processor Trace format.
+  The obtained size may differ from the requested size.  Use "info
+  record" to see the obtained buffer size.
+
 * New commands
 
 record btrace bts
 record bts
   Start branch trace recording using Intel(R) Branch Trace Store format.
 
+record btrace pt
+record pt
+  Start branch trace recording using Intel(R) Processor Trace format.
+
 * New remote packets
 
 qXfer:btrace-conf:read
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 45e9035..00766ea 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -31,6 +31,11 @@
 #include "filenames.h"
 #include "xml-support.h"
 #include "regcache.h"
+#include "rsp-low.h"
+
+#include <inttypes.h>
+
+static void btrace_add_pc (struct thread_info *tp);
 
 /* Print a record debug message.  Use do ... while (0) to avoid ambiguities
    when used in if statements.  */
@@ -741,6 +746,252 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
   btinfo->level = -level;
 }
 
+#if defined (HAVE_LIBIPT)
+
+static enum btrace_insn_class
+pt_reclassify_insn (enum pt_insn_class iclass)
+{
+  switch (iclass)
+    {
+    case ptic_call:
+      return BTRACE_INSN_CALL;
+
+    case ptic_return:
+      return BTRACE_INSN_RETURN;
+
+    case ptic_jump:
+      return BTRACE_INSN_JUMP;
+
+    default:
+      return BTRACE_INSN_OTHER;
+    }
+}
+
+/* Add function branch trace using DECODER.  */
+
+static void
+ftrace_add_pt (struct pt_insn_decoder *decoder,
+	       struct btrace_function **pbegin,
+	       struct btrace_function **pend, int *plevel,
+	       unsigned int *ngaps)
+{
+  struct btrace_function *begin, *end, *upd;
+  uint64_t offset;
+  int errcode, nerrors;
+
+  begin = *pbegin;
+  end = *pend;
+  nerrors = 0;
+  for (;;)
+    {
+      struct btrace_insn btinsn;
+      struct pt_insn insn;
+
+      errcode = pt_insn_sync_forward (decoder);
+      if (errcode < 0)
+	{
+	  if (errcode != -pte_eos)
+	    warning (_("Failed to synchronize onto the Intel(R) Processor "
+		       "Trace stream: %s."), pt_errstr (pt_errcode (errcode)));
+	  break;
+	}
+
+      memset (&btinsn, 0, sizeof (btinsn));
+      for (;;)
+	{
+	  errcode = pt_insn_next (decoder, &insn);
+	  if (errcode < 0)
+	    break;
+
+	  /* Look for gaps in the trace - unless we're at the beginning.  */
+	  if (begin != NULL)
+	    {
+	      /* Tracing is disabled and re-enabled each time we enter the
+		 kernel.  Most times, we continue from the same instruction we
+		 stopped before.  This is indicated via the RESUMED instruction
+		 flag.  The ENABLED instruction flag means that we continued
+		 from some other instruction.  Indicate this as a trace gap.  */
+	      if (insn.enabled)
+		*pend = end = ftrace_new_gap (end, BDE_PT_DISABLED);
+
+	      /* Indicate trace overflows.  */
+	      if (insn.resynced)
+		*pend = end = ftrace_new_gap (end, BDE_PT_OVERFLOW);
+	    }
+
+	  upd = ftrace_update_function (end, insn.ip);
+	  if (upd != end)
+	    {
+	      *pend = end = upd;
+
+	      if (begin == NULL)
+		*pbegin = begin = upd;
+	    }
+
+	  /* Maintain the function level offset.  */
+	  *plevel = min (*plevel, end->level);
+
+	  btinsn.pc = (CORE_ADDR) insn.ip;
+	  btinsn.size = (gdb_byte) insn.size;
+	  btinsn.iclass = pt_reclassify_insn (insn.iclass);
+
+	  ftrace_update_insns (end, &btinsn);
+	  ftrace_update_lines (end, insn.ip);
+	}
+
+      if (errcode == -pte_eos)
+	break;
+
+      /* If the gap is at the very beginning, we ignore it - we will have
+	 less trace, but we won't have any holes in the trace.  */
+      if (begin == NULL)
+	continue;
+
+      pt_insn_get_offset (decoder, &offset);
+
+      warning (_("Failed to decode Intel(R) Processor Trace near trace "
+		 "offset 0x%" PRIx64 " near recorded PC 0x%" PRIx64 ": %s."),
+	       offset, insn.ip, pt_errstr (pt_errcode (errcode)));
+
+      /* Indicate the gap in the trace.  */
+      *pend = end = ftrace_new_gap (end, errcode);
+      *ngaps += 1;
+    }
+
+  if (nerrors > 0)
+    warning (_("The recorded execution trace may have gaps."));
+}
+
+/* A callback function to allow the trace decoder to read the inferior's
+   memory.  */
+
+static int
+btrace_pt_readmem_callback (gdb_byte *buffer, size_t size,
+			    const struct pt_asid *asid, CORE_ADDR pc,
+			    void *context)
+{
+  volatile struct gdb_exception except;
+  int errcode;
+
+  TRY_CATCH (except, RETURN_MASK_ERROR)
+    {
+      errcode = target_read_code (pc, buffer, size);
+      if (errcode != 0)
+	return -pte_nomap;
+    }
+
+  if (except.reason != 0)
+    return -pte_nomap;
+
+  return size;
+}
+
+/* Translate the vendor from one enum to another.  */
+
+static enum pt_cpu_vendor
+pt_translate_cpu_vendor (enum btrace_cpu_vendor vendor)
+{
+  switch (vendor)
+    {
+    default:
+      return pcv_unknown;
+
+    case CV_INTEL:
+      return pcv_intel;
+    }
+}
+
+/* Compute the function branch trace from Intel(R) Processor Trace.  */
+
+static void
+btrace_compute_ftrace_pt (struct thread_info *tp,
+			  const struct btrace_data_pt *btrace)
+{
+  volatile struct gdb_exception except;
+  struct btrace_thread_info *btinfo;
+  struct pt_insn_decoder *decoder;
+  struct pt_config config;
+  int level, errcode;
+
+  if (btrace->size == 0)
+    return;
+
+  btinfo = &tp->btrace;
+  level = btinfo->begin != NULL ? -btinfo->level : INT_MAX;
+
+  memset (&config, 0, sizeof(config));
+
+  config.size = sizeof (config);
+  config.begin = btrace->data;
+  config.end = btrace->data + btrace->size;
+
+  config.cpu.vendor = pt_translate_cpu_vendor (btrace->config.cpu.vendor);
+  config.cpu.family = btrace->config.cpu.family;
+  config.cpu.model = btrace->config.cpu.model;
+  config.cpu.stepping = btrace->config.cpu.stepping;
+
+  errcode = pt_cpu_errata (&config.errata, &config.cpu);
+  if (errcode < 0)
+    error (_("Failed to configure the Intel(R) Processor Trace decoder: %s."),
+	   pt_errstr (pt_errcode (errcode)));
+
+  decoder = pt_insn_alloc_decoder (&config);
+  if (decoder == NULL)
+    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      struct pt_image *image;
+
+      image = pt_insn_get_image(decoder);
+      if (image == NULL)
+	error (_("Failed to configure the Intel(R) Processor Trace decoder."));
+
+      errcode = pt_image_set_callback(image, btrace_pt_readmem_callback, NULL);
+      if (errcode < 0)
+	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
+		 "%s."), pt_errstr (pt_errcode (errcode)));
+
+      ftrace_add_pt (decoder, &btinfo->begin, &btinfo->end, &level,
+		     &btinfo->ngaps);
+    }
+
+  pt_insn_free_decoder (decoder);
+
+  /* LEVEL is the minimal function level of all btrace function segments.
+     Define the global level offset to -LEVEL so all function levels are
+     normalized to start at zero.  */
+  btinfo->level = -level;
+
+  /* Indicate a gap in the trace if we quit trace processing.  Errors were
+     already logged before.  */
+  if (except.reason == RETURN_QUIT && btinfo->end != NULL)
+    {
+      btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
+      btinfo->ngaps++;
+    }
+
+  /* Add a single last instruction entry for the current PC.
+     This allows us to compute the backtrace at the current PC using both
+     standard unwind and btrace unwind.
+     This extra entry is ignored by all record commands.  */
+  btrace_add_pc (tp);
+
+  if (except.reason < 0)
+    throw_exception (except);
+}
+
+#else /* defined (HAVE_LIBIPT)  */
+
+static void
+btrace_compute_ftrace_pt (struct thread_info *tp,
+			  const struct btrace_data_pt *btrace)
+{
+  internal_error (__FILE__, __LINE__, _("Unexpected branch trace format."));
+}
+
+#endif /* defined (HAVE_LIBIPT)  */
+
 /* Compute the function branch trace from a block branch trace BTRACE for
    a thread given by BTINFO.  */
 
@@ -757,6 +1008,10 @@ btrace_compute_ftrace (struct thread_info *tp, struct btrace_data *btrace)
     case BTRACE_FORMAT_BTS:
       btrace_compute_ftrace_bts (tp, &btrace->variant.bts);
       return;
+
+    case BTRACE_FORMAT_PT:
+      btrace_compute_ftrace_pt (tp, &btrace->variant.pt);
+      return;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -946,6 +1201,15 @@ btrace_stitch_bts (struct btrace_data_bts *btrace, struct thread_info *tp)
   return 0;
 }
 
+/* Stitch branch trace in Intel(R) Processor Trace format.  */
+
+static int
+btrace_stitch_pt (struct btrace_data_pt *btrace, struct thread_info *tp)
+{
+  /* FIXME: support stitching.  */
+  return -1;
+}
+
 /* Adjust the block trace in order to stitch old and new trace together.
    BTRACE is the new delta trace between the last and the current stop.
    TP is the traced thread.
@@ -966,6 +1230,9 @@ btrace_stitch_trace (struct btrace_data *btrace, struct thread_info *tp)
 
     case BTRACE_FORMAT_BTS:
       return btrace_stitch_bts (&btrace->variant.bts, tp);
+
+    case BTRACE_FORMAT_PT:
+      return btrace_stitch_pt (&btrace->variant.pt, tp);
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -1111,7 +1378,7 @@ check_xml_btrace_version (struct gdb_xml_parser *parser,
 {
   const char *version = xml_find_attribute (attributes, "version")->value;
 
-  if (strcmp (version, "1.0") != 0)
+  if (strcmp (version, "1.0") != 0 && strcmp (version, "2.0") != 0)
     gdb_xml_error (parser, _("Unsupported btrace version: \"%s\""), version);
 }
 
@@ -1150,12 +1417,131 @@ parse_xml_btrace_block (struct gdb_xml_parser *parser,
   block->end = *end;
 }
 
+/* Parse a "raw" xml record.  */
+
+static void
+parse_xml_raw (struct gdb_xml_parser *parser, const char *body_text,
+	       gdb_byte **pdata, unsigned long *psize)
+{
+  struct cleanup *cleanup;
+  gdb_byte *data, *bin;
+  unsigned long size;
+  size_t len;
+
+  len = strlen (body_text);
+  size = len / 2;
+
+  if ((size_t) size * 2 != len)
+    gdb_xml_error (parser, _("Bad raw data size."));
+
+  bin = data = xmalloc (size);
+  cleanup = make_cleanup (xfree, data);
+
+  /* We use hex encoding - see common/rsp-low.h.  */
+  while (len > 0)
+    {
+      char hi, lo;
+
+      hi = *body_text++;
+      lo = *body_text++;
+
+      if (hi == 0 || lo == 0)
+	gdb_xml_error (parser, _("Bad hex encoding."));
+
+      *bin++ = fromhex (hi) * 16 + fromhex (lo);
+      len -= 2;
+    }
+
+  discard_cleanups (cleanup);
+
+  *pdata = data;
+  *psize = size;
+}
+
+/* Parse a btrace pt-config "cpu" xml record.  */
+
+static void
+parse_xml_btrace_pt_config_cpu (struct gdb_xml_parser *parser,
+				const struct gdb_xml_element *element,
+				void *user_data,
+				VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_data *btrace;
+  const char *vendor;
+  ULONGEST *family, *model, *stepping;
+
+  vendor = xml_find_attribute (attributes, "vendor")->value;
+  family = xml_find_attribute (attributes, "family")->value;
+  model = xml_find_attribute (attributes, "model")->value;
+  stepping = xml_find_attribute (attributes, "stepping")->value;
+
+  btrace = user_data;
+
+  if (strcmp (vendor, "GenuineIntel") == 0)
+    btrace->variant.pt.config.cpu.vendor = CV_INTEL;
+
+  btrace->variant.pt.config.cpu.family = *family;
+  btrace->variant.pt.config.cpu.model = *model;
+  btrace->variant.pt.config.cpu.stepping = *stepping;
+}
+
+/* Parse a btrace pt "raw" xml record.  */
+
+static void
+parse_xml_btrace_pt_raw (struct gdb_xml_parser *parser,
+			 const struct gdb_xml_element *element,
+			 void *user_data, const char *body_text)
+{
+  struct btrace_data *btrace;
+
+  btrace = user_data;
+  parse_xml_raw (parser, body_text, &btrace->variant.pt.data,
+		 &btrace->variant.pt.size);
+}
+
+/* Parse a btrace "pt" xml record.  */
+
+static void
+parse_xml_btrace_pt (struct gdb_xml_parser *parser,
+		     const struct gdb_xml_element *element,
+		     void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_data *btrace;
+
+  btrace = user_data;
+  btrace->format = BTRACE_FORMAT_PT;
+  btrace->variant.pt.config.cpu.vendor = CV_UNKNOWN;
+  btrace->variant.pt.data = NULL;
+  btrace->variant.pt.size = 0;
+}
+
 static const struct gdb_xml_attribute block_attributes[] = {
   { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
+static const struct gdb_xml_attribute btrace_pt_config_cpu_attributes[] = {
+  { "vendor", GDB_XML_AF_NONE, NULL, NULL },
+  { "family", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "model", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "stepping", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_pt_config_children[] = {
+  { "cpu", btrace_pt_config_cpu_attributes, NULL, GDB_XML_EF_OPTIONAL,
+    parse_xml_btrace_pt_config_cpu, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_pt_children[] = {
+  { "pt-config", NULL, btrace_pt_config_children, GDB_XML_EF_OPTIONAL, NULL,
+    NULL },
+  { "raw", NULL, NULL, GDB_XML_EF_OPTIONAL, NULL, parse_xml_btrace_pt_raw },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute btrace_attributes[] = {
   { "version", GDB_XML_AF_NONE, NULL, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
@@ -1164,6 +1550,8 @@ static const struct gdb_xml_attribute btrace_attributes[] = {
 static const struct gdb_xml_element btrace_children[] = {
   { "block", block_attributes, NULL,
     GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, parse_xml_btrace_block, NULL },
+  { "pt", NULL, btrace_pt_children, GDB_XML_EF_OPTIONAL, parse_xml_btrace_pt,
+    NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
@@ -1221,9 +1609,33 @@ parse_xml_btrace_conf_bts (struct gdb_xml_parser *parser,
 
   size = xml_find_attribute (attributes, "size");
   if (size != NULL)
-    conf->bts.size = (unsigned int) * (ULONGEST *) size->value;
+    conf->bts.size = (unsigned int) *(ULONGEST *) size->value;
 }
 
+/* Parse a btrace-conf "pt" xml record.  */
+
+static void
+parse_xml_btrace_conf_pt (struct gdb_xml_parser *parser,
+			  const struct gdb_xml_element *element,
+			  void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_config *conf;
+  struct gdb_xml_value *size;
+
+  conf = user_data;
+  conf->format = BTRACE_FORMAT_PT;
+  conf->pt.size = 0;
+
+  size = xml_find_attribute (attributes, "size");
+  if (size != NULL)
+    conf->pt.size = (unsigned int) *(ULONGEST *) size->value;
+}
+
+static const struct gdb_xml_attribute btrace_conf_pt_attributes[] = {
+  { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute btrace_conf_bts_attributes[] = {
   { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
@@ -1232,6 +1644,8 @@ static const struct gdb_xml_attribute btrace_conf_bts_attributes[] = {
 static const struct gdb_xml_element btrace_conf_children[] = {
   { "bts", btrace_conf_bts_attributes, NULL, GDB_XML_EF_OPTIONAL,
     parse_xml_btrace_conf_bts, NULL },
+  { "pt", btrace_conf_pt_attributes, NULL, GDB_XML_EF_OPTIONAL,
+    parse_xml_btrace_conf_pt, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 0ddd4c1..3cdd8a4 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -28,6 +28,10 @@
 
 #include "btrace-common.h"
 
+#if defined (HAVE_LIBIPT)
+#  include <intel-pt.h>
+#endif
+
 struct thread_info;
 struct btrace_function;
 
@@ -96,6 +100,21 @@ enum btrace_bts_error
   BDE_BTS_INSN_SIZE
 };
 
+/* Decode errors for the Intel Processor Trace recording format.  */
+enum btrace_pt_error
+{
+  /* The user cancelled trace processing.  */
+  BDE_PT_USER_QUIT = 1,
+
+  /* Tracing was temporarily disabled.  */
+  BDE_PT_DISABLED,
+
+  /* Trace recording overflowed.  */
+  BDE_PT_OVERFLOW
+
+  /* Negative numbers are used by the decoder library.  */
+};
+
 /* A branch trace function segment.
 
    This represents a function segment in a branch trace, i.e. a consecutive
diff --git a/gdb/common/btrace-common.c b/gdb/common/btrace-common.c
index 878cfed..77b99bf 100644
--- a/gdb/common/btrace-common.c
+++ b/gdb/common/btrace-common.c
@@ -33,6 +33,9 @@ btrace_format_string (enum btrace_format format)
 
     case BTRACE_FORMAT_BTS:
       return _("Intel(R) Branch Trace Store");
+
+    case BTRACE_FORMAT_PT:
+      return _("Intel(R) Processor Trace");
     }
 
   internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
@@ -60,6 +63,10 @@ btrace_data_fini (struct btrace_data *data)
     case BTRACE_FORMAT_BTS:
       VEC_free (btrace_block_s, data->variant.bts.blocks);
       return;
+
+    case BTRACE_FORMAT_PT:
+      xfree (data->variant.pt.data);
+      return;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -77,6 +84,9 @@ btrace_data_empty (struct btrace_data *data)
 
     case BTRACE_FORMAT_BTS:
       return VEC_empty (btrace_block_s, data->variant.bts.blocks);
+
+    case BTRACE_FORMAT_PT:
+      return (data->variant.pt.size == 0);
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 5e67e52..3b703a1 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -58,7 +58,10 @@ enum btrace_format
 
   /* Branch trace is in Branch Trace Store format.
      Actually, the format is a sequence of blocks derived from BTS.  */
-  BTRACE_FORMAT_BTS
+  BTRACE_FORMAT_BTS,
+
+  /* Branch trace is in Intel(R) Processor Trace format.  */
+  BTRACE_FORMAT_PT
 };
 
 /* An enumeration of cpu vendors.  */
@@ -97,6 +100,14 @@ struct btrace_config_bts
   unsigned int size;
 };
 
+/* An Intel Processor Trace configuration.  */
+
+struct btrace_config_pt
+{
+  /* The size of the branch trace buffer in bytes.  */
+  unsigned int size;
+};
+
 /* A branch tracing configuration.
 
    This describes the requested configuration as well as the actually
@@ -111,6 +122,9 @@ struct btrace_config
 
   /* The BTS format configuration.  */
   struct btrace_config_bts bts;
+
+  /* The Intel Processor Trace format configuration.  */
+  struct btrace_config_pt pt;
 };
 
 /* Branch trace in BTS format.  */
@@ -121,6 +135,26 @@ struct btrace_data_bts
   VEC (btrace_block_s) *blocks;
 };
 
+/* Configuration information to go with the trace data.  */
+struct btrace_data_pt_config
+{
+  /* The processor on which the trace has been collected.  */
+  struct btrace_cpu cpu;
+};
+
+/* Branch trace in Intel Processor Trace format.  */
+struct btrace_data_pt
+{
+  /* Some configuration information to go with the data.  */
+  struct btrace_data_pt_config config;
+
+  /* The trace data.  */
+  gdb_byte *data;
+
+  /* The size of DATA in bytes.  */
+  unsigned long size;
+};
+
 /* The branch trace data.  */
 struct btrace_data
 {
@@ -130,6 +164,9 @@ struct btrace_data
   {
     /* Format == BTRACE_FORMAT_BTS.  */
     struct btrace_data_bts bts;
+
+    /* Format == BTRACE_FORMAT_PT.  */
+    struct btrace_data_pt pt;
   } variant;
 };
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2e9805a..b5bd6db 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6341,12 +6341,16 @@ For architecture environments that support process record and replay,
 @kindex record full
 @kindex record btrace
 @kindex record btrace bts
+@kindex record btrace pt
 @kindex record bts
+@kindex record pt
 @kindex rec
 @kindex rec full
 @kindex rec btrace
 @kindex rec btrace bts
+@kindex rec btrace pt
 @kindex rec bts
+@kindex rec pt
 @item record @var{method}
 This command starts the process record and replay target.  The
 recording method can be specified as parameter.  Without a parameter
@@ -6374,6 +6378,20 @@ formats are available:
 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.
+
+@item pt
+Use Intel's Processor Trace recording format.  In this format, the
+processor stores the execution trace in a compressed form that is
+afterwards decoded by @value{GDBN}.
+
+The trace can be recorded with very low overhead.  The compressed
+trace format also allows small trace buffers to already contain a big
+number of instructions compared to BTS.
+
+Decoding the recorded execution trace, on the other hand, is more
+expensive than decoding BTS trace.  This is mostly due to the
+increased number of instructions to process.  You should increase the
+buffer-size with care.
 @end table
 
 Not all recording formats may be available on all processors.
@@ -6384,9 +6402,6 @@ already running.  Therefore, you need first to start the process with
 the @kbd{run} or @kbd{start} commands, and then start the recording
 with the @kbd{record @var{method}} command.
 
-Both @code{record @var{method}} and @code{rec @var{method}} are
-aliases of @code{target record-@var{method}}.
-
 @cindex displaced stepping, and process record and replay
 Displaced stepping (@pxref{Maintenance Commands,, displaced stepping})
 will be automatically disabled when process record and replay target
@@ -6551,6 +6566,29 @@ also need longer to process the branch trace data before it can be used.
 Show the current setting of the requested ring buffer size for branch
 tracing in BTS format.
 
+@kindex set record btrace pt
+@item set record btrace pt buffer-size @var{size}
+@itemx set record btrace pt buffer-size unlimited
+Set the requested ring buffer size for branch tracing in Intel
+Processor Trace format.  Default is 16KB.
+
+If @var{size} is a positive number, then @value{GDBN} will try to
+allocate a buffer of at least @var{size} bytes for each new thread
+that uses the btrace recording method and the Intel Processor Trace
+format.  The actually obtained buffer size may differ from the
+requested @var{size}. Use the @code{info record} command to see the
+actual buffer size for each thread.
+
+If @var{limit} is @code{unlimited} or zero, @value{GDBN} will try to
+allocate a buffer of 4MB.
+
+Bigger buffers mean longer traces.  On the other hand, @value{GDBN} will
+also need longer to process the branch trace data before it can be used.
+
+@item show record btrace pt buffer-size @var{size}
+Show the current setting of the requested ring buffer size for branch
+tracing in Intel Processor Trace format.
+
 @kindex info record
 @item info record
 Show various statistics about the recording depending on the recording
@@ -6596,6 +6634,12 @@ For the @code{bts} recording format, it also shows:
 @item
 Size of the perf ring buffer.
 @end itemize
+
+For the @code{pt} recording format, it also shows:
+@itemize @bullet
+@item
+Size of the perf ring buffer.
+@end itemize
 @end table
 
 @kindex record delete
@@ -35747,11 +35791,21 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab Yes
 
+@item @samp{Qbtrace:pt}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
 @item @samp{Qbtrace-conf:bts:size}
 @tab Yes
 @tab @samp{-}
 @tab Yes
 
+@item @samp{Qbtrace-conf:pt:size}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
 @item @samp{QNonStop}
 @tab No
 @tab @samp{-}
@@ -36009,9 +36063,15 @@ The remote stub understands the @samp{Qbtrace:off} packet.
 @item Qbtrace:bts
 The remote stub understands the @samp{Qbtrace:bts} packet.
 
+@item Qbtrace:pt
+The remote stub understands the @samp{Qbtrace:pt} packet.
+
 @item Qbtrace-conf:bts:size
 The remote stub understands the @samp{Qbtrace-conf:bts:size} packet.
 
+@item Qbtrace-conf:pt:size
+The remote stub understands the @samp{Qbtrace-conf:pt:size} packet.
+
 @end table
 
 @item qSymbol::
@@ -36430,7 +36490,18 @@ A badly formed request or an error was encountered.
 @end table
 
 @item Qbtrace:bts
-Enable branch tracing for the current thread using bts tracing.
+Enable branch tracing for the current thread using Intel Branch Trace Store.
+
+Reply:
+@table @samp
+@item OK
+Branch tracing has been enabled.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
+@item Qbtrace:pt
+Enable branch tracing for the current thread using Intel Processor Trace.
 
 Reply:
 @table @samp
@@ -36463,6 +36534,18 @@ The ring buffer size has been set.
 A badly formed request or an error was encountered.
 @end table
 
+@item Qbtrace-conf:pt:size=@var{value}
+Set the requested ring buffer size for new threads that use the
+btrace recording method in pt format.
+
+Reply:
+@table @samp
+@item OK
+The ring buffer size has been set.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
 @end table
 
 @node Architecture-Specific Protocol Details
@@ -38974,12 +39057,24 @@ and ending at @var{end}:
 The formal DTD for the branch trace format is given below:
 
 @smallexample
-<!ELEMENT btrace  (block)* >
-<!ATTLIST btrace  version CDATA   #FIXED "1.0">
+<!ELEMENT btrace  (block* | pt) >
+<!ATTLIST btrace  version CDATA   #FIXED "2.0">
 
 <!ELEMENT block        EMPTY>
 <!ATTLIST block        begin  CDATA   #REQUIRED
                        end    CDATA   #REQUIRED>
+
+<!ELEMENT pt (pt-config?, raw?)>
+
+<!ELEMENT pt-config (cpu?)>
+
+<!ELEMENT cpu EMPTY>
+<!ATTLIST cpu vendor   CDATA #REQUIRED
+              family   CDATA #REQUIRED
+              model    CDATA #REQUIRED
+              stepping CDATA #REQUIRED>
+
+<!ELEMENT raw (#PCDATA)>
 @end smallexample
 
 @node Branch Trace Configuration Format
@@ -39000,6 +39095,12 @@ This thread uses the Branch Trace Store (BTS) format.
 @item size
 The size of the BTS ring buffer in bytes.
 @end table
+@item pt
+This thread uses the Intel Processor Trace (Intel PT) format.
+@table @code
+@item size
+The size of the Intel PT ring buffer in bytes.
+@end table
 @end table
 
 @value{GDBN} must be linked with the Expat library to support XML
@@ -39008,11 +39109,14 @@ 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 btrace-conf	(bts?, pt?)>
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "2.0">
 
 <!ELEMENT bts	EMPTY>
 <!ATTLIST bts	size	CDATA	#IMPLIED>
+
+<!ELEMENT pt	EMPTY>
+<!ATTLIST pt	size	CDATA	#IMPLIED>
 @end smallexample
 
 @include agentexpr.texi
diff --git a/gdb/features/btrace-conf.dtd b/gdb/features/btrace-conf.dtd
index 907816c..c116bcb 100644
--- a/gdb/features/btrace-conf.dtd
+++ b/gdb/features/btrace-conf.dtd
@@ -4,8 +4,11 @@
      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 btrace-conf	(bts?, pt?)>
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "2.0">
 
 <!ELEMENT bts	EMPTY>
 <!ATTLIST bts	size	CDATA	#IMPLIED>
+
+<!ELEMENT pt	EMPTY>
+<!ATTLIST pt	size	CDATA	#IMPLIED>
diff --git a/gdb/features/btrace.dtd b/gdb/features/btrace.dtd
index 7fffc3c..3bc622d 100644
--- a/gdb/features/btrace.dtd
+++ b/gdb/features/btrace.dtd
@@ -4,9 +4,21 @@
      are permitted in any medium without royalty provided the copyright
      notice and this notice are preserved.  -->
 
-<!ELEMENT btrace  (block)* >
-<!ATTLIST btrace  version CDATA   #FIXED "1.0">
+<!ELEMENT btrace  (block* | pt)>
+<!ATTLIST btrace  version CDATA   #FIXED "2.0">
 
 <!ELEMENT block        EMPTY>
 <!ATTLIST block        begin  CDATA   #REQUIRED
                        end    CDATA   #REQUIRED>
+
+<!ELEMENT pt (pt-config?, raw?)>
+
+<!ELEMENT pt-config (cpu?)>
+
+<!ELEMENT cpu EMPTY>
+<!ATTLIST cpu vendor   CDATA #REQUIRED
+              family   CDATA #REQUIRED
+              model    CDATA #REQUIRED
+              stepping CDATA #REQUIRED>
+
+<!ELEMENT raw (#PCDATA)>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 6dca61e..4c25c98 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -20,6 +20,7 @@
 #include "linux-low.h"
 #include "nat/linux-osdata.h"
 #include "agent.h"
+#include "rsp-low.h"
 
 #include "nat/linux-nat.h"
 #include "nat/linux-waitpid.h"
@@ -5953,6 +5954,55 @@ linux_low_disable_btrace (struct btrace_target_info *tinfo)
   return (err == BTRACE_ERR_NONE ? 0 : -1);
 }
 
+/* Encode an Intel Processor Trace configuration.  */
+
+static void
+linux_low_encode_pt_config (struct buffer *buffer,
+			    const struct btrace_data_pt_config *config)
+{
+  buffer_grow_str (buffer, "<pt-config>\n");
+
+  switch (config->cpu.vendor)
+    {
+    case CV_INTEL:
+      buffer_xml_printf (buffer, "<cpu vendor=\"GenuineIntel\" family=\"%u\" "
+			 "model=\"%u\" stepping=\"%u\"/>\n",
+			 config->cpu.family, config->cpu.model,
+			 config->cpu.stepping);
+      break;
+
+    default:
+      break;
+    }
+
+  buffer_grow_str (buffer, "</pt-config>\n");
+}
+
+/* Encode a raw buffer.  */
+
+static void
+linux_low_encode_raw (struct buffer *buffer, const gdb_byte *data,
+		      unsigned int size)
+{
+  if (size == 0)
+    return;
+
+  /* We use hex encoding - see common/rsp-low.h.  */
+  buffer_grow_str (buffer, "<raw>\n");
+
+  while (size-- > 0)
+    {
+      char elem[2];
+
+      elem[0] = tohex ((*data >> 4) & 0xf);
+      elem[1] = tohex (*data++ & 0xf);
+
+      buffer_grow (buffer, elem, 2);
+    }
+
+  buffer_grow_str (buffer, "</raw>\n");
+}
+
 /* See to_read_btrace target method.  */
 
 static int
@@ -5974,15 +6024,14 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
       else
 	buffer_grow_str0 (buffer, "E.Generic Error.");
 
-      btrace_data_fini (&btrace);
-      return -1;
+      goto err;
     }
 
   switch (btrace.format)
     {
     case BTRACE_FORMAT_NONE:
       buffer_grow_str0 (buffer, "E.No Trace.");
-      break;
+      goto err;
 
     case BTRACE_FORMAT_BTS:
       buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
@@ -5997,15 +6046,31 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
       buffer_grow_str0 (buffer, "</btrace>\n");
       break;
 
-    default:
-      buffer_grow_str0 (buffer, "E.Unknown Trace Format.");
+    case BTRACE_FORMAT_PT:
+      buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
+      buffer_grow_str (buffer, "<btrace version=\"2.0\">\n");
+      buffer_grow_str (buffer, "<pt>\n");
+
+      linux_low_encode_pt_config (buffer, &btrace.variant.pt.config);
 
-      btrace_data_fini (&btrace);
-      return -1;
+      linux_low_encode_raw (buffer, btrace.variant.pt.data,
+			    btrace.variant.pt.size);
+
+      buffer_grow_str (buffer, "</pt>\n");
+      buffer_grow_str0 (buffer, "</btrace>\n");
+      break;
+
+    default:
+      buffer_grow_str0 (buffer, "E.Unsupported Trace Format.");
+      goto err;
     }
 
   btrace_data_fini (&btrace);
   return 0;
+
+err:
+  btrace_data_fini (&btrace);
+  return -1;
 }
 
 /* See to_btrace_conf target method.  */
@@ -6032,6 +6097,12 @@ linux_low_btrace_conf (const struct btrace_target_info *tinfo,
 	  buffer_xml_printf (buffer, " size=\"0x%x\"", conf->bts.size);
 	  buffer_xml_printf (buffer, " />\n");
 	  break;
+
+	case BTRACE_FORMAT_PT:
+	  buffer_xml_printf (buffer, "<pt");
+	  buffer_xml_printf (buffer, " size=\"0x%x\"", conf->pt.size);
+	  buffer_xml_printf (buffer, "/>\n");
+	  break;
 	}
     }
 
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 156fcc8..1c7dea4 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -402,6 +402,23 @@ handle_btrace_enable_bts (struct thread_info *thread)
   return NULL;
 }
 
+/* Handle btrace enabling in Intel Processor Trace format.  */
+
+static const char *
+handle_btrace_enable_pt (struct thread_info *thread)
+{
+  if (thread->btrace != NULL)
+    return "E.Btrace already enabled.";
+
+  current_btrace_conf.format = BTRACE_FORMAT_PT;
+  thread->btrace = target_enable_btrace (thread->entry.id,
+					 &current_btrace_conf);
+  if (thread->btrace == NULL)
+    return "E.Could not enable btrace.";
+
+  return NULL;
+}
+
 /* Handle btrace disabling.  */
 
 static const char *
@@ -450,10 +467,12 @@ handle_btrace_general_set (char *own_buf)
 
   if (strcmp (op, "bts") == 0)
     err = handle_btrace_enable_bts (thread);
+  else if (strcmp (op, "pt") == 0)
+    err = handle_btrace_enable_pt (thread);
   else if (strcmp (op, "off") == 0)
     err = handle_btrace_disable (thread);
   else
-    err = "E.Bad Qbtrace operation. Use bts or off.";
+    err = "E.Bad Qbtrace operation. Use bts, pt, or off.";
 
   if (err != 0)
     strcpy (own_buf, err);
@@ -505,6 +524,21 @@ handle_btrace_conf_general_set (char *own_buf)
 
       current_btrace_conf.bts.size = (unsigned int) size;
     }
+  else if (strncmp (op, "pt:size=", strlen ("pt:size=")) == 0)
+    {
+      unsigned long size;
+      char *endp = NULL;
+
+      errno = 0;
+      size = strtoul (op + strlen ("pt:size="), &endp, 16);
+      if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX)
+	{
+	  strcpy (own_buf, "E.Bad size value.");
+	  return -1;
+	}
+
+      current_btrace_conf.pt.size = (unsigned int) size;
+    }
   else
     {
       strcpy (own_buf, "E.Bad Qbtrace configuration option.");
@@ -1815,12 +1849,25 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
 static void
 supported_btrace_packets (char *buf)
 {
+  int btrace_supported = 0;
+
   if (target_supports_btrace (BTRACE_FORMAT_BTS))
     {
       strcat (buf, ";Qbtrace:bts+");
       strcat (buf, ";Qbtrace-conf:bts:size+");
+
+      btrace_supported = 1;
     }
-  else
+
+  if (target_supports_btrace (BTRACE_FORMAT_PT))
+    {
+      strcat (buf, ";Qbtrace:pt+");
+      strcat (buf, ";Qbtrace-conf:pt:size+");
+
+      btrace_supported = 1;
+    }
+
+  if (!btrace_supported)
     return;
 
   strcat (buf, ";Qbtrace:off+");
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index c5c05a2..021ce67 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -109,6 +109,119 @@ perf_event_new_data (const struct perf_event_buffer *pev)
  * except when a 32-bit inferior is running on a 64-bit OS.
  */
 
+/* Copy the last SIZE bytes from PEV ending at DATA_HEAD and return a pointer
+   to the memory holding the copy.
+   The caller is responsible for freeing the memory.  */
+
+static gdb_byte *
+perf_event_read (const struct perf_event_buffer *pev, unsigned long data_head,
+		 unsigned long size)
+{
+  const gdb_byte *begin, *end, *start, *stop;
+  gdb_byte *buffer;
+  unsigned long data_tail, buffer_size;
+
+  if (size == 0)
+    return NULL;
+
+  gdb_assert (size <= data_head);
+  data_tail = data_head - size;
+
+  buffer_size = pev->size;
+  begin = pev->mem;
+  start = begin + data_tail % buffer_size;
+  stop = begin + data_head % buffer_size;
+
+  buffer = xmalloc (size);
+
+  if (start < stop)
+    memcpy (buffer, start, stop - start);
+  else
+    {
+      end = begin + buffer_size;
+
+      memcpy (buffer, start, end - start);
+      memcpy (buffer + (end - start), begin, stop - begin);
+    }
+
+  return buffer;
+}
+
+/* Copy the perf event buffer data from PEV.
+   Store a pointer to the copy into DATA and its size in SIZE.  */
+
+static void
+perf_event_read_all (struct perf_event_buffer *pev, gdb_byte **data,
+		     unsigned long *psize)
+{
+  unsigned long data_head, size;
+
+  data_head = *pev->data_head;
+
+  size = pev->size;
+  if (data_head < size)
+    size = data_head;
+
+  *data = perf_event_read (pev, data_head, size);
+  *psize = size;
+
+  pev->last_head = data_head;
+}
+
+/* Copy the new perf event data from PEV.
+   Store a pointer to the copy into DATA and its size in SIZE.
+   Returns BTRACE_ERR_NONE on success.
+   Returns BTRACE_ERR_OVERFLOW if the perf event buffer overflowed.  */
+
+static enum btrace_error
+perf_event_read_new (struct perf_event_buffer *pev, gdb_byte **data,
+		     unsigned long *psize)
+{
+  unsigned long data_head, data_tail, size, buffer_size;
+
+  data_head = *pev->data_head;
+  data_tail = pev->last_head;
+
+  /* Check for data head overflows.  We might be able to recover from those
+     but they are very unlikely and it's not worth the effort, I think.  */
+  if (data_head < data_tail)
+    return BTRACE_ERR_OVERFLOW;
+
+  /* Check for buffer overflows.  */
+  buffer_size = pev->size;
+  size = data_head - data_tail;
+  if (buffer_size < size)
+    return BTRACE_ERR_OVERFLOW;
+
+  *data = perf_event_read (pev, data_head, size);
+  *psize = size;
+
+  pev->last_head = data_head;
+  return BTRACE_ERR_NONE;
+}
+
+/* Determine the event type.
+   Returns zero on success and fills in TYPE; returns -1 otherwise.  */
+
+static int
+perf_event_pt_event_type (int *type)
+{
+  FILE *file;
+  int found;
+
+  file = fopen ("/sys/bus/event_source/devices/intel_pt/type", "r");
+  if (file == NULL)
+    return -1;
+
+  found = fscanf (file, "%d", type);
+
+  fclose (file);
+
+  if (found == 1)
+    return 0;
+  return -1;
+}
+
 static int
 linux_determine_ptr_bits (void)
 {
@@ -361,6 +474,93 @@ kernel_supports_bts (void)
     }
 }
 
+/* Check whether the kernel supports Intel Processor Trace.  */
+
+static int
+kernel_supports_pt (void)
+{
+  struct perf_event_attr attr;
+  pid_t child, pid;
+  int status, file, type;
+
+  errno = 0;
+  child = fork ();
+  switch (child)
+    {
+    case -1:
+      warning (_("test pt: cannot fork: %s."), strerror (errno));
+      return 0;
+
+    case 0:
+      status = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
+      if (status != 0)
+	{
+	  warning (_("test pt: cannot PTRACE_TRACEME: %s."),
+		   strerror (errno));
+	  _exit (1);
+	}
+
+      status = raise (SIGTRAP);
+      if (status != 0)
+	{
+	  warning (_("test pt: cannot raise SIGTRAP: %s."),
+		   strerror (errno));
+	  _exit (1);
+	}
+
+      _exit (1);
+
+    default:
+      pid = waitpid (child, &status, 0);
+      if (pid != child)
+	{
+	  warning (_("test pt: bad pid %ld, error: %s."),
+		   (long) pid, strerror (errno));
+	  return 0;
+	}
+
+      if (!WIFSTOPPED (status))
+	{
+	  warning (_("test pt: expected stop. status: %d."),
+		   status);
+	  return 0;
+	}
+
+      status = perf_event_pt_event_type (&type);
+      if (status != 0)
+	file = -1;
+      else
+	{
+	  memset (&attr, 0, sizeof (attr));
+
+	  attr.size = sizeof (attr);
+	  attr.type = type;
+	  attr.exclude_kernel = 1;
+	  attr.exclude_hv = 1;
+	  attr.exclude_idle = 1;
+
+	  file = syscall (SYS_perf_event_open, &attr, child, -1, -1, 0);
+	  if (file >= 0)
+	    close (file);
+	}
+
+      kill (child, SIGKILL);
+      ptrace (PTRACE_KILL, child, NULL, NULL);
+
+      pid = waitpid (child, &status, 0);
+      if (pid != child)
+	{
+	  warning (_("test pt: bad pid %ld, error: %s."),
+		   (long) pid, strerror (errno));
+	  if (!WIFSIGNALED (status))
+	    warning (_("test pt: expected killed. status: %d."),
+		     status);
+	}
+
+      return (file >= 0);
+    }
+}
+
 /* Check whether an Intel cpu supports BTS.  */
 
 static int
@@ -431,6 +631,24 @@ linux_supports_bts (void)
   return cached > 0;
 }
 
+/* Check whether the linux target supports Intel Processor Trace.  */
+
+static int
+linux_supports_pt (void)
+{
+  static int cached;
+
+  if (cached == 0)
+    {
+      if (!kernel_supports_pt ())
+	cached = -1;
+      else
+	cached = 1;
+    }
+
+  return cached > 0;
+}
+
 /* See linux-btrace.h.  */
 
 int
@@ -443,6 +661,9 @@ linux_supports_btrace (struct target_ops *ops, enum btrace_format format)
 
     case BTRACE_FORMAT_BTS:
       return linux_supports_bts ();
+
+    case BTRACE_FORMAT_PT:
+      return linux_supports_pt ();
     }
 
   internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
@@ -487,13 +708,13 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
   if (size == 0)
     {
       errno = EINVAL;
-      goto err;
-    }
+      goto err_out;
+  }
 
   errno = 0;
   bts->file = syscall (SYS_perf_event_open, &bts->attr, pid, -1, -1, 0);
   if (bts->file < 0)
-    goto err;
+    goto err_out;
 
   /* The buffer size can be requested in powers of two pages.
      We track the number of pages we request in PAGES and its base-2 log
@@ -531,11 +752,116 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
   /* We were not able to allocate any buffer.  */
   close (bts->file);
 
+ err_out:
+  xfree (tinfo);
+  return NULL;
+}
+
+#if defined(PERF_ATTR_SIZE_VER4)
+
+/* Enable branch tracing in Intel Processor Trace format.  */
+
+static struct btrace_target_info *
+linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
+{
+  struct perf_event_mmap_page *header;
+  struct btrace_target_info *tinfo;
+  struct btrace_tinfo_pt *pt;
+  unsigned int pages, size;
+  int pid, pg, errcode, type;
+
+  if (conf->size == 0)
+    return NULL;
+
+  errcode = perf_event_pt_event_type (&type);
+  if (errcode != 0)
+    return NULL;
+
+  pid = ptid_get_lwp (ptid);
+  if (pid == 0)
+    pid = ptid_get_pid (ptid);
+
+  tinfo = xzalloc (sizeof (*tinfo));
+  tinfo->ptid = ptid;
+  tinfo->ptr_bits = 0;
+
+  tinfo->conf.format = BTRACE_FORMAT_PT;
+  pt = &tinfo->variant.pt;
+
+  pt->attr.size = sizeof (pt->attr);
+  pt->attr.type = type;
+
+  pt->attr.exclude_kernel = 1;
+  pt->attr.exclude_hv = 1;
+  pt->attr.exclude_idle = 1;
+
+  errno = 0;
+  pt->file = syscall (SYS_perf_event_open, &pt->attr, pid, -1, -1, 0);
+  if (pt->file < 0)
+    goto err;
+
+  /* Allocate the configuration page. */
+  header = mmap (NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+		 pt->file, 0);
+  if (header == MAP_FAILED)
+    goto err_file;
+
+  header->aux_offset = header->data_offset + header->data_size;
+  size = (conf->size + PAGE_SIZE - 1) / PAGE_SIZE;
+
+  /* The buffer size can be requested in powers of two pages.
+     We track the number of pages we request in PAGES and its base-2 log
+     in PG.  */
+
+  /* Adjust size to the next power of two.  */
+  for (pg = 0, pages = 1; pages != size; ++pg, pages = (1u << pg))
+    if ((pages & size) != 0)
+      size += pages;
+
+  /* We try to allocate the requested size.
+     If that fails, try to get as much as we can.  */
+  for (; size > 0; size >>= 1)
+    {
+      header->aux_size = size * PAGE_SIZE;
+
+      pt->pt.mem = mmap (NULL, header->aux_size, PROT_READ, MAP_SHARED,
+			 pt->file, header->aux_offset);
+      if (pt->pt.mem != MAP_FAILED)
+	break;
+    }
+
+  if (size == 0)
+    goto err_conf;
+
+  pt->header = header;
+  pt->pt.size = header->aux_size;
+  pt->pt.data_head = &header->aux_head;
+
+  tinfo->conf.pt.size = pt->pt.size;
+  return tinfo;
+
+ err_conf:
+  munmap((void *) header, PAGE_SIZE);
+
+ err_file:
+  close (pt->file);
+
  err:
   xfree (tinfo);
   return NULL;
 }
 
+#else /* !defined(PERF_ATTR_SIZE_VER4) */
+
+static struct btrace_target_info *
+linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
+{
+  errno = EOPNOTSUPP;
+  return NULL;
+}
+
+#endif /* !defined(PERF_ATTR_SIZE_VER4) */
+
 /* See linux-btrace.h.  */
 
 struct btrace_target_info *
@@ -552,6 +878,10 @@ linux_enable_btrace (ptid_t ptid, const struct btrace_config *conf)
     case BTRACE_FORMAT_BTS:
       tinfo = linux_enable_bts (ptid, &conf->bts);
       break;
+
+    case BTRACE_FORMAT_PT:
+      tinfo = linux_enable_pt (ptid, &conf->pt);
+      break;
     }
 
   return tinfo;
@@ -568,6 +898,18 @@ linux_disable_bts (struct btrace_tinfo_bts *tinfo)
   return BTRACE_ERR_NONE;
 }
 
+/* Disable Intel Processor Trace tracing.  */
+
+static enum btrace_error
+linux_disable_pt (struct btrace_tinfo_pt *tinfo)
+{
+  munmap((void *) tinfo->pt.mem, tinfo->pt.size);
+  munmap((void *) tinfo->header, PAGE_SIZE);
+  close (tinfo->file);
+
+  return BTRACE_ERR_NONE;
+}
+
 /* See linux-btrace.h.  */
 
 enum btrace_error
@@ -584,6 +926,10 @@ linux_disable_btrace (struct btrace_target_info *tinfo)
     case BTRACE_FORMAT_BTS:
       errcode = linux_disable_bts (&tinfo->variant.bts);
       break;
+
+    case BTRACE_FORMAT_PT:
+      errcode = linux_disable_pt (&tinfo->variant.pt);
+      break;
     }
 
   if (errcode == BTRACE_ERR_NONE)
@@ -681,6 +1027,51 @@ linux_read_bts (struct btrace_data_bts *btrace,
   return BTRACE_ERR_NONE;
 }
 
+/* Fill in the Intel Processor Trace configuration information.  */
+
+static void
+linux_fill_btrace_pt_config (struct btrace_data_pt_config *conf)
+{
+  conf->cpu = btrace_this_cpu ();
+}
+
+/* Read branch trace data in Intel Processor Trace format for the thread given
+   by TINFO into BTRACE using the TYPE reading method.  */
+
+static enum btrace_error
+linux_read_pt (struct btrace_data_pt *btrace,
+	       struct btrace_target_info *tinfo,
+	       enum btrace_read_type type)
+{
+  struct perf_event_buffer *pt;
+  enum btrace_error errcode;
+
+  pt = &tinfo->variant.pt.pt;
+
+  linux_fill_btrace_pt_config (&btrace->config);
+
+  switch (type)
+    {
+    case BTRACE_READ_DELTA:
+      errcode = perf_event_read_new (pt, &btrace->data, &btrace->size);
+      if (errcode != BTRACE_ERR_NONE)
+	return errcode;
+
+      return BTRACE_ERR_NONE;
+
+    case BTRACE_READ_NEW:
+      if (!perf_event_new_data (pt))
+	return BTRACE_ERR_NONE;
+
+      /* Fall through.  */
+    case BTRACE_READ_ALL:
+      perf_event_read_all (pt, &btrace->data, &btrace->size);
+      return BTRACE_ERR_NONE;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown btrace read type."));
+}
+
 /* See linux-btrace.h.  */
 
 enum btrace_error
@@ -699,6 +1090,13 @@ linux_read_btrace (struct btrace_data *btrace,
       btrace->variant.bts.blocks = NULL;
 
       return linux_read_bts (&btrace->variant.bts, tinfo, type);
+
+    case BTRACE_FORMAT_PT:
+      /* We read btrace in Intel Processor Trace format.  */
+      btrace->format = BTRACE_FORMAT_PT;
+      btrace->variant.pt.data = NULL;
+
+      return linux_read_pt (&btrace->variant.pt, tinfo, type);
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index 12cdcde..064356e 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -64,6 +64,22 @@ struct btrace_tinfo_bts
   /* The BTS perf event buffer.  */
   struct perf_event_buffer bts;
 };
+
+/* Branch trace target information for Intel Processor Trace.  */
+struct btrace_tinfo_pt
+{
+  /* The Linux perf_event configuration for collecting the branch trace.  */
+  struct perf_event_attr attr;
+
+  /* The perf event file.  */
+  int file;
+
+  /* The perf event configuration page. */
+  volatile struct perf_event_mmap_page *header;
+
+  /* The trace perf event buffer.  */
+  struct perf_event_buffer pt;
+};
 #endif /* HAVE_LINUX_PERF_EVENT_H */
 
 /* Branch trace target information per thread.  */
@@ -81,6 +97,9 @@ struct btrace_target_info
   {
     /* CONF.FORMAT == BTRACE_FORMAT_BTS.  */
     struct btrace_tinfo_bts bts;
+
+    /* CONF.FORMAT == BTRACE_FORMAT_PT.  */
+    struct btrace_tinfo_pt pt;
   } variant;
 #endif /* HAVE_LINUX_PERF_EVENT_H */
 
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index b3e3c3b..2eb520d 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -84,6 +84,10 @@ static struct cmd_list_element *show_record_btrace_cmdlist;
 static struct cmd_list_element *set_record_btrace_bts_cmdlist;
 static struct cmd_list_element *show_record_btrace_bts_cmdlist;
 
+/* Command lists for "set/show record btrace pt".  */
+static struct cmd_list_element *set_record_btrace_pt_cmdlist;
+static struct cmd_list_element *show_record_btrace_pt_cmdlist;
+
 /* Print a record-btrace debug message.  Use do ... while (0) to avoid
    ambiguities when used in if statements.  */
 
@@ -321,6 +325,22 @@ record_btrace_print_bts_conf (const struct btrace_config_bts *conf)
     }
 }
 
+/* Print an Intel Processor Trace configuration.  */
+
+static void
+record_btrace_print_pt_conf (const struct btrace_config_pt *conf)
+{
+  const char *suffix;
+  unsigned int size;
+
+  size = conf->size;
+  if (size > 0)
+    {
+      suffix = record_btrace_adjust_size (&size);
+      printf_unfiltered (_("Buffer size: %u%s.\n"), size, suffix);
+    }
+}
+
 /* Print a branch tracing configuration.  */
 
 static void
@@ -337,6 +357,10 @@ record_btrace_print_conf (const struct btrace_config *conf)
     case BTRACE_FORMAT_BTS:
       record_btrace_print_bts_conf (&conf->bts);
       return;
+
+    case BTRACE_FORMAT_PT:
+      record_btrace_print_pt_conf (&conf->pt);
+      return;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -447,6 +471,33 @@ btrace_ui_out_decode_error (struct ui_out *uiout, int errcode,
 	  break;
 	}
       break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      switch (errcode)
+	{
+	case BDE_PT_USER_QUIT:
+	  is_error = 0;
+	  errstr = _("trace decode cancelled");
+	  break;
+
+	case BDE_PT_DISABLED:
+	  is_error = 0;
+	  errstr = _("disabled");
+	  break;
+
+	case BDE_PT_OVERFLOW:
+	  is_error = 0;
+	  errstr = _("overflow");
+	  break;
+
+	default:
+	  if (errcode < 0)
+	    errstr = pt_errstr (pt_errcode (errcode));
+	  break;
+	}
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
     }
 
   ui_out_text (uiout, _("["));
@@ -2216,6 +2267,28 @@ cmd_record_btrace_bts_start (char *args, int from_tty)
     }
 }
 
+/* Start recording Intel Processor Trace.  */
+
+static void
+cmd_record_btrace_pt_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_PT;
+
+  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
@@ -2226,6 +2299,14 @@ cmd_record_btrace_start (char *args, int from_tty)
   if (args != NULL && *args != 0)
     error (_("Invalid argument."));
 
+  record_btrace_conf.format = BTRACE_FORMAT_PT;
+
+  TRY_CATCH (exception, RETURN_MASK_ALL)
+    execute_command ("target record-btrace", from_tty);
+
+  if (exception.error == 0)
+    return;
+
   record_btrace_conf.format = BTRACE_FORMAT_BTS;
 
   TRY_CATCH (exception, RETURN_MASK_ALL)
@@ -2283,6 +2364,25 @@ cmd_show_record_btrace_bts (char *args, int from_tty)
   cmd_show_list (show_record_btrace_bts_cmdlist, from_tty, "");
 }
 
+/* The "set record btrace pt" command.  */
+
+static void
+cmd_set_record_btrace_pt (char *args, int from_tty)
+{
+  printf_unfiltered (_("\"set record btrace pt\" must be followed "
+		       "by an apporpriate subcommand.\n"));
+  help_list (set_record_btrace_pt_cmdlist, "set record btrace pt ",
+	     all_commands, gdb_stdout);
+}
+
+/* The "show record btrace pt" command.  */
+
+static void
+cmd_show_record_btrace_pt (char *args, int from_tty)
+{
+  cmd_show_list (show_record_btrace_pt_cmdlist, from_tty, "");
+}
+
 void _initialize_record_btrace (void);
 
 /* Initialize btrace commands.  */
@@ -2303,6 +2403,13 @@ This format may not be available on all processors."),
 	   &record_btrace_cmdlist);
   add_alias_cmd ("bts", "btrace bts", class_obscure, 1, &record_cmdlist);
 
+  add_cmd ("pt", class_obscure, cmd_record_btrace_pt_start,
+	   _("\
+Start branch trace recording in Intel(R) Processor Trace format.\n\n\
+This format may not be available on all processors."),
+	   &record_btrace_cmdlist);
+  add_alias_cmd ("pt", "btrace pt", 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);
@@ -2349,6 +2456,27 @@ The trace buffer size may not be changed while recording."), NULL, NULL,
 			    &set_record_btrace_bts_cmdlist,
 			    &show_record_btrace_bts_cmdlist);
 
+  add_prefix_cmd ("pt", class_support, cmd_set_record_btrace_pt,
+		  _("Set record btrace pt options"),
+		  &set_record_btrace_pt_cmdlist,
+		  "set record btrace pt ", 0, &set_record_btrace_cmdlist);
+
+  add_prefix_cmd ("pt", class_support, cmd_show_record_btrace_pt,
+		  _("Show record btrace pt options"),
+		  &show_record_btrace_pt_cmdlist,
+		  "show record btrace pt ", 0, &show_record_btrace_cmdlist);
+
+  add_setshow_uinteger_cmd ("buffer-size", no_class,
+			    &record_btrace_conf.pt.size,
+			    _("Set the record/replay pt buffer size."),
+			    _("Show the record/replay pt buffer size."), _("\
+Bigger buffers allow longer recording but also take more time to process \
+the recorded execution.\n\
+The actual buffer size may differ from the requested size.  Use \"info record\" \
+to see the actual buffer size."), NULL, NULL,
+			    &set_record_btrace_pt_cmdlist,
+			    &show_record_btrace_pt_cmdlist);
+
   init_record_btrace_ops ();
   add_target (&record_btrace_ops);
 
@@ -2356,4 +2484,5 @@ The trace buffer size may not be changed while recording."), NULL, NULL,
 			       xcalloc, xfree);
 
   record_btrace_conf.bts.size = 64 * 1024;
+  record_btrace_conf.pt.size = 16 * 1024;
 }
diff --git a/gdb/remote.c b/gdb/remote.c
index b78b848..4fa7747 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1310,6 +1310,7 @@ enum {
   PACKET_QTBuffer_size,
   PACKET_Qbtrace_off,
   PACKET_Qbtrace_bts,
+  PACKET_Qbtrace_pt,
   PACKET_qXfer_btrace,
 
   /* Support for the QNonStop packet.  */
@@ -1338,6 +1339,9 @@ enum {
   /* Support for the Qbtrace-conf:bts:size packet.  */
   PACKET_Qbtrace_conf_bts_size,
 
+  /* Support for the Qbtrace-conf:pt:size packet.  */
+  PACKET_Qbtrace_conf_pt_size,
+
   PACKET_MAX
 };
 
@@ -4020,12 +4024,15 @@ static const struct protocol_feature remote_protocol_features[] = {
   { "tracenz", PACKET_DISABLE, remote_supported_packet, PACKET_tracenz_feature },
   { "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
   { "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
+  { "Qbtrace:pt", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_pt },
   { "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_btrace },
   { "qXfer:btrace-conf:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_btrace_conf },
   { "Qbtrace-conf:bts:size", PACKET_DISABLE, remote_supported_packet,
-    PACKET_Qbtrace_conf_bts_size }
+    PACKET_Qbtrace_conf_bts_size },
+  { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet,
+    PACKET_Qbtrace_conf_pt_size }
 };
 
 static char *remote_support_xml;
@@ -11373,6 +11380,15 @@ remote_supports_btrace (struct target_ops *self, enum btrace_format format)
 
       case BTRACE_FORMAT_BTS:
 	return (packet_support (PACKET_Qbtrace_bts) == PACKET_ENABLE);
+
+      case BTRACE_FORMAT_PT:
+	/* The trace is decoded on the host.  Even if our target supports it,
+	   we still need to have libipt to decode the trace.  */
+#if defined (HAVE_LIBIPT)
+	return (packet_support (PACKET_Qbtrace_pt) == PACKET_ENABLE);
+#else /* !defined (HAVE_LIBIPT)  */
+	return 0;
+#endif /* !defined (HAVE_LIBIPT)  */
     }
 
   internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
@@ -11412,6 +11428,28 @@ btrace_sync_conf (const struct btrace_config *conf)
 
       rs->btrace_config.bts.size = conf->bts.size;
     }
+
+  packet = &remote_protocol_packets[PACKET_Qbtrace_conf_pt_size];
+  if (packet_config_support (packet) == PACKET_ENABLE
+      && conf->pt.size != rs->btrace_config.pt.size)
+    {
+      pos = buf;
+      pos += xsnprintf (pos, endbuf - pos, "%s=0x%x", packet->name,
+                        conf->pt.size);
+
+      putpkt (buf);
+      getpkt (&buf, &rs->buf_size, 0);
+
+      if (packet_ok (buf, packet) == PACKET_ERROR)
+	{
+	  if (buf[0] == 'E' && buf[1] == '.')
+	    error (_("Failed to configure the trace buffer size: %s"), buf + 2);
+	  else
+	    error (_("Failed to configure the trace buffer size."));
+	}
+
+      rs->btrace_config.pt.size = conf->pt.size;
+    }
 }
 
 /* Read the current thread's btrace configuration from the target and
@@ -11423,7 +11461,7 @@ btrace_read_config (struct btrace_config *conf)
   char *xml;
 
   xml = target_read_stralloc (&current_target,
-                              TARGET_OBJECT_BTRACE_CONF, "");
+			      TARGET_OBJECT_BTRACE_CONF, "");
   if (xml != NULL)
     {
       struct cleanup *cleanup;
@@ -11441,13 +11479,24 @@ 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 packet_config *packet = NULL;
   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)
+  switch (conf->format)
+    {
+      case BTRACE_FORMAT_BTS:
+	packet = &remote_protocol_packets[PACKET_Qbtrace_bts];
+	break;
+
+      case BTRACE_FORMAT_PT:
+	packet = &remote_protocol_packets[PACKET_Qbtrace_pt];
+	break;
+    }
+
+  if (packet == NULL || packet_config_support (packet) != PACKET_ENABLE)
     error (_("Target does not support branch tracing."));
 
   btrace_sync_conf (conf);
@@ -11564,7 +11613,7 @@ remote_read_btrace (struct target_ops *self,
     }
 
   xml = target_read_stralloc (&current_target,
-                              TARGET_OBJECT_BTRACE, annex);
+			      TARGET_OBJECT_BTRACE, annex);
   if (xml == NULL)
     return BTRACE_ERR_UNKNOWN;
 
@@ -12304,7 +12353,10 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
        "Qbtrace:off", "disable-btrace", 0);
 
   add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_bts],
-       "Qbtrace:bts", "enable-btrace", 0);
+       "Qbtrace:bts", "enable-btrace-bts", 0);
+
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_pt],
+       "Qbtrace:pt", "enable-btrace-pt", 0);
 
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
        "qXfer:btrace", "read-btrace", 0);
@@ -12315,6 +12367,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_bts_size],
        "Qbtrace-conf:bts:size", "btrace-conf-bts-size", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size],
+       "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0);
+
   /* Assert that we've registered commands for all packet configs.  */
   {
     int i;
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace
  2015-01-29 19:28 ` [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace Markus Metzger
@ 2015-01-29 19:28   ` Eli Zaretskii
  2015-01-30 18:57     ` Metzger, Markus T
  0 siblings, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2015-01-29 19:28 UTC (permalink / raw)
  To: Markus Metzger; +Cc: palves, gdb-patches

> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org
> Date: Thu, 29 Jan 2015 17:28:19 +0100
> 

Does "[wip]" mean I shouldn't yet review the patch?

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 04/15] record btrace: add configuration struct
  2015-01-29 18:35 ` [PATCH v3 04/15] record btrace: add configuration struct Markus Metzger
@ 2015-01-29 19:29   ` Eli Zaretskii
  0 siblings, 0 replies; 20+ messages in thread
From: Eli Zaretskii @ 2015-01-29 19:29 UTC (permalink / raw)
  To: Markus Metzger; +Cc: palves, gdb-patches

> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org
> Date: Thu, 29 Jan 2015 17:28:08 +0100
> 
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -14,6 +14,17 @@
>  * The command 'thread apply all' can now support new option '-ascending'
>    to call its specified command for all threads in ascending order.
>  
> +* New commands
> +
> +record btrace bts
> +record bts
> +  Start branch trace recording using Intel(R) Branch Trace Store format.
> +
> +* New remote packets
> +
> +qXfer:btrace-conf:read
> +  Return the branch trace configuration for the current thread.
> +
>  *** Changes in GDB 7.9

This part is OK.

> +@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.

Please us @dfn{...} around "Branch Trace Store" (it's new
terminology), and please use "@acronym{BTS}".

Also, please add a @cindex entry for "branch trace store" here.

The documentation parts are OK with these fixed.

Thanks.

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace
  2015-01-29 19:28   ` Eli Zaretskii
@ 2015-01-30 18:57     ` Metzger, Markus T
  0 siblings, 0 replies; 20+ messages in thread
From: Metzger, Markus T @ 2015-01-30 18:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: palves, gdb-patches

> -----Original Message-----
> From: Eli Zaretskii [mailto:eliz@gnu.org]
> Sent: Thursday, January 29, 2015 6:11 PM
> To: Metzger, Markus T
> Cc: palves@redhat.com; gdb-patches@sourceware.org
> Subject: Re: [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace
> 
> > From: Markus Metzger <markus.t.metzger@intel.com>
> > Cc: gdb-patches@sourceware.org
> > Date: Thu, 29 Jan 2015 17:28:19 +0100
> >
> 
> Does "[wip]" mean I shouldn't yet review the patch?

I added it to motivate the patches before it.  They do lots
of changes that might make you wonder what for.

You may review the patch if you want and I will incorporate
your feedback.  I will send the patch out for review again
when the kernel changes it depends on have been merged;
this time without the [wip].
You will get another chance for review.

Regards,
Markus.
Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen, Deutschland
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
Registergericht: Muenchen HRB 47456
Ust.-IdNr./VAT Registration No.: DE129385895
Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052

^ permalink raw reply	[flat|nested] 20+ messages in thread

* RE: [PATCH v3 00/15] record btrace: prepare for a new trace format
  2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
                   ` (14 preceding siblings ...)
  2015-01-29 19:28 ` [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace Markus Metzger
@ 2015-02-04  8:25 ` Metzger, Markus T
  15 siblings, 0 replies; 20+ messages in thread
From: Metzger, Markus T @ 2015-02-04  8:25 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Jan Kratochvil (jan.kratochvil@redhat.com)

> -----Original Message-----
> From: Metzger, Markus T
> Sent: Thursday, January 29, 2015 5:28 PM
> To: palves@redhat.com

Hello Pedro,

>   btrace: add struct btrace_data
>   btrace: add format argument to supports_btrace
>   btrace, linux: add perf event buffer abstraction
>   record btrace: add configuration struct
>   record-btrace: add bts buffer size configuration option
>   btrace: update btrace_compute_ftrace parameters
>   btrace: extend struct btrace_insn
>   btrace: identify cpu
>   record-btrace: indicate gaps

I don't think it was a very good idea from me to extend the patch series
while under review.  Let's focus on the above patches from the original
series...

>   btrace: less debug output
>   btrace: work around _dl_runtime_resolve returning to resolved function
>   btrace: support 32-bit inferior on 64-bit host
>   btrace: increase buffer size for exception test

... and ignore the new bug-fix patches.  I'll send them in a new, separate
review request.  I found another bug I see on some targets and I'm working
on simplifying the test suite.  If I keep adding (those) patches to this series,
we will never get anywhere with it.

Makes sense?

Markus.

Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen, Deutschland
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
Registergericht: Muenchen HRB 47456
Ust.-IdNr./VAT Registration No.: DE129385895
Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2015-02-04  8:25 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-29 16:28 [PATCH v3 00/15] record btrace: prepare for a new trace format Markus Metzger
2015-01-29 16:29 ` [PATCH v3 05/15] record-btrace: add bts buffer size configuration option Markus Metzger
2015-01-29 16:29 ` [PATCH v3 12/15] btrace: support 32-bit inferior on 64-bit host Markus Metzger
2015-01-29 16:29 ` [PATCH v3 08/15] btrace: identify cpu Markus Metzger
2015-01-29 16:29 ` [PATCH v3 07/15] btrace: extend struct btrace_insn Markus Metzger
2015-01-29 16:29 ` [PATCH v3 13/15] btrace: increase buffer size for exception test Markus Metzger
2015-01-29 16:29 ` [PATCH v3 02/15] btrace: add format argument to supports_btrace Markus Metzger
2015-01-29 16:30 ` [PATCH v3 01/15] btrace: add struct btrace_data Markus Metzger
2015-01-29 16:30 ` [PATCH v3 06/15] btrace: update btrace_compute_ftrace parameters Markus Metzger
2015-01-29 16:30 ` [PATCH v3 14/15] configure: check for libipt Markus Metzger
2015-01-29 16:30 ` [PATCH v3 09/15] record-btrace: indicate gaps Markus Metzger
2015-01-29 16:33 ` [PATCH v3 11/15] btrace: work around _dl_runtime_resolve returning to resolved function Markus Metzger
2015-01-29 17:11 ` [PATCH v3 10/15] btrace: less debug output Markus Metzger
2015-01-29 17:11 ` [PATCH v3 03/15] btrace, linux: add perf event buffer abstraction Markus Metzger
2015-01-29 18:35 ` [PATCH v3 04/15] record btrace: add configuration struct Markus Metzger
2015-01-29 19:29   ` Eli Zaretskii
2015-01-29 19:28 ` [PATCH v3 15/15] [wip] btrace: support Intel(R) Processor Trace Markus Metzger
2015-01-29 19:28   ` Eli Zaretskii
2015-01-30 18:57     ` Metzger, Markus T
2015-02-04  8:25 ` [PATCH v3 00/15] record btrace: prepare for a new trace format Metzger, Markus T

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).