Add support for the x86 XSAVE extended state on FreeBSD/x86.
authorJohn Baldwin <jhb@FreeBSD.org>
Sat, 21 Feb 2015 21:43:30 +0000 (16:43 -0500)
committerJohn Baldwin <jhb@FreeBSD.org>
Mon, 13 Apr 2015 20:07:01 +0000 (16:07 -0400)
Recognize NT_X86_XSTATE notes in FreeBSD process cores.  Recent
FreeBSD versions include a note containing the XSAVE state for each
thread in the process when XSAVE is in use.  The note stores a copy of
the current XSAVE mask in a reserved section of the machine-defined
XSAVE state at the same offset as Linux's NT_X86_XSTATE note.

For native processes, use the PT_GETXSTATE_INFO ptrace request to
determine if XSAVE is enabled, and if so the active XSAVE state mask
(that is, the value of %xcr0 for the target process) as well as the
size of XSAVE state area.  Use the PT_GETXSTATE and PT_SETXSTATE requests
to fetch and store the XSAVE state, respectively, in the BSD x86
native targets.

In addition, the FreeBSD amd64 and i386 native targets now include
"read_description" target methods to determine the correct x86 target
description for the current XSAVE mask.  On FreeBSD amd64 this also
properly returns an i386 target description for 32-bit binaries which
allows the 64-bit GDB to run 32-bit binaries.

Note that the ptrace changes are in the BSD native targets, not the
FreeBSD-specific native targets since that is where the other ptrace
register accesses occur.  Of the other BSDs, NetBSD and DragonFly use
XSAVE in the kernel but do not currently export the extended state via
ptrace(2).  OpenBSD does not currently support XSAVE.

bfd/ChangeLog:

* elf.c (elfcore_grok_note): Recognize NT_X86_XSTATE on
FreeBSD.
(elfcore_write_xstatereg): Use correct note name on FreeBSD.

gdb/ChangeLog:

* amd64-tdep.c (amd64_target_description): New function.
* amd64-tdep.h: Export amd64_target_description and tdesc_amd64.
* amd64bsd-nat.c [PT_GETXSTATE_INFO]: New variable amd64bsd_xsave_len.
(amd64bsd_fetch_inferior_registers) [PT_GETXSTATE_INFO]: Handle
x86 extended save area.
(amd64bsd_store_inferior_registers) [PT_GETXSTATE_INFO]: Likewise.
* amd64bsd-nat.h: Export amd64bsd_xsave_len.
* amd64fbsd-nat.c (amd64fbsd_read_description): New function.
(_initialize_amd64fbsd_nat): Set "to_read_description" to
"amd64fbsd_read_description".
* amd64fbsd-tdep.c (amd64fbsd_core_read_description): New function.
(amd64fbsd_supply_xstateregset): New function.
(amd64fbsd_collect_xstateregset): New function.
Add "amd64fbsd_xstateregset".
(amd64fbsd_iterate_over_regset_sections): New function.
(amd64fbsd_init_abi): Set "xsave_xcr0_offset" to
"I386_FBSD_XSAVE_XCR0_OFFSET".
Add "iterate_over_regset_sections" gdbarch method.
Add "core_read_description" gdbarch method.
* i386-tdep.c (i386_target_description): New function.
* i386-tdep.h: Export i386_target_description and tdesc_i386.
* i386bsd-nat.c [PT_GETXSTATE_INFO]: New variable i386bsd_xsave_len.
(i386bsd_fetch_inferior_registers) [PT_GETXSTATE_INFO]: Handle
x86 extended save area.
(i386bsd_store_inferior_registers) [PT_GETXSTATE_INFO]: Likewise.
* i386bsd-nat.h: Export i386bsd_xsave_len.
* i386fbsd-nat.c (i386fbsd_read_description): New function.
(_initialize_i386fbsd_nat): Set "to_read_description" to
"i386fbsd_read_description".
* i386fbsd-tdep.c (i386fbsd_core_read_xcr0): New function.
(i386fbsd_core_read_description): New function.
(i386fbsd_supply_xstateregset): New function.
(i386fbsd_collect_xstateregset): New function.
Add "i386fbsd_xstateregset".
(i386fbsd_iterate_over_regset_sections): New function.
(i386fbsd4_init_abi): Set "xsave_xcr0_offset" to
"I386_FBSD_XSAVE_XCR0_OFFSET".
Add "iterate_over_regset_sections" gdbarch method.
Add "core_read_description" gdbarch method.
* i386fbsd-tdep.h: New file.

16 files changed:
bfd/ChangeLog
bfd/elf.c
gdb/ChangeLog
gdb/amd64-tdep.c
gdb/amd64-tdep.h
gdb/amd64bsd-nat.c
gdb/amd64bsd-nat.h
gdb/amd64fbsd-nat.c
gdb/amd64fbsd-tdep.c
gdb/i386-tdep.c
gdb/i386-tdep.h
gdb/i386bsd-nat.c
gdb/i386bsd-nat.h
gdb/i386fbsd-nat.c
gdb/i386fbsd-tdep.c
gdb/i386fbsd-tdep.h [new file with mode: 0644]

index 729630d4100527884bb4bf54b92cdde1a178ff8e..55c37f03959d5ff8758235cbac92845fdf07ba94 100644 (file)
@@ -1,3 +1,9 @@
+2015-04-13  John Baldwin  <jhb@FreeBSD.org>
+
+       * elf.c (elfcore_grok_note): Recognize NT_X86_XSTATE on
+       FreeBSD.
+       (elfcore_write_xstatereg): Use correct note name on FreeBSD.
+
 2015-04-13  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/18250
index a031b9e11b3abf3a3feedb11db82392844103ad6..41fb023c498b3a5f59a4f10db0150c23faf8d40c 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -8737,6 +8737,9 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
       if (note->namesz == 6
          && strcmp (note->namedata, "LINUX") == 0)
        return elfcore_grok_xstatereg (abfd, note);
+      else if (note->namesz == 8
+         && strcmp (note->namedata, "FreeBSD") == 0)
+       return elfcore_grok_xstatereg (abfd, note);
       else
        return TRUE;
 
@@ -9556,7 +9559,11 @@ char *
 elfcore_write_xstatereg (bfd *abfd, char *buf, int *bufsiz,
                         const void *xfpregs, int size)
 {
-  char *note_name = "LINUX";
+  char *note_name;
+  if (get_elf_backend_data (abfd)->elf_osabi == ELFOSABI_FREEBSD)
+    note_name = "FreeBSD";
+  else
+    note_name = "LINUX";
   return elfcore_write_note (abfd, buf, bufsiz,
                             note_name, NT_X86_XSTATE, xfpregs, size);
 }
index 8a14194e1913e84d3b736043d29d958e0ff1cb6c..1cd95c478c139fe7a01986e70c1442d8581a3022 100644 (file)
@@ -1,3 +1,46 @@
+2015-04-13  John Baldwin  <jhb@FreeBSD.org>
+
+       * amd64-tdep.c (amd64_target_description): New function.
+       * amd64-tdep.h: Export amd64_target_description and tdesc_amd64.
+       * amd64bsd-nat.c [PT_GETXSTATE_INFO]: New variable amd64bsd_xsave_len.
+       (amd64bsd_fetch_inferior_registers) [PT_GETXSTATE_INFO]: Handle
+       x86 extended save area.
+       (amd64bsd_store_inferior_registers) [PT_GETXSTATE_INFO]: Likewise.
+       * amd64bsd-nat.h: Export amd64bsd_xsave_len.
+       * amd64fbsd-nat.c (amd64fbsd_read_description): New function.
+       (_initialize_amd64fbsd_nat): Set "to_read_description" to
+       "amd64fbsd_read_description".
+       * amd64fbsd-tdep.c (amd64fbsd_core_read_description): New function.
+       (amd64fbsd_supply_xstateregset): New function.
+       (amd64fbsd_collect_xstateregset): New function.
+       Add "amd64fbsd_xstateregset".
+       (amd64fbsd_iterate_over_regset_sections): New function.
+       (amd64fbsd_init_abi): Set "xsave_xcr0_offset" to
+       "I386_FBSD_XSAVE_XCR0_OFFSET".
+       Add "iterate_over_regset_sections" gdbarch method.
+       Add "core_read_description" gdbarch method.
+       * i386-tdep.c (i386_target_description): New function.
+       * i386-tdep.h: Export i386_target_description and tdesc_i386.
+       * i386bsd-nat.c [PT_GETXSTATE_INFO]: New variable i386bsd_xsave_len.
+       (i386bsd_fetch_inferior_registers) [PT_GETXSTATE_INFO]: Handle
+       x86 extended save area.
+       (i386bsd_store_inferior_registers) [PT_GETXSTATE_INFO]: Likewise.
+       * i386bsd-nat.h: Export i386bsd_xsave_len.
+       * i386fbsd-nat.c (i386fbsd_read_description): New function.
+       (_initialize_i386fbsd_nat): Set "to_read_description" to
+       "i386fbsd_read_description".
+       * i386fbsd-tdep.c (i386fbsd_core_read_xcr0): New function.
+       (i386fbsd_core_read_description): New function.
+       (i386fbsd_supply_xstateregset): New function.
+       (i386fbsd_collect_xstateregset): New function.
+       Add "i386fbsd_xstateregset".
+       (i386fbsd_iterate_over_regset_sections): New function.
+       (i386fbsd4_init_abi): Set "xsave_xcr0_offset" to
+       "I386_FBSD_XSAVE_XCR0_OFFSET".
+       Add "iterate_over_regset_sections" gdbarch method.
+       Add "core_read_description" gdbarch method.
+       * i386fbsd-tdep.h: New file.
+
 2015-04-11  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * NEWS (Changes since GDB 7.9): Add removed -xdb.
index 3e5d1bd8a7cdc62c87a0c77956500e162077b277..461b701ac41787c544e82863f498b9257331b205 100644 (file)
@@ -39,6 +39,7 @@
 #include "disasm.h"
 #include "amd64-tdep.h"
 #include "i387-tdep.h"
+#include "x86-xstate.h"
 
 #include "features/i386/amd64.c"
 #include "features/i386/amd64-avx.c"
@@ -3118,6 +3119,25 @@ amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_ptr_bit (gdbarch, 32);
 }
 
+/* Return the target description for a specified XSAVE feature mask.  */
+
+const struct target_desc *
+amd64_target_description (uint64_t xcr0)
+{
+  switch (xcr0 & X86_XSTATE_ALL_MASK)
+    {
+    case X86_XSTATE_MPX_AVX512_MASK:
+    case X86_XSTATE_AVX512_MASK:
+      return tdesc_amd64_avx512;
+    case X86_XSTATE_MPX_MASK:
+      return tdesc_amd64_mpx;
+    case X86_XSTATE_AVX_MASK:
+      return tdesc_amd64_avx;
+    default:
+      return tdesc_amd64;
+    }
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 void _initialize_amd64_tdep (void);
 
index 318fd436f5d7ac57e445003f750a1227d08641da..704225e6f3902913482dc3b46712345ba1236531 100644 (file)
@@ -84,6 +84,8 @@ enum amd64_regnum
 
 #define AMD64_NUM_REGS         (AMD64_ZMM31H_REGNUM + 1)
 
+extern struct target_desc *tdesc_amd64;
+
 extern struct displaced_step_closure *amd64_displaced_step_copy_insn
   (struct gdbarch *gdbarch, CORE_ADDR from, CORE_ADDR to,
    struct regcache *regs);
@@ -95,6 +97,7 @@ extern void amd64_displaced_step_fixup (struct gdbarch *gdbarch,
 extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
 extern void amd64_x32_init_abi (struct gdbarch_info info,
                                struct gdbarch *gdbarch);
+extern const struct target_desc *amd64_target_description (uint64_t xcr0);
 
 /* Fill register REGNUM in REGCACHE with the appropriate
    floating-point or SSE register value from *FXSAVE.  If REGNUM is
index 31060a123daf4980bdc0cfe2be9552a52f1a7ebf..66d42894bd41222a38e59caf8cb897ddfc9bc004 100644 (file)
 #include "inf-ptrace.h"
 \f
 
+#ifdef PT_GETXSTATE_INFO
+size_t amd64bsd_xsave_len;
+#endif
+
 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
    for all registers (including the floating-point registers).  */
 
@@ -60,6 +64,20 @@ amd64bsd_fetch_inferior_registers (struct target_ops *ops,
   if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
       struct fpreg fpregs;
+#ifdef PT_GETXSTATE_INFO
+      char *xstateregs;
+
+      if (amd64bsd_xsave_len != 0)
+       {
+         xstateregs = alloca (amd64bsd_xsave_len);
+         if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
+                     (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
+           perror_with_name (_("Couldn't get extended state status"));
+
+         amd64_supply_xsave (regcache, -1, xstateregs);
+         return;
+       }
+#endif
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
                  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
@@ -99,6 +117,24 @@ amd64bsd_store_inferior_registers (struct target_ops *ops,
   if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
       struct fpreg fpregs;
+#ifdef PT_GETXSTATE_INFO
+      char *xstateregs;
+
+      if (amd64bsd_xsave_len != 0)
+       {
+         xstateregs = alloca (amd64bsd_xsave_len);
+         if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
+                     (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
+           perror_with_name (_("Couldn't get extended state status"));
+
+         amd64_collect_xsave (regcache, regnum, xstateregs, 0);
+
+         if (ptrace (PT_SETXSTATE, ptid_get_pid (inferior_ptid),
+                     (PTRACE_TYPE_ARG3) xstateregs, amd64bsd_xsave_len) == -1)
+           perror_with_name (_("Couldn't write extended state status"));
+         return;
+       }
+#endif
 
       if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
                  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
index 167eb5615673ec10db2b04cf5e3b106ad214d177..09776ee305ab9d81c96a2c73d751c37e8602a63e 100644 (file)
@@ -20,6 +20,9 @@
 #ifndef AMD64BSD_NAT_H
 #define AMD64BSD_NAT_H
 
+/* Low level amd64 XSAVE info.  */
+extern size_t amd64bsd_xsave_len;
+
 /* Low level amd64 debug register functions.  */
 
 extern void amd64bsd_dr_set_control (unsigned long control);
index b1b261c19610d5424f93448fa0054af4e6cad480..a721f48edee3dd8cd36ebb593da04e7e826f106c 100644 (file)
@@ -151,6 +151,50 @@ amd64fbsd_mourn_inferior (struct target_ops *ops)
   super_mourn_inferior (ops);
 }
 
+/* Implement the to_read_description method.  */
+
+static const struct target_desc *
+amd64fbsd_read_description (struct target_ops *ops)
+{
+#ifdef PT_GETXSTATE_INFO
+  static int xsave_probed;
+  static uint64_t xcr0;
+#endif
+  struct reg regs;
+  int is64;
+
+  if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
+             (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+    perror_with_name (_("Couldn't get registers"));
+  is64 = (regs.r_cs == GSEL (GUCODE_SEL, SEL_UPL));
+#ifdef PT_GETXSTATE_INFO
+  if (!xsave_probed)
+    {
+      struct ptrace_xstate_info info;
+
+      if (ptrace (PT_GETXSTATE_INFO, ptid_get_pid (inferior_ptid),
+                 (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
+       {
+         amd64bsd_xsave_len = info.xsave_len;
+         xcr0 = info.xsave_mask;
+       }
+      xsave_probed = 1;
+    }
+
+  if (amd64bsd_xsave_len != 0)
+    {
+      if (is64)
+       return amd64_target_description (xcr0);
+      else
+       return i386_target_description (xcr0);
+    }
+#endif
+  if (is64)
+    return tdesc_amd64;
+  else
+    return tdesc_i386;
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 void _initialize_amd64fbsd_nat (void);
 
@@ -181,6 +225,7 @@ _initialize_amd64fbsd_nat (void)
 
   super_mourn_inferior = t->to_mourn_inferior;
   t->to_mourn_inferior = amd64fbsd_mourn_inferior;
+  t->to_read_description = amd64fbsd_read_description;
 
   t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
   t->to_find_memory_regions = fbsd_find_memory_regions;
index 62dcb83d6d0b4b3bfb6c9a674a6f866670b51e97..52705d9e305aafcae49fc8e255a4e77cd7836616 100644 (file)
@@ -23,6 +23,9 @@
 #include "gdbcore.h"
 #include "regcache.h"
 #include "osabi.h"
+#include "regset.h"
+#include "i386fbsd-tdep.h"
+#include "x86-xstate.h"
 
 #include "amd64-tdep.h"
 #include "bsd-uthread.h"
@@ -169,6 +172,59 @@ static int amd64fbsd_jmp_buf_reg_offset[] =
   0 * 8                                /* %rip */
 };
 
+/* Implement the core_read_description gdbarch method.  */
+
+static const struct target_desc *
+amd64fbsd_core_read_description (struct gdbarch *gdbarch,
+                                struct target_ops *target,
+                                bfd *abfd)
+{
+  return amd64_target_description (i386fbsd_core_read_xcr0 (abfd));
+}
+
+/* Similar to amd64_supply_fpregset, but use XSAVE extended state.  */
+
+static void
+amd64fbsd_supply_xstateregset (const struct regset *regset,
+                              struct regcache *regcache, int regnum,
+                              const void *xstateregs, size_t len)
+{
+  amd64_supply_xsave (regcache, regnum, xstateregs);
+}
+
+/* Similar to amd64_collect_fpregset, but use XSAVE extended state.  */
+
+static void
+amd64fbsd_collect_xstateregset (const struct regset *regset,
+                               const struct regcache *regcache,
+                               int regnum, void *xstateregs, size_t len)
+{
+  amd64_collect_xsave (regcache, regnum, xstateregs, 1);
+}
+
+static const struct regset amd64fbsd_xstateregset =
+  {
+    NULL,
+    amd64fbsd_supply_xstateregset,
+    amd64fbsd_collect_xstateregset
+  };
+
+/* Iterate over core file register note sections.  */
+
+static void
+amd64fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                       iterate_over_regset_sections_cb *cb,
+                                       void *cb_data,
+                                       const struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  cb (".reg", tdep->sizeof_gregset, &i386_gregset, NULL, cb_data);
+  cb (".reg2", tdep->sizeof_fpregset, &amd64_fpregset, NULL, cb_data);
+  cb (".reg-xstate", X86_XSTATE_SIZE(tdep->xcr0),
+      &amd64fbsd_xstateregset, "XSAVE extended state", cb_data);
+}
+
 static void
 amd64fbsd_supply_uthread (struct regcache *regcache,
                          int regnum, CORE_ADDR addr)
@@ -233,6 +289,15 @@ amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->sc_reg_offset = amd64fbsd_sc_reg_offset;
   tdep->sc_num_regs = ARRAY_SIZE (amd64fbsd_sc_reg_offset);
 
+  tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
+
+  /* Iterate over core file register note sections.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, amd64fbsd_iterate_over_regset_sections);
+
+  set_gdbarch_core_read_description (gdbarch,
+                                    amd64fbsd_core_read_description);
+
   /* FreeBSD provides a user-level threads implementation.  */
   bsd_uthread_set_supply_uthread (gdbarch, amd64fbsd_supply_uthread);
   bsd_uthread_set_collect_uthread (gdbarch, amd64fbsd_collect_uthread);
index 4d979159cc396ee3120cd1d7dc901f96104ebd3b..0c7eb5afbe890445ce302bbf14f53694e4e6b465 100644 (file)
@@ -8598,6 +8598,25 @@ i386_coff_osabi_sniffer (bfd *abfd)
 }
 \f
 
+/* Return the target description for a specified XSAVE feature mask.  */
+
+const struct target_desc *
+i386_target_description (uint64_t xcr0)
+{
+  switch (xcr0 & X86_XSTATE_ALL_MASK)
+    {
+    case X86_XSTATE_MPX_AVX512_MASK:
+    case X86_XSTATE_AVX512_MASK:
+      return tdesc_i386_avx512;
+    case X86_XSTATE_MPX_MASK:
+      return tdesc_i386_mpx;
+    case X86_XSTATE_AVX_MASK:
+      return tdesc_i386_avx;
+    default:
+      return tdesc_i386;
+    }
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 void _initialize_i386_tdep (void);
 
index 8bfd4129cac9e5e43e75d85f6587abb6e471c6c4..7880f6ca5942aea303b4546ea45651ad9e4c714a 100644 (file)
@@ -328,6 +328,8 @@ enum record_i386_regnum
 /* Size of the largest register.  */
 #define I386_MAX_REGISTER_SIZE 64
 
+extern struct target_desc *tdesc_i386;
+
 /* Types for i386-specific registers.  */
 extern struct type *i387_ext_type (struct gdbarch *gdbarch);
 
@@ -416,6 +418,7 @@ extern void i386_svr4_init_abi (struct gdbarch_info, struct gdbarch *);
 
 extern int i386_process_record (struct gdbarch *gdbarch,
                                 struct regcache *regcache, CORE_ADDR addr);
+extern const struct target_desc *i386_target_description (uint64_t xcr0);
 
 \f
 
index 16e0707336b25956e4903770d07ac7aac00c4bb0..ac8a19bb50915505540e46479f59d9356660782e 100644 (file)
@@ -81,6 +81,10 @@ static int i386bsd_r_reg_offset[] =
    so that we try PT_GETXMMREGS the first time around.  */
 static int have_ptrace_xmmregs = -1;
 #endif
+
+#ifdef PT_GETXSTATE_INFO
+size_t i386bsd_xsave_len;
+#endif
 \f
 
 /* Supply the general-purpose registers in GREGS, to REGCACHE.  */
@@ -148,7 +152,24 @@ i386bsd_fetch_inferior_registers (struct target_ops *ops,
       struct fpreg fpregs;
 #ifdef HAVE_PT_GETXMMREGS
       char xmmregs[512];
+#endif
+
+#ifdef PT_GETXSTATE_INFO
+      if (i386bsd_xsave_len != 0)
+       {
+         char *xstateregs;
+
+         xstateregs = alloca (i386bsd_xsave_len);
+         if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
+                     (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
+           perror_with_name (_("Couldn't get extended state status"));
 
+         i387_supply_xsave (regcache, -1, xstateregs);
+         return;
+       }
+#endif
+      
+#ifdef HAVE_PT_GETXMMREGS
       if (have_ptrace_xmmregs != 0
          && ptrace(PT_GETXMMREGS, ptid_get_pid (inferior_ptid),
                    (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
@@ -158,18 +179,15 @@ i386bsd_fetch_inferior_registers (struct target_ops *ops,
        }
       else
        {
+         have_ptrace_xmmregs = 0;
+#endif
           if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
                      (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
            perror_with_name (_("Couldn't get floating point status"));
 
          i387_supply_fsave (regcache, -1, &fpregs);
+#ifdef HAVE_PT_GETXMMREGS
        }
-#else
-      if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid),
-                 (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
-       perror_with_name (_("Couldn't get floating point status"));
-
-      i387_supply_fsave (regcache, -1, &fpregs);
 #endif
     }
 }
@@ -204,7 +222,28 @@ i386bsd_store_inferior_registers (struct target_ops *ops,
       struct fpreg fpregs;
 #ifdef HAVE_PT_GETXMMREGS
       char xmmregs[512];
+#endif
+
+#ifdef PT_GETXSTATE_INFO
+      if (i386bsd_xsave_len != 0)
+       {
+         char *xstateregs;
+
+         xstateregs = alloca (i386bsd_xsave_len);
+         if (ptrace (PT_GETXSTATE, ptid_get_pid (inferior_ptid),
+                     (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
+           perror_with_name (_("Couldn't get extended state status"));
 
+         i387_collect_xsave (regcache, -1, xstateregs, 0);
+
+         if (ptrace (PT_SETXSTATE, ptid_get_pid (inferior_ptid),
+                     (PTRACE_TYPE_ARG3) xstateregs, i386bsd_xsave_len) == -1)
+           perror_with_name (_("Couldn't write extended state status"));
+         return;
+       }
+#endif
+
+#ifdef HAVE_PT_GETXMMREGS
       if (have_ptrace_xmmregs != 0
          && ptrace(PT_GETXMMREGS, ptid_get_pid (inferior_ptid),
                    (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
index a11f5547d4fd967545e3ba793f6a78de54619cc0..2f50c32545ee24b0027814dec407a21655e91c3c 100644 (file)
@@ -25,6 +25,9 @@
 
 extern struct target_ops *i386bsd_target (void);
 
+/* Low level i386 XSAVE info.  */
+extern size_t i386bsd_xsave_len;
+
 /* low level i386 debug register functions used in i386fbsd-nat.c.  */
 
 extern void i386bsd_dr_set_control (unsigned long control);
index ad439e3d44e384729699e8aa1117c072ac75d418..6c43f2c4e8dfbdd424ce1272e9fa554b76932208 100644 (file)
@@ -116,6 +116,37 @@ i386fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
 }
 \f
 
+#ifdef PT_GETXSTATE_INFO
+/* Implement the to_read_description method.  */
+
+static const struct target_desc *
+i386fbsd_read_description (struct target_ops *ops)
+{
+  static int xsave_probed;
+  static uint64_t xcr0;
+
+  if (!xsave_probed)
+    {
+      struct ptrace_xstate_info info;
+
+      if (ptrace (PT_GETXSTATE_INFO, ptid_get_pid (inferior_ptid),
+                 (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
+       {
+         i386bsd_xsave_len = info.xsave_len;
+         xcr0 = info.xsave_mask;
+       }
+      xsave_probed = 1;
+    }
+
+  if (i386bsd_xsave_len != 0)
+    {
+      return i386_target_description (xcr0);
+    }
+  else
+    return tdesc_i386;
+}
+#endif
+
 /* Prevent warning from -Wmissing-prototypes.  */
 void _initialize_i386fbsd_nat (void);
 
@@ -140,6 +171,9 @@ _initialize_i386fbsd_nat (void)
 
 #endif /* HAVE_PT_GETDBREGS */
 
+#ifdef PT_GETXSTATE_INFO
+  t->to_read_description = i386fbsd_read_description;
+#endif
 
   t->to_resume = i386fbsd_resume;
   t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
index ed417063643e26d2c375697910efc9a77ae30831..99e08cbdede7e8c41f58e196d7a88b7cae00b834 100644 (file)
@@ -22,6 +22,9 @@
 #include "gdbcore.h"
 #include "osabi.h"
 #include "regcache.h"
+#include "regset.h"
+#include "i386fbsd-tdep.h"
+#include "x86-xstate.h"
 
 #include "i386-tdep.h"
 #include "i387-tdep.h"
@@ -235,6 +238,100 @@ static int i386fbsd_jmp_buf_reg_offset[] =
   0 * 4                                /* %eip */
 };
 
+/* Get XSAVE extended state xcr0 from core dump.  */
+
+uint64_t
+i386fbsd_core_read_xcr0 (bfd *abfd)
+{
+  asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate");
+  uint64_t xcr0;
+
+  if (xstate)
+    {
+      size_t size = bfd_section_size (abfd, xstate);
+
+      /* Check extended state size.  */
+      if (size < X86_XSTATE_AVX_SIZE)
+       xcr0 = X86_XSTATE_SSE_MASK;
+      else
+       {
+         char contents[8];
+
+         if (! bfd_get_section_contents (abfd, xstate, contents,
+                                         I386_FBSD_XSAVE_XCR0_OFFSET,
+                                         8))
+           {
+             warning (_("Couldn't read `xcr0' bytes from "
+                        "`.reg-xstate' section in core file."));
+             return 0;
+           }
+
+         xcr0 = bfd_get_64 (abfd, contents);
+       }
+    }
+  else
+    xcr0 = 0;
+
+  return xcr0;
+}
+
+/* Implement the core_read_description gdbarch method.  */
+
+static const struct target_desc *
+i386fbsd_core_read_description (struct gdbarch *gdbarch,
+                               struct target_ops *target,
+                               bfd *abfd)
+{
+  return i386_target_description (i386fbsd_core_read_xcr0 (abfd));
+}
+
+/* Similar to i386_supply_fpregset, but use XSAVE extended state.  */
+
+static void
+i386fbsd_supply_xstateregset (const struct regset *regset,
+                             struct regcache *regcache, int regnum,
+                             const void *xstateregs, size_t len)
+{
+  i387_supply_xsave (regcache, regnum, xstateregs);
+}
+
+/* Similar to i386_collect_fpregset, but use XSAVE extended state.  */
+
+static void
+i386fbsd_collect_xstateregset (const struct regset *regset,
+                              const struct regcache *regcache,
+                              int regnum, void *xstateregs, size_t len)
+{
+  i387_collect_xsave (regcache, regnum, xstateregs, 1);
+}
+
+/* Register set definitions.  */
+
+static const struct regset i386fbsd_xstateregset =
+  {
+    NULL,
+    i386fbsd_supply_xstateregset,
+    i386fbsd_collect_xstateregset
+  };
+
+/* Iterate over core file register note sections.  */
+
+static void
+i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
+                                      iterate_over_regset_sections_cb *cb,
+                                      void *cb_data,
+                                      const struct regcache *regcache)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  cb (".reg", tdep->sizeof_gregset, &i386_gregset, NULL, cb_data);
+  cb (".reg2", tdep->sizeof_fpregset, &i386_fpregset, NULL, cb_data);
+
+  if (tdep->xcr0 & X86_XSTATE_AVX)
+    cb (".reg-xstate", X86_XSTATE_SIZE(tdep->xcr0),
+       &i386fbsd_xstateregset, "XSAVE extended state", cb_data);
+}
+
 static void
 i386fbsd_supply_uthread (struct regcache *regcache,
                         int regnum, CORE_ADDR addr)
@@ -376,6 +473,15 @@ i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* FreeBSD 4.0 introduced a new `struct sigcontext'.  */
   tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
   tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
+
+  tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
+
+  /* Iterate over core file register note sections.  */
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, i386fbsd_iterate_over_regset_sections);
+
+  set_gdbarch_core_read_description (gdbarch,
+                                    i386fbsd_core_read_description);
 }
 
 \f
diff --git a/gdb/i386fbsd-tdep.h b/gdb/i386fbsd-tdep.h
new file mode 100644 (file)
index 0000000..8d6f998
--- /dev/null
@@ -0,0 +1,31 @@
+/* Target-dependent code for FreeBSD x86.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef I386FBSD_TDEP_H
+#define I386FBSD_TDEP_H
+
+/* Get XSAVE extended state xcr0 from core dump.  */
+extern uint64_t i386fbsd_core_read_xcr0 (bfd *abfd);
+
+/* The format of the XSAVE extended area is determined by hardware.
+   Cores store the XSAVE extended area in a NT_X86_XSTATE note that
+   matches the layout on Linux.  */
+#define I386_FBSD_XSAVE_XCR0_OFFSET 464
+
+#endif /* i386fbsd-tdep.h */