+}
+
+/* `xstate_bv' is at byte offset 512. */
+#define XSAVE_XSTATE_BV_ADDR(xsave) (xsave + 512)
+
+/* At xsave_avxh_offset[REGNUM] you'll find the offset to the location in
+ the upper 128bit of AVX register data structure used by the "xsave"
+ instruction where GDB register REGNUM is stored. */
+
+static int xsave_avxh_offset[] =
+{
+ 576 + 0 * 16, /* Upper 128bit of %ymm0 through ... */
+ 576 + 1 * 16,
+ 576 + 2 * 16,
+ 576 + 3 * 16,
+ 576 + 4 * 16,
+ 576 + 5 * 16,
+ 576 + 6 * 16,
+ 576 + 7 * 16,
+ 576 + 8 * 16,
+ 576 + 9 * 16,
+ 576 + 10 * 16,
+ 576 + 11 * 16,
+ 576 + 12 * 16,
+ 576 + 13 * 16,
+ 576 + 14 * 16,
+ 576 + 15 * 16 /* Upper 128bit of ... %ymm15 (128 bits each). */
+};
+
+#define XSAVE_AVXH_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
+
+/* At xsave_ymm_avx512_offset[REGNUM] you'll find the offset to the location in
+ the upper 128bit of ZMM register data structure used by the "xsave"
+ instruction where GDB register REGNUM is stored. */
+
+static int xsave_ymm_avx512_offset[] =
+{
+ /* HI16_ZMM_area + 16 bytes + regnum* 64 bytes. */
+ 1664 + 16 + 0 * 64, /* %ymm16 through... */
+ 1664 + 16 + 1 * 64,
+ 1664 + 16 + 2 * 64,
+ 1664 + 16 + 3 * 64,
+ 1664 + 16 + 4 * 64,
+ 1664 + 16 + 5 * 64,
+ 1664 + 16 + 6 * 64,
+ 1664 + 16 + 7 * 64,
+ 1664 + 16 + 8 * 64,
+ 1664 + 16 + 9 * 64,
+ 1664 + 16 + 10 * 64,
+ 1664 + 16 + 11 * 64,
+ 1664 + 16 + 12 * 64,
+ 1664 + 16 + 13 * 64,
+ 1664 + 16 + 14 * 64,
+ 1664 + 16 + 15 * 64 /* ... %ymm31 (128 bits each). */
+};
+
+#define XSAVE_YMM_AVX512_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_ymm_avx512_offset[regnum - I387_YMM16H_REGNUM (tdep)])
+
+static int xsave_xmm_avx512_offset[] =
+{
+ 1664 + 0 * 64, /* %ymm16 through... */
+ 1664 + 1 * 64,
+ 1664 + 2 * 64,
+ 1664 + 3 * 64,
+ 1664 + 4 * 64,
+ 1664 + 5 * 64,
+ 1664 + 6 * 64,
+ 1664 + 7 * 64,
+ 1664 + 8 * 64,
+ 1664 + 9 * 64,
+ 1664 + 10 * 64,
+ 1664 + 11 * 64,
+ 1664 + 12 * 64,
+ 1664 + 13 * 64,
+ 1664 + 14 * 64,
+ 1664 + 15 * 64 /* ... %ymm31 (128 bits each). */
+};
+
+#define XSAVE_XMM_AVX512_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)])
+
+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_MPX_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_mpx_offset[regnum - I387_BND0R_REGNUM (tdep)])
+
+ /* At xsave_avx512__h_offset[REGNUM] you find the offset to the location
+ of the AVX512 opmask register data structure used by the "xsave"
+ instruction where GDB register REGNUM is stored. */
+
+static int xsave_avx512_k_offset[] =
+{
+ 1088 + 0 * 8, /* %k0 through... */
+ 1088 + 1 * 8,
+ 1088 + 2 * 8,
+ 1088 + 3 * 8,
+ 1088 + 4 * 8,
+ 1088 + 5 * 8,
+ 1088 + 6 * 8,
+ 1088 + 7 * 8 /* %k7 (64 bits each). */
+};
+
+#define XSAVE_AVX512_K_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_avx512_k_offset[regnum - I387_K0_REGNUM (tdep)])
+
+/* At xsave_avx512_zmm_h_offset[REGNUM] you find the offset to the location in
+ the upper 256bit of AVX512 ZMMH register data structure used by the "xsave"
+ instruction where GDB register REGNUM is stored. */
+
+static int xsave_avx512_zmm_h_offset[] =
+{
+ 1152 + 0 * 32,
+ 1152 + 1 * 32, /* Upper 256bit of %zmmh0 through... */
+ 1152 + 2 * 32,
+ 1152 + 3 * 32,
+ 1152 + 4 * 32,
+ 1152 + 5 * 32,
+ 1152 + 6 * 32,
+ 1152 + 7 * 32,
+ 1152 + 8 * 32,
+ 1152 + 9 * 32,
+ 1152 + 10 * 32,
+ 1152 + 11 * 32,
+ 1152 + 12 * 32,
+ 1152 + 13 * 32,
+ 1152 + 14 * 32,
+ 1152 + 15 * 32, /* Upper 256bit of... %zmmh15 (256 bits each). */
+ 1664 + 32 + 0 * 64, /* Upper 256bit of... %zmmh16 (256 bits each). */
+ 1664 + 32 + 1 * 64,
+ 1664 + 32 + 2 * 64,
+ 1664 + 32 + 3 * 64,
+ 1664 + 32 + 4 * 64,
+ 1664 + 32 + 5 * 64,
+ 1664 + 32 + 6 * 64,
+ 1664 + 32 + 7 * 64,
+ 1664 + 32 + 8 * 64,
+ 1664 + 32 + 9 * 64,
+ 1664 + 32 + 10 * 64,
+ 1664 + 32 + 11 * 64,
+ 1664 + 32 + 12 * 64,
+ 1664 + 32 + 13 * 64,
+ 1664 + 32 + 14 * 64,
+ 1664 + 32 + 15 * 64 /* Upper 256bit of... %zmmh31 (256 bits each). */
+};
+
+#define XSAVE_AVX512_ZMM_H_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_avx512_zmm_h_offset[regnum - I387_ZMM0H_REGNUM (tdep)])
+
+/* At xsave_pkeys_offset[REGNUM] you find the offset to the location
+ of the PKRU register data structure used by the "xsave"
+ instruction where GDB register REGNUM is stored. */
+
+static int xsave_pkeys_offset[] =
+{
+2688 + 0 * 8 /* %pkru (64 bits in XSTATE, 32-bit actually used by
+ instructions and applications). */
+};
+
+#define XSAVE_PKEYS_ADDR(tdep, xsave, regnum) \
+ (xsave + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)])
+
+/* Similar to i387_supply_fxsave, but use XSAVE extended state. */
+
+void
+i387_supply_xsave (struct regcache *regcache, int regnum,
+ const void *xsave)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ const gdb_byte *regs = (const gdb_byte *) xsave;
+ int i;
+ ULONGEST clear_bv;
+ static const gdb_byte zero[I386_MAX_REGISTER_SIZE] = { 0 };
+ enum
+ {
+ none = 0x0,
+ x87 = 0x1,
+ sse = 0x2,
+ avxh = 0x4,
+ mpx = 0x8,
+ avx512_k = 0x10,
+ avx512_zmm_h = 0x20,
+ avx512_ymmh_avx512 = 0x40,
+ avx512_xmm_avx512 = 0x80,
+ pkeys = 0x100,
+ all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h
+ | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys
+ } regclass;
+
+ gdb_assert (regs != NULL);
+ gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
+ gdb_assert (tdep->num_xmm_regs > 0);
+
+ if (regnum == -1)
+ regclass = all;
+ else if (regnum >= I387_PKRU_REGNUM (tdep)
+ && regnum < I387_PKEYSEND_REGNUM (tdep))
+ regclass = pkeys;
+ else if (regnum >= I387_ZMM0H_REGNUM (tdep)
+ && regnum < I387_ZMMENDH_REGNUM (tdep))
+ regclass = avx512_zmm_h;
+ else if (regnum >= I387_K0_REGNUM (tdep)
+ && regnum < I387_KEND_REGNUM (tdep))
+ regclass = avx512_k;
+ else if (regnum >= I387_YMM16H_REGNUM (tdep)
+ && regnum < I387_YMMH_AVX512_END_REGNUM (tdep))
+ regclass = avx512_ymmh_avx512;
+ else if (regnum >= I387_XMM16_REGNUM (tdep)
+ && regnum < I387_XMM_AVX512_END_REGNUM (tdep))
+ regclass = avx512_xmm_avx512;
+ 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 if (regnum >= I387_ST0_REGNUM (tdep)
+ && regnum < I387_FCTRL_REGNUM (tdep))
+ regclass = x87;
+ 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;
+
+ /* 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 none:
+ break;
+
+ case pkeys:
+ if ((clear_bv & X86_XSTATE_PKRU))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_PKEYS_ADDR (tdep, regs, regnum));
+ return;
+
+ case avx512_zmm_h:
+ if ((clear_bv & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum));
+ return;
+
+ case avx512_k:
+ if ((clear_bv & X86_XSTATE_K))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_AVX512_K_ADDR (tdep, regs, regnum));
+ return;
+
+ case avx512_ymmh_avx512:
+ if ((clear_bv & X86_XSTATE_ZMM))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum));
+ return;
+
+ case avx512_xmm_avx512:
+ if ((clear_bv & X86_XSTATE_ZMM))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum));
+ return;
+
+ case avxh:
+ if ((clear_bv & X86_XSTATE_AVX))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_AVXH_ADDR (tdep, regs, regnum));
+ return;
+
+ case mpx:
+ if ((clear_bv & X86_XSTATE_BNDREGS))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ XSAVE_MPX_ADDR (tdep, regs, regnum));
+ return;
+
+ case sse:
+ if ((clear_bv & X86_XSTATE_SSE))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ FXSAVE_ADDR (tdep, regs, regnum));
+ return;
+
+ case x87:
+ if ((clear_bv & X86_XSTATE_X87))
+ regcache_raw_supply (regcache, regnum, zero);
+ else
+ regcache_raw_supply (regcache, regnum,
+ FXSAVE_ADDR (tdep, regs, regnum));
+ return;
+
+ case all:
+ /* Handle PKEYS registers. */
+ if ((tdep->xcr0 & X86_XSTATE_PKRU))
+ {
+ if ((clear_bv & X86_XSTATE_PKRU))
+ {
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_PKRU_REGNUM (tdep);
+ i < I387_PKEYSEND_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_PKEYS_ADDR (tdep, regs, i));
+ }
+ }
+
+ /* Handle the upper ZMM registers. */
+ if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ {
+ if ((clear_bv & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM)))
+ {
+ for (i = I387_ZMM0H_REGNUM (tdep);
+ i < I387_ZMMENDH_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_ZMM0H_REGNUM (tdep);
+ i < I387_ZMMENDH_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i));
+ }
+ }
+
+ /* Handle AVX512 OpMask registers. */
+ if ((tdep->xcr0 & X86_XSTATE_K))
+ {
+ if ((clear_bv & X86_XSTATE_K))
+ {
+ for (i = I387_K0_REGNUM (tdep);
+ i < I387_KEND_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_K0_REGNUM (tdep);
+ i < I387_KEND_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_AVX512_K_ADDR (tdep, regs, i));
+ }
+ }
+
+ /* Handle the YMM_AVX512 registers. */
+ if ((tdep->xcr0 & X86_XSTATE_ZMM))
+ {
+ if ((clear_bv & X86_XSTATE_ZMM))
+ {
+ for (i = I387_YMM16H_REGNUM (tdep);
+ i < I387_YMMH_AVX512_END_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ for (i = I387_XMM16_REGNUM (tdep);
+ i < I387_XMM_AVX512_END_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_YMM16H_REGNUM (tdep);
+ i < I387_YMMH_AVX512_END_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_YMM_AVX512_ADDR (tdep, regs, i));
+ for (i = I387_XMM16_REGNUM (tdep);
+ i < I387_XMM_AVX512_END_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_XMM_AVX512_ADDR (tdep, regs, i));
+ }
+ }
+ /* Handle the upper YMM registers. */
+ if ((tdep->xcr0 & X86_XSTATE_AVX))
+ {
+ if ((clear_bv & X86_XSTATE_AVX))
+ {
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_YMM0H_REGNUM (tdep);
+ i < I387_YMMENDH_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i,
+ XSAVE_AVXH_ADDR (tdep, regs, i));
+ }
+ }
+
+ /* Handle the MPX registers. */
+ if ((tdep->xcr0 & X86_XSTATE_BNDREGS))
+ {
+ if (clear_bv & X86_XSTATE_BNDREGS)
+ {
+ 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 & X86_XSTATE_BNDCFG))
+ {
+ if (clear_bv & X86_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));
+ }
+ }
+
+ /* Handle the XMM registers. */
+ if ((tdep->xcr0 & X86_XSTATE_SSE))
+ {
+ if ((clear_bv & X86_XSTATE_SSE))
+ {
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_XMM0_REGNUM (tdep);
+ i < I387_MXCSR_REGNUM (tdep); i++)
+ regcache_raw_supply (regcache, i,
+ FXSAVE_ADDR (tdep, regs, i));
+ }
+ }
+
+ /* Handle the x87 registers. */
+ if ((tdep->xcr0 & X86_XSTATE_X87))
+ {
+ if ((clear_bv & X86_XSTATE_X87))
+ {
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, zero);
+ }
+ else
+ {
+ for (i = I387_ST0_REGNUM (tdep);
+ i < I387_FCTRL_REGNUM (tdep);
+ i++)
+ regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ }
+ }
+ break;
+ }
+
+ /* Only handle x87 control registers. */
+ for (i = I387_FCTRL_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
+ if (regnum == -1 || regnum == i)
+ {
+ /* 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))
+ {
+ gdb_byte val[4];
+
+ memcpy (val, FXSAVE_ADDR (tdep, regs, i), 2);
+ val[2] = val[3] = 0;
+ if (i == I387_FOP_REGNUM (tdep))
+ val[1] &= ((1 << 3) - 1);
+ 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
+ FP data to recreate the traditional i387 tag word. */
+
+ unsigned long ftag = 0;
+ int fpreg;
+ int top;
+
+ top = ((FXSAVE_ADDR (tdep, regs,
+ I387_FSTAT_REGNUM (tdep)))[1] >> 3);
+ top &= 0x7;
+
+ for (fpreg = 7; fpreg >= 0; fpreg--)
+ {
+ int tag;
+
+ if (val[0] & (1 << fpreg))
+ {
+ int thisreg = (fpreg + 8 - top) % 8
+ + I387_ST0_REGNUM (tdep);
+ tag = i387_tag (FXSAVE_ADDR (tdep, regs, thisreg));
+ }
+ else
+ tag = 3; /* Empty */
+
+ ftag |= tag << (2 * fpreg);
+ }
+ val[0] = ftag & 0xff;
+ val[1] = (ftag >> 8) & 0xff;
+ }
+ regcache_raw_supply (regcache, i, val);
+ }
+ else
+ regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
+ }