aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog76
-rw-r--r--gdb/gdbserver/Makefile.in14
-rw-r--r--gdb/gdbserver/configure.srv20
-rw-r--r--gdb/gdbserver/i387-fp.c267
-rw-r--r--gdb/gdbserver/i387-fp.h5
-rw-r--r--gdb/gdbserver/linux-arm-low.c8
-rw-r--r--gdb/gdbserver/linux-crisv32-low.c4
-rw-r--r--gdb/gdbserver/linux-low.c55
-rw-r--r--gdb/gdbserver/linux-low.h6
-rw-r--r--gdb/gdbserver/linux-m68k-low.c6
-rw-r--r--gdb/gdbserver/linux-mips-low.c6
-rw-r--r--gdb/gdbserver/linux-ppc-low.c10
-rw-r--r--gdb/gdbserver/linux-s390-low.c4
-rw-r--r--gdb/gdbserver/linux-sh-low.c4
-rw-r--r--gdb/gdbserver/linux-sparc-low.c6
-rw-r--r--gdb/gdbserver/linux-x86-low.c181
-rw-r--r--gdb/gdbserver/linux-xtensa-low.c6
-rw-r--r--gdb/gdbserver/server.c5
-rw-r--r--gdb/gdbserver/target.h7
19 files changed, 633 insertions, 57 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 1102e12..8a26b27 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -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
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 7fecced..2ec9784 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -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
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index f7c80bd..8bc9aeb 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -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.
diff --git a/gdb/gdbserver/i387-fp.c b/gdb/gdbserver/i387-fp.c
index 7ef4ba3..5461022 100644
--- a/gdb/gdbserver/i387-fp.c
+++ b/gdb/gdbserver/i387-fp.c
@@ -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;
diff --git a/gdb/gdbserver/i387-fp.h b/gdb/gdbserver/i387-fp.h
index d1e0681..ed1a322 100644
--- a/gdb/gdbserver/i387-fp.h
+++ b/gdb/gdbserver/i387-fp.h
@@ -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 */
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 54668f8..32bd7bb 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -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 = {
diff --git a/gdb/gdbserver/linux-crisv32-low.c b/gdb/gdbserver/linux-crisv32-low.c
index 6ba48b6..d426c32 100644
--- a/gdb/gdbserver/linux-crisv32-low.c
+++ b/gdb/gdbserver/linux-crisv32-low.c
@@ -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 = {
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 38af9d0..f159244 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -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
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index d7aa418..52623bf 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -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;
diff --git a/gdb/gdbserver/linux-m68k-low.c b/gdb/gdbserver/linux-m68k-low.c
index 14e3864..6c98bb1 100644
--- a/gdb/gdbserver/linux-m68k-low.c
+++ b/gdb/gdbserver/linux-m68k-low.c
@@ -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 };
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 70f6700..1c04b2e 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -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 = {
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 10a1309..000b20f 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -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 = {
diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c
index 5460f57..eb865dc 100644
--- a/gdb/gdbserver/linux-s390-low.c
+++ b/gdb/gdbserver/linux-s390-low.c
@@ -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 }
};
diff --git a/gdb/gdbserver/linux-sh-low.c b/gdb/gdbserver/linux-sh-low.c
index 9d27e7f..87a0dd2 100644
--- a/gdb/gdbserver/linux-sh-low.c
+++ b/gdb/gdbserver/linux-sh-low.c
@@ -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 = {
diff --git a/gdb/gdbserver/linux-sparc-low.c b/gdb/gdbserver/linux-sparc-low.c
index 0bb5f2f..e0bfe81 100644
--- a/gdb/gdbserver/linux-sparc-low.c
+++ b/gdb/gdbserver/linux-sparc-low.c
@@ -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 = {
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 37fe60f..3853b25 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -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
};
diff --git a/gdb/gdbserver/linux-xtensa-low.c b/gdb/gdbserver/linux-xtensa-low.c
index c5ed351..8d0e73a 100644
--- a/gdb/gdbserver/linux-xtensa-low.c
+++ b/gdb/gdbserver/linux-xtensa-low.c
@@ -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
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index c6fc005..568640e 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -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);
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index ac68652..6109b1c 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -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);