/* Intel 387 floating point stuff.
- Copyright (C) 1988-1989, 1991-1994, 1998-2005, 2007-2012 Free
- Software Foundation, Inc.
+ Copyright (C) 1988-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "value.h"
#include "gdb_assert.h"
-#include "gdb_string.h"
+#include <string.h>
#include "i386-tdep.h"
#include "i387-tdep.h"
ULONGEST fop;
int fop_p;
int fpreg;
- int fpreg_p;
int top;
- int top_p;
gdb_assert (gdbarch == get_frame_arch (frame));
if (value_entirely_available (regval))
{
- const char *raw = value_contents (regval);
+ const gdb_byte *raw = value_contents (regval);
fputs_filtered ("0x", file);
for (i = 9; i >= 0; i--)
576 + 15 * 16 /* Upper 128bit of ... %ymm15 (128 bits each). */
};
+static int xsave_mpx_offset[] =
+{
+ 960 + 0 * 16, /* bnd0r...bnd3r registers. */
+ 960 + 1 * 16,
+ 960 + 2 * 16,
+ 960 + 3 * 16,
+ 1024 + 0 * 8, /* bndcfg ... bndstatus. */
+ 1024 + 1 * 8,
+};
+
#define XSAVE_AVXH_ADDR(tdep, xsave, regnum) \
(xsave + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
+#define XSAVE_MPX_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_mpx_offset[regnum - I387_BND0R_REGNUM (tdep)])
+
/* Similar to i387_supply_fxsave, but use XSAVE extended state. */
void
const gdb_byte *regs = xsave;
int i;
unsigned int clear_bv;
- const gdb_byte *p;
+ static const gdb_byte zero[MAX_REGISTER_SIZE] = { 0 };
enum
{
none = 0x0,
x87 = 0x1,
sse = 0x2,
avxh = 0x4,
- all = x87 | sse | avxh
+ mpx = 0x8,
+ all = x87 | sse | avxh | mpx
} regclass;
+ gdb_assert (regs != NULL);
gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
gdb_assert (tdep->num_xmm_regs > 0);
else if (regnum >= I387_YMM0H_REGNUM (tdep)
&& regnum < I387_YMMENDH_REGNUM (tdep))
regclass = avxh;
+ else if (regnum >= I387_BND0R_REGNUM (tdep)
+ && regnum < I387_MPXEND_REGNUM (tdep))
+ regclass = mpx;
else if (regnum >= I387_XMM0_REGNUM(tdep)
&& regnum < I387_MXCSR_REGNUM (tdep))
regclass = sse;
else
regclass = none;
- if (regs != NULL && regclass != none)
+ if (regclass != none)
{
/* Get `xstat_bv'. */
const gdb_byte *xstate_bv_p = XSAVE_XSTATE_BV_ADDR (regs);
clear_bv = (~(*xstate_bv_p)) & tdep->xcr0;
}
else
- clear_bv = I386_XSTATE_AVX_MASK;
+ clear_bv = I386_XSTATE_ALL_MASK;
+
+ /* With the delayed xsave mechanism, in between the program
+ starting, and the program accessing the vector registers for the
+ first time, the register's values are invalid. The kernel
+ initializes register states to zero when they are set the first
+ time in a program. This means that from the user-space programs'
+ perspective, it's the same as if the registers have always been
+ zero from the start of the program. Therefore, the debugger
+ should provide the same illusion to the user. */
switch (regclass)
{
case avxh:
if ((clear_bv & I386_XSTATE_AVX))
- p = NULL;
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_AVXH_ADDR (tdep, regs, regnum));
+ return;
+
+ case mpx:
+ if ((clear_bv & I386_XSTATE_BNDREGS))
+ regcache_raw_supply (regcache, regnum, zero);
else
- p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
- regcache_raw_supply (regcache, regnum, p);
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_MPX_ADDR (tdep, regs, regnum));
return;
case sse:
if ((clear_bv & I386_XSTATE_SSE))
- p = NULL;
+ regcache_raw_supply (regcache, regnum, zero);
else
- p = FXSAVE_ADDR (tdep, regs, regnum);
- regcache_raw_supply (regcache, regnum, p);
+ regcache_raw_supply (regcache, regnum,
+ FXSAVE_ADDR (tdep, regs, regnum));
return;
case x87:
if ((clear_bv & I386_XSTATE_X87))
- p = NULL;
+ regcache_raw_supply (regcache, regnum, zero);
else
- p = FXSAVE_ADDR (tdep, regs, regnum);
- regcache_raw_supply (regcache, regnum, p);
+ regcache_raw_supply (regcache, regnum,
+ FXSAVE_ADDR (tdep, regs, regnum));
return;
case all:
if ((tdep->xcr0 & I386_XSTATE_AVX))
{
if ((clear_bv & I386_XSTATE_AVX))
- p = NULL;
+ {
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
else
- p = regs;
+ {
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_AVXH_ADDR (tdep, regs, i));
+ }
+ }
- for (i = I387_YMM0H_REGNUM (tdep);
- i < I387_YMMENDH_REGNUM (tdep); i++)
+ /* Handle the MPX registers. */
+ if ((tdep->xcr0 & I386_XSTATE_BNDREGS))
+ {
+ if (clear_bv & I386_XSTATE_BNDREGS)
{
- if (p != NULL)
- p = XSAVE_AVXH_ADDR (tdep, regs, i);
- regcache_raw_supply (regcache, i, p);
+ for (i = I387_BND0R_REGNUM (tdep);
+ i < I387_BNDCFGU_REGNUM (tdep); i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_BND0R_REGNUM (tdep);
+ i < I387_BNDCFGU_REGNUM (tdep); i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_MPX_ADDR (tdep, regs, i));
+ }
+ }
+
+ /* Handle the MPX registers. */
+ if ((tdep->xcr0 & I386_XSTATE_BNDCFG))
+ {
+ if (clear_bv & I386_XSTATE_BNDCFG)
+ {
+ for (i = I387_BNDCFGU_REGNUM (tdep);
+ i < I387_MPXEND_REGNUM (tdep); i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_BNDCFGU_REGNUM (tdep);
+ i < I387_MPXEND_REGNUM (tdep); i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_MPX_ADDR (tdep, regs, i));
}
}
if ((tdep->xcr0 & I386_XSTATE_SSE))
{
if ((clear_bv & I386_XSTATE_SSE))
- p = NULL;
+ {
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
else
- p = regs;
-
- for (i = I387_XMM0_REGNUM (tdep);
- i < I387_MXCSR_REGNUM (tdep); i++)
{
- if (p != NULL)
- p = FXSAVE_ADDR (tdep, regs, i);
- regcache_raw_supply (regcache, i, p);
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep); i++)
+ regcache_raw_supply (regcache, i,
+ FXSAVE_ADDR (tdep, regs, i));
}
}
if ((tdep->xcr0 & I386_XSTATE_X87))
{
if ((clear_bv & I386_XSTATE_X87))
- p = NULL;
+ {
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
else
- p = regs;
-
- for (i = I387_ST0_REGNUM (tdep);
- i < I387_FCTRL_REGNUM (tdep); i++)
{
- if (p != NULL)
- p = FXSAVE_ADDR (tdep, regs, i);
- regcache_raw_supply (regcache, i, p);
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
}
}
break;
for (i = I387_FCTRL_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
if (regnum == -1 || regnum == i)
{
- if (regs == NULL)
- {
- regcache_raw_supply (regcache, i, NULL);
- continue;
- }
-
/* 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)
}
if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
- {
- p = regs == NULL ? NULL : FXSAVE_MXCSR_ADDR (regs);
- regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), p);
- }
+ regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
+ FXSAVE_MXCSR_ADDR (regs));
}
/* Similar to i387_collect_fxsave, but use XSAVE extended state. */
x87 = 0x2 | check,
sse = 0x4 | check,
avxh = 0x8 | check,
- all = x87 | sse | avxh
+ mpx = 0x10 | check,
+ all = x87 | sse | avxh | mpx
} regclass;
gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
else if (regnum >= I387_YMM0H_REGNUM (tdep)
&& regnum < I387_YMMENDH_REGNUM (tdep))
regclass = avxh;
- else if (regnum >= I387_XMM0_REGNUM(tdep)
+ else if (regnum >= I387_BND0R_REGNUM (tdep)
+ && regnum < I387_MPXEND_REGNUM (tdep))
+ regclass = mpx;
+ else if (regnum >= I387_XMM0_REGNUM (tdep)
&& regnum < I387_MXCSR_REGNUM (tdep))
regclass = sse;
else if (regnum >= I387_ST0_REGNUM (tdep)
/* Clear register set if its bit in xstat_bv is zero. */
if (clear_bv)
{
+ if ((clear_bv & I386_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 & I386_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 & I386_XSTATE_AVX))
for (i = I387_YMM0H_REGNUM (tdep);
i < I387_YMMENDH_REGNUM (tdep); i++)
memcpy (p, raw, 16);
}
}
+ /* Check if any upper MPX registers are changed. */
+ if ((tdep->xcr0 & I386_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))
+ {
+ xstate_bv |= I386_XSTATE_BNDREGS;
+ memcpy (p, raw, 16);
+ }
+ }
+
+ /* Check if any upper MPX registers are changed. */
+ if ((tdep->xcr0 & I386_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))
+ {
+ xstate_bv |= I386_XSTATE_BNDCFG;
+ memcpy (p, raw, 8);
+ }
+ }
/* Check if any SSE registers are changed. */
if ((tdep->xcr0 & I386_XSTATE_SSE))
}
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 |= I386_XSTATE_BNDREGS;
+ memcpy (p, raw, 16);
+ }
+ }
+ else
+ {
+ p = XSAVE_MPX_ADDR (tdep, regs, regnum);
+ xstate_bv |= I386_XSTATE_BNDCFG;
+ memcpy (p, raw, 8);
+ }
+ break;
+
case sse:
/* This is an SSE register. */
p = FXSAVE_ADDR (tdep, regs, regnum);
case x87:
case sse:
case avxh:
+ case mpx:
/* Register REGNUM has been updated. Return. */
return;
}