From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 27857 invoked by alias); 4 Mar 2010 18:08:12 -0000 Received: (qmail 27845 invoked by uid 22791); 4 Mar 2010 18:08:09 -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; Thu, 04 Mar 2010 18:08:03 +0000 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP; 04 Mar 2010 10:05:51 -0800 X-ExtLoop1: 1 Received: from gnu-6.sc.intel.com ([10.3.194.107]) by orsmga002.jf.intel.com with ESMTP; 04 Mar 2010 10:07:10 -0800 Received: by gnu-6.sc.intel.com (Postfix, from userid 500) id 9E72B81239A; Thu, 4 Mar 2010 10:07:48 -0800 (PST) Date: Thu, 04 Mar 2010 18:08:00 -0000 From: "H.J. Lu" To: GDB Subject: PATCH: 4/6: Add AVX support (amd64 changes) Message-ID: <20100304180748.GC10869@intel.com> Reply-To: "H.J. Lu" References: <20100304180219.GA10826@intel.com> <20100304180408.GA10869@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20100304180408.GA10869@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/msg00199.txt.bz2 Hi, Here are the amd64 changes to support AVX. OK to install? Thanks. H.J. --- 2010-03-04 H.J. Lu * amd64-linux-nat.c: Include "regset.h", "elf/common.h" and . (xstate_size): New. (xstate_size_n_of_int64): Likewise. (amd64_linux_fetch_inferior_registers): Support PTRACE_GETFPREGS. (amd64_linux_store_inferior_registers): Likewise. (amd64_linux_read_description): Check and enable AVX target descriptions. * amd64-linux-tdep.c: Include "regset.h", "i386-linux-tdep.h" and "features/i386/amd64-avx-linux.c". (amd64_linux_regset_sections): New. (amd64_linux_core_read_description): Check and enable AVX target description. (amd64_linux_init_abi): Set xsave_xcr0_offset. Call set_gdbarch_core_regset_sections. (_initialize_amd64_linux_tdep): Call initialize_tdesc_amd64_avx_linux. * amd64-linux-tdep.h (tdesc_amd64_avx_linux): New. (amd64_linux_regset_sections): Likewise. * amd64-tdep.c: Include "features/i386/amd64-avx.c". (amd64_register_names): Renamed to ... (amd64_sse_register_names): This. (amd64_avx_register_names): New. (amd64_xmm_names): Likewise. (amd64_supply_xstateregset): Likewise. (amd64_collect_xstateregset): Likewise. (amd64_supply_xsave): Likewise. (amd64_collect_xsave): Likewise. (AMD64_NUM_REGS): Updated. (amd64_pseudo_register_name): Support pseudo XMM registers. (amd64_regset_from_core_section): Support .reg-xstate section. (amd64_init_abi): Set num_xmm_regs, register_names and num_vector_regs. (amd64_init_abi): Call initialize_tdesc_amd64_avx. * amd64-tdep.h (amd64_supply_xsave): New. (amd64_collect_xsave): Likewise. diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c index b9d5833..4a79891 100644 --- a/gdb/amd64-linux-nat.c +++ b/gdb/amd64-linux-nat.c @@ -23,11 +23,14 @@ #include "inferior.h" #include "gdbcore.h" #include "regcache.h" +#include "regset.h" #include "linux-nat.h" #include "amd64-linux-tdep.h" #include "gdb_assert.h" #include "gdb_string.h" +#include "elf/common.h" +#include #include #include #include @@ -52,6 +55,16 @@ #include "amd64-nat.h" #include "i386-nat.h" +/* The extended state size in bytes. */ +static unsigned int xstate_size; + +/* The extended state size in unit of int64. We use array of int64 for + better alignment. */ +static unsigned int xstate_size_n_of_int64; + +/* Does the current host support PTRACE_GETREGSET? */ +static int have_ptrace_getregset = -1; + /* Mapping between the general-purpose registers in GNU/Linux x86-64 `struct user' format and GDB's register cache layout. */ @@ -183,10 +196,26 @@ amd64_linux_fetch_inferior_registers (struct target_ops *ops, { elf_fpregset_t fpregs; - if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0) - perror_with_name (_("Couldn't get floating point status")); + if (have_ptrace_getregset) + { + unsigned long long xstateregs[xstate_size_n_of_int64]; + struct iovec iov; + + iov.iov_base = xstateregs; + iov.iov_len = xstate_size; + if (ptrace (PTRACE_GETREGSET, tid, + (unsigned int) NT_X86_XSTATE, (long) &iov) < 0) + perror_with_name (_("Couldn't get extended state status")); + + amd64_supply_xsave (regcache, -1, xstateregs); + } + else + { + if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0) + perror_with_name (_("Couldn't get floating point status")); - amd64_supply_fxsave (regcache, -1, &fpregs); + amd64_supply_fxsave (regcache, -1, &fpregs); + } } } @@ -226,15 +255,33 @@ amd64_linux_store_inferior_registers (struct target_ops *ops, { elf_fpregset_t fpregs; - if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0) - perror_with_name (_("Couldn't get floating point status")); + if (have_ptrace_getregset) + { + unsigned long long xstateregs[xstate_size_n_of_int64]; + struct iovec iov; - amd64_collect_fxsave (regcache, regnum, &fpregs); + iov.iov_base = xstateregs; + iov.iov_len = xstate_size; + if (ptrace (PTRACE_GETREGSET, tid, + (unsigned int) NT_X86_XSTATE, (long) &iov) < 0) + perror_with_name (_("Couldn't get extended state status")); - if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0) - perror_with_name (_("Couldn't write floating point status")); + amd64_collect_xsave (regcache, regnum, xstateregs, 0); - return; + if (ptrace (PTRACE_SETREGSET, tid, + (unsigned int) NT_X86_XSTATE, (long) &iov) < 0) + perror_with_name (_("Couldn't write extended state status")); + } + else + { + if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0) + perror_with_name (_("Couldn't get floating point status")); + + amd64_collect_fxsave (regcache, regnum, &fpregs); + + if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0) + perror_with_name (_("Couldn't write floating point status")); + } } } @@ -688,6 +735,8 @@ amd64_linux_read_description (struct target_ops *ops) { unsigned long cs; int tid; + int is_64bit; + static unsigned long long xcr0; /* GNU/Linux LWP ID's are process ID's. */ tid = TIDGET (inferior_ptid); @@ -701,10 +750,53 @@ amd64_linux_read_description (struct target_ops *ops) if (errno != 0) perror_with_name (_("Couldn't get CS register")); - if (cs == AMD64_LINUX_USER64_CS) - return tdesc_amd64_linux; + is_64bit = cs == AMD64_LINUX_USER64_CS; + + if (have_ptrace_getregset == -1) + { + unsigned long long xstateregs[(I386_XSTATE_SSE_SIZE + / sizeof (long long))]; + struct iovec iov; + + iov.iov_base = xstateregs; + iov.iov_len = I386_XSTATE_SSE_SIZE; + + /* Check if PTRACE_GETREGSET works. */ + if (ptrace (PTRACE_GETREGSET, tid, + (unsigned int) NT_X86_XSTATE, (long) &iov) < 0) + have_ptrace_getregset = 0; + else + { + have_ptrace_getregset = 1; + + /* Get XCR0 from XSAVE extended state. */ + xcr0 = xstateregs[(I386_LINUX_XSAVE_XCR0_OFFSET + / sizeof (long long))]; + + xstate_size = I386_XSTATE_SIZE (xcr0); + xstate_size_n_of_int64 = xstate_size / sizeof (long long); + } + + i386_linux_update_xstateregset (amd64_linux_regset_sections, + xstate_size); + } + + /* Check the native XCR0 only if PTRACE_GETREGSET is available. */ + if (have_ptrace_getregset + && (xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK) + { + if (is_64bit) + return tdesc_amd64_avx_linux; + else + return tdesc_i386_avx_linux; + } else - return tdesc_i386_linux; + { + if (is_64bit) + return tdesc_amd64_linux; + else + return tdesc_i386_linux; + } } /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 4ad6dc9..51722bf 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -28,7 +28,9 @@ #include "symtab.h" #include "gdbtypes.h" #include "reggroups.h" +#include "regset.h" #include "amd64-linux-tdep.h" +#include "i386-linux-tdep.h" #include "linux-tdep.h" #include "gdb_string.h" @@ -38,6 +40,7 @@ #include "xml-syscall.h" #include "features/i386/amd64-linux.c" +#include "features/i386/amd64-avx-linux.c" /* The syscall's XML filename for i386. */ #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml" @@ -45,6 +48,15 @@ #include "record.h" #include "linux-record.h" +/* Supported register note sections. */ +struct core_regset_section amd64_linux_regset_sections[] = +{ + { ".reg", 144, "general-purpose" }, + { ".reg2", 512, "floating-point" }, + { ".reg-xstate", 0, "XSAVE extended state" }, + { NULL, 0 } +}; + /* Mapping between the general-purpose registers in `struct user' format and GDB's register cache layout. */ @@ -1250,12 +1262,17 @@ amd64_linux_core_read_description (struct gdbarch *gdbarch, bfd *abfd) { asection *section = bfd_get_section_by_name (abfd, ".reg2"); + unsigned long long xcr0; if (section == NULL) return NULL; /* Linux/x86-64. */ - return tdesc_amd64_linux; + xcr0 = i386_linux_core_read_xcr0 (gdbarch, target, abfd); + if ((xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK) + return tdesc_amd64_avx_linux; + else + return tdesc_amd64_linux; } static void @@ -1297,6 +1314,8 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->sc_reg_offset = amd64_linux_sc_reg_offset; tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset); + tdep->xsave_xcr0_offset = I386_LINUX_XSAVE_XCR0_OFFSET; + /* GNU/Linux uses SVR4-style shared libraries. */ set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); @@ -1318,6 +1337,9 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* GNU/Linux uses SVR4-style shared libraries. */ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + /* Install supported register note sections. */ + set_gdbarch_core_regset_sections (gdbarch, amd64_linux_regset_sections); + set_gdbarch_core_read_description (gdbarch, amd64_linux_core_read_description); @@ -1517,4 +1539,5 @@ _initialize_amd64_linux_tdep (void) /* Initialize the Linux target description */ initialize_tdesc_amd64_linux (); + initialize_tdesc_amd64_avx_linux (); } diff --git a/gdb/amd64-linux-tdep.h b/gdb/amd64-linux-tdep.h index 33316fb..78d9744 100644 --- a/gdb/amd64-linux-tdep.h +++ b/gdb/amd64-linux-tdep.h @@ -33,6 +33,10 @@ /* Linux target description. */ extern struct target_desc *tdesc_amd64_linux; +extern struct target_desc *tdesc_amd64_avx_linux; + +/* Supported register note sections. */ +extern struct core_regset_section amd64_linux_regset_sections[]; /* Enum that defines the syscall identifiers for amd64 linux. Used for process record/replay, these will be translated into diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 8c41a8a..1a6cd80 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -43,6 +43,7 @@ #include "i387-tdep.h" #include "features/i386/amd64.c" +#include "features/i386/amd64-avx.c" /* Note that the AMD64 architecture was previously known as x86-64. The latter is (forever) engraved into the canonical system name as @@ -53,7 +54,7 @@ /* Register information. */ -static const char *amd64_register_names[] = +static const char *amd64_sse_register_names[] = { "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp", @@ -71,8 +72,26 @@ static const char *amd64_register_names[] = "mxcsr", }; +static const char *amd64_avx_register_names[] = +{ + "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp", + + /* %r8 is indeed register number 8. */ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "rip", "eflags", "cs", "ss", "ds", "es", "fs", "gs", + + /* %st0 is register number 24. */ + "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7", + "fctrl", "fstat", "ftag", "fiseg", "fioff", "foseg", "fooff", "fop", + + /* %ymm0 is register number 40. */ + "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", + "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", + "mxcsr" +}; + /* Total number of registers. */ -#define AMD64_NUM_REGS ARRAY_SIZE (amd64_register_names) +#define AMD64_NUM_REGS ARRAY_SIZE (amd64_sse_register_names) /* The registers used to pass integer arguments during a function call. */ static int amd64_dummy_call_integer_regs[] = @@ -234,6 +253,14 @@ static const char *amd64_dword_names[] = "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; +/* Register names for XMMM pseudo-registers. */ + +static const char *amd64_xmm_names[] = +{ + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" +}; + /* Return the name of register REGNUM. */ static const char * @@ -242,6 +269,8 @@ amd64_pseudo_register_name (struct gdbarch *gdbarch, int regnum) struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); if (i386_byte_regnum_p (gdbarch, regnum)) return amd64_byte_names[regnum - tdep->al_regnum]; + else if (i386_xmm_regnum_p (gdbarch, regnum)) + return amd64_xmm_names[regnum - tdep->xmm0_regnum]; else if (i386_word_regnum_p (gdbarch, regnum)) return amd64_word_names[regnum - tdep->ax_regnum]; else if (i386_dword_regnum_p (gdbarch, regnum)) @@ -2148,6 +2177,28 @@ amd64_collect_fpregset (const struct regset *regset, amd64_collect_fxsave (regcache, regnum, fpregs); } +/* Similar to amd64_supply_fpregset, but use XSAVE extended state. */ + +static void +amd64_supply_xstateregset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *xstateregs, size_t len) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); + amd64_supply_xsave (regcache, regnum, xstateregs); +} + +/* Similar to amd64_collect_fpregset, but use XSAVE extended state. */ + +static void +amd64_collect_xstateregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *xstateregs, size_t len) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); + amd64_collect_xsave (regcache, regnum, xstateregs, 1); +} + /* Return the appropriate register set for the core section identified by SECT_NAME and SECT_SIZE. */ @@ -2166,6 +2217,16 @@ amd64_regset_from_core_section (struct gdbarch *gdbarch, return tdep->fpregset; } + if (strcmp (sect_name, ".reg-xstate") == 0) + { + if (tdep->xstateregset == NULL) + tdep->xstateregset = regset_alloc (gdbarch, + amd64_supply_xstateregset, + amd64_collect_xstateregset); + + return tdep->xstateregset; + } + return i386_regset_from_core_section (gdbarch, sect_name, sect_size); } @@ -2226,7 +2287,17 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->tdesc = tdesc; tdep->num_core_regs = AMD64_NUM_GREGS + I387_NUM_REGS; - tdep->register_names = amd64_register_names; + + if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.sse") != NULL) + { + tdep->register_names = amd64_sse_register_names; + tdep->num_xmm_regs = 0; + } + else + { + tdep->register_names = amd64_avx_register_names; + tdep->num_xmm_regs = 16; + } tdep->num_byte_regs = 16; tdep->num_word_regs = 16; @@ -2243,7 +2314,7 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* AMD64 has an FPU and 16 SSE registers. */ tdep->st0_regnum = AMD64_ST0_REGNUM; - tdep->num_xmm_regs = 16; + tdep->num_vector_regs = 16; /* This is what all the fuss is about. */ set_gdbarch_long_bit (gdbarch, 64); @@ -2321,6 +2392,7 @@ void _initialize_amd64_tdep (void) { initialize_tdesc_amd64 (); + initialize_tdesc_amd64_avx (); } @@ -2356,6 +2428,30 @@ amd64_supply_fxsave (struct regcache *regcache, int regnum, } } +/* Similar to amd64_supply_fxsave, but use XSAVE extended state. */ + +void +amd64_supply_xsave (struct regcache *regcache, int regnum, + const void *xsave) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + i387_supply_xsave (regcache, regnum, xsave); + + if (xsave && gdbarch_ptr_bit (gdbarch) == 64) + { + const gdb_byte *regs = xsave; + + if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep)) + regcache_raw_supply (regcache, I387_FISEG_REGNUM (tdep), + regs + 12); + if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep)) + regcache_raw_supply (regcache, I387_FOSEG_REGNUM (tdep), + regs + 20); + } +} + /* Fill register REGNUM (if it is a floating-point or SSE register) in *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for all registers. This function doesn't touch any of the reserved @@ -2379,3 +2475,26 @@ amd64_collect_fxsave (const struct regcache *regcache, int regnum, regcache_raw_collect (regcache, I387_FOSEG_REGNUM (tdep), regs + 20); } } + +/* Similar to amd64_collect_fxsave, but but use XSAVE extended state. */ + +void +amd64_collect_xsave (const struct regcache *regcache, int regnum, + void *xsave, int gcore) +{ + struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + gdb_byte *regs = xsave; + + i387_collect_xsave (regcache, regnum, xsave, gcore); + + if (gdbarch_ptr_bit (gdbarch) == 64) + { + if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep)) + regcache_raw_collect (regcache, I387_FISEG_REGNUM (tdep), + regs + 12); + if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep)) + regcache_raw_collect (regcache, I387_FOSEG_REGNUM (tdep), + regs + 20); + } +} diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h index 363479c..4dccb4f 100644 --- a/gdb/amd64-tdep.h +++ b/gdb/amd64-tdep.h @@ -91,6 +91,10 @@ extern struct type *amd64_register_type (struct gdbarch *gdbarch, int regnum); extern void amd64_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave); +/* Similar to amd64_supply_fxsave, but use XSAVE extended state. */ +extern void amd64_supply_xsave (struct regcache *regcache, int regnum, + const void *xsave); + /* Fill register REGNUM (if it is a floating-point or SSE register) in *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for all registers. This function doesn't touch any of the reserved @@ -99,6 +103,10 @@ extern void amd64_supply_fxsave (struct regcache *regcache, int regnum, extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave); +/* Similar to amd64_collect_fxsave, but but use XSAVE extended state. */ +extern void amd64_collect_xsave (const struct regcache *regcache, + int regnum, void *xsave, int gcore); + void amd64_classify (struct type *type, enum amd64_reg_class class[2]);