From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9381 invoked by alias); 6 Mar 2010 22:23:05 -0000 Received: (qmail 9353 invoked by uid 22791); 6 Mar 2010 22:23:00 -0000 X-SWARE-Spam-Status: No, hits=-0.7 required=5.0 tests=AWL,BAYES_00,NO_DNS_FOR_FROM X-Spam-Check-By: sourceware.org Received: from mga09.intel.com (HELO mga09.intel.com) (134.134.136.24) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 06 Mar 2010 22:22:53 +0000 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 06 Mar 2010 14:20:48 -0800 X-ExtLoop1: 1 Received: from gnu-6.sc.intel.com ([10.3.194.107]) by orsmga001.jf.intel.com with ESMTP; 06 Mar 2010 14:22:31 -0800 Received: by gnu-6.sc.intel.com (Postfix, from userid 500) id E7E4F81239A; Sat, 6 Mar 2010 14:22:50 -0800 (PST) Date: Sat, 06 Mar 2010 22:23:00 -0000 From: "H.J. Lu" To: GDB Subject: PATCH: 6/6 [2nd try]: Add AVX support (gdbserver changes) Message-ID: <20100306222250.GG21133@intel.com> Reply-To: "H.J. Lu" References: <20100304180219.GA10826@intel.com> <20100304180408.GA10869@intel.com> <20100304180748.GC10869@intel.com> <20100304180901.GD10869@intel.com> <20100304181003.GE10869@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20100304181003.GE10869@intel.com> User-Agent: Mutt/1.5.20 (2009-08-17) Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-03/txt/msg00267.txt.bz2 Hi, Here are gdbserver changes to support AVX. OK to install? Thanks. H.J. ---- 2010-03-06 H.J. Lu * 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 . (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 . (init_registers_i386_avx_linux): New. (init_registers_amd64_avx_linux): Likewise. (PTRACE_GETREGSET): Likewise. (PTRACE_SETREGSET): Likewise. (x86_fill_xstateregset): Likewise. (x86_store_xstateregset): Likewise. (x86_linux_process_qsupported): Likewise. (target_regsets): Add NT_X86_XSTATE entry and Initialize nt_type. (the_low_target): Add x86_linux_process_qsupported. * server.c (use_xml): New. (get_features_xml): Don't use XML file if use_xml is 0. (handle_query): Call target_process_qsupported. * server.h (use_xml): New. * target.h (target_ops): Add process_qsupported. (target_process_qsupported): New. 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 e5818cd..a2f4323 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..3e60882 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 & bit_I386_XSTATE_X87)) + for (i = 0; i < 8; i++) + memset (((char *) &fp->st_space[0]) + i * 16, 0, 10); + + if ((clear_bv & bit_I386_XSTATE_SSE)) + for (i = 0; i < num_xmm_registers; i++) + memset (((char *) &fp->xmm_space[0]) + i * 16, 0, 16); + + if ((clear_bv & bit_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 & bit_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 |= bit_I386_XSTATE_X87; + memcpy (p, raw, 10); + } + } + } + + /* Check if any SSE registers are changed. */ + if ((x86_xcr0 & bit_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 |= bit_I386_XSTATE_SSE; + memcpy (p, raw, 16); + } + } + } + + /* Check if any AVX registers are changed. */ + if ((x86_xcr0 & bit_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 |= bit_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 & bit_I386_XSTATE_X87)) + { + int st0_regnum = find_regno ("st0"); + + if ((clear_bv & bit_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 & bit_I386_XSTATE_SSE)) + { + int xmm0_regnum = find_regno ("xmm0"); + + if ((clear_bv & bit_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 & bit_I386_XSTATE_AVX)) + { + int ymm0h_regnum = find_regno ("ymm0h"); + + if ((clear_bv & bit_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 6499ca7..4edb152 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -39,6 +39,7 @@ #include #include #include +#include #ifndef ELFMAG0 /* Don't include here. If it got included by gdb_proc_service.h then ELFMAG0 will have been defined. If it didn't get included by @@ -2281,14 +2282,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]) { @@ -2297,10 +2299,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) { @@ -2338,14 +2351,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]) { @@ -2358,10 +2372,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) @@ -2371,9 +2396,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 } @@ -3434,6 +3459,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, @@ -3477,7 +3509,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 82ad00c..57e7adb 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..0dab604 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, 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 496baa2..b9981ec 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,24 @@ 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); #include #include #include +#include + +#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 +268,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 +292,28 @@ 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, +# ifdef __x86_64__ + FP_REGS, +# else + EXTENDED_REGS, +# endif + 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 @@ -772,6 +807,65 @@ x86_siginfo_fixup (struct siginfo *native, void *inf, int direction) return 0; } +/* Process qSupported query, "x86=xml". Update the buffer size for + PTRACE_GETREGSET. */ + +static void +x86_linux_process_qsupported (const char *query) +{ + int pid; + unsigned long long xstateregs[I386_XSTATE_SSE_SIZE / sizeof (long long)]; + struct iovec iov; + + /* Return if gdb doesn't support XML. */ + if (query == NULL || strcmp (query, "x86=xml") != 0) + { + use_xml = 0; + return; + } + + /* Check if XSAVE extended state is supported. */ + pid = pid_of (get_thread_lwp (current_inferior)); + + iov.iov_base = xstateregs; + iov.iov_len = I386_XSTATE_SSE_SIZE; + + /* Check if PTRACE_GETREGSET works. */ + if (ptrace (PTRACE_GETREGSET, pid, + (unsigned int) NT_X86_XSTATE, (long) &iov) == 0) + { + struct regset_info *regset; + unsigned long long xcr0; + + /* 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; + + /* 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 + } + } +}; + /* Initialize gdbserver for the architecture of the inferior. */ static void @@ -850,5 +944,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 a03f877..6e46a7a 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -32,6 +32,13 @@ #include #endif +int use_xml = +#ifdef USE_XML + 1; +#else + 0; +#endif + ptid_t cont_thread; ptid_t general_thread; ptid_t step_thread; @@ -474,20 +481,19 @@ get_features_xml (const char *annex) annex = gdbserver_xmltarget; } -#ifdef USE_XML - { - extern const char *const xml_builtin[][2]; - int i; + if (use_xml) + { + extern const char *const xml_builtin[][2]; + int i; - /* Look for the annex. */ - for (i = 0; xml_builtin[i][0] != NULL; i++) - if (strcmp (annex, xml_builtin[i][0]) == 0) - break; + /* Look for the annex. */ + for (i = 0; xml_builtin[i][0] != NULL; i++) + if (strcmp (annex, xml_builtin[i][0]) == 0) + break; - if (xml_builtin[i][0] != NULL) - return xml_builtin[i][1]; - } -#endif + if (xml_builtin[i][0] != NULL) + return xml_builtin[i][1]; + } return NULL; } @@ -1236,6 +1242,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 ';'. */ @@ -1251,6 +1260,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (target_supports_multi_process ()) multi_process = 1; } + else if (strncmp (p, "x86:xstate=", 11) == 0) + target_process_qsupported (p); } sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1); diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index f46ee60..a9cd024 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -22,6 +22,8 @@ #include "config.h" +extern int use_xml; + #ifdef __MINGW32CE__ #include "wincecompat.h" #endif 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);