[PATCH] Add support for recording xsave x86 instruction

Pierre Marsais
2018-09-21T00:38:34Z

Latest version of glibc's ld.so use the xsave instruction in the
resolver. This breaks gdb record when calling shared libraries:

```
$ gcc -o fail -ggdb -x c - <<EOF
#include <stdlib.h>

int main() {
exit(0);
}
EOF
$ gdb ./fail
Reading symbols from ./fail...done.
(gdb) b main
Breakpoint 1 at 0x113d: file <stdin>, line 4.
(gdb) r
Starting program: /tmp/fail

Breakpoint 1, main () at <stdin>:4
4 <stdin>: No such file or directory.
(gdb) record
(gdb) c
Continuing.
Process record does not support instruction 0xfae64 at address
0x7ffff7fe96dc.
```

In order to record xsave instructions, we record the first 512 bytes of
legacy XSAVE Area and the following 64 bytes of XSAVE Header, and for
each the feature of bit set of xcr0. At the moment we don't check if
the user requested to save less fields, we record all the supported
fields.

gdb/ChangeLog:
2018-09-21 Pierre Marsais <pierre.marsais@lse.epita.fr>

* i386-tdep.c: Include "nat/x86-cpuid.h".
(i386_process_record): Handle xsave instruction.

gdb/testsuite/ChangeLog:
2018-09-21 Pierre Marsais <pierre.marsais@lse.epita.fr>

* gdb.reverse/i386-xsave-reverse.c: New file.
* gdb.reverse/i386-xsave-reverse.exp: New file.
---
gdb/i386-tdep.c | 23 ++++++
.../gdb.reverse/i386-xsave-reverse.c | 34 +++++++++
.../gdb.reverse/i386-xsave-reverse.exp | 75 +++++++++++++++++++
3 files changed, 132 insertions(+)
create mode 100644 gdb/testsuite/gdb.reverse/i386-xsave-reverse.c
create mode 100644 gdb/testsuite/gdb.reverse/i386-xsave-reverse.exp

diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index a6994aaf12..78dbbfe5f0 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -31,6 +31,7 @@
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbtypes.h"
+#include "nat/x86-cpuid.h"
#include "objfiles.h"
#include "osabi.h"
#include "regcache.h"
@@ -7385,6 +7386,28 @@ no_support_3dnow_data:
return -1;
break;

+ case 4: /* xsave */
+ uint64_t tmpu64;
+ if (i386_record_lea_modrm_addr (&ir, &tmpu64))
+ return -1;
+ if (record_full_arch_list_add_mem (tmpu64, 512 + 64))
+ return -1;
+
+ for (int i = 2; i < 64; i++) {
+ if (!((1 << i) & tdep->xcr0))
+ continue;
+
+ unsigned int size, offset, tmp1, tmp2;
+
+ if (!__get_cpuid_count(0xd, i, &size, &offset, &tmp1, &tmp2))
+ return -1;
+
+ if (record_full_arch_list_add_mem (tmpu64 + offset, size))
+ return -1;
+ }
+
+ break;
+
case 5: /* lfence */
case 6: /* mfence */
case 7: /* sfence clflush */
diff --git a/gdb/testsuite/gdb.reverse/i386-xsave-reverse.c b/gdb/testsuite/gdb.reverse/i386-xsave-reverse.c
new file mode 100644
index 0000000000..d0e87158a2
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/i386-xsave-reverse.c
@@ -0,0 +1,34 @@
+/* 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/>. */
+
+/* Architecture tests for intel i386 platform. */
+
+void xsave_test(void) {
+ char buf[4096] __attribute__ ((aligned (64))) = { 0 };
+
+ asm ("xor %%eax, %%eax\n\t"
+ "not %%eax\n\t"
+ "mov %%eax, %%edx\n\t"
+ "xsave %0":"=m"(buf) ::"eax", "edx");
+} /* end xsave_test */
+
+int
+main ()
+{
+ xsave_test ();
+ return 0; /* end of main */
+}
diff --git a/gdb/testsuite/gdb.reverse/i386-xsave-reverse.exp b/gdb/testsuite/gdb.reverse/i386-xsave-reverse.exp
new file mode 100644
index 0000000000..3ea8935c0e
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/i386-xsave-reverse.exp
@@ -0,0 +1,75 @@
+# 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 is part of the gdb testsuite.
+
+#
+# This test tests some i386 general instructions for reverse execution.
+#
+
+if ![supports_reverse] {
+ return
+}
+
+
+if ![istarget "*86*-*linux*"] then {
+ verbose "Skipping i386 reverse tests."
+ return
+}
+
+standard_testfile
+
+# some targets have leading underscores on assembly symbols.
+set additional_flags [gdb_target_symbol_prefix_flags]
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile \
+ [list debug $additional_flags]]} {
+ return -1
+}
+
+set end_of_main [gdb_get_line_number " end of main "]
+set end_xsave_test [gdb_get_line_number " end xsave_test "]
+
+runto main
+
+if [supports_process_record] {
+ # Activate process record/replay
+ gdb_test_no_output "record" "turn on process record"
+}
+
+global hex
+global decimal
+
+#xsave_test
+
+gdb_test "break $end_xsave_test" \
+ "Breakpoint $decimal at .* line $end_xsave_test\." \
+ "set breakpoint at end of xsave_test"
+
+set test "continue to end of xsave_test"
+gdb_test_multiple "continue" $test {
+ -re " end xsave_test .*\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re " Illegal instruction.*\r\n$gdb_prompt $" {
+ untested i386-xsave-reverse
+ return -1
+ }
+}
+
+gdb_test "reverse-step" "xor.*" "reverse-step to xsave"
+
+gdb_test "print buf" ".* = '\\\\000' <repeats 4095 times>" \
+ "verify xsave buffer after reverse xsave"
--
2.19.0