[10/10] btrace: Extend event decoding for ptwrite.
Commit Message
From: Felix Willgerodt <felix.willgerodt@intel.com>
Call the ptwrite listener 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.
2019-05-29 Felix Willgerodt <felix.willgerodt@intel.com>
gdb/ChangeLog:
* btrace.c (handle_pt_insn_events): Handle ptev_ptwrite.
gdb/testsuite/ChangeLog:
* gdb.btrace/ptwrite.c: New file.
* gdb.btrace/ptwrite.exp: New file.
* gdb.btrace/x86_64-ptwrite.S: New file.
* lib/gdb.exp (skip_btrace_ptw_tests): New function.
gdb/doc/ChangeLog:
* python.texi (gdb.ptwrite): New documentation.
---
gdb/NEWS | 6 +
gdb/btrace.c | 47 +++
gdb/doc/python.texi | 111 +++++
gdb/testsuite/gdb.btrace/ptwrite.c | 40 ++
gdb/testsuite/gdb.btrace/ptwrite.exp | 212 ++++++++++
gdb/testsuite/gdb.btrace/x86_64-ptwrite.S | 479 ++++++++++++++++++++++
gdb/testsuite/lib/gdb.exp | 92 +++++
7 files changed, 987 insertions(+)
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
Comments
> From: felix.willgerodt@intel.com
> Cc: markus.t.metzger@intel.com, Felix Willgerodt <felix.willgerodt@intel.com>
> Date: Wed, 29 May 2019 10:47:53 +0200
>
> +* GDB now supports printing of ptwrite payloads from the Intel Processor
> + Trace during 'record instruction-history', 'record function-call-history',
^^
Extra blank.
> + all stepping commands and in Python. Printing is customizable via a
^
A comma missing there.
> +use of the PTWRITE instruction. PTWRITE is a x86 instruction that allows to
^^
Two spaces between sentences, please.
> +The @value{NGCC} built-in functions for it are:
> +@smallexample
> +void __builtin_ia32_ptwrite32 (unsigned)
> +void __builtin_ia32_ptwrite64 (unsigned long long)
> +@end smallexample
Should there be a semi-colon at the end of each function prototype?
> +as auxiliary information into the execution history. Auxiliary information
> +is by default printed during 'record instruction-history',
> +'record function-call-history' and all stepping commands and is accessible
The two "record" commands should be in @code and without quotes.
Also, please add a comma before the last "and".
> +in Python as a @code{RecordAuxiliary} object.
> +
> +@exdent Sample program:
> +@smallexample
> +void
> +ptwrite64 (unsigned long long value)
> +@{
> + __builtin_ia32_ptwrite64 (value);
> +@}
> +
> +int
> +main (void)
> +@{
> + ptwrite64 (0x42);
> + return 0; /* break here. */
> +@}
> +@end smallexample
> +
> +@exdent @value{GDBN} output after recording the sample program in pt format:
> +@smallexample
> +(gdb) record instruction-history 12,14
> +12 0x000000000040074c <ptwrite64+16>: ptwrite %rbx
> +13 [payload: 0x42]
> +14 0x0000000000400751 <ptwrite64+21>: mov -0x8(%rbp),%rbx
> +(gdb) record function-call-history
> +1 main
> +2 ptwrite64
> + [payload: 0x42]
> +3 main
> +@end smallexample
Long examples such as the two above should use @group to avoid being
split between two pages in an unfortunate place.
> +auxiliary information. A custom Python function can be registered via
^^
Two spaces.
> +@code{gdb.ptwrite.register_listener()} as the @dfn{ptwrite listener function}.
Every term you put in @dfn should have an index entry, as this is
generally terminology people will later look up in the manual.
> +This function will be called with the ptwrite payload and IP as arguments
> +during trace decoding.
If "IP" stands for "instruction pointer", I think that we prefer "PC"
instead.
> +@table @code
> +
> +@item register_listener (@var{listener})
> +Used to register the ptwrite listener. The listener can be any callable
> +object that accepts two arguments. It can return a string, which will be
^^^
Extra space.
> +printed by @value{GDBN} during the aforementioned commands, or @code{None},
> +resulting in no output. @code{None} can also be registered to deactivate
> +printing.
> +
> +@item get_listener ()
> +Returns the currently active ptwrite listener function.
> +
> +@item default_listener (@var{payload}, @var{ip})
> +The listener function active by default.
> +@end table
Why is this a @table, and not a series of @defun's?
> +threads. The listener can however distinguish between multiple threads
^^
Missing space.
> +with the help of @code{gdb.selected_thread().global_num} or similar.
Please add a cross-reference to where gdb.selected_thread is described
in the manual.
Thanks.
Hello Felix,
> @@ -1244,6 +1244,53 @@ handle_pt_insn_events (struct btrace_thread_info
> *btinfo,
> bfun->insn_offset - 1, offset);
>
> break;
> +
> + case ptev_ptwrite:
> + {
> + uint64_t *ip = nullptr;
> + gdb::unique_xmalloc_ptr<char> ptw_string = nullptr;
> + struct btrace_insn ptw_insn;
> +
> + /* Lookup the ip. */
> + if (event.ip_suppressed == 0)
> + ip = &event.variant.ptwrite.ip;
> + else if (!btinfo->functions.empty ()
> + && !btinfo->functions.back ().insn.empty ())
> + ip = &btinfo->functions.back ().insn.back ().pc;
Libipt will provide the PTWRITE instruction's IP. We may get PTW events without IP
but those wouldn't bind to the previous instruction - or libipt would have filled in
the event IP.
If EVENT.IP_SUPPRESSED is set, there is no IP.
> + else
> + /* This should never happen. */
> + error (_("Failed to obtain the PC of the current instruction."));
We explicitly allow a nullptr IP in the callback function.
> +
> + try
> + {
> + if (btinfo->ptw_callback_fun != nullptr)
> + ptw_string = btinfo->ptw_callback_fun (
> + &event.variant.ptwrite.payload, ip,
> + btinfo->ptw_listener);
> + }
> + catch (const gdb_exception_error &error)
> + {
> + warning (_("Failed to call ptwrite listener."));
This indicates a bug in the user's ptwrite-listener object. Should we print a
backtrace and fail with an error?
> + }
> +
> + if (ptw_string == nullptr)
> + break;
> +
> + btinfo->aux_data.emplace_back (ptw_string.get ());
> +
> + /* Update insn list with ptw payload insn. */
> + ptw_insn.aux_data_index = btinfo->aux_data.size () - 1;
> + ptw_insn.flags = 0;
Can we preserve the SPECULATIVE flag?
> + ptw_insn.iclass = BTRACE_INSN_AUX;
> + ptw_insn.size = 0;
> +
> + bfun = ftrace_update_function (btinfo, *ip);
> + bfun->flags |= BFUN_AUX_DECODED;
> +
> + ftrace_update_insns (bfun, ptw_insn);
> +
> + break;
> + }
> }
> }
> #endif /* defined (HAVE_PT_INSN_EVENT) */
[...]
> +When recording multithreaded programs, @value{GDBN} creates a new copy of
Also when recording a single threaded program. Maybe just remove this part.
> the
> +listener function for each thread to allow for independent internal states.
> +There is currently no support for registering different listeners for different
> +threads. The listener can however distinguish between multiple threads
You write 'currently'. Are there plans to support different listeners for different threads?
> +with the help of @code{gdb.selected_thread().global_num} or similar.
> +
> +@exdent For example:
> +@smallexample
> +(gdb) python-interactive
> +>>> def my_listener(payload, ip):
> +... if gdb.selected_thread().global_num == 1:
> +... return "payload: @{0@}, ip: @{:#x@}".format(payload, ip)
> +... else:
> +... return None
> +...
An example where the listener accumulates payloads would be nice.
> +++ b/gdb/testsuite/gdb.btrace/ptwrite.c
> @@ -0,0 +1,40 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2018 Free Software Foundation, Inc.
It's 2019, meanwhile.
> +
> + 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 <stdint.h>
> +
> +void
> +ptwrite64 (uint64_t value)
> +{
> + asm volatile ("PTWRITE %0;" : : "b" (value));
> +}
> +
> +void
> +ptwrite32 (uint32_t value)
> +{
> + asm volatile ("PTWRITE %0;" : : "b" (value));
> +}
> +
> +int
> +main (void)
> +{
> +
Spurious empty line.
> + ptwrite64 (0x42);
> + ptwrite32 (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..4cbd030be44
> --- /dev/null
> +++ b/gdb/testsuite/gdb.btrace/ptwrite.exp
> @@ -0,0 +1,212 @@
> +# This testcase is part of GDB, the GNU debugger.
> +#
> +# Copyright 2018 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_pt_tests] } {
> + unsupported "Target does not support record btrace pt."
> + return -1
> +}
> +
> +if { [skip_btrace_ptw_tests] } {
> + unsupported "Hardware does not support ptwrite instructions."
> + return -1
> +}
> +
> +set comp_flags "additional_flags=-I${srcdir}/.."
If we need this only in the COMPILE case, I'd move it there; or just inline it.
> +set opts {}
> +
> +if [info exists COMPILE] {
> + # make check RUNTESTFLAGS="gdb.btrace/ptwrite.exp COMPILE=1"
> + standard_testfile ptwrite.c
> + lappend opts debug comp_flags
> +} elseif {[istarget "i?86-*-*"] || [istarget "x86_64-*-*"]} {
> + if {[is_amd64_regs_target]} {
> + standard_testfile x86_64-ptwrite.S
> + } else {
> + unsupported "target architecture not supported"
> + return -1
> + }
> +} else {
> + unsupported "target architecture not supported"
> + return -1
> +}
> +
> +if [prepare_for_testing "failed to prepare" $testfile $srcfile $opts] {
> + unsupported "Compiler does not support ptwrite."
I don't think we need an 'unsupported' here. We should get 'failed to prepare', already.
> + 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
You can use with_test_prefix to avoid repeating the prefix in each test.
> +gdb_test_no_output "set record instruction-history-size unlimited" "Default:
> set unlimited"
> +gdb_test_no_output "record btrace pt" "Default: record btrace pt"
> +gdb_test "next" ".*" "Default: first next"
> +gdb_test "next" ".*" "Default: second next"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index c703a7e6338..ba7ccfd46ba 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -2874,6 +2874,98 @@ gdb_caching_proc skip_btrace_pt_tests {
> return $skip_btrace_tests
> }
>
> +# Run a test on the target to see if it supports ptwrite instructions.
> +# Return 0 if so, 1 if it does not. Based on 'check_vmx_hw_available'
> +# from the GCC testsuite.
> +
> +gdb_caching_proc skip_btrace_ptw_tests {
> + global srcdir subdir gdb_prompt inferior_exited_re
> +
> + set me "skip_ptw_tests"
> +
> + # Set up, compile, and execute a test program.
> + # Include the current process ID in the file names to prevent conflicts
> + # with invocations for multiple testsuites.
> + set src [standard_temp_file ptw[pid].c]
> + set exe [standard_temp_file ptw[pid].x]
> +
> + gdb_produce_source $src {
> + #include <stdbool.h>
> + #include <stdint.h>
> + #include <stdio.h>
> + #include "x86-cpuid.h"
> +
> + #define bit_PTW (1 << 4)
> +
> + bool
> + have_ptw ()
> + {
> + unsigned int eax, ebx, ecx, edx;
> +
> + if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
> + return false;
> +
> + if ((ecx & bit_OSXSAVE) != bit_OSXSAVE)
> + return false;
> +
> + if (__get_cpuid_max (0, NULL) < 0x14)
> + return false;
> +
> + __cpuid_count (0x14, 0, eax, ebx, ecx, edx);
> +
> + return (ebx & bit_PTW) == bit_PTW;
> + }
> +
> + int
> + main ()
> + {
> + return have_ptw ();
> + }
> +
> + }
> +
> + verbose "$me: compiling testfile $src" 2
> +
> + set test_flags [list additional_flags=-I${srcdir}/../nat]
> +
> + set compile_flags [concat {debug nowarnings quiet} ${test_flags}]
> + set lines [gdb_compile $src $exe executable $compile_flags]
> +
> + if ![string match "" $lines] then {
> + verbose "$me: testfile compilation failed, returning 1" 2
> + file delete $src
> + return 1
> + }
> +
> + # No error message, compilation succeeded so now run it via gdb.
> + gdb_exit
> + gdb_start
> + gdb_reinitialize_dir $srcdir/$subdir
> + gdb_load $exe
> + if ![runto_main] {
> + file delete $src
> + return 1
> + }
> + file delete $src
> +
> + # In case of an unexpected output, we return 2 as a fail value.
> + set skip_ptw_tests 2
> + gdb_test_multiple "print (int) have_ptw ()" "check ptw support" {
> + -re ".. = 1\r\n$gdb_prompt $" {
> + set skip_ptw_tests 0
> + }
> + -re ".. = 0\r\n$gdb_prompt $" {
> + set skip_ptw_tests 1
> + }
> + }
> +
> + gdb_exit
> + remote_file build delete $exe
> +
> + verbose "$me: returning $skip_ptw_tests" 2
> + return $skip_ptw_tests
We still don't know if the OS supports it, do we?
> +}
> +
> # 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.
>
> --
> 2.20.1
Thanks,
Markus.
Intel Deutschland GmbH
Registered Address: Am Campeon 10-12, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Christin Eisenschmid, Gary Kershaw
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
@@ -3,6 +3,12 @@
*** Changes since GDB 8.3
+* 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 listener function in Python. By default, the raw ptwrite
+ payload is printed for each ptwrite that is encountered.
+
* New built-in convenience variables $_gdb_major and $_gdb_minor
provide the GDB version. They are handy for conditionally using
features available only in or since specific GDB versions, in
@@ -1244,6 +1244,53 @@ handle_pt_insn_events (struct btrace_thread_info *btinfo,
bfun->insn_offset - 1, offset);
break;
+
+ case ptev_ptwrite:
+ {
+ uint64_t *ip = nullptr;
+ gdb::unique_xmalloc_ptr<char> ptw_string = nullptr;
+ struct btrace_insn ptw_insn;
+
+ /* Lookup the ip. */
+ if (event.ip_suppressed == 0)
+ ip = &event.variant.ptwrite.ip;
+ else if (!btinfo->functions.empty ()
+ && !btinfo->functions.back ().insn.empty ())
+ ip = &btinfo->functions.back ().insn.back ().pc;
+ else
+ /* This should never happen. */
+ error (_("Failed to obtain the PC of the current instruction."));
+
+ try
+ {
+ if (btinfo->ptw_callback_fun != nullptr)
+ ptw_string = btinfo->ptw_callback_fun (
+ &event.variant.ptwrite.payload, ip,
+ btinfo->ptw_listener);
+ }
+ catch (const gdb_exception_error &error)
+ {
+ warning (_("Failed to call ptwrite listener."));
+ }
+
+ if (ptw_string == nullptr)
+ break;
+
+ btinfo->aux_data.emplace_back (ptw_string.get ());
+
+ /* Update insn list with ptw payload insn. */
+ ptw_insn.aux_data_index = btinfo->aux_data.size () - 1;
+ ptw_insn.flags = 0;
+ ptw_insn.iclass = BTRACE_INSN_AUX;
+ ptw_insn.size = 0;
+
+ bfun = ftrace_update_function (btinfo, *ip);
+ bfun->flags |= BFUN_AUX_DECODED;
+
+ ftrace_update_insns (bfun, ptw_insn);
+
+ break;
+ }
}
}
#endif /* defined (HAVE_PT_INSN_EVENT) */
@@ -5683,6 +5683,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 listener registration.
@end menu
@node gdb.printing
@@ -5874,3 +5875,113 @@ substitute_prompt (``frame: \f,
"frame: main, print arguments: 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 PTWRITE instruction. 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} inserts the raw payload value
+as auxiliary information into the execution history. Auxiliary information
+is by default printed during 'record instruction-history',
+'record function-call-history' and all stepping commands and is accessible
+in Python as a @code{RecordAuxiliary} object.
+
+@exdent Sample program:
+@smallexample
+void
+ptwrite64 (unsigned long long value)
+@{
+ __builtin_ia32_ptwrite64 (value);
+@}
+
+int
+main (void)
+@{
+ ptwrite64 (0x42);
+ return 0; /* break here. */
+@}
+@end smallexample
+
+@exdent @value{GDBN} output after recording the sample program in pt format:
+@smallexample
+(gdb) record instruction-history 12,14
+12 0x000000000040074c <ptwrite64+16>: ptwrite %rbx
+13 [payload: 0x42]
+14 0x0000000000400751 <ptwrite64+21>: mov -0x8(%rbp),%rbx
+(gdb) record function-call-history
+1 main
+2 ptwrite64
+ [payload: 0x42]
+3 main
+@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_listener()} as the @dfn{ptwrite listener function}.
+This function will be called with the ptwrite payload and IP as arguments
+during trace decoding.
+
+@table @code
+
+@item register_listener (@var{listener})
+Used to register the ptwrite listener. The listener can be any callable
+object that accepts two arguments. 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.
+
+@item get_listener ()
+Returns the currently active ptwrite listener function.
+
+@item default_listener (@var{payload}, @var{ip})
+The listener function active by default.
+@end table
+
+When recording multithreaded programs, @value{GDBN} creates a new copy of the
+listener function for each thread to allow for independent internal states.
+There is currently no support for registering different listeners for different
+threads. The listener can however distinguish between multiple threads
+with the help of @code{gdb.selected_thread().global_num} or similar.
+
+@exdent For example:
+@smallexample
+(gdb) python-interactive
+>>> def my_listener(payload, ip):
+... if gdb.selected_thread().global_num == 1:
+... return "payload: @{0@}, ip: @{:#x@}".format(payload, ip)
+... else:
+... return None
+...
+>>> import gdb.ptwrite
+>>> gdb.ptwrite.register_listener(my_listener)
+>>>
+(gdb) record instruction-history 127,129
+127 0x000000000040116c <ptwrite32(unsigned int)+13>: ptwrite %ebx
+128 [payload: 4919, ip: 0x40074c]
+129 0x0000000000401170 <ptwrite32(unsigned int)+17>: nop
+(gdb) info threads
+* 1 Thread 0x7ffff7fd8740 (LWP 25796) "ptwrite_threads" task (arg=0x0)
+ at bin/ptwrite/ptwrite_threads.c:45
+ 2 Thread 0x7ffff6eb8700 (LWP 25797) "ptwrite_threads" task (arg=0x0)
+ at bin/ptwrite/ptwrite_threads.c:45
+(gdb) thread 2
+[Switching to thread 2 (Thread 0x7ffff6eb8700 (LWP 25797))]
+#0 task (arg=0x0) at ptwrite_threads.c:45
+45 return NULL;
+(gdb) record instruction-history 1753,1755
+1753 0x000000000040116c <ptwrite32(unsigned int)+13>: ptwrite %ebx
+1754 0x0000000000401170 <ptwrite32(unsigned int)+17>: nop
+1755 0x0000000000401171 <ptwrite32(unsigned int)+18>: pop %rbx
+@end smallexample
+
+This GDB feature is dependent on hardware and operating system support and
+requires the Intel Processor Trace decoder library in version 2.0.0 or newer.
new file mode 100644
@@ -0,0 +1,40 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2018 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 <stdint.h>
+
+void
+ptwrite64 (uint64_t value)
+{
+ asm volatile ("PTWRITE %0;" : : "b" (value));
+}
+
+void
+ptwrite32 (uint32_t value)
+{
+ asm volatile ("PTWRITE %0;" : : "b" (value));
+}
+
+int
+main (void)
+{
+
+ ptwrite64 (0x42);
+ ptwrite32 (0x43);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,212 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2018 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_pt_tests] } {
+ unsupported "Target does not support record btrace pt."
+ return -1
+}
+
+if { [skip_btrace_ptw_tests] } {
+ unsupported "Hardware does not support ptwrite instructions."
+ return -1
+}
+
+set comp_flags "additional_flags=-I${srcdir}/.."
+set opts {}
+
+if [info exists COMPILE] {
+ # make check RUNTESTFLAGS="gdb.btrace/ptwrite.exp COMPILE=1"
+ standard_testfile ptwrite.c
+ lappend opts debug comp_flags
+} elseif {[istarget "i?86-*-*"] || [istarget "x86_64-*-*"]} {
+ if {[is_amd64_regs_target]} {
+ standard_testfile x86_64-ptwrite.S
+ } else {
+ unsupported "target architecture not supported"
+ return -1
+ }
+} else {
+ unsupported "target architecture not supported"
+ return -1
+}
+
+if [prepare_for_testing "failed to prepare" $testfile $srcfile $opts] {
+ unsupported "Compiler does not support ptwrite."
+ 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" "Default: set unlimited"
+gdb_test_no_output "record btrace pt" "Default: record btrace pt"
+gdb_test "next" ".*" "Default: first next"
+gdb_test "next" ".*" "Default: second next"
+
+
+# Test libipt version (must be >= 2.0.0)
+set libipt_supports_ptwrite 0
+
+gdb_test_multiple "maint info btrace" "check libipt version" {
+ -re ".*Version: \[01\]\.\[0-9\]+\.\[0-9\]+.*"
+ {
+ set libipt_supports_ptwrite 0
+ }
+ -re ".*Version: \[0-9\]+\.\[0-9\]+\.\[0-9\]+.*"
+ {
+ set libipt_supports_ptwrite 1
+ }
+ default {
+ set libipt_supports_ptwrite 0
+ }
+}
+
+if { $libipt_supports_ptwrite == 0 } {
+ unsupported "libipt version doesn't support ptwrite decoding."
+ return -1
+}
+
+# Test record instruction-history
+gdb_test "record instruction-history 1" [multi_line \
+ ".*\[0-9\]+\t $hex <ptwrite64\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t \\\[payload: 0x42\\\]" \
+ ".*\[0-9\]+\t $hex <ptwrite32\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t \\\[payload: 0x43\\\].*" \
+ ] "Default: record instruction-history 1"
+
+# Test function call history
+gdb_test "record function-call-history 1,4" [multi_line \
+ "1\tmain" \
+ "2\tptwrite64" \
+ "\t\t\\\[payload: 0x42\\\]" \
+ "3\tmain" \
+ "4\tptwrite32" \
+ "\t\t\\\[payload: 0x43\\\]" \
+ ] "Default: record function-call-history 1,4"
+
+gdb_test "record function-call-history /s 1,4" [multi_line \
+ "1\tmain" \
+ "2\tptwrite64" \
+ "3\tmain" \
+ "4\tptwrite32" \
+ ] "Default: record function-call-history /s 1,4"
+
+# Test payload printing during stepping
+gdb_test "record goto 10" "No such instruction\."
+gdb_test "record goto 9" ".*ptwrite64.* at .*ptwrite.c:23.*"
+gdb_test "stepi" ".*\\\[payload: 0x42\\\].*"
+gdb_test "reverse-stepi" ".*\\\[payload: 0x42\\\].*"
+gdb_test "continue" ".*\\\[payload: 0x42\\\].*\\\[payload: 0x43\\\].*"
+gdb_test "reverse-continue" ".*\\\[payload: 0x43\\\].*\\\[payload: 0x42\\\].*"
+
+# Test auxiliary type in python
+gdb_py_test_multiple "Default: auxiliary type in python" \
+ "python" "" \
+ "h = gdb.current_recording().instruction_history" "" \
+ "for insn in h: print(insn)" "" \
+ "end" [multi_line \
+ ".*RecordAuxiliary.*" \
+ ".*RecordAuxiliary.*" \
+ ]
+
+
+### 2. Test listener registration
+### 2.1 Custom listener
+
+gdb_py_test_multiple "Custom: register listener in python" \
+ "python" "" \
+ "def my_listener(payload, ip):" "" \
+ " if payload == 66:" "" \
+ " return \"payload: {0}, ip: {1:#x}\".format(payload, ip)" "" \
+ " else:" "" \
+ " return None" "" \
+ "import gdb.ptwrite" "" \
+ "gdb.ptwrite.register_listener(my_listener)" "" \
+ "end" ""
+
+gdb_test "record instruction-history 1" [multi_line \
+ ".*\[0-9\]+\t $hex <ptwrite64\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t \\\[payload: 66, ip: $hex\\\]" \
+ ".*\[0-9\]+\t $hex <ptwrite32\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t $hex <ptwrite32\\+\[0-9\]+>:.*" \
+ ] "Custom: record instruction-history 1"
+
+### 2.2 None as listener
+
+gdb_py_test_multiple "None: register listener in python" \
+ "python" "" \
+ "import gdb.ptwrite" "" \
+ "gdb.ptwrite.register_listener(None)" "" \
+ "end" ""
+
+gdb_test "record instruction-history 1" [multi_line \
+ ".*\[0-9\]+\t $hex <ptwrite64\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t $hex <ptwrite64\\+\[0-9\]+>:.*" \
+ "\[0-9\]+\t $hex <ptwrite32\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t $hex <ptwrite32\\+\[0-9\]+>:.*" \
+ ] "None: record instruction-history 1"
+
+### 2.3 Lambdas as listener
+
+gdb_py_test_multiple "Lambdas: register listener in python" \
+ "python" "" \
+ "import gdb.ptwrite" "" \
+ "gdb.ptwrite.register_listener(lambda payload, ip: \"{}\".format(payload + 2))" "" \
+ "end" ""
+
+gdb_test "record instruction-history 1" [multi_line \
+ ".*\[0-9\]+\t $hex <ptwrite64\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t \\\[68\\\]" \
+ ".*\[0-9\]+\t $hex <ptwrite32\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t \\\[69\\\].*" \
+ ] "Lambdas: record instruction-history 1"
+
+### 2.4 Functors as listener
+
+gdb_py_test_multiple "Functors: register listener 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_listener(foobar())" "" \
+ "end" ""
+
+gdb_test "record instruction-history 1" [multi_line \
+ ".*\[0-9\]+\t $hex <ptwrite64\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t \\\[1, 66\\\]" \
+ ".*\[0-9\]+\t $hex <ptwrite32\\+\[0-9\]+>:\tptwrite %\[a-z\]+" \
+ "\[0-9\]+\t \\\[2, 67\\\].*" \
+ ] "Functors: record instruction-history 1"
new file mode 100644
@@ -0,0 +1,479 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2018 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 8.1.1 20180502:
+ gcc -S -dA -g ptwrite.c -o x86_64-ptwrite.S. */
+
+ .file "ptwrite.c"
+ .text
+.Ltext0:
+ .globl ptwrite64
+ .type ptwrite64, @function
+ptwrite64:
+.LFB0:
+ .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
+ pushq %rbx
+ .cfi_offset 3, -24
+ movq %rdi, -16(%rbp)
+ # ptwrite.c:23:3
+ .loc 1 23 3
+ movq -16(%rbp), %rax
+ movq %rax, %rbx
+#APP
+# 23 "ptwrite.c" 1
+ PTWRITE %rbx;
+# 0 "" 2
+ # ptwrite.c:24:1
+ .loc 1 24 1
+#NO_APP
+ nop
+ popq %rbx
+ popq %rbp
+ .cfi_def_cfa 7, 8
+# SUCC: EXIT [always]
+ ret
+ .cfi_endproc
+.LFE0:
+ .size ptwrite64, .-ptwrite64
+ .globl ptwrite32
+ .type ptwrite32, @function
+ptwrite32:
+.LFB1:
+ # 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
+ pushq %rbx
+ .cfi_offset 3, -24
+ movl %edi, -12(%rbp)
+ # ptwrite.c:29:3
+ .loc 1 29 3
+ movl -12(%rbp), %eax
+ movl %eax, %ebx
+#APP
+# 29 "ptwrite.c" 1
+ PTWRITE %ebx;
+# 0 "" 2
+ # ptwrite.c:30:1
+ .loc 1 30 1
+#NO_APP
+ nop
+ popq %rbx
+ popq %rbp
+ .cfi_def_cfa 7, 8
+# SUCC: EXIT [always]
+ ret
+ .cfi_endproc
+.LFE1:
+ .size ptwrite32, .-ptwrite32
+ .globl main
+ .type main, @function
+main:
+.LFB2:
+ # 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:36:3
+ .loc 1 36 3
+ movl $66, %edi
+ call ptwrite64
+ # ptwrite.c:37:3
+ .loc 1 37 3
+ movl $67, %edi
+ call ptwrite32
+ # ptwrite.c:39:10
+ .loc 1 39 10
+ movl $0, %eax
+ # ptwrite.c:40:1
+ .loc 1 40 1
+ popq %rbp
+ .cfi_def_cfa 7, 8
+# SUCC: EXIT [always]
+ ret
+ .cfi_endproc
+.LFE2:
+ .size main, .-main
+.Letext0:
+ .file 2 "/usr/include/bits/types.h"
+ .file 3 "/usr/include/bits/stdint-uintn.h"
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .long 0x10f # 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 .LASF13 # DW_AT_producer: "GNU C17 8.1.1 20180502 (Red Hat 8.1.1-1) -mtune=generic -march=x86-64 -g"
+ .byte 0xc # DW_AT_language
+ .long .LASF14 # DW_AT_name: "ptwrite.c"
+ .long .LASF15 # 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 0x1 # DW_AT_byte_size
+ .byte 0x8 # DW_AT_encoding
+ .long .LASF0 # DW_AT_name: "unsigned char"
+ .uleb128 0x2 # (DIE (0x34) DW_TAG_base_type)
+ .byte 0x2 # DW_AT_byte_size
+ .byte 0x7 # DW_AT_encoding
+ .long .LASF1 # DW_AT_name: "short unsigned int"
+ .uleb128 0x2 # (DIE (0x3b) DW_TAG_base_type)
+ .byte 0x4 # DW_AT_byte_size
+ .byte 0x7 # DW_AT_encoding
+ .long .LASF2 # DW_AT_name: "unsigned int"
+ .uleb128 0x2 # (DIE (0x42) DW_TAG_base_type)
+ .byte 0x8 # DW_AT_byte_size
+ .byte 0x7 # DW_AT_encoding
+ .long .LASF3 # DW_AT_name: "long unsigned int"
+ .uleb128 0x2 # (DIE (0x49) DW_TAG_base_type)
+ .byte 0x1 # DW_AT_byte_size
+ .byte 0x6 # DW_AT_encoding
+ .long .LASF4 # DW_AT_name: "signed char"
+ .uleb128 0x2 # (DIE (0x50) DW_TAG_base_type)
+ .byte 0x2 # DW_AT_byte_size
+ .byte 0x5 # DW_AT_encoding
+ .long .LASF5 # DW_AT_name: "short int"
+ .uleb128 0x3 # (DIE (0x57) DW_TAG_base_type)
+ .byte 0x4 # DW_AT_byte_size
+ .byte 0x5 # DW_AT_encoding
+ .ascii "int\0" # DW_AT_name
+ .uleb128 0x4 # (DIE (0x5e) DW_TAG_typedef)
+ .long .LASF7 # DW_AT_name: "__uint32_t"
+ .byte 0x2 # DW_AT_decl_file (/usr/include/bits/types.h)
+ .byte 0x29 # DW_AT_decl_line
+ .byte 0x16 # DW_AT_decl_column
+ .long 0x3b # DW_AT_type
+ .uleb128 0x2 # (DIE (0x6a) DW_TAG_base_type)
+ .byte 0x8 # DW_AT_byte_size
+ .byte 0x5 # DW_AT_encoding
+ .long .LASF6 # DW_AT_name: "long int"
+ .uleb128 0x4 # (DIE (0x71) DW_TAG_typedef)
+ .long .LASF8 # DW_AT_name: "__uint64_t"
+ .byte 0x2 # DW_AT_decl_file (/usr/include/bits/types.h)
+ .byte 0x2c # DW_AT_decl_line
+ .byte 0x1b # DW_AT_decl_column
+ .long 0x42 # DW_AT_type
+ .uleb128 0x2 # (DIE (0x7d) DW_TAG_base_type)
+ .byte 0x1 # DW_AT_byte_size
+ .byte 0x6 # DW_AT_encoding
+ .long .LASF9 # DW_AT_name: "char"
+ .uleb128 0x4 # (DIE (0x84) DW_TAG_typedef)
+ .long .LASF10 # DW_AT_name: "uint32_t"
+ .byte 0x3 # DW_AT_decl_file (/usr/include/bits/stdint-uintn.h)
+ .byte 0x1a # DW_AT_decl_line
+ .byte 0x14 # DW_AT_decl_column
+ .long 0x5e # DW_AT_type
+ .uleb128 0x4 # (DIE (0x90) DW_TAG_typedef)
+ .long .LASF11 # DW_AT_name: "uint64_t"
+ .byte 0x3 # DW_AT_decl_file (/usr/include/bits/stdint-uintn.h)
+ .byte 0x1b # DW_AT_decl_line
+ .byte 0x14 # DW_AT_decl_column
+ .long 0x71 # DW_AT_type
+ .uleb128 0x5 # (DIE (0x9c) DW_TAG_subprogram)
+ # DW_AT_external
+ .long .LASF16 # 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 0x57 # DW_AT_type
+ .quad .LFB2 # DW_AT_low_pc
+ .quad .LFE2-.LFB2 # 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 0x6 # (DIE (0xba) DW_TAG_subprogram)
+ # DW_AT_external
+ .long .LASF17 # DW_AT_name: "ptwrite32"
+ .byte 0x1 # DW_AT_decl_file (ptwrite.c)
+ .byte 0x1b # DW_AT_decl_line
+ .byte 0x1 # DW_AT_decl_column
+ # DW_AT_prototyped
+ .quad .LFB1 # DW_AT_low_pc
+ .quad .LFE1-.LFB1 # DW_AT_high_pc
+ .uleb128 0x1 # DW_AT_frame_base
+ .byte 0x9c # DW_OP_call_frame_cfa
+ # DW_AT_GNU_all_call_sites
+ .long 0xe8 # DW_AT_sibling
+ .uleb128 0x7 # (DIE (0xd8) DW_TAG_formal_parameter)
+ .long .LASF12 # DW_AT_name: "value"
+ .byte 0x1 # DW_AT_decl_file (ptwrite.c)
+ .byte 0x1b # DW_AT_decl_line
+ .byte 0x15 # DW_AT_decl_column
+ .long 0x84 # DW_AT_type
+ .uleb128 0x2 # DW_AT_location
+ .byte 0x91 # DW_OP_fbreg
+ .sleb128 -28
+ .byte 0 # end of children of DIE 0xba
+ .uleb128 0x8 # (DIE (0xe8) DW_TAG_subprogram)
+ # DW_AT_external
+ .long .LASF18 # DW_AT_name: "ptwrite64"
+ .byte 0x1 # DW_AT_decl_file (ptwrite.c)
+ .byte 0x15 # DW_AT_decl_line
+ .byte 0x1 # DW_AT_decl_column
+ # DW_AT_prototyped
+ .quad .LFB0 # DW_AT_low_pc
+ .quad .LFE0-.LFB0 # DW_AT_high_pc
+ .uleb128 0x1 # DW_AT_frame_base
+ .byte 0x9c # DW_OP_call_frame_cfa
+ # DW_AT_GNU_all_call_sites
+ .uleb128 0x7 # (DIE (0x102) DW_TAG_formal_parameter)
+ .long .LASF12 # DW_AT_name: "value"
+ .byte 0x1 # DW_AT_decl_file (ptwrite.c)
+ .byte 0x15 # DW_AT_decl_line
+ .byte 0x15 # DW_AT_decl_column
+ .long 0x90 # DW_AT_type
+ .uleb128 0x2 # DW_AT_location
+ .byte 0x91 # DW_OP_fbreg
+ .sleb128 -32
+ .byte 0 # end of children of DIE 0xe8
+ .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 0xe # (DW_FORM_strp)
+ .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 0x8 # (DW_FORM_string)
+ .byte 0
+ .byte 0
+ .uleb128 0x4 # (abbrev code)
+ .uleb128 0x16 # (TAG: DW_TAG_typedef)
+ .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)
+ .byte 0
+ .byte 0
+ .uleb128 0x5 # (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 0x6 # (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 0x7 # (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 0x8 # (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)
+ .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 "unsigned int"
+.LASF7:
+ .string "__uint32_t"
+.LASF15:
+ .string "gdb/gdb/testsuite/gdb.btrace"
+.LASF14:
+ .string "ptwrite.c"
+.LASF18:
+ .string "ptwrite64"
+.LASF3:
+ .string "long unsigned int"
+.LASF11:
+ .string "uint64_t"
+.LASF0:
+ .string "unsigned char"
+.LASF16:
+ .string "main"
+.LASF10:
+ .string "uint32_t"
+.LASF6:
+ .string "long int"
+.LASF8:
+ .string "__uint64_t"
+.LASF13:
+ .string "GNU C17 8.1.1 20180502 (Red Hat 8.1.1-1) -mtune=generic -march=x86-64 -g"
+.LASF1:
+ .string "short unsigned int"
+.LASF4:
+ .string "signed char"
+.LASF12:
+ .string "value"
+.LASF5:
+ .string "short int"
+.LASF17:
+ .string "ptwrite32"
+.LASF9:
+ .string "char"
+ .ident "GCC: (GNU) 8.1.1 20180502 (Red Hat 8.1.1-1)"
+ .section .note.GNU-stack,"",@progbits
@@ -2874,6 +2874,98 @@ gdb_caching_proc skip_btrace_pt_tests {
return $skip_btrace_tests
}
+# Run a test on the target to see if it supports ptwrite instructions.
+# Return 0 if so, 1 if it does not. Based on 'check_vmx_hw_available'
+# from the GCC testsuite.
+
+gdb_caching_proc skip_btrace_ptw_tests {
+ global srcdir subdir gdb_prompt inferior_exited_re
+
+ set me "skip_ptw_tests"
+
+ # Set up, compile, and execute a test program.
+ # Include the current process ID in the file names to prevent conflicts
+ # with invocations for multiple testsuites.
+ set src [standard_temp_file ptw[pid].c]
+ set exe [standard_temp_file ptw[pid].x]
+
+ gdb_produce_source $src {
+ #include <stdbool.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include "x86-cpuid.h"
+
+ #define bit_PTW (1 << 4)
+
+ bool
+ have_ptw ()
+ {
+ unsigned int eax, ebx, ecx, edx;
+
+ if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+ return false;
+
+ if ((ecx & bit_OSXSAVE) != bit_OSXSAVE)
+ return false;
+
+ if (__get_cpuid_max (0, NULL) < 0x14)
+ return false;
+
+ __cpuid_count (0x14, 0, eax, ebx, ecx, edx);
+
+ return (ebx & bit_PTW) == bit_PTW;
+ }
+
+ int
+ main ()
+ {
+ return have_ptw ();
+ }
+
+ }
+
+ verbose "$me: compiling testfile $src" 2
+
+ set test_flags [list additional_flags=-I${srcdir}/../nat]
+
+ set compile_flags [concat {debug nowarnings quiet} ${test_flags}]
+ set lines [gdb_compile $src $exe executable $compile_flags]
+
+ if ![string match "" $lines] then {
+ verbose "$me: testfile compilation failed, returning 1" 2
+ file delete $src
+ return 1
+ }
+
+ # No error message, compilation succeeded so now run it via gdb.
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load $exe
+ if ![runto_main] {
+ file delete $src
+ return 1
+ }
+ file delete $src
+
+ # In case of an unexpected output, we return 2 as a fail value.
+ set skip_ptw_tests 2
+ gdb_test_multiple "print (int) have_ptw ()" "check ptw support" {
+ -re ".. = 1\r\n$gdb_prompt $" {
+ set skip_ptw_tests 0
+ }
+ -re ".. = 0\r\n$gdb_prompt $" {
+ set skip_ptw_tests 1
+ }
+ }
+
+ gdb_exit
+ remote_file build delete $exe
+
+ 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.