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

@ -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
};