mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
97de3545ca
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.
236 lines
6.3 KiB
C
236 lines
6.3 KiB
C
/* Native-dependent code for AMD64 BSD's.
|
||
|
||
Copyright (C) 2003-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/>. */
|
||
|
||
#include "defs.h"
|
||
#include "inferior.h"
|
||
#include "regcache.h"
|
||
#include "target.h"
|
||
|
||
/* We include <signal.h> to make sure `struct fxsave64' is defined on
|
||
NetBSD, since NetBSD's <machine/reg.h> needs it. */
|
||
#include <signal.h>
|
||
#include <sys/types.h>
|
||
#include <sys/ptrace.h>
|
||
#include <machine/reg.h>
|
||
|
||
#include "amd64-tdep.h"
|
||
#include "amd64-nat.h"
|
||
#include "amd64bsd-nat.h"
|
||
#include "inf-ptrace.h"
|
||
|
||
|
||
#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). */
|
||
|
||
static void
|
||
amd64bsd_fetch_inferior_registers (struct target_ops *ops,
|
||
struct regcache *regcache, int regnum)
|
||
{
|
||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||
|
||
if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
|
||
{
|
||
struct reg regs;
|
||
|
||
if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) ®s, 0) == -1)
|
||
perror_with_name (_("Couldn't get registers"));
|
||
|
||
amd64_supply_native_gregset (regcache, ®s, -1);
|
||
if (regnum != -1)
|
||
return;
|
||
}
|
||
|
||
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)
|
||
perror_with_name (_("Couldn't get floating point status"));
|
||
|
||
amd64_supply_fxsave (regcache, -1, &fpregs);
|
||
}
|
||
}
|
||
|
||
/* Store register REGNUM back into the inferior. If REGNUM is -1, do
|
||
this for all registers (including the floating-point registers). */
|
||
|
||
static void
|
||
amd64bsd_store_inferior_registers (struct target_ops *ops,
|
||
struct regcache *regcache, int regnum)
|
||
{
|
||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||
|
||
if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
|
||
{
|
||
struct reg regs;
|
||
|
||
if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) ®s, 0) == -1)
|
||
perror_with_name (_("Couldn't get registers"));
|
||
|
||
amd64_collect_native_gregset (regcache, ®s, regnum);
|
||
|
||
if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) ®s, 0) == -1)
|
||
perror_with_name (_("Couldn't write registers"));
|
||
|
||
if (regnum != -1)
|
||
return;
|
||
}
|
||
|
||
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)
|
||
perror_with_name (_("Couldn't get floating point status"));
|
||
|
||
amd64_collect_fxsave (regcache, regnum, &fpregs);
|
||
|
||
if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
|
||
perror_with_name (_("Couldn't write floating point status"));
|
||
}
|
||
}
|
||
|
||
/* Create a prototype *BSD/amd64 target. The client can override it
|
||
with local methods. */
|
||
|
||
struct target_ops *
|
||
amd64bsd_target (void)
|
||
{
|
||
struct target_ops *t;
|
||
|
||
t = inf_ptrace_target ();
|
||
t->to_fetch_registers = amd64bsd_fetch_inferior_registers;
|
||
t->to_store_registers = amd64bsd_store_inferior_registers;
|
||
return t;
|
||
}
|
||
|
||
|
||
/* Support for debug registers. */
|
||
|
||
#ifdef HAVE_PT_GETDBREGS
|
||
|
||
static unsigned long
|
||
amd64bsd_dr_get (ptid_t ptid, int regnum)
|
||
{
|
||
struct dbreg dbregs;
|
||
|
||
if (ptrace (PT_GETDBREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
|
||
perror_with_name (_("Couldn't read debug registers"));
|
||
|
||
return DBREG_DRX ((&dbregs), regnum);
|
||
}
|
||
|
||
static void
|
||
amd64bsd_dr_set (int regnum, unsigned long value)
|
||
{
|
||
struct dbreg dbregs;
|
||
|
||
if (ptrace (PT_GETDBREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
|
||
perror_with_name (_("Couldn't get debug registers"));
|
||
|
||
/* For some mysterious reason, some of the reserved bits in the
|
||
debug control register get set. Mask these off, otherwise the
|
||
ptrace call below will fail. */
|
||
DBREG_DRX ((&dbregs), 7) &= ~(0xffffffff0000fc00);
|
||
|
||
DBREG_DRX ((&dbregs), regnum) = value;
|
||
|
||
if (ptrace (PT_SETDBREGS, ptid_get_pid (inferior_ptid),
|
||
(PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
|
||
perror_with_name (_("Couldn't write debug registers"));
|
||
}
|
||
|
||
void
|
||
amd64bsd_dr_set_control (unsigned long control)
|
||
{
|
||
amd64bsd_dr_set (7, control);
|
||
}
|
||
|
||
void
|
||
amd64bsd_dr_set_addr (int regnum, CORE_ADDR addr)
|
||
{
|
||
gdb_assert (regnum >= 0 && regnum <= 4);
|
||
|
||
amd64bsd_dr_set (regnum, addr);
|
||
}
|
||
|
||
CORE_ADDR
|
||
amd64bsd_dr_get_addr (int regnum)
|
||
{
|
||
return amd64bsd_dr_get (inferior_ptid, regnum);
|
||
}
|
||
|
||
unsigned long
|
||
amd64bsd_dr_get_status (void)
|
||
{
|
||
return amd64bsd_dr_get (inferior_ptid, 6);
|
||
}
|
||
|
||
unsigned long
|
||
amd64bsd_dr_get_control (void)
|
||
{
|
||
return amd64bsd_dr_get (inferior_ptid, 7);
|
||
}
|
||
|
||
#endif /* PT_GETDBREGS */
|