diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2010-04-07 18:49:46 +0000 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2010-04-07 18:49:46 +0000 |
commit | 1570b33e44a894b781674d0906a733584ad780e0 (patch) | |
tree | e0c60c1fe61de76707fd85ab006f65cecc34f9ea /gdb/gdbserver/linux-x86-low.c | |
parent | c302619d21ca83543e770ff0c699a838d9dce885 (diff) | |
download | gdb-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.c | 181 |
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 }; |