public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Felix Willgerodt <felix.willgerodt@intel.com>
To: gdb-patches@sourceware.org, markus.t.metzger@intel.com
Subject: [PATCH v6 10/10] btrace: Extend ptwrite event decoding.
Date: Fri, 16 Sep 2022 13:36:46 +0200	[thread overview]
Message-ID: <20220916113646.49749-11-felix.willgerodt@intel.com> (raw)
In-Reply-To: <20220916113646.49749-1-felix.willgerodt@intel.com>

Call the ptwrite filter function whenever a ptwrite event is decoded.
The returned string is written to the aux_data string table and a
corresponding auxiliary instruction is appended to the function segment.
---
 gdb/NEWS                                  |   6 +
 gdb/btrace.c                              |  54 +++
 gdb/config.in                             |   3 +
 gdb/configure                             |  11 +
 gdb/doc/python.texi                       | 150 ++++++
 gdb/testsuite/gdb.btrace/i386-ptwrite.S   | 550 ++++++++++++++++++++++
 gdb/testsuite/gdb.btrace/ptwrite.c        |  39 ++
 gdb/testsuite/gdb.btrace/ptwrite.exp      | 209 ++++++++
 gdb/testsuite/gdb.btrace/x86_64-ptwrite.S | 544 +++++++++++++++++++++
 gdb/testsuite/lib/gdb.exp                 |  74 +++
 gdbsupport/common.m4                      |   2 +
 gdbsupport/config.in                      |   3 +
 gdbsupport/configure                      |  11 +
 13 files changed, 1656 insertions(+)
 create mode 100644 gdb/testsuite/gdb.btrace/i386-ptwrite.S
 create mode 100644 gdb/testsuite/gdb.btrace/ptwrite.c
 create mode 100644 gdb/testsuite/gdb.btrace/ptwrite.exp
 create mode 100644 gdb/testsuite/gdb.btrace/x86_64-ptwrite.S

diff --git a/gdb/NEWS b/gdb/NEWS
index 555ef2ddf77..d75027ad64d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,12 @@
 
 *** Changes since GDB 12
 
+* GDB now supports printing of ptwrite payloads from the Intel Processor
+  Trace during 'record instruction-history', 'record function-call-history',
+  all stepping commands and in  Python.  Printing is customizable via a
+  ptwrite filter function in  Python.  By default, the raw ptwrite
+  payload is printed for each ptwrite that is encountered.
+
 * GDB now supports dumping memory tag data for AArch64 MTE.  It also supports
   reading memory tag data for AArch64 MTE from core files generated by
   the gcore command or the Linux kernel.
diff --git a/gdb/btrace.c b/gdb/btrace.c
index 14739d1d922..0dd816035e7 100644
--- a/gdb/btrace.c
+++ b/gdb/btrace.c
@@ -1253,6 +1253,54 @@ handle_pt_insn_events (struct btrace_thread_info *btinfo,
 		   bfun->insn_offset - 1, offset);
 
 	  break;
+#if defined (HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE)
+	case ptev_ptwrite:
+	  {
+	    uint64_t ip = 0;
+	    std::string ptw_string;
+	    btrace_insn_flags flags = 0;
+
+	    /* Lookup the ip if available.  */
+	    if (event.ip_suppressed == 0)
+	      ip = event.variant.ptwrite.ip;
+
+	    if (btinfo->ptw_callback_fun != nullptr)
+	      ptw_string
+		= btinfo->ptw_callback_fun (event.variant.ptwrite.payload,
+					    ip, btinfo->ptw_context);
+
+	    if (ptw_string.empty ())
+	      break;
+
+	    btinfo->aux_data.emplace_back (ptw_string);
+
+	    if (!btinfo->functions.empty ()
+		&& !btinfo->functions.back ().insn.empty ())
+	      flags = btinfo->functions.back ().insn.back ().flags;
+
+	    /* Update insn list with ptw payload insn.  */
+	    struct btrace_insn ptw_insn;
+	    ptw_insn.aux_data_index = btinfo->aux_data.size () - 1;
+	    ptw_insn.size = 0;
+	    ptw_insn.iclass = BTRACE_INSN_AUX;
+	    ptw_insn.flags = flags;
+
+	    if (ip != 0)
+	      bfun = ftrace_update_function (btinfo, ip);
+	    else
+	      {
+		if (btinfo->functions.empty ())
+		  bfun = ftrace_new_function (btinfo, NULL, NULL);
+		else
+		  bfun = &btinfo->functions.back ();
+	      }
+
+	    bfun->flags |= BFUN_CONTAINS_AUX;
+	    ftrace_update_insns (bfun, ptw_insn);
+
+	    break;
+	  }
+#endif /* defined (HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE) */
 	}
     }
 #endif /* defined (HAVE_PT_INSN_EVENT) */
@@ -2981,6 +3029,12 @@ pt_print_packet (const struct pt_packet *packet)
     case ppt_mnt:
       gdb_printf (("mnt %" PRIx64 ""), packet->payload.mnt.payload);
       break;
+
+#if defined (HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE)
+    case ppt_ptw:
+      gdb_printf (("ptw %" PRIx64 ""), packet->payload.ptw.payload);
+      break;
+#endif /* defined (HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE) */
     }
 }
 
diff --git a/gdb/config.in b/gdb/config.in
index a4975c68aad..d572c51ec79 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -460,6 +460,9 @@
 /* Define to 1 if `pl_tdname' is a member of `struct ptrace_lwpinfo'. */
 #undef HAVE_STRUCT_PTRACE_LWPINFO_PL_TDNAME
 
+/* Define to 1 if `variant.ptwrite' is a member of `struct pt_event'. */
+#undef HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE
+
 /* Define to 1 if `enabled' is a member of `struct pt_insn'. */
 #undef HAVE_STRUCT_PT_INSN_ENABLED
 
diff --git a/gdb/configure b/gdb/configure
index 4dbd0c3b13c..b1ad2a001ec 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -15349,6 +15349,17 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+fi
+
+      ac_fn_c_check_member "$LINENO" "struct pt_event" "variant.ptwrite" "ac_cv_member_struct_pt_event_variant_ptwrite" "#include <intel-pt.h>
+"
+if test "x$ac_cv_member_struct_pt_event_variant_ptwrite" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE 1
+_ACEOF
+
+
 fi
 
       LIBS=$save_LIBS
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index b963202b7b9..7d600677077 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -7115,6 +7115,7 @@ registering objfile-specific pretty-printers and frame-filters.
 * gdb.printing::       Building and registering pretty-printers.
 * gdb.types::          Utilities for working with types.
 * gdb.prompt::         Utilities for prompt value substitution.
+* gdb.ptwrite::        Utilities for ptwrite filter registration.
 @end menu
 
 @node gdb.printing
@@ -7305,3 +7306,152 @@ substitute_prompt ("frame: \f, args: \p@{print frame-arguments@}")
 "frame: main, args: scalars"
 @end smallexample
 @end table
+
+@node gdb.ptwrite
+@subsubsection gdb.ptwrite
+@cindex gdb.ptwrite
+
+This module provides additional functionality for recording programs that
+make use of the @code{PTWRITE} instruction.  @code{PTWRITE} is a x86
+instruction that allows to write values into the Intel Processor Trace
+(@pxref{Process Record and Replay}).
+The @value{NGCC} built-in functions for it are:
+@smallexample
+void __builtin_ia32_ptwrite32 (unsigned);
+void __builtin_ia32_ptwrite64 (unsigned long long);
+@end smallexample
+
+If an inferior uses the instruction, @value{GDBN} by default inserts the
+raw payload value as auxiliary information into the execution history.
+Auxiliary information is by default printed during
+@code{record instruction-history}, @code{record function-call-history},
+and all stepping commands and is accessible in Python as a
+@code{RecordAuxiliary} object.
+
+@exdent Sample program:
+@smallexample
+@group
+void
+ptwrite64 (unsigned long long value)
+@{
+  __builtin_ia32_ptwrite64 (value);
+@}
+@end group
+
+@group
+int
+main (void)
+@{
+  ptwrite64 (0x42);
+  return 0; /* break here.  */
+@}
+@end group
+@end smallexample
+
+
+@exdent @value{GDBN} output after recording the sample program in pt format:
+@smallexample
+@group
+(gdb) record instruction-history 12,14
+12         0x0040074c <ptwrite64+16>:   ptwrite %rbx
+13         [42]
+14         0x00400751 <ptwrite64+21>:   mov -0x8(%rbp),%rbx
+(gdb) record function-call-history
+1       main
+2       ptwrite64
+                [42]
+3       main
+@end group
+@end smallexample
+
+The @code{gdb.ptwrite} module allows customizing the default output of ptwrite
+auxiliary information.  A custom Python function can be registered via
+@code{gdb.ptwrite.register_filter} as the ptwrite filter function.
+This function will be called with the ptwrite payload and PC as arguments
+during trace decoding.
+
+@findex gdb.ptwrite.register_filter
+@defun register_filter (@var{filter})
+Used to register the ptwrite filter.  The filter can be any callable
+object that accepts two arguments, the payload and PC.  It can return
+a string, which will be printed by @value{GDBN} during the aforementioned
+commands, or @code{None}, resulting in no output.  @code{None} can also be
+registered to deactivate printing.
+@end defun
+
+@findex gdb.ptwrite.get_filter
+@defun get_filter ()
+Returns the currently active ptwrite filter function.
+@end defun
+
+@findex gdb.ptwrite.default_filter
+@defun default_filter (@var{payload}, @var{ip})
+The filter function active by default.  It prints the payload in hexadecimal
+format.
+@end defun
+
+@value{GDBN} creates a new copy of the filter function for each thread to
+allow for independent internal states.  There is no support for registering
+different filters for different threads.  The filter can however
+distinguish between multiple threads with the help of
+@code{gdb.selected_thread().global_num} (@pxref{Threads In Python}) or
+similar.  For example:
+
+@smallexample
+@group
+(gdb) python-interactive
+>>> class my_filter():
+...    def __init__(self):
+...        self.var = 0
+...    def __call__(self, payload, ip):
+...        if gdb.selected_thread().global_num == 1:
+...            self.var += 1
+...            return f"counter: @{self.var@}, ip: @{ip:#x@}"
+...        else:
+...            return None
+...
+>>> import gdb.ptwrite
+>>> gdb.ptwrite.register_filter(my_filter())
+>>>
+@end group
+
+@group
+(gdb) record function-call-history 59,64
+59      pthread_create@@GLIBC_2.2.5
+60      job()
+61      task(void*)
+62      ptwrite64(unsigned long)
+                [counter: 1, ip: 0x401156]
+63      task(void*)
+64      ptwrite32(unsigned int)
+                [counter: 2, ip: 0x40116c]
+@end group
+
+@group
+(gdb) info threads 
+* 1    Thread 0x7ffff7fd8740 (LWP 25796) "ptw_threads" task ()
+    at bin/ptwrite/ptw_threads.c:45
+  2    Thread 0x7ffff6eb8700 (LWP 25797) "ptw_threads" task ()
+    at bin/ptwrite/ptw_threads.c:45
+@end group
+
+@group
+(gdb) thread 2
+[Switching to thread 2 (Thread 0x7ffff6eb8700 (LWP 25797))]
+#0  task (arg=0x0) at ptwrite_threads.c:45
+45        return NULL;
+@end group
+
+@group
+(gdb) record function-call-history 10,14
+10    start_thread
+11    task(void*)
+12    ptwrite64(unsigned long)
+13    task(void*)
+14    ptwrite32(unsigned int)
+@end group
+@end smallexample
+
+This @value{GDBN} feature is dependent on hardware and operating system
+support and requires the Intel Processor Trace decoder library in version
+2.0.0 or newer.
diff --git a/gdb/testsuite/gdb.btrace/i386-ptwrite.S b/gdb/testsuite/gdb.btrace/i386-ptwrite.S
new file mode 100644
index 00000000000..efafb4b847b
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/i386-ptwrite.S
@@ -0,0 +1,550 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2022 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+   This file has been generated using gcc version 10.3.1 20210422
+   (Red Hat 10.3.1-1):
+   gcc -S -dA -g -m32 -mptwrite ptwrite.c -o i386-ptwrite.S.  */
+
+
+	.file	"ptwrite.c"
+	.text
+.Ltext0:
+	.globl	ptwrite1
+	.type	ptwrite1, @function
+ptwrite1:
+.LFB4021:
+	.file 1 "ptwrite.c"
+	# ptwrite.c:22:1
+	.loc 1 22 1
+	.cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (FALLTHRU)
+	pushl	%ebp
+	.cfi_def_cfa_offset 8
+	.cfi_offset 5, -8
+	movl	%esp, %ebp
+	.cfi_def_cfa_register 5
+	subl	$16, %esp
+	# ptwrite.c:23:3
+	.loc 1 23 3
+	movl	8(%ebp), %eax
+	movl	%eax, -4(%ebp)
+.LBB6:
+.LBB7:
+	.file 2 "/usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h"
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:307:3
+	.loc 2 307 3
+	movl	-4(%ebp), %eax
+	ptwrite	%eax
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:308:1
+	.loc 2 308 1
+	nop
+.LBE7:
+.LBE6:
+	# ptwrite.c:24:1
+	.loc 1 24 1
+	nop
+	leave
+	.cfi_restore 5
+	.cfi_def_cfa 4, 4
+# SUCC: EXIT [always]
+	ret
+	.cfi_endproc
+.LFE4021:
+	.size	ptwrite1, .-ptwrite1
+	.globl	ptwrite2
+	.type	ptwrite2, @function
+ptwrite2:
+.LFB4022:
+	# ptwrite.c:28:1
+	.loc 1 28 1
+	.cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (FALLTHRU)
+	pushl	%ebp
+	.cfi_def_cfa_offset 8
+	.cfi_offset 5, -8
+	movl	%esp, %ebp
+	.cfi_def_cfa_register 5
+	subl	$16, %esp
+	# ptwrite.c:29:3
+	.loc 1 29 3
+	movl	8(%ebp), %eax
+	movl	%eax, -4(%ebp)
+.LBB8:
+.LBB9:
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:307:3
+	.loc 2 307 3
+	movl	-4(%ebp), %eax
+	ptwrite	%eax
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:308:1
+	.loc 2 308 1
+	nop
+.LBE9:
+.LBE8:
+	# ptwrite.c:30:1
+	.loc 1 30 1
+	nop
+	leave
+	.cfi_restore 5
+	.cfi_def_cfa 4, 4
+# SUCC: EXIT [always]
+	ret
+	.cfi_endproc
+.LFE4022:
+	.size	ptwrite2, .-ptwrite2
+	.globl	main
+	.type	main, @function
+main:
+.LFB4023:
+	# ptwrite.c:34:1
+	.loc 1 34 1
+	.cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (FALLTHRU)
+	pushl	%ebp
+	.cfi_def_cfa_offset 8
+	.cfi_offset 5, -8
+	movl	%esp, %ebp
+	.cfi_def_cfa_register 5
+	# ptwrite.c:35:3
+	.loc 1 35 3
+	pushl	$66
+	call	ptwrite1
+	addl	$4, %esp
+	# ptwrite.c:36:3
+	.loc 1 36 3
+	pushl	$67
+	call	ptwrite2
+	addl	$4, %esp
+	# ptwrite.c:38:10
+	.loc 1 38 10
+	movl	$0, %eax
+	# ptwrite.c:39:1
+	.loc 1 39 1
+	leave
+	.cfi_restore 5
+	.cfi_def_cfa 4, 4
+# SUCC: EXIT [always]
+	ret
+	.cfi_endproc
+.LFE4023:
+	.size	main, .-main
+.Letext0:
+	.section	.debug_info,"",@progbits
+.Ldebug_info0:
+	.long	0x129	# Length of Compilation Unit Info
+	.value	0x4	# DWARF version number
+	.long	.Ldebug_abbrev0	# Offset Into Abbrev. Section
+	.byte	0x4	# Pointer Size (in bytes)
+	.uleb128 0x1	# (DIE (0xb) DW_TAG_compile_unit)
+	.long	.LASF15	# DW_AT_producer: "GNU C17 10.3.1 20210422 (Red Hat 10.3.1-1) -m32 -mptwrite -mtune=generic -march=i686 -g"
+	.byte	0xc	# DW_AT_language
+	.long	.LASF16	# DW_AT_name: "ptwrite.c"
+	.long	.LASF17	# DW_AT_comp_dir: "gdb/gdb/testsuite/gdb.btrace"
+	.long	.Ltext0	# DW_AT_low_pc
+	.long	.Letext0-.Ltext0	# DW_AT_high_pc
+	.long	.Ldebug_line0	# DW_AT_stmt_list
+	.uleb128 0x2	# (DIE (0x25) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.ascii "int\0"	# DW_AT_name
+	.uleb128 0x3	# (DIE (0x2c) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF0	# DW_AT_name: "short int"
+	.uleb128 0x3	# (DIE (0x33) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF1	# DW_AT_name: "char"
+	.uleb128 0x3	# (DIE (0x3a) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF2	# DW_AT_name: "long long int"
+	.uleb128 0x3	# (DIE (0x41) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x4	# DW_AT_encoding
+	.long	.LASF3	# DW_AT_name: "float"
+	.uleb128 0x3	# (DIE (0x48) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF4	# DW_AT_name: "unsigned int"
+	.uleb128 0x3	# (DIE (0x4f) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF5	# DW_AT_name: "long int"
+	.uleb128 0x3	# (DIE (0x56) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x8	# DW_AT_encoding
+	.long	.LASF6	# DW_AT_name: "unsigned char"
+	.uleb128 0x3	# (DIE (0x5d) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF7	# DW_AT_name: "short unsigned int"
+	.uleb128 0x3	# (DIE (0x64) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF8	# DW_AT_name: "long unsigned int"
+	.uleb128 0x3	# (DIE (0x6b) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF9	# DW_AT_name: "signed char"
+	.uleb128 0x3	# (DIE (0x72) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF10	# DW_AT_name: "long long unsigned int"
+	.uleb128 0x3	# (DIE (0x79) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x4	# DW_AT_encoding
+	.long	.LASF11	# DW_AT_name: "double"
+	.uleb128 0x4	# (DIE (0x80) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF18	# DW_AT_name: "main"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x21	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.long	0x25	# DW_AT_type
+	.long	.LFB4023	# DW_AT_low_pc
+	.long	.LFE4023-.LFB4023	# DW_AT_high_pc
+	.uleb128 0x1	# DW_AT_frame_base
+	.byte	0x9c	# DW_OP_call_frame_cfa
+			# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x5	# (DIE (0x96) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF12	# DW_AT_name: "ptwrite2"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x1b	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.long	.LFB4022	# DW_AT_low_pc
+	.long	.LFE4022-.LFB4022	# DW_AT_high_pc
+	.uleb128 0x1	# DW_AT_frame_base
+	.byte	0x9c	# DW_OP_call_frame_cfa
+			# DW_AT_GNU_all_call_sites
+	.long	0xd5	# DW_AT_sibling
+	.uleb128 0x6	# (DIE (0xac) DW_TAG_formal_parameter)
+	.long	.LASF14	# DW_AT_name: "value"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x1b	# DW_AT_decl_line
+	.byte	0xf	# DW_AT_decl_column
+	.long	0x25	# DW_AT_type
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 0
+	.uleb128 0x7	# (DIE (0xbb) DW_TAG_inlined_subroutine)
+	.long	0x114	# DW_AT_abstract_origin
+	.long	.LBB8	# DW_AT_low_pc
+	.long	.LBE8-.LBB8	# DW_AT_high_pc
+	.byte	0x1	# DW_AT_call_file (ptwrite.c)
+	.byte	0x1d	# DW_AT_call_line
+	.byte	0x3	# DW_AT_call_column
+	.uleb128 0x8	# (DIE (0xcb) DW_TAG_formal_parameter)
+	.long	0x11e	# DW_AT_abstract_origin
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -12
+	.byte	0	# end of children of DIE 0xbb
+	.byte	0	# end of children of DIE 0x96
+	.uleb128 0x5	# (DIE (0xd5) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF13	# DW_AT_name: "ptwrite1"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x15	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.long	.LFB4021	# DW_AT_low_pc
+	.long	.LFE4021-.LFB4021	# DW_AT_high_pc
+	.uleb128 0x1	# DW_AT_frame_base
+	.byte	0x9c	# DW_OP_call_frame_cfa
+			# DW_AT_GNU_all_call_sites
+	.long	0x114	# DW_AT_sibling
+	.uleb128 0x6	# (DIE (0xeb) DW_TAG_formal_parameter)
+	.long	.LASF14	# DW_AT_name: "value"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x15	# DW_AT_decl_line
+	.byte	0xf	# DW_AT_decl_column
+	.long	0x25	# DW_AT_type
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 0
+	.uleb128 0x7	# (DIE (0xfa) DW_TAG_inlined_subroutine)
+	.long	0x114	# DW_AT_abstract_origin
+	.long	.LBB6	# DW_AT_low_pc
+	.long	.LBE6-.LBB6	# DW_AT_high_pc
+	.byte	0x1	# DW_AT_call_file (ptwrite.c)
+	.byte	0x17	# DW_AT_call_line
+	.byte	0x3	# DW_AT_call_column
+	.uleb128 0x8	# (DIE (0x10a) DW_TAG_formal_parameter)
+	.long	0x11e	# DW_AT_abstract_origin
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -12
+	.byte	0	# end of children of DIE 0xfa
+	.byte	0	# end of children of DIE 0xd5
+	.uleb128 0x9	# (DIE (0x114) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF19	# DW_AT_name: "_ptwrite32"
+	.byte	0x2	# DW_AT_decl_file (/usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h)
+	.value	0x131	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.byte	0x3	# DW_AT_inline
+			# DW_AT_artificial
+	.uleb128 0xa	# (DIE (0x11e) DW_TAG_formal_parameter)
+	.ascii "__B\0"	# DW_AT_name
+	.byte	0x2	# DW_AT_decl_file (/usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h)
+	.value	0x131	# DW_AT_decl_line
+	.byte	0x16	# DW_AT_decl_column
+	.long	0x48	# DW_AT_type
+	.byte	0	# end of children of DIE 0x114
+	.byte	0	# end of children of DIE 0xb
+	.section	.debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+	.uleb128 0x1	# (abbrev code)
+	.uleb128 0x11	# (TAG: DW_TAG_compile_unit)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x25	# (DW_AT_producer)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x13	# (DW_AT_language)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x1b	# (DW_AT_comp_dir)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x10	# (DW_AT_stmt_list)
+	.uleb128 0x17	# (DW_FORM_sec_offset)
+	.byte	0
+	.byte	0
+	.uleb128 0x2	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.byte	0
+	.byte	0
+	.uleb128 0x3	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.byte	0
+	.byte	0
+	.uleb128 0x4	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.byte	0
+	.byte	0
+	.uleb128 0x5	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.uleb128 0x2117	# (DW_AT_GNU_all_call_sites)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x6	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.byte	0
+	.byte	0
+	.uleb128 0x7	# (abbrev code)
+	.uleb128 0x1d	# (TAG: DW_TAG_inlined_subroutine)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x31	# (DW_AT_abstract_origin)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.uleb128 0x58	# (DW_AT_call_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x59	# (DW_AT_call_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x57	# (DW_AT_call_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0x8	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x31	# (DW_AT_abstract_origin)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.byte	0
+	.byte	0
+	.uleb128 0x9	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0x5	# (DW_FORM_data2)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x20	# (DW_AT_inline)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x34	# (DW_AT_artificial)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.byte	0
+	.byte	0
+	.uleb128 0xa	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0x5	# (DW_FORM_data2)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_aranges,"",@progbits
+	.long	0x1c	# Length of Address Ranges Info
+	.value	0x2	# DWARF aranges version
+	.long	.Ldebug_info0	# Offset of Compilation Unit Info
+	.byte	0x4	# Size of Address
+	.byte	0	# Size of Segment Descriptor
+	.value	0	# Pad to 8 byte boundary
+	.value	0
+	.long	.Ltext0	# Address
+	.long	.Letext0-.Ltext0	# Length
+	.long	0
+	.long	0
+	.section	.debug_line,"",@progbits
+.Ldebug_line0:
+	.section	.debug_str,"MS",@progbits,1
+.LASF2:
+	.string	"long long int"
+.LASF14:
+	.string	"value"
+.LASF19:
+	.string	"_ptwrite32"
+.LASF4:
+	.string	"unsigned int"
+.LASF17:
+	.string	"gdb/gdb/testsuite/gdb.btrace"
+.LASF18:
+	.string	"main"
+.LASF16:
+	.string	"ptwrite.c"
+.LASF8:
+	.string	"long unsigned int"
+.LASF10:
+	.string	"long long unsigned int"
+.LASF13:/
+	.string	"ptwrite1"
+.LASF12:
+	.string	"ptwrite2"
+.LASF6:
+	.string	"unsigned char"
+.LASF1:
+	.string	"char"
+.LASF5:
+	.string	"long int"
+.LASF15:
+	.string	"GNU C17 10.3.1 20210422 (Red Hat 10.3.1-1) -m32 -mptwrite -mtune=generic -march=i686 -g"
+.LASF11:
+	.string	"double"
+.LASF7:
+	.string	"short unsigned int"
+.LASF9:
+	.string	"signed char"
+.LASF3:
+	.string	"float"
+.LASF0:
+	.string	"short int"
+	.ident	"GCC: (GNU) 10.3.1 20210422 (Red Hat 10.3.1-1)"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.btrace/ptwrite.c b/gdb/testsuite/gdb.btrace/ptwrite.c
new file mode 100644
index 00000000000..c85b656919b
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/ptwrite.c
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2021 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <immintrin.h>
+
+void
+ptwrite1 (int value)
+{
+  _ptwrite32 (value);
+}
+
+void
+ptwrite2 (int value)
+{
+  _ptwrite32 (value);
+}
+
+int
+main (void)
+{
+  ptwrite1 (0x42);
+  ptwrite2 (0x43);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.btrace/ptwrite.exp b/gdb/testsuite/gdb.btrace/ptwrite.exp
new file mode 100644
index 00000000000..569760087a4
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/ptwrite.exp
@@ -0,0 +1,209 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2021 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib gdb-python.exp
+
+if { [skip_btrace_ptw_tests] } {
+    unsupported "No support for ptwrite decoding."
+    return -1
+}
+
+set opts {}
+
+if [info exists COMPILE] {
+    # make check RUNTESTFLAGS="gdb.btrace/ptwrite.exp COMPILE=1"
+    standard_testfile ptwrite.c
+    lappend opts debug additional_flags=-mptwrite
+} elseif {[istarget "i?86-*-*"] || [istarget "x86_64-*-*"]} {
+    if {[is_amd64_regs_target]} {
+	standard_testfile x86_64-ptwrite.S
+    } else {
+	standard_testfile i386-ptwrite.S
+    }
+} else {
+    unsupported "target architecture not supported"
+    return -1
+}
+
+if [prepare_for_testing "failed to prepare" $testfile $srcfile $opts] {
+    return -1
+}
+
+if { ![runto_main] } {
+    untested "failed to run to main"
+    return -1
+}
+
+# This needs to be after runto_main
+if { [skip_python_tests] } {
+    unsupported "Configuration doesn't support python scripting."
+    return -1
+}
+
+### 1. Default testrun
+
+# Setup recording
+gdb_test_no_output "set record instruction-history-size unlimited"
+gdb_test_no_output "record btrace pt"
+gdb_test "next" ".*" "next"
+gdb_test "next" ".*" "next 2"
+
+with_test_prefix "Default" {
+    # Test record instruction-history
+    gdb_test "record instruction-history 1" [multi_line \
+	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   \\\[42\\\]" \
+	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   \\\[43\\\].*" \
+	]
+
+    gdb_test "record instruction-history /a 1" [multi_line \
+	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+.*" \
+	]
+
+    # Test function call history
+    gdb_test "record function-call-history 1,4" [multi_line \
+	"1\tmain" \
+	"2\tptwrite1" \
+	"\t\t\\\[42\\\]" \
+	"3\tmain" \
+	"4\tptwrite2" \
+	"\t\t\\\[43\\\]" \
+	]
+
+    gdb_test "record function-call-history /a 1,4" [multi_line \
+	"1\tmain" \
+	"2\tptwrite1" \
+	"3\tmain" \
+	"4\tptwrite2" \
+	]
+}
+
+# Test payload printing during stepping
+with_test_prefix "Stepping" {
+    gdb_test "record goto 10" "No such instruction\."
+    gdb_test "record goto 9" ".*ptwrite.* at .*"
+    gdb_test "stepi" ".*\\\[42\\\].*"
+    gdb_test "reverse-stepi" ".*\\\[42\\\].*"
+    gdb_test "continue" [multi_line \
+	    ".*\\\[42\\\]" \
+	    "\\\[43\\\].*" \
+	    ]
+    gdb_test "reverse-continue" [multi_line \
+	    ".*\\\[43\\\]" \
+	    "\\\[42\\\].*" \
+	    ]
+}
+
+# Test auxiliary type in python
+gdb_test_multiline "auxiliary type in python" \
+    "python" "" \
+    "h = gdb.current_recording().instruction_history" "" \
+    "for insn in h:" "" \
+    "    if hasattr(insn, 'decoded'):" "" \
+    "        print(insn.decoded.decode())" "" \
+    "    elif hasattr(insn, 'data'):" "" \
+    "        print(insn.data)" "" \
+    "end" \
+    [multi_line \
+	".*mov    -0x4\\\(%(e|r)bp\\\),%(e|r)ax" \
+	"ptwrite %eax" \
+	"42" \
+	"nop.*" \
+	"mov    -0x4\\\(%(e|r)bp\\\),%(e|r)ax" \
+	"ptwrite %eax" \
+	"43" \
+	"nop.*"
+    ]
+
+
+### 2. Test filter registration
+### 2.1 Custom filter
+with_test_prefix "Custom" {
+    gdb_test_multiline "register filter in python" \
+	"python" "" \
+	"def my_filter(payload, ip):" "" \
+	"    if  payload == 66:" "" \
+	"        return \"payload: {0}, ip: {1:#x}\".format(payload, ip)" "" \
+	"    else:" "" \
+	"        return None" "" \
+	"import gdb.ptwrite" "" \
+	"gdb.ptwrite.register_filter(my_filter)" "" \
+	"end" ""
+
+    gdb_test "record instruction-history 1" [multi_line \
+	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   \\\[payload: 66, ip: $hex\\\]" \
+	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:.*" \
+	]
+}
+
+### 2.2 None as filter
+with_test_prefix "None" {
+    gdb_test_multiline "register filter in python" \
+	"python" "" \
+	"import gdb.ptwrite" "" \
+	"gdb.ptwrite.register_filter(None)" "" \
+	"end" ""
+
+    gdb_test "record instruction-history 1" [multi_line \
+	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:.*" \
+	"\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:.*" \
+	]
+}
+
+### 2.3 Lambdas as filter
+with_test_prefix "Lambdas" {
+    gdb_test_multiline "register filter in python" \
+	"python" "" \
+	"import gdb.ptwrite" "" \
+	"gdb.ptwrite.register_filter(lambda payload, ip: \"{}\".format(payload + 2))" "" \
+	"end" ""
+
+    gdb_test "record instruction-history 1" [multi_line \
+	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   \\\[68\\\]" \
+	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   \\\[69\\\].*" \
+	] "Lambdas: record instruction-history 1"
+}
+
+### 2.4 Functors as filter
+with_test_prefix "Functors" {
+    gdb_test_multiline "register filter in python" \
+	"python" "" \
+	"import gdb.ptwrite" "" \
+	"class foobar(object):" "" \
+	"    def __init__(self):" "" \
+	"        self.variable = 0" "" \
+	"    def __call__(self, payload, ip):" "" \
+	"        self.variable += 1" "" \
+	"        return \"{}, {}\".format(self.variable, payload)" "" \
+	"gdb.ptwrite.register_filter(foobar())" "" \
+	"end" ""
+
+    gdb_test "record instruction-history 1" [multi_line \
+	".*\[0-9\]+\t   $hex <ptwrite1\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   \\\[1, 66\\\]" \
+	".*\[0-9\]+\t   $hex <ptwrite2\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+	"\[0-9\]+\t   \\\[2, 67\\\].*" \
+	] "Functors: record instruction-history 1"
+}
diff --git a/gdb/testsuite/gdb.btrace/x86_64-ptwrite.S b/gdb/testsuite/gdb.btrace/x86_64-ptwrite.S
new file mode 100644
index 00000000000..6fe64013399
--- /dev/null
+++ b/gdb/testsuite/gdb.btrace/x86_64-ptwrite.S
@@ -0,0 +1,544 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2022 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+   This file has been generated using gcc version 10.3.1 20210422
+   (Red Hat 10.3.1-1):
+   gcc -S -dA -g -mptwrite ptwrite.c -o x86_64-ptwrite.S.  */
+
+	.file	"ptwrite.c"
+	.text
+.Ltext0:
+	.globl	ptwrite1
+	.type	ptwrite1, @function
+ptwrite1:
+.LFB4096:
+	.file 1 "ptwrite.c"
+	# ptwrite.c:22:1
+	.loc 1 22 1
+	.cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (FALLTHRU)
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset 6, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register 6
+	movl	%edi, -20(%rbp)
+	# ptwrite.c:23:3
+	.loc 1 23 3
+	movl	-20(%rbp), %eax
+	movl	%eax, -4(%rbp)
+.LBB6:
+.LBB7:
+	.file 2 "/usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h"
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:307:3
+	.loc 2 307 3
+	movl	-4(%rbp), %eax
+	ptwrite	%eax
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:308:1
+	.loc 2 308 1
+	nop
+.LBE7:
+.LBE6:
+	# ptwrite.c:24:1
+	.loc 1 24 1
+	nop
+	popq	%rbp
+	.cfi_def_cfa 7, 8
+# SUCC: EXIT [always] 
+	ret
+	.cfi_endproc
+.LFE4096:
+	.size	ptwrite1, .-ptwrite1
+	.globl	ptwrite2
+	.type	ptwrite2, @function
+ptwrite2:
+.LFB4097:
+	# ptwrite.c:28:1
+	.loc 1 28 1
+	.cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (FALLTHRU)
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset 6, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register 6
+	movl	%edi, -20(%rbp)
+	# ptwrite.c:29:3
+	.loc 1 29 3
+	movl	-20(%rbp), %eax
+	movl	%eax, -4(%rbp)
+.LBB8:
+.LBB9:
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:307:3
+	.loc 2 307 3
+	movl	-4(%rbp), %eax
+	ptwrite	%eax
+	# /usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h:308:1
+	.loc 2 308 1
+	nop
+.LBE9:
+.LBE8:
+	# ptwrite.c:30:1
+	.loc 1 30 1
+	nop
+	popq	%rbp
+	.cfi_def_cfa 7, 8
+# SUCC: EXIT [always] 
+	ret
+	.cfi_endproc
+.LFE4097:
+	.size	ptwrite2, .-ptwrite2
+	.globl	main
+	.type	main, @function
+main:
+.LFB4098:
+	# ptwrite.c:34:1
+	.loc 1 34 1
+	.cfi_startproc
+# BLOCK 2 seq:0
+# PRED: ENTRY (FALLTHRU)
+	pushq	%rbp
+	.cfi_def_cfa_offset 16
+	.cfi_offset 6, -16
+	movq	%rsp, %rbp
+	.cfi_def_cfa_register 6
+	# ptwrite.c:35:3
+	.loc 1 35 3
+	movl	$66, %edi
+	call	ptwrite1
+	# ptwrite.c:36:3
+	.loc 1 36 3
+	movl	$67, %edi
+	call	ptwrite2
+	# ptwrite.c:38:10
+	.loc 1 38 10
+	movl	$0, %eax
+	# ptwrite.c:39:1
+	.loc 1 39 1
+	popq	%rbp
+	.cfi_def_cfa 7, 8
+# SUCC: EXIT [always] 
+	ret
+	.cfi_endproc
+.LFE4098:
+	.size	main, .-main
+.Letext0:
+	.section	.debug_info,"",@progbits
+.Ldebug_info0:
+	.long	0x159	# Length of Compilation Unit Info
+	.value	0x4	# DWARF version number
+	.long	.Ldebug_abbrev0	# Offset Into Abbrev. Section
+	.byte	0x8	# Pointer Size (in bytes)
+	.uleb128 0x1	# (DIE (0xb) DW_TAG_compile_unit)
+	.long	.LASF15	# DW_AT_producer: "GNU C17 10.3.1 20210422 (Red Hat 10.3.1-1) -mptwrite -mtune=generic -march=x86-64 -g"
+	.byte	0xc	# DW_AT_language
+	.long	.LASF16	# DW_AT_name: "ptwrite.c"
+	.long	.LASF17	# DW_AT_comp_dir: "gdb/gdb/testsuite/gdb.btrace"
+	.quad	.Ltext0	# DW_AT_low_pc
+	.quad	.Letext0-.Ltext0	# DW_AT_high_pc
+	.long	.Ldebug_line0	# DW_AT_stmt_list
+	.uleb128 0x2	# (DIE (0x2d) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.ascii "int\0"	# DW_AT_name
+	.uleb128 0x3	# (DIE (0x34) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF0	# DW_AT_name: "short int"
+	.uleb128 0x3	# (DIE (0x3b) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF1	# DW_AT_name: "char"
+	.uleb128 0x3	# (DIE (0x42) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF2	# DW_AT_name: "long long int"
+	.uleb128 0x3	# (DIE (0x49) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x4	# DW_AT_encoding
+	.long	.LASF3	# DW_AT_name: "float"
+	.uleb128 0x3	# (DIE (0x50) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF4	# DW_AT_name: "long unsigned int"
+	.uleb128 0x3	# (DIE (0x57) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x5	# DW_AT_encoding
+	.long	.LASF5	# DW_AT_name: "long int"
+	.uleb128 0x3	# (DIE (0x5e) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x8	# DW_AT_encoding
+	.long	.LASF6	# DW_AT_name: "unsigned char"
+	.uleb128 0x3	# (DIE (0x65) DW_TAG_base_type)
+	.byte	0x2	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF7	# DW_AT_name: "short unsigned int"
+	.uleb128 0x3	# (DIE (0x6c) DW_TAG_base_type)
+	.byte	0x4	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF8	# DW_AT_name: "unsigned int"
+	.uleb128 0x3	# (DIE (0x73) DW_TAG_base_type)
+	.byte	0x1	# DW_AT_byte_size
+	.byte	0x6	# DW_AT_encoding
+	.long	.LASF9	# DW_AT_name: "signed char"
+	.uleb128 0x3	# (DIE (0x7a) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x7	# DW_AT_encoding
+	.long	.LASF10	# DW_AT_name: "long long unsigned int"
+	.uleb128 0x3	# (DIE (0x81) DW_TAG_base_type)
+	.byte	0x8	# DW_AT_byte_size
+	.byte	0x4	# DW_AT_encoding
+	.long	.LASF11	# DW_AT_name: "double"
+	.uleb128 0x4	# (DIE (0x88) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF18	# DW_AT_name: "main"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x21	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.long	0x2d	# DW_AT_type
+	.quad	.LFB4098	# DW_AT_low_pc
+	.quad	.LFE4098-.LFB4098	# DW_AT_high_pc
+	.uleb128 0x1	# DW_AT_frame_base
+	.byte	0x9c	# DW_OP_call_frame_cfa
+			# DW_AT_GNU_all_tail_call_sites
+	.uleb128 0x5	# (DIE (0xa6) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF12	# DW_AT_name: "ptwrite2"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x1b	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.quad	.LFB4097	# DW_AT_low_pc
+	.quad	.LFE4097-.LFB4097	# DW_AT_high_pc
+	.uleb128 0x1	# DW_AT_frame_base
+	.byte	0x9c	# DW_OP_call_frame_cfa
+			# DW_AT_GNU_all_call_sites
+	.long	0xf5	# DW_AT_sibling
+	.uleb128 0x6	# (DIE (0xc4) DW_TAG_formal_parameter)
+	.long	.LASF14	# DW_AT_name: "value"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x1b	# DW_AT_decl_line
+	.byte	0xf	# DW_AT_decl_column
+	.long	0x2d	# DW_AT_type
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -36
+	.uleb128 0x7	# (DIE (0xd3) DW_TAG_inlined_subroutine)
+	.long	0x144	# DW_AT_abstract_origin
+	.quad	.LBB8	# DW_AT_low_pc
+	.quad	.LBE8-.LBB8	# DW_AT_high_pc
+	.byte	0x1	# DW_AT_call_file (ptwrite.c)
+	.byte	0x1d	# DW_AT_call_line
+	.byte	0x3	# DW_AT_call_column
+	.uleb128 0x8	# (DIE (0xeb) DW_TAG_formal_parameter)
+	.long	0x14e	# DW_AT_abstract_origin
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -20
+	.byte	0	# end of children of DIE 0xd3
+	.byte	0	# end of children of DIE 0xa6
+	.uleb128 0x5	# (DIE (0xf5) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF13	# DW_AT_name: "ptwrite1"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x15	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.quad	.LFB4096	# DW_AT_low_pc
+	.quad	.LFE4096-.LFB4096	# DW_AT_high_pc
+	.uleb128 0x1	# DW_AT_frame_base
+	.byte	0x9c	# DW_OP_call_frame_cfa
+			# DW_AT_GNU_all_call_sites
+	.long	0x144	# DW_AT_sibling
+	.uleb128 0x6	# (DIE (0x113) DW_TAG_formal_parameter)
+	.long	.LASF14	# DW_AT_name: "value"
+	.byte	0x1	# DW_AT_decl_file (ptwrite.c)
+	.byte	0x15	# DW_AT_decl_line
+	.byte	0xf	# DW_AT_decl_column
+	.long	0x2d	# DW_AT_type
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -36
+	.uleb128 0x7	# (DIE (0x122) DW_TAG_inlined_subroutine)
+	.long	0x144	# DW_AT_abstract_origin
+	.quad	.LBB6	# DW_AT_low_pc
+	.quad	.LBE6-.LBB6	# DW_AT_high_pc
+	.byte	0x1	# DW_AT_call_file (ptwrite.c)
+	.byte	0x17	# DW_AT_call_line
+	.byte	0x3	# DW_AT_call_column
+	.uleb128 0x8	# (DIE (0x13a) DW_TAG_formal_parameter)
+	.long	0x14e	# DW_AT_abstract_origin
+	.uleb128 0x2	# DW_AT_location
+	.byte	0x91	# DW_OP_fbreg
+	.sleb128 -20
+	.byte	0	# end of children of DIE 0x122
+	.byte	0	# end of children of DIE 0xf5
+	.uleb128 0x9	# (DIE (0x144) DW_TAG_subprogram)
+			# DW_AT_external
+	.long	.LASF19	# DW_AT_name: "_ptwrite32"
+	.byte	0x2	# DW_AT_decl_file (/usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h)
+	.value	0x131	# DW_AT_decl_line
+	.byte	0x1	# DW_AT_decl_column
+			# DW_AT_prototyped
+	.byte	0x3	# DW_AT_inline
+			# DW_AT_artificial
+	.uleb128 0xa	# (DIE (0x14e) DW_TAG_formal_parameter)
+	.ascii "__B\0"	# DW_AT_name
+	.byte	0x2	# DW_AT_decl_file (/usr/lib/gcc/x86_64-redhat-linux/10/include/immintrin.h)
+	.value	0x131	# DW_AT_decl_line
+	.byte	0x16	# DW_AT_decl_column
+	.long	0x6c	# DW_AT_type
+	.byte	0	# end of children of DIE 0x144
+	.byte	0	# end of children of DIE 0xb
+	.section	.debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+	.uleb128 0x1	# (abbrev code)
+	.uleb128 0x11	# (TAG: DW_TAG_compile_unit)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x25	# (DW_AT_producer)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x13	# (DW_AT_language)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x1b	# (DW_AT_comp_dir)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x7	# (DW_FORM_data8)
+	.uleb128 0x10	# (DW_AT_stmt_list)
+	.uleb128 0x17	# (DW_FORM_sec_offset)
+	.byte	0
+	.byte	0
+	.uleb128 0x2	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.byte	0
+	.byte	0
+	.uleb128 0x3	# (abbrev code)
+	.uleb128 0x24	# (TAG: DW_TAG_base_type)
+	.byte	0	# DW_children_no
+	.uleb128 0xb	# (DW_AT_byte_size)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3e	# (DW_AT_encoding)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.byte	0
+	.byte	0
+	.uleb128 0x4	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0	# DW_children_no
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x7	# (DW_FORM_data8)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.uleb128 0x2116	# (DW_AT_GNU_all_tail_call_sites)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.byte	0
+	.byte	0
+	.uleb128 0x5	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x7	# (DW_FORM_data8)
+	.uleb128 0x40	# (DW_AT_frame_base)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.uleb128 0x2117	# (DW_AT_GNU_all_call_sites)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x1	# (DW_AT_sibling)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.uleb128 0x6	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.byte	0
+	.byte	0
+	.uleb128 0x7	# (abbrev code)
+	.uleb128 0x1d	# (TAG: DW_TAG_inlined_subroutine)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x31	# (DW_AT_abstract_origin)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x11	# (DW_AT_low_pc)
+	.uleb128 0x1	# (DW_FORM_addr)
+	.uleb128 0x12	# (DW_AT_high_pc)
+	.uleb128 0x7	# (DW_FORM_data8)
+	.uleb128 0x58	# (DW_AT_call_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x59	# (DW_AT_call_line)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x57	# (DW_AT_call_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.byte	0
+	.byte	0
+	.uleb128 0x8	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x31	# (DW_AT_abstract_origin)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.uleb128 0x2	# (DW_AT_location)
+	.uleb128 0x18	# (DW_FORM_exprloc)
+	.byte	0
+	.byte	0
+	.uleb128 0x9	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x1	# DW_children_yes
+	.uleb128 0x3f	# (DW_AT_external)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0xe	# (DW_FORM_strp)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0x5	# (DW_FORM_data2)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x27	# (DW_AT_prototyped)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.uleb128 0x20	# (DW_AT_inline)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x34	# (DW_AT_artificial)
+	.uleb128 0x19	# (DW_FORM_flag_present)
+	.byte	0
+	.byte	0
+	.uleb128 0xa	# (abbrev code)
+	.uleb128 0x5	# (TAG: DW_TAG_formal_parameter)
+	.byte	0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x3a	# (DW_AT_decl_file)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x3b	# (DW_AT_decl_line)
+	.uleb128 0x5	# (DW_FORM_data2)
+	.uleb128 0x39	# (DW_AT_decl_column)
+	.uleb128 0xb	# (DW_FORM_data1)
+	.uleb128 0x49	# (DW_AT_type)
+	.uleb128 0x13	# (DW_FORM_ref4)
+	.byte	0
+	.byte	0
+	.byte	0
+	.section	.debug_aranges,"",@progbits
+	.long	0x2c	# Length of Address Ranges Info
+	.value	0x2	# DWARF aranges version
+	.long	.Ldebug_info0	# Offset of Compilation Unit Info
+	.byte	0x8	# Size of Address
+	.byte	0	# Size of Segment Descriptor
+	.value	0	# Pad to 16 byte boundary
+	.value	0
+	.quad	.Ltext0	# Address
+	.quad	.Letext0-.Ltext0	# Length
+	.quad	0
+	.quad	0
+	.section	.debug_line,"",@progbits
+.Ldebug_line0:
+	.section	.debug_str,"MS",@progbits,1
+.LASF2:
+	.string	"long long int"
+.LASF14:
+	.string	"value"
+.LASF19:
+	.string	"_ptwrite32"
+.LASF8:
+	.string	"unsigned int"
+.LASF17:
+	.string	"gdb/gdb/testsuite/gdb.btrace"
+.LASF18:
+	.string	"main"
+.LASF16:
+	.string	"ptwrite.c"
+.LASF4:
+	.string	"long unsigned int"
+.LASF10:
+	.string	"long long unsigned int"
+.LASF15:
+	.string	"GNU C17 10.3.1 20210422 (Red Hat 10.3.1-1) -mptwrite -mtune=generic -march=x86-64 -g"
+.LASF13:
+	.string	"ptwrite1"
+.LASF12:
+	.string	"ptwrite2"
+.LASF6:
+	.string	"unsigned char"
+.LASF1:
+	.string	"char"
+.LASF5:
+	.string	"long int"
+.LASF11:
+	.string	"double"
+.LASF7:
+	.string	"short unsigned int"
+.LASF9:
+	.string	"signed char"
+.LASF3:
+	.string	"float"
+.LASF0:
+	.string	"short int"
+	.ident	"GCC: (GNU) 10.3.1 20210422 (Red Hat 10.3.1-1)"
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 0f6bb20b49c..99039e9e6c4 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -3687,6 +3687,80 @@ gdb_caching_proc skip_btrace_pt_tests {
     return $skip_btrace_tests
 }
 
+# Run a test on the target to see if it supports ptwrite instructions and
+# if GDB can decode ptwrite events.  Return 0 if so, 1 if it does not.
+
+gdb_caching_proc skip_btrace_ptw_tests {
+    global srcdir subdir gdb_prompt inferior_exited_re decimal
+
+    set me "skip_ptw_tests"
+    if { [skip_btrace_pt_tests] } {
+	verbose "$me:  target does not support btrace pt, returning 1" 2
+	return 1
+    }
+
+    set src {
+	int
+	main ()
+	{
+	  asm volatile ("PTWRITE %0;" : : "b"(0x42));
+	  return 0;
+	}
+    }
+
+    if {![gdb_simple_compile $me $src executable]} {
+        return 1
+    }
+
+    gdb_exit
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load "$obj"
+    if ![runto_main] {
+        return 1
+    }
+
+    gdb_test_no_output "record btrace pt" "$me: record btrace pt"
+
+    set skip_ptw_tests 2
+    gdb_test_multiple "next" "$me: next" {
+        -re -wrap ".*Illegal instruction.*" {
+            verbose -log "$me:  ptwrite instruction support not detected."
+            set skip_ptw_tests 2
+        }
+        -re -wrap ".*$inferior_exited_re normally.*" {
+            verbose -log "$me:  ptwrite support not detected."
+            set skip_ptw_tests 2
+        }
+        -re -wrap "$decimal.*(at|in).*" {
+            set skip_ptw_tests 1
+        }
+    }
+
+    if { $skip_ptw_tests == 1 } {
+	# Show the func-call-history to get the packet trace.
+	gdb_test "record function-call-history" ".*"
+
+	gdb_test_multiple "maintenance btrace packet-history 0,1000" \
+	    "$me: check decoding support" {
+	    -re  "ptw" {
+		verbose -log "$me:  ptwrite decoding support detected."
+		set skip_ptw_tests 0
+	    }
+	    -re ".*${gdb_prompt} $" {
+		verbose -log "$me:  ptwrite decoding support not detected."
+	    }
+	}
+    }
+
+    gdb_exit
+    remote_file build delete $obj
+
+    verbose "$me:  returning $skip_ptw_tests" 2
+    return $skip_ptw_tests
+}
+
+
 # Run a test on the target to see if it supports Aarch64 SVE hardware.
 # Return 0 if so, 1 if it does not.  Note this causes a restart of GDB.
 
diff --git a/gdbsupport/common.m4 b/gdbsupport/common.m4
index 0fed186ae1d..526f7d47c05 100644
--- a/gdbsupport/common.m4
+++ b/gdbsupport/common.m4
@@ -179,6 +179,8 @@ AC_DEFUN([GDB_AC_COMMON], [
       AC_CHECK_FUNCS(pt_insn_event)
       AC_CHECK_MEMBERS([struct pt_insn.enabled, struct pt_insn.resynced], [], [],
 		       [#include <intel-pt.h>])
+      AC_CHECK_MEMBERS([struct pt_event.variant.ptwrite], [], [],
+		       [#include <intel-pt.h>])
       LIBS=$save_LIBS
     fi
   fi
diff --git a/gdbsupport/config.in b/gdbsupport/config.in
index 577866c97b3..56a314195f3 100644
--- a/gdbsupport/config.in
+++ b/gdbsupport/config.in
@@ -235,6 +235,9 @@
 /* Define to 1 if you have the <string.h> header file. */
 #undef HAVE_STRING_H
 
+/* Define to 1 if `variant.ptwrite' is a member of `struct pt_event'. */
+#undef HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE
+
 /* Define to 1 if `enabled' is a member of `struct pt_insn'. */
 #undef HAVE_STRUCT_PT_INSN_ENABLED
 
diff --git a/gdbsupport/configure b/gdbsupport/configure
index 1b0752609e5..5b1d9bde715 100755
--- a/gdbsupport/configure
+++ b/gdbsupport/configure
@@ -9605,6 +9605,17 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
+fi
+
+      ac_fn_c_check_member "$LINENO" "struct pt_event" "variant.ptwrite" "ac_cv_member_struct_pt_event_variant_ptwrite" "#include <intel-pt.h>
+"
+if test "x$ac_cv_member_struct_pt_event_variant_ptwrite" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_PT_EVENT_VARIANT_PTWRITE 1
+_ACEOF
+
+
 fi
 
       LIBS=$save_LIBS
-- 
2.34.3

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de <http://www.intel.de>
Managing Directors: Christin Eisenschmid, Sharon Heck, Tiffany Doon Silva  
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928


  parent reply	other threads:[~2022-09-16 11:38 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-16 11:36 [PATCH v6 00/10] Extensions for PTWRITE Felix Willgerodt
2022-09-16 11:36 ` [PATCH v6 01/10] btrace: Introduce auxiliary instructions Felix Willgerodt
2022-09-16 11:46   ` Eli Zaretskii
2022-09-16 14:01     ` Willgerodt, Felix
2022-09-16 14:18       ` Eli Zaretskii
2022-09-16 11:36 ` [PATCH v6 02/10] btrace: Enable auxiliary instructions in record instruction-history Felix Willgerodt
2022-09-16 11:50   ` Eli Zaretskii
2022-09-16 11:36 ` [PATCH v6 03/10] btrace: Enable auxiliary instructions in record function-call-history Felix Willgerodt
2022-09-16 11:43   ` Eli Zaretskii
2022-09-16 11:36 ` [PATCH v6 04/10] btrace: Handle stepping and goto for auxiliary instructions Felix Willgerodt
2022-09-16 11:36 ` [PATCH v6 05/10] python: Introduce gdb.RecordAuxiliary class Felix Willgerodt
2022-09-16 12:04   ` Eli Zaretskii
2022-09-16 11:36 ` [PATCH v6 06/10] python: Add clear() to gdb.Record Felix Willgerodt
2022-09-16 11:49   ` Eli Zaretskii
2022-09-16 11:36 ` [PATCH v6 07/10] btrace, gdbserver: Add ptwrite to btrace_config_pt Felix Willgerodt
2022-09-16 11:49   ` Eli Zaretskii
2022-09-16 14:02     ` Willgerodt, Felix
2022-10-19 14:41   ` Metzger, Markus T
2022-10-20 11:49     ` Willgerodt, Felix
2022-10-20 12:31       ` Metzger, Markus T
2022-09-16 11:36 ` [PATCH v6 08/10] btrace, linux: Enable ptwrite packets Felix Willgerodt
2022-09-16 11:36 ` [PATCH v6 09/10] btrace, python: Enable ptwrite filter registration Felix Willgerodt
2022-10-19 14:41   ` Metzger, Markus T
2022-10-20 11:49     ` Willgerodt, Felix
2022-10-20 12:33       ` Metzger, Markus T
2022-09-16 11:36 ` Felix Willgerodt [this message]
2022-09-16 12:01   ` [PATCH v6 10/10] btrace: Extend ptwrite event decoding Eli Zaretskii
2022-09-16 14:02     ` Willgerodt, Felix
2022-09-16 14:21       ` Eli Zaretskii
2022-09-16 14:34         ` Willgerodt, Felix
2022-09-16 15:29           ` Eli Zaretskii
2022-09-19 11:23             ` Willgerodt, Felix
2022-10-19 14:45 ` [PATCH v6 00/10] Extensions for PTWRITE Metzger, Markus T

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220916113646.49749-11-felix.willgerodt@intel.com \
    --to=felix.willgerodt@intel.com \
    --cc=gdb-patches@sourceware.org \
    --cc=markus.t.metzger@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).