Patchwork [v2] Add support for recording xsave x86 instruction

login
register
mail settings
Submitter Pierre Marsais
Date Oct. 1, 2018, 12:29 a.m.
Message ID <20181001002942.31919-1-pierre.marsais@lse.epita.fr>
Download mbox | patch
Permalink /patch/29593/
State New
Headers show

Comments

Pierre Marsais - Oct. 1, 2018, 12:29 a.m.
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 from the beginning
of the XSAVE area to the end of the last state component in the Request
Feature Bitmap (whose value is XCR0 & EDX:EAX). At the moment we don't
account for non requested state component within the XSAVE area.

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

	* i386-tdep.c: (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.
---
Changes in v2:
* Address Markus review
* Do not support instruction when MOD == 3
* Query XSAVE area buffer size with cpuid in tests
* Use X86_XSTATE_SIZE macro to get XSAVE area size instead of cpuid

 gdb/i386-tdep.c                               | 35 +++++++++
 .../gdb.reverse/i386-xsave-reverse.c          | 47 ++++++++++++
 .../gdb.reverse/i386-xsave-reverse.exp        | 75 +++++++++++++++++++
 3 files changed, 157 insertions(+)
 create mode 100644 gdb/testsuite/gdb.reverse/i386-xsave-reverse.c
 create mode 100644 gdb/testsuite/gdb.reverse/i386-xsave-reverse.exp

Patch

diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index a6994aaf12..9c52adbd1b 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -7385,6 +7385,41 @@  no_support_3dnow_data:
             return -1;
           break;
 
+        case 4: /* xsave */
+          {
+            if (ir.mod == 3) {
+              opcode = (opcode << 8) | ir.modrm;
+              goto no_support;
+            }
+
+            ULONGEST rfbm_eax, rfbm_edx;
+
+            regcache_raw_read_unsigned (regcache, I386_EAX_REGNUM, &rfbm_eax);
+            rfbm_eax &= (1ULL << 32) - 1;
+
+            regcache_raw_read_unsigned (regcache, I386_EDX_REGNUM, &rfbm_edx);
+            rfbm_edx &= (1ULL << 32) - 1;
+
+            uint64_t rfbm = tdep->xcr0 & (rfbm_eax | (rfbm_edx << 32));
+
+            if (rfbm & ~X86_XSTATE_ALL_MASK) {
+              printf_unfiltered (_("Process record does not support XSAVE "
+                                   "instruction with RFBM=%" PRIx64 ".\n"),
+                                   rfbm);
+              opcode = (opcode << 8) | ir.modrm;
+              goto no_support;
+            }
+
+            uint64_t tmpu64;
+            if (i386_record_lea_modrm_addr (&ir, &tmpu64))
+              return -1;
+
+            if (record_full_arch_list_add_mem (tmpu64,
+                                               X86_XSTATE_SIZE (rfbm)))
+              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..5e90d1ad9c
--- /dev/null
+++ b/gdb/testsuite/gdb.reverse/i386-xsave-reverse.c
@@ -0,0 +1,47 @@ 
+/* 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.  */
+
+#include <cpuid.h>
+#include <stdint.h>
+#include <string.h>
+
+uint32_t get_xsave_buffer_size(void) {
+  uint32_t size, eax, ecx, edx;
+  __get_cpuid_count(0xd, 0, &eax, &size, &ecx, &edx);
+
+  return size;
+}
+
+void xsave_test(void) {
+  uint32_t xsave_buf_sze = get_xsave_buffer_size();
+  char buf[xsave_buf_sze] __attribute__ ((aligned (64)));
+  memset(buf, 0, xsave_buf_sze);
+
+  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..f47f507101
--- /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] || ![supports_process_record]} {
+    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 "]
+
+if ![runto main] then {
+    fail "run to main"
+    return
+}
+
+# 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 .* times>" \
+    "verify xsave buffer after reverse xsave"