FreeBSD x86 nat: Use register maps for GP register sets.
authorJohn Baldwin <jhb@FreeBSD.org>
Fri, 28 Jan 2022 19:14:37 +0000 (11:14 -0800)
committerJohn Baldwin <jhb@FreeBSD.org>
Fri, 28 Jan 2022 19:14:37 +0000 (11:14 -0800)
Rather than using the x86-specific register offset tables, use
register maps to describe the layout of the general purpose registers
fetched via PT_GETREGS.  The sole user-visible difference is that
FreeBSD/amd64 will now report additional segment registers ($ds, $es,
$fs, and $gs) for both 32-bit and 64-bit processes.

As part of these changes, the FreeBSD x86 native targets no longer use
amd64-bsd-nat.c or i386-bsd-nat.c.  Remove FreeBSD-specific register
handling (for $fs_base, $gs_base, and XSAVE state) from these files.
Similarly, remove the global x86bsd_xsave_len from x86-bsd-nat.c.  The
FreeBSD x86 native targets use a static xsave_len instead.

While here, rework the probing of PT_GETXMMREGS on FreeBSD/i386.
Probe the ptrace op once in the target read_description method and
cache the result for the future similar to the way the status of XSAVE
support is probed in the read_description method.  In addition, return
the proper xcr0 mask (X87-only) for old kernels or systems without
either XSAVE or XMM support.

gdb/amd64-bsd-nat.c
gdb/amd64-fbsd-nat.c
gdb/amd64-fbsd-tdep.c
gdb/amd64-fbsd-tdep.h [new file with mode: 0644]
gdb/configure.nat
gdb/i386-bsd-nat.c
gdb/i386-fbsd-nat.c
gdb/i386-fbsd-tdep.h
gdb/x86-bsd-nat.c
gdb/x86-bsd-nat.h

index 52730ba276edafcec600c95dfcafc4bb24face74..77dc4c935ca1310d1349365cc2aea1970c589338 100644 (file)
@@ -59,9 +59,6 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   ptid_t ptid = regcache->ptid ();
-#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)
-  i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
-#endif
 
   if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
@@ -75,50 +72,9 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
        return;
     }
 
-#ifdef PT_GETFSBASE
-  if (regnum == -1 || regnum == tdep->fsbase_regnum)
-    {
-      register_t base;
-
-      if (gdb_ptrace (PT_GETFSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't get segment register fs_base"));
-
-      regcache->raw_supply (tdep->fsbase_regnum, &base);
-      if (regnum != -1)
-       return;
-    }
-#endif
-#ifdef PT_GETGSBASE
-  if (regnum == -1 || regnum == tdep->fsbase_regnum + 1)
-    {
-      register_t base;
-
-      if (gdb_ptrace (PT_GETGSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't get segment register gs_base"));
-
-      regcache->raw_supply (tdep->fsbase_regnum + 1, &base);
-      if (regnum != -1)
-       return;
-    }
-#endif
-
   if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
       struct fpreg fpregs;
-#ifdef PT_GETXSTATE_INFO
-      void *xstateregs;
-
-      if (x86bsd_xsave_len != 0)
-       {
-         xstateregs = alloca (x86bsd_xsave_len);
-         if (gdb_ptrace (PT_GETXSTATE, 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 (gdb_ptrace (PT_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
        perror_with_name (_("Couldn't get floating point status"));
@@ -135,9 +91,6 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   ptid_t ptid = regcache->ptid ();
-#if defined(PT_SETFSBASE) || defined(PT_SETGSBASE)
-  i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
-#endif
 
   if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
@@ -155,58 +108,9 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum)
        return;
     }
 
-#ifdef PT_SETFSBASE
-  if (regnum == -1 || regnum == tdep->fsbase_regnum)
-    {
-      register_t base;
-
-      /* Clear the full base value to support 32-bit targets.  */
-      base = 0;
-      regcache->raw_collect (tdep->fsbase_regnum, &base);
-
-      if (gdb_ptrace (PT_SETFSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't write segment register fs_base"));
-      if (regnum != -1)
-       return;
-    }
-#endif
-#ifdef PT_SETGSBASE
-  if (regnum == -1 || regnum == tdep->fsbase_regnum + 1)
-    {
-      register_t base;
-
-      /* Clear the full base value to support 32-bit targets.  */
-      base = 0;
-      regcache->raw_collect (tdep->fsbase_regnum + 1, &base);
-
-      if (gdb_ptrace (PT_SETGSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't write segment register gs_base"));
-      if (regnum != -1)
-       return;
-    }
-#endif
-
   if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
     {
       struct fpreg fpregs;
-#ifdef PT_GETXSTATE_INFO
-      void *xstateregs;
-
-      if (x86bsd_xsave_len != 0)
-       {
-         xstateregs = alloca (x86bsd_xsave_len);
-         if (gdb_ptrace (PT_GETXSTATE, ptid, (PTRACE_TYPE_ARG3) xstateregs, 0)
-             == -1)
-           perror_with_name (_("Couldn't get extended state status"));
-
-         amd64_collect_xsave (regcache, regnum, xstateregs, 0);
-
-         if (gdb_ptrace (PT_SETXSTATE, ptid, (PTRACE_TYPE_ARG3) xstateregs,
-                         x86bsd_xsave_len) == -1)
-           perror_with_name (_("Couldn't write extended state status"));
-         return;
-       }
-#endif
 
       if (gdb_ptrace (PT_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
        perror_with_name (_("Couldn't get floating point status"));
index f9bd45de4554de2248cac4554deccb75d8789676..98a1af03a66012812991a1ba3f76b26c8ea8e747 100644 (file)
 
 #include "fbsd-nat.h"
 #include "amd64-tdep.h"
+#include "amd64-fbsd-tdep.h"
 #include "amd64-nat.h"
-#include "amd64-bsd-nat.h"
 #include "x86-nat.h"
 #include "gdbsupport/x86-xstate.h"
-\f
+#include "x86-bsd-nat.h"
 
 class amd64_fbsd_nat_target final
-  : public amd64_bsd_nat_target<fbsd_nat_target>
+  : public x86bsd_nat_target<fbsd_nat_target>
 {
 public:
-  /* Add some extra features to the common *BSD/amd64 target.  */
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+
   const struct target_desc *read_description () override;
 
 #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO)
@@ -51,61 +53,208 @@ public:
 
 static amd64_fbsd_nat_target the_amd64_fbsd_nat_target;
 
-/* Offset in `struct reg' where MEMBER is stored.  */
-#define REG_OFFSET(member) offsetof (struct reg, member)
+#ifdef PT_GETXSTATE_INFO
+static size_t xsave_len;
+#endif
+
+/* This is a layout of the amd64 'struct reg' but with i386
+   registers.  */
 
-/* At amd64fbsd64_r_reg_offset[REGNUM] you'll find the offset in
-   `struct reg' location where the GDB register REGNUM is stored.
-   Unsupported registers are marked with `-1'.  */
-static int amd64fbsd64_r_reg_offset[] =
+static const struct regcache_map_entry amd64_fbsd32_gregmap[] =
 {
-  REG_OFFSET (r_rax),
-  REG_OFFSET (r_rbx),
-  REG_OFFSET (r_rcx),
-  REG_OFFSET (r_rdx),
-  REG_OFFSET (r_rsi),
-  REG_OFFSET (r_rdi),
-  REG_OFFSET (r_rbp),
-  REG_OFFSET (r_rsp),
-  REG_OFFSET (r_r8),
-  REG_OFFSET (r_r9),
-  REG_OFFSET (r_r10),
-  REG_OFFSET (r_r11),
-  REG_OFFSET (r_r12),
-  REG_OFFSET (r_r13),
-  REG_OFFSET (r_r14),
-  REG_OFFSET (r_r15),
-  REG_OFFSET (r_rip),
-  REG_OFFSET (r_rflags),
-  REG_OFFSET (r_cs),
-  REG_OFFSET (r_ss),
-  -1,
-  -1,
-  -1,
-  -1
+  { 8, REGCACHE_MAP_SKIP, 8 },
+  { 1, I386_EDI_REGNUM, 8 },
+  { 1, I386_ESI_REGNUM, 8 },
+  { 1, I386_EBP_REGNUM, 8 },
+  { 1, I386_EBX_REGNUM, 8 },
+  { 1, I386_EDX_REGNUM, 8 },
+  { 1, I386_ECX_REGNUM, 8 },
+  { 1, I386_EAX_REGNUM, 8 },
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* trapno */
+  { 1, I386_FS_REGNUM, 2 },
+  { 1, I386_GS_REGNUM, 2 },
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* err */
+  { 1, I386_ES_REGNUM, 2 },
+  { 1, I386_DS_REGNUM, 2 },
+  { 1, I386_EIP_REGNUM, 8 },
+  { 1, I386_CS_REGNUM, 8 },
+  { 1, I386_EFLAGS_REGNUM, 8 },
+  { 1, I386_ESP_REGNUM, 0 },
+  { 1, I386_SS_REGNUM, 8 },
+  { 0 }
 };
-\f
 
-/* Mapping between the general-purpose registers in FreeBSD/amd64
-   `struct reg' format and GDB's register cache layout for
-   FreeBSD/i386.
+static const struct regset amd64_fbsd32_gregset =
+{
+  amd64_fbsd32_gregmap, regcache_supply_regset, regcache_collect_regset
+};
 
-   Note that most FreeBSD/amd64 registers are 64-bit, while the
-   FreeBSD/i386 registers are all 32-bit, but since we're
-   little-endian we get away with that.  */
+/* Return the regset to use for 'struct reg' for the GDBARCH.  */
 
-/* From <machine/reg.h>.  */
-static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
+static const struct regset *
+find_gregset (struct gdbarch *gdbarch)
 {
-  14 * 8, 13 * 8,              /* %eax, %ecx */
-  12 * 8, 11 * 8,              /* %edx, %ebx */
-  20 * 8, 10 * 8,              /* %esp, %ebp */
-  9 * 8, 8 * 8,                        /* %esi, %edi */
-  17 * 8, 19 * 8,              /* %eip, %eflags */
-  18 * 8, 21 * 8,              /* %cs, %ss */
-  -1, -1, -1, -1               /* %ds, %es, %fs, %gs */
-};
-\f
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+    return &amd64_fbsd32_gregset;
+  else
+    return &amd64_fbsd_gregset;
+}
+
+/* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
+   for all registers.  */
+
+void
+amd64_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)
+  const i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+#endif
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+  const struct regset *gregset = find_gregset (gdbarch);
+
+  if (fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS, gregset))
+    {
+      if (regnum != -1)
+       return;
+    }
+
+#ifdef PT_GETFSBASE
+  if (regnum == -1 || regnum == tdep->fsbase_regnum)
+    {
+      register_t base;
+
+      if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't get segment register fs_base"));
+
+      regcache->raw_supply (tdep->fsbase_regnum, &base);
+      if (regnum != -1)
+       return;
+    }
+#endif
+#ifdef PT_GETGSBASE
+  if (regnum == -1 || regnum == tdep->fsbase_regnum + 1)
+    {
+      register_t base;
+
+      if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't get segment register gs_base"));
+
+      regcache->raw_supply (tdep->fsbase_regnum + 1, &base);
+      if (regnum != -1)
+       return;
+    }
+#endif
+
+  /* There is no amd64_fxsave_supplies or amd64_xsave_supplies.
+     Instead, the earlier register sets return early if the request
+     was for a specific register that was already satisified to avoid
+     fetching the FPU/XSAVE state unnecessarily.  */
+
+#ifdef PT_GETXSTATE_INFO
+  if (xsave_len != 0)
+    {
+      void *xstateregs = alloca (xsave_len);
+
+      if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
+       perror_with_name (_("Couldn't get extended state status"));
+
+      amd64_supply_xsave (regcache, regnum, xstateregs);
+      return;
+    }
+#endif
+
+  struct fpreg fpregs;
+
+  if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+    perror_with_name (_("Couldn't get floating point status"));
+
+  amd64_supply_fxsave (regcache, regnum, &fpregs);
+}
+
+/* Store register REGNUM back into the inferior.  If REGNUM is -1, do
+   this for all registers.  */
+
+void
+amd64_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)
+  const i386_gdbarch_tdep *tdep = (i386_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+#endif
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+  const struct regset *gregset = find_gregset (gdbarch);
+
+  if (store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS,
+                                     gregset))
+    {
+      if (regnum != -1)
+       return;
+    }
+
+#ifdef PT_SETFSBASE
+  if (regnum == -1 || regnum == tdep->fsbase_regnum)
+    {
+      register_t base;
+
+      /* Clear the full base value to support 32-bit targets.  */
+      base = 0;
+      regcache->raw_collect (tdep->fsbase_regnum, &base);
+
+      if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't write segment register fs_base"));
+      if (regnum != -1)
+       return;
+    }
+#endif
+#ifdef PT_SETGSBASE
+  if (regnum == -1 || regnum == tdep->fsbase_regnum + 1)
+    {
+      register_t base;
+
+      /* Clear the full base value to support 32-bit targets.  */
+      base = 0;
+      regcache->raw_collect (tdep->fsbase_regnum + 1, &base);
+
+      if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't write segment register gs_base"));
+      if (regnum != -1)
+       return;
+    }
+#endif
+
+  /* There is no amd64_fxsave_supplies or amd64_xsave_supplies.
+     Instead, the earlier register sets return early if the request
+     was for a specific register that was already satisified to avoid
+     fetching the FPU/XSAVE state unnecessarily.  */
+
+#ifdef PT_GETXSTATE_INFO
+  if (xsave_len != 0)
+    {
+      void *xstateregs = alloca (xsave_len);
+
+      if (ptrace (PT_GETXSTATE, pid, (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, pid, (PTRACE_TYPE_ARG3) xstateregs,
+                 xsave_len) == -1)
+       perror_with_name (_("Couldn't write extended state status"));
+      return;
+    }
+#endif
+
+  struct fpreg fpregs;
+
+  if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+    perror_with_name (_("Couldn't get floating point status"));
+
+  amd64_collect_fxsave (regcache, regnum, &fpregs);
+
+  if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+    perror_with_name (_("Couldn't write floating point status"));
+}
 
 /* Support for debugging kernel virtual memory images.  */
 
@@ -179,13 +328,13 @@ amd64_fbsd_nat_target::read_description ()
       if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (),
                  (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
        {
-         x86bsd_xsave_len = info.xsave_len;
+         xsave_len = info.xsave_len;
          xcr0 = info.xsave_mask;
        }
       xsave_probed = 1;
     }
 
-  if (x86bsd_xsave_len != 0)
+  if (xsave_len != 0)
     {
       if (is64)
        return amd64_target_description (xcr0, true);
@@ -213,9 +362,6 @@ void _initialize_amd64fbsd_nat ();
 void
 _initialize_amd64fbsd_nat ()
 {
-  amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
-  amd64_native_gregset64_reg_offset = amd64fbsd64_r_reg_offset;
-
   add_inf_child_target (&the_amd64_fbsd_nat_target);
 
   /* Support debugging kernel virtual memory images.  */
index fa363776fc01aa75fd0b5969dcb149c0241627d7..f87c976dd613872f94aee64cd0d2f270c9fb0d0f 100644 (file)
@@ -27,6 +27,7 @@
 #include "gdbsupport/x86-xstate.h"
 
 #include "amd64-tdep.h"
+#include "amd64-fbsd-tdep.h"
 #include "fbsd-tdep.h"
 #include "solib-svr4.h"
 #include "inferior.h"
diff --git a/gdb/amd64-fbsd-tdep.h b/gdb/amd64-fbsd-tdep.h
new file mode 100644 (file)
index 0000000..0a18dbc
--- /dev/null
@@ -0,0 +1,27 @@
+/* FreeBSD/amd64 target support, prototypes.
+
+   Copyright (C) 2021 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 AMD64_FBSD_TDEP_H
+#define AMD64_FBSD_TDEP_H
+
+#include "regset.h"
+
+extern const struct regset amd64_fbsd_gregset;
+
+#endif /* AMD64_FBSD_TDEP_H */
index 6fc3978a77e43db21e070ce2c3033e9c409337cc..20ce8050a9692e87678863d7eba900f35d2b8eae 100644 (file)
@@ -165,7 +165,7 @@ case ${gdb_host} in
            i386)
                # Host: FreeBSD/i386
                NATDEPFILES="${NATDEPFILES} x86-nat.o nat/x86-dregs.o \
-               x86-bsd-nat.o i386-bsd-nat.o i386-fbsd-nat.o bsd-kvm.o"
+               x86-bsd-nat.o i386-fbsd-nat.o bsd-kvm.o"
                ;;
            mips)
                # Host: FreeBSD/mips
@@ -192,7 +192,7 @@ case ${gdb_host} in
        case ${gdb_host_cpu} in
            i386)
                # Host: FreeBSD/amd64
-               NATDEPFILES="${NATDEPFILES} amd64-nat.o amd64-bsd-nat.o \
+               NATDEPFILES="${NATDEPFILES} amd64-nat.o \
                amd64-fbsd-nat.o bsd-kvm.o x86-nat.o nat/x86-dregs.o \
                x86-bsd-nat.o"
                ;;
index c112b02c2e1ba8418edb47bbd632f871c2c1fdf4..bd9655c9ef99f7214f4cd2c2e421e2a29a9efbb4 100644 (file)
@@ -159,56 +159,12 @@ i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
        return;
     }
 
-#ifdef PT_GETFSBASE
-  if (regnum == -1 || regnum == I386_FSBASE_REGNUM)
-    {
-      register_t base;
-
-      if (gdb_ptrace (PT_GETFSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't get segment register fs_base"));
-
-      regcache->raw_supply (I386_FSBASE_REGNUM, &base);
-      if (regnum != -1)
-       return;
-    }
-#endif
-#ifdef PT_GETGSBASE
-  if (regnum == -1 || regnum == I386_GSBASE_REGNUM)
-    {
-      register_t base;
-
-      if (gdb_ptrace (PT_GETGSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't get segment register gs_base"));
-
-      regcache->raw_supply (I386_GSBASE_REGNUM, &base);
-      if (regnum != -1)
-       return;
-    }
-#endif
-
   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
     {
       struct fpreg fpregs;
 #ifdef HAVE_PT_GETXMMREGS
       char xmmregs[512];
-#endif
-
-#ifdef PT_GETXSTATE_INFO
-      if (x86bsd_xsave_len != 0)
-       {
-         void *xstateregs;
 
-         xstateregs = alloca (x86bsd_xsave_len);
-         if (gdb_ptrace (PT_GETXSTATE, 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
          && gdb_ptrace(PT_GETXMMREGS, ptid,
                        (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
@@ -255,60 +211,12 @@ i386bsd_store_inferior_registers (struct regcache *regcache, int regnum)
        return;
     }
 
-#ifdef PT_SETFSBASE
-  if (regnum == -1 || regnum == I386_FSBASE_REGNUM)
-    {
-      register_t base;
-
-      regcache->raw_collect (I386_FSBASE_REGNUM, &base);
-
-      if (gdb_ptrace (PT_SETFSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't write segment register fs_base"));
-      if (regnum != -1)
-       return;
-    }
-#endif
-#ifdef PT_SETGSBASE
-  if (regnum == -1 || regnum == I386_GSBASE_REGNUM)
-    {
-      register_t base;
-
-      regcache->raw_collect (I386_GSBASE_REGNUM, &base);
-
-      if (gdb_ptrace (PT_SETGSBASE, ptid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
-       perror_with_name (_("Couldn't write segment register gs_base"));
-      if (regnum != -1)
-       return;
-    }
-#endif
-
   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
     {
       struct fpreg fpregs;
 #ifdef HAVE_PT_GETXMMREGS
       char xmmregs[512];
-#endif
-
-#ifdef PT_GETXSTATE_INFO
-      if (x86bsd_xsave_len != 0)
-       {
-         void *xstateregs;
-
-         xstateregs = alloca (x86bsd_xsave_len);
-         if (gdb_ptrace (PT_GETXSTATE, ptid,
-                         (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
-           perror_with_name (_("Couldn't get extended state status"));
 
-         i387_collect_xsave (regcache, -1, xstateregs, 0);
-
-         if (gdb_ptrace (PT_SETXSTATE, ptid, (PTRACE_TYPE_ARG3) xstateregs,
-                         x86bsd_xsave_len) == -1)
-           perror_with_name (_("Couldn't write extended state status"));
-         return;
-       }
-#endif
-
-#ifdef HAVE_PT_GETXMMREGS
       if (have_ptrace_xmmregs != 0
          && gdb_ptrace(PT_GETXMMREGS, ptid,
                        (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
index 75fe5e78f203ac6a25907483de6c489f35e53e0b..6fb67434a2d2431d7dfca9a682241a02ddbab9b1 100644 (file)
 
 #include "fbsd-nat.h"
 #include "i386-tdep.h"
+#include "i386-fbsd-tdep.h"
+#include "i387-tdep.h"
 #include "x86-nat.h"
 #include "gdbsupport/x86-xstate.h"
 #include "x86-bsd-nat.h"
-#include "i386-bsd-nat.h"
 
 class i386_fbsd_nat_target final
-  : public i386_bsd_nat_target<fbsd_nat_target>
+  : public x86bsd_nat_target<fbsd_nat_target>
 {
 public:
-  /* Add some extra features to the common *BSD/i386 target.  */
-#ifdef PT_GETXSTATE_INFO
+  void fetch_registers (struct regcache *, int) override;
+  void store_registers (struct regcache *, int) override;
+
+#if defined(PT_GETXMMREGS) || defined(PT_GETXSTATE_INFO)
   const struct target_desc *read_description () override;
 #endif
 
@@ -52,6 +55,192 @@ public:
 
 static i386_fbsd_nat_target the_i386_fbsd_nat_target;
 
+#ifdef PT_GETXSTATE_INFO
+static size_t xsave_len;
+#endif
+
+#ifdef HAVE_PT_GETXMMREGS
+static int have_ptrace_xmmregs;
+#endif
+
+/* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
+   for all registers.  */
+
+void
+i386_fbsd_nat_target::fetch_registers (struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+#endif
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  if (fetch_register_set<struct reg> (regcache, regnum, PT_GETREGS,
+                                     &i386_fbsd_gregset))
+    {
+      if (regnum != -1)
+       return;
+    }
+
+#ifdef PT_GETFSBASE
+  if (regnum == -1 || regnum == I386_FSBASE_REGNUM)
+    {
+      register_t base;
+
+      if (ptrace (PT_GETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't get segment register fs_base"));
+
+      regcache->raw_supply (I386_FSBASE_REGNUM, &base);
+      if (regnum != -1)
+       return;
+    }
+#endif
+#ifdef PT_GETGSBASE
+  if (regnum == -1 || regnum == I386_GSBASE_REGNUM)
+    {
+      register_t base;
+
+      if (ptrace (PT_GETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't get segment register gs_base"));
+
+      regcache->raw_supply (I386_GSBASE_REGNUM, &base);
+      if (regnum != -1)
+       return;
+    }
+#endif
+
+  /* There is no i386_fxsave_supplies or i386_xsave_supplies.
+     Instead, the earlier register sets return early if the request
+     was for a specific register that was already satisified to avoid
+     fetching the FPU/XSAVE state unnecessarily.  */
+
+#ifdef PT_GETXSTATE_INFO
+  if (xsave_len != 0)
+    {
+      void *xstateregs = alloca (xsave_len);
+
+      if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
+       perror_with_name (_("Couldn't get extended state status"));
+
+      i387_supply_xsave (regcache, regnum, xstateregs);
+      return;
+    }
+#endif
+#ifdef HAVE_PT_GETXMMREGS
+  if (have_ptrace_xmmregs != 0)
+    {
+      char xmmregs[I387_SIZEOF_FXSAVE];
+
+      if (ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1)
+       perror_with_name (_("Couldn't get XMM registers"));
+
+      i387_supply_fxsave (regcache, regnum, xmmregs);
+      return;
+    }
+#endif
+
+  struct fpreg fpregs;
+
+  if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+    perror_with_name (_("Couldn't get floating point status"));
+
+  i387_supply_fsave (regcache, regnum, &fpregs);
+}
+
+/* Store register REGNUM back into the inferior.  If REGNUM is -1, do
+   this for all registers.  */
+
+void
+i386_fbsd_nat_target::store_registers (struct regcache *regcache, int regnum)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+#if defined(PT_GETFSBASE) || defined(PT_GETGSBASE)
+  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+#endif
+  pid_t pid = get_ptrace_pid (regcache->ptid ());
+
+  if (store_register_set<struct reg> (regcache, regnum, PT_GETREGS, PT_SETREGS,
+                                     &i386_fbsd_gregset))
+    {
+      if (regnum != -1)
+       return;
+    }
+
+#ifdef PT_SETFSBASE
+  if (regnum == -1 || regnum == I386_FSBASE_REGNUM)
+    {
+      register_t base;
+
+      regcache->raw_collect (I386_FSBASE_REGNUM, &base);
+
+      if (ptrace (PT_SETFSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't write segment register fs_base"));
+      if (regnum != -1)
+       return;
+    }
+#endif
+#ifdef PT_SETGSBASE
+  if (regnum == -1 || regnum == I386_GSBASE_REGNUM)
+    {
+      register_t base;
+
+      regcache->raw_collect (I386_GSBASE_REGNUM, &base);
+
+      if (ptrace (PT_SETGSBASE, pid, (PTRACE_TYPE_ARG3) &base, 0) == -1)
+       perror_with_name (_("Couldn't write segment register gs_base"));
+      if (regnum != -1)
+       return;
+    }
+#endif
+
+  /* There is no i386_fxsave_supplies or i386_xsave_supplies.
+     Instead, the earlier register sets return early if the request
+     was for a specific register that was already satisified to avoid
+     fetching the FPU/XSAVE state unnecessarily.  */
+
+#ifdef PT_GETXSTATE_INFO
+  if (xsave_len != 0)
+    {
+      void *xstateregs = alloca (xsave_len);
+
+      if (ptrace (PT_GETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, 0) == -1)
+       perror_with_name (_("Couldn't get extended state status"));
+
+      i387_collect_xsave (regcache, regnum, xstateregs, 0);
+
+      if (ptrace (PT_SETXSTATE, pid, (PTRACE_TYPE_ARG3) xstateregs, xsave_len)
+         == -1)
+       perror_with_name (_("Couldn't write extended state status"));
+      return;
+    }
+#endif
+#ifdef HAVE_PT_GETXMMREGS
+  if (have_ptrace_xmmregs != 0)
+    {
+      char xmmregs[I387_SIZEOF_FXSAVE];
+
+      if (ptrace(PT_GETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1)
+       perror_with_name (_("Couldn't get XMM registers"));
+
+      i387_collect_fxsave (regcache, regnum, xmmregs);
+
+      if (ptrace (PT_SETXMMREGS, pid, (PTRACE_TYPE_ARG3) xmmregs, 0) == -1)
+       perror_with_name (_("Couldn't write XMM registers"));
+      return;
+    }
+#endif
+
+  struct fpreg fpregs;
+
+  if (ptrace (PT_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+    perror_with_name (_("Couldn't get floating point status"));
+
+  i387_collect_fsave (regcache, regnum, &fpregs);
+
+  if (ptrace (PT_SETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+    perror_with_name (_("Couldn't write floating point status"));
+}
+
 /* Resume execution of the inferior process.  If STEP is nonzero,
    single-step it.  If SIGNAL is nonzero, give it that signal.  */
 
@@ -135,15 +324,21 @@ i386fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
 }
 \f
 
-#ifdef PT_GETXSTATE_INFO
+#if defined(PT_GETXMMREGS) || defined(PT_GETXSTATE_INFO)
 /* Implement the read_description method.  */
 
 const struct target_desc *
 i386_fbsd_nat_target::read_description ()
 {
+#ifdef PT_GETXSTATE_INFO
   static int xsave_probed;
   static uint64_t xcr0;
+#endif
+#ifdef PT_GETXMMREGS
+  static int xmm_probed;
+#endif
 
+#ifdef PT_GETXSTATE_INFO
   if (!xsave_probed)
     {
       struct ptrace_xstate_info info;
@@ -151,16 +346,32 @@ i386_fbsd_nat_target::read_description ()
       if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (),
                  (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
        {
-         x86bsd_xsave_len = info.xsave_len;
+         xsave_len = info.xsave_len;
          xcr0 = info.xsave_mask;
        }
       xsave_probed = 1;
     }
 
-  if (x86bsd_xsave_len == 0)
-    xcr0 = X86_XSTATE_SSE_MASK;
+  if (xsave_len != 0)
+    return i386_target_description (xcr0, true);
+#endif
+
+#ifdef PT_GETXMMREGS
+  if (!xmm_probed)
+    {
+      char xmmregs[I387_SIZEOF_FXSAVE];
+
+      if (ptrace (PT_GETXMMREGS, inferior_ptid.pid (),
+                 (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
+       have_ptrace_xmmregs = 1;
+      xmm_probed = 1;
+    }
+
+  if (have_ptrace_xmmregs)
+    return i386_target_description (X86_XSTATE_SSE_MASK, true);
+#endif
 
-  return i386_target_description (xcr0, true);
+  return i386_target_description (X86_XSTATE_X87_MASK, true);
 }
 #endif
 
index 583f49f84f25601df093913a9edce158832bd817..76f4c20f6575fc615e05a0ab52f344f8eb6c7366 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef I386_FBSD_TDEP_H
 #define I386_FBSD_TDEP_H
 
+#include "regset.h"
+
 /* Get XSAVE extended state xcr0 from core dump.  */
 extern uint64_t i386fbsd_core_read_xcr0 (bfd *abfd);
 
@@ -28,4 +30,6 @@ extern uint64_t i386fbsd_core_read_xcr0 (bfd *abfd);
    matches the layout on Linux.  */
 #define I386_FBSD_XSAVE_XCR0_OFFSET 464
 
+extern const struct regset i386_fbsd_gregset;
+
 #endif /* i386-fbsd-tdep.h */
index 06da979f83bb4907c4d86110657e48868f5899cf..099059a5e0bf0face550090d455537eb22c52e99 100644 (file)
 #include "inf-ptrace.h"
 \f
 
-#ifdef PT_GETXSTATE_INFO
-size_t x86bsd_xsave_len;
-#endif
-
 /* Support for debug registers.  */
 
 #ifdef HAVE_PT_GETDBREGS
index a545ee3330626d6d96c1098ae24ea5377d063b1c..8b6760e716937165fa07b9ca9b2fed15a21ed4e7 100644 (file)
@@ -22,9 +22,6 @@
 
 #include "x86-nat.h"
 
-/* Low level x86 XSAVE info.  */
-extern size_t x86bsd_xsave_len;
-
 /* A prototype *BSD/x86 target.  */
 
 #ifdef HAVE_PT_GETDBREGS