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.
This commit is contained in:
John Baldwin
2022-01-28 11:14:37 -08:00
parent b95a31ed5d
commit 00d7af046f
10 changed files with 458 additions and 264 deletions

View File

@@ -59,9 +59,6 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
{ {
struct gdbarch *gdbarch = regcache->arch (); struct gdbarch *gdbarch = regcache->arch ();
ptid_t ptid = regcache->ptid (); 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)) if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
{ {
@@ -75,50 +72,9 @@ amd64bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
return; 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)) if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
{ {
struct fpreg fpregs; 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) if (gdb_ptrace (PT_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
perror_with_name (_("Couldn't get floating point status")); 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 (); struct gdbarch *gdbarch = regcache->arch ();
ptid_t ptid = regcache->ptid (); 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)) if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
{ {
@@ -155,58 +108,9 @@ amd64bsd_store_inferior_registers (struct regcache *regcache, int regnum)
return; 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)) if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
{ {
struct fpreg fpregs; 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) if (gdb_ptrace (PT_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
perror_with_name (_("Couldn't get floating point status")); perror_with_name (_("Couldn't get floating point status"));

View File

@@ -31,17 +31,19 @@
#include "fbsd-nat.h" #include "fbsd-nat.h"
#include "amd64-tdep.h" #include "amd64-tdep.h"
#include "amd64-fbsd-tdep.h"
#include "amd64-nat.h" #include "amd64-nat.h"
#include "amd64-bsd-nat.h"
#include "x86-nat.h" #include "x86-nat.h"
#include "gdbsupport/x86-xstate.h" #include "gdbsupport/x86-xstate.h"
#include "x86-bsd-nat.h"
class amd64_fbsd_nat_target final class amd64_fbsd_nat_target final
: public amd64_bsd_nat_target<fbsd_nat_target> : public x86bsd_nat_target<fbsd_nat_target>
{ {
public: 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; const struct target_desc *read_description () override;
#if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO) #if defined(HAVE_PT_GETDBREGS) && defined(USE_SIGTRAP_SIGINFO)
@@ -51,61 +53,208 @@ public:
static amd64_fbsd_nat_target the_amd64_fbsd_nat_target; static amd64_fbsd_nat_target the_amd64_fbsd_nat_target;
/* Offset in `struct reg' where MEMBER is stored. */ #ifdef PT_GETXSTATE_INFO
#define REG_OFFSET(member) offsetof (struct reg, member) static size_t xsave_len;
#endif
/* At amd64fbsd64_r_reg_offset[REGNUM] you'll find the offset in /* This is a layout of the amd64 'struct reg' but with i386
`struct reg' location where the GDB register REGNUM is stored. registers. */
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), { 8, REGCACHE_MAP_SKIP, 8 },
REG_OFFSET (r_rbx), { 1, I386_EDI_REGNUM, 8 },
REG_OFFSET (r_rcx), { 1, I386_ESI_REGNUM, 8 },
REG_OFFSET (r_rdx), { 1, I386_EBP_REGNUM, 8 },
REG_OFFSET (r_rsi), { 1, I386_EBX_REGNUM, 8 },
REG_OFFSET (r_rdi), { 1, I386_EDX_REGNUM, 8 },
REG_OFFSET (r_rbp), { 1, I386_ECX_REGNUM, 8 },
REG_OFFSET (r_rsp), { 1, I386_EAX_REGNUM, 8 },
REG_OFFSET (r_r8), { 1, REGCACHE_MAP_SKIP, 4 }, /* trapno */
REG_OFFSET (r_r9), { 1, I386_FS_REGNUM, 2 },
REG_OFFSET (r_r10), { 1, I386_GS_REGNUM, 2 },
REG_OFFSET (r_r11), { 1, REGCACHE_MAP_SKIP, 4 }, /* err */
REG_OFFSET (r_r12), { 1, I386_ES_REGNUM, 2 },
REG_OFFSET (r_r13), { 1, I386_DS_REGNUM, 2 },
REG_OFFSET (r_r14), { 1, I386_EIP_REGNUM, 8 },
REG_OFFSET (r_r15), { 1, I386_CS_REGNUM, 8 },
REG_OFFSET (r_rip), { 1, I386_EFLAGS_REGNUM, 8 },
REG_OFFSET (r_rflags), { 1, I386_ESP_REGNUM, 0 },
REG_OFFSET (r_cs), { 1, I386_SS_REGNUM, 8 },
REG_OFFSET (r_ss), { 0 }
-1,
-1,
-1,
-1
}; };
/* Mapping between the general-purpose registers in FreeBSD/amd64 static const struct regset amd64_fbsd32_gregset =
`struct reg' format and GDB's register cache layout for
FreeBSD/i386.
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. */
/* From <machine/reg.h>. */
static int amd64fbsd32_r_reg_offset[I386_NUM_GREGS] =
{ {
14 * 8, 13 * 8, /* %eax, %ecx */ amd64_fbsd32_gregmap, regcache_supply_regset, regcache_collect_regset
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 */
}; };
/* Return the regset to use for 'struct reg' for the GDBARCH. */
static const struct regset *
find_gregset (struct gdbarch *gdbarch)
{
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. */ /* 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 (), if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (),
(PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0) (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
{ {
x86bsd_xsave_len = info.xsave_len; xsave_len = info.xsave_len;
xcr0 = info.xsave_mask; xcr0 = info.xsave_mask;
} }
xsave_probed = 1; xsave_probed = 1;
} }
if (x86bsd_xsave_len != 0) if (xsave_len != 0)
{ {
if (is64) if (is64)
return amd64_target_description (xcr0, true); return amd64_target_description (xcr0, true);
@@ -213,9 +362,6 @@ void _initialize_amd64fbsd_nat ();
void void
_initialize_amd64fbsd_nat () _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); add_inf_child_target (&the_amd64_fbsd_nat_target);
/* Support debugging kernel virtual memory images. */ /* Support debugging kernel virtual memory images. */

View File

@@ -27,6 +27,7 @@
#include "gdbsupport/x86-xstate.h" #include "gdbsupport/x86-xstate.h"
#include "amd64-tdep.h" #include "amd64-tdep.h"
#include "amd64-fbsd-tdep.h"
#include "fbsd-tdep.h" #include "fbsd-tdep.h"
#include "solib-svr4.h" #include "solib-svr4.h"
#include "inferior.h" #include "inferior.h"

27
gdb/amd64-fbsd-tdep.h Normal file
View File

@@ -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 */

View File

@@ -165,7 +165,7 @@ case ${gdb_host} in
i386) i386)
# Host: FreeBSD/i386 # Host: FreeBSD/i386
NATDEPFILES="${NATDEPFILES} x86-nat.o nat/x86-dregs.o \ 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) mips)
# Host: FreeBSD/mips # Host: FreeBSD/mips
@@ -192,7 +192,7 @@ case ${gdb_host} in
case ${gdb_host_cpu} in case ${gdb_host_cpu} in
i386) i386)
# Host: FreeBSD/amd64 # 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 \ amd64-fbsd-nat.o bsd-kvm.o x86-nat.o nat/x86-dregs.o \
x86-bsd-nat.o" x86-bsd-nat.o"
;; ;;

View File

@@ -159,56 +159,12 @@ i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
return; 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) if (regnum == -1 || regnum >= I386_ST0_REGNUM)
{ {
struct fpreg fpregs; struct fpreg fpregs;
#ifdef HAVE_PT_GETXMMREGS #ifdef HAVE_PT_GETXMMREGS
char xmmregs[512]; 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 if (have_ptrace_xmmregs != 0
&& gdb_ptrace(PT_GETXMMREGS, ptid, && gdb_ptrace(PT_GETXMMREGS, ptid,
(PTRACE_TYPE_ARG3) xmmregs, 0) == 0) (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
@@ -255,60 +211,12 @@ i386bsd_store_inferior_registers (struct regcache *regcache, int regnum)
return; 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) if (regnum == -1 || regnum >= I386_ST0_REGNUM)
{ {
struct fpreg fpregs; struct fpreg fpregs;
#ifdef HAVE_PT_GETXMMREGS #ifdef HAVE_PT_GETXMMREGS
char xmmregs[512]; 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 if (have_ptrace_xmmregs != 0
&& gdb_ptrace(PT_GETXMMREGS, ptid, && gdb_ptrace(PT_GETXMMREGS, ptid,
(PTRACE_TYPE_ARG3) xmmregs, 0) == 0) (PTRACE_TYPE_ARG3) xmmregs, 0) == 0)

View File

@@ -29,17 +29,20 @@
#include "fbsd-nat.h" #include "fbsd-nat.h"
#include "i386-tdep.h" #include "i386-tdep.h"
#include "i386-fbsd-tdep.h"
#include "i387-tdep.h"
#include "x86-nat.h" #include "x86-nat.h"
#include "gdbsupport/x86-xstate.h" #include "gdbsupport/x86-xstate.h"
#include "x86-bsd-nat.h" #include "x86-bsd-nat.h"
#include "i386-bsd-nat.h"
class i386_fbsd_nat_target final class i386_fbsd_nat_target final
: public i386_bsd_nat_target<fbsd_nat_target> : public x86bsd_nat_target<fbsd_nat_target>
{ {
public: public:
/* Add some extra features to the common *BSD/i386 target. */ void fetch_registers (struct regcache *, int) override;
#ifdef PT_GETXSTATE_INFO void store_registers (struct regcache *, int) override;
#if defined(PT_GETXMMREGS) || defined(PT_GETXSTATE_INFO)
const struct target_desc *read_description () override; const struct target_desc *read_description () override;
#endif #endif
@@ -52,6 +55,192 @@ public:
static i386_fbsd_nat_target the_i386_fbsd_nat_target; 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, /* Resume execution of the inferior process. If STEP is nonzero,
single-step it. If SIGNAL is nonzero, give it that signal. */ 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. */ /* Implement the read_description method. */
const struct target_desc * const struct target_desc *
i386_fbsd_nat_target::read_description () i386_fbsd_nat_target::read_description ()
{ {
#ifdef PT_GETXSTATE_INFO
static int xsave_probed; static int xsave_probed;
static uint64_t xcr0; static uint64_t xcr0;
#endif
#ifdef PT_GETXMMREGS
static int xmm_probed;
#endif
#ifdef PT_GETXSTATE_INFO
if (!xsave_probed) if (!xsave_probed)
{ {
struct ptrace_xstate_info info; struct ptrace_xstate_info info;
@@ -151,16 +346,32 @@ i386_fbsd_nat_target::read_description ()
if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (), if (ptrace (PT_GETXSTATE_INFO, inferior_ptid.pid (),
(PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0) (PTRACE_TYPE_ARG3) &info, sizeof (info)) == 0)
{ {
x86bsd_xsave_len = info.xsave_len; xsave_len = info.xsave_len;
xcr0 = info.xsave_mask; xcr0 = info.xsave_mask;
} }
xsave_probed = 1; xsave_probed = 1;
} }
if (x86bsd_xsave_len == 0) if (xsave_len != 0)
xcr0 = X86_XSTATE_SSE_MASK;
return i386_target_description (xcr0, true); 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 (X86_XSTATE_X87_MASK, true);
} }
#endif #endif

View File

@@ -20,6 +20,8 @@
#ifndef I386_FBSD_TDEP_H #ifndef I386_FBSD_TDEP_H
#define I386_FBSD_TDEP_H #define I386_FBSD_TDEP_H
#include "regset.h"
/* Get XSAVE extended state xcr0 from core dump. */ /* Get XSAVE extended state xcr0 from core dump. */
extern uint64_t i386fbsd_core_read_xcr0 (bfd *abfd); 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. */ matches the layout on Linux. */
#define I386_FBSD_XSAVE_XCR0_OFFSET 464 #define I386_FBSD_XSAVE_XCR0_OFFSET 464
extern const struct regset i386_fbsd_gregset;
#endif /* i386-fbsd-tdep.h */ #endif /* i386-fbsd-tdep.h */

View File

@@ -33,10 +33,6 @@
#include "inf-ptrace.h" #include "inf-ptrace.h"
#ifdef PT_GETXSTATE_INFO
size_t x86bsd_xsave_len;
#endif
/* Support for debug registers. */ /* Support for debug registers. */
#ifdef HAVE_PT_GETDBREGS #ifdef HAVE_PT_GETDBREGS

View File

@@ -22,9 +22,6 @@
#include "x86-nat.h" #include "x86-nat.h"
/* Low level x86 XSAVE info. */
extern size_t x86bsd_xsave_len;
/* A prototype *BSD/x86 target. */ /* A prototype *BSD/x86 target. */
#ifdef HAVE_PT_GETDBREGS #ifdef HAVE_PT_GETDBREGS