aboutsummaryrefslogtreecommitdiff
path: root/gdb/i387-tdep.c
diff options
context:
space:
mode:
authorAndrew Burgess <andrew.burgess@embecosm.com>2018-05-03 17:46:14 +0100
committerAndrew Burgess <andrew.burgess@embecosm.com>2018-05-08 18:03:46 +0100
commit8ee22052f690c007556b97eed59f49350ece5ca9 (patch)
tree4e777bd6bcd84d061f8ca31b5425d000d866ce3b /gdb/i387-tdep.c
parent886d542809fd73fba55ba72da1bd64ba50164222 (diff)
downloadgdb-8ee22052f690c007556b97eed59f49350ece5ca9.zip
gdb-8ee22052f690c007556b97eed59f49350ece5ca9.tar.gz
gdb-8ee22052f690c007556b97eed59f49350ece5ca9.tar.bz2
gdb/x86: Handle kernels using compact xsave format
For GNU/Linux on x86-64, if the target is using the xsave format for passing the floating-point information from the inferior then there currently exists a bug relating to the x87 control registers, and the mxcsr register. The xsave format allows different floating-point features to be lazily enabled, a bit in the xsave format tells GDB which floating-point features have been enabled, and which have not. Currently in GDB, when reading the floating point state, we check the xsave bit flags, if the feature is enabled then we read the feature from the xsave buffer, and if the feature is not enabled, then we supply the default value from within GDB. Within GDB, when writing the floating point state, we first fetch the xsave state from the target and then, for any feature that is not yet enabled, we write the default values into the xsave buffer. Next we compare the regcache value with the value in the xsave buffer, and, if the value has changed we update the value in the xsave buffer, and mark the feature enabled in the xsave bit flags. The problem then, is that the x87 control registers were not following this pattern. We assumed that these registers were always written out by the kernel, and we always wrote them out to the xsave buffer (but didn't enabled the feature). The result of this is that if the kernel had not yet enabled the x87 feature then within GDB we would see random values for the x87 floating point control registers, and if the user tried to modify one of these register, that modification would be lost. Finally, the mxcsr register was also broken in the same way as the x87 control registers. The added complexity with this case is that the mxcsr register is part of both the avx and sse floating point feature set. When reading or writing this register we need to check that at least one of these features is enabled. This bug was present in native GDB, and within gdbserver. Both are fixed with this commit. gdb/ChangeLog: * common/x86-xstate.h (I387_FCTRL_INIT_VAL): New constant. (I387_MXCSR_INIT_VAL): New constant. * amd64-tdep.c (amd64_supply_xsave): Only read state from xsave buffer if it was supplied by the inferior. * i387-tdep.c (i387_supply_fsave): Use I387_MXCSR_INIT_VAL. (i387_xsave_get_clear_bv): New function. (i387_supply_xsave): Only read x87 control registers from the xsave buffer if the feature is enabled, and the state will have been written, otherwise, provide a suitable default. (i387_collect_xsave): Pre-clear all registers in xsave buffer, including x87 control registers. Update control registers if they have changed from the default value, and mark features as enabled as required. * i387-tdep.h (i387_xsave_get_clear_bv): Declare. gdb/gdbserver/ChangeLog: * i387-fp.c (i387_cache_to_xsave): Only write x87 control registers to the cache if their values have changed. (i387_xsave_to_cache): Provide default values for x87 control registers when these features are available, but disabled. * regcache.c (supply_register_by_name_zeroed): New function. * regcache.h (supply_register_by_name_zeroed): Declare new function. gdb/testsuite/ChangeLog: * gdb.arch/amd64-init-x87-values.S: New file. * gdb.arch/amd64-init-x87-values.exp: New file.
Diffstat (limited to 'gdb/i387-tdep.c')
-rw-r--r--gdb/i387-tdep.c767
1 files changed, 432 insertions, 335 deletions
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
index 1938792..aca70c1 100644
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -479,7 +479,7 @@ i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
{
gdb_byte buf[4];
- store_unsigned_integer (buf, 4, byte_order, 0x1f80);
+ store_unsigned_integer (buf, 4, byte_order, I387_MXCSR_INIT_VAL);
regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), buf);
}
}
@@ -892,6 +892,27 @@ static int xsave_pkeys_offset[] =
#define XSAVE_PKEYS_ADDR(tdep, xsave, regnum) \
(xsave + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
+
+/* Extract from XSAVE a bitset of the features that are available on the
+ target, but which have not yet been enabled. */
+
+ULONGEST
+i387_xsave_get_clear_bv (struct gdbarch *gdbarch, const void *xsave)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ const gdb_byte *regs = (const gdb_byte *) xsave;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Get `xstat_bv'. The supported bits in `xstat_bv' are 8 bytes. */
+ ULONGEST xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
+ 8, byte_order);
+
+ /* Clear part in vector registers if its bit in xstat_bv is zero. */
+ ULONGEST clear_bv = (~(xstate_bv)) & tdep->xcr0;
+
+ return clear_bv;
+}
+
/* Similar to i387_supply_fxsave, but use XSAVE extended state. */
void
@@ -899,6 +920,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
const void *xsave)
{
struct gdbarch *gdbarch = regcache->arch ();
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
const gdb_byte *regs = (const gdb_byte *) xsave;
int i;
@@ -956,20 +978,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
else
regclass = none;
- if (regclass != none)
- {
- /* Get `xstat_bv'. The supported bits in `xstat_bv' are 8 bytes. */
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- ULONGEST xstate_bv = 0;
-
- xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
- 8, byte_order);
-
- /* Clear part in vector registers if its bit in xstat_bv is zero. */
- clear_bv = (~(xstate_bv)) & tdep->xcr0;
- }
- else
- clear_bv = X86_XSTATE_ALL_MASK;
+ clear_bv = i387_xsave_get_clear_bv (gdbarch, xsave);
/* With the delayed xsave mechanism, in between the program
starting, and the program accessing the vector registers for the
@@ -1246,10 +1255,30 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
for (i = I387_FCTRL_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
if (regnum == -1 || regnum == i)
{
+ if (clear_bv & X86_XSTATE_X87)
+ {
+ if (i == I387_FCTRL_REGNUM (tdep))
+ {
+ gdb_byte buf[4];
+
+ store_unsigned_integer (buf, 4, byte_order,
+ I387_FCTRL_INIT_VAL);
+ regcache_raw_supply (regcache, i, buf);
+ }
+ else if (i == I387_FTAG_REGNUM (tdep))
+ {
+ gdb_byte buf[4];
+
+ store_unsigned_integer (buf, 4, byte_order, 0xffff);
+ regcache_raw_supply (regcache, i, buf);
+ }
+ else
+ regcache_raw_supply (regcache, i, zero);
+ }
/* Most of the FPU control registers occupy only 16 bits in
the xsave extended state. Give those a special treatment. */
- if (i != I387_FIOFF_REGNUM (tdep)
- && i != I387_FOOFF_REGNUM (tdep))
+ else if (i != I387_FIOFF_REGNUM (tdep)
+ && i != I387_FOOFF_REGNUM (tdep))
{
gdb_byte val[4];
@@ -1257,7 +1286,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
val[2] = val[3] = 0;
if (i == I387_FOP_REGNUM (tdep))
val[1] &= ((1 << 3) - 1);
- else if (i== I387_FTAG_REGNUM (tdep))
+ else if (i == I387_FTAG_REGNUM (tdep))
{
/* The fxsave area contains a simplified version of
the tag word. We have to look at the actual 80-bit
@@ -1291,13 +1320,26 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
}
regcache_raw_supply (regcache, i, val);
}
- else
+ else
regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
}
if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
- regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
- FXSAVE_MXCSR_ADDR (regs));
+ {
+ /* The MXCSR register is placed into the xsave buffer if either the
+ AVX or SSE features are enabled. */
+ if ((clear_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ == (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ {
+ gdb_byte buf[4];
+
+ store_unsigned_integer (buf, 4, byte_order, I387_MXCSR_INIT_VAL);
+ regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), buf);
+ }
+ else
+ regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
+ FXSAVE_MXCSR_ADDR (regs));
+ }
}
/* Similar to i387_collect_fxsave, but use XSAVE extended state. */
@@ -1307,22 +1349,24 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
void *xsave, int gcore)
{
struct gdbarch *gdbarch = regcache->arch ();
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- gdb_byte *regs = (gdb_byte *) xsave;
+ gdb_byte *p, *regs = (gdb_byte *) xsave;
+ gdb_byte raw[I386_MAX_REGISTER_SIZE];
+ ULONGEST initial_xstate_bv, clear_bv, xstate_bv = 0;
int i;
enum
{
- none = 0x0,
- check = 0x1,
- x87 = 0x2 | check,
- sse = 0x4 | check,
- avxh = 0x8 | check,
- mpx = 0x10 | check,
- avx512_k = 0x20 | check,
- avx512_zmm_h = 0x40 | check,
- avx512_ymmh_avx512 = 0x80 | check,
- avx512_xmm_avx512 = 0x100 | check,
- pkeys = 0x200 | check,
+ x87_ctrl_or_mxcsr = 0x1,
+ x87 = 0x2,
+ sse = 0x4,
+ avxh = 0x8,
+ mpx = 0x10,
+ avx512_k = 0x20,
+ avx512_zmm_h = 0x40,
+ avx512_ymmh_avx512 = 0x80,
+ avx512_xmm_avx512 = 0x100,
+ pkeys = 0x200,
all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h
| avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
} regclass;
@@ -1359,8 +1403,12 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
else if (regnum >= I387_ST0_REGNUM (tdep)
&& regnum < I387_FCTRL_REGNUM (tdep))
regclass = x87;
+ else if ((regnum >= I387_FCTRL_REGNUM (tdep)
+ && regnum < I387_XMM0_REGNUM (tdep))
+ || regnum == I387_MXCSR_REGNUM (tdep))
+ regclass = x87_ctrl_or_mxcsr;
else
- regclass = none;
+ internal_error (__FILE__, __LINE__, _("invalid i387 regnum %d"), regnum);
if (gcore)
{
@@ -1373,361 +1421,387 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
memcpy (XSAVE_XSTATE_BV_ADDR (regs), &tdep->xcr0, 8);
}
- if ((regclass & check))
+ /* The supported bits in `xstat_bv' are 8 bytes. */
+ initial_xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
+ 8, byte_order);
+ clear_bv = (~(initial_xstate_bv)) & tdep->xcr0;
+
+ /* The XSAVE buffer was filled lazily by the kernel. Only those
+ features that are enabled were written into the buffer, disabled
+ features left the buffer uninitialised. In order to identify if any
+ registers have changed we will be comparing the register cache
+ version to the version in the XSAVE buffer, it is important then that
+ at this point we initialise to the default values any features in
+ XSAVE that are not yet initialised.
+
+ This could be made more efficient, we know which features (from
+ REGNUM) we will be potentially updating, and could limit ourselves to
+ only clearing that feature. However, the extra complexity does not
+ seem justified at this point. */
+ if (clear_bv)
{
- gdb_byte raw[I386_MAX_REGISTER_SIZE];
- ULONGEST initial_xstate_bv, clear_bv, xstate_bv = 0;
- gdb_byte *p;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-
- /* The supported bits in `xstat_bv' are 8 bytes. */
- initial_xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
- 8, byte_order);
- clear_bv = (~(initial_xstate_bv)) & tdep->xcr0;
+ if ((clear_bv & X86_XSTATE_PKRU))
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep); i++)
+ memset (XSAVE_PKEYS_ADDR (tdep, regs, i), 0, 4);
- /* Clear register set if its bit in xstat_bv is zero. */
- if (clear_bv)
- {
- if ((clear_bv & X86_XSTATE_PKRU))
- for (i = I387_PKRU_REGNUM (tdep);
- i < I387_PKEYSEND_REGNUM (tdep); i++)
- memset (XSAVE_PKEYS_ADDR (tdep, regs, i), 0, 4);
+ if ((clear_bv & X86_XSTATE_BNDREGS))
+ for (i = I387_BND0R_REGNUM (tdep);
+ i < I387_BNDCFGU_REGNUM (tdep); i++)
+ memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 16);
- if ((clear_bv & X86_XSTATE_BNDREGS))
- for (i = I387_BND0R_REGNUM (tdep);
- i < I387_BNDCFGU_REGNUM (tdep); i++)
- memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 16);
+ if ((clear_bv & X86_XSTATE_BNDCFG))
+ for (i = I387_BNDCFGU_REGNUM (tdep);
+ i < I387_MPXEND_REGNUM (tdep); i++)
+ memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 8);
- if ((clear_bv & X86_XSTATE_BNDCFG))
- for (i = I387_BNDCFGU_REGNUM (tdep);
- i < I387_MPXEND_REGNUM (tdep); i++)
- memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 8);
+ if ((clear_bv & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ for (i = I387_ZMM0H_REGNUM (tdep);
+ i < I387_ZMMENDH_REGNUM (tdep); i++)
+ memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32);
- if ((clear_bv & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
- for (i = I387_ZMM0H_REGNUM (tdep);
- i < I387_ZMMENDH_REGNUM (tdep); i++)
- memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32);
+ if ((clear_bv & X86_XSTATE_K))
+ for (i = I387_K0_REGNUM (tdep);
+ i < I387_KEND_REGNUM (tdep); i++)
+ memset (XSAVE_AVX512_K_ADDR (tdep, regs, i), 0, 8);
- if ((clear_bv & X86_XSTATE_K))
- for (i = I387_K0_REGNUM (tdep);
- i < I387_KEND_REGNUM (tdep); i++)
- memset (XSAVE_AVX512_K_ADDR (tdep, regs, i), 0, 8);
+ if ((clear_bv & X86_XSTATE_ZMM))
+ {
+ for (i = I387_YMM16H_REGNUM (tdep);
+ i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
+ memset (XSAVE_YMM_AVX512_ADDR (tdep, regs, i), 0, 16);
+ for (i = I387_XMM16_REGNUM (tdep);
+ i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
+ memset (XSAVE_XMM_AVX512_ADDR (tdep, regs, i), 0, 16);
+ }
- if ((clear_bv & X86_XSTATE_ZMM))
- {
- for (i = I387_YMM16H_REGNUM (tdep);
- i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
- memset (XSAVE_YMM_AVX512_ADDR (tdep, regs, i), 0, 16);
- for (i = I387_XMM16_REGNUM (tdep);
- i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
- memset (XSAVE_XMM_AVX512_ADDR (tdep, regs, i), 0, 16);
- }
+ if ((clear_bv & X86_XSTATE_AVX))
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep); i++)
+ memset (XSAVE_AVXH_ADDR (tdep, regs, i), 0, 16);
- if ((clear_bv & X86_XSTATE_AVX))
- for (i = I387_YMM0H_REGNUM (tdep);
- i < I387_YMMENDH_REGNUM (tdep); i++)
- memset (XSAVE_AVXH_ADDR (tdep, regs, i), 0, 16);
+ if ((clear_bv & X86_XSTATE_SSE))
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep); i++)
+ memset (FXSAVE_ADDR (tdep, regs, i), 0, 16);
+
+ /* The mxcsr register is written into the xsave buffer if either AVX
+ or SSE is enabled, so only clear it if both of those features
+ require clearing. */
+ if ((clear_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ == (X86_XSTATE_AVX | X86_XSTATE_SSE))
+ store_unsigned_integer (FXSAVE_ADDR (tdep, regs, i), 2, byte_order,
+ I387_MXCSR_INIT_VAL);
- if ((clear_bv & X86_XSTATE_SSE))
- for (i = I387_XMM0_REGNUM (tdep);
- i < I387_MXCSR_REGNUM (tdep); i++)
- memset (FXSAVE_ADDR (tdep, regs, i), 0, 16);
+ if ((clear_bv & X86_XSTATE_X87))
+ {
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep); i++)
+ memset (FXSAVE_ADDR (tdep, regs, i), 0, 10);
- if ((clear_bv & X86_XSTATE_X87))
- for (i = I387_ST0_REGNUM (tdep);
- i < I387_FCTRL_REGNUM (tdep); i++)
- memset (FXSAVE_ADDR (tdep, regs, i), 0, 10);
+ for (i = I387_FCTRL_REGNUM (tdep);
+ i < I387_XMM0_REGNUM (tdep); i++)
+ {
+ if (i == I387_FCTRL_REGNUM (tdep))
+ store_unsigned_integer (FXSAVE_ADDR (tdep, regs, i), 2,
+ byte_order, I387_FCTRL_INIT_VAL);
+ else
+ memset (FXSAVE_ADDR (tdep, regs, i), 0,
+ regcache_register_size (regcache, i));
+ }
}
+ }
- if (regclass == all)
- {
- /* Check if any PKEYS registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_PKRU))
- for (i = I387_PKRU_REGNUM (tdep);
- i < I387_PKEYSEND_REGNUM (tdep); i++)
+ if (regclass == all)
+ {
+ /* Check if any PKEYS registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_PKRU))
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_PKEYS_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 4) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_PKEYS_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 4) != 0)
- {
- xstate_bv |= X86_XSTATE_PKRU;
- memcpy (p, raw, 4);
- }
+ xstate_bv |= X86_XSTATE_PKRU;
+ memcpy (p, raw, 4);
}
+ }
- /* Check if any ZMMH registers are changed. */
- if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
- for (i = I387_ZMM0H_REGNUM (tdep);
- i < I387_ZMMENDH_REGNUM (tdep); i++)
+ /* Check if any ZMMH registers are changed. */
+ if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ for (i = I387_ZMM0H_REGNUM (tdep);
+ i < I387_ZMMENDH_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 32) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 32) != 0)
- {
- xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
- memcpy (p, raw, 32);
- }
+ xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
+ memcpy (p, raw, 32);
}
+ }
- /* Check if any K registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_K))
- for (i = I387_K0_REGNUM (tdep);
- i < I387_KEND_REGNUM (tdep); i++)
+ /* Check if any K registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_K))
+ for (i = I387_K0_REGNUM (tdep);
+ i < I387_KEND_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_AVX512_K_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 8) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_AVX512_K_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 8) != 0)
- {
- xstate_bv |= X86_XSTATE_K;
- memcpy (p, raw, 8);
- }
+ xstate_bv |= X86_XSTATE_K;
+ memcpy (p, raw, 8);
}
+ }
- /* Check if any XMM or upper YMM registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_ZMM))
+ /* Check if any XMM or upper YMM registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_ZMM))
+ {
+ for (i = I387_YMM16H_REGNUM (tdep);
+ i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
{
- for (i = I387_YMM16H_REGNUM (tdep);
- i < I387_YMMH_AVX512_END_REGNUM (tdep); i++)
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_YMM_AVX512_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_YMM_AVX512_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
}
- for (i = I387_XMM16_REGNUM (tdep);
- i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
+ }
+ for (i = I387_XMM16_REGNUM (tdep);
+ i < I387_XMM_AVX512_END_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_XMM_AVX512_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16) != 0)
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_XMM_AVX512_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
}
}
+ }
- /* Check if any upper YMM registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_AVX))
- for (i = I387_YMM0H_REGNUM (tdep);
- i < I387_YMMENDH_REGNUM (tdep); i++)
+ /* Check if any upper MPX registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_BNDREGS))
+ for (i = I387_BND0R_REGNUM (tdep);
+ i < I387_BNDCFGU_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_MPX_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16))
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_AVXH_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_AVX;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_BNDREGS;
+ memcpy (p, raw, 16);
}
- /* Check if any upper MPX registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_BNDREGS))
- for (i = I387_BND0R_REGNUM (tdep);
- i < I387_BNDCFGU_REGNUM (tdep); i++)
+ }
+
+ /* Check if any upper MPX registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_BNDCFG))
+ for (i = I387_BNDCFGU_REGNUM (tdep);
+ i < I387_MPXEND_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_MPX_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 8))
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_BNDREGS;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_BNDCFG;
+ memcpy (p, raw, 8);
}
+ }
- /* Check if any upper MPX registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_BNDCFG))
- for (i = I387_BNDCFGU_REGNUM (tdep);
- i < I387_MPXEND_REGNUM (tdep); i++)
+ /* Check if any upper YMM registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_AVX))
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = XSAVE_AVXH_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16))
{
- regcache_raw_collect (regcache, i, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 8))
- {
- xstate_bv |= X86_XSTATE_BNDCFG;
- memcpy (p, raw, 8);
- }
+ xstate_bv |= X86_XSTATE_AVX;
+ memcpy (p, raw, 16);
}
+ }
- /* Check if any SSE registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_SSE))
- for (i = I387_XMM0_REGNUM (tdep);
- i < I387_MXCSR_REGNUM (tdep); i++)
+ /* Check if any SSE registers are changed. */
+ if ((tdep->xcr0 & X86_XSTATE_SSE))
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 16))
{
- regcache_raw_collect (regcache, i, raw);
- p = FXSAVE_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_SSE;
- memcpy (p, raw, 16);
- }
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 16);
}
+ }
- /* Check if any X87 registers are changed. */
- if ((tdep->xcr0 & X86_XSTATE_X87))
- for (i = I387_ST0_REGNUM (tdep);
- i < I387_FCTRL_REGNUM (tdep); i++)
+ if ((tdep->xcr0 & X86_XSTATE_AVX) || (tdep->xcr0 & X86_XSTATE_SSE))
+ {
+ i = I387_MXCSR_REGNUM (tdep);
+ regcache_raw_collect (regcache, i, raw);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 4))
+ {
+ /* Now, we need to mark one of either SSE of AVX as enabled.
+ We could pick either. What we do is check to see if one
+ of the features is already enabled, if it is then we leave
+ it at that, otherwise we pick SSE. */
+ if ((xstate_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX)) == 0)
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 4);
+ }
+ }
+
+ /* Check if any X87 registers are changed. Only the non-control
+ registers are handled here, the control registers are all handled
+ later on in this function. */
+ if ((tdep->xcr0 & X86_XSTATE_X87))
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep); i++)
+ {
+ regcache_raw_collect (regcache, i, raw);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, 10))
{
- regcache_raw_collect (regcache, i, raw);
- p = FXSAVE_ADDR (tdep, regs, i);
- if (memcmp (raw, p, 10))
- {
- xstate_bv |= X86_XSTATE_X87;
- memcpy (p, raw, 10);
- }
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, raw, 10);
}
- }
- else
- {
- /* Check if REGNUM is changed. */
- regcache_raw_collect (regcache, regnum, raw);
+ }
+ }
+ else
+ {
+ /* Check if REGNUM is changed. */
+ regcache_raw_collect (regcache, regnum, raw);
- switch (regclass)
+ switch (regclass)
+ {
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("invalid i387 regclass"));
+
+ case pkeys:
+ /* This is a PKEYS register. */
+ p = XSAVE_PKEYS_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 4) != 0)
{
- default:
- internal_error (__FILE__, __LINE__,
- _("invalid i387 regclass"));
-
- case pkeys:
- /* This is a PKEYS register. */
- p = XSAVE_PKEYS_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 4) != 0)
- {
- xstate_bv |= X86_XSTATE_PKRU;
- memcpy (p, raw, 4);
- }
- break;
-
- case avx512_zmm_h:
- /* This is a ZMM register. */
- p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 32) != 0)
- {
- xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
- memcpy (p, raw, 32);
- }
- break;
- case avx512_k:
- /* This is a AVX512 mask register. */
- p = XSAVE_AVX512_K_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 8) != 0)
- {
- xstate_bv |= X86_XSTATE_K;
- memcpy (p, raw, 8);
- }
- break;
+ xstate_bv |= X86_XSTATE_PKRU;
+ memcpy (p, raw, 4);
+ }
+ break;
- case avx512_ymmh_avx512:
- /* This is an upper YMM16-31 register. */
- p = XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
- break;
+ case avx512_zmm_h:
+ /* This is a ZMM register. */
+ p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 32) != 0)
+ {
+ xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM);
+ memcpy (p, raw, 32);
+ }
+ break;
+ case avx512_k:
+ /* This is a AVX512 mask register. */
+ p = XSAVE_AVX512_K_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 8) != 0)
+ {
+ xstate_bv |= X86_XSTATE_K;
+ memcpy (p, raw, 8);
+ }
+ break;
- case avx512_xmm_avx512:
- /* This is an upper XMM16-31 register. */
- p = XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16) != 0)
- {
- xstate_bv |= X86_XSTATE_ZMM;
- memcpy (p, raw, 16);
- }
- break;
+ case avx512_ymmh_avx512:
+ /* This is an upper YMM16-31 register. */
+ p = XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16) != 0)
+ {
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
+ }
+ break;
- case avxh:
- /* This is an upper YMM register. */
- p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_AVX;
- memcpy (p, raw, 16);
- }
- break;
+ case avx512_xmm_avx512:
+ /* This is an upper XMM16-31 register. */
+ p = XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16) != 0)
+ {
+ xstate_bv |= X86_XSTATE_ZMM;
+ memcpy (p, raw, 16);
+ }
+ break;
- case mpx:
- if (regnum < I387_BNDCFGU_REGNUM (tdep))
- {
- regcache_raw_collect (regcache, regnum, raw);
- p = XSAVE_MPX_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 16))
- {
- xstate_bv |= X86_XSTATE_BNDREGS;
- memcpy (p, raw, 16);
- }
- }
- else
- {
- p = XSAVE_MPX_ADDR (tdep, regs, regnum);
- xstate_bv |= X86_XSTATE_BNDCFG;
- memcpy (p, raw, 8);
- }
- break;
+ case avxh:
+ /* This is an upper YMM register. */
+ p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16))
+ {
+ xstate_bv |= X86_XSTATE_AVX;
+ memcpy (p, raw, 16);
+ }
+ break;
- case sse:
- /* This is an SSE register. */
- p = FXSAVE_ADDR (tdep, regs, regnum);
+ case mpx:
+ if (regnum < I387_BNDCFGU_REGNUM (tdep))
+ {
+ regcache_raw_collect (regcache, regnum, raw);
+ p = XSAVE_MPX_ADDR (tdep, regs, regnum);
if (memcmp (raw, p, 16))
{
- xstate_bv |= X86_XSTATE_SSE;
+ xstate_bv |= X86_XSTATE_BNDREGS;
memcpy (p, raw, 16);
}
- break;
+ }
+ else
+ {
+ p = XSAVE_MPX_ADDR (tdep, regs, regnum);
+ xstate_bv |= X86_XSTATE_BNDCFG;
+ memcpy (p, raw, 8);
+ }
+ break;
- case x87:
- /* This is an x87 register. */
- p = FXSAVE_ADDR (tdep, regs, regnum);
- if (memcmp (raw, p, 10))
- {
- xstate_bv |= X86_XSTATE_X87;
- memcpy (p, raw, 10);
- }
- break;
+ case sse:
+ /* This is an SSE register. */
+ p = FXSAVE_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 16))
+ {
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 16);
}
- }
+ break;
- /* Update the corresponding bits in `xstate_bv' if any SSE/AVX
- registers are changed. */
- if (xstate_bv)
- {
- /* The supported bits in `xstat_bv' are 8 bytes. */
- initial_xstate_bv |= xstate_bv;
- store_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
- 8, byte_order,
- initial_xstate_bv);
+ case x87:
+ /* This is an x87 register. */
+ p = FXSAVE_ADDR (tdep, regs, regnum);
+ if (memcmp (raw, p, 10))
+ {
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, raw, 10);
+ }
+ break;
- switch (regclass)
+ case x87_ctrl_or_mxcsr:
+ /* We only handle MXCSR here. All other x87 control registers
+ are handled separately below. */
+ if (regnum == I387_MXCSR_REGNUM (tdep))
{
- default:
- internal_error (__FILE__, __LINE__,
- _("invalid i387 regclass"));
-
- case all:
- break;
-
- case x87:
- case sse:
- case avxh:
- case mpx:
- case avx512_k:
- case avx512_zmm_h:
- case avx512_ymmh_avx512:
- case avx512_xmm_avx512:
- case pkeys:
- /* Register REGNUM has been updated. Return. */
- return;
+ p = FXSAVE_MXCSR_ADDR (regs);
+ if (memcmp (raw, p, 2))
+ {
+ /* We're only setting MXCSR, so check the initial state
+ to see if either of AVX or SSE are already enabled.
+ If they are then we'll attribute this changed MXCSR to
+ that feature. If neither feature is enabled, then
+ we'll attribute this change to the SSE feature. */
+ xstate_bv |= (initial_xstate_bv
+ & (X86_XSTATE_AVX | X86_XSTATE_SSE));
+ if ((xstate_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE)) == 0)
+ xstate_bv |= X86_XSTATE_SSE;
+ memcpy (p, raw, 2);
+ }
}
}
- else
- {
- /* Return if REGNUM isn't changed. */
- if (regclass != all)
- return;
- }
}
/* Only handle x87 control registers. */
@@ -1769,15 +1843,38 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
buf[0] |= (1 << fpreg);
}
}
- memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (p, buf, 2))
+ {
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, buf, 2);
+ }
}
else
- regcache_raw_collect (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ {
+ int regsize;
+
+ regcache_raw_collect (regcache, i, raw);
+ regsize = regcache_register_size (regcache, i);
+ p = FXSAVE_ADDR (tdep, regs, i);
+ if (memcmp (raw, p, regsize))
+ {
+ xstate_bv |= X86_XSTATE_X87;
+ memcpy (p, raw, regsize);
+ }
+ }
}
- if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
- regcache_raw_collect (regcache, I387_MXCSR_REGNUM (tdep),
- FXSAVE_MXCSR_ADDR (regs));
+ /* Update the corresponding bits in `xstate_bv' if any
+ registers are changed. */
+ if (xstate_bv)
+ {
+ /* The supported bits in `xstat_bv' are 8 bytes. */
+ initial_xstate_bv |= xstate_bv;
+ store_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs),
+ 8, byte_order,
+ initial_xstate_bv);
+ }
}
/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in