aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver/linux-x86-low.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2010-04-07 18:49:46 +0000
committerH.J. Lu <hjl.tools@gmail.com>2010-04-07 18:49:46 +0000
commit1570b33e44a894b781674d0906a733584ad780e0 (patch)
treee0c60c1fe61de76707fd85ab006f65cecc34f9ea /gdb/gdbserver/linux-x86-low.c
parentc302619d21ca83543e770ff0c699a838d9dce885 (diff)
downloadgdb-1570b33e44a894b781674d0906a733584ad780e0.zip
gdb-1570b33e44a894b781674d0906a733584ad780e0.tar.gz
gdb-1570b33e44a894b781674d0906a733584ad780e0.tar.bz2
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.
Diffstat (limited to 'gdb/gdbserver/linux-x86-low.c')
-rw-r--r--gdb/gdbserver/linux-x86-low.c181
1 files changed, 172 insertions, 9 deletions
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
};