Add x86 AVX support to gdbserver.

2010-04-07  H.J. Lu  <hongjiu.lu@intel.com>

	* Makefile.in (clean): Updated.
	(i386-avx.o): New.
	(i386-avx.c): Likewise.
	(i386-avx-linux.o): Likewise.
	(i386-avx-linux.c): Likewise.
	(amd64-avx.o): Likewise.
	(amd64-avx.c): Likewise.
	(amd64-avx-linux.o): Likewise.
	(amd64-avx-linux.c): Likewise.

	* configure.srv (srv_i386_regobj): Add i386-avx.o.
	(srv_i386_linux_regobj): Add i386-avx-linux.o.
	(srv_amd64_regobj): Add amd64-avx.o.
	(srv_amd64_linux_regobj): Add amd64-avx-linux.o.
	(srv_i386_32bit_xmlfiles): Add i386/32bit-avx.xml.
	(srv_i386_64bit_xmlfiles): Add i386/64bit-avx.xml.
	(srv_i386_xmlfiles): Add i386/i386-avx.xml.
	(srv_amd64_xmlfiles): Add i386/amd64-avx.xml.
	(srv_i386_linux_xmlfiles): Add i386/i386-avx-linux.xml.
	(srv_amd64_linux_xmlfiles): Add i386/amd64-avx-linux.xml.

	* i387-fp.c: Include "i386-xstate.h".
	(i387_xsave): New.
	(i387_cache_to_xsave): Likewise.
	(i387_xsave_to_cache): Likewise.
	(x86_xcr0): Likewise.

	* i387-fp.h (i387_cache_to_xsave): Likewise.
	(i387_xsave_to_cache): Likewise.
	(x86_xcr0): Likewise.

	* linux-arm-low.c (target_regsets): Initialize nt_type to 0.
	* linux-crisv32-low.c (target_regsets): Likewise.
	* linux-m68k-low.c (target_regsets): Likewise.
	* linux-mips-low.c (target_regsets): Likewise.
	* linux-ppc-low.c (target_regsets): Likewise.
	* linux-s390-low.c (target_regsets): Likewise.
	* linux-sh-low.c (target_regsets): Likewise.
	* linux-sparc-low.c (target_regsets): Likewise.
	* linux-xtensa-low.c (target_regsets): Likewise.

	* linux-low.c: Include <sys/uio.h>.
	(regsets_fetch_inferior_registers): Support nt_type.
	(regsets_store_inferior_registers): Likewise.
	(linux_process_qsupported): New.
	(linux_target_ops): Add linux_process_qsupported.

	* linux-low.h (regset_info): Add nt_type.
	(linux_target_ops): Add process_qsupported.

	* linux-x86-low.c: Include "i386-xstate.h", "elf/common.h"
	and <sys/uio.h>.
	(init_registers_i386_avx_linux): New.
	(init_registers_amd64_avx_linux): Likewise.
	(xmltarget_i386_linux_no_xml): Likewise.
	(xmltarget_amd64_linux_no_xml): Likewise.
	(PTRACE_GETREGSET): Likewise.
	(PTRACE_SETREGSET): Likewise.
	(x86_fill_xstateregset): Likewise.
	(x86_store_xstateregset): Likewise.
	(use_xml): Likewise.
	(x86_linux_update_xmltarget): Likewise.
	(x86_linux_process_qsupported): Likewise.
	(target_regsets): Add NT_X86_XSTATE entry and Initialize nt_type.
	(x86_arch_setup): Don't call init_registers_amd64_linux nor
	init_registers_i386_linux here.  Call
	x86_linux_update_xmltarget.
	(the_low_target): Add x86_linux_process_qsupported.

	* server.c (handle_query): Call target_process_qsupported.

	* target.h (target_ops): Add process_qsupported.
	(target_process_qsupported): New.
This commit is contained in:
H.J. Lu 2010-04-07 18:49:46 +00:00
parent c302619d21
commit 1570b33e44
19 changed files with 633 additions and 57 deletions

View File

@ -1,3 +1,79 @@
2010-04-07 H.J. Lu <hongjiu.lu@intel.com>
* Makefile.in (clean): Updated.
(i386-avx.o): New.
(i386-avx.c): Likewise.
(i386-avx-linux.o): Likewise.
(i386-avx-linux.c): Likewise.
(amd64-avx.o): Likewise.
(amd64-avx.c): Likewise.
(amd64-avx-linux.o): Likewise.
(amd64-avx-linux.c): Likewise.
* configure.srv (srv_i386_regobj): Add i386-avx.o.
(srv_i386_linux_regobj): Add i386-avx-linux.o.
(srv_amd64_regobj): Add amd64-avx.o.
(srv_amd64_linux_regobj): Add amd64-avx-linux.o.
(srv_i386_32bit_xmlfiles): Add i386/32bit-avx.xml.
(srv_i386_64bit_xmlfiles): Add i386/64bit-avx.xml.
(srv_i386_xmlfiles): Add i386/i386-avx.xml.
(srv_amd64_xmlfiles): Add i386/amd64-avx.xml.
(srv_i386_linux_xmlfiles): Add i386/i386-avx-linux.xml.
(srv_amd64_linux_xmlfiles): Add i386/amd64-avx-linux.xml.
* i387-fp.c: Include "i386-xstate.h".
(i387_xsave): New.
(i387_cache_to_xsave): Likewise.
(i387_xsave_to_cache): Likewise.
(x86_xcr0): Likewise.
* i387-fp.h (i387_cache_to_xsave): Likewise.
(i387_xsave_to_cache): Likewise.
(x86_xcr0): Likewise.
* linux-arm-low.c (target_regsets): Initialize nt_type to 0.
* linux-crisv32-low.c (target_regsets): Likewise.
* linux-m68k-low.c (target_regsets): Likewise.
* linux-mips-low.c (target_regsets): Likewise.
* linux-ppc-low.c (target_regsets): Likewise.
* linux-s390-low.c (target_regsets): Likewise.
* linux-sh-low.c (target_regsets): Likewise.
* linux-sparc-low.c (target_regsets): Likewise.
* linux-xtensa-low.c (target_regsets): Likewise.
* linux-low.c: Include <sys/uio.h>.
(regsets_fetch_inferior_registers): Support nt_type.
(regsets_store_inferior_registers): Likewise.
(linux_process_qsupported): New.
(linux_target_ops): Add linux_process_qsupported.
* linux-low.h (regset_info): Add nt_type.
(linux_target_ops): Add process_qsupported.
* linux-x86-low.c: Include "i386-xstate.h", "elf/common.h"
and <sys/uio.h>.
(init_registers_i386_avx_linux): New.
(init_registers_amd64_avx_linux): Likewise.
(xmltarget_i386_linux_no_xml): Likewise.
(xmltarget_amd64_linux_no_xml): Likewise.
(PTRACE_GETREGSET): Likewise.
(PTRACE_SETREGSET): Likewise.
(x86_fill_xstateregset): Likewise.
(x86_store_xstateregset): Likewise.
(use_xml): Likewise.
(x86_linux_update_xmltarget): Likewise.
(x86_linux_process_qsupported): Likewise.
(target_regsets): Add NT_X86_XSTATE entry and Initialize nt_type.
(x86_arch_setup): Don't call init_registers_amd64_linux nor
init_registers_i386_linux here. Call
x86_linux_update_xmltarget.
(the_low_target): Add x86_linux_process_qsupported.
* server.c (handle_query): Call target_process_qsupported.
* target.h (target_ops): Add process_qsupported.
(target_process_qsupported): New.
2010-04-03 Pedro Alves <pedro@codesourcery.com>
* inferiors.c (add_thread): Set last_status kind to

View File

@ -217,6 +217,8 @@ clean:
rm -f powerpc-isa205-vsx64l.c
rm -f s390-linux32.c s390-linux64.c s390x-linux64.c
rm -f xml-builtin.c stamp-xml
rm -f i386-avx.c i386-avx-linux.c
rm -f amd64-avx.c amd64-avx-linux.c
maintainer-clean realclean distclean: clean
rm -f nm.h tm.h xm.h config.status config.h stamp-h config.log
@ -351,6 +353,12 @@ i386.c : $(srcdir)/../regformats/i386/i386.dat $(regdat_sh)
i386-linux.o : i386-linux.c $(regdef_h)
i386-linux.c : $(srcdir)/../regformats/i386/i386-linux.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/i386/i386-linux.dat i386-linux.c
i386-avx.o : i386-avx.c $(regdef_h)
i386-avx.c : $(srcdir)/../regformats/i386/i386-avx.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/i386/i386-avx.dat i386-avx.c
i386-avx-linux.o : i386-avx-linux.c $(regdef_h)
i386-avx-linux.c : $(srcdir)/../regformats/i386/i386-avx-linux.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/i386/i386-avx-linux.dat i386-avx-linux.c
reg-ia64.o : reg-ia64.c $(regdef_h)
reg-ia64.c : $(srcdir)/../regformats/reg-ia64.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-ia64.dat reg-ia64.c
@ -438,6 +446,12 @@ amd64.c : $(srcdir)/../regformats/i386/amd64.dat $(regdat_sh)
amd64-linux.o : amd64-linux.c $(regdef_h)
amd64-linux.c : $(srcdir)/../regformats/i386/amd64-linux.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/i386/amd64-linux.dat amd64-linux.c
amd64-avx.o : amd64-avx.c $(regdef_h)
amd64-avx.c : $(srcdir)/../regformats/i386/amd64-avx.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/i386/amd64-avx.dat amd64-avx.c
amd64-avx-linux.o : amd64-avx-linux.c $(regdef_h)
amd64-avx-linux.c : $(srcdir)/../regformats/i386/amd64-avx-linux.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/i386/amd64-avx-linux.dat amd64-avx-linux.c
reg-xtensa.o : reg-xtensa.c $(regdef_h)
reg-xtensa.c : $(srcdir)/../regformats/reg-xtensa.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-xtensa.dat reg-xtensa.c

View File

@ -22,17 +22,17 @@
# Default hostio_last_error implementation
srv_hostio_err_objs="hostio-errno.o"
srv_i386_regobj=i386.o
srv_i386_linux_regobj=i386-linux.o
srv_amd64_regobj=amd64.o
srv_amd64_linux_regobj=amd64-linux.o
srv_i386_regobj="i386.o i386-avx.o"
srv_i386_linux_regobj="i386-linux.o i386-avx-linux.o"
srv_amd64_regobj="amd64.o x86-64-avx.o"
srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o"
srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml"
srv_i386_64bit_xmlfiles="i386/64bit-core.xml i386/64bit-sse.xml"
srv_i386_xmlfiles="i386/i386.xml $srv_i386_32bit_xmlfiles"
srv_amd64_xmlfiles="i386/amd64.xml $srv_i386_64bit_xmlfiles"
srv_i386_linux_xmlfiles="i386/i386-linux.xml i386/32bit-linux.xml $srv_i386_32bit_xmlfiles"
srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/64bit-linux.xml $srv_i386_64bit_xmlfiles"
srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml i386/32bit-avx.xml"
srv_i386_64bit_xmlfiles="i386/64bit-core.xml i386/64bit-sse.xml i386/64bit-avx.xml"
srv_i386_xmlfiles="i386/i386.xml i386/i386-avx.xml $srv_i386_32bit_xmlfiles"
srv_amd64_xmlfiles="i386/amd64.xml i386/amd64-avx.xml $srv_i386_64bit_xmlfiles"
srv_i386_linux_xmlfiles="i386/i386-linux.xml i386/i386-avx-linux.xml i386/32bit-linux.xml $srv_i386_32bit_xmlfiles"
srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/64bit-linux.xml $srv_i386_64bit_xmlfiles"
# Input is taken from the "${target}" variable.

View File

@ -19,6 +19,7 @@
#include "server.h"
#include "i387-fp.h"
#include "i386-xstate.h"
int num_xmm_registers = 8;
@ -72,6 +73,46 @@ struct i387_fxsave {
unsigned char xmm_space[256];
};
struct i387_xsave {
/* All these are only sixteen bits, plus padding, except for fop (which
is only eleven bits), and fooff / fioff (which are 32 bits each). */
unsigned short fctrl;
unsigned short fstat;
unsigned short ftag;
unsigned short fop;
unsigned int fioff;
unsigned short fiseg;
unsigned short pad1;
unsigned int fooff;
unsigned short foseg;
unsigned short pad12;
unsigned int mxcsr;
unsigned int mxcsr_mask;
/* Space for eight 80-bit FP values in 128-bit spaces. */
unsigned char st_space[128];
/* Space for eight 128-bit XMM values, or 16 on x86-64. */
unsigned char xmm_space[256];
unsigned char reserved1[48];
/* The extended control register 0 (the XFEATURE_ENABLED_MASK
register). */
unsigned long long xcr0;
unsigned char reserved2[40];
/* The XSTATE_BV bit vector. */
unsigned long long xstate_bv;
unsigned char reserved3[56];
/* Space for eight upper 128-bit YMM values, or 16 on x86-64. */
unsigned char ymmh_space[256];
};
void
i387_cache_to_fsave (struct regcache *regcache, void *buf)
{
@ -199,6 +240,128 @@ i387_cache_to_fxsave (struct regcache *regcache, void *buf)
fp->foseg = val;
}
void
i387_cache_to_xsave (struct regcache *regcache, void *buf)
{
struct i387_xsave *fp = (struct i387_xsave *) buf;
int i;
unsigned long val, val2;
unsigned int clear_bv;
unsigned long long xstate_bv = 0;
char raw[16];
char *p;
/* The supported bits in `xstat_bv' are 1 byte. Clear part in
vector registers if its bit in xstat_bv is zero. */
clear_bv = (~fp->xstate_bv) & x86_xcr0;
/* Clear part in x87 and vector registers if its bit in xstat_bv is
zero. */
if (clear_bv)
{
if ((clear_bv & I386_XSTATE_X87))
for (i = 0; i < 8; i++)
memset (((char *) &fp->st_space[0]) + i * 16, 0, 10);
if ((clear_bv & I386_XSTATE_SSE))
for (i = 0; i < num_xmm_registers; i++)
memset (((char *) &fp->xmm_space[0]) + i * 16, 0, 16);
if ((clear_bv & I386_XSTATE_AVX))
for (i = 0; i < num_xmm_registers; i++)
memset (((char *) &fp->ymmh_space[0]) + i * 16, 0, 16);
}
/* Check if any x87 registers are changed. */
if ((x86_xcr0 & I386_XSTATE_X87))
{
int st0_regnum = find_regno ("st0");
for (i = 0; i < 8; i++)
{
collect_register (regcache, i + st0_regnum, raw);
p = ((char *) &fp->st_space[0]) + i * 16;
if (memcmp (raw, p, 10))
{
xstate_bv |= I386_XSTATE_X87;
memcpy (p, raw, 10);
}
}
}
/* Check if any SSE registers are changed. */
if ((x86_xcr0 & I386_XSTATE_SSE))
{
int xmm0_regnum = find_regno ("xmm0");
for (i = 0; i < num_xmm_registers; i++)
{
collect_register (regcache, i + xmm0_regnum, raw);
p = ((char *) &fp->xmm_space[0]) + i * 16;
if (memcmp (raw, p, 16))
{
xstate_bv |= I386_XSTATE_SSE;
memcpy (p, raw, 16);
}
}
}
/* Check if any AVX registers are changed. */
if ((x86_xcr0 & I386_XSTATE_AVX))
{
int ymm0h_regnum = find_regno ("ymm0h");
for (i = 0; i < num_xmm_registers; i++)
{
collect_register (regcache, i + ymm0h_regnum, raw);
p = ((char *) &fp->ymmh_space[0]) + i * 16;
if (memcmp (raw, p, 16))
{
xstate_bv |= I386_XSTATE_AVX;
memcpy (p, raw, 16);
}
}
}
/* Update the corresponding bits in xstate_bv if any SSE/AVX
registers are changed. */
fp->xstate_bv |= xstate_bv;
collect_register_by_name (regcache, "fioff", &fp->fioff);
collect_register_by_name (regcache, "fooff", &fp->fooff);
collect_register_by_name (regcache, "mxcsr", &fp->mxcsr);
/* This one's 11 bits... */
collect_register_by_name (regcache, "fop", &val2);
fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
/* Some registers are 16-bit. */
collect_register_by_name (regcache, "fctrl", &val);
fp->fctrl = val;
collect_register_by_name (regcache, "fstat", &val);
fp->fstat = val;
/* Convert to the simplifed tag form stored in fxsave data. */
collect_register_by_name (regcache, "ftag", &val);
val &= 0xFFFF;
val2 = 0;
for (i = 7; i >= 0; i--)
{
int tag = (val >> (i * 2)) & 3;
if (tag != 3)
val2 |= (1 << i);
}
fp->ftag = val2;
collect_register_by_name (regcache, "fiseg", &val);
fp->fiseg = val;
collect_register_by_name (regcache, "foseg", &val);
fp->foseg = val;
}
static int
i387_ftag (struct i387_fxsave *fp, int regno)
{
@ -296,3 +459,107 @@ i387_fxsave_to_cache (struct regcache *regcache, const void *buf)
val = (fp->fop) & 0x7FF;
supply_register_by_name (regcache, "fop", &val);
}
void
i387_xsave_to_cache (struct regcache *regcache, const void *buf)
{
struct i387_xsave *fp = (struct i387_xsave *) buf;
struct i387_fxsave *fxp = (struct i387_fxsave *) buf;
int i, top;
unsigned long val;
unsigned int clear_bv;
char *p;
/* The supported bits in `xstat_bv' are 1 byte. Clear part in
vector registers if its bit in xstat_bv is zero. */
clear_bv = (~fp->xstate_bv) & x86_xcr0;
/* Check if any x87 registers are changed. */
if ((x86_xcr0 & I386_XSTATE_X87))
{
int st0_regnum = find_regno ("st0");
if ((clear_bv & I386_XSTATE_X87))
p = NULL;
else
p = (char *) buf;
for (i = 0; i < 8; i++)
{
if (p)
p = ((char *) &fp->st_space[0]) + i * 16;
supply_register (regcache, i + st0_regnum, p);
}
}
if ((x86_xcr0 & I386_XSTATE_SSE))
{
int xmm0_regnum = find_regno ("xmm0");
if ((clear_bv & I386_XSTATE_SSE))
p = NULL;
else
p = (char *) buf;
for (i = 0; i < num_xmm_registers; i++)
{
if (p)
p = ((char *) &fp->xmm_space[0]) + i * 16;
supply_register (regcache, i + xmm0_regnum, p);
}
}
if ((x86_xcr0 & I386_XSTATE_AVX))
{
int ymm0h_regnum = find_regno ("ymm0h");
if ((clear_bv & I386_XSTATE_AVX))
p = NULL;
else
p = (char *) buf;
for (i = 0; i < num_xmm_registers; i++)
{
if (p)
p = ((char *) &fp->ymmh_space[0]) + i * 16;
supply_register (regcache, i + ymm0h_regnum, p);
}
}
supply_register_by_name (regcache, "fioff", &fp->fioff);
supply_register_by_name (regcache, "fooff", &fp->fooff);
supply_register_by_name (regcache, "mxcsr", &fp->mxcsr);
/* Some registers are 16-bit. */
val = fp->fctrl & 0xFFFF;
supply_register_by_name (regcache, "fctrl", &val);
val = fp->fstat & 0xFFFF;
supply_register_by_name (regcache, "fstat", &val);
/* Generate the form of ftag data that GDB expects. */
top = (fp->fstat >> 11) & 0x7;
val = 0;
for (i = 7; i >= 0; i--)
{
int tag;
if (fp->ftag & (1 << i))
tag = i387_ftag (fxp, (i + 8 - top) % 8);
else
tag = 3;
val |= tag << (2 * i);
}
supply_register_by_name (regcache, "ftag", &val);
val = fp->fiseg & 0xFFFF;
supply_register_by_name (regcache, "fiseg", &val);
val = fp->foseg & 0xFFFF;
supply_register_by_name (regcache, "foseg", &val);
val = (fp->fop) & 0x7FF;
supply_register_by_name (regcache, "fop", &val);
}
/* Default to SSE. */
unsigned long long x86_xcr0 = I386_XSTATE_SSE_MASK;

View File

@ -26,6 +26,11 @@ void i387_fsave_to_cache (struct regcache *regcache, const void *buf);
void i387_cache_to_fxsave (struct regcache *regcache, void *buf);
void i387_fxsave_to_cache (struct regcache *regcache, const void *buf);
void i387_cache_to_xsave (struct regcache *regcache, void *buf);
void i387_xsave_to_cache (struct regcache *regcache, const void *buf);
extern unsigned long long x86_xcr0;
extern int num_xmm_registers;
#endif /* I387_FP_H */

View File

@ -354,16 +354,16 @@ arm_arch_setup (void)
}
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4,
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, 18 * 4,
GENERAL_REGS,
arm_fill_gregset, arm_store_gregset },
{ PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
{ PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 0, 16 * 8 + 6 * 4,
EXTENDED_REGS,
arm_fill_wmmxregset, arm_store_wmmxregset },
{ PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 32 * 8 + 4,
{ PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 0, 32 * 8 + 4,
EXTENDED_REGS,
arm_fill_vfpregset, arm_store_vfpregset },
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {

View File

@ -365,9 +365,9 @@ cris_store_gregset (const void *buf)
typedef unsigned long elf_gregset_t[cris_num_regs];
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
GENERAL_REGS, cris_fill_gregset, cris_store_gregset },
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {

View File

@ -39,6 +39,7 @@
#include <dirent.h>
#include <sys/stat.h>
#include <sys/vfs.h>
#include <sys/uio.h>
#ifndef ELFMAG0
/* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
then ELFMAG0 will have been defined. If it didn't get included by
@ -2977,14 +2978,15 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
struct regset_info *regset;
int saw_general_regs = 0;
int pid;
struct iovec iov;
regset = target_regsets;
pid = lwpid_of (get_thread_lwp (current_inferior));
while (regset->size >= 0)
{
void *buf;
int res;
void *buf, *data;
int nt_type, res;
if (regset->size == 0 || disabled_regsets[regset - target_regsets])
{
@ -2993,10 +2995,21 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
}
buf = xmalloc (regset->size);
nt_type = regset->nt_type;
if (nt_type)
{
iov.iov_base = buf;
iov.iov_len = regset->size;
data = (void *) &iov;
}
else
data = buf;
#ifndef __sparc__
res = ptrace (regset->get_request, pid, 0, buf);
res = ptrace (regset->get_request, pid, nt_type, data);
#else
res = ptrace (regset->get_request, pid, buf, 0);
res = ptrace (regset->get_request, pid, data, nt_type);
#endif
if (res < 0)
{
@ -3034,14 +3047,15 @@ regsets_store_inferior_registers (struct regcache *regcache)
struct regset_info *regset;
int saw_general_regs = 0;
int pid;
struct iovec iov;
regset = target_regsets;
pid = lwpid_of (get_thread_lwp (current_inferior));
while (regset->size >= 0)
{
void *buf;
int res;
void *buf, *data;
int nt_type, res;
if (regset->size == 0 || disabled_regsets[regset - target_regsets])
{
@ -3054,10 +3068,21 @@ regsets_store_inferior_registers (struct regcache *regcache)
/* First fill the buffer with the current register set contents,
in case there are any items in the kernel's regset that are
not in gdbserver's regcache. */
nt_type = regset->nt_type;
if (nt_type)
{
iov.iov_base = buf;
iov.iov_len = regset->size;
data = (void *) &iov;
}
else
data = buf;
#ifndef __sparc__
res = ptrace (regset->get_request, pid, 0, buf);
res = ptrace (regset->get_request, pid, nt_type, data);
#else
res = ptrace (regset->get_request, pid, buf, 0);
res = ptrace (regset->get_request, pid, &iov, data);
#endif
if (res == 0)
@ -3067,9 +3092,9 @@ regsets_store_inferior_registers (struct regcache *regcache)
/* Only now do we write the register set. */
#ifndef __sparc__
res = ptrace (regset->set_request, pid, 0, buf);
res = ptrace (regset->set_request, pid, nt_type, data);
#else
res = ptrace (regset->set_request, pid, buf, 0);
res = ptrace (regset->set_request, pid, data, nt_type);
#endif
}
@ -4133,6 +4158,13 @@ linux_core_of_thread (ptid_t ptid)
return core;
}
static void
linux_process_qsupported (const char *query)
{
if (the_low_target.process_qsupported != NULL)
the_low_target.process_qsupported (query);
}
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
@ -4176,7 +4208,8 @@ static struct target_ops linux_target_ops = {
#else
NULL,
#endif
linux_core_of_thread
linux_core_of_thread,
linux_process_qsupported
};
static void

View File

@ -35,6 +35,9 @@ enum regset_type {
struct regset_info
{
int get_request, set_request;
/* If NT_TYPE isn't 0, it will be passed to ptrace as the 3rd
argument and the 4th argument should be "const struct iovec *". */
int nt_type;
int size;
enum regset_type type;
regset_fill_func fill_function;
@ -111,6 +114,9 @@ struct linux_target_ops
/* Hook to call prior to resuming a thread. */
void (*prepare_to_resume) (struct lwp_info *);
/* Hook to support target specific qSupported. */
void (*process_qsupported) (const char *);
};
extern struct linux_target_ops the_low_target;

View File

@ -112,14 +112,14 @@ m68k_store_fpregset (struct regcache *regcache, const void *buf)
struct regset_info target_regsets[] = {
#ifdef HAVE_PTRACE_GETREGS
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
GENERAL_REGS,
m68k_fill_gregset, m68k_store_gregset },
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t),
FP_REGS,
m68k_fill_fpregset, m68k_store_fpregset },
#endif /* HAVE_PTRACE_GETREGS */
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, -1, -1, NULL, NULL }
};
static const unsigned char m68k_breakpoint[] = { 0x4E, 0x4F };

View File

@ -343,12 +343,12 @@ mips_store_fpregset (struct regcache *regcache, const void *buf)
struct regset_info target_regsets[] = {
#ifdef HAVE_PTRACE_GETREGS
{ PTRACE_GETREGS, PTRACE_SETREGS, 38 * 8, GENERAL_REGS,
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, 38 * 8, GENERAL_REGS,
mips_fill_gregset, mips_store_gregset },
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, 33 * 8, FP_REGS,
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, 33 * 8, FP_REGS,
mips_fill_fpregset, mips_store_fpregset },
#endif /* HAVE_PTRACE_GETREGS */
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {

View File

@ -593,14 +593,14 @@ struct regset_info target_regsets[] = {
fetch them every time, but still fall back to PTRACE_PEEKUSER for the
general registers. Some kernels support these, but not the newer
PPC_PTRACE_GETREGS. */
{ PTRACE_GETVSXREGS, PTRACE_SETVSXREGS, SIZEOF_VSXREGS, EXTENDED_REGS,
{ PTRACE_GETVSXREGS, PTRACE_SETVSXREGS, 0, SIZEOF_VSXREGS, EXTENDED_REGS,
ppc_fill_vsxregset, ppc_store_vsxregset },
{ PTRACE_GETVRREGS, PTRACE_SETVRREGS, SIZEOF_VRREGS, EXTENDED_REGS,
{ PTRACE_GETVRREGS, PTRACE_SETVRREGS, 0, SIZEOF_VRREGS, EXTENDED_REGS,
ppc_fill_vrregset, ppc_store_vrregset },
{ PTRACE_GETEVRREGS, PTRACE_SETEVRREGS, 32 * 4 + 8 + 4, EXTENDED_REGS,
{ PTRACE_GETEVRREGS, PTRACE_SETEVRREGS, 0, 32 * 4 + 8 + 4, EXTENDED_REGS,
ppc_fill_evrregset, ppc_store_evrregset },
{ 0, 0, 0, GENERAL_REGS, ppc_fill_gregset, NULL },
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, 0, GENERAL_REGS, ppc_fill_gregset, NULL },
{ 0, 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {

View File

@ -181,8 +181,8 @@ static void s390_fill_gregset (struct regcache *regcache, void *buf)
}
struct regset_info target_regsets[] = {
{ 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL },
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL },
{ 0, 0, 0, -1, -1, NULL, NULL }
};

View File

@ -104,8 +104,8 @@ static void sh_fill_gregset (struct regcache *regcache, void *buf)
}
struct regset_info target_regsets[] = {
{ 0, 0, 0, GENERAL_REGS, sh_fill_gregset, NULL },
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, 0, GENERAL_REGS, sh_fill_gregset, NULL },
{ 0, 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {

View File

@ -260,13 +260,13 @@ sparc_reinsert_addr (void)
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
GENERAL_REGS,
sparc_fill_gregset, sparc_store_gregset },
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (fpregset_t),
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (fpregset_t),
FP_REGS,
sparc_fill_fpregset, sparc_store_fpregset },
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {

View File

@ -24,6 +24,8 @@
#include "linux-low.h"
#include "i387-fp.h"
#include "i386-low.h"
#include "i386-xstate.h"
#include "elf/common.h"
#include "gdb_proc_service.h"
@ -31,10 +33,35 @@
void init_registers_i386_linux (void);
/* Defined in auto-generated file amd64-linux.c. */
void init_registers_amd64_linux (void);
/* Defined in auto-generated file i386-avx-linux.c. */
void init_registers_i386_avx_linux (void);
/* Defined in auto-generated file amd64-avx-linux.c. */
void init_registers_amd64_avx_linux (void);
/* Backward compatibility for gdb without XML support. */
static const char *xmltarget_i386_linux_no_xml = "@<target>\
<architecture>i386</architecture>\
<osabi>GNU/Linux</osabi>\
</target>";
static const char *xmltarget_amd64_linux_no_xml = "@<target>\
<architecture>i386:x86-64</architecture>\
<osabi>GNU/Linux</osabi>\
</target>";
#include <sys/reg.h>
#include <sys/procfs.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#ifndef PTRACE_GETREGSET
#define PTRACE_GETREGSET 0x4204
#endif
#ifndef PTRACE_SETREGSET
#define PTRACE_SETREGSET 0x4205
#endif
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 25
@ -252,6 +279,18 @@ x86_store_fpxregset (struct regcache *regcache, const void *buf)
#endif
static void
x86_fill_xstateregset (struct regcache *regcache, void *buf)
{
i387_cache_to_xsave (regcache, buf);
}
static void
x86_store_xstateregset (struct regcache *regcache, const void *buf)
{
i387_xsave_to_cache (regcache, buf);
}
/* ??? The non-biarch i386 case stores all the i387 regs twice.
Once in i387_.*fsave.* and once in i387_.*fxsave.*.
This is, presumably, to handle the case where PTRACE_[GS]ETFPXREGS
@ -264,21 +303,23 @@ x86_store_fpxregset (struct regcache *regcache, const void *buf)
struct regset_info target_regsets[] =
{
#ifdef HAVE_PTRACE_GETREGS
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
GENERAL_REGS,
x86_fill_gregset, x86_store_gregset },
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_X86_XSTATE, 0,
EXTENDED_REGS, x86_fill_xstateregset, x86_store_xstateregset },
# ifndef __x86_64__
# ifdef HAVE_PTRACE_GETFPXREGS
{ PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, sizeof (elf_fpxregset_t),
{ PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, 0, sizeof (elf_fpxregset_t),
EXTENDED_REGS,
x86_fill_fpxregset, x86_store_fpxregset },
# endif
# endif
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, sizeof (elf_fpregset_t),
FP_REGS,
x86_fill_fpregset, x86_store_fpregset },
#endif /* HAVE_PTRACE_GETREGS */
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, -1, -1, NULL, NULL }
};
static CORE_ADDR
@ -780,6 +821,128 @@ x86_siginfo_fixup (struct siginfo *native, void *inf, int direction)
return 0;
}
static int use_xml;
/* Update gdbserver_xmltarget. */
static void
x86_linux_update_xmltarget (void)
{
static unsigned long long xcr0;
static int have_ptrace_getregset = -1;
if (!current_inferior)
return;
#ifdef __x86_64__
if (num_xmm_registers == 8)
init_registers_i386_linux ();
else
init_registers_amd64_linux ();
#else
init_registers_i386_linux ();
#endif
if (!use_xml)
{
/* Don't use XML. */
#ifdef __x86_64__
if (num_xmm_registers == 8)
gdbserver_xmltarget = xmltarget_i386_linux_no_xml;
else
gdbserver_xmltarget = xmltarget_amd64_linux_no_xml;
#else
gdbserver_xmltarget = xmltarget_i386_linux_no_xml;
#endif
x86_xcr0 = I386_XSTATE_SSE_MASK;
return;
}
/* Check if XSAVE extended state is supported. */
if (have_ptrace_getregset == -1)
{
int pid = pid_of (get_thread_lwp (current_inferior));
unsigned long long xstateregs[I386_XSTATE_SSE_SIZE / sizeof (long long)];
struct iovec iov;
struct regset_info *regset;
iov.iov_base = xstateregs;
iov.iov_len = sizeof (xstateregs);
/* Check if PTRACE_GETREGSET works. */
if (ptrace (PTRACE_GETREGSET, pid, (unsigned int) NT_X86_XSTATE,
&iov) < 0)
{
have_ptrace_getregset = 0;
return;
}
else
have_ptrace_getregset = 1;
/* Get XCR0 from XSAVE extended state at byte 464. */
xcr0 = xstateregs[464 / sizeof (long long)];
/* Use PTRACE_GETREGSET if it is available. */
for (regset = target_regsets;
regset->fill_function != NULL; regset++)
if (regset->get_request == PTRACE_GETREGSET)
regset->size = I386_XSTATE_SIZE (xcr0);
else if (regset->type != GENERAL_REGS)
regset->size = 0;
}
if (have_ptrace_getregset)
{
/* AVX is the highest feature we support. */
if ((xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK)
{
x86_xcr0 = xcr0;
#ifdef __x86_64__
/* I386 has 8 xmm regs. */
if (num_xmm_registers == 8)
init_registers_i386_avx_linux ();
else
init_registers_amd64_avx_linux ();
#else
init_registers_i386_avx_linux ();
#endif
}
}
}
/* Process qSupported query, "xmlRegisters=". Update the buffer size for
PTRACE_GETREGSET. */
static void
x86_linux_process_qsupported (const char *query)
{
/* Return if gdb doesn't support XML. If gdb sends "xmlRegisters="
with "i386" in qSupported query, it supports x86 XML target
descriptions. */
use_xml = 0;
if (query != NULL && strncmp (query, "xmlRegisters=", 13) == 0)
{
char *copy = xstrdup (query + 13);
char *p;
for (p = strtok (copy, ","); p != NULL; p = strtok (NULL, ","))
{
if (strcmp (p, "i386") == 0)
{
use_xml = 1;
break;
}
}
free (copy);
}
x86_linux_update_xmltarget ();
}
/* Initialize gdbserver for the architecture of the inferior. */
static void
@ -800,8 +963,6 @@ x86_arch_setup (void)
}
else if (use_64bit)
{
init_registers_amd64_linux ();
/* Amd64 doesn't have HAVE_LINUX_USRREGS. */
the_low_target.num_regs = -1;
the_low_target.regmap = NULL;
@ -811,14 +972,13 @@ x86_arch_setup (void)
/* Amd64 has 16 xmm regs. */
num_xmm_registers = 16;
x86_linux_update_xmltarget ();
return;
}
#endif
/* Ok we have a 32-bit inferior. */
init_registers_i386_linux ();
the_low_target.num_regs = I386_NUM_REGS;
the_low_target.regmap = i386_regmap;
the_low_target.cannot_fetch_register = i386_cannot_fetch_register;
@ -826,6 +986,8 @@ x86_arch_setup (void)
/* I386 has 8 xmm regs. */
num_xmm_registers = 8;
x86_linux_update_xmltarget ();
}
/* This is initialized assuming an amd64 target.
@ -858,5 +1020,6 @@ struct linux_target_ops the_low_target =
x86_siginfo_fixup,
x86_linux_new_process,
x86_linux_new_thread,
x86_linux_prepare_to_resume
x86_linux_prepare_to_resume,
x86_linux_process_qsupported
};

View File

@ -131,13 +131,13 @@ xtensa_store_xtregset (struct regcache *regcache, const void *buf)
}
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
{ PTRACE_GETREGS, PTRACE_SETREGS, 0, sizeof (elf_gregset_t),
GENERAL_REGS,
xtensa_fill_gregset, xtensa_store_gregset },
{ PTRACE_GETXTREGS, PTRACE_SETXTREGS, XTENSA_ELF_XTREG_SIZE,
{ PTRACE_GETXTREGS, PTRACE_SETXTREGS, 0, XTENSA_ELF_XTREG_SIZE,
EXTENDED_REGS,
xtensa_fill_xtregset, xtensa_store_xtregset },
{ 0, 0, -1, -1, NULL, NULL }
{ 0, 0, 0, -1, -1, NULL, NULL }
};
#if XCHAL_HAVE_BE

View File

@ -1289,6 +1289,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
char *p = &own_buf[10];
/* Start processing qSupported packet. */
target_process_qsupported (NULL);
/* Process each feature being provided by GDB. The first
feature will follow a ':', and latter features will follow
';'. */
@ -1304,6 +1307,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_multi_process ())
multi_process = 1;
}
else
target_process_qsupported (p);
}
sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);

View File

@ -286,6 +286,9 @@ struct target_ops
/* Returns the core given a thread, or -1 if not known. */
int (*core_of_thread) (ptid_t);
/* Target specific qSupported support. */
void (*process_qsupported) (const char *);
};
extern struct target_ops *the_target;
@ -326,6 +329,10 @@ void set_target_ops (struct target_ops *);
(the_target->supports_multi_process ? \
(*the_target->supports_multi_process) () : 0)
#define target_process_qsupported(query) \
if (the_target->process_qsupported) \
the_target->process_qsupported (query)
/* Start non-stop mode, returns 0 on success, -1 on failure. */
int start_non_stop (int nonstop);