aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2022-01-28 11:14:37 -0800
committerJohn Baldwin <jhb@FreeBSD.org>2022-01-28 11:14:37 -0800
commit00d7af046f12f18759b5b2c909d0b4527ac1857e (patch)
treed33e822e40937118700c31faf3a40c527664c7e0 /gdb
parentb95a31ed5d2b34f1a4072d701f5cd51075e61c01 (diff)
downloadgdb-00d7af046f12f18759b5b2c909d0b4527ac1857e.zip
gdb-00d7af046f12f18759b5b2c909d0b4527ac1857e.tar.gz
gdb-00d7af046f12f18759b5b2c909d0b4527ac1857e.tar.bz2
FreeBSD x86 nat: Use register maps for GP register sets.
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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/amd64-bsd-nat.c96
-rw-r--r--gdb/amd64-fbsd-nat.c260
-rw-r--r--gdb/amd64-fbsd-tdep.c1
-rw-r--r--gdb/amd64-fbsd-tdep.h27
-rw-r--r--gdb/configure.nat4
-rw-r--r--gdb/i386-bsd-nat.c92
-rw-r--r--gdb/i386-fbsd-nat.c229
-rw-r--r--gdb/i386-fbsd-tdep.h4
-rw-r--r--gdb/x86-bsd-nat.c4
-rw-r--r--gdb/x86-bsd-nat.h3
10 files changed, 457 insertions, 263 deletions
diff --git a/gdb/amd64-bsd-nat.c b/gdb/amd64-bsd-nat.c
index 52730ba..77dc4c9 100644
--- a/gdb/amd64-bsd-nat.c
+++ b/gdb/amd64-bsd-nat.c
@@ -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"));
diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c
index f9bd45d..98a1af0 100644
--- a/gdb/amd64-fbsd-nat.c
+++ b/gdb/amd64-fbsd-nat.c
@@ -31,17 +31,19 @@
#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"
-
+#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 }
};
-
-/* 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 */
-};
-
+ 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. */
diff --git a/gdb/amd64-fbsd-tdep.c b/gdb/amd64-fbsd-tdep.c
index fa36377..f87c976 100644
--- a/gdb/amd64-fbsd-tdep.c
+++ b/gdb/amd64-fbsd-tdep.c
@@ -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
index 0000000..0a18dbc
--- /dev/null
+++ b/gdb/amd64-fbsd-tdep.h
@@ -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 */
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 6fc3978..20ce805 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -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"
;;
diff --git a/gdb/i386-bsd-nat.c b/gdb/i386-bsd-nat.c
index c112b02..bd9655c 100644
--- a/gdb/i386-bsd-nat.c
+++ b/gdb/i386-bsd-nat.c
@@ -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)
diff --git a/gdb/i386-fbsd-nat.c b/gdb/i386-fbsd-nat.c
index 75fe5e7..6fb6743 100644
--- a/gdb/i386-fbsd-nat.c
+++ b/gdb/i386-fbsd-nat.c
@@ -29,17 +29,20 @@
#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)
}
-#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
diff --git a/gdb/i386-fbsd-tdep.h b/gdb/i386-fbsd-tdep.h
index 583f49f..76f4c20f 100644
--- a/gdb/i386-fbsd-tdep.h
+++ b/gdb/i386-fbsd-tdep.h
@@ -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 */
diff --git a/gdb/x86-bsd-nat.c b/gdb/x86-bsd-nat.c
index 06da979..099059a 100644
--- a/gdb/x86-bsd-nat.c
+++ b/gdb/x86-bsd-nat.c
@@ -33,10 +33,6 @@
#include "inf-ptrace.h"
-#ifdef PT_GETXSTATE_INFO
-size_t x86bsd_xsave_len;
-#endif
-
/* Support for debug registers. */
#ifdef HAVE_PT_GETDBREGS
diff --git a/gdb/x86-bsd-nat.h b/gdb/x86-bsd-nat.h
index a545ee3..8b6760e 100644
--- a/gdb/x86-bsd-nat.h
+++ b/gdb/x86-bsd-nat.h
@@ -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