diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2010-04-07 18:43:45 +0000 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2010-04-07 18:43:45 +0000 |
commit | c131fcee79bd9082762a1699a657949771fa245f (patch) | |
tree | 3b3f41a8026f682bd2c2f04477fd8f66ce2b6545 /gdb/i386-linux-nat.c | |
parent | 98adf0f383f6c4087ff347b207e4aad8a139994b (diff) | |
download | gdb-c131fcee79bd9082762a1699a657949771fa245f.zip gdb-c131fcee79bd9082762a1699a657949771fa245f.tar.gz gdb-c131fcee79bd9082762a1699a657949771fa245f.tar.bz2 |
Support i386 AVX.
2010-04-07 H.J. Lu <hongjiu.lu@intel.com>
* i386-linux-nat.c: Include "regset.h", "elf/common.h",
<sys/uio.h> and "i386-xstate.h".
(PTRACE_GETREGSET): New.
(PTRACE_SETREGSET): Likewise.
(fetch_xstateregs): Likewise.
(store_xstateregs): Likewise.
(GETXSTATEREGS_SUPPLIES): Likewise.
(regmap): Include 8 upper YMM registers.
(i386_linux_fetch_inferior_registers): Support XSAVE extended
state.
(i386_linux_store_inferior_registers): Likewise.
(i386_linux_read_description): Check and enable AVX target
descriptions.
* i386-linux-tdep.c: Include "regset.h", "i387-tdep.h",
"i386-xstate.h" and "features/i386/i386-avx-linux.c".
(i386_linux_regset_sections): Add ".reg-xstate".
(i386_linux_gregset_reg_offset): Include 8 upper YMM registers.
(i386_linux_core_read_xcr0): New.
(i386_linux_core_read_description): Check and enable AVX target
description.
(i386_linux_init_abi): Set xsave_xcr0_offset.
(_initialize_i386_linux_tdep): Call
initialize_tdesc_i386_avx_linux.
* i386-linux-tdep.h (I386_LINUX_ORIG_EAX_REGNUM): Replace
I386_SSE_NUM_REGS with I386_AVX_NUM_REGS.
(i386_linux_core_read_xcr0): New.
(tdesc_i386_avx_linux): Likewise.
(I386_LINUX_XSAVE_XCR0_OFFSET): Likewise.
* i386-tdep.c: Include "i386-xstate.h" and
"features/i386/i386-avx.c".
(i386_ymm_names): New.
(i386_ymmh_names): Likewise.
(i386_ymmh_regnum_p): Likewise.
(i386_ymm_regnum_p): Likewise.
(i386_xmm_regnum_p): Likewise.
(i386_register_name): Likewise.
(i386_ymm_type): Likewise.
(i386_supply_xstateregset): Likewise.
(i386_collect_xstateregset): Likewise.
(i386_sse_regnum_p): Removed.
(i386_pseudo_register_name): Support pseudo YMM registers.
(i386_pseudo_register_type): Likewise.
(i386_pseudo_register_read): Likewise.
(i386_pseudo_register_write): Likewise.
(i386_dbx_reg_to_regnum): Return %ymmN register number for
%xmmN if AVX is available.
(i386_regset_from_core_section): Support .reg-xstate section.
(i386_register_reggroup_p): Supper upper YMM and YMM registers.
(i386_process_record): Replace i386_sse_regnum_p with
i386_xmm_regnum_p.
(i386_validate_tdesc_p): Support org.gnu.gdb.i386.avx feature.
Set ymmh_register_names, num_ymm_regs, ymm0h_regnum and xcr0.
(i386_gdbarch_init): Set xstateregset. Set xsave_xcr0_offset.
Call set_gdbarch_register_name. Replace I386_SSE_NUM_REGS with
I386_AVX_NUM_REGS. Set ymmh_register_names, ymm0h_regnum and
num_ymm_regs. Add num_ymm_regs to set_gdbarch_num_pseudo_regs.
Set ymm0_regnum.
(_initialize_i386_tdep): Call initialize_tdesc_i386_avx.
* i386-tdep.h (gdbarch_tdep): Add xstateregset, ymm0_regnum,
xcr0, xsave_xcr0_offset, ymm0h_regnum, ymmh_register_names and
i386_ymm_type.
(i386_regnum): Add I386_YMM0H_REGNUM, and I386_YMM7H_REGNUM.
(I386_AVX_NUM_REGS): New.
(i386_xmm_regnum_p): Likewise.
(i386_ymm_regnum_p): Likewise.
(i386_ymmh_regnum_p): Likewise.
* common/i386-xstate.h: New.
Diffstat (limited to 'gdb/i386-linux-nat.c')
-rw-r--r-- | gdb/i386-linux-nat.c | 125 |
1 files changed, 124 insertions, 1 deletions
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c index 31b9086..a251907 100644 --- a/gdb/i386-linux-nat.c +++ b/gdb/i386-linux-nat.c @@ -23,11 +23,14 @@ #include "inferior.h" #include "gdbcore.h" #include "regcache.h" +#include "regset.h" #include "target.h" #include "linux-nat.h" #include "gdb_assert.h" #include "gdb_string.h" +#include "elf/common.h" +#include <sys/uio.h> #include <sys/ptrace.h> #include <sys/user.h> #include <sys/procfs.h> @@ -69,6 +72,19 @@ /* Defines ps_err_e, struct ps_prochandle. */ #include "gdb_proc_service.h" + +#include "i386-xstate.h" + +#ifndef PTRACE_GETREGSET +#define PTRACE_GETREGSET 0x4204 +#endif + +#ifndef PTRACE_SETREGSET +#define PTRACE_SETREGSET 0x4205 +#endif + +/* Does the current host support PTRACE_GETREGSET? */ +static int have_ptrace_getregset = -1; /* The register sets used in GNU/Linux ELF core-dumps are identical to @@ -98,6 +114,8 @@ static int regmap[] = -1, -1, -1, -1, /* xmm0, xmm1, xmm2, xmm3 */ -1, -1, -1, -1, /* xmm4, xmm5, xmm6, xmm6 */ -1, /* mxcsr */ + -1, -1, -1, -1, /* ymm0h, ymm1h, ymm2h, ymm3h */ + -1, -1, -1, -1, /* ymm4h, ymm5h, ymm6h, ymm6h */ ORIG_EAX }; @@ -110,6 +128,9 @@ static int regmap[] = #define GETFPXREGS_SUPPLIES(regno) \ (I386_ST0_REGNUM <= (regno) && (regno) < I386_SSE_NUM_REGS) +#define GETXSTATEREGS_SUPPLIES(regno) \ + (I386_ST0_REGNUM <= (regno) && (regno) < I386_AVX_NUM_REGS) + /* Does the current host support the GETREGS request? */ int have_ptrace_getregs = #ifdef HAVE_PTRACE_GETREGS @@ -355,6 +376,57 @@ static void store_fpregs (const struct regcache *regcache, int tid, int regno) { /* Transfering floating-point and SSE registers to and from GDB. */ +/* Fetch all registers covered by the PTRACE_GETREGSET request from + process/thread TID and store their values in GDB's register array. + Return non-zero if successful, zero otherwise. */ + +static int +fetch_xstateregs (struct regcache *regcache, int tid) +{ + char xstateregs[I386_XSTATE_MAX_SIZE]; + struct iovec iov; + + if (!have_ptrace_getregset) + return 0; + + iov.iov_base = xstateregs; + iov.iov_len = sizeof(xstateregs); + if (ptrace (PTRACE_GETREGSET, tid, (unsigned int) NT_X86_XSTATE, + &iov) < 0) + perror_with_name (_("Couldn't read extended state status")); + + i387_supply_xsave (regcache, -1, xstateregs); + return 1; +} + +/* Store all valid registers in GDB's register array covered by the + PTRACE_SETREGSET request into the process/thread specified by TID. + Return non-zero if successful, zero otherwise. */ + +static int +store_xstateregs (const struct regcache *regcache, int tid, int regno) +{ + char xstateregs[I386_XSTATE_MAX_SIZE]; + struct iovec iov; + + if (!have_ptrace_getregset) + return 0; + + iov.iov_base = xstateregs; + iov.iov_len = sizeof(xstateregs); + if (ptrace (PTRACE_GETREGSET, tid, (unsigned int) NT_X86_XSTATE, + &iov) < 0) + perror_with_name (_("Couldn't read extended state status")); + + i387_collect_xsave (regcache, regno, xstateregs, 0); + + if (ptrace (PTRACE_SETREGSET, tid, (unsigned int) NT_X86_XSTATE, + (int) &iov) < 0) + perror_with_name (_("Couldn't write extended state status")); + + return 1; +} + #ifdef HAVE_PTRACE_GETFPXREGS /* Fill GDB's register array with the floating-point and SSE register @@ -489,6 +561,8 @@ i386_linux_fetch_inferior_registers (struct target_ops *ops, return; } + if (fetch_xstateregs (regcache, tid)) + return; if (fetch_fpxregs (regcache, tid)) return; fetch_fpregs (regcache, tid); @@ -501,6 +575,12 @@ i386_linux_fetch_inferior_registers (struct target_ops *ops, return; } + if (GETXSTATEREGS_SUPPLIES (regno)) + { + if (fetch_xstateregs (regcache, tid)) + return; + } + if (GETFPXREGS_SUPPLIES (regno)) { if (fetch_fpxregs (regcache, tid)) @@ -553,6 +633,8 @@ i386_linux_store_inferior_registers (struct target_ops *ops, if (regno == -1) { store_regs (regcache, tid, regno); + if (store_xstateregs (regcache, tid, regno)) + return; if (store_fpxregs (regcache, tid, regno)) return; store_fpregs (regcache, tid, regno); @@ -565,6 +647,12 @@ i386_linux_store_inferior_registers (struct target_ops *ops, return; } + if (GETXSTATEREGS_SUPPLIES (regno)) + { + if (store_xstateregs (regcache, tid, regno)) + return; + } + if (GETFPXREGS_SUPPLIES (regno)) { if (store_fpxregs (regcache, tid, regno)) @@ -858,7 +946,42 @@ i386_linux_child_post_startup_inferior (ptid_t ptid) static const struct target_desc * i386_linux_read_description (struct target_ops *ops) { - return tdesc_i386_linux; + static uint64_t xcr0; + + if (have_ptrace_getregset == -1) + { + int tid; + uint64_t xstateregs[(I386_XSTATE_SSE_SIZE / sizeof (uint64_t))]; + struct iovec iov; + + /* GNU/Linux LWP ID's are process ID's. */ + tid = TIDGET (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + + iov.iov_base = xstateregs; + iov.iov_len = sizeof (xstateregs); + + /* Check if PTRACE_GETREGSET works. */ + if (ptrace (PTRACE_GETREGSET, tid, (unsigned int) NT_X86_XSTATE, + &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))]; + } + } + + /* Check the native XCR0 only if PTRACE_GETREGSET is available. */ + if (have_ptrace_getregset + && (xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK) + return tdesc_i386_avx_linux; + else + return tdesc_i386_linux; } void |