public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 06/12] btrace: update btrace_compute_ftrace parameters
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
@ 2014-07-14 13:56 ` Markus Metzger
  2014-07-14 13:56 ` [PATCH 09/12] btrace: use the new cpu identifier Markus Metzger
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:56 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.

2014-07-14  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 0eb5f1f..d96994d 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] 30+ messages in thread

* [PATCH 08/12] btrace: identify cpu
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (2 preceding siblings ...)
  2014-07-14 13:56 ` [PATCH 02/12] btrace: add format argument to supports_btrace Markus Metzger
@ 2014-07-14 13:56 ` Markus Metzger
  2014-11-05 20:47   ` Pedro Alves
  2014-07-14 13:57 ` [PATCH 05/12] record-btrace: add bts buffer size configuration option Markus Metzger
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:56 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Add a struct for identifying a processor and a function to identify the
processor we're running on.

We will need this feature for the new btrace format.

2014-07-14  Markus Metzger  <markus.t.metzger@intel.com>

	* common/btrace-common.h (btrace_cpu_vendor, btrace_cpu)
	(btrace_this_cpu): New.
	* common/btrace-common.c: Include i386-cpuid.h.
	(btrace_this_cpu): New.


---
 gdb/common/btrace-common.c | 37 +++++++++++++++++++++++++++++++++++++
 gdb/common/btrace-common.h | 30 ++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/gdb/common/btrace-common.c b/gdb/common/btrace-common.c
index 90774a2..178ad35 100644
--- a/gdb/common/btrace-common.c
+++ b/gdb/common/btrace-common.c
@@ -18,10 +18,47 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "btrace-common.h"
+#include "nat/i386-cpuid.h"
 
 
 /* See btrace-common.h.  */
 
+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 = i386_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 = i386_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;
+}
+
+/* See btrace-common.h.  */
+
 const char *
 btrace_format_string (enum btrace_format format)
 {
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 3629736..5fa9806 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -74,6 +74,34 @@ enum btrace_error
   BTRACE_ERR_OVERFLOW
 };
 
+/* 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
@@ -147,6 +175,8 @@ struct btrace_data
   } variant;
 };
 
+/* Identify the cpu we're running on.  */
+extern struct btrace_cpu btrace_this_cpu (void);
 
 /* Return a string representation of FORMAT.  */
 extern const char *btrace_format_string (enum btrace_format format);
-- 
1.8.3.1

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

* [PATCH 02/12] btrace: add format argument to supports_btrace
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
  2014-07-14 13:56 ` [PATCH 06/12] btrace: update btrace_compute_ftrace parameters Markus Metzger
  2014-07-14 13:56 ` [PATCH 09/12] btrace: use the new cpu identifier Markus Metzger
@ 2014-07-14 13:56 ` Markus Metzger
  2014-11-05 20:45   ` Pedro Alves
  2014-07-14 13:56 ` [PATCH 08/12] btrace: identify cpu Markus Metzger
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:56 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.

Moved declarations in btrace-common.h around to break a cyclic dependency
with gdbserver/server.h.

2014-07-14  Markus Metzger <markus.t.metzger@intel.com>

	* btrace.c (btrace_enable): Pass BTRACE_FORMAT_BTS.
	* common/btrace-common.h (btrace_format, btrace_target_info)
	(btrace_read_type, btrace_error): Move.
	* common/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.
	* common/linux-btrace.h (linux_supports_btrace): Update parameters.
	* 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.

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/common/btrace-common.h | 94 +++++++++++++++++++++++-----------------------
 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-delegates.c     |  6 +--
 gdb/target.c               |  8 ++++
 gdb/target.h               |  5 +--
 11 files changed, 130 insertions(+), 97 deletions(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 567cc8c..7b6b828 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/common/btrace-common.h b/gdb/common/btrace-common.h
index d5f013c..a28dfff 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -26,6 +26,54 @@
    inferior.  For presentation purposes, the branch trace is represented as a
    list of sequential control-flow blocks, one such list per thread.  */
 
+
+/* 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
+};
+
+/* Target specific branch trace information.  */
+struct btrace_target_info;
+
+/* Enumeration of btrace read types.  */
+
+enum btrace_read_type
+{
+  /* Send all available trace.  */
+  BTRACE_READ_ALL,
+
+  /* Send all available trace, if it changed.  */
+  BTRACE_READ_NEW,
+
+  /* Send the trace since the last request.  This will fail if the trace
+     buffer overflowed.  */
+  BTRACE_READ_DELTA
+};
+
+/* Enumeration of btrace errors.  */
+
+enum btrace_error
+{
+  /* No error.  Everything is OK.  */
+  BTRACE_ERR_NONE,
+
+  /* An unknown error.  */
+  BTRACE_ERR_UNKNOWN,
+
+  /* Branch tracing is not supported on this system.  */
+  BTRACE_ERR_NOT_SUPPORTED,
+
+  /* The branch trace buffer overflowed; no delta read possible.  */
+  BTRACE_ERR_OVERFLOW
+};
+
 #ifdef GDBSERVER
 #  include "server.h"
 #else
@@ -55,18 +103,6 @@ struct btrace_block
 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
 {
@@ -87,40 +123,6 @@ struct btrace_data
   } variant;
 };
 
-/* Target specific branch trace information.  */
-struct btrace_target_info;
-
-/* Enumeration of btrace read types.  */
-
-enum btrace_read_type
-{
-  /* Send all available trace.  */
-  BTRACE_READ_ALL,
-
-  /* Send all available trace, if it changed.  */
-  BTRACE_READ_NEW,
-
-  /* Send the trace since the last request.  This will fail if the trace
-     buffer overflowed.  */
-  BTRACE_READ_DELTA
-};
-
-/* Enumeration of btrace errors.  */
-
-enum btrace_error
-{
-  /* No error.  Everything is OK.  */
-  BTRACE_ERR_NONE,
-
-  /* An unknown error.  */
-  BTRACE_ERR_UNKNOWN,
-
-  /* Branch tracing is not supported on this system.  */
-  BTRACE_ERR_NOT_SUPPORTED,
-
-  /* The branch trace buffer overflowed; no delta read possible.  */
-  BTRACE_ERR_OVERFLOW
-};
 
 /* Return a string representation of FORMAT.  */
 extern const char *btrace_format_string (enum btrace_format format);
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index cf1dffe..146d95f 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -443,12 +443,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))
     {
@@ -1709,6 +1703,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
@@ -1940,12 +1948,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 f5eda8a..b9aa00b 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -25,9 +25,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;
 
@@ -357,7 +357,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.  */
@@ -498,9 +498,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 7ec5815..20b4ef0 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -262,10 +262,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;
@@ -276,14 +276,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);
 	}
@@ -291,7 +291,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);
 	}
@@ -302,14 +302,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;
 	}
@@ -334,10 +334,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);
 	}
 
@@ -345,10 +345,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;
 
@@ -386,10 +386,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;
 
@@ -398,24 +398,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;
@@ -426,6 +426,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)
 {
@@ -616,7 +633,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 5d713f4..7b02db5 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -62,7 +62,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 5ba4e06..9715e8a 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -200,9 +200,6 @@ record_btrace_open (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 1a390b9..aa2db4f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11244,16 +11244,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-delegates.c b/gdb/target-delegates.c
index 5971ec2..0cbd382 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -1359,14 +1359,14 @@ tdefault_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;
 }
diff --git a/gdb/target.c b/gdb/target.c
index 52858a9..635dde0 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3400,6 +3400,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 8b0282f..cc1a094 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -985,7 +985,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
@@ -2200,8 +2200,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] 30+ messages in thread

* [PATCH 09/12] btrace: use the new cpu identifier
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
  2014-07-14 13:56 ` [PATCH 06/12] btrace: update btrace_compute_ftrace parameters Markus Metzger
@ 2014-07-14 13:56 ` Markus Metzger
  2014-07-14 13:56 ` [PATCH 02/12] btrace: add format argument to supports_btrace Markus Metzger
                   ` (10 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:56 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

The preceding patch added a cpu identifier.  Use it.

2014-07-14  Markus Metzger  <markus.t.metzger@intel.com>

	* common/linux-btrace.c: Remove include i386-cpuid.h.
	(intel_supports_bts): Update parameters.
	(cpu_supports_bts): Call btrace_this_cpu.


---
 gdb/nat/linux-btrace.c | 36 +++++++++++++-----------------------
 1 file changed, 13 insertions(+), 23 deletions(-)

diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 628358f..b52106e 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -31,7 +31,6 @@
 #include "regcache.h"
 #include "gdbthread.h"
 #include "gdb_wait.h"
-#include "i386-cpuid.h"
 
 #ifdef HAVE_SYS_SYSCALL_H
 #include <sys/syscall.h>
@@ -405,22 +404,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 (!i386_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:
@@ -448,17 +437,18 @@ intel_supports_bts (void)
 static int
 cpu_supports_bts (void)
 {
-  unsigned int ebx, ecx, edx;
+  struct btrace_cpu cpu;
 
-  if (!i386_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] 30+ messages in thread

* [PATCH 00/12] record btrace: prepare for a new trace format
@ 2014-07-14 13:56 Markus Metzger
  2014-07-14 13:56 ` [PATCH 06/12] btrace: update btrace_compute_ftrace parameters Markus Metzger
                   ` (12 more replies)
  0 siblings, 13 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:56 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

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


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 not part
of the series under review.


Markus Metzger (12):
  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
  btrace: use the new cpu identifier
  record-btrace: indicate gaps
  configure: check for libipt
  [wip] btrace: support Intel(R) Processor Trace

 gdb/Makefile.in                                  |  16 +-
 gdb/NEWS                                         |  37 +
 gdb/btrace.c                                     | 965 ++++++++++++++++++++---
 gdb/btrace.h                                     |  98 ++-
 gdb/common/btrace-common.c                       | 175 ++++
 gdb/common/btrace-common.h                       | 242 +++++-
 gdb/config.in                                    |   3 +
 gdb/configure                                    | 498 ++++++++++++
 gdb/configure.ac                                 |  20 +
 gdb/doc/gdb.texinfo                              | 189 ++++-
 gdb/features/btrace-conf.dtd                     |  17 +
 gdb/features/btrace.dtd                          |  18 +-
 gdb/gdbserver/Makefile.in                        |   8 +-
 gdb/gdbserver/linux-low.c                        | 181 ++++-
 gdb/gdbserver/server.c                           | 228 +++++-
 gdb/gdbserver/target.h                           |  27 +-
 gdb/nat/linux-btrace.c                           | 806 ++++++++++++++++---
 gdb/nat/linux-btrace.h                           |  79 +-
 gdb/record-btrace.c                              | 497 +++++++++++-
 gdb/remote.c                                     | 233 +++++-
 gdb/target-delegates.c                           |  32 +-
 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/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                              |  18 +-
 34 files changed, 4143 insertions(+), 408 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] 30+ messages in thread

* [PATCH 10/12] record-btrace: indicate gaps
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (5 preceding siblings ...)
  2014-07-14 13:57 ` [PATCH 12/12] [wip] btrace: support Intel(R) Processor Trace Markus Metzger
@ 2014-07-14 13:57 ` Markus Metzger
  2014-07-14 13:57 ` [PATCH 07/12] btrace: extend struct btrace_insn Markus Metzger
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:57 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.

2014-07-14  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.c (ftrace_find_call): Skip gaps.
	(ftrace_new_gap): New.
	(ftrace_update_function): Create new function after gap.
	(btrace_compute_ftrace_bts): Create gap on error.
	(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): Assert that the last function is not empty.
	(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): 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                                     | 135 +++++++++++++++++--
 gdb/btrace.h                                     |  40 +++++-
 gdb/record-btrace.c                              | 160 ++++++++++++++++++-----
 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, 306 insertions(+), 65 deletions(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 0171352..517c73a 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -336,8 +336,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);
 
@@ -446,6 +447,32 @@ ftrace_new_switch (struct btrace_function *prev,
   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);
+
+  /* This is a gap in the trace.  The call stack will likely be wrong at this
+     point.  We keep the function level, though.  */
+  bfun->level = prev != NULL ? prev->level : 0;
+  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 +495,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.
@@ -595,13 +622,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,6 +654,11 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
 	    {
 	      warning (_("Recorded trace may be corrupted around %s."),
 		       core_addr_to_string_nz (pc));
+
+	      /* Indicate the gap in the trace.  */
+	      end = ftrace_new_gap (end, BDE_BTS_OVERFLOW);
+	      ngaps += 1;
+
 	      break;
 	    }
 
@@ -658,6 +691,11 @@ 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.  */
+	      end = ftrace_new_gap (end, BDE_BTS_INSN_SIZE);
+	      ngaps += 1;
+
 	      break;
 	    }
 
@@ -676,6 +714,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
@@ -1007,6 +1046,7 @@ btrace_clear (struct thread_info *tp)
 
   btinfo->begin = NULL;
   btinfo->end = NULL;
+  btinfo->ngaps = 0;
 
   btrace_clear_history (btinfo);
 }
@@ -1205,6 +1245,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);
@@ -1221,6 +1265,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;
 }
 
@@ -1256,6 +1305,7 @@ btrace_insn_end (struct btrace_insn_iterator *it,
   /* 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);
+  gdb_assert (length > 0);
 
   it->function = bfun;
   it->index = length - 1;
@@ -1279,6 +1329,23 @@ 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)
+	{
+	  stride -= 1;
+	  steps += 1;
+
+	  bfun = bfun->flow.next;
+	  index = 0;
+
+	  /* There won't be a gap at the end since we will always add
+	     an entry for the current PC.  */
+	  gdb_assert (bfun != NULL);
+
+	  continue;
+	}
+
       gdb_assert (0 < end);
       gdb_assert (index < end);
 
@@ -1353,12 +1420,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;
@@ -1385,6 +1460,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);
 }
 
@@ -1396,7 +1502,7 @@ 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)
@@ -1405,7 +1511,12 @@ btrace_find_insn_by_number (struct btrace_insn_iterator *it,
   if (bfun == NULL)
     return 0;
 
-  end = bfun->insn_offset + VEC_length (btrace_insn_s, bfun->insn);
+  /* Since we're searching backwards from the end, we will never find gaps;
+     we will already stop at the function segment succeeding a gap.  */
+  length = VEC_length (btrace_insn_s, bfun->insn);
+  gdb_assert (length > 0);
+
+  end = bfun->insn_offset + length;
   if (end <= number)
     return 0;
 
@@ -1507,6 +1618,9 @@ btrace_call_next (struct btrace_call_iterator *it, unsigned int stride)
 	  insns = VEC_length (btrace_insn_s, bfun->insn);
 	  if (insns == 1)
 	    steps -= 1;
+
+	  /* We won't have gaps at the end.  */
+	  gdb_assert (insns > 0);
 	}
 
       if (stride == steps)
@@ -1547,6 +1661,9 @@ btrace_call_prev (struct btrace_call_iterator *it, unsigned int stride)
       if (insns == 1)
 	bfun = bfun->flow.prev;
 
+      /* We won't have gaps at the end.  */
+      gdb_assert (insns > 0);
+
       if (bfun == NULL)
 	return 0;
 
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 3de7b73..7b524fa 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 f653d6b..418bb92 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -351,7 +351,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");
 
@@ -369,6 +369,7 @@ record_btrace_info (struct target_ops *self)
 
   insns = 0;
   calls = 0;
+  gaps = 0;
 
   if (!btrace_is_empty (tp))
     {
@@ -380,19 +381,67 @@ 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);
+      /* The last instruction does not really belong to the trace.  */
+      insns -= 1;
+
+      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
@@ -405,6 +454,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)
 {
@@ -422,13 +472,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);
+	}
     }
 }
 
@@ -505,7 +572,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)
@@ -565,7 +632,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);
@@ -706,6 +773,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;
@@ -1736,9 +1818,13 @@ 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);
+      /* We are always able to step at least once - to the last instruction.
+	 Skip gaps during replay.  */
+      do
+	{
+	  steps = btrace_insn_next (replay, 1);
+	  gdb_assert (steps == 1);
+	} while (btrace_insn_get (replay) == NULL);
 
       /* Determine the end of the instruction trace.  */
       btrace_insn_end (&end, btinfo);
@@ -1754,10 +1840,14 @@ 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 ();
 
@@ -1776,9 +1866,15 @@ 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);
+	  /* We are always able to step at least once - to the last instruction.
+	     Skip gaps during replay.  */
+	  do
+	    {
+	      steps = btrace_insn_next (replay, 1);
+	      gdb_assert (steps == 1);
+
+	      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)
@@ -1787,9 +1883,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));
@@ -1810,13 +1903,16 @@ 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 a13b950..68a9563 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"]
 gdb_test "record stop" ".*"
 
@@ -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"]
 gdb_test "record stop" ".*"
diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp
index 71ccf07..d594102 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 2926c0f..37203a3 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 593055b..c55c9de 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 5a77357..e61a297 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 1bc8125..7bf7cc9 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 a263607..2cdaf73 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 4c1d875..6925193 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 483166b..86ffa0a 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 cce41e6..5c9625c 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] 30+ messages in thread

* [PATCH 11/12] configure: check for libipt
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (7 preceding siblings ...)
  2014-07-14 13:57 ` [PATCH 07/12] btrace: extend struct btrace_insn Markus Metzger
@ 2014-07-14 13:57 ` Markus Metzger
  2014-07-14 13:57 ` [PATCH 04/12] record btrace: add configuration struct Markus Metzger
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:57 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

2014-07-14  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 785d790..2dd9cc0 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)
@@ -557,7 +560,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 8585b49..30d401b 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 a4c0a8c..2e0e1e9 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -658,6 +658,9 @@ TARGET_SYSTEM_ROOT
 CONFIG_LDFLAGS
 RDYNAMIC
 ALLOCA
+LTLIBIPT
+LIBIPT
+HAVE_LIBIPT
 GUILE_LIBS
 GUILE_CPPFLAGS
 pkg_config_prog_path
@@ -818,6 +821,8 @@ with_libexpat_prefix
 with_python
 with_guile
 enable_libmcheck
+with_intel_pt
+with_libipt_prefix
 with_included_regex
 with_sysroot
 with_system_gdbinit
@@ -1536,6 +1541,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
@@ -9182,6 +9190,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 a2ac15f..aa47a04 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1240,6 +1240,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] 30+ messages in thread

* [PATCH 03/12] btrace, linux: add perf event buffer abstraction
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (9 preceding siblings ...)
  2014-07-14 13:57 ` [PATCH 04/12] record btrace: add configuration struct Markus Metzger
@ 2014-07-14 13:57 ` Markus Metzger
  2014-07-14 14:48 ` [PATCH 01/12] btrace: add struct btrace_data Markus Metzger
  2014-10-28 14:35 ` [PATCH 00/12] record btrace: prepare for a new trace format Metzger, Markus T
  12 siblings, 0 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:57 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.

We will need other perf event buffers with different content.

2014-07-14  Markus Metzger <markus.t.metzger@intel.com>

	* common/linux-btrace.h (perf_event_buffer): New.
	(btrace_target_info) <buffer, size, data_head>: Replace with ...
	<bts>: ... this.
	* common/linux-btrace.c (perf_event_header, perf_event_mmap_size)
	(perf_event_buffer_size, perf_event_buffer_begin)
	(perf_event_buffer_end): Update parameters.  Updated users.
	(perf_event_map_buffer, perf_event_unmap_buffer)
	(perf_event_new_data): New.
	(linux_enable_btrace): Call perf_event_map_buffer.
	(linux_disable_btrace): Call perf_event_unmap_buffer.
	(linux_btrace_has_changed): Remove.
---
 gdb/nat/linux-btrace.c | 117 ++++++++++++++++++++++++++++++-------------------
 gdb/nat/linux-btrace.h |  29 ++++++++----
 2 files changed, 93 insertions(+), 53 deletions(-)

diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 20b4ef0..f33a455 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -72,42 +72,90 @@ struct perf_event_sample
 /* Get the perf_event header.  */
 
 static inline volatile struct perf_event_mmap_page *
-perf_event_header (struct btrace_target_info* tinfo)
+perf_event_header (const struct perf_event_buffer *pevent)
 {
-  return tinfo->buffer;
+  return pevent->mem;
 }
 
 /* Get the size of the perf_event mmap buffer.  */
 
 static inline size_t
-perf_event_mmap_size (const struct btrace_target_info *tinfo)
+perf_event_mmap_size (const struct perf_event_buffer *pevent)
 {
   /* The branch trace buffer is preceded by a configuration page.  */
-  return (tinfo->size + 1) * PAGE_SIZE;
+  return (pevent->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)
+perf_event_buffer_size (const struct perf_event_buffer *pevent)
 {
-  return tinfo->size * PAGE_SIZE;
+  return pevent->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)
+perf_event_buffer_begin (const struct perf_event_buffer *pevent)
 {
-  return ((const uint8_t *) tinfo->buffer) + PAGE_SIZE;
+  return ((const uint8_t *) pevent->mem) + 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)
+perf_event_buffer_end (const struct perf_event_buffer *pevent)
 {
-  return perf_event_buffer_begin (tinfo) + perf_event_buffer_size (tinfo);
+  return perf_event_buffer_begin (pevent) + perf_event_buffer_size (pevent);
+}
+
+/* Map a perf event buffer.
+   Return zero on success; a negative number otherwise.  */
+
+static int
+perf_event_map_buffer (struct perf_event_buffer *pev, int file, off_t offset)
+{
+  int pg;
+
+  /* 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 number of pages we request needs to be a power of two.  */
+      pev->size = 1 << pg;
+      pev->mem = mmap (NULL, perf_event_mmap_size (pev),
+		       PROT_READ, MAP_SHARED, file, offset);
+      if (pev->mem != MAP_FAILED)
+	return 0;
+    }
+
+  return -1;
+}
+
+/* Unmap a perf event buffer.
+   Return zero on success; a negative number otherwise.  */
+
+static int
+perf_event_unmap_buffer (struct perf_event_buffer *pev)
+{
+  int errcode;
+
+  errcode = munmap (pev->mem, perf_event_mmap_size (pev));
+  if (errcode != 0)
+    return errno;
+
+  return 0;
+}
+
+/* Return non-zero if there is new data in PEVENT; zero otherwise.  */
+
+static int
+perf_event_new_data (const struct perf_event_buffer *pev)
+{
+  volatile struct perf_event_mmap_page *header = perf_event_header (pev);
+  return header->data_head != pev->data_head;
 }
 
 /* Check whether an address is in the kernel.  */
@@ -447,7 +495,7 @@ struct btrace_target_info *
 linux_enable_btrace (ptid_t ptid)
 {
   struct btrace_target_info *tinfo;
-  int pid, pg;
+  int pid, errcode;
 
   tinfo = xzalloc (sizeof (*tinfo));
   tinfo->ptid = ptid;
@@ -475,20 +523,9 @@ linux_enable_btrace (ptid_t ptid)
   if (tinfo->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 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;
-    }
+  errcode = perf_event_map_buffer (&tinfo->bts, tinfo->file, 0);
+  if (errcode == 0)
+    return tinfo;
 
   /* We were not able to allocate any buffer.  */
   close (tinfo->file);
@@ -505,8 +542,7 @@ linux_disable_btrace (struct btrace_target_info *tinfo)
 {
   int errcode;
 
-  errno = 0;
-  errcode = munmap (tinfo->buffer, perf_event_mmap_size (tinfo));
+  errcode = perf_event_unmap_buffer (&tinfo->bts);
   if (errcode != 0)
     return BTRACE_ERR_UNKNOWN;
 
@@ -516,16 +552,6 @@ linux_disable_btrace (struct btrace_target_info *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.  */
 
@@ -535,18 +561,21 @@ linux_read_bts (struct btrace_data_bts *btrace,
 		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;
 
+  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;
+  header = perf_event_header (pevent);
+  buffer_size = perf_event_buffer_size (pevent);
+  data_tail = pevent->data_head;
 
   /* We may need to retry reading the trace.  See below.  */
   while (retries--)
@@ -583,13 +612,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 = perf_event_buffer_begin (pevent);
       start = begin + data_head % buffer_size;
 
       if (data_head <= buffer_size)
 	end = start;
       else
-	end = perf_event_buffer_end (tinfo);
+	end = perf_event_buffer_end (pevent);
 
       btrace->blocks = perf_event_read_bts (tinfo, begin, end, start, size);
 
@@ -602,7 +631,7 @@ linux_read_bts (struct btrace_data_bts *btrace,
 	break;
     }
 
-  tinfo->data_head = data_head;
+  pevent->data_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 7b02db5..5af3f87 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -33,6 +33,22 @@
 #  include <linux/perf_event.h>
 #endif
 
+#if HAVE_LINUX_PERF_EVENT_H
+/* A Linux perf event buffer.  */
+struct perf_event_buffer
+{
+  /* The mapped memory.  */
+  void *mem;
+
+  /* The size of the mapped memory in pages excluding the initial
+     configuration page.  */
+  size_t size;
+
+  /* The data_head value from the last read.  */
+  unsigned long data_head;
+};
+#endif /* HAVE_LINUX_PERF_EVENT_H */
+
 /* Branch trace target information per thread.  */
 struct btrace_target_info
 {
@@ -43,16 +59,11 @@ 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 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] 30+ messages in thread

* [PATCH 05/12] record-btrace: add bts buffer size configuration option
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (3 preceding siblings ...)
  2014-07-14 13:56 ` [PATCH 08/12] btrace: identify cpu Markus Metzger
@ 2014-07-14 13:57 ` Markus Metzger
  2014-07-14 15:44   ` Eli Zaretskii
  2014-11-05 20:46   ` Pedro Alves
  2014-07-14 13:57 ` [PATCH 12/12] [wip] btrace: support Intel(R) Processor Trace Markus Metzger
                   ` (7 subsequent siblings)
  12 siblings, 2 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:57 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Eli Zaretskii

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.

CC: Eli Zaretskii  <eliz@gnu.org>

2014-07-14  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.
	* common/linux-btrace.c (linux_enable_btrace): Use config.
	(perf_event_map_buffer): Add size parameter in pages.
	* 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                                 |  16 +++++
 gdb/btrace.c                             |  14 +++-
 gdb/common/btrace-common.h               |  15 +++-
 gdb/doc/gdb.texinfo                      |  77 ++++++++++++++++++--
 gdb/features/btrace-conf.dtd             |   3 +-
 gdb/gdbserver/linux-low.c                |   4 +-
 gdb/gdbserver/server.c                   |  60 +++++++++++++++-
 gdb/nat/linux-btrace.c                   |  38 +++++++---
 gdb/record-btrace.c                      | 118 ++++++++++++++++++++++++++++++-
 gdb/remote.c                             |  40 ++++++++++-
 gdb/testsuite/gdb.btrace/buffer-size.exp |  57 +++++++++++++++
 11 files changed, 419 insertions(+), 23 deletions(-)
 create mode 100644 gdb/testsuite/gdb.btrace/buffer-size.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index f32d1ef..d8ee284 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -9,11 +9,27 @@ record btrace bts
 record bts
   Start branch trace recording using Intel(R) Branch Trace Store format.
 
+* New options
+
+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 remote packets
 
 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.8
 
 * New command line options
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 3e263a1..0eb5f1f 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -1128,13 +1128,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 b1126b4..3629736 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -74,15 +74,28 @@ enum btrace_error
   BTRACE_ERR_OVERFLOW
 };
 
+/* 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;
 };
 
 #ifdef GDBSERVER
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d2760e0..e27233a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6471,6 +6471,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
@@ -6497,9 +6520,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
@@ -35464,6 +35503,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{-}
@@ -35721,6 +35765,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::
@@ -36160,6 +36207,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
@@ -38688,7 +38747,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}.
@@ -38700,6 +38768,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	#REQUIRED>
 @end smallexample
 
 @include agentexpr.texi
diff --git a/gdb/features/btrace-conf.dtd b/gdb/features/btrace-conf.dtd
index e9cb2ef..9a865d4 100644
--- a/gdb/features/btrace-conf.dtd
+++ b/gdb/features/btrace-conf.dtd
@@ -5,6 +5,7 @@
      notice and this notice are preserved.  -->
 
 <!ELEMENT btrace-conf	(bts?)>
-<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.1">
 
 <!ELEMENT bts	EMPTY>
+<!ATTLIST bts	size	CDATA	#IMPLIED>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index c7253aa..d68e730 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -6043,7 +6043,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 c601e8d..1994c8c 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -479,6 +479,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
@@ -638,6 +690,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;
@@ -1777,7 +1832,10 @@ static void
 supported_btrace_packets (char *buf)
 {
   if (target_supports_btrace (BTRACE_FORMAT_BTS))
-    strcat (buf, ";Qbtrace:bts+");
+    {
+      strcat (buf, ";Qbtrace:bts+");
+      strcat (own_buf, ";Qbtrace-conf:bts:size+");
+    }
   else
     return;
 
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 5c6d79c..628358f 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -114,17 +114,26 @@ perf_event_buffer_end (const struct perf_event_buffer *pevent)
    Return zero on success; a negative number otherwise.  */
 
 static int
-perf_event_map_buffer (struct perf_event_buffer *pev, int file, off_t offset)
+perf_event_map_buffer (struct perf_event_buffer *pev, int file, off_t offset,
+		       unsigned int size)
 {
+  unsigned int pages;
   int pg;
 
-  /* 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.  */
-      pev->size = 1 << pg;
+      pev->size = size;
       pev->mem = mmap (NULL, perf_event_mmap_size (pev),
 		       PROT_READ, MAP_SHARED, file, offset);
       if (pev->mem != MAP_FAILED)
@@ -492,10 +501,11 @@ 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 btrace_target_info *tinfo;
   struct btrace_tinfo_bts *bts;
+  unsigned int pages;
   int pid, errcode;
 
   tinfo = xzalloc (sizeof (*tinfo));
@@ -521,15 +531,23 @@ 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.  */
+  pages = (unsigned int) (((ULONGEST) conf->size + PAGE_SIZE - 1) / PAGE_SIZE);
+  if (pages == 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;
 
-  errcode = perf_event_map_buffer (&bts->bts, bts->file, 0);
+  errcode = perf_event_map_buffer (&bts->bts, bts->file, 0, pages);
   if (errcode == 0)
     {
       tinfo->conf.format = BTRACE_FORMAT_BTS;
+      tinfo->conf.bts.size = bts->bts.size * PAGE_SIZE;
       return tinfo;
     }
 
@@ -555,7 +573,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 fa2d741..f653d6b 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -77,6 +77,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.  */
 
@@ -270,6 +278,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
@@ -290,8 +363,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);
 
@@ -2089,6 +2161,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.  */
@@ -2132,9 +2223,32 @@ 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."), _("\
+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_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 6e93b0c..60e4e0e 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1340,6 +1340,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
 };
 
@@ -3938,7 +3941,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;
@@ -11296,7 +11301,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 != btrace_target_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."));
+	}
+
+      btrace_target_config.bts.size = conf->bts.size;
+    }
 }
 
 /* Read the current thread's btrace configuration from the target and
@@ -12196,6 +12229,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..a13b950
--- /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"
+
+gdb_test_no_output "record btrace bts"
+gdb_test "show record btrace bts buffer-size" "The record/replay bts buffer size is 1\.\r"
+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"]
+gdb_test "record stop" ".*"
+
+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"
+
+gdb_test_no_output "record btrace bts"
+gdb_test "show record btrace bts buffer-size" "The record/replay bts buffer size is unlimited\.\r"
+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"]
+gdb_test "record stop" ".*"
-- 
1.8.3.1

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

* [PATCH 07/12] btrace: extend struct btrace_insn
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (6 preceding siblings ...)
  2014-07-14 13:57 ` [PATCH 10/12] record-btrace: indicate gaps Markus Metzger
@ 2014-07-14 13:57 ` Markus Metzger
  2014-11-05 20:46   ` Pedro Alves
  2014-07-14 13:57 ` [PATCH 11/12] configure: check for libipt Markus Metzger
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:57 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.

2014-07-14  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 | 109 ++++++++++++++++++++++++++++++++---------------------------
 gdb/btrace.h |  22 ++++++++++++
 2 files changed, 81 insertions(+), 50 deletions(-)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index d96994d..0171352 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,35 @@ 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");
 }
 
+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_ALL)
+    {
+      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 +617,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 +629,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 +638,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_ALL)
+	    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 8656cda..3de7b73 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] 30+ messages in thread

* [PATCH 04/12] record btrace: add configuration struct
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (8 preceding siblings ...)
  2014-07-14 13:57 ` [PATCH 11/12] configure: check for libipt Markus Metzger
@ 2014-07-14 13:57 ` Markus Metzger
  2014-07-14 15:06   ` Eli Zaretskii
  2014-11-05 20:45   ` Pedro Alves
  2014-07-14 13:57 ` [PATCH 03/12] btrace, linux: add perf event buffer abstraction Markus Metzger
                   ` (2 subsequent siblings)
  12 siblings, 2 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:57 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Eli Zaretskii

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

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

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

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

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

CC: Eli Zaretskii  <eliz@gnu.org>

2014-07-14  Markus Metzger  <markus.t.metzger@intel.com>

	* Makefile.in (XMLFILES): Add btrace-conf.dtd.
	* amd64-linux-nat.c (amd64_linux_enable_btrace): Update parameters.
	(amd64_linux_btrace_conf): New.
	(_initialize_amd64_linux_nat): Initialize to_btrace_conf.
	* i386-linux-nat.c (i386_linux_enable_btrace): Update parameters.
	(i386_linux_btrace_conf): New.
	(_initialize_i386_linux_nat): Initialize to_btrace_conf.
	* 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.
	* common/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.
	* common/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.
	* 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_btrace_reset): New.
	(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_target_config): 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.
	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                           |  77 ++++++++++++-
 gdb/gdbserver/target.h                           |  19 +++-
 gdb/nat/linux-btrace.c                           | 131 ++++++++++++++++++-----
 gdb/nat/linux-btrace.h                           |  35 ++++--
 gdb/record-btrace.c                              |  69 ++++++++++--
 gdb/remote.c                                     |  82 +++++++++++++-
 gdb/target-delegates.c                           |  22 +++-
 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 ++-
 27 files changed, 646 insertions(+), 82 deletions(-)
 create mode 100644 gdb/features/btrace-conf.dtd

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 349fca9..785d790 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -581,7 +581,7 @@ XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
 	$(srcdir)/features/library-list-aix.dtd \
 	$(srcdir)/features/library-list-svr4.dtd $(srcdir)/features/osdata.dtd \
 	$(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd \
-	$(srcdir)/features/btrace.dtd
+	$(srcdir)/features/btrace.dtd $(srcdir)/features/btrace-conf.dtd
 
 # This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
 # interface to the serial port.  Hopefully if get ported to OS/2, VMS,
diff --git a/gdb/NEWS b/gdb/NEWS
index d9a19ae..f32d1ef 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,17 @@
 
 *** Changes since GDB 7.8
 
+* New commands (for set/show, see "New options" below)
+
+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.8
 
 * New command line options
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 7b6b828..3e263a1 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)
 {
@@ -1107,6 +1118,60 @@ parse_xml_btrace (struct btrace_data *btrace, const char *buffer)
 #endif  /* !defined (HAVE_LIBEXPAT) */
 }
 
+#if defined (HAVE_LIBEXPAT)
+
+/* Parse a btrace-conf "bts" xml record.  */
+
+static void
+parse_xml_btrace_conf_bts (struct gdb_xml_parser *parser,
+			  const struct gdb_xml_element *element,
+			  void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_config *conf;
+
+  conf = user_data;
+  conf->format = BTRACE_FORMAT_BTS;
+}
+
+static const struct gdb_xml_element btrace_conf_children[] = {
+  { "bts", NULL, NULL, GDB_XML_EF_OPTIONAL, parse_xml_btrace_conf_bts, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute btrace_conf_attributes[] = {
+  { "version", GDB_XML_AF_NONE, NULL, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_conf_elements[] = {
+  { "btrace-conf", btrace_conf_attributes, btrace_conf_children,
+    GDB_XML_EF_NONE, NULL, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+#endif /* defined (HAVE_LIBEXPAT) */
+
+/* See btrace.h.  */
+
+void
+parse_xml_btrace_conf (struct btrace_config *conf, const char *xml)
+{
+  int errcode;
+
+#if defined (HAVE_LIBEXPAT)
+
+  errcode = gdb_xml_parse_quick (_("btrace-conf"), "btrace-conf.dtd",
+				 btrace_conf_elements, xml, conf);
+  if (errcode != 0)
+    error (_("Error parsing branch trace configuration."));
+
+#else  /* !defined (HAVE_LIBEXPAT) */
+
+  error (_("XML parsing is not supported."));
+
+#endif  /* !defined (HAVE_LIBEXPAT) */
+}
+
 /* See btrace.h.  */
 
 const struct btrace_insn *
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 3954581..8656cda 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -215,7 +215,13 @@ struct btrace_thread_info
 };
 
 /* Enable branch tracing for a thread.  */
-extern void btrace_enable (struct thread_info *tp);
+extern void btrace_enable (struct thread_info *tp,
+			   const struct btrace_config *conf);
+
+/* Get the branch trace configuration for a thread.
+   Return NULL if branch tracing is not enabled for that thread.  */
+extern const struct btrace_config *
+  btrace_conf (const struct btrace_thread_info *);
 
 /* Disable branch tracing for a thread.
    This will also delete the current branch trace data.  */
@@ -238,6 +244,9 @@ extern void btrace_free_objfile (struct objfile *);
 /* Parse a branch trace xml document XML into DATA.  */
 extern void parse_xml_btrace (struct btrace_data *data, const char *xml);
 
+/* Parse a branch trace configuration xml document XML into CONF.  */
+extern void parse_xml_btrace_conf (struct btrace_config *conf, const char *xml);
+
 /* Dereference a branch trace instruction iterator.  Return a pointer to the
    instruction the iterator points to.  */
 extern const struct btrace_insn *
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index a28dfff..b1126b4 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -74,6 +74,17 @@ enum btrace_error
   BTRACE_ERR_OVERFLOW
 };
 
+/* 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;
+};
+
 #ifdef GDBSERVER
 #  include "server.h"
 #else
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3662470..d2760e0 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6283,9 +6283,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
@@ -6298,13 +6302,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
@@ -6482,9 +6497,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
@@ -32712,7 +32727,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
@@ -33690,6 +33706,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
@@ -35362,6 +35379,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{-}
@@ -35546,6 +35568,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}).
@@ -35840,6 +35866,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
@@ -38644,6 +38679,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 09ff7b2..c7253aa 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5940,11 +5940,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)
     {
@@ -6022,6 +6022,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 = {
@@ -6096,11 +6125,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 146d95f..c601e8d 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -131,6 +131,9 @@ struct vstop_notif
   struct target_waitstatus status;
 };
 
+/* The current btrace configuration.  */
+static struct btrace_config current_btrace_conf;
+
 DEFINE_QUEUE_P (notif_event_p);
 
 /* Put a stop reply to the stop reply queue.  */
@@ -398,15 +401,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.";
 
@@ -460,7 +465,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
@@ -1527,10 +1532,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 },
@@ -1715,6 +1783,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 b9aa00b..4a04aef 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -359,9 +359,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.  */
@@ -373,6 +374,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);
 };
@@ -502,8 +508,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)
@@ -511,6 +517,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 f33a455..5c6d79c 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -181,8 +181,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
@@ -288,7 +288,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.  */
@@ -489,28 +489,31 @@ 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 btrace_target_info *tinfo;
+  struct btrace_tinfo_bts *bts;
   int pid, errcode;
 
   tinfo = xzalloc (sizeof (*tinfo));
   tinfo->ptid = ptid;
 
-  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;
+  bts = &tinfo->variant.bts;
+
+  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;
 
   /* We sample from and to address.  */
-  tinfo->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
+  bts->attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ADDR;
 
-  tinfo->attr.exclude_kernel = 1;
-  tinfo->attr.exclude_hv = 1;
-  tinfo->attr.exclude_idle = 1;
+  bts->attr.exclude_kernel = 1;
+  bts->attr.exclude_hv = 1;
+  bts->attr.exclude_idle = 1;
 
   tinfo->ptr_bits = 0;
 
@@ -519,16 +522,19 @@ linux_enable_btrace (ptid_t ptid)
     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;
 
-  errcode = perf_event_map_buffer (&tinfo->bts, tinfo->file, 0);
+  errcode = perf_event_map_buffer (&bts->bts, bts->file, 0);
   if (errcode == 0)
-    return tinfo;
+    {
+      tinfo->conf.format = BTRACE_FORMAT_BTS;
+      return tinfo;
+    }
 
   /* We were not able to allocate any buffer.  */
-  close (tinfo->file);
+  close (bts->file);
 
  err:
   xfree (tinfo);
@@ -537,8 +543,29 @@ 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)
 {
   int errcode;
 
@@ -547,11 +574,34 @@ linux_disable_btrace (struct btrace_target_info *tinfo)
     return BTRACE_ERR_UNKNOWN;
 
   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.  */
 
@@ -566,7 +616,7 @@ linux_read_bts (struct btrace_data_bts *btrace,
   unsigned long data_head, data_tail, retries = 5;
   size_t buffer_size, size;
 
-  pevent = &tinfo->bts;
+  pevent = &tinfo->variant.bts.bts;
 
   /* For delta reads, we return at least the partial last block containing
      the current PC.  */
@@ -650,11 +700,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);
+      return linux_read_bts (&btrace->variant.bts, tinfo, type);
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
+
+/* See linux-btrace.h.  */
+
+const struct btrace_config *
+linux_btrace_conf (const struct btrace_target_info *tinfo)
+{
+  return &tinfo->conf;
 }
 
 #else /* !HAVE_LINUX_PERF_EVENT_H */
@@ -670,7 +737,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;
 }
@@ -693,4 +760,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 5af3f87..8ceeabf 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -47,23 +47,37 @@ struct perf_event_buffer
   /* The data_head value from the last read.  */
   unsigned long data_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;
 
   /* 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.
@@ -76,7 +90,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);
@@ -86,4 +101,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 9715e8a..fa2d741 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -71,6 +71,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.  */
 
@@ -133,7 +139,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);
@@ -209,7 +215,7 @@ record_btrace_open (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);
       }
@@ -270,6 +276,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;
 
@@ -279,13 +286,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;
@@ -2007,15 +2019,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.  */
@@ -2051,11 +2096,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 aa2db4f..6e93b0c 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -229,6 +229,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;
@@ -1335,6 +1337,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
 };
 
@@ -3931,7 +3936,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;
@@ -4279,6 +4286,8 @@ remote_open_1 (char *name, int from_tty,
       }
   }
 
+  remote_btrace_reset ();
+
   if (target_async_permitted)
     wait_forever_enabled_p = 1;
 }
@@ -8861,6 +8870,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;
     }
@@ -11239,8 +11253,23 @@ struct btrace_target_info
 {
   /* The ptid of the traced thread.  */
   ptid_t ptid;
+
+  /* The obtained branch trace configuration.  */
+  struct btrace_config conf;
 };
 
+/* The target's btrace configuration.  */
+
+static struct btrace_config btrace_target_config;
+
+/* Reset our idea of our target's btrace configuration.  */
+
+static void
+remote_btrace_reset (void)
+{
+  memset (&btrace_target_config, 0, sizeof (btrace_target_config));
+}
+
 /* Check whether the target supports branch tracing.  */
 
 static int
@@ -11263,20 +11292,50 @@ 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)
+{
+  struct cleanup *cleanup;
+  char *xml;
+
+  xml = target_read_stralloc (&current_target,
+                              TARGET_OBJECT_BTRACE_CONF, "");
+  if (xml != NULL)
+    {
+
+      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);
@@ -11296,6 +11355,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;
 }
 
@@ -11392,6 +11459,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)
 {
@@ -11528,6 +11602,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;
 }
@@ -12118,6 +12193,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-delegates.c b/gdb/target-delegates.c
index 0cbd382..f38c9d8 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -1372,14 +1372,14 @@ tdefault_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 ();
 }
@@ -1423,6 +1423,19 @@ tdefault_read_btrace (struct target_ops *self, struct btrace_data *arg1, struct
   tcomplain ();
 }
 
+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 void
 delegate_stop_recording (struct target_ops *self)
 {
@@ -1902,6 +1915,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_save_record == NULL)
@@ -2064,6 +2079,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_save_record = tdefault_save_record;
   ops->to_delete_record = tdefault_delete_record;
diff --git a/gdb/target.c b/gdb/target.c
index 635dde0..42fc04d 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3409,9 +3409,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.  */
@@ -3442,6 +3442,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 cc1a094..40070e5 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -199,7 +199,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, ...  */
 };
 
@@ -988,10 +990,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.  */
@@ -1015,6 +1019,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 ();
@@ -2203,7 +2212,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);
@@ -2216,6 +2226,10 @@ extern enum btrace_error target_read_btrace (struct btrace_data *,
 					     struct btrace_target_info *,
 					     enum btrace_read_type);
 
+/* See to_btrace_conf in struct target_ops.  */
+extern const struct btrace_config *
+  target_btrace_conf (const struct btrace_target_info *);
+
 /* See to_stop_recording in struct target_ops.  */
 extern void target_stop_recording (void);
 
diff --git a/gdb/testsuite/gdb.btrace/delta.exp b/gdb/testsuite/gdb.btrace/delta.exp
index 5c3505c..71ccf07 100644
--- a/gdb/testsuite/gdb.btrace/delta.exp
+++ b/gdb/testsuite/gdb.btrace/delta.exp
@@ -39,6 +39,7 @@ gdb_test_no_output "record btrace"
 with_test_prefix "no trace" {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 0 instructions in 0 functions for .*" \
     ] "\r\n"]
   gdb_test "record instruction-history" "No trace\."
@@ -51,6 +52,7 @@ gdb_test "stepi"
 proc check_trace {} {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 1 instructions in 1 functions for .*" \
     ] "\r\n"]
   gdb_test "record instruction-history /f 1" \
@@ -71,6 +73,7 @@ with_test_prefix "twice" {
 gdb_test "reverse-stepi"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 1 instructions in 1 functions for .*" \
   "Replay in progress\.  At instruction 1\." \
   ] "\r\n"] "reverse-stepi"
@@ -79,5 +82,6 @@ gdb_test "info record" [join [list \
 gdb_test "stepi"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 1 instructions in 1 functions for .*" \
   ] "\r\n"] "and back"
diff --git a/gdb/testsuite/gdb.btrace/enable.exp b/gdb/testsuite/gdb.btrace/enable.exp
index 78c7e53..2926c0f 100644
--- a/gdb/testsuite/gdb.btrace/enable.exp
+++ b/gdb/testsuite/gdb.btrace/enable.exp
@@ -56,7 +56,9 @@ gdb_test "record btrace" "The process is already being recorded\\.  Use \"record
 gdb_test "record full" "The process is already being recorded\\.  Use \"record stop\" to stop recording first\\." "record full cannot be enabled"
 
 # no trace recorded yet
-gdb_test "info record" "Active record target: record-btrace\r\nRecorded 0 instructions in 0 functions for thread 1.*\\." "info record without trace"
+gdb_test "info record" "Active record target: record-btrace\r
+.*\r
+Recorded 0 instructions in 0 functions for thread 1.*\\." "info record without trace"
 
 # stop btrace record
 gdb_test "record stop" "Process record is stopped and all execution logs are deleted\\." "record stop"
diff --git a/gdb/testsuite/gdb.btrace/finish.exp b/gdb/testsuite/gdb.btrace/finish.exp
index a27082e..593055b 100644
--- a/gdb/testsuite/gdb.btrace/finish.exp
+++ b/gdb/testsuite/gdb.btrace/finish.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
diff --git a/gdb/testsuite/gdb.btrace/instruction_history.exp b/gdb/testsuite/gdb.btrace/instruction_history.exp
index 29102c4..5a77357 100644
--- a/gdb/testsuite/gdb.btrace/instruction_history.exp
+++ b/gdb/testsuite/gdb.btrace/instruction_history.exp
@@ -50,7 +50,7 @@ gdb_continue_to_breakpoint "cont to $bp_location" ".*$srcfile2:$bp_location.*"
 set traced {}
 set testname "determine number of recorded instructions"
 gdb_test_multiple "info record" $testname {
-    -re "Active record target: record-btrace\r\nRecorded \(\[0-9\]*\) instructions in \(\[0-9\]*\) functions for thread 1 .*\\.\r\n$gdb_prompt $" {
+    -re "Active record target: record-btrace\r\n.*\r\nRecorded \(\[0-9\]*\) instructions in \(\[0-9\]*\) functions for thread 1 .*\\.\r\n$gdb_prompt $" {
         set traced $expect_out(1,string)
         pass $testname
     }
diff --git a/gdb/testsuite/gdb.btrace/next.exp b/gdb/testsuite/gdb.btrace/next.exp
index b39eb79..1bc8125 100644
--- a/gdb/testsuite/gdb.btrace/next.exp
+++ b/gdb/testsuite/gdb.btrace/next.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -55,6 +56,7 @@ with_test_prefix "reverse-next - 2" { check_replay_at 1 }
 gdb_test "next" ".*main\.3.*"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "next back"
 
diff --git a/gdb/testsuite/gdb.btrace/nexti.exp b/gdb/testsuite/gdb.btrace/nexti.exp
index fd94df6..a263607 100644
--- a/gdb/testsuite/gdb.btrace/nexti.exp
+++ b/gdb/testsuite/gdb.btrace/nexti.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -55,6 +56,7 @@ with_test_prefix "reverse-nexti - 1" { check_replay_at 1 }
 gdb_test "nexti" ".*main\.3.*" "next, 1.5"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "nexti back"
 
diff --git a/gdb/testsuite/gdb.btrace/nohist.exp b/gdb/testsuite/gdb.btrace/nohist.exp
index c0a1a87..4c1d875 100644
--- a/gdb/testsuite/gdb.btrace/nohist.exp
+++ b/gdb/testsuite/gdb.btrace/nohist.exp
@@ -33,6 +33,7 @@ if ![runto_main] {
 proc check_not_replaying {} {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
 	"Recorded 0 instructions in 0 functions for \[^\\\r\\\n\]*" \
     ] "\r\n"]
 }
diff --git a/gdb/testsuite/gdb.btrace/step.exp b/gdb/testsuite/gdb.btrace/step.exp
index 7c34d25..483166b 100644
--- a/gdb/testsuite/gdb.btrace/step.exp
+++ b/gdb/testsuite/gdb.btrace/step.exp
@@ -37,6 +37,7 @@ gdb_test "next"
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -85,5 +86,6 @@ with_test_prefix "step to 39" { check_replay_at 39 }
 gdb_test "step" ".*main\.3.*"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "step to live"
diff --git a/gdb/testsuite/gdb.btrace/stepi.exp b/gdb/testsuite/gdb.btrace/stepi.exp
index fb12e28..cce41e6 100644
--- a/gdb/testsuite/gdb.btrace/stepi.exp
+++ b/gdb/testsuite/gdb.btrace/stepi.exp
@@ -35,6 +35,7 @@ if ![runto_main] {
 proc check_replay_at { insn } {
   gdb_test "info record" [join [list \
     "Active record target: record-btrace" \
+    "Recording format: .*" \
     "Recorded 40 instructions in 16 functions for .*" \
     "Replay in progress\.  At instruction $insn\." \
     ] "\r\n"]
@@ -59,6 +60,7 @@ with_test_prefix "stepi to 40" { check_replay_at 40 }
 gdb_test "stepi" ".*main\.3.*"
 gdb_test "info record" [join [list \
   "Active record target: record-btrace" \
+  "Recording format: .*" \
   "Recorded 40 instructions in 16 functions for \[^\\\r\\\n\]*" \
   ] "\r\n"] "stepi to live"
 
diff --git a/gdb/x86-linux-nat.c b/gdb/x86-linux-nat.c
index 52c2a61..f92f845 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -428,13 +428,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."),
@@ -477,6 +478,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
@@ -551,6 +562,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] 30+ messages in thread

* [PATCH 12/12] [wip] btrace: support Intel(R) Processor Trace
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (4 preceding siblings ...)
  2014-07-14 13:57 ` [PATCH 05/12] record-btrace: add bts buffer size configuration option Markus Metzger
@ 2014-07-14 13:57 ` Markus Metzger
  2014-07-14 13:57 ` [PATCH 10/12] record-btrace: indicate gaps Markus Metzger
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 13:57 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

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

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


2014-07-14  Markus Metzger <markus.t.metzger@intel.com>
---
 gdb/NEWS                     |  10 +
 gdb/btrace.c                 | 486 ++++++++++++++++++++++++++++++++++++++++++-
 gdb/btrace.h                 |  19 ++
 gdb/common/btrace-common.c   |  59 ++++++
 gdb/common/btrace-common.h   |  99 ++++++++-
 gdb/doc/gdb.texinfo          |  50 ++++-
 gdb/features/btrace-conf.dtd |  10 +-
 gdb/features/btrace.dtd      |  18 +-
 gdb/gdbserver/linux-low.c    | 119 ++++++++++-
 gdb/gdbserver/server.c       |  70 ++++++-
 gdb/nat/linux-btrace.c       | 459 +++++++++++++++++++++++++++++++++++++++-
 gdb/nat/linux-btrace.h       |  19 ++
 gdb/record-btrace.c          | 151 ++++++++++++++
 gdb/remote.c                 | 100 ++++++++-
 14 files changed, 1641 insertions(+), 28 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index d8ee284..14a6237 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -9,6 +9,10 @@ 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 options
 
 set|show record btrace bts buffer-size
@@ -17,6 +21,12 @@ 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 remote packets
 
 qXfer:btrace-conf:read
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 517c73a..7639aa4 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.  */
@@ -722,6 +727,245 @@ 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 on the 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 (_("decode error near offset 0x%" PRIx64
+		 " near 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 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, CORE_ADDR pc,
+			    void *ignored)
+{
+  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 trace decoder: %s."),
+	   pt_errstr (pt_errcode (errcode)));
+
+  decoder = pt_insn_alloc_decoder (&config);
+  if (decoder == NULL)
+    error (_("Failed to allocate trace decoder."));
+
+  TRY_CATCH (except, RETURN_MASK_ALL)
+    {
+      errcode = pt_insn_add_callback(decoder, btrace_pt_readmem_callback, NULL);
+      if (errcode < 0)
+	error (_("Failed to configure instruction 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 trace format."));
+}
+
+#endif /* defined (HAVE_LIBIPT)  */
+
 /* Compute the function branch trace from a block branch trace BTRACE for
    a thread given by BTINFO.  */
 
@@ -738,6 +982,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."));
@@ -909,6 +1157,16 @@ btrace_stitch_bts (struct btrace_data_bts *btrace,
   return 0;
 }
 
+/* Stitch branch trace in Intel(R) Processor Trace format.  */
+
+static int
+btrace_stitch_pt (struct btrace_data_pt *btrace,
+		  const struct btrace_thread_info *btinfo)
+{
+  /* 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.
    BTINFO is the old branch trace until the last stop.
@@ -930,6 +1188,9 @@ btrace_stitch_trace (struct btrace_data *btrace,
 
     case BTRACE_FORMAT_BTS:
       return btrace_stitch_bts (&btrace->variant.bts, btinfo);
+
+    case BTRACE_FORMAT_PT:
+      return btrace_stitch_pt (&btrace->variant.pt, btinfo);
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -1075,7 +1336,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);
 }
 
@@ -1115,12 +1376,171 @@ 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 perf-sideband "raw" xml record.  */
+
+static void
+parse_xml_btrace_pt_perf_sideband_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.sideband.variant.perf.data,
+		 &btrace->variant.pt.sideband.variant.perf.size);
+}
+
+/* Parse a btrace pt "perf-sideband" xml record.  */
+
+static void
+parse_xml_btrace_pt_perf_sideband (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->variant.pt.sideband.format = BTRACE_PT_SIDEBAND_PERF;
+  btrace->variant.pt.sideband.variant.perf.data = NULL;
+  btrace->variant.pt.sideband.variant.perf.size = 0;
+}
+
+/* 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;
+  btrace->variant.pt.sideband.format = BTRACE_PT_SIDEBAND_NONE;
+}
+
 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_perf_sideband_children[] = {
+  { "raw", NULL, NULL, GDB_XML_EF_OPTIONAL, NULL,
+    parse_xml_btrace_pt_perf_sideband_raw },
+  { 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 },
+  { "perf-sideband", NULL, btrace_pt_perf_sideband_children,
+    GDB_XML_EF_OPTIONAL, parse_xml_btrace_pt_perf_sideband, NULL },
+  { 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 }
@@ -1129,6 +1549,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 }
 };
 
@@ -1186,9 +1608,67 @@ 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 "perf-sideband" xml record.  */
+
+static void
+parse_xml_btrace_conf_perf_sideband (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->pt.sideband.format = BTRACE_PT_SIDEBAND_PERF;
+  conf->pt.sideband.perf.size = 0;
+
+  size = xml_find_attribute (attributes, "size");
+  if (size != NULL)
+    conf->pt.sideband.perf.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;
+  /* We initialize the sideband format to 'no sideband'.  This will be
+     overwritten by sideband elements.  */
+  conf->pt.sideband.format = BTRACE_PT_SIDEBAND_NONE;
+  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_perf_sideband_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_pt_children[] = {
+  { "perf-sideband", btrace_conf_perf_sideband_attributes, NULL,
+    GDB_XML_EF_OPTIONAL, parse_xml_btrace_conf_perf_sideband, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+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 }
@@ -1197,6 +1677,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, btrace_conf_pt_children,
+    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 7b524fa..b0ccb2c 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 178ad35..c12df95 100644
--- a/gdb/common/btrace-common.c
+++ b/gdb/common/btrace-common.c
@@ -66,6 +66,7 @@ btrace_format_string (enum btrace_format format)
     {
     case BTRACE_FORMAT_NONE: return "No or unknown 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"));
@@ -73,12 +74,44 @@ btrace_format_string (enum btrace_format format)
 
 /* See btrace-common.h.  */
 
+const char *
+btrace_pt_sideband_format_string (enum btrace_pt_sideband_format format)
+{
+  switch (format)
+    {
+    case BTRACE_PT_SIDEBAND_NONE: return "none";
+    case BTRACE_PT_SIDEBAND_PERF: return "perf";
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unknown sideband format"));
+}
+
+/* See btrace-common.h.  */
+
 void
 btrace_data_init (struct btrace_data *data)
 {
   data->format = BTRACE_FORMAT_NONE;
 }
 
+/* Destroy sideband data.  */
+
+static void
+btrace_data_pt_sideband_fini (struct btrace_data_pt_sideband *sideband)
+{
+  switch (sideband->format)
+    {
+    case BTRACE_PT_SIDEBAND_NONE:
+      return;
+
+    case BTRACE_PT_SIDEBAND_PERF:
+      xfree (sideband->variant.perf.data);
+      return;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unknown sideband format"));
+}
+
 /* See btrace-common.h.  */
 
 void
@@ -93,11 +126,33 @@ 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);
+      btrace_data_pt_sideband_fini (&data->variant.pt.sideband);
+      return;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
 }
 
+/* Return non-zero if SIDEBAND is empty; zero otherwise.  */
+
+static int
+btrace_data_pt_sideband_empty (struct btrace_data_pt_sideband *sideband)
+{
+  switch (sideband->format)
+    {
+    case BTRACE_PT_SIDEBAND_NONE:
+      return 1;
+
+    case BTRACE_PT_SIDEBAND_PERF:
+      return sideband->variant.perf.size == 0;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unknown sideband format"));
+}
+
 /* See btrace-common.h.  */
 
 int
@@ -110,6 +165,10 @@ 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
+	      && btrace_data_pt_sideband_empty (&data->variant.pt.sideband));
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index 5fa9806..7717b8f 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -36,7 +36,21 @@ 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
+};
+
+/* Enumeration of Intel Processor Trace sideband formats.  */
+
+enum btrace_pt_sideband_format
+{
+  /* No sideband information.  */
+  BTRACE_PT_SIDEBAND_NONE,
+
+  /* Linux perf-event sideband information.  */
+  BTRACE_PT_SIDEBAND_PERF
 };
 
 /* Target specific branch trace information.  */
@@ -110,6 +124,36 @@ struct btrace_config_bts
   unsigned int size;
 };
 
+/* A PERF sideband configuration.  */
+
+struct btrace_config_pt_perf
+{
+  /* The size of the sideband buffer in bytes.  */
+  unsigned int size;
+};
+
+/* An Intel Processor Trace sideband configuration.  */
+
+struct btrace_config_pt_sideband
+{
+  /* The sideband format.  */
+  enum btrace_pt_sideband_format format;
+
+  /* The configuration for perf sideband data.  */
+  struct btrace_config_pt_perf perf;
+};
+
+/* An Intel Processor Trace configuration.  */
+
+struct btrace_config_pt
+{
+  /* The size of the branch trace buffer in bytes.  */
+  unsigned int size;
+
+  /* The sideband configuration.  */
+  struct btrace_config_pt_sideband sideband;
+};
+
 /* A branch tracing configuration.
 
    This describes the requested configuration as well as the actually
@@ -124,6 +168,9 @@ struct btrace_config
 
   /* The BTS format configuration.  */
   struct btrace_config_bts bts;
+
+  /* The Intel Processor Trace format configuration.  */
+  struct btrace_config_pt pt;
 };
 
 #ifdef GDBSERVER
@@ -163,6 +210,49 @@ 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;
+};
+
+/* Intel Processor Trace sideband data.  */
+struct btrace_data_pt_sideband
+{
+  /* The sideband format.  */
+  enum btrace_pt_sideband_format format;
+
+  union
+  {
+    /* Format == BTRACE_PT_SIDEBAND_PERF.  */
+    struct
+    {
+      /* The sideband data.  */
+      gdb_byte *data;
+
+      /* The size of DATA in bytes.  */
+      unsigned long size;
+    } perf;
+  } variant;
+};
+
+/* 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 sideband data.  */
+  struct btrace_data_pt_sideband sideband;
+};
+
 /* The branch trace data.  */
 struct btrace_data
 {
@@ -172,6 +262,9 @@ struct btrace_data
   {
     /* Format == BTRACE_FORMAT_BTS.  */
     struct btrace_data_bts bts;
+
+    /* Format == BTRACE_FORMAT_PT.  */
+    struct btrace_data_pt pt;
   } variant;
 };
 
@@ -181,6 +274,10 @@ extern struct btrace_cpu btrace_this_cpu (void);
 /* Return a string representation of FORMAT.  */
 extern const char *btrace_format_string (enum btrace_format format);
 
+/* Return a string representation of FORMAT.  */
+extern const char *
+  btrace_pt_sideband_format_string (enum btrace_pt_sideband_format format);
+
 /* Initialize DATA.  */
 extern void btrace_data_init (struct btrace_data *data);
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e27233a..35a4244 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6284,12 +6284,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
@@ -6317,6 +6321,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.
@@ -6327,9 +6345,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
@@ -6494,6 +6509,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
@@ -6539,6 +6577,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
diff --git a/gdb/features/btrace-conf.dtd b/gdb/features/btrace-conf.dtd
index 9a865d4..b8d1744 100644
--- a/gdb/features/btrace-conf.dtd
+++ b/gdb/features/btrace-conf.dtd
@@ -4,8 +4,14 @@
      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.1">
+<!ELEMENT btrace-conf	(bts?, pt?)>
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.2">
 
 <!ELEMENT bts	EMPTY>
 <!ATTLIST bts	size	CDATA	#IMPLIED>
+
+<!ELEMENT pt	(perf-sideband?)>
+<!ATTLIST pt	size	CDATA	#IMPLIED>
+
+<!ELEMENT perf-sideband	EMPTY>
+<!ATTLIST perf-sideband	size	CDATA	#IMPLIED>
diff --git a/gdb/features/btrace.dtd b/gdb/features/btrace.dtd
index a3193b0..ae93845 100644
--- a/gdb/features/btrace.dtd
+++ b/gdb/features/btrace.dtd
@@ -4,9 +4,23 @@
      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?, perf-sideband?)>
+
+<!ELEMENT pt-config (cpu?)>
+
+<!ELEMENT cpu EMPTY>
+<!ATTLIST cpu vendor   CDATA #REQUIRED
+              family   CDATA #REQUIRED
+              model    CDATA #REQUIRED
+              stepping CDATA #REQUIRED>
+
+<!ELEMENT perf-sideband (raw?)>
+
+<!ELEMENT raw (#PCDATA)>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index d68e730..53e29bf 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"
@@ -5968,6 +5969,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
@@ -5989,15 +6039,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");
@@ -6012,15 +6061,50 @@ 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);
+
+      linux_low_encode_raw (buffer, btrace.variant.pt.data,
+			    btrace.variant.pt.size);
+
+      switch (btrace.variant.pt.sideband.format)
+	{
+	case BTRACE_PT_SIDEBAND_NONE:
+	  break;
+
+	case BTRACE_PT_SIDEBAND_PERF:
+	  buffer_grow_str (buffer, "<perf-sideband>\n");
+	  linux_low_encode_raw (buffer,
+				btrace.variant.pt.sideband.variant.perf.data,
+				btrace.variant.pt.sideband.variant.perf.size);
+	  buffer_grow_str (buffer, "</perf-sideband>\n");
+	  break;
+
+	default:
+	  buffer_free (buffer);
+	  buffer_grow_str0 (buffer, "E.Unsupported sideband format.");
+	  goto err;
+	}
+
+      buffer_grow_str (buffer, "</pt>\n");
+      buffer_grow_str0 (buffer, "</btrace>\n");
+      break;
 
-      btrace_data_fini (&btrace);
-      return -1;
+    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.  */
@@ -6047,6 +6131,27 @@ 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");
+
+	  switch (conf->pt.sideband.format)
+	    {
+	    default:
+	      break;
+
+	    case BTRACE_PT_SIDEBAND_PERF:
+	      buffer_xml_printf (buffer, "<perf-sideband");
+	      buffer_xml_printf (buffer, " size=\"0x%x\"",
+				 conf->pt.sideband.perf.size);
+	      buffer_xml_printf (buffer, "/>\n");
+	      break;
+	    }
+
+	  buffer_xml_printf (buffer, "</pt>\n");
+	  break;
 	}
     }
 
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 1994c8c..88cf0a6 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -418,6 +418,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 *
@@ -466,10 +483,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);
@@ -521,6 +540,37 @@ 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 if (strncmp (op, "pt:perf-sideband:size=",
+		    strlen ("pt:perf-sideband:size=")) == 0)
+    {
+      unsigned long size;
+      char *endp = NULL;
+
+      errno = 0;
+      size = strtoul (op + strlen ("pt:perf-sideband: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.sideband.perf.size = (unsigned int) size;
+    }
   else
     {
       strcpy (own_buf, "E.Bad Qbtrace configuration option.");
@@ -1831,12 +1881,26 @@ 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 (own_buf, ";Qbtrace-conf:bts:size+");
+      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+");
+      strcat (buf, ";Qbtrace-conf:pt:perf-sideband: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 b52106e..67c4fad 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -166,6 +166,123 @@ perf_event_new_data (const struct perf_event_buffer *pev)
   return header->data_head != pev->data_head;
 }
 
+/* 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 = perf_event_buffer_size (pev);
+  begin = perf_event_buffer_begin (pev);
+  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)
+{
+  volatile struct perf_event_mmap_page *header;
+  unsigned long data_head, size;
+
+  header = perf_event_header (pev);
+  data_head = header->data_head;
+
+  size = perf_event_buffer_size (pev);
+  if (data_head < size)
+    size = data_head;
+
+  *data = perf_event_read (pev, data_head, size);
+  *psize = size;
+
+  pev->data_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)
+{
+  volatile struct perf_event_mmap_page *header;
+  unsigned long data_head, data_tail, size, buffer_size;
+
+  header = perf_event_header (pev);
+  data_head = header->data_head;
+  data_tail = pev->data_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 = perf_event_buffer_size (pev);
+  size = data_head - data_tail;
+  if (buffer_size < size)
+    return BTRACE_ERR_OVERFLOW;
+
+  *data = perf_event_read (pev, data_head, size);
+  *psize = size;
+
+  pev->data_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;
+}
+
 /* Check whether an address is in the kernel.  */
 
 static inline int
@@ -401,6 +518,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
@@ -471,6 +675,28 @@ 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;
+
+#ifndef PERF_FLAG_FD_ITRACE
+  return 0;
+#endif
+
+  if (cached == 0)
+    {
+      if (!kernel_supports_pt ())
+	cached = -1;
+      else
+	cached = 1;
+    }
+
+  return cached > 0;
+}
+
 /* See linux-btrace.h.  */
 
 int
@@ -483,6 +709,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"));
@@ -525,13 +754,13 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
   pages = (unsigned int) (((ULONGEST) conf->size + PAGE_SIZE - 1) / PAGE_SIZE);
   if (pages == 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;
 
   errcode = perf_event_map_buffer (&bts->bts, bts->file, 0, pages);
   if (errcode == 0)
@@ -544,11 +773,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;
+}
+
+/* Enable branch tracing in Intel Processor Trace format.  */
+
+#if defined(PERF_FLAG_FD_ITRACE)
+
+static struct btrace_target_info *
+linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
+{
+  struct btrace_target_info *tinfo;
+  struct btrace_tinfo_pt *pt;
+  unsigned int pt_pages, sb_pages;
+  int pid, errcode, type;
+
+  pt_pages = (conf->size + PAGE_SIZE - 1) / PAGE_SIZE;
+  /* We do require a trace buffer, we're OK without a sideband buffer.  */
+  if (pt_pages == 0)
+    return NULL;
+
+  switch (conf->sideband.format)
+    {
+    case BTRACE_PT_SIDEBAND_PERF:
+      sb_pages = (conf->sideband.perf.size + PAGE_SIZE - 1) / PAGE_SIZE;
+      break;
+
+    default:
+      sb_pages = 0;
+      break;
+    }
+
+  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;
+
+  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;
+
+  tinfo->ptr_bits = 0;
+
+  errno = 0;
+  pt->sb_file = syscall (SYS_perf_event_open, &pt->attr, pid, -1, -1, 0);
+  if (pt->sb_file < 0)
+    goto err;
+
+  pt->pt_file = syscall (SYS_perf_event_open, NULL, -1, -1, pt->sb_file,
+			 PERF_FLAG_FD_ITRACE);
+  if (pt->sb_file < 0)
+    goto err_pt_file;
+
+  errcode = perf_event_map_buffer (&pt->pt, pt->pt_file, 0, pt_pages);
+  if (errcode != 0)
+    goto err_sb_file;
+
+  tinfo->conf.format = BTRACE_FORMAT_PT;
+  tinfo->conf.pt.size = pt->pt.size * PAGE_SIZE;
+
+  if (sb_pages == 0)
+      tinfo->conf.pt.sideband.format = BTRACE_PT_SIDEBAND_NONE;
+  else
+    {
+      errcode = perf_event_map_buffer (&pt->sideband, pt->sb_file, 0, sb_pages);
+      if (errcode != 0)
+	goto err_mmap;
+
+      tinfo->conf.pt.sideband.format = BTRACE_PT_SIDEBAND_PERF;
+      tinfo->conf.pt.sideband.perf.size = pt->sideband.size * PAGE_SIZE;
+    }
+
+  return tinfo;
+
+ err_mmap:
+  perf_event_unmap_buffer (&pt->pt);
+
+ err_pt_file:
+  close (pt->pt_file);
+
+ err_sb_file:
+  close (pt->sb_file);
+
  err:
   xfree (tinfo);
   return NULL;
 }
 
+#else /* defined(PERF_FLAG_FD_ITRACE) */
+
+static struct btrace_target_info *
+linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
+{
+  return NULL;
+}
+
+#endif /* defined(PERF_FLAG_FD_ITRACE) */
+
 /* See linux-btrace.h.  */
 
 struct btrace_target_info *
@@ -565,6 +899,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;
@@ -586,6 +924,25 @@ 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)
+{
+  int errcode;
+
+  errcode = perf_event_unmap_buffer (&tinfo->pt);
+  if (errcode != 0)
+    return BTRACE_ERR_UNKNOWN;
+
+  (void) perf_event_unmap_buffer (&tinfo->sideband);
+
+  close (tinfo->pt_file);
+  close (tinfo->sb_file);
+
+  return BTRACE_ERR_NONE;
+}
+
 /* See linux-btrace.h.  */
 
 enum btrace_error
@@ -602,6 +959,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)
@@ -701,6 +1062,92 @@ 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, *sideband;
+  enum btrace_error errcode;
+
+  pt = &tinfo->variant.pt.pt;
+
+  linux_fill_btrace_pt_config (&btrace->config);
+
+  switch (tinfo->conf.pt.sideband.format)
+    {
+    case BTRACE_PT_SIDEBAND_PERF:
+      sideband = &tinfo->variant.pt.sideband;
+      break;
+
+    case BTRACE_PT_SIDEBAND_NONE:
+      sideband = NULL;
+      break;
+
+    default:
+      return BTRACE_ERR_NOT_SUPPORTED;
+    }
+
+  switch (type)
+    {
+    case BTRACE_READ_DELTA:
+      errcode = perf_event_read_new (pt, &btrace->data, &btrace->size);
+      if (errcode != BTRACE_ERR_NONE)
+	return errcode;
+
+      if (sideband != NULL)
+	{
+	  btrace->sideband.format = BTRACE_PT_SIDEBAND_PERF;
+	  errcode = perf_event_read_new (sideband,
+					 &btrace->sideband.variant.perf.data,
+					 &btrace->sideband.variant.perf.size);
+
+	  /* If we run into any errors when reading sideband information, we
+	     fall back to a full read.
+	     We will still be able to stitch traces since the trace buffer did
+	     not overflow.  */
+	  if (errcode != BTRACE_ERR_NONE)
+	    perf_event_read_all (sideband,
+				 &btrace->sideband.variant.perf.data,
+				 &btrace->sideband.variant.perf.size);
+	}
+
+      return BTRACE_ERR_NONE;
+
+    case BTRACE_READ_NEW:
+      if (!perf_event_new_data (pt)
+	  && (sideband == NULL || !perf_event_new_data (sideband)))
+	return BTRACE_ERR_NONE;
+
+      /* Fall through.  */
+    case BTRACE_READ_ALL:
+      perf_event_read_all (pt, &btrace->data, &btrace->size);
+
+      if (sideband != NULL)
+	{
+	  btrace->sideband.format = BTRACE_PT_SIDEBAND_PERF;
+	  perf_event_read_all (sideband,
+			       &btrace->sideband.variant.perf.data,
+			       &btrace->sideband.variant.perf.size);
+	}
+
+      return BTRACE_ERR_NONE;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown btrace read type."));
+}
+
 /* See linux-btrace.h.  */
 
 enum btrace_error
@@ -719,6 +1166,14 @@ 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;
+      btrace->variant.pt.sideband.format = BTRACE_PT_SIDEBAND_NONE;
+
+      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 8ceeabf..b4d7ab8 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -60,6 +60,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 trace and sideband files.  */
+  int pt_file, sb_file;
+
+  /* The trace perf event buffer.  */
+  struct perf_event_buffer pt;
+
+  /* The sideband perf event buffer.  */
+  struct perf_event_buffer sideband;
+};
 #endif /* HAVE_LINUX_PERF_EVENT_H */
 
 /* Branch trace target information per thread.  */
@@ -77,6 +93,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 418bb92..4c3b443 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -85,6 +85,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.  */
 
@@ -322,6 +326,42 @@ 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)
+{
+  enum btrace_pt_sideband_format format;
+  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);
+    }
+
+  format = conf->sideband.format;
+  switch (format)
+    {
+    case BTRACE_PT_SIDEBAND_PERF:
+      printf_unfiltered (_("Sideband format: %s.\n"),
+			 btrace_pt_sideband_format_string (format));
+
+      size = conf->sideband.perf.size;
+      if (size > 0)
+	{
+	  suffix = record_btrace_adjust_size (&size);
+	  printf_unfiltered (_("Sideband buffer size: %u%s.\n"), size, suffix);
+	}
+      break;
+
+    default:
+      break;
+    }
+}
+
 /* Print a branch tracing configuration.  */
 
 static void
@@ -338,6 +378,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."));
@@ -429,6 +473,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, _("["));
@@ -2209,6 +2280,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
@@ -2219,6 +2312,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)
@@ -2276,6 +2377,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.  */
@@ -2296,6 +2416,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);
@@ -2340,6 +2467,27 @@ to see the actual buffer size."), 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);
 
@@ -2347,4 +2495,7 @@ to see the actual buffer size."), NULL, NULL,
 			       xcalloc, xfree);
 
   record_btrace_conf.bts.size = 64 * 1024;
+
+  record_btrace_conf.pt.size = 16 * 1024;
+  record_btrace_conf.pt.sideband.format = BTRACE_PT_SIDEBAND_NONE;
 }
diff --git a/gdb/remote.c b/gdb/remote.c
index 60e4e0e..1dcfa08 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1315,6 +1315,7 @@ enum {
   PACKET_QTBuffer_size,
   PACKET_Qbtrace_off,
   PACKET_Qbtrace_bts,
+  PACKET_Qbtrace_pt,
   PACKET_qXfer_btrace,
 
   /* Support for the QNonStop packet.  */
@@ -1343,6 +1344,12 @@ 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,
+
+  /* Support for the Qbtrace-conf:pt:perf-sideband:size packet.  */
+  PACKET_Qbtrace_conf_pt_perf_size,
+
   PACKET_MAX
 };
 
@@ -3938,12 +3945,17 @@ 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 },
+  { "Qbtrace-conf:pt:perf-sideband:size", PACKET_DISABLE,
+    remote_supported_packet, PACKET_Qbtrace_conf_pt_perf_size }
 };
 
 static char *remote_support_xml;
@@ -11292,6 +11304,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"));
@@ -11330,6 +11351,52 @@ static void btrace_sync_conf (const struct btrace_config *conf)
 
       btrace_target_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 != btrace_target_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."));
+	}
+
+      btrace_target_config.pt.size = conf->pt.size;
+    }
+
+  packet = &remote_protocol_packets[PACKET_Qbtrace_conf_pt_perf_size];
+  if (packet_config_support (packet) == PACKET_ENABLE
+      && (conf->pt.sideband.perf.size
+	  != btrace_target_config.pt.sideband.perf.size))
+    {
+      pos = buf;
+      pos += xsnprintf (pos, endbuf - pos, "%s=0x%x", packet->name,
+			conf->pt.sideband.perf.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 sideband buffer "
+		     "size: %s"), buf + 2);
+	  else
+	    error (_("Failed to configure the sideband buffer size."));
+	}
+
+      btrace_target_config.pt.sideband.perf.size = conf->pt.sideband.perf.size;
+    }
 }
 
 /* Read the current thread's btrace configuration from the target and
@@ -11341,7 +11408,7 @@ static void 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)
     {
 
@@ -11358,13 +11425,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);
@@ -11481,7 +11559,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;
 
@@ -12221,7 +12299,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);
@@ -12232,6 +12313,13 @@ 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);
+
+  add_packet_config_cmd (
+       &remote_protocol_packets[PACKET_Qbtrace_conf_pt_perf_size],
+       "Qbtrace-conf:pt:perf-sideband:size", "btrace-conf-pt-perf-size", 0);
+
   /* Assert that we've registered commands for all packet configs.  */
   {
     int i;
-- 
1.8.3.1

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

* [PATCH 01/12] btrace: add struct btrace_data
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (10 preceding siblings ...)
  2014-07-14 13:57 ` [PATCH 03/12] btrace, linux: add perf event buffer abstraction Markus Metzger
@ 2014-07-14 14:48 ` Markus Metzger
  2014-11-05 20:44   ` Pedro Alves
  2014-10-28 14:35 ` [PATCH 00/12] record btrace: prepare for a new trace format Metzger, Markus T
  12 siblings, 1 reply; 30+ messages in thread
From: Markus Metzger @ 2014-07-14 14:48 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.

2014-07-14  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 (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.
	* common/linux-btrace.c (linux_read_btrace): Split into this and...
	(linux_read_bts): ...this.
	* common/linux-btrace.h (linux_read_btrace): Update parameters.
	* 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.
	* amd64-linux-nat.c (amd64_linux_read_btrace): Update parameters.
	* i386-linux-nat.c (i386_linux_read_btrace): Update parameters.
	* target-delegates.c: Regenerate.

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            |   9 ++-
 gdb/btrace.c               | 155 +++++++++++++++++++++++++++++++++------------
 gdb/btrace.h               |   6 +-
 gdb/common/btrace-common.c |  79 +++++++++++++++++++++++
 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-delegates.c     |   4 +-
 gdb/target.c               |   2 +-
 gdb/target.h               |   8 +--
 gdb/x86-linux-nat.c        |   2 +-
 14 files changed, 318 insertions(+), 83 deletions(-)
 create mode 100644 gdb/common/btrace-common.c

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ce15501..349fca9 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -850,7 +850,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
 	common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.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
+	target/waitstatus.c common/print-utils.c common/rsp-low.c \
+	common/btrace-common.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -1034,7 +1035,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	gdb_vecs.o jit.o progspace.o skip.o probe.o \
 	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
+	print-utils.o rsp-low.o btrace-common.o
 
 TSOBS = inflow.o
 
@@ -2144,6 +2145,10 @@ rsp-low.o: ${srcdir}/common/rsp-low.c
 	$(COMPILE) $(srcdir)/common/rsp-low.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 87a171e..567cc8c 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,31 @@ 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."));
+      return;
+    }
 
   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 +1081,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 +1105,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 +1581,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 f83a80f..3954581 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..90774a2
--- /dev/null
+++ b/gdb/common/btrace-common.c
@@ -0,0 +1,79 @@
+/* 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 "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 25617bb..d5f013c 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -51,13 +51,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;
 
@@ -93,4 +122,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 f9a2f17..c00585f 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -169,7 +169,7 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/buffer.c $(srcdir)/nat/linux-btrace.c \
 	$(srcdir)/common/filestuff.c $(srcdir)/target/waitstatus.c \
 	$(srcdir)/nat/mips-linux-watch.c $(srcdir)/common/print-utils.c \
-	$(srcdir)/common/rsp-low.c
+	$(srcdir)/common/rsp-low.c $(srcdir)/common/btrace-common.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -182,7 +182,8 @@ OBS = agent.o ax.o inferiors.o regcache.o remote-utils.o server.o signals.o \
       target.o waitstatus.o utils.o debug.o version.o vec.o gdb_vecs.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 $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
+      tdesc.o print-utils.o rsp-low.o btrace-common.o $(XML_BUILTIN) \
+      $(DEPFILES) $(LIBOBJS)
 GDBREPLAY_OBS = gdbreplay.o version.o
 GDBSERVER_LIBS = @GDBSERVER_LIBS@
 XM_CLIBS = @LIBS@
@@ -545,6 +546,9 @@ linux-btrace.o: ../nat/linux-btrace.c
 linux-osdata.o: ../nat/linux-osdata.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
+btrace-common.o: ../common/btrace-common.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
 linux-procfs.o: ../nat/linux-procfs.c
 	$(COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 215a80c..09ff7b2 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -106,6 +106,7 @@
 
 #ifdef HAVE_LINUX_BTRACE
 # include "nat/linux-btrace.h"
+# include "btrace-common.h"
 #endif
 
 #ifndef HAVE_ELF32_AUXV_T
@@ -5973,12 +5974,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)
     {
@@ -5987,20 +5989,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 188220b..7ec5815 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -509,12 +509,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;
@@ -536,7 +537,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)
 	{
@@ -573,7 +574,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
@@ -589,12 +590,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.  */
@@ -624,7 +640,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 12e9b60..5d713f4 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -71,7 +71,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 76efefa..1a390b9 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -11339,7 +11339,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)
 {
@@ -11379,7 +11379,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-delegates.c b/gdb/target-delegates.c
index a92c46a..5971ec2 100644
--- a/gdb/target-delegates.c
+++ b/gdb/target-delegates.c
@@ -1411,14 +1411,14 @@ tdefault_teardown_btrace (struct target_ops *self, struct btrace_target_info *ar
 }
 
 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 ();
 }
diff --git a/gdb/target.c b/gdb/target.c
index c9c5e4b..52858a9 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -3425,7 +3425,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 8bf160c..8b0282f 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1008,11 +1008,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 ());
@@ -2215,7 +2213,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 7527370..52c2a61 100644
--- a/gdb/x86-linux-nat.c
+++ b/gdb/x86-linux-nat.c
@@ -471,7 +471,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] 30+ messages in thread

* Re: [PATCH 04/12] record btrace: add configuration struct
  2014-07-14 13:57 ` [PATCH 04/12] record btrace: add configuration struct Markus Metzger
@ 2014-07-14 15:06   ` Eli Zaretskii
  2014-11-05 20:45   ` Pedro Alves
  1 sibling, 0 replies; 30+ messages in thread
From: Eli Zaretskii @ 2014-07-14 15:06 UTC (permalink / raw)
  To: Markus Metzger; +Cc: palves, gdb-patches

> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, Eli Zaretskii <eliz@gnu.org>
> Date: Mon, 14 Jul 2014 15:56:28 +0200
> 
> 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.

Thanks.

> diff --git a/gdb/NEWS b/gdb/NEWS
> index d9a19ae..f32d1ef 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,17 @@
>  
>  *** Changes since GDB 7.8
>  
> +* New commands (for set/show, see "New options" below)
> +
> +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.8

This part is OK.

> +@table @code
> +@item bts
> +Use Intel's Branch Trace Store (BTS) recording format.  In this format,

Suggest to put "Branch Trace Store" in @dfn and "BTS" in @acronym,
this will look better in print.

Also, there should be @cindex entries for these 2 terms.

The documentation parts are OK with those changes.

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

* Re: [PATCH 05/12] record-btrace: add bts buffer size configuration option
  2014-07-14 13:57 ` [PATCH 05/12] record-btrace: add bts buffer size configuration option Markus Metzger
@ 2014-07-14 15:44   ` Eli Zaretskii
  2014-11-05 20:46   ` Pedro Alves
  1 sibling, 0 replies; 30+ messages in thread
From: Eli Zaretskii @ 2014-07-14 15:44 UTC (permalink / raw)
  To: Markus Metzger; +Cc: palves, gdb-patches

> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org, Eli Zaretskii <eliz@gnu.org>
> Date: Mon, 14 Jul 2014 15:56:29 +0200
> 
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -9,11 +9,27 @@ record btrace bts
>  record bts
>    Start branch trace recording using Intel(R) Branch Trace Store format.
>  
> +* New options
> +
> +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.

This hints that the "show" command only shows the requested size, is
that right?  If so, I suggest to tell that explcitly, or maybe delete
the last 2 sentences from NEWS and leave them for the manual.

> +@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 SIZE is optional, it should be in brackets [...].

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

By "thread" you mean threads in the inferior, is that right?  If so,
"uses" is not really accurate, since it's not the thread that is
recording the branch trace, is it?

> +If @var{limit} is @code{unlimited} or zero, @value{GDBN} will try to
> +allocate a buffer of 4MB.

I wonder whether we should advertise the size of "unlimited" here.
What if we would like to change it, or if some architecture requires a
different maximum?

I also wonder what kind of "unlimited" is it.  In general, when I ask
for "unlimited", I expect the value to be limited only by the amount
of available virtual memory; 4MB sounds too few to fit my intuitive
notion of "unlimited".  What are the reason for such a small upper
bound?

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

"errtext" is not literal text, it stands for some meaningful error
message, right?  If so, please use @var{errtext}.

> @@ -38688,7 +38747,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.

Please add a cross-reference here to the section which describes BTS.

The documentation parts are OK with these fixed.

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

* RE: [PATCH 00/12] record btrace: prepare for a new trace format
  2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
                   ` (11 preceding siblings ...)
  2014-07-14 14:48 ` [PATCH 01/12] btrace: add struct btrace_data Markus Metzger
@ 2014-10-28 14:35 ` Metzger, Markus T
  2014-11-05 20:50   ` Pedro Alves
  12 siblings, 1 reply; 30+ messages in thread
From: Metzger, Markus T @ 2014-10-28 14:35 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Hello Pedro, Maintainers,

Any feedback to this series?

Here are links to the original emails:
https://sourceware.org/ml/gdb-patches/2014-07/msg00322.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00334.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00324.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00329.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00330.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00333.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00325.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00328.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00326.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00323.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00331.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00327.html
https://sourceware.org/ml/gdb-patches/2014-07/msg00332.html

The patches don't apply anymore.  I can send an updated patch
series if that's requested.  There are no changes besides resolving
merge conflicts except for:

The kernel interface changed meanwhile which affects:
    btrace, linux: add perf event buffer abstraction
    [wip] btrace: support Intel(R) Processor Trace

I have updates for those, as well, if someone wants to try out the
patches together with an experimental kernel.

Thanks,
Markus.

> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] On Behalf Of Markus Metzger
> Sent: Monday, July 14, 2014 3:56 PM
> To: palves@redhat.com
> Cc: gdb-patches@sourceware.org
> Subject: [PATCH 00/12] record btrace: prepare for a new trace format
> 
> 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
> 
> 
> 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 not
> part
> of the series under review.
> 
> 
> Markus Metzger (12):
>   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
>   btrace: use the new cpu identifier
>   record-btrace: indicate gaps
>   configure: check for libipt
>   [wip] btrace: support Intel(R) Processor Trace
> 
>  gdb/Makefile.in                                  |  16 +-
>  gdb/NEWS                                         |  37 +
>  gdb/btrace.c                                     | 965 ++++++++++++++++++++---
>  gdb/btrace.h                                     |  98 ++-
>  gdb/common/btrace-common.c                       | 175 ++++
>  gdb/common/btrace-common.h                       | 242 +++++-
>  gdb/config.in                                    |   3 +
>  gdb/configure                                    | 498 ++++++++++++
>  gdb/configure.ac                                 |  20 +
>  gdb/doc/gdb.texinfo                              | 189 ++++-
>  gdb/features/btrace-conf.dtd                     |  17 +
>  gdb/features/btrace.dtd                          |  18 +-
>  gdb/gdbserver/Makefile.in                        |   8 +-
>  gdb/gdbserver/linux-low.c                        | 181 ++++-
>  gdb/gdbserver/server.c                           | 228 +++++-
>  gdb/gdbserver/target.h                           |  27 +-
>  gdb/nat/linux-btrace.c                           | 806 ++++++++++++++++---
>  gdb/nat/linux-btrace.h                           |  79 +-
>  gdb/record-btrace.c                              | 497 +++++++++++-
>  gdb/remote.c                                     | 233 +++++-
>  gdb/target-delegates.c                           |  32 +-
>  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/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                              |  18 +-
>  34 files changed, 4143 insertions(+), 408 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

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] 30+ messages in thread

* Re: [PATCH 01/12] btrace: add struct btrace_data
  2014-07-14 14:48 ` [PATCH 01/12] btrace: add struct btrace_data Markus Metzger
@ 2014-11-05 20:44   ` Pedro Alves
  0 siblings, 0 replies; 30+ messages in thread
From: Pedro Alves @ 2014-11-05 20:44 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

Hi Markus,

On 07/14/2014 02:56 PM, Markus Metzger wrote:
> +    default:
> +      gdb_xml_error (parser, _("Btrace format error."));
> +      return;
> +    }

gdb_xml_error throws, so the return is dead.

On 07/14/2014 02:56 PM, Markus Metzger wrote:
> +
> +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";

Please put the return statements on their own lines.  Also, I
think at least the first string should go through _() for i18n.

> +    }
> +
> +  internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
> +}


Thanks,
Pedro Alves

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

* Re: [PATCH 02/12] btrace: add format argument to supports_btrace
  2014-07-14 13:56 ` [PATCH 02/12] btrace: add format argument to supports_btrace Markus Metzger
@ 2014-11-05 20:45   ` Pedro Alves
  2014-11-14 12:36     ` Metzger, Markus T
  0 siblings, 1 reply; 30+ messages in thread
From: Pedro Alves @ 2014-11-05 20:45 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 07/14/2014 02:56 PM, Markus Metzger wrote:
> 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.


> 
> Moved declarations in btrace-common.h around to break a cyclic dependency
> with gdbserver/server.h.

This should no longer be necessary since
462f517e5020a464e84d2b8535b1b68d39329dc2.

> +/* Target specific branch trace information.  */
> +struct btrace_target_info;
> +
> +/* Enumeration of btrace read types.  */
> +
> +enum btrace_read_type
> +{
> +  /* Send all available trace.  */
> +  BTRACE_READ_ALL,
> +
> +  /* Send all available trace, if it changed.  */
> +  BTRACE_READ_NEW,
> +
> +  /* Send the trace since the last request.  This will fail if the trace
> +     buffer overflowed.  */
> +  BTRACE_READ_DELTA
> +};

What does "Send" mean here?

Thanks,
Pedro Alves

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

* Re: [PATCH 04/12] record btrace: add configuration struct
  2014-07-14 13:57 ` [PATCH 04/12] record btrace: add configuration struct Markus Metzger
  2014-07-14 15:06   ` Eli Zaretskii
@ 2014-11-05 20:45   ` Pedro Alves
  1 sibling, 0 replies; 30+ messages in thread
From: Pedro Alves @ 2014-11-05 20:45 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches, Eli Zaretskii

On 07/14/2014 02:56 PM, Markus Metzger wrote:

> index 146d95f..c601e8d 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -131,6 +131,9 @@ struct vstop_notif
>    struct target_waitstatus status;
>  };
>
> +/* The current btrace configuration.  */
> +static struct btrace_config current_btrace_conf;

Why do we need this global?  Please expand the comment.

> --- a/gdb/remote.c
> +++ b/gdb/remote.c

> +/* The target's btrace configuration.  */
> +
> +static struct btrace_config btrace_target_config;

If this mirrors the state on the remote target, then
it should be a field of struct remote_state, not global.

> +/* Synchronize the configuration with the target.  */
> +
> +static void btrace_sync_conf (const struct btrace_config *conf)

Line break after void.

> +{
> +  /* 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)
> +{

Line break after void.

> +static void btrace_read_config (struct btrace_config *conf)
> +{
> +  struct cleanup *cleanup;

Move this within the if block below.

> +  char *xml;
> +
> +  xml = target_read_stralloc (&current_target,
> +                              TARGET_OBJECT_BTRACE_CONF, "");
> +  if (xml != NULL)
> +    {
> +
> +      cleanup = make_cleanup (xfree, xml);
> +      parse_xml_btrace_conf (conf, xml);

Spurious empty line.


Thanks,
Pedro Alves

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

* Re: [PATCH 05/12] record-btrace: add bts buffer size configuration option
  2014-07-14 13:57 ` [PATCH 05/12] record-btrace: add bts buffer size configuration option Markus Metzger
  2014-07-14 15:44   ` Eli Zaretskii
@ 2014-11-05 20:46   ` Pedro Alves
  1 sibling, 0 replies; 30+ messages in thread
From: Pedro Alves @ 2014-11-05 20:46 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches, Eli Zaretskii

On 07/14/2014 02:56 PM, Markus Metzger wrote:
> --- a/gdb/features/btrace-conf.dtd
> +++ b/gdb/features/btrace-conf.dtd
> @@ -5,6 +5,7 @@
>       notice and this notice are preserved.  -->
>  
>  <!ELEMENT btrace-conf	(bts?)>
> -<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
> +<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.1">

I don't see why we need to bump the version.  GDB that know
about attribute cope with it being missing.  And GDBs that aren't
expecting the attribute just ignore it.

>
>  <!ELEMENT bts	EMPTY>
> +<!ATTLIST bts	size	CDATA	#IMPLIED>

>  supported_btrace_packets (char *buf)
>  {
>    if (target_supports_btrace (BTRACE_FORMAT_BTS))
> -    strcat (buf, ";Qbtrace:bts+");
> +    {
> +      strcat (buf, ";Qbtrace:bts+");
> +      strcat (own_buf, ";Qbtrace-conf:bts:size+");
> +    }

'buf' or 'own_buf' ?

> +  if (pages == 0) {

Misplaced {

> +    errno = EINVAL;
> +    goto err;
> +  }
> +



> +/* 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";

Pedantically, this should be "kB".




> +  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."), _("\
> +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_bts_cmdlist,
> +			    &show_record_btrace_bts_cmdlist);

I think the documentation of these knobs should mention that
the setting takes effect the next time btrace is enabled, not
immediately.



> +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"
> +
> +gdb_test_no_output "record btrace bts"
> +gdb_test "show record btrace bts buffer-size" "The record/replay bts buffer size is 1\.\r"

See:
  https://sourceware.org/gdb/wiki/GDBTestcaseCookbook#Make_sure_test_messages_are_unique

Thanks,
Pedro Alves

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

* Re: [PATCH 07/12] btrace: extend struct btrace_insn
  2014-07-14 13:57 ` [PATCH 07/12] btrace: extend struct btrace_insn Markus Metzger
@ 2014-11-05 20:46   ` Pedro Alves
  0 siblings, 0 replies; 30+ messages in thread
From: Pedro Alves @ 2014-11-05 20:46 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 07/14/2014 02:56 PM, Markus Metzger wrote:
> +static enum btrace_insn_class
> +ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc)

Missing intro comment.

> +{
> +  volatile struct gdb_exception error;
> +  enum btrace_insn_class iclass;
> +
> +  iclass = BTRACE_INSN_OTHER;
> +  TRY_CATCH (error, RETURN_MASK_ALL)

This swallows ctrl-c.  I think it should be RETURN_MASK_ERROR.
Likewise other TRY_CATCH uses.

> +    {

Thanks,
Pedro Alves

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

* Re: [PATCH 08/12] btrace: identify cpu
  2014-07-14 13:56 ` [PATCH 08/12] btrace: identify cpu Markus Metzger
@ 2014-11-05 20:47   ` Pedro Alves
  0 siblings, 0 replies; 30+ messages in thread
From: Pedro Alves @ 2014-11-05 20:47 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 07/14/2014 02:56 PM, Markus Metzger wrote:
> diff --git a/gdb/common/btrace-common.c b/gdb/common/btrace-common.c
> index 90774a2..178ad35 100644
> --- a/gdb/common/btrace-common.c
> +++ b/gdb/common/btrace-common.c
> @@ -18,10 +18,47 @@
>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>  
>  #include "btrace-common.h"
> +#include "nat/i386-cpuid.h"

Hm, this is a layering violation.
common/ files must not include nat/ files.
If btrace-common.c is only used by native code, then it should
itself be in nat/ too.

Thanks,
Pedro Alves

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

* Re: [PATCH 00/12] record btrace: prepare for a new trace format
  2014-10-28 14:35 ` [PATCH 00/12] record btrace: prepare for a new trace format Metzger, Markus T
@ 2014-11-05 20:50   ` Pedro Alves
  2014-11-06  9:04     ` Metzger, Markus T
  0 siblings, 1 reply; 30+ messages in thread
From: Pedro Alves @ 2014-11-05 20:50 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: gdb-patches

On 10/28/2014 02:34 PM, Metzger, Markus T wrote:
> Hello Pedro, Maintainers,
> 
> Any feedback to this series?

Thanks, and sorry for the delay...

I read 1-11, and skimmed 12; will leave that one for when
you actually submit it.

This all looks reasonable, and the patches look
very well written to me.  Kudos.  I just spotted a few
minor issues which I pointed out as replies to the patches.
Patches that I didn't reply to were ones I didn't fell like
I had anything useful to say.

Thanks,
Pedro Alves

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

* RE: [PATCH 00/12] record btrace: prepare for a new trace format
  2014-11-05 20:50   ` Pedro Alves
@ 2014-11-06  9:04     ` Metzger, Markus T
  2014-11-07 11:27       ` Pedro Alves
  0 siblings, 1 reply; 30+ messages in thread
From: Metzger, Markus T @ 2014-11-06  9:04 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: Pedro Alves [mailto:palves@redhat.com]
> Sent: Wednesday, November 5, 2014 9:50 PM


> I read 1-11, and skimmed 12; will leave that one for when
> you actually submit it.

Thanks for your review!  I'll address your comments and
resend the patch series.

#12 depends on the kernel interface, which is currently
under review.  It will remain wip until the kernel patches
are merged but is otherwise not expected to change
(except for following the kernel interface).

Would you be OK to apply #1 to #11 and then wait for
#12?  I can't say how long it will take but it might be after
the next GDB release.

Also #12 depends on a decoder library which is available
from here:  https://github.com/01org/processor-trace.


Thanks,
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] 30+ messages in thread

* Re: [PATCH 00/12] record btrace: prepare for a new trace format
  2014-11-06  9:04     ` Metzger, Markus T
@ 2014-11-07 11:27       ` Pedro Alves
  0 siblings, 0 replies; 30+ messages in thread
From: Pedro Alves @ 2014-11-07 11:27 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: gdb-patches

On 11/06/2014 09:02 AM, Metzger, Markus T wrote:
>> -----Original Message-----
>> From: Pedro Alves [mailto:palves@redhat.com]
>> Sent: Wednesday, November 5, 2014 9:50 PM
> 
> 
>> I read 1-11, and skimmed 12; will leave that one for when
>> you actually submit it.
> 
> Thanks for your review!  I'll address your comments and
> resend the patch series.
> 
> #12 depends on the kernel interface, which is currently
> under review.  It will remain wip until the kernel patches
> are merged but is otherwise not expected to change
> (except for following the kernel interface).
> 
> Would you be OK to apply #1 to #11 and then wait for
> #12?  I can't say how long it will take but it might be after
> the next GDB release.

I think 1-10 would be fine.  Parts of it add user-visible
features that are useful already, even.

I think #11 should wait until libipt is actually used.

> Also #12 depends on a decoder library which is available
> from here:  https://github.com/01org/processor-trace.

Thanks,
Pedro Alves

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

* RE: [PATCH 02/12] btrace: add format argument to supports_btrace
  2014-11-05 20:45   ` Pedro Alves
@ 2014-11-14 12:36     ` Metzger, Markus T
  2014-11-14 13:36       ` Pedro Alves
  0 siblings, 1 reply; 30+ messages in thread
From: Metzger, Markus T @ 2014-11-14 12:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: Pedro Alves [mailto:palves@redhat.com]
> Sent: Wednesday, November 5, 2014 9:45 PM


> > Moved declarations in btrace-common.h around to break a cyclic
> dependency
> > with gdbserver/server.h.
> 
> This should no longer be necessary since
> 462f517e5020a464e84d2b8535b1b68d39329dc2.

Good.  It indeed is no longer necessary.


> > +/* Target specific branch trace information.  */
> > +struct btrace_target_info;
> > +
> > +/* Enumeration of btrace read types.  */
> > +
> > +enum btrace_read_type
> > +{
> > +  /* Send all available trace.  */
> > +  BTRACE_READ_ALL,
> > +
> > +  /* Send all available trace, if it changed.  */
> > +  BTRACE_READ_NEW,
> > +
> > +  /* Send the trace since the last request.  This will fail if the trace
> > +     buffer overflowed.  */
> > +  BTRACE_READ_DELTA
> > +};
> 
> What does "Send" mean here?

It means as much as "read".  It determines what trace you'll get
when reading btrace.

I realize it's the producer's view; it should rather be the consumer's
view.  Do you want me to change it in a separate patch?

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] 30+ messages in thread

* Re: [PATCH 02/12] btrace: add format argument to supports_btrace
  2014-11-14 12:36     ` Metzger, Markus T
@ 2014-11-14 13:36       ` Pedro Alves
  2014-11-14 13:47         ` Metzger, Markus T
  0 siblings, 1 reply; 30+ messages in thread
From: Pedro Alves @ 2014-11-14 13:36 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: gdb-patches

On 11/14/2014 12:36 PM, Metzger, Markus T wrote:

>> From: Pedro Alves [mailto:palves@redhat.com]

>>> +/* Target specific branch trace information.  */
>>> +struct btrace_target_info;
>>> +
>>> +/* Enumeration of btrace read types.  */
>>> +
>>> +enum btrace_read_type
>>> +{
>>> +  /* Send all available trace.  */
>>> +  BTRACE_READ_ALL,
>>> +
>>> +  /* Send all available trace, if it changed.  */
>>> +  BTRACE_READ_NEW,
>>> +
>>> +  /* Send the trace since the last request.  This will fail if the trace
>>> +     buffer overflowed.  */
>>> +  BTRACE_READ_DELTA
>>> +};
>>
>> What does "Send" mean here?
> 
> It means as much as "read".  It determines what trace you'll get
> when reading btrace.
> I realize it's the producer's view; it should rather be the consumer's
> view.  

Ah, yeah.

> Do you want me to change it in a separate patch?

Hmm, I'm confused -- why a separate patch instead of simply
adjusting this one?

Thanks,
Pedro Alves

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

* RE: [PATCH 02/12] btrace: add format argument to supports_btrace
  2014-11-14 13:36       ` Pedro Alves
@ 2014-11-14 13:47         ` Metzger, Markus T
  2014-11-14 13:50           ` Metzger, Markus T
  2014-11-14 13:50           ` Pedro Alves
  0 siblings, 2 replies; 30+ messages in thread
From: Metzger, Markus T @ 2014-11-14 13:47 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: gdb-patches-owner@sourceware.org [mailto:gdb-patches-
> owner@sourceware.org] On Behalf Of Pedro Alves
> Sent: Friday, November 14, 2014 2:37 PM


> >>> +enum btrace_read_type
> >>> +{
> >>> +  /* Send all available trace.  */
> >>> +  BTRACE_READ_ALL,
> >>> +
> >>> +  /* Send all available trace, if it changed.  */
> >>> +  BTRACE_READ_NEW,
> >>> +
> >>> +  /* Send the trace since the last request.  This will fail if the trace
> >>> +     buffer overflowed.  */
> >>> +  BTRACE_READ_DELTA
> >>> +};
> >>
> >> What does "Send" mean here?
> >
> > It means as much as "read".  It determines what trace you'll get
> > when reading btrace.
> > I realize it's the producer's view; it should rather be the consumer's
> > view.
> 
> Ah, yeah.
> 
> > Do you want me to change it in a separate patch?
> 
> Hmm, I'm confused -- why a separate patch instead of simply
> adjusting this one?

Because this chunk will go away.  As you pointed out, moving
declarations around is no longer necessary and this change is unrelated.

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] 30+ messages in thread

* Re: [PATCH 02/12] btrace: add format argument to supports_btrace
  2014-11-14 13:47         ` Metzger, Markus T
  2014-11-14 13:50           ` Metzger, Markus T
@ 2014-11-14 13:50           ` Pedro Alves
  1 sibling, 0 replies; 30+ messages in thread
From: Pedro Alves @ 2014-11-14 13:50 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: gdb-patches

On 11/14/2014 01:47 PM, Metzger, Markus T wrote:
>> owner@sourceware.org] On Behalf Of Pedro Alves

>>> Do you want me to change it in a separate patch?
>>
>> Hmm, I'm confused -- why a separate patch instead of simply
>> adjusting this one?
> 
> Because this chunk will go away.  As you pointed out, moving
> declarations around is no longer necessary and this change is unrelated.

D'oh!

If you want to push a fix for that as a separate patch, it's
preapproved.

Thanks,
Pedro Alves

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

* RE: [PATCH 02/12] btrace: add format argument to supports_btrace
  2014-11-14 13:47         ` Metzger, Markus T
@ 2014-11-14 13:50           ` Metzger, Markus T
  2014-11-14 13:50           ` Pedro Alves
  1 sibling, 0 replies; 30+ messages in thread
From: Metzger, Markus T @ 2014-11-14 13:50 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: Metzger, Markus T
> Sent: Friday, November 14, 2014 2:48 PM
> To: Pedro Alves
> Cc: gdb-patches@sourceware.org


> Because this chunk will go away

It's of course hunk, not chunk;-)

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] 30+ messages in thread

end of thread, other threads:[~2014-11-14 13:50 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-14 13:56 [PATCH 00/12] record btrace: prepare for a new trace format Markus Metzger
2014-07-14 13:56 ` [PATCH 06/12] btrace: update btrace_compute_ftrace parameters Markus Metzger
2014-07-14 13:56 ` [PATCH 09/12] btrace: use the new cpu identifier Markus Metzger
2014-07-14 13:56 ` [PATCH 02/12] btrace: add format argument to supports_btrace Markus Metzger
2014-11-05 20:45   ` Pedro Alves
2014-11-14 12:36     ` Metzger, Markus T
2014-11-14 13:36       ` Pedro Alves
2014-11-14 13:47         ` Metzger, Markus T
2014-11-14 13:50           ` Metzger, Markus T
2014-11-14 13:50           ` Pedro Alves
2014-07-14 13:56 ` [PATCH 08/12] btrace: identify cpu Markus Metzger
2014-11-05 20:47   ` Pedro Alves
2014-07-14 13:57 ` [PATCH 05/12] record-btrace: add bts buffer size configuration option Markus Metzger
2014-07-14 15:44   ` Eli Zaretskii
2014-11-05 20:46   ` Pedro Alves
2014-07-14 13:57 ` [PATCH 12/12] [wip] btrace: support Intel(R) Processor Trace Markus Metzger
2014-07-14 13:57 ` [PATCH 10/12] record-btrace: indicate gaps Markus Metzger
2014-07-14 13:57 ` [PATCH 07/12] btrace: extend struct btrace_insn Markus Metzger
2014-11-05 20:46   ` Pedro Alves
2014-07-14 13:57 ` [PATCH 11/12] configure: check for libipt Markus Metzger
2014-07-14 13:57 ` [PATCH 04/12] record btrace: add configuration struct Markus Metzger
2014-07-14 15:06   ` Eli Zaretskii
2014-11-05 20:45   ` Pedro Alves
2014-07-14 13:57 ` [PATCH 03/12] btrace, linux: add perf event buffer abstraction Markus Metzger
2014-07-14 14:48 ` [PATCH 01/12] btrace: add struct btrace_data Markus Metzger
2014-11-05 20:44   ` Pedro Alves
2014-10-28 14:35 ` [PATCH 00/12] record btrace: prepare for a new trace format Metzger, Markus T
2014-11-05 20:50   ` Pedro Alves
2014-11-06  9:04     ` Metzger, Markus T
2014-11-07 11:27       ` Pedro Alves

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).