public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 4/5] btrace: store raw btrace data
  2015-06-23  8:22 [PATCH 0/5] Support Intel(R) Processor Trace Markus Metzger
@ 2015-06-23  8:22 ` Markus Metzger
  2015-06-30 12:56   ` Pedro Alves
  2015-06-23  8:22 ` [PATCH 5/5] btrace: maintenance commands Markus Metzger
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Markus Metzger @ 2015-06-23  8:22 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Store the raw branch trace data that has been read from the target.

This data can be used for maintenance commands as well as for generating
a core file for the "record save" command.

2015-06-23  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.c (btrace_fetch): Append the new trace data.
	(btrace_clear): Clear the stored trace data.
	* btrace.h (btrace_thread_info) <data>: New.
	* common/btrace-common.h (btrace_data_clear)
	(btrace_data_append): New.
	* common/btrace-common.c (btrace_data_clear)
	(btrace_data_append): New.
---
 gdb/btrace.c               |  5 +++
 gdb/btrace.h               |  3 ++
 gdb/common/btrace-common.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/common/btrace-common.h |  9 +++++
 4 files changed, 104 insertions(+)

diff --git a/gdb/btrace.c b/gdb/btrace.c
index d3cdd19..561ccd6 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -1249,6 +1249,10 @@ btrace_fetch (struct thread_info *tp)
   /* Compute the trace, provided we have any.  */
   if (!btrace_data_empty (&btrace))
     {
+      /* Store the raw trace data.  The stored data will be cleared in
+	 btrace_clear, so we always append the new trace.  */
+      btrace_data_append (&btinfo->data, &btrace);
+
       btrace_clear_history (btinfo);
       btrace_compute_ftrace (tp, &btrace);
     }
@@ -1285,6 +1289,7 @@ btrace_clear (struct thread_info *tp)
   btinfo->end = NULL;
   btinfo->ngaps = 0;
 
+  btrace_data_clear (&btinfo->data);
   btrace_clear_history (btinfo);
 }
 
diff --git a/gdb/btrace.h b/gdb/btrace.h
index c25dc84..0845b78 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -248,6 +248,9 @@ struct btrace_thread_info
      the underlying architecture.  */
   struct btrace_target_info *target;
 
+  /* The raw branch trace data for the below branch trace.  */
+  struct btrace_data data;
+
   /* The current branch trace for this thread (both inclusive).
 
      The last instruction of END is the current instruction, which is not
diff --git a/gdb/common/btrace-common.c b/gdb/common/btrace-common.c
index 676428e..95193eb 100644
--- a/gdb/common/btrace-common.c
+++ b/gdb/common/btrace-common.c
@@ -91,3 +91,90 @@ btrace_data_empty (struct btrace_data *data)
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
 }
+
+/* See btrace-common.h.  */
+
+void
+btrace_data_clear (struct btrace_data *data)
+{
+  btrace_data_fini (data);
+  btrace_data_init (data);
+}
+
+/* See btrace-common.h.  */
+
+int
+btrace_data_append (struct btrace_data *dst,
+		    const struct btrace_data *src)
+{
+  switch (src->format)
+    {
+    case BTRACE_FORMAT_NONE:
+      return 0;
+
+    case BTRACE_FORMAT_BTS:
+      switch (dst->format)
+	{
+	default:
+	  return -1;
+
+	case BTRACE_FORMAT_NONE:
+	  dst->format = BTRACE_FORMAT_BTS;
+	  dst->variant.bts.blocks = NULL;
+
+	  /* Fall-through.  */
+	case BTRACE_FORMAT_BTS:
+	  {
+	    unsigned int blk;
+
+	    /* We copy blocks in reverse order to have the oldest block at
+	       index zero.  */
+	    blk = VEC_length (btrace_block_s, src->variant.bts.blocks);
+	    while (blk != 0)
+	      {
+		btrace_block_s *block;
+
+		block = VEC_index (btrace_block_s, src->variant.bts.blocks,
+				   --blk);
+
+		VEC_safe_push (btrace_block_s, dst->variant.bts.blocks, block);
+	      }
+	  }
+	}
+      return 0;
+
+    case BTRACE_FORMAT_PT:
+      switch (dst->format)
+	{
+	default:
+	  return -1;
+
+	case BTRACE_FORMAT_NONE:
+	  dst->format = BTRACE_FORMAT_PT;
+	  dst->variant.pt.data = NULL;
+	  dst->variant.pt.size = 0;
+
+	  /* fall-through.  */
+	case BTRACE_FORMAT_BTS:
+	  {
+	    gdb_byte *data;
+	    unsigned long size;
+
+	    size = src->variant.pt.size + dst->variant.pt.size;
+	    data = xmalloc (size);
+
+	    memcpy (data, dst->variant.pt.data, dst->variant.pt.size);
+	    memcpy (data + dst->variant.pt.size, src->variant.pt.data,
+		    src->variant.pt.size);
+
+	    xfree (dst->variant.pt.data);
+
+	    dst->variant.pt.data = data;
+	    dst->variant.pt.size = size;
+	  }
+	}
+      return 0;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
+}
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index ebae17e..f22efc5 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -214,7 +214,16 @@ extern void btrace_data_init (struct btrace_data *data);
 /* Cleanup DATA.  */
 extern void btrace_data_fini (struct btrace_data *data);
 
+/* Clear DATA.  */
+extern void btrace_data_clear (struct btrace_data *data);
+
 /* Return non-zero if DATA is empty; zero otherwise.  */
 extern int btrace_data_empty (struct btrace_data *data);
 
+/* Append the branch trace data from SRC to the end of DST.
+   Both SRC and DST must use the same format.
+   Returns zero on success; a negative number otherwise.  */
+extern int btrace_data_append (struct btrace_data *dst,
+			       const struct btrace_data *src);
+
 #endif /* BTRACE_COMMON_H */
-- 
1.8.3.1

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

* [PATCH 3/5] btrace, linux: use data_size and data_offset
  2015-06-23  8:22 [PATCH 0/5] Support Intel(R) Processor Trace Markus Metzger
  2015-06-23  8:22 ` [PATCH 4/5] btrace: store raw btrace data Markus Metzger
  2015-06-23  8:22 ` [PATCH 5/5] btrace: maintenance commands Markus Metzger
@ 2015-06-23  8:22 ` Markus Metzger
  2015-06-30 12:56   ` Pedro Alves
  2015-06-23  8:22 ` [PATCH 1/5] configure: check for libipt Markus Metzger
  2015-06-23  8:23 ` [PATCH 2/5] btrace: support Intel(R) Processor Trace Markus Metzger
  4 siblings, 1 reply; 20+ messages in thread
From: Markus Metzger @ 2015-06-23  8:22 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

In struct perf_event_mmap_page there are new fields data_size and data_offset
that give the location of the perf_event data buffer relative to the mmap
page.  Use them if they are present.

2015-06-23  Markus Metzger  <markus.t.metzger@intel.com>

	nat/linux-btrace.c (linux_enable_bts): Check for PERF_ATTR_SIZE_VER5.
	Check for data_offset and data_size fields.  Use them.
---
 gdb/nat/linux-btrace.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index 40915da..2ed167a 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -644,7 +644,7 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
   struct perf_event_mmap_page *header;
   struct btrace_target_info *tinfo;
   struct btrace_tinfo_bts *bts;
-  unsigned long long size, pages;
+  unsigned long long size, pages, data_offset, data_size;
   int pid, pg;
 
   tinfo = xzalloc (sizeof (*tinfo));
@@ -706,16 +706,27 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
 	break;
     }
 
-  if (header == MAP_FAILED)
+  if (pages == 0)
     goto err_file;
 
+  data_offset = PAGE_SIZE;
+  data_size = size;
+
+#if defined(PERF_ATTR_SIZE_VER5)
+  if (offsetof(struct perf_event_mmap_page, data_size) <= header->size)
+    {
+      data_offset = header->data_offset;
+      data_size = header->data_size;
+    }
+#endif /* defined(PERF_ATTR_SIZE_VER5) */
+
   bts->header = header;
-  bts->bts.mem = ((const uint8_t *) header) + PAGE_SIZE;
-  bts->bts.size = size;
+  bts->bts.mem = ((const uint8_t *) header) + data_offset;
+  bts->bts.size = data_size;
   bts->bts.data_head = &header->data_head;
   bts->bts.last_head = 0;
 
-  tinfo->conf.bts.size = size;
+  tinfo->conf.bts.size = data_size;
   return tinfo;
 
  err_file:
-- 
1.8.3.1

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

* [PATCH 1/5] configure: check for libipt
  2015-06-23  8:22 [PATCH 0/5] Support Intel(R) Processor Trace Markus Metzger
                   ` (2 preceding siblings ...)
  2015-06-23  8:22 ` [PATCH 3/5] btrace, linux: use data_size and data_offset Markus Metzger
@ 2015-06-23  8:22 ` Markus Metzger
  2015-06-30 12:56   ` Pedro Alves
  2015-06-23  8:23 ` [PATCH 2/5] btrace: support Intel(R) Processor Trace Markus Metzger
  4 siblings, 1 reply; 20+ messages in thread
From: Markus Metzger @ 2015-06-23  8:22 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Check for libipt, an Intel(R) Processor Trace decoder library.  The sources
can be found on github at:

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

2015-06-23  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 3008177..dfaa8a3 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -174,6 +174,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)
@@ -590,7 +593,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
 CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(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 5b6dbbb..9ef53b3 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -234,6 +234,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 5100921..e8979f0 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -658,6 +658,9 @@ TARGET_SYSTEM_ROOT
 CONFIG_LDFLAGS
 RDYNAMIC
 ALLOCA
+LTLIBIPT
+LIBIPT
+HAVE_LIBIPT
 HAVE_GUILE_FALSE
 HAVE_GUILE_TRUE
 GUILE_LIBS
@@ -831,6 +834,8 @@ with_libexpat_prefix
 with_python
 with_guile
 enable_libmcheck
+with_intel_pt
+with_libipt_prefix
 with_included_regex
 with_sysroot
 with_system_gdbinit
@@ -1553,6 +1558,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(R) 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
@@ -9661,6 +9669,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_insn_alloc_decoder (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 2035a37..a40860a 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1242,6 +1242,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(R) 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_insn_alloc_decoder (0);])
+  if test "$HAVE_LIBIPT" != yes; then
+    if test "$with_intel_pt" = yes; then
+      AC_MSG_ERROR([libipt is missing or unusable])
+    else
+      AC_MSG_WARN([libipt is missing or unusable; some features may be unavailable.])
+    fi
+  fi
+fi
+
 # ------------------------- #
 # Checks for header files.  #
 # ------------------------- #
-- 
1.8.3.1

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

* [PATCH 5/5] btrace: maintenance commands
  2015-06-23  8:22 [PATCH 0/5] Support Intel(R) Processor Trace Markus Metzger
  2015-06-23  8:22 ` [PATCH 4/5] btrace: store raw btrace data Markus Metzger
@ 2015-06-23  8:22 ` Markus Metzger
  2015-06-23 15:28   ` Eli Zaretskii
  2015-06-30 12:57   ` Pedro Alves
  2015-06-23  8:22 ` [PATCH 3/5] btrace, linux: use data_size and data_offset Markus Metzger
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 20+ messages in thread
From: Markus Metzger @ 2015-06-23  8:22 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches, Eli Zaretskii

Add maintenance commands that help debugging the btrace record target.
The following new commands are added:

maint info btrace
  Print information about branch tracing internals.

maint btrace packet-history
  Print the raw branch tracing data.

maint btrace clear-packet-history
  Discard the stored raw branch tracing data.

maint btrace clear
  Discard all branch tracing data.  It will be fetched and processed
  anew by the next "record" command.

maint set|show btrace pt skip-pad
  Set and show whether PAD packets are skipped when computing the
  packet history.

CC: Eli Zaretskii  <eliz@gnu.org>

2015-06-23  Markus Metzger  <markus.t.metzger@intel.com>

	* btrace.c: Include gdbcmd.h, cli/cli-utils.h, and ctype.h.
	(maint_btrace_cmdlist, maint_btrace_set_cmdlist)
	(maint_btrace_show_cmdlist, maint_btrace_pt_set_cmdlist)
	(maint_btrace_pt_show_cmdlist, maint_btrace_pt_skip_pad)
	(btrace_maint_clear): New.
	(btrace_fetch, btrace_clear): Call btrace_maint_clear.
	(pt_print_packet, btrace_maint_decode_pt)
	(btrace_maint_update_pt_packets, btrace_maint_update_packets)
	(btrace_maint_print_packets, get_uint, get_context_size, no_chunk)
	(maint_btrace_packet_history_cmd)
	(maint_btrace_clear_packet_history_cmd, maint_btrace_clear_cmd)
	(maint_btrace_cmd, maint_btrace_set_cmd, maint_btrace_show_cmd)
	(maint_btrace_pt_set_cmd, maint_btrace_pt_show_cmd)
	(maint_info_btrace_cmd, _initialize_btrace): New.
	* btrace.h (btrace_pt_packet, btrace_pt_packet_s)
	(btrace_maint_packet_history, btrace_maint_info): New.
	(btrace_thread_info) <maint>: New.
	* NEWS: Announce it.

doc/
	* gdb.texinfo (Maintenance Commands): Document it.
---
 gdb/NEWS            |  17 ++
 gdb/btrace.c        | 722 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/btrace.h        |  63 +++++
 gdb/doc/gdb.texinfo |  60 +++++
 4 files changed, 862 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index 9ab64bf..7c15a94 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -116,6 +116,19 @@ record btrace pt
 record pt
   Start branch trace recording using Intel(R) Processor Trace format.
 
+maint info btrace
+  Print information about branch tracing internals.
+
+maint btrace packet-history
+  Print the raw branch tracing data.
+
+maint btrace clear-packet-history
+  Discard the stored raw branch tracing data.
+
+maint btrace clear
+  Discard all branch tracing data.  It will be fetched and processed
+  anew by the next "record" command.
+
 * New options
 
 set debug dwarf-die
@@ -169,6 +182,10 @@ set|show record btrace pt buffer-size
   The obtained size may differ from the requested size.  Use "info
   record" to see the obtained buffer size.
 
+maint set|show btrace pt skip-pad
+  Set and show whether PAD packets are skipped when computing the
+  packet history.
+
 * The command 'thread apply all' can now support new option '-ascending'
   to call its specified command for all threads in ascending order.
 
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 561ccd6..6740433 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -32,8 +32,21 @@
 #include "xml-support.h"
 #include "regcache.h"
 #include "rsp-low.h"
+#include "gdbcmd.h"
+#include "cli/cli-utils.h"
 
 #include <inttypes.h>
+#include <ctype.h>
+
+/* Command lists for btrace maintenance commands.  */
+static struct cmd_list_element *maint_btrace_cmdlist;
+static struct cmd_list_element *maint_btrace_set_cmdlist;
+static struct cmd_list_element *maint_btrace_show_cmdlist;
+static struct cmd_list_element *maint_btrace_pt_set_cmdlist;
+static struct cmd_list_element *maint_btrace_pt_show_cmdlist;
+
+/* Control whether to skip PAD packets when computing the packet history.  */
+static int maint_btrace_pt_skip_pad = 1;
 
 static void btrace_add_pc (struct thread_info *tp);
 
@@ -1186,6 +1199,33 @@ btrace_clear_history (struct btrace_thread_info *btinfo)
   btinfo->replay = NULL;
 }
 
+/* Clear the branch trace maintenance histories in BTINFO.  */
+
+static void
+btrace_maint_clear (struct btrace_thread_info *btinfo)
+{
+  switch (btinfo->data.format)
+    {
+    default:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      btinfo->maint.variant.bts.packet_history.begin = 0;
+      btinfo->maint.variant.bts.packet_history.end = 0;
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      xfree (btinfo->maint.variant.pt.packets);
+
+      btinfo->maint.variant.pt.packets = NULL;
+      btinfo->maint.variant.pt.packet_history.begin = 0;
+      btinfo->maint.variant.pt.packet_history.end = 0;
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
 /* See btrace.h.  */
 
 void
@@ -1252,6 +1292,7 @@ btrace_fetch (struct thread_info *tp)
       /* Store the raw trace data.  The stored data will be cleared in
 	 btrace_clear, so we always append the new trace.  */
       btrace_data_append (&btinfo->data, &btrace);
+      btrace_maint_clear (btinfo);
 
       btrace_clear_history (btinfo);
       btrace_compute_ftrace (tp, &btrace);
@@ -1289,6 +1330,8 @@ btrace_clear (struct thread_info *tp)
   btinfo->end = NULL;
   btinfo->ngaps = 0;
 
+  /* Must clear the maint data before - it depends on BTINFO->DATA.  */
+  btrace_maint_clear (btinfo);
   btrace_data_clear (&btinfo->data);
   btrace_clear_history (btinfo);
 }
@@ -2192,3 +2235,682 @@ make_cleanup_btrace_data (struct btrace_data *data)
 {
   return make_cleanup (do_btrace_data_cleanup, data);
 }
+
+#if defined (HAVE_LIBIPT)
+
+/* Print a single packet.  */
+
+static void
+pt_print_packet (const struct pt_packet *packet)
+{
+  switch (packet->type)
+    {
+    default:
+      printf_unfiltered ("[??: %x]", packet->type);
+      break;
+
+    case ppt_psb:
+      printf_unfiltered ("psb");
+      break;
+
+    case ppt_psbend:
+      printf_unfiltered ("psbend");
+      break;
+
+    case ppt_pad:
+      printf_unfiltered ("pad");
+      break;
+
+    case ppt_tip:
+      printf_unfiltered ("tip %u: 0x%" PRIx64 "",
+			 packet->payload.ip.ipc,
+			 packet->payload.ip.ip);
+      break;
+
+    case ppt_tip_pge:
+      printf_unfiltered ("tip.pge %u: 0x%" PRIx64 "",
+			 packet->payload.ip.ipc,
+			 packet->payload.ip.ip);
+      break;
+
+    case ppt_tip_pgd:
+      printf_unfiltered ("tip.pgd %u: 0x%" PRIx64 "",
+			 packet->payload.ip.ipc,
+			 packet->payload.ip.ip);
+      break;
+
+    case ppt_fup:
+      printf_unfiltered ("fup %u: 0x%" PRIx64 "",
+			 packet->payload.ip.ipc,
+			 packet->payload.ip.ip);
+      break;
+
+    case ppt_tnt_8:
+      printf_unfiltered ("tnt-8 %u: 0x%" PRIx64 "",
+			 packet->payload.tnt.bit_size,
+			 packet->payload.tnt.payload);
+      break;
+
+    case ppt_tnt_64:
+      printf_unfiltered ("tnt-64 %u: 0x%" PRIx64 "",
+			 packet->payload.tnt.bit_size,
+			 packet->payload.tnt.payload);
+      break;
+
+    case ppt_pip:
+      printf_unfiltered ("pip %" PRIx64 "", packet->payload.pip.cr3);
+      break;
+
+    case ppt_tsc:
+      printf_unfiltered ("tsc %" PRIx64 "", packet->payload.tsc.tsc);
+      break;
+
+    case ppt_cbr:
+      printf_unfiltered ("cbr %u", packet->payload.cbr.ratio);
+      break;
+
+    case ppt_mode:
+      switch (packet->payload.mode.leaf)
+	{
+	default:
+	  printf_unfiltered ("mode %u", packet->payload.mode.leaf);
+	  break;
+
+	case pt_mol_exec:
+	  printf_unfiltered ("mode.exec%s%s",
+			     packet->payload.mode.bits.exec.csl ? " cs.l" : "",
+			     packet->payload.mode.bits.exec.csd ? " cs.d" : "");
+	  break;
+
+	case pt_mol_tsx:
+	  printf_unfiltered ("mode.tsx%s%s",
+			     packet->payload.mode.bits.tsx.intx ? " intx" : "",
+			     packet->payload.mode.bits.tsx.abrt ? " abrt" : "");
+	  break;
+	}
+      break;
+
+    case ppt_ovf:
+      printf_unfiltered ("ovf");
+      break;
+
+    }
+}
+
+/* Decode packets into MAINT using DECODER.  */
+
+static void
+btrace_maint_decode_pt (struct btrace_maint_info *maint,
+			struct pt_packet_decoder *decoder)
+{
+  int errcode;
+
+  for (;;)
+    {
+      struct btrace_pt_packet packet;
+
+      errcode = pt_pkt_sync_forward (decoder);
+      if (errcode < 0)
+	break;
+
+      for (;;)
+	{
+	  pt_pkt_get_offset (decoder, &packet.offset);
+
+	  errcode = pt_pkt_next (decoder, &packet.packet,
+				 sizeof(packet.packet));
+	  if (errcode < 0)
+	    break;
+
+	  if (maint_btrace_pt_skip_pad == 0 || packet.packet.type != ppt_pad)
+	    {
+	      packet.errcode = pt_errcode (errcode);
+	      VEC_safe_push (btrace_pt_packet_s, maint->variant.pt.packets,
+			     &packet);
+	    }
+	}
+
+      if (errcode == -pte_eos)
+	break;
+
+      packet.errcode = pt_errcode (errcode);
+      VEC_safe_push (btrace_pt_packet_s, maint->variant.pt.packets,
+		     &packet);
+
+      warning (_("Error at trace offset 0x%" PRIx64 ": %s."),
+	       packet.offset, pt_errstr (packet.errcode));
+    }
+
+  if (errcode != -pte_eos)
+    warning (_("Failed to synchronize onto the Intel(R) Processor Trace "
+	       "stream: %s."), pt_errstr (pt_errcode (errcode)));
+}
+
+/* Update the packet history in BTINFO.  */
+
+static void
+btrace_maint_update_pt_packets (struct btrace_thread_info *btinfo)
+{
+  volatile struct gdb_exception except;
+  struct pt_packet_decoder *decoder;
+  struct btrace_data_pt *pt;
+  struct pt_config config;
+  int errcode;
+
+  pt = &btinfo->data.variant.pt;
+
+  /* Nothing to do if there is no trace.  */
+  if (pt->size == 0)
+    return;
+
+  memset (&config, 0, sizeof(config));
+
+  config.size = sizeof (config);
+  config.begin = pt->data;
+  config.end = pt->data + pt->size;
+
+  config.cpu.vendor = pt_translate_cpu_vendor (pt->config.cpu.vendor);
+  config.cpu.family = pt->config.cpu.family;
+  config.cpu.model = pt->config.cpu.model;
+  config.cpu.stepping = pt->config.cpu.stepping;
+
+  errcode = pt_cpu_errata (&config.errata, &config.cpu);
+  if (errcode < 0)
+    error (_("Failed to configure the Intel(R) Processor Trace decoder: %s."),
+	   pt_errstr (pt_errcode (errcode)));
+
+  decoder = pt_pkt_alloc_decoder (&config);
+  if (decoder == NULL)
+    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
+
+  TRY
+    {
+      btrace_maint_decode_pt (&btinfo->maint, decoder);
+    }
+  CATCH (except, RETURN_MASK_ALL)
+    {
+      pt_pkt_free_decoder (decoder);
+
+      if (except.reason < 0)
+	throw_exception (except);
+    }
+  END_CATCH
+
+  pt_pkt_free_decoder (decoder);
+}
+
+#endif /* !defined (HAVE_LIBIPT)  */
+
+/* Update the packet maintenance information for BTINFO and store the
+   low and high bounds into BEGIN and END, respectively.
+   Store the current iterator state into FROM and TO.  */
+
+static void
+btrace_maint_update_packets (struct btrace_thread_info *btinfo,
+			     unsigned int *begin, unsigned int *end,
+			     unsigned int *from, unsigned int *to)
+{
+  switch (btinfo->data.format)
+    {
+    default:
+      *begin = 0;
+      *end = 0;
+      *from = 0;
+      *to = 0;
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      /* Nothing to do - we operate directly on BTINFO->DATA.  */
+      *begin = 0;
+      *end = VEC_length (btrace_block_s, btinfo->data.variant.bts.blocks);
+      *from = btinfo->maint.variant.bts.packet_history.begin;
+      *to = btinfo->maint.variant.bts.packet_history.end;
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      if (VEC_empty (btrace_pt_packet_s, btinfo->maint.variant.pt.packets))
+	btrace_maint_update_pt_packets (btinfo);
+
+      *begin = 0;
+      *end = VEC_length (btrace_pt_packet_s, btinfo->maint.variant.pt.packets);
+      *from = btinfo->maint.variant.pt.packet_history.begin;
+      *to = btinfo->maint.variant.pt.packet_history.end;
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
+/* Print packets in BTINFO from BEGIN (inclusive) until END (exclusive) and
+   update the current iterator position.  */
+
+static void
+btrace_maint_print_packets (struct btrace_thread_info *btinfo,
+			    unsigned int begin, unsigned int end)
+{
+  switch (btinfo->data.format)
+    {
+    default:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      {
+	VEC (btrace_block_s) *blocks;
+	unsigned int blk;
+
+	blocks = btinfo->data.variant.bts.blocks;
+	for (blk = begin; blk < end; ++blk)
+	  {
+	    const btrace_block_s *block;
+
+	    block = VEC_index (btrace_block_s, blocks, blk);
+
+	    printf_unfiltered ("%u\tbegin: %s, end: %s\n", blk,
+			       core_addr_to_string_nz (block->begin),
+			       core_addr_to_string_nz (block->end));
+	  }
+
+	btinfo->maint.variant.bts.packet_history.begin = begin;
+	btinfo->maint.variant.bts.packet_history.end = end;
+      }
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      {
+	VEC (btrace_pt_packet_s) *packets;
+	unsigned int pkt;
+
+	packets = btinfo->maint.variant.pt.packets;
+	for (pkt = begin; pkt < end; ++pkt)
+	  {
+	    const struct btrace_pt_packet *packet;
+
+	    packet = VEC_index (btrace_pt_packet_s, packets, pkt);
+
+	    printf_unfiltered ("%u\t", pkt);
+	    printf_unfiltered ("0x%" PRIx64 "\t", packet->offset);
+
+	    if (packet->errcode == pte_ok)
+	      pt_print_packet (&packet->packet);
+	    else
+	      printf_unfiltered ("[error: %s]", pt_errstr (packet->errcode));
+
+	    printf_unfiltered ("\n");
+	  }
+
+	btinfo->maint.variant.pt.packet_history.begin = begin;
+	btinfo->maint.variant.pt.packet_history.end = end;
+      }
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
+/* Read a number from an argument string.  */
+
+static unsigned int
+get_uint (char **arg)
+{
+  char *begin, *end, *pos;
+  unsigned long number;
+
+  begin = *arg;
+  pos = skip_spaces (begin);
+
+  if (!isdigit (*pos))
+    error (_("Expected positive number, got: %s."), pos);
+
+  number = strtoul (pos, &end, 10);
+  if (number > UINT_MAX)
+    error (_("Number too big."));
+
+  *arg += (end - begin);
+
+  return (unsigned int) number;
+}
+
+/* Read a context size from an argument string.  */
+
+static int
+get_context_size (char **arg)
+{
+  char *pos;
+  int number;
+
+  pos = skip_spaces (*arg);
+
+  if (!isdigit (*pos))
+    error (_("Expected positive number, got: %s."), pos);
+
+  return strtol (pos, arg, 10);
+}
+
+/* Complain about junk at the end of an argument string.  */
+
+static void
+no_chunk (char *arg)
+{
+  if (*arg != 0)
+    error (_("Junk after argument: %s."), arg);
+}
+
+/* The "maintenance btrace packet-history" command.  */
+
+static void
+maint_btrace_packet_history_cmd (char *arg, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+  unsigned int size, begin, end, from, to;
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  size = 10;
+  btinfo = &tp->btrace;
+
+  btrace_maint_update_packets (btinfo, &begin, &end, &from, &to);
+  if (begin == end)
+    {
+      printf_unfiltered (_("No trace.\n"));
+      return;
+    }
+
+  if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
+    {
+      from = to;
+
+      if (end - from < size)
+	size = end - from;
+      to = from + size;
+    }
+  else if (strcmp (arg, "-") == 0)
+    {
+      to = from;
+
+      if (to - begin < size)
+	size = to - begin;
+      from = to - size;
+    }
+  else
+    {
+      from = get_uint (&arg);
+      if (end <= from)
+	error (_("'%u' is out of range."), from);
+
+      arg = skip_spaces (arg);
+      if (*arg == ',')
+	{
+	  arg = skip_spaces (++arg);
+
+	  if (*arg == '+')
+	    {
+	      arg += 1;
+	      size = get_context_size (&arg);
+
+	      no_chunk (arg);
+
+	      if (end - from < size)
+		size = end - from;
+	      to = from + size;
+	    }
+	  else if (*arg == '-')
+	    {
+	      arg += 1;
+	      size = get_context_size (&arg);
+
+	      no_chunk (arg);
+
+	      /* Include the packet given as first argument.  */
+	      from += 1;
+	      to = from;
+
+	      if (to - begin < size)
+		size = to - begin;
+	      from = to - size;
+	    }
+	  else
+	    {
+	      to = get_uint (&arg);
+
+	      /* Include the packet at the second argument and silently
+		 truncate the range.  */
+	      if (to < end)
+		to += 1;
+	      else
+		to = end;
+
+	      no_chunk (arg);
+	    }
+	}
+      else
+	{
+	  no_chunk (arg);
+
+	  if (end - from < size)
+	    size = end - from;
+	  to = from + size;
+	}
+
+      dont_repeat ();
+    }
+
+  btrace_maint_print_packets (btinfo, from, to);
+}
+
+/* The "maintenance btrace clear-packet-history" command.  */
+
+static void
+maint_btrace_clear_packet_history_cmd (char *args, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+
+  if (args != NULL && *args != 0)
+    error (_("Invalid argument."));
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  btinfo = &tp->btrace;
+
+  /* Must clear the maint data before - it depends on BTINFO->DATA.  */
+  btrace_maint_clear (btinfo);
+  btrace_data_clear (&btinfo->data);
+}
+
+/* The "maintenance btrace clear" command.  */
+
+static void
+maint_btrace_clear_cmd (char *args, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+
+  if (args != NULL && *args != 0)
+    error (_("Invalid argument."));
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  btrace_clear (tp);
+}
+
+/* The "maintenance btrace" command.  */
+
+static void
+maint_btrace_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_cmdlist, "maintenance btrace ", all_commands,
+	     gdb_stdout);
+}
+
+/* The "maintenance set btrace" command.  */
+
+static void
+maint_btrace_set_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_set_cmdlist, "maintenance set btrace ", all_commands,
+	     gdb_stdout);
+}
+
+/* The "maintenance show btrace" command.  */
+
+static void
+maint_btrace_show_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_show_cmdlist, "maintenance show btrace ",
+	     all_commands, gdb_stdout);
+}
+
+/* The "maintenance set btrace pt" command.  */
+
+static void
+maint_btrace_pt_set_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_pt_set_cmdlist, "maintenance set btrace pt ",
+	     all_commands, gdb_stdout);
+}
+
+/* The "maintenance show btrace pt" command.  */
+
+static void
+maint_btrace_pt_show_cmd (char *args, int from_tty)
+{
+  help_list (maint_btrace_pt_show_cmdlist, "maintenance show btrace pt ",
+	     all_commands, gdb_stdout);
+}
+
+/* The "maintenance info btrace" command.  */
+
+static void
+maint_info_btrace_cmd (char *args, int from_tty)
+{
+  struct btrace_thread_info *btinfo;
+  struct thread_info *tp;
+  const struct btrace_config *conf;
+
+  if (args != NULL && *args != 0)
+    error (_("Invalid argument."));
+
+  tp = find_thread_ptid (inferior_ptid);
+  if (tp == NULL)
+    error (_("No thread."));
+
+  btinfo = &tp->btrace;
+
+  conf = btrace_conf (btinfo);
+  if (conf == NULL)
+    error (_("No btrace configuration."));
+
+  printf_unfiltered (_("Format: %s.\n"),
+		     btrace_format_string (conf->format));
+
+  switch (conf->format)
+    {
+    default:
+      break;
+
+    case BTRACE_FORMAT_BTS:
+      printf_unfiltered (_("Number of packets: %u.\n"),
+			 VEC_length (btrace_block_s,
+				     btinfo->data.variant.bts.blocks));
+      break;
+
+#if defined (HAVE_LIBIPT)
+    case BTRACE_FORMAT_PT:
+      {
+	struct pt_version version;
+
+	version = pt_library_version ();
+	printf_unfiltered (_("Version: %u.%u.%u%s.\n"), version.major,
+			   version.minor, version.build,
+			   version.ext != NULL ? version.ext : "");
+
+	btrace_maint_update_pt_packets (btinfo);
+	printf_unfiltered (_("Number of packets: %u.\n"),
+			   VEC_length (btrace_pt_packet_s,
+				       btinfo->maint.variant.pt.packets));
+      }
+      break;
+#endif /* defined (HAVE_LIBIPT)  */
+    }
+}
+
+/* Initialize btrace maintenance commands.  */
+
+void _initialize_btrace (void);
+void
+_initialize_btrace (void)
+{
+  add_cmd ("btrace", class_maintenance, maint_info_btrace_cmd,
+	   _("Info about branch tracing data."), &maintenanceinfolist);
+
+  add_prefix_cmd ("btrace", class_maintenance, maint_btrace_cmd,
+		  _("Branch tracing maintenance commands."),
+		  &maint_btrace_cmdlist, "maintenance btrace ",
+		  0, &maintenancelist);
+
+  add_prefix_cmd ("btrace", class_maintenance, maint_btrace_set_cmd, _("\
+Set branch tracing specific variables."),
+                  &maint_btrace_set_cmdlist, "maintenance set btrace ",
+                  0, &maintenance_set_cmdlist);
+
+  add_prefix_cmd ("pt", class_maintenance, maint_btrace_pt_set_cmd, _("\
+Set Intel(R) Processor Trace specific variables."),
+                  &maint_btrace_pt_set_cmdlist, "maintenance set btrace pt ",
+                  0, &maint_btrace_set_cmdlist);
+
+  add_prefix_cmd ("btrace", class_maintenance, maint_btrace_show_cmd, _("\
+Show branch tracing specific variables."),
+                  &maint_btrace_show_cmdlist, "maintenance show btrace ",
+                  0, &maintenance_show_cmdlist);
+
+  add_prefix_cmd ("pt", class_maintenance, maint_btrace_pt_show_cmd, _("\
+Show Intel(R) Processor Trace specific variables."),
+                  &maint_btrace_pt_show_cmdlist, "maintenance show btrace pt ",
+                  0, &maint_btrace_show_cmdlist);
+
+  add_setshow_boolean_cmd ("skip-pad", class_maintenance,
+			   &maint_btrace_pt_skip_pad, _("\
+Set whether PAD packets should be skipped in the btrace packet history."), _("\
+Show whether PAD packets should be skipped in the btrace packet history."),_("\
+When enabled, PAD packets are ignored when processing the trace to compute \
+the btrace packet history.\n\
+This does not modify the already computed packet history.  Use 'maintenance \
+btrace clear-packet-history' to clear and recompute the existing history."),
+			   NULL, NULL, &maint_btrace_pt_set_cmdlist,
+			   &maint_btrace_pt_show_cmdlist);
+
+  add_cmd ("packet-history", class_maintenance, maint_btrace_packet_history_cmd,
+	   _("Prints the raw branch tracing data.\n\
+With no argument, prints ten more packets after the previous ten-line print.\n\
+With '-' as argument prints ten packets before a previous ten-line print.\n\
+One integer argument specifies a packet number, and ten packets are printed \
+after that packet.\n\
+Two integer arguments with comma between them specify starting and ending packet \
+numbers to print.\n\
+If the second argument is preceded by '+' or '-', it specifies the distance \
+from the first argument.\n\
+"),
+	   &maint_btrace_cmdlist);
+
+  add_cmd ("clear-packet-history", class_maintenance,
+	   maint_btrace_clear_packet_history_cmd,
+	   _("Clears the branch tracing packet history.\n\
+Discards the raw branch tracing data but not the execution history data.\n\
+"),
+	   &maint_btrace_cmdlist);
+
+  add_cmd ("clear", class_maintenance, maint_btrace_clear_cmd,
+	   _("Clears the branch tracing data.\n\
+Discards the raw branch tracing data and the execution history data.\n\
+The next 'record' command will fetch the branch tracing data anew.\n\
+"),
+	   &maint_btrace_cmdlist);
+
+}
diff --git a/gdb/btrace.h b/gdb/btrace.h
index 0845b78..93c84ff 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -233,6 +233,66 @@ enum btrace_thread_flag
   BTHR_MOVE = (BTHR_STEP | BTHR_RSTEP | BTHR_CONT | BTHR_RCONT)
 };
 
+#if defined (HAVE_LIBIPT)
+/* A packet.  */
+struct btrace_pt_packet
+{
+  /* The offset in the trace stream.  */
+  uint64_t offset;
+
+  /* The decode error code.  */
+  enum pt_error_code errcode;
+
+  /* The decoded packet.  Only valid if ERRCODE == pte_ok.  */
+  struct pt_packet packet;
+};
+
+/* Define functions operating on a vector of packets.  */
+typedef struct btrace_pt_packet btrace_pt_packet_s;
+DEF_VEC_O (btrace_pt_packet_s);
+#endif /* defined (HAVE_LIBIPT)  */
+
+/* Branch trace iteration state for "maintenance btrace packet-history".  */
+struct btrace_maint_packet_history
+{
+  /* The branch trace packet range from BEGIN (inclusive) to
+     END (exclusive) that has been covered last time.  */
+  unsigned int begin;
+  unsigned int end;
+};
+
+/* Branch trace maintenance information per thread.
+
+   This information is used by "maintenance btrace" commands.  */
+struct btrace_maint_info
+{
+  /* Most information is format-specific.
+     The format can be found in the BTRACE.DATA.FORMAT field of each thread.  */
+  union
+  {
+    /* BTRACE.DATA.FORMAT == BTRACE_FORMAT_BTS  */
+    struct
+    {
+      /* The packet history iterator.
+	 We are iterating over BTRACE.DATA.FORMAT.VARIANT.BTS.BLOCKS.  */
+      struct btrace_maint_packet_history packet_history;
+    } bts;
+
+#if defined (HAVE_LIBIPT)
+    /* BTRACE.DATA.FORMAT == BTRACE_FORMAT_PT  */
+    struct
+    {
+      /* A vector of decoded packets.  */
+      VEC (btrace_pt_packet_s) *packets;
+
+      /* The packet history iterator.
+	 We are iterating over the above PACKETS vector.  */
+      struct btrace_maint_packet_history packet_history;
+    } pt;
+#endif /* defined (HAVE_LIBIPT)  */
+  } variant;
+};
+
 /* Branch trace information per thread.
 
    This represents the branch trace configuration as well as the entry point
@@ -284,6 +344,9 @@ struct btrace_thread_info
 
   /* Why the thread stopped, if we need to track it.  */
   enum target_stop_reason stop_reason;
+
+  /* Maintenance information.  */
+  struct btrace_maint_info maint;
 };
 
 /* Enable branch tracing for a thread.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d3000e5..9245185 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33965,6 +33965,66 @@ Shared library events.
 This prints information about each @code{bfd} object that is known to
 @value{GDBN}.  @xref{Top, , BFD, bfd, The Binary File Descriptor Library}.
 
+@kindex maint info btrace
+@item maint info btrace
+This prints information about raw branch tracing data.
+
+@kindex maint btrace packet-history
+@item maint btrace packet-history
+Print the raw branch trace packets that are used to compute the
+execution history for the @samp{record btrace} command.  The
+information printed as well as the format depends on the btrace
+recording format.
+
+@table @code
+@item bts
+For the BTS recording format, it prints a list of blocks of sequential
+code.  For each block, the following information is printed:
+
+@table @code
+@item The block number
+Newer blocks have higher numbers.  The oldest block has number zero.
+@item The lowest @samp{PC}
+@item The highest @samp{PC}
+@end table
+
+@item pt
+For the Intel(R) Processor Trace recording format, it prints a list of
+Intel(R) Processor Trace packets.  For each packet, the following
+information is printed:
+
+@table @code
+@item The packet number
+Newer packets have higher numbers.  The oldest packet has number zero.
+@item The trace offset
+The packet's offset in the trace stream.
+@item The packet opcode and payload
+@end table
+@end table
+
+@kindex maint btrace clear-packet-history
+@item maint btrace clear-packet-history
+Discards the cached packet history printed by the @samp{maint btrace
+packet-history} command.  The history will be computed again when
+needed.
+
+@kindex maint btrace clear
+@item maint btrace clear
+Discard the branch trace data.  The data will be fetched anew and the
+branch trace will be recomputed when needed.
+
+This implicitly truncates the branch trace to a single branch trace
+buffer.  When updating branch trace incrementally, the branch trace
+available to @value{GDBN} may be bigger than a single branch trace
+buffer.
+
+@kindex maint set btrace pt skip-pad
+@item maint set btrace pt skip-pad
+@kindex maint show btrace pt skip-pad
+@item maint show btrace pt skip-pad
+Control whether @value{GDBN} will skip PAD packets when computing the
+packet history.
+
 @kindex set displaced-stepping
 @kindex show displaced-stepping
 @cindex displaced stepping support
-- 
1.8.3.1

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

* [PATCH 0/5] Support Intel(R) Processor Trace
@ 2015-06-23  8:22 Markus Metzger
  2015-06-23  8:22 ` [PATCH 4/5] btrace: store raw btrace data Markus Metzger
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Markus Metzger @ 2015-06-23  8:22 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

Processor Trace (PT) is a new h/w tracing feature available with the 5th
generation Core processor.

It allows recording control-flow execution trace similar to Branch Trace Store
(BTS), which is already supported by GDB via the "record btrace" command.
PT is also integrated into GDB's record framework and enabled via the "record
btrace" or the "record btrace pt" command.  The former falls back to BTS, if
PT is not available.

Compared to BTS, PT is more compact and significantly less intrusive.  This
means longer traces and less recording overhead.

The PT driver has been merged into kernel 4.1.  This patch series adds GDB
support.  The actual decode is done in a separate library that is available
open source on github:

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

Markus Metzger (5):
  configure: check for libipt
  btrace: support Intel(R) Processor Trace
  btrace, linux: use data_size and data_offset
  btrace: store raw btrace data
  btrace: maintenance commands

 gdb/Makefile.in              |    5 +-
 gdb/NEWS                     |   27 +
 gdb/btrace.c                 | 1134 +++++++++++++++++++++++++++++++++++++++++-
 gdb/btrace.h                 |   85 ++++
 gdb/common/btrace-common.c   |   97 ++++
 gdb/common/btrace-common.h   |   48 +-
 gdb/config.in                |    3 +
 gdb/configure                |  498 +++++++++++++++++++
 gdb/configure.ac             |   20 +
 gdb/doc/gdb.texinfo          |  187 ++++++-
 gdb/features/btrace-conf.dtd |    7 +-
 gdb/features/btrace.dtd      |   16 +-
 gdb/gdbserver/linux-low.c    |   85 +++-
 gdb/gdbserver/server.c       |   51 +-
 gdb/nat/linux-btrace.c       |  398 ++++++++++++++-
 gdb/nat/linux-btrace.h       |   19 +
 gdb/record-btrace.c          |  139 +++++-
 gdb/remote.c                 |   65 ++-
 18 files changed, 2841 insertions(+), 43 deletions(-)

-- 
1.8.3.1

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

* [PATCH 2/5] btrace: support Intel(R) Processor Trace
  2015-06-23  8:22 [PATCH 0/5] Support Intel(R) Processor Trace Markus Metzger
                   ` (3 preceding siblings ...)
  2015-06-23  8:22 ` [PATCH 1/5] configure: check for libipt Markus Metzger
@ 2015-06-23  8:23 ` Markus Metzger
  2015-06-23 15:32   ` Eli Zaretskii
  2015-06-30 12:56   ` Pedro Alves
  4 siblings, 2 replies; 20+ messages in thread
From: Markus Metzger @ 2015-06-23  8:23 UTC (permalink / raw)
  To: palves; +Cc: gdb-patches

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

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

Intel Processor Trace support requires kernel 4.1 and libipt.

2015-06-23  Markus Metzger  <markus.t.metzger@intel.com>

gdb/
	* NEWS: Announce new commands "record btrace pt" and "record pt".
	Announce new options "set|show record btrace pt buffer-size".
	* btrace.c: Include "rsp-low.h".
	Include "inttypes.h".
	(btrace_add_pc): Add forward declaration.
	(pt_reclassify_insn, ftrace_add_pt, btrace_pt_readmem_callback)
	(pt_translate_cpu_vendor, btrace_compute_ftrace_pt): New.
	(btrace_compute_ftrace): Support BTRACE_FORMAT_PT.
	(check_xml_btrace_version): Update version check.
	(parse_xml_raw, parse_xml_btrace_pt_config_cpu)
	(parse_xml_btrace_pt_raw, parse_xml_btrace_pt)
	(btrace_pt_config_cpu_attributes, btrace_pt_config_children)
	(btrace_pt_children): New.
	(btrace_children): Add support for "pt".
	(parse_xml_btrace_conf_pt, btrace_conf_pt_attributes): New.
	(btrace_conf_children): Add support for "pt".
	* btrace.h: Include "intel-pt.h".
	(btrace_pt_error): New.
	* common/btrace-common.c (btrace_format_string, btrace_data_fini)
	(btrace_data_empty): Support BTRACE_FORMAT_PT.
	* common/btrace-common.h (btrace_format): Add BTRACE_FORMAT_PT.
	(struct btrace_config_pt): New.
	(struct btrace_config)<pt>: New.
	(struct btrace_data_pt_config, struct btrace_data_pt): New.
	(struct btrace_data)<pt>: New.
	* features/btrace-conf.dtd (btrace-conf)<pt>: New.
	(pt): New.
	* features/btrace.dtd (btrace)<pt>: New.
	(pt, pt-config, cpu): New.
	* nat/linux-btrace.c (perf_event_read, perf_event_read_all)
	(perf_event_pt_event_type, kernel_supports_pt)
	(linux_supports_pt): New.
	(linux_supports_btrace): Support BTRACE_FORMAT_PT.
	(linux_enable_bts): Free tinfo on error.
	(linux_enable_pt): New.
	(linux_enable_btrace): Support BTRACE_FORMAT_PT.
	(linux_disable_pt): New.
	(linux_disable_btrace): Support BTRACE_FORMAT_PT.
	(linux_fill_btrace_pt_config, linux_read_pt): New.
	(linux_read_btrace): Support BTRACE_FORMAT_PT.
	* nat/linux-btrace.h (struct btrace_tinfo_pt): New.
	(struct btrace_target_info)<pt>: New.
	* record-btrace.c (set_record_btrace_pt_cmdlist)
	(show_record_btrace_pt_cmdlist): New.
	(record_btrace_print_pt_conf): New.
	(record_btrace_print_conf): Support BTRACE_FORMAT_PT.
	(btrace_ui_out_decode_error): Support BTRACE_FORMAT_PT.
	(cmd_record_btrace_pt_start): New.
	(cmd_record_btrace_start): Support BTRACE_FORMAT_PT.
	(cmd_set_record_btrace_pt, cmd_show_record_btrace_pt): New.
	(_initialize_record_btrace): Add new commands.
	* remote.c (PACKET_Qbtrace_pt, PACKET_Qbtrace_conf_pt_size): New.
	(remote_protocol_features): Add "Qbtrace:pt".
	Add "Qbtrace-conf:pt:size".
	(remote_supports_btrace): Support BTRACE_FORMAT_PT.
	(btrace_sync_conf): Support PACKET_Qbtrace_conf_pt_size.
	(remote_enable_btrace): Support BTRACE_FORMAT_PT.
	(_initialize_remote): Add new commands.

gdbserver/
	* linux-low.c: Include "rsp-low.h"
	(linux_low_encode_pt_config, linux_low_encode_raw): New.
	(linux_low_read_btrace): Support BTRACE_FORMAT_PT.
	(linux_low_btrace_conf): Support BTRACE_FORMAT_PT.
	(handle_btrace_enable_pt): New.
	(handle_btrace_general_set): Support "pt".
	(handle_btrace_conf_general_set): Support "pt:size".

doc/
	* gdb.texinfo (Process Record and Replay): Spell out that variables
	and registers are not available during btrace replay.
	Describe the new "record btrace pt" command.
	Describe the new "set|show record btrace pt buffer-size" options.
	(General Query Packets): Describe the new Qbtrace:pt and
	Qbtrace-conf:pt:size packets.
	Expand "bts" to "Branch Trace Store".
	Update the branch trace DTD.
---
 gdb/NEWS                     |  10 ++
 gdb/btrace.c                 | 407 ++++++++++++++++++++++++++++++++++++++++++-
 gdb/btrace.h                 |  19 ++
 gdb/common/btrace-common.c   |  10 ++
 gdb/common/btrace-common.h   |  39 ++++-
 gdb/doc/gdb.texinfo          | 127 ++++++++++++--
 gdb/features/btrace-conf.dtd |   7 +-
 gdb/features/btrace.dtd      |  16 +-
 gdb/gdbserver/linux-low.c    |  85 ++++++++-
 gdb/gdbserver/server.c       |  51 +++++-
 gdb/nat/linux-btrace.c       | 377 ++++++++++++++++++++++++++++++++++++++-
 gdb/nat/linux-btrace.h       |  19 ++
 gdb/record-btrace.c          | 139 ++++++++++++++-
 gdb/remote.c                 |  65 ++++++-
 14 files changed, 1334 insertions(+), 37 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 3ec5851..9ab64bf 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -112,6 +112,10 @@ show mpx bound
 set mpx bound on i386 and amd64
    Support for bound table investigation on Intel(R) MPX enabled applications.
 
+record btrace pt
+record pt
+  Start branch trace recording using Intel(R) Processor Trace format.
+
 * New options
 
 set debug dwarf-die
@@ -159,6 +163,12 @@ set debug linux-namespaces
 show debug linux-namespaces
   Control display of debugging info regarding Linux namespaces.
 
+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.
+
 * The command 'thread apply all' can now support new option '-ascending'
   to call its specified command for all threads in ascending order.
 
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 68057c5..d3cdd19 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.  */
@@ -686,6 +691,249 @@ btrace_compute_ftrace_bts (struct thread_info *tp,
   btinfo->level = -level;
 }
 
+#if defined (HAVE_LIBIPT)
+
+static enum btrace_insn_class
+pt_reclassify_insn (enum pt_insn_class iclass)
+{
+  switch (iclass)
+    {
+    case ptic_call:
+      return BTRACE_INSN_CALL;
+
+    case ptic_return:
+      return BTRACE_INSN_RETURN;
+
+    case ptic_jump:
+      return BTRACE_INSN_JUMP;
+
+    default:
+      return BTRACE_INSN_OTHER;
+    }
+}
+
+/* Add function branch trace using DECODER.  */
+
+static void
+ftrace_add_pt (struct pt_insn_decoder *decoder,
+	       struct btrace_function **pbegin,
+	       struct btrace_function **pend, int *plevel,
+	       unsigned int *ngaps)
+{
+  struct btrace_function *begin, *end, *upd;
+  uint64_t offset;
+  int errcode, nerrors;
+
+  begin = *pbegin;
+  end = *pend;
+  nerrors = 0;
+  for (;;)
+    {
+      struct btrace_insn btinsn;
+      struct pt_insn insn;
+
+      errcode = pt_insn_sync_forward (decoder);
+      if (errcode < 0)
+	{
+	  if (errcode != -pte_eos)
+	    warning (_("Failed to synchronize onto the Intel(R) Processor "
+		       "Trace stream: %s."), pt_errstr (pt_errcode (errcode)));
+	  break;
+	}
+
+      memset (&btinsn, 0, sizeof (btinsn));
+      for (;;)
+	{
+	  errcode = pt_insn_next (decoder, &insn, sizeof(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);
+	}
+
+      if (errcode == -pte_eos)
+	break;
+
+      /* If the gap is at the very beginning, we ignore it - we will have
+	 less trace, but we won't have any holes in the trace.  */
+      if (begin == NULL)
+	continue;
+
+      pt_insn_get_offset (decoder, &offset);
+
+      warning (_("Failed to decode Intel(R) Processor Trace near trace "
+		 "offset 0x%" PRIx64 " near recorded PC 0x%" PRIx64 ": %s."),
+	       offset, insn.ip, pt_errstr (pt_errcode (errcode)));
+
+      /* Indicate the gap in the trace.  */
+      *pend = end = ftrace_new_gap (end, errcode);
+      *ngaps += 1;
+    }
+
+  if (nerrors > 0)
+    warning (_("The recorded execution trace may have gaps."));
+}
+
+/* A callback function to allow the trace decoder to read the inferior's
+   memory.  */
+
+static int
+btrace_pt_readmem_callback (gdb_byte *buffer, size_t size,
+			    const struct pt_asid *asid, CORE_ADDR pc,
+			    void *context)
+{
+  int errcode;
+
+  TRY
+    {
+      errcode = target_read_code (pc, buffer, size);
+      if (errcode != 0)
+	return -pte_nomap;
+    }
+  CATCH (error, RETURN_MASK_ERROR)
+    {
+      return -pte_nomap;
+    }
+  END_CATCH
+
+  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)
+{
+  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;
+
+  pt_config_init(&config);
+  config.begin = btrace->data;
+  config.end = btrace->data + btrace->size;
+
+  config.cpu.vendor = pt_translate_cpu_vendor (btrace->config.cpu.vendor);
+  config.cpu.family = btrace->config.cpu.family;
+  config.cpu.model = btrace->config.cpu.model;
+  config.cpu.stepping = btrace->config.cpu.stepping;
+
+  errcode = pt_cpu_errata (&config.errata, &config.cpu);
+  if (errcode < 0)
+    error (_("Failed to configure the Intel(R) Processor Trace decoder: %s."),
+	   pt_errstr (pt_errcode (errcode)));
+
+  decoder = pt_insn_alloc_decoder (&config);
+  if (decoder == NULL)
+    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
+
+  TRY
+    {
+      struct pt_image *image;
+
+      image = pt_insn_get_image(decoder);
+      if (image == NULL)
+	error (_("Failed to configure the Intel(R) Processor Trace decoder."));
+
+      errcode = pt_image_set_callback(image, btrace_pt_readmem_callback, NULL);
+      if (errcode < 0)
+	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
+		 "%s."), pt_errstr (pt_errcode (errcode)));
+
+      ftrace_add_pt (decoder, &btinfo->begin, &btinfo->end, &level,
+		     &btinfo->ngaps);
+    }
+  CATCH (error, RETURN_MASK_ALL)
+    {
+      /* Indicate a gap in the trace if we quit trace processing.  Errors were
+	 already logged before.  */
+      if (error.reason == RETURN_QUIT && btinfo->end != NULL)
+	{
+	  btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
+	  btinfo->ngaps++;
+	}
+    }
+  END_CATCH
+
+  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;
+
+  /* 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);
+}
+
+#else /* defined (HAVE_LIBIPT)  */
+
+static void
+btrace_compute_ftrace_pt (struct thread_info *tp,
+			  const struct btrace_data_pt *btrace)
+{
+  internal_error (__FILE__, __LINE__, _("Unexpected branch trace format."));
+}
+
+#endif /* defined (HAVE_LIBIPT)  */
+
 /* Compute the function branch trace from a block branch trace BTRACE for
    a thread given by BTINFO.  */
 
@@ -702,6 +950,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."));
@@ -911,6 +1163,10 @@ btrace_stitch_trace (struct btrace_data *btrace, struct thread_info *tp)
 
     case BTRACE_FORMAT_BTS:
       return btrace_stitch_bts (&btrace->variant.bts, tp);
+
+    case BTRACE_FORMAT_PT:
+      /* Delta reads are not supported.  */
+      return -1;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -1056,7 +1312,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);
 }
 
@@ -1095,12 +1351,131 @@ parse_xml_btrace_block (struct gdb_xml_parser *parser,
   block->end = *end;
 }
 
+/* Parse a "raw" xml record.  */
+
+static void
+parse_xml_raw (struct gdb_xml_parser *parser, const char *body_text,
+	       gdb_byte **pdata, unsigned long *psize)
+{
+  struct cleanup *cleanup;
+  gdb_byte *data, *bin;
+  unsigned long size;
+  size_t len;
+
+  len = strlen (body_text);
+  size = len / 2;
+
+  if ((size_t) size * 2 != len)
+    gdb_xml_error (parser, _("Bad raw data size."));
+
+  bin = data = xmalloc (size);
+  cleanup = make_cleanup (xfree, data);
+
+  /* We use hex encoding - see common/rsp-low.h.  */
+  while (len > 0)
+    {
+      char hi, lo;
+
+      hi = *body_text++;
+      lo = *body_text++;
+
+      if (hi == 0 || lo == 0)
+	gdb_xml_error (parser, _("Bad hex encoding."));
+
+      *bin++ = fromhex (hi) * 16 + fromhex (lo);
+      len -= 2;
+    }
+
+  discard_cleanups (cleanup);
+
+  *pdata = data;
+  *psize = size;
+}
+
+/* Parse a btrace pt-config "cpu" xml record.  */
+
+static void
+parse_xml_btrace_pt_config_cpu (struct gdb_xml_parser *parser,
+				const struct gdb_xml_element *element,
+				void *user_data,
+				VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_data *btrace;
+  const char *vendor;
+  ULONGEST *family, *model, *stepping;
+
+  vendor = xml_find_attribute (attributes, "vendor")->value;
+  family = xml_find_attribute (attributes, "family")->value;
+  model = xml_find_attribute (attributes, "model")->value;
+  stepping = xml_find_attribute (attributes, "stepping")->value;
+
+  btrace = user_data;
+
+  if (strcmp (vendor, "GenuineIntel") == 0)
+    btrace->variant.pt.config.cpu.vendor = CV_INTEL;
+
+  btrace->variant.pt.config.cpu.family = *family;
+  btrace->variant.pt.config.cpu.model = *model;
+  btrace->variant.pt.config.cpu.stepping = *stepping;
+}
+
+/* Parse a btrace pt "raw" xml record.  */
+
+static void
+parse_xml_btrace_pt_raw (struct gdb_xml_parser *parser,
+			 const struct gdb_xml_element *element,
+			 void *user_data, const char *body_text)
+{
+  struct btrace_data *btrace;
+
+  btrace = user_data;
+  parse_xml_raw (parser, body_text, &btrace->variant.pt.data,
+		 &btrace->variant.pt.size);
+}
+
+/* Parse a btrace "pt" xml record.  */
+
+static void
+parse_xml_btrace_pt (struct gdb_xml_parser *parser,
+		     const struct gdb_xml_element *element,
+		     void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_data *btrace;
+
+  btrace = user_data;
+  btrace->format = BTRACE_FORMAT_PT;
+  btrace->variant.pt.config.cpu.vendor = CV_UNKNOWN;
+  btrace->variant.pt.data = NULL;
+  btrace->variant.pt.size = 0;
+}
+
 static const struct gdb_xml_attribute block_attributes[] = {
   { "begin", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { "end", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
+static const struct gdb_xml_attribute btrace_pt_config_cpu_attributes[] = {
+  { "vendor", GDB_XML_AF_NONE, NULL, NULL },
+  { "family", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "model", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "stepping", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_pt_config_children[] = {
+  { "cpu", btrace_pt_config_cpu_attributes, NULL, GDB_XML_EF_OPTIONAL,
+    parse_xml_btrace_pt_config_cpu, NULL },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element btrace_pt_children[] = {
+  { "pt-config", NULL, btrace_pt_config_children, GDB_XML_EF_OPTIONAL, NULL,
+    NULL },
+  { "raw", NULL, NULL, GDB_XML_EF_OPTIONAL, NULL, parse_xml_btrace_pt_raw },
+  { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute btrace_attributes[] = {
   { "version", GDB_XML_AF_NONE, NULL, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
@@ -1109,6 +1484,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 }
 };
 
@@ -1166,9 +1543,33 @@ parse_xml_btrace_conf_bts (struct gdb_xml_parser *parser,
 
   size = xml_find_attribute (attributes, "size");
   if (size != NULL)
-    conf->bts.size = (unsigned int) * (ULONGEST *) size->value;
+    conf->bts.size = (unsigned int) *(ULONGEST *) size->value;
 }
 
+/* Parse a btrace-conf "pt" xml record.  */
+
+static void
+parse_xml_btrace_conf_pt (struct gdb_xml_parser *parser,
+			  const struct gdb_xml_element *element,
+			  void *user_data, VEC (gdb_xml_value_s) *attributes)
+{
+  struct btrace_config *conf;
+  struct gdb_xml_value *size;
+
+  conf = user_data;
+  conf->format = BTRACE_FORMAT_PT;
+  conf->pt.size = 0;
+
+  size = xml_find_attribute (attributes, "size");
+  if (size != NULL)
+    conf->pt.size = (unsigned int) *(ULONGEST *) size->value;
+}
+
+static const struct gdb_xml_attribute btrace_conf_pt_attributes[] = {
+  { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute btrace_conf_bts_attributes[] = {
   { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
@@ -1177,6 +1578,8 @@ static const struct gdb_xml_attribute btrace_conf_bts_attributes[] = {
 static const struct gdb_xml_element btrace_conf_children[] = {
   { "bts", btrace_conf_bts_attributes, NULL, GDB_XML_EF_OPTIONAL,
     parse_xml_btrace_conf_bts, NULL },
+  { "pt", btrace_conf_pt_attributes, NULL, GDB_XML_EF_OPTIONAL,
+    parse_xml_btrace_conf_pt, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
diff --git a/gdb/btrace.h b/gdb/btrace.h
index b7437f1..c25dc84 100644
--- a/gdb/btrace.h
+++ b/gdb/btrace.h
@@ -29,6 +29,10 @@
 #include "btrace-common.h"
 #include "target/waitstatus.h" /* For enum target_stop_reason.  */
 
+#if defined (HAVE_LIBIPT)
+#  include <intel-pt.h>
+#endif
+
 struct thread_info;
 struct btrace_function;
 
@@ -97,6 +101,21 @@ enum btrace_bts_error
   BDE_BTS_INSN_SIZE
 };
 
+/* Decode errors for the Intel(R) 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 0ea50f0..676428e 100644
--- a/gdb/common/btrace-common.c
+++ b/gdb/common/btrace-common.c
@@ -33,6 +33,9 @@ btrace_format_string (enum btrace_format format)
 
     case BTRACE_FORMAT_BTS:
       return _("Branch Trace Store");
+
+    case BTRACE_FORMAT_PT:
+      return _("Intel(R) Processor Trace");
     }
 
   internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
@@ -60,6 +63,10 @@ btrace_data_fini (struct btrace_data *data)
     case BTRACE_FORMAT_BTS:
       VEC_free (btrace_block_s, data->variant.bts.blocks);
       return;
+
+    case BTRACE_FORMAT_PT:
+      xfree (data->variant.pt.data);
+      return;
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
@@ -77,6 +84,9 @@ btrace_data_empty (struct btrace_data *data)
 
     case BTRACE_FORMAT_BTS:
       return VEC_empty (btrace_block_s, data->variant.bts.blocks);
+
+    case BTRACE_FORMAT_PT:
+      return (data->variant.pt.size == 0);
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
diff --git a/gdb/common/btrace-common.h b/gdb/common/btrace-common.h
index ba99a06..ebae17e 100644
--- a/gdb/common/btrace-common.h
+++ b/gdb/common/btrace-common.h
@@ -58,7 +58,10 @@ enum btrace_format
 
   /* Branch trace is in Branch Trace Store (BTS) format.
      Actually, the format is a sequence of blocks derived from BTS.  */
-  BTRACE_FORMAT_BTS
+  BTRACE_FORMAT_BTS,
+
+  /* Branch trace is in Intel(R) Processor Trace format.  */
+  BTRACE_FORMAT_PT
 };
 
 /* An enumeration of cpu vendors.  */
@@ -97,6 +100,14 @@ struct btrace_config_bts
   unsigned int size;
 };
 
+/* An Intel(R) Processor Trace configuration.  */
+
+struct btrace_config_pt
+{
+  /* The size of the branch trace buffer in bytes.  */
+  unsigned int size;
+};
+
 /* A branch tracing configuration.
 
    This describes the requested configuration as well as the actually
@@ -111,6 +122,9 @@ struct btrace_config
 
   /* The BTS format configuration.  */
   struct btrace_config_bts bts;
+
+  /* The Intel(R) Processor Trace format configuration.  */
+  struct btrace_config_pt pt;
 };
 
 /* Branch trace in BTS format.  */
@@ -121,6 +135,26 @@ struct btrace_data_bts
   VEC (btrace_block_s) *blocks;
 };
 
+/* Configuration information to go with the trace data.  */
+struct btrace_data_pt_config
+{
+  /* The processor on which the trace has been collected.  */
+  struct btrace_cpu cpu;
+};
+
+/* Branch trace in Intel(R) Processor Trace format.  */
+struct btrace_data_pt
+{
+  /* Some configuration information to go with the data.  */
+  struct btrace_data_pt_config config;
+
+  /* The trace data.  */
+  gdb_byte *data;
+
+  /* The size of DATA in bytes.  */
+  unsigned long size;
+};
+
 /* The branch trace data.  */
 struct btrace_data
 {
@@ -130,6 +164,9 @@ struct btrace_data
   {
     /* Format == BTRACE_FORMAT_BTS.  */
     struct btrace_data_bts bts;
+
+    /* Format == BTRACE_FORMAT_PT.  */
+    struct btrace_data_pt pt;
   } variant;
 };
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c9a532a..d3000e5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6417,12 +6417,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
@@ -6438,8 +6442,9 @@ execution.
 @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.
+be overwritten when the buffer is full.  It allows limited reverse
+execution.  Variables and registers are not available during reverse
+execution.
 
 The recording format can be specified as parameter.  Without a parameter
 the command chooses the recording format.  The following recording
@@ -6451,6 +6456,21 @@ formats are available:
 Use the @dfn{Branch Trace Store} (@acronym{BTS}) recording format.  In
 this format, the processor stores a from/to record for each executed
 branch in the btrace ring buffer.
+
+@item pt
+@cindex Intel(R) Processor Trace
+Use the @dfn{Intel(R) 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 @acronym{BTS}.
+
+Decoding the recorded execution trace, on the other hand, is more
+expensive than decoding @acronym{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.
@@ -6461,9 +6481,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
@@ -6629,6 +6646,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 @acronym{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(R)
+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(R) 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(R) Processor Trace format.
+
 @kindex info record
 @item info record
 Show various statistics about the recording depending on the recording
@@ -6674,6 +6714,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
@@ -36279,11 +36325,21 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab Yes
 
+@item @samp{Qbtrace:pt}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
 @item @samp{Qbtrace-conf:bts:size}
 @tab Yes
 @tab @samp{-}
 @tab Yes
 
+@item @samp{Qbtrace-conf:pt:size}
+@tab Yes
+@tab @samp{-}
+@tab Yes
+
 @item @samp{QNonStop}
 @tab No
 @tab @samp{-}
@@ -36565,9 +36621,15 @@ The remote stub understands the @samp{Qbtrace:off} packet.
 @item Qbtrace:bts
 The remote stub understands the @samp{Qbtrace:bts} packet.
 
+@item Qbtrace:pt
+The remote stub understands the @samp{Qbtrace:pt} packet.
+
 @item Qbtrace-conf:bts:size
 The remote stub understands the @samp{Qbtrace-conf:bts:size} packet.
 
+@item Qbtrace-conf:pt:size
+The remote stub understands the @samp{Qbtrace-conf:pt:size} packet.
+
 @item swbreak
 The remote stub reports the @samp{swbreak} stop reason for memory
 breakpoints.
@@ -37012,7 +37074,18 @@ A badly formed request or an error was encountered.
 @end table
 
 @item Qbtrace:bts
-Enable branch tracing for the current thread using bts tracing.
+Enable branch tracing for the current thread using Branch Trace Store.
+
+Reply:
+@table @samp
+@item OK
+Branch tracing has been enabled.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
+@item Qbtrace:pt
+Enable branch tracing for the current thread using Intel(R) Processor Trace.
 
 Reply:
 @table @samp
@@ -37045,6 +37118,18 @@ The ring buffer size has been set.
 A badly formed request or an error was encountered.
 @end table
 
+@item Qbtrace-conf:pt:size=@var{value}
+Set the requested ring buffer size for new threads that use the
+btrace recording method in pt format.
+
+Reply:
+@table @samp
+@item OK
+The ring buffer size has been set.
+@item E.errtext
+A badly formed request or an error was encountered.
+@end table
+
 @end table
 
 @node Architecture-Specific Protocol Details
@@ -39596,12 +39681,24 @@ and ending at @var{end}:
 The formal DTD for the branch trace format is given below:
 
 @smallexample
-<!ELEMENT btrace  (block)* >
-<!ATTLIST btrace  version CDATA   #FIXED "1.0">
+<!ELEMENT btrace  (block* | pt) >
+<!ATTLIST btrace  version CDATA   #FIXED "2.0">
 
 <!ELEMENT block        EMPTY>
 <!ATTLIST block        begin  CDATA   #REQUIRED
                        end    CDATA   #REQUIRED>
+
+<!ELEMENT pt (pt-config?, raw?)>
+
+<!ELEMENT pt-config (cpu?)>
+
+<!ELEMENT cpu EMPTY>
+<!ATTLIST cpu vendor   CDATA #REQUIRED
+              family   CDATA #REQUIRED
+              model    CDATA #REQUIRED
+              stepping CDATA #REQUIRED>
+
+<!ELEMENT raw (#PCDATA)>
 @end smallexample
 
 @node Branch Trace Configuration Format
@@ -39622,6 +39719,13 @@ This thread uses the @dfn{Branch Trace Store} (@acronym{BTS}) format.
 @item size
 The size of the @acronym{BTS} ring buffer in bytes.
 @end table
+@item pt
+This thread uses the @dfn{Intel(R) Processor Trace} (@acronym{Intel(R)
+PT}) format.
+@table @code
+@item size
+The size of the @acronym{Intel(R) PT} ring buffer in bytes.
+@end table
 @end table
 
 @value{GDBN} must be linked with the Expat library to support XML
@@ -39630,11 +39734,14 @@ branch trace configuration discovery.  @xref{Expat}.
 The formal DTD for the branch trace configuration format is given below:
 
 @smallexample
-<!ELEMENT btrace-conf	(bts?)>
-<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
+<!ELEMENT btrace-conf	(bts?, pt?)>
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "2.0">
 
 <!ELEMENT bts	EMPTY>
 <!ATTLIST bts	size	CDATA	#IMPLIED>
+
+<!ELEMENT pt	EMPTY>
+<!ATTLIST pt	size	CDATA	#IMPLIED>
 @end smallexample
 
 @include agentexpr.texi
diff --git a/gdb/features/btrace-conf.dtd b/gdb/features/btrace-conf.dtd
index 588bb80..35f9413 100644
--- a/gdb/features/btrace-conf.dtd
+++ b/gdb/features/btrace-conf.dtd
@@ -4,8 +4,11 @@
      are permitted in any medium without royalty provided the copyright
      notice and this notice are preserved.  -->
 
-<!ELEMENT btrace-conf	(bts?)>
-<!ATTLIST btrace-conf	version	CDATA	#FIXED "1.0">
+<!ELEMENT btrace-conf	(bts?, pt?)>
+<!ATTLIST btrace-conf	version	CDATA	#FIXED "2.0">
 
 <!ELEMENT bts	EMPTY>
 <!ATTLIST bts	size	CDATA	#IMPLIED>
+
+<!ELEMENT pt	EMPTY>
+<!ATTLIST pt	size	CDATA	#IMPLIED>
diff --git a/gdb/features/btrace.dtd b/gdb/features/btrace.dtd
index 7fffc3c..3bc622d 100644
--- a/gdb/features/btrace.dtd
+++ b/gdb/features/btrace.dtd
@@ -4,9 +4,21 @@
      are permitted in any medium without royalty provided the copyright
      notice and this notice are preserved.  -->
 
-<!ELEMENT btrace  (block)* >
-<!ATTLIST btrace  version CDATA   #FIXED "1.0">
+<!ELEMENT btrace  (block* | pt)>
+<!ATTLIST btrace  version CDATA   #FIXED "2.0">
 
 <!ELEMENT block        EMPTY>
 <!ATTLIST block        begin  CDATA   #REQUIRED
                        end    CDATA   #REQUIRED>
+
+<!ELEMENT pt (pt-config?, raw?)>
+
+<!ELEMENT pt-config (cpu?)>
+
+<!ELEMENT cpu EMPTY>
+<!ATTLIST cpu vendor   CDATA #REQUIRED
+              family   CDATA #REQUIRED
+              model    CDATA #REQUIRED
+              stepping CDATA #REQUIRED>
+
+<!ELEMENT raw (#PCDATA)>
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 3774d17..ad95b74 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -21,6 +21,7 @@
 #include "nat/linux-osdata.h"
 #include "agent.h"
 #include "tdesc.h"
+#include "rsp-low.h"
 
 #include "nat/linux-nat.h"
 #include "nat/linux-waitpid.h"
@@ -6461,6 +6462,55 @@ linux_low_disable_btrace (struct btrace_target_info *tinfo)
   return (err == BTRACE_ERR_NONE ? 0 : -1);
 }
 
+/* Encode an Intel(R) 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
@@ -6482,15 +6532,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");
@@ -6505,15 +6554,31 @@ linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
       buffer_grow_str0 (buffer, "</btrace>\n");
       break;
 
-    default:
-      buffer_grow_str0 (buffer, "E.Unknown Trace Format.");
+    case BTRACE_FORMAT_PT:
+      buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
+      buffer_grow_str (buffer, "<btrace version=\"2.0\">\n");
+      buffer_grow_str (buffer, "<pt>\n");
+
+      linux_low_encode_pt_config (buffer, &btrace.variant.pt.config);
 
-      btrace_data_fini (&btrace);
-      return -1;
+      linux_low_encode_raw (buffer, btrace.variant.pt.data,
+			    btrace.variant.pt.size);
+
+      buffer_grow_str (buffer, "</pt>\n");
+      buffer_grow_str0 (buffer, "</btrace>\n");
+      break;
+
+    default:
+      buffer_grow_str0 (buffer, "E.Unsupported Trace Format.");
+      goto err;
     }
 
   btrace_data_fini (&btrace);
   return 0;
+
+err:
+  btrace_data_fini (&btrace);
+  return -1;
 }
 
 /* See to_btrace_conf target method.  */
@@ -6540,6 +6605,12 @@ linux_low_btrace_conf (const struct btrace_target_info *tinfo,
 	  buffer_xml_printf (buffer, " size=\"0x%x\"", conf->bts.size);
 	  buffer_xml_printf (buffer, " />\n");
 	  break;
+
+	case BTRACE_FORMAT_PT:
+	  buffer_xml_printf (buffer, "<pt");
+	  buffer_xml_printf (buffer, " size=\"0x%x\"", conf->pt.size);
+	  buffer_xml_printf (buffer, "/>\n");
+	  break;
 	}
     }
 
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index c9effc2..7e388dd 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -408,6 +408,23 @@ handle_btrace_enable_bts (struct thread_info *thread)
   return NULL;
 }
 
+/* Handle btrace enabling in Intel(R) 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 *
@@ -456,10 +473,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);
@@ -511,6 +530,21 @@ handle_btrace_conf_general_set (char *own_buf)
 
       current_btrace_conf.bts.size = (unsigned int) size;
     }
+  else if (strncmp (op, "pt:size=", strlen ("pt:size=")) == 0)
+    {
+      unsigned long size;
+      char *endp = NULL;
+
+      errno = 0;
+      size = strtoul (op + strlen ("pt:size="), &endp, 16);
+      if (endp == NULL || *endp != 0 || errno != 0 || size > UINT_MAX)
+	{
+	  strcpy (own_buf, "E.Bad size value.");
+	  return -1;
+	}
+
+      current_btrace_conf.pt.size = (unsigned int) size;
+    }
   else
     {
       strcpy (own_buf, "E.Bad Qbtrace configuration option.");
@@ -1871,12 +1905,25 @@ crc32 (CORE_ADDR base, int len, unsigned int crc)
 static void
 supported_btrace_packets (char *buf)
 {
+  int btrace_supported = 0;
+
   if (target_supports_btrace (BTRACE_FORMAT_BTS))
     {
       strcat (buf, ";Qbtrace:bts+");
       strcat (buf, ";Qbtrace-conf:bts:size+");
+
+      btrace_supported = 1;
     }
-  else
+
+  if (target_supports_btrace (BTRACE_FORMAT_PT))
+    {
+      strcat (buf, ";Qbtrace:pt+");
+      strcat (buf, ";Qbtrace-conf:pt:size+");
+
+      btrace_supported = 1;
+    }
+
+  if (!btrace_supported)
     return;
 
   strcat (buf, ";Qbtrace:off+");
diff --git a/gdb/nat/linux-btrace.c b/gdb/nat/linux-btrace.c
index e7aff5e..40915da 100644
--- a/gdb/nat/linux-btrace.c
+++ b/gdb/nat/linux-btrace.c
@@ -108,6 +108,87 @@ perf_event_new_data (const struct perf_event_buffer *pev)
    This is the same as the size of a pointer for the inferior process
    except when a 32-bit inferior is running on a 64-bit OS.  */
 
+/* Copy the last SIZE bytes from PEV ending at DATA_HEAD and return a pointer
+   to the memory holding the copy.
+   The caller is responsible for freeing the memory.  */
+
+static gdb_byte *
+perf_event_read (const struct perf_event_buffer *pev, unsigned long data_head,
+		 unsigned long size)
+{
+  const gdb_byte *begin, *end, *start, *stop;
+  gdb_byte *buffer;
+  unsigned long data_tail, buffer_size;
+
+  if (size == 0)
+    return NULL;
+
+  gdb_assert (size <= data_head);
+  data_tail = data_head - size;
+
+  buffer_size = pev->size;
+  begin = pev->mem;
+  start = begin + data_tail % buffer_size;
+  stop = begin + data_head % buffer_size;
+
+  buffer = xmalloc (size);
+
+  if (start < stop)
+    memcpy (buffer, start, stop - start);
+  else
+    {
+      end = begin + buffer_size;
+
+      memcpy (buffer, start, end - start);
+      memcpy (buffer + (end - start), begin, stop - begin);
+    }
+
+  return buffer;
+}
+
+/* Copy the perf event buffer data from PEV.
+   Store a pointer to the copy into DATA and its size in SIZE.  */
+
+static void
+perf_event_read_all (struct perf_event_buffer *pev, gdb_byte **data,
+		     unsigned long *psize)
+{
+  unsigned long data_head, size;
+
+  data_head = *pev->data_head;
+
+  size = pev->size;
+  if (data_head < size)
+    size = data_head;
+
+  *data = perf_event_read (pev, data_head, size);
+  *psize = size;
+
+  pev->last_head = data_head;
+}
+
+/* Determine the event type.
+   Returns zero on success and fills in TYPE; returns -1 otherwise.  */
+
+static int
+perf_event_pt_event_type (int *type)
+{
+  FILE *file;
+  int found;
+
+  file = fopen ("/sys/bus/event_source/devices/intel_pt/type", "r");
+  if (file == NULL)
+    return -1;
+
+  found = fscanf (file, "%d", type);
+
+  fclose (file);
+
+  if (found == 1)
+    return 0;
+  return -1;
+}
+
 static int
 linux_determine_kernel_ptr_bits (void)
 {
@@ -360,6 +441,93 @@ kernel_supports_bts (void)
     }
 }
 
+/* Check whether the kernel supports Intel(R) 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
@@ -430,6 +598,24 @@ linux_supports_bts (void)
   return cached > 0;
 }
 
+/* Check whether the linux target supports Intel(R) Processor Trace.  */
+
+static int
+linux_supports_pt (void)
+{
+  static int cached;
+
+  if (cached == 0)
+    {
+      if (!kernel_supports_pt ())
+	cached = -1;
+      else
+	cached = 1;
+    }
+
+  return cached > 0;
+}
+
 /* See linux-btrace.h.  */
 
 int
@@ -442,6 +628,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"));
@@ -484,7 +673,7 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
   errno = 0;
   bts->file = syscall (SYS_perf_event_open, &bts->attr, pid, -1, -1, 0);
   if (bts->file < 0)
-    goto err;
+    goto err_out;
 
   /* Convert the requested size in bytes to pages (rounding up).  */
   pages = (((unsigned long long) conf->size) + PAGE_SIZE - 1) / PAGE_SIZE;
@@ -533,11 +722,127 @@ linux_enable_bts (ptid_t ptid, const struct btrace_config_bts *conf)
   /* We were not able to allocate any buffer.  */
   close (bts->file);
 
+ err_out:
+  xfree (tinfo);
+  return NULL;
+}
+
+#if defined(PERF_ATTR_SIZE_VER5)
+
+/* Enable branch tracing in Intel(R) Processor Trace format.  */
+
+static struct btrace_target_info *
+linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
+{
+  struct perf_event_mmap_page *header;
+  struct btrace_target_info *tinfo;
+  struct btrace_tinfo_pt *pt;
+  unsigned long long pages, size;
+  int pid, pg, errcode, type;
+
+  if (conf->size == 0)
+    return NULL;
+
+  errcode = perf_event_pt_event_type (&type);
+  if (errcode != 0)
+    return NULL;
+
+  pid = ptid_get_lwp (ptid);
+  if (pid == 0)
+    pid = ptid_get_pid (ptid);
+
+  tinfo = xzalloc (sizeof (*tinfo));
+  tinfo->ptid = ptid;
+  tinfo->ptr_bits = 0;
+
+  tinfo->conf.format = BTRACE_FORMAT_PT;
+  pt = &tinfo->variant.pt;
+
+  pt->attr.size = sizeof (pt->attr);
+  pt->attr.type = type;
+
+  pt->attr.exclude_kernel = 1;
+  pt->attr.exclude_hv = 1;
+  pt->attr.exclude_idle = 1;
+
+  errno = 0;
+  pt->file = syscall (SYS_perf_event_open, &pt->attr, pid, -1, -1, 0);
+  if (pt->file < 0)
+    goto err;
+
+  /* Allocate the configuration page. */
+  header = mmap (NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+		 pt->file, 0);
+  if (header == MAP_FAILED)
+    goto err_file;
+
+  header->aux_offset = header->data_offset + header->data_size;
+
+  /* Convert the requested size in bytes to pages (rounding up).  */
+  pages = (((unsigned long long) conf->size) + PAGE_SIZE - 1) / PAGE_SIZE;
+  /* We need at least one page.  */
+  if (pages == 0)
+    pages = 1;
+
+  /* The buffer size can be requested in powers of two pages.  Adjust PAGES
+     to the next power of two.  */
+  for (pg = 0; pages != (1u << pg); ++pg)
+    if ((pages & (1u << pg)) != 0)
+      pages += (1u << pg);
+
+  /* We try to allocate the requested size.
+     If that fails, try to get as much as we can.  */
+  for (; pages > 0; pages >>= 1)
+    {
+      size_t length;
+
+      size = pages * PAGE_SIZE;
+      length = size;
+
+      /* Check for overflows.  */
+      if ((unsigned long long) length < size)
+	continue;
+
+      header->aux_size = size;
+
+      pt->pt.mem = mmap (NULL, length, PROT_READ, MAP_SHARED, pt->file,
+			 header->aux_offset);
+      if (pt->pt.mem != MAP_FAILED)
+	break;
+    }
+
+  if (pages == 0)
+    goto err_conf;
+
+  pt->header = header;
+  pt->pt.size = size;
+  pt->pt.data_head = &header->aux_head;
+
+  tinfo->conf.pt.size = size;
+  return tinfo;
+
+ err_conf:
+  munmap((void *) header, PAGE_SIZE);
+
+ err_file:
+  close (pt->file);
+
  err:
   xfree (tinfo);
   return NULL;
 }
 
+#else /* !defined(PERF_ATTR_SIZE_VER5) */
+
+static struct btrace_target_info *
+linux_enable_pt (ptid_t ptid, const struct btrace_config_pt *conf)
+{
+  errno = EOPNOTSUPP;
+  return NULL;
+}
+
+#endif /* !defined(PERF_ATTR_SIZE_VER5) */
+
 /* See linux-btrace.h.  */
 
 struct btrace_target_info *
@@ -554,6 +859,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;
@@ -570,6 +879,18 @@ linux_disable_bts (struct btrace_tinfo_bts *tinfo)
   return BTRACE_ERR_NONE;
 }
 
+/* Disable Intel(R) Processor Trace tracing.  */
+
+static enum btrace_error
+linux_disable_pt (struct btrace_tinfo_pt *tinfo)
+{
+  munmap((void *) tinfo->pt.mem, tinfo->pt.size);
+  munmap((void *) tinfo->header, PAGE_SIZE);
+  close (tinfo->file);
+
+  return BTRACE_ERR_NONE;
+}
+
 /* See linux-btrace.h.  */
 
 enum btrace_error
@@ -586,6 +907,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)
@@ -683,6 +1008,48 @@ linux_read_bts (struct btrace_data_bts *btrace,
   return BTRACE_ERR_NONE;
 }
 
+/* Fill in the Intel(R) 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(R) 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;
+
+  pt = &tinfo->variant.pt.pt;
+
+  linux_fill_btrace_pt_config (&btrace->config);
+
+  switch (type)
+    {
+    case BTRACE_READ_DELTA:
+      /* We don't support delta reads.  The data head (i.e. aux_head) wraps
+	 around to stay inside the aux buffer.  */
+      return BTRACE_ERR_NOT_SUPPORTED;
+
+    case BTRACE_READ_NEW:
+      if (!perf_event_new_data (pt))
+	return BTRACE_ERR_NONE;
+
+      /* Fall through.  */
+    case BTRACE_READ_ALL:
+      perf_event_read_all (pt, &btrace->data, &btrace->size);
+      return BTRACE_ERR_NONE;
+    }
+
+  internal_error (__FILE__, __LINE__, _("Unkown btrace read type."));
+}
+
 /* See linux-btrace.h.  */
 
 enum btrace_error
@@ -701,6 +1068,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(R) Processor Trace format.  */
+      btrace->format = BTRACE_FORMAT_PT;
+      btrace->variant.pt.data = NULL;
+      btrace->variant.pt.size = 0;
+
+      return linux_read_pt (&btrace->variant.pt, tinfo, type);
     }
 
   internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
diff --git a/gdb/nat/linux-btrace.h b/gdb/nat/linux-btrace.h
index 12cdcde..245feea 100644
--- a/gdb/nat/linux-btrace.h
+++ b/gdb/nat/linux-btrace.h
@@ -64,6 +64,22 @@ struct btrace_tinfo_bts
   /* The BTS perf event buffer.  */
   struct perf_event_buffer bts;
 };
+
+/* Branch trace target information for Intel(R) Processor Trace.  */
+struct btrace_tinfo_pt
+{
+  /* The Linux perf_event configuration for collecting the branch trace.  */
+  struct perf_event_attr attr;
+
+  /* The perf event file.  */
+  int file;
+
+  /* The perf event configuration page. */
+  volatile struct perf_event_mmap_page *header;
+
+  /* The trace perf event buffer.  */
+  struct perf_event_buffer pt;
+};
 #endif /* HAVE_LINUX_PERF_EVENT_H */
 
 /* Branch trace target information per thread.  */
@@ -81,6 +97,9 @@ struct btrace_target_info
   {
     /* CONF.FORMAT == BTRACE_FORMAT_BTS.  */
     struct btrace_tinfo_bts bts;
+
+    /* CONF.FORMAT == BTRACE_FORMAT_PT.  */
+    struct btrace_tinfo_pt pt;
   } variant;
 #endif /* HAVE_LINUX_PERF_EVENT_H */
 
diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c
index 240a8dc..94cc6f4 100644
--- a/gdb/record-btrace.c
+++ b/gdb/record-btrace.c
@@ -80,6 +80,10 @@ static struct cmd_list_element *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.  */
 
@@ -332,6 +336,22 @@ record_btrace_print_bts_conf (const struct btrace_config_bts *conf)
     }
 }
 
+/* Print an Intel(R) Processor Trace configuration.  */
+
+static void
+record_btrace_print_pt_conf (const struct btrace_config_pt *conf)
+{
+  const char *suffix;
+  unsigned int size;
+
+  size = conf->size;
+  if (size > 0)
+    {
+      suffix = record_btrace_adjust_size (&size);
+      printf_unfiltered (_("Buffer size: %u%s.\n"), size, suffix);
+    }
+}
+
 /* Print a branch tracing configuration.  */
 
 static void
@@ -348,6 +368,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."));
@@ -458,6 +482,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, _("["));
@@ -2305,7 +2356,6 @@ init_record_btrace_ops (void)
 static void
 cmd_record_btrace_bts_start (char *args, int from_tty)
 {
-
   if (args != NULL && *args != 0)
     error (_("Invalid argument."));
 
@@ -2323,16 +2373,15 @@ cmd_record_btrace_bts_start (char *args, int from_tty)
   END_CATCH
 }
 
-/* Alias for "target record".  */
+/* Start recording Intel(R) Processor Trace.  */
 
 static void
-cmd_record_btrace_start (char *args, int from_tty)
+cmd_record_btrace_pt_start (char *args, int from_tty)
 {
-
   if (args != NULL && *args != 0)
     error (_("Invalid argument."));
 
-  record_btrace_conf.format = BTRACE_FORMAT_BTS;
+  record_btrace_conf.format = BTRACE_FORMAT_PT;
 
   TRY
     {
@@ -2346,6 +2395,38 @@ cmd_record_btrace_start (char *args, int from_tty)
   END_CATCH
 }
 
+/* Alias for "target record".  */
+
+static void
+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
+    {
+      execute_command ("target record-btrace", from_tty);
+    }
+  CATCH (exception, RETURN_MASK_ALL)
+    {
+      record_btrace_conf.format = BTRACE_FORMAT_BTS;
+
+      TRY
+	{
+	  execute_command ("target record-btrace", from_tty);
+	}
+      CATCH (exception, RETURN_MASK_ALL)
+	{
+	  record_btrace_conf.format = BTRACE_FORMAT_NONE;
+	  throw_exception (exception);
+	}
+      END_CATCH
+    }
+  END_CATCH
+}
+
 /* The "set record btrace" command.  */
 
 static void
@@ -2391,6 +2472,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.  */
@@ -2411,6 +2511,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);
@@ -2457,6 +2564,27 @@ The trace buffer size may not be changed while recording."), NULL, NULL,
 			    &set_record_btrace_bts_cmdlist,
 			    &show_record_btrace_bts_cmdlist);
 
+  add_prefix_cmd ("pt", class_support, cmd_set_record_btrace_pt,
+		  _("Set record btrace pt options"),
+		  &set_record_btrace_pt_cmdlist,
+		  "set record btrace pt ", 0, &set_record_btrace_cmdlist);
+
+  add_prefix_cmd ("pt", class_support, cmd_show_record_btrace_pt,
+		  _("Show record btrace pt options"),
+		  &show_record_btrace_pt_cmdlist,
+		  "show record btrace pt ", 0, &show_record_btrace_cmdlist);
+
+  add_setshow_uinteger_cmd ("buffer-size", no_class,
+			    &record_btrace_conf.pt.size,
+			    _("Set the record/replay pt buffer size."),
+			    _("Show the record/replay pt buffer size."), _("\
+Bigger buffers allow longer recording but also take more time to process \
+the recorded execution.\n\
+The actual buffer size may differ from the requested size.  Use \"info record\" \
+to see the actual buffer size."), NULL, NULL,
+			    &set_record_btrace_pt_cmdlist,
+			    &show_record_btrace_pt_cmdlist);
+
   init_record_btrace_ops ();
   add_target (&record_btrace_ops);
 
@@ -2464,4 +2592,5 @@ The trace buffer size may not be changed while recording."), NULL, NULL,
 			       xcalloc, xfree);
 
   record_btrace_conf.bts.size = 64 * 1024;
+  record_btrace_conf.pt.size = 16 * 1024;
 }
diff --git a/gdb/remote.c b/gdb/remote.c
index f15d75e..0010476 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1322,6 +1322,7 @@ enum {
   PACKET_QTBuffer_size,
   PACKET_Qbtrace_off,
   PACKET_Qbtrace_bts,
+  PACKET_Qbtrace_pt,
   PACKET_qXfer_btrace,
 
   /* Support for the QNonStop packet.  */
@@ -1362,6 +1363,9 @@ enum {
   /* Support for vfork events.  */
   PACKET_vfork_event_feature,
 
+  /* Support for the Qbtrace-conf:pt:size packet.  */
+  PACKET_Qbtrace_conf_pt_size,
+
   PACKET_MAX
 };
 
@@ -4145,6 +4149,7 @@ 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,
@@ -4157,6 +4162,8 @@ static const struct protocol_feature remote_protocol_features[] = {
     PACKET_fork_event_feature },
   { "vfork-events", PACKET_DISABLE, remote_supported_packet,
     PACKET_vfork_event_feature },
+  { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet,
+    PACKET_Qbtrace_conf_pt_size }
 };
 
 static char *remote_support_xml;
@@ -11884,6 +11891,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"));
@@ -11923,6 +11939,28 @@ btrace_sync_conf (const struct btrace_config *conf)
 
       rs->btrace_config.bts.size = conf->bts.size;
     }
+
+  packet = &remote_protocol_packets[PACKET_Qbtrace_conf_pt_size];
+  if (packet_config_support (packet) == PACKET_ENABLE
+      && conf->pt.size != rs->btrace_config.pt.size)
+    {
+      pos = buf;
+      pos += xsnprintf (pos, endbuf - pos, "%s=0x%x", packet->name,
+                        conf->pt.size);
+
+      putpkt (buf);
+      getpkt (&buf, &rs->buf_size, 0);
+
+      if (packet_ok (buf, packet) == PACKET_ERROR)
+	{
+	  if (buf[0] == 'E' && buf[1] == '.')
+	    error (_("Failed to configure the trace buffer size: %s"), buf + 2);
+	  else
+	    error (_("Failed to configure the trace buffer size."));
+	}
+
+      rs->btrace_config.pt.size = conf->pt.size;
+    }
 }
 
 /* Read the current thread's btrace configuration from the target and
@@ -11934,7 +11972,7 @@ btrace_read_config (struct btrace_config *conf)
   char *xml;
 
   xml = target_read_stralloc (&current_target,
-                              TARGET_OBJECT_BTRACE_CONF, "");
+			      TARGET_OBJECT_BTRACE_CONF, "");
   if (xml != NULL)
     {
       struct cleanup *cleanup;
@@ -11952,12 +11990,23 @@ 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 ();
 
-  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);
@@ -12079,7 +12128,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;
 
@@ -12883,7 +12932,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);
@@ -12906,6 +12958,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_vfork_event_feature],
 			 "vfork-event-feature", "vfork-event-feature", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size],
+       "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0);
+
   /* Assert that we've registered "set remote foo-packet" commands
      for all packet configs.  */
   {
-- 
1.8.3.1

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

* Re: [PATCH 5/5] btrace: maintenance commands
  2015-06-23  8:22 ` [PATCH 5/5] btrace: maintenance commands Markus Metzger
@ 2015-06-23 15:28   ` Eli Zaretskii
  2015-06-24  7:05     ` Metzger, Markus T
  2015-06-30 12:57   ` Pedro Alves
  1 sibling, 1 reply; 20+ messages in thread
From: Eli Zaretskii @ 2015-06-23 15:28 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: Tue, 23 Jun 2015 10:16:58 +0200
> 
> Add maintenance commands that help debugging the btrace record target.

Thanks.

> +  add_setshow_boolean_cmd ("skip-pad", class_maintenance,
> +			   &maint_btrace_pt_skip_pad, _("\
> +Set whether PAD packets should be skipped in the btrace packet history."), _("\
> +Show whether PAD packets should be skipped in the btrace packet history."),_("\
> +When enabled, PAD packets are ignored when processing the trace to compute \
> +the btrace packet history.\n\

This line is too long to fit on a standard text terminal.  Is that
necessary?

> +This does not modify the already computed packet history.  Use 'maintenance \
> +btrace clear-packet-history' to clear and recompute the existing history."),

Same here (and in a few more places).

> +	   _("Prints the raw branch tracing data.\n\

I think we use "Print", not "Prints".  (Again, there are other doc
strings in the patch with the same issue.)

> +execution history for the @samp{record btrace} command.  The
> +information printed as well as the format depends on the btrace
> +recording format.

"Both the information and the format in which it is printed depend
on ..."

> +@table @code
> +@item bts
> +For the BTS recording format, it prints a list of blocks of sequential

"print" instead of "it prints" -- this matches the style of the
previous sentences.

> +code.  For each block, the following information is printed:
> +
> +@table @code

@code is inappropriate here, I suggest to use @asis instead.

> +@item The block number

I'd lose the "The" part, it's redundant in a table.

The documentation parts are OK with those fixed.

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

* Re: [PATCH 2/5] btrace: support Intel(R) Processor Trace
  2015-06-23  8:23 ` [PATCH 2/5] btrace: support Intel(R) Processor Trace Markus Metzger
@ 2015-06-23 15:32   ` Eli Zaretskii
  2015-06-30 12:56   ` Pedro Alves
  1 sibling, 0 replies; 20+ messages in thread
From: Eli Zaretskii @ 2015-06-23 15:32 UTC (permalink / raw)
  To: Markus Metzger; +Cc: palves, gdb-patches

> From: Markus Metzger <markus.t.metzger@intel.com>
> Cc: gdb-patches@sourceware.org
> Date: Tue, 23 Jun 2015 10:16:55 +0200
> 
> Adds a new command "record btrace pt" to configure the kernel to use
> Intel(R) Processor Trace instead of Branch Trace Strore.
> 
> The "record btrace" command chooses the tracing format automatically.
> 
> Intel Processor Trace support requires kernel 4.1 and libipt.

The documentation parts are OK, with one comment:

> +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(R) Processor Trace
> +format.  The actually obtained buffer size may differ from the
> +requested @var{size}. Use the @code{info record} command to see the
                       ^^
Two spaces here.

Thanks.

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

* RE: [PATCH 5/5] btrace: maintenance commands
  2015-06-23 15:28   ` Eli Zaretskii
@ 2015-06-24  7:05     ` Metzger, Markus T
  2015-06-24 14:38       ` Eli Zaretskii
  0 siblings, 1 reply; 20+ messages in thread
From: Metzger, Markus T @ 2015-06-24  7:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: palves, gdb-patches

> -----Original Message-----
> From: Eli Zaretskii [mailto:eliz@gnu.org]
> Sent: Tuesday, June 23, 2015 5:28 PM
> To: Metzger, Markus T
> Cc: palves@redhat.com; gdb-patches@sourceware.org
> Subject: Re: [PATCH 5/5] btrace: maintenance commands

Thanks for your quick review.  Here are the parts I changed:

diff --git a/gdb/btrace.c b/gdb/btrace.c
index 561ccd6..e0e5267 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
[...]
+  add_setshow_boolean_cmd ("skip-pad", class_maintenance,
+			   &maint_btrace_pt_skip_pad, _("\
+Set whether PAD packets should be skipped in the btrace packet history."), _("\
+Show whether PAD packets should be skipped in the btrace packet history."),_("\
+When enabled, PAD packets are ignored in the btrace packet history."),
+			   NULL, NULL, &maint_btrace_pt_set_cmdlist,
+			   &maint_btrace_pt_show_cmdlist);
+
+  add_cmd ("packet-history", class_maintenance, maint_btrace_packet_history_cmd,
+	   _("Print the raw branch tracing data.\n\
+With no argument, print ten more packets after the previous ten-line print.\n\
+With '-' as argument print ten packets before a previous ten-line print.\n\
+One argument specifies the starting packet of a ten-line print.\n\
+Two arguments with comma between specify starting and ending packets to \
+print.\n\
+Preceded with '+'/'-' the second argument specifies the distance from the \
+first.\n"),
+	   &maint_btrace_cmdlist);

For the above, strings are less than 80 characters per line.  Just the trailing '\'
or '");' doesn't fit so I have to break the string earlier.

[...]
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 58a9bc7..f4c95ae 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33965,6 +33965,66 @@ Shared library events.
 This prints information about each @code{bfd} object that is known to
 @value{GDBN}.  @xref{Top, , BFD, bfd, The Binary File Descriptor Library}.
 
+@kindex maint info btrace
+@item maint info btrace
+Pint information about raw branch tracing data.
+
+@kindex maint btrace packet-history
+@item maint btrace packet-history
+Print the raw branch trace packets that are used to compute the
+execution history for the @samp{record btrace} command.  Both the
+information and the format in which it is printed depend on the btrace
+recording format.
+
+@table @code
+@item bts
+For the BTS recording format, print a list of blocks of sequential
+code.  For each block, the following information is printed:
+
+@table @asis
+@item Block number
+Newer blocks have higher numbers.  The oldest block has number zero.
+@item Lowest @samp{PC}
+@item Highest @samp{PC}
+@end table
+
+@item pt
+For the Intel(R) Processor Trace recording format, print a list of
+Intel(R) Processor Trace packets.  For each packet, the following
+information is printed:
+
+@table @asis
+@item Packet number
+Newer packets have higher numbers.  The oldest packet has number zero.
+@item Trace offset
+The packet's offset in the trace stream.
+@item Packet opcode and payload
+@end table
+@end table
+
+@kindex maint btrace clear-packet-history
+@item maint btrace clear-packet-history
+Discards the cached packet history printed by the @samp{maint btrace
+packet-history} command.  The history will be computed again when
+needed.
+
+@kindex maint btrace clear
+@item maint btrace clear
+Discard the branch trace data.  The data will be fetched anew and the
+branch trace will be recomputed when needed.
+
+This implicitly truncates the branch trace to a single branch trace
+buffer.  When updating branch trace incrementally, the branch trace
+available to @value{GDBN} may be bigger than a single branch trace
+buffer.
+
+@kindex maint set btrace pt skip-pad
+@item maint set btrace pt skip-pad
+@kindex maint show btrace pt skip-pad
+@item maint show btrace pt skip-pad
+Control whether @value{GDBN} will skip PAD packets when computing the
+packet history.
+
 @kindex set displaced-stepping
 @kindex show displaced-stepping
 @cindex displaced stepping support

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

* Re: [PATCH 5/5] btrace: maintenance commands
  2015-06-24  7:05     ` Metzger, Markus T
@ 2015-06-24 14:38       ` Eli Zaretskii
  0 siblings, 0 replies; 20+ messages in thread
From: Eli Zaretskii @ 2015-06-24 14:38 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: palves, gdb-patches

> From: "Metzger, Markus T" <markus.t.metzger@intel.com>
> CC: "palves@redhat.com" <palves@redhat.com>, "gdb-patches@sourceware.org"
> 	<gdb-patches@sourceware.org>
> Date: Wed, 24 Jun 2015 07:05:18 +0000
> 
> > -----Original Message-----
> > From: Eli Zaretskii [mailto:eliz@gnu.org]
> > Sent: Tuesday, June 23, 2015 5:28 PM
> > To: Metzger, Markus T
> > Cc: palves@redhat.com; gdb-patches@sourceware.org
> > Subject: Re: [PATCH 5/5] btrace: maintenance commands
> 
> Thanks for your quick review.  Here are the parts I changed:

Thanks, this is good.

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

* Re: [PATCH 2/5] btrace: support Intel(R) Processor Trace
  2015-06-23  8:23 ` [PATCH 2/5] btrace: support Intel(R) Processor Trace Markus Metzger
  2015-06-23 15:32   ` Eli Zaretskii
@ 2015-06-30 12:56   ` Pedro Alves
  2015-06-30 14:54     ` Metzger, Markus T
  1 sibling, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2015-06-30 12:56 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 06/23/2015 09:16 AM, Markus Metzger wrote:
> Adds a new command "record btrace pt" to configure the kernel to use
> Intel(R) Processor Trace instead of Branch Trace Strore.

This looks very good to me.  A few minor details to sort out,
and this is good to go.

> 
> The "record btrace" command chooses the tracing format automatically.
> 
> Intel Processor Trace support requires kernel 4.1 and libipt.

s/kernel/Linux/.

> diff --git a/gdb/NEWS b/gdb/NEWS
> index 3ec5851..9ab64bf 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -112,6 +112,10 @@ show mpx bound
>  set mpx bound on i386 and amd64
>     Support for bound table investigation on Intel(R) MPX enabled applications.
>  
> +record btrace pt
> +record pt
> +  Start branch trace recording using Intel(R) Processor Trace format.
> +
>  * New options
>  

The patch also includes new RSP packets.  Those should be mentioned
in NEWS as well.  I think the new configure switch should be mentioned
in a:

* New configure options

section too.

> +  decoder = pt_insn_alloc_decoder (&config);
> +  if (decoder == NULL)
> +    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
> +
> +  TRY
> +    {
> +      struct pt_image *image;
> +
> +      image = pt_insn_get_image(decoder);
> +      if (image == NULL)
> +	error (_("Failed to configure the Intel(R) Processor Trace decoder."));
> +
> +      errcode = pt_image_set_callback(image, btrace_pt_readmem_callback, NULL);
> +      if (errcode < 0)
> +	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
> +		 "%s."), pt_errstr (pt_errcode (errcode)));
> +
> +      ftrace_add_pt (decoder, &btinfo->begin, &btinfo->end, &level,
> +		     &btinfo->ngaps);
> +    }
> +  CATCH (error, RETURN_MASK_ALL)
> +    {
> +      /* Indicate a gap in the trace if we quit trace processing.  Errors were
> +	 already logged before.  */

What does this "already logged before" mean?  AFAICS, the errors thrown
in the TRY branch are just swallowed here.  Did you mean to rethrow them?
Otherwise I'm not seeing the point in throwing them in the first place.

> +      if (error.reason == RETURN_QUIT && btinfo->end != NULL)
> +	{
> +	  btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
> +	  btinfo->ngaps++;
> +	}
> +    }
> +  END_CATCH
> +



>    internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
> @@ -1056,7 +1312,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)

What fails if you send the new xml to an old/unpatched gdb, while keeping the
version at 1.0?  Is the new file really incompatible, or are you just
adding new elements/attributes?  There's usually no need to bump the
version in the latter case.  Old gdb will just ignore the
elements/attributes it doesn't recognize, and thus not support the feature.

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

typo: "apporpriate"

> +  help_list (set_record_btrace_pt_cmdlist, "set record btrace pt ",
> +	     all_commands, gdb_stdout);
> +}


> +  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,
                                           ^^^^
Please add a "showfunc" hook for i18n.

Thanks,
Pedro Alves

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

* Re: [PATCH 4/5] btrace: store raw btrace data
  2015-06-23  8:22 ` [PATCH 4/5] btrace: store raw btrace data Markus Metzger
@ 2015-06-30 12:56   ` Pedro Alves
  0 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2015-06-30 12:56 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 06/23/2015 09:16 AM, Markus Metzger wrote:
> Store the raw branch trace data that has been read from the target.
> 
> This data can be used for maintenance commands as well as for generating
> a core file for the "record save" command.
> 

OK.

Thanks,
Pedro Alves

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

* Re: [PATCH 3/5] btrace, linux: use data_size and data_offset
  2015-06-23  8:22 ` [PATCH 3/5] btrace, linux: use data_size and data_offset Markus Metzger
@ 2015-06-30 12:56   ` Pedro Alves
  0 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2015-06-30 12:56 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 06/23/2015 09:16 AM, Markus Metzger wrote:

OK with,


> +#if defined(PERF_ATTR_SIZE_VER5)
> +  if (offsetof(struct perf_event_mmap_page, data_size) <= header->size)

'offsetof ('

and 'defined (', while at it.

> +    {
> +      data_offset = header->data_offset;
> +      data_size = header->data_size;
> +    }
> +#endif /* defined(PERF_ATTR_SIZE_VER5) */
> +


Thanks,
Pedro Alves

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

* Re: [PATCH 1/5] configure: check for libipt
  2015-06-23  8:22 ` [PATCH 1/5] configure: check for libipt Markus Metzger
@ 2015-06-30 12:56   ` Pedro Alves
  2015-06-30 14:54     ` Metzger, Markus T
  0 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2015-06-30 12:56 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches

On 06/23/2015 09:16 AM, Markus Metzger wrote:
> Check for libipt, an Intel(R) Processor Trace decoder library.  The sources
> can be found on github at:
> 
>     https://github.com/01org/processor-trace
> 
> 2015-06-23  Markus Metzger  <markus.t.metzger@intel.com>
> 
> 	* configure.ac: Check for libipt
> 	* configure: Regenerate.
> 	* config.in: Regenerate.
> 	* Makefile.in (LIBIPT): New.
> 	(CLIBS): Add $LIBIPT.

OK.

Is the library host independent?  That is, does it handle
host vs target endianness, integer types, etc.?  E.g., is a big endian PPC
host debugging against an x86-64 gdbserver able to use libipt?  Another
example would be a big endian PPC host loading an x86-64 core dump that
includes ipt data (once we get to it).

Thanks,
Pedro Alves

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

* Re: [PATCH 5/5] btrace: maintenance commands
  2015-06-23  8:22 ` [PATCH 5/5] btrace: maintenance commands Markus Metzger
  2015-06-23 15:28   ` Eli Zaretskii
@ 2015-06-30 12:57   ` Pedro Alves
  1 sibling, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2015-06-30 12:57 UTC (permalink / raw)
  To: Markus Metzger; +Cc: gdb-patches, Eli Zaretskii

On 06/23/2015 09:16 AM, Markus Metzger wrote:
> Add maintenance commands that help debugging the btrace record target.
> The following new commands are added:

Looks good to me, with the minor nits pointed out below addressed.


>  }
> @@ -2192,3 +2235,682 @@ make_cleanup_btrace_data (struct btrace_data *data)
>  {
>    return make_cleanup (do_btrace_data_cleanup, data);
>  }
> +
> +#if defined (HAVE_LIBIPT)
> +
> +/* Print a single packet.  */
> +
> +static void
> +pt_print_packet (const struct pt_packet *packet)
> +{
> +  switch (packet->type)
> +    {
> +    default:
> +      printf_unfiltered ("[??: %x]", packet->type);

I think the missing _() will result in ARI warnings.
You can use extra ()'s to suppress them, like:

     printf_unfiltered (("[??: %x]"), packet->type);


> +      break;
> +
> +    case ppt_psb:
> +      printf_unfiltered ("psb");
> +      break;

etc.

> +btrace clear-packet-history' to clear and recompute the existing history."),
> +			   NULL, NULL, &maint_btrace_pt_set_cmdlist,
> +			   &maint_btrace_pt_show_cmdlist);

Please add a show callback.

Thanks,
Pedro Alves

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

* RE: [PATCH 2/5] btrace: support Intel(R) Processor Trace
  2015-06-30 12:56   ` Pedro Alves
@ 2015-06-30 14:54     ` Metzger, Markus T
  2015-06-30 15:08       ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Metzger, Markus T @ 2015-06-30 14:54 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: Pedro Alves [mailto:palves@redhat.com]
> Sent: Tuesday, June 30, 2015 2:57 PM
> To: Metzger, Markus T
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 2/5] btrace: support Intel(R) Processor Trace
> 
> On 06/23/2015 09:16 AM, Markus Metzger wrote:
> > Adds a new command "record btrace pt" to configure the kernel to use
> > Intel(R) Processor Trace instead of Branch Trace Strore.
> 
> This looks very good to me.  A few minor details to sort out,
> and this is good to go.

Thanks.


> > +  decoder = pt_insn_alloc_decoder (&config);
> > +  if (decoder == NULL)
> > +    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
> > +
> > +  TRY
> > +    {
> > +      struct pt_image *image;
> > +
> > +      image = pt_insn_get_image(decoder);
> > +      if (image == NULL)
> > +	error (_("Failed to configure the Intel(R) Processor Trace decoder."));
> > +
> > +      errcode = pt_image_set_callback(image,
> btrace_pt_readmem_callback, NULL);
> > +      if (errcode < 0)
> > +	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
> > +		 "%s."), pt_errstr (pt_errcode (errcode)));
> > +
> > +      ftrace_add_pt (decoder, &btinfo->begin, &btinfo->end, &level,
> > +		     &btinfo->ngaps);
> > +    }
> > +  CATCH (error, RETURN_MASK_ALL)
> > +    {
> > +      /* Indicate a gap in the trace if we quit trace processing.  Errors were
> > +	 already logged before.  */
> 
> What does this "already logged before" mean?  AFAICS, the errors thrown
> in the TRY branch are just swallowed here.  Did you mean to rethrow them?
> Otherwise I'm not seeing the point in throwing them in the first place.

This means that decode errors are already represented as gaps in the trace.
When the trace is printed, the error at a trace gap is printed.

This code is now handling a user interrupt, which is also represented
as a gap at the very end of the trace.

This reference to decode errors is maybe more confusing than helpful.
I'll remove it.


> >    internal_error (__FILE__, __LINE__, _("Unkown branch trace format."));
> > @@ -1056,7 +1312,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)
> 
> What fails if you send the new xml to an old/unpatched gdb, while keeping
> the
> version at 1.0?  Is the new file really incompatible, or are you just
> adding new elements/attributes?  There's usually no need to bump the
> version in the latter case.  Old gdb will just ignore the
> elements/attributes it doesn't recognize, and thus not support the feature.

I'm just adding new elements and attributes.  I thought I'd bump the version
since there are new features.  Should I leave it at version 1.0?


regards,
markus.

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

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

* RE: [PATCH 1/5] configure: check for libipt
  2015-06-30 12:56   ` Pedro Alves
@ 2015-06-30 14:54     ` Metzger, Markus T
  2015-06-30 15:01       ` Pedro Alves
  0 siblings, 1 reply; 20+ messages in thread
From: Metzger, Markus T @ 2015-06-30 14:54 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: Tuesday, June 30, 2015 2:56 PM
> To: Metzger, Markus T
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 1/5] configure: check for libipt
> 
> On 06/23/2015 09:16 AM, Markus Metzger wrote:
> > Check for libipt, an Intel(R) Processor Trace decoder library.  The sources
> > can be found on github at:
> >
> >     https://github.com/01org/processor-trace
> >
> > 2015-06-23  Markus Metzger  <markus.t.metzger@intel.com>
> >
> > 	* configure.ac: Check for libipt
> > 	* configure: Regenerate.
> > 	* config.in: Regenerate.
> > 	* Makefile.in (LIBIPT): New.
> > 	(CLIBS): Add $LIBIPT.
> 
> OK.
> 
> Is the library host independent?  That is, does it handle
> host vs target endianness, integer types, etc.?  E.g., is a big endian PPC
> host debugging against an x86-64 gdbserver able to use libipt?  Another
> example would be a big endian PPC host loading an x86-64 core dump that
> includes ipt data (once we get to it).

No.  It may not be too hard to make it work, though.  Most of the memory
accesses are byte-wise, already.

I don't have a PPC system to test this configuration.  Is this something
where Sergio's buildbot can help?  How is this cross-platform testing
usually handled?

Until libipt is available for PPC, you simply can't build a GDB with Intel PT
support on PPC.  When you configure GDB, HAVE_LIBIPT will be undefined
and GDB will fall back to BTS or report an error.  We're not breaking anything.
The feature will just not be available on all platforms.

Regards,
Markus.

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

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

* Re: [PATCH 1/5] configure: check for libipt
  2015-06-30 14:54     ` Metzger, Markus T
@ 2015-06-30 15:01       ` Pedro Alves
  0 siblings, 0 replies; 20+ messages in thread
From: Pedro Alves @ 2015-06-30 15:01 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: gdb-patches

On 06/30/2015 03:54 PM, Metzger, Markus T wrote:

>> Is the library host independent?  That is, does it handle
>> host vs target endianness, integer types, etc.?  E.g., is a big endian PPC
>> host debugging against an x86-64 gdbserver able to use libipt?  Another
>> example would be a big endian PPC host loading an x86-64 core dump that
>> includes ipt data (once we get to it).
> 
> No.  It may not be too hard to make it work, though.  Most of the memory
> accesses are byte-wise, already.
> 
> I don't have a PPC system to test this configuration.  

FYI, there's a few quite powerful ppc64 machines in the
gcc compile farm (gcc110-gcc112):

  https://gcc.gnu.org/wiki/CompileFarm

> Is this something
> where Sergio's buildbot can help?  How is this cross-platform testing
> usually handled?

Probably not, as no buildslave configured in our buildbot does any cross testing.
It wouldn't be impossible, we could use the gcc compile farm machines for
that, just nobody ever set it up.

> Until libipt is available for PPC, you simply can't build a GDB with Intel PT
> support on PPC.  When you configure GDB, HAVE_LIBIPT will be undefined
> and GDB will fall back to BTS or report an error.  We're not breaking anything.
> The feature will just not be available on all platforms.

OK, that's fine.  Was just checking.

Thanks,
Pedro Alves

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

* Re: [PATCH 2/5] btrace: support Intel(R) Processor Trace
  2015-06-30 14:54     ` Metzger, Markus T
@ 2015-06-30 15:08       ` Pedro Alves
  2015-07-01  8:39         ` Metzger, Markus T
  0 siblings, 1 reply; 20+ messages in thread
From: Pedro Alves @ 2015-06-30 15:08 UTC (permalink / raw)
  To: Metzger, Markus T; +Cc: gdb-patches

On 06/30/2015 03:54 PM, Metzger, Markus T wrote:

>>> +  decoder = pt_insn_alloc_decoder (&config);
>>> +  if (decoder == NULL)
>>> +    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
>>> +
>>> +  TRY
>>> +    {
>>> +      struct pt_image *image;
>>> +
>>> +      image = pt_insn_get_image(decoder);
>>> +      if (image == NULL)
>>> +	error (_("Failed to configure the Intel(R) Processor Trace decoder."));
>>> +
>>> +      errcode = pt_image_set_callback(image,
>> btrace_pt_readmem_callback, NULL);
>>> +      if (errcode < 0)
>>> +	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
>>> +		 "%s."), pt_errstr (pt_errcode (errcode)));
>>> +
>>> +      ftrace_add_pt (decoder, &btinfo->begin, &btinfo->end, &level,
>>> +		     &btinfo->ngaps);
>>> +    }
>>> +  CATCH (error, RETURN_MASK_ALL)
>>> +    {
>>> +      /* Indicate a gap in the trace if we quit trace processing.  Errors were
>>> +	 already logged before.  */
>>
>> What does this "already logged before" mean?  AFAICS, the errors thrown
>> in the TRY branch are just swallowed here.  Did you mean to rethrow them?
>> Otherwise I'm not seeing the point in throwing them in the first place.
> 
> This means that decode errors are already represented as gaps in the trace.
> When the trace is printed, the error at a trace gap is printed.
> 
> This code is now handling a user interrupt, which is also represented
> as a gap at the very end of the trace.
> 
> This reference to decode errors is maybe more confusing than helpful.
> I'll remove it.

I still don't get why throw the errors in the TRY branch:

      if (image == NULL)
	error (_("Failed to configure the Intel(R) Processor Trace decoder."));

      errcode = pt_image_set_callback(image, btrace_pt_readmem_callback, NULL);
      if (errcode < 0)
	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
		 "%s."), pt_errstr (pt_errcode (errcode)));

... if they're just dropped on the catch brock.  Shouldn't those
be rethrown?  The CATCH block you had does not do that.  And it
neither rethrows the ctrl-c that generates the RETURN_QUIT:

+  CATCH (error, RETURN_MASK_ALL)
+    {
+      /* Indicate a gap in the trace if we quit trace processing.  Errors were
+	 already logged before.  */
+      if (error.reason == RETURN_QUIT && btinfo->end != NULL)
+	{
+	  btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
+	  btinfo->ngaps++;
+	}
+    }

So shouldn't that be:

  CATCH (error, RETURN_MASK_ALL)
    {
      /* Indicate a gap in the trace if we quit trace processing.  Errors were
	 already logged before.  */
      if (error.reason == RETURN_QUIT && btinfo->end != NULL)
	{
	  btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
	  btinfo->ngaps++;
	}

+     throw_exception (error);
    }

?

> I'm just adding new elements and attributes.  I thought I'd bump the version
> since there are new features.  Should I leave it at version 1.0?

Yes.  That way record bts with old gdb should still work with
new gdbserver.  (Please give that a try to make sure it actually
still works.)

Thanks,
Pedro Alves

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

* RE: [PATCH 2/5] btrace: support Intel(R) Processor Trace
  2015-06-30 15:08       ` Pedro Alves
@ 2015-07-01  8:39         ` Metzger, Markus T
  0 siblings, 0 replies; 20+ messages in thread
From: Metzger, Markus T @ 2015-07-01  8:39 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> -----Original Message-----
> From: Pedro Alves [mailto:palves@redhat.com]
> Sent: Tuesday, June 30, 2015 5:09 PM
> To: Metzger, Markus T
> Cc: gdb-patches@sourceware.org
> Subject: Re: [PATCH 2/5] btrace: support Intel(R) Processor Trace
> 
> On 06/30/2015 03:54 PM, Metzger, Markus T wrote:
> 
> >>> +  decoder = pt_insn_alloc_decoder (&config);
> >>> +  if (decoder == NULL)
> >>> +    error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
> >>> +
> >>> +  TRY
> >>> +    {
> >>> +      struct pt_image *image;
> >>> +
> >>> +      image = pt_insn_get_image(decoder);
> >>> +      if (image == NULL)
> >>> +	error (_("Failed to configure the Intel(R) Processor Trace decoder."));
> >>> +
> >>> +      errcode = pt_image_set_callback(image,
> >> btrace_pt_readmem_callback, NULL);
> >>> +      if (errcode < 0)
> >>> +	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
> >>> +		 "%s."), pt_errstr (pt_errcode (errcode)));
> >>> +
> >>> +      ftrace_add_pt (decoder, &btinfo->begin, &btinfo->end, &level,
> >>> +		     &btinfo->ngaps);
> >>> +    }
> >>> +  CATCH (error, RETURN_MASK_ALL)
> >>> +    {
> >>> +      /* Indicate a gap in the trace if we quit trace processing.  Errors were
> >>> +	 already logged before.  */
> >>
> >> What does this "already logged before" mean?  AFAICS, the errors thrown
> >> in the TRY branch are just swallowed here.  Did you mean to rethrow
> them?
> >> Otherwise I'm not seeing the point in throwing them in the first place.
> >
> > This means that decode errors are already represented as gaps in the trace.
> > When the trace is printed, the error at a trace gap is printed.
> >
> > This code is now handling a user interrupt, which is also represented
> > as a gap at the very end of the trace.
> >
> > This reference to decode errors is maybe more confusing than helpful.
> > I'll remove it.
> 
> I still don't get why throw the errors in the TRY branch:
> 
>       if (image == NULL)
> 	error (_("Failed to configure the Intel(R) Processor Trace decoder."));
> 
>       errcode = pt_image_set_callback(image, btrace_pt_readmem_callback,
> NULL);
>       if (errcode < 0)
> 	error (_("Failed to configure the Intel(R) Processor Trace decoder: "
> 		 "%s."), pt_errstr (pt_errcode (errcode)));
> 
> ... if they're just dropped on the catch brock.  Shouldn't those
> be rethrown?  The CATCH block you had does not do that.  And it
> neither rethrows the ctrl-c that generates the RETURN_QUIT:
> 
> +  CATCH (error, RETURN_MASK_ALL)
> +    {
> +      /* Indicate a gap in the trace if we quit trace processing.  Errors were
> +	 already logged before.  */
> +      if (error.reason == RETURN_QUIT && btinfo->end != NULL)
> +	{
> +	  btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
> +	  btinfo->ngaps++;
> +	}
> +    }
> 
> So shouldn't that be:
> 
>   CATCH (error, RETURN_MASK_ALL)
>     {
>       /* Indicate a gap in the trace if we quit trace processing.  Errors were
> 	 already logged before.  */
>       if (error.reason == RETURN_QUIT && btinfo->end != NULL)
> 	{
> 	  btinfo->end = ftrace_new_gap (btinfo->end, BDE_PT_USER_QUIT);
> 	  btinfo->ngaps++;
> 	}
> 
> +     throw_exception (error);
>     }
> 
> ?

You're right.  We should rethrow.  Thanks.

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

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

end of thread, other threads:[~2015-07-01  8:39 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-23  8:22 [PATCH 0/5] Support Intel(R) Processor Trace Markus Metzger
2015-06-23  8:22 ` [PATCH 4/5] btrace: store raw btrace data Markus Metzger
2015-06-30 12:56   ` Pedro Alves
2015-06-23  8:22 ` [PATCH 5/5] btrace: maintenance commands Markus Metzger
2015-06-23 15:28   ` Eli Zaretskii
2015-06-24  7:05     ` Metzger, Markus T
2015-06-24 14:38       ` Eli Zaretskii
2015-06-30 12:57   ` Pedro Alves
2015-06-23  8:22 ` [PATCH 3/5] btrace, linux: use data_size and data_offset Markus Metzger
2015-06-30 12:56   ` Pedro Alves
2015-06-23  8:22 ` [PATCH 1/5] configure: check for libipt Markus Metzger
2015-06-30 12:56   ` Pedro Alves
2015-06-30 14:54     ` Metzger, Markus T
2015-06-30 15:01       ` Pedro Alves
2015-06-23  8:23 ` [PATCH 2/5] btrace: support Intel(R) Processor Trace Markus Metzger
2015-06-23 15:32   ` Eli Zaretskii
2015-06-30 12:56   ` Pedro Alves
2015-06-30 14:54     ` Metzger, Markus T
2015-06-30 15:08       ` Pedro Alves
2015-07-01  8:39         ` Metzger, Markus T

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