| /* Intel 387 floating point stuff. | 
 |  | 
 |    Copyright (C) 1988-2023 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "defs.h" | 
 | #include "frame.h" | 
 | #include "gdbcore.h" | 
 | #include "inferior.h" | 
 | #include "language.h" | 
 | #include "regcache.h" | 
 | #include "target-float.h" | 
 | #include "value.h" | 
 |  | 
 | #include "i386-tdep.h" | 
 | #include "i387-tdep.h" | 
 | #include "gdbsupport/x86-xstate.h" | 
 |  | 
 | /* Print the floating point number specified by RAW.  */ | 
 |  | 
 | static void | 
 | print_i387_value (struct gdbarch *gdbarch, | 
 | 		  const gdb_byte *raw, struct ui_file *file) | 
 | { | 
 |   /* We try to print 19 digits.  The last digit may or may not contain | 
 |      garbage, but we'd better print one too many.  We need enough room | 
 |      to print the value, 1 position for the sign, 1 for the decimal | 
 |      point, 19 for the digits and 6 for the exponent adds up to 27.  */ | 
 |   const struct type *type = i387_ext_type (gdbarch); | 
 |   std::string str = target_float_to_string (raw, type, " %-+27.19g"); | 
 |   gdb_printf (file, "%s", str.c_str ()); | 
 | } | 
 |  | 
 | /* Print the classification for the register contents RAW.  */ | 
 |  | 
 | static void | 
 | print_i387_ext (struct gdbarch *gdbarch, | 
 | 		const gdb_byte *raw, struct ui_file *file) | 
 | { | 
 |   int sign; | 
 |   int integer; | 
 |   unsigned int exponent; | 
 |   unsigned long fraction[2]; | 
 |  | 
 |   sign = raw[9] & 0x80; | 
 |   integer = raw[7] & 0x80; | 
 |   exponent = (((raw[9] & 0x7f) << 8) | raw[8]); | 
 |   fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); | 
 |   fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) | 
 | 		 | (raw[5] << 8) | raw[4]); | 
 |  | 
 |   if (exponent == 0x7fff && integer) | 
 |     { | 
 |       if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000) | 
 | 	/* Infinity.  */ | 
 | 	gdb_printf (file, " %cInf", (sign ? '-' : '+')); | 
 |       else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000) | 
 | 	/* Real Indefinite (QNaN).  */ | 
 | 	gdb_puts (" Real Indefinite (QNaN)", file); | 
 |       else if (fraction[1] & 0x40000000) | 
 | 	/* QNaN.  */ | 
 | 	gdb_puts (" QNaN", file); | 
 |       else | 
 | 	/* SNaN.  */ | 
 | 	gdb_puts (" SNaN", file); | 
 |     } | 
 |   else if (exponent < 0x7fff && exponent > 0x0000 && integer) | 
 |     /* Normal.  */ | 
 |     print_i387_value (gdbarch, raw, file); | 
 |   else if (exponent == 0x0000) | 
 |     { | 
 |       /* Denormal or zero.  */ | 
 |       print_i387_value (gdbarch, raw, file); | 
 |        | 
 |       if (integer) | 
 | 	/* Pseudo-denormal.  */ | 
 | 	gdb_puts (" Pseudo-denormal", file); | 
 |       else if (fraction[0] || fraction[1]) | 
 | 	/* Denormal.  */ | 
 | 	gdb_puts (" Denormal", file); | 
 |     } | 
 |   else | 
 |     /* Unsupported.  */ | 
 |     gdb_puts (" Unsupported", file); | 
 | } | 
 |  | 
 | /* Print the status word STATUS.  If STATUS_P is false, then STATUS | 
 |    was unavailable.  */ | 
 |  | 
 | static void | 
 | print_i387_status_word (int status_p, | 
 | 			unsigned int status, struct ui_file *file) | 
 | { | 
 |   gdb_printf (file, "Status Word:         "); | 
 |   if (!status_p) | 
 |     { | 
 |       gdb_printf (file, "%s\n", _("<unavailable>")); | 
 |       return; | 
 |     } | 
 |  | 
 |   gdb_printf (file, "%s", hex_string_custom (status, 4)); | 
 |   gdb_puts ("  ", file); | 
 |   gdb_printf (file, " %s", (status & 0x0001) ? "IE" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x0002) ? "DE" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x0004) ? "ZE" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x0008) ? "OE" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x0010) ? "UE" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x0020) ? "PE" : "  "); | 
 |   gdb_puts ("  ", file); | 
 |   gdb_printf (file, " %s", (status & 0x0080) ? "ES" : "  "); | 
 |   gdb_puts ("  ", file); | 
 |   gdb_printf (file, " %s", (status & 0x0040) ? "SF" : "  "); | 
 |   gdb_puts ("  ", file); | 
 |   gdb_printf (file, " %s", (status & 0x0100) ? "C0" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x0200) ? "C1" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x0400) ? "C2" : "  "); | 
 |   gdb_printf (file, " %s", (status & 0x4000) ? "C3" : "  "); | 
 |  | 
 |   gdb_puts ("\n", file); | 
 |  | 
 |   gdb_printf (file, | 
 | 	      "                       TOP: %d\n", ((status >> 11) & 7)); | 
 | } | 
 |  | 
 | /* Print the control word CONTROL.  If CONTROL_P is false, then | 
 |    CONTROL was unavailable.  */ | 
 |  | 
 | static void | 
 | print_i387_control_word (int control_p, | 
 | 			 unsigned int control, struct ui_file *file) | 
 | { | 
 |   gdb_printf (file, "Control Word:        "); | 
 |   if (!control_p) | 
 |     { | 
 |       gdb_printf (file, "%s\n", _("<unavailable>")); | 
 |       return; | 
 |     } | 
 |  | 
 |   gdb_printf (file, "%s", hex_string_custom (control, 4)); | 
 |   gdb_puts ("  ", file); | 
 |   gdb_printf (file, " %s", (control & 0x0001) ? "IM" : "  "); | 
 |   gdb_printf (file, " %s", (control & 0x0002) ? "DM" : "  "); | 
 |   gdb_printf (file, " %s", (control & 0x0004) ? "ZM" : "  "); | 
 |   gdb_printf (file, " %s", (control & 0x0008) ? "OM" : "  "); | 
 |   gdb_printf (file, " %s", (control & 0x0010) ? "UM" : "  "); | 
 |   gdb_printf (file, " %s", (control & 0x0020) ? "PM" : "  "); | 
 |  | 
 |   gdb_puts ("\n", file); | 
 |  | 
 |   gdb_puts ("                       PC: ", file); | 
 |   switch ((control >> 8) & 3) | 
 |     { | 
 |     case 0: | 
 |       gdb_puts ("Single Precision (24-bits)\n", file); | 
 |       break; | 
 |     case 1: | 
 |       gdb_puts ("Reserved\n", file); | 
 |       break; | 
 |     case 2: | 
 |       gdb_puts ("Double Precision (53-bits)\n", file); | 
 |       break; | 
 |     case 3: | 
 |       gdb_puts ("Extended Precision (64-bits)\n", file); | 
 |       break; | 
 |     } | 
 |        | 
 |   gdb_puts ("                       RC: ", file); | 
 |   switch ((control >> 10) & 3) | 
 |     { | 
 |     case 0: | 
 |       gdb_puts ("Round to nearest\n", file); | 
 |       break; | 
 |     case 1: | 
 |       gdb_puts ("Round down\n", file); | 
 |       break; | 
 |     case 2: | 
 |       gdb_puts ("Round up\n", file); | 
 |       break; | 
 |     case 3: | 
 |       gdb_puts ("Round toward zero\n", file); | 
 |       break; | 
 |     } | 
 | } | 
 |  | 
 | /* Print out the i387 floating point state.  Note that we ignore FRAME | 
 |    in the code below.  That's OK since floating-point registers are | 
 |    never saved on the stack.  */ | 
 |  | 
 | void | 
 | i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, | 
 | 		       frame_info_ptr frame, const char *args) | 
 | { | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); | 
 |   ULONGEST fctrl; | 
 |   int fctrl_p; | 
 |   ULONGEST fstat; | 
 |   int fstat_p; | 
 |   ULONGEST ftag; | 
 |   int ftag_p; | 
 |   ULONGEST fiseg; | 
 |   int fiseg_p; | 
 |   ULONGEST fioff; | 
 |   int fioff_p; | 
 |   ULONGEST foseg; | 
 |   int foseg_p; | 
 |   ULONGEST fooff; | 
 |   int fooff_p; | 
 |   ULONGEST fop; | 
 |   int fop_p; | 
 |   int fpreg; | 
 |   int top; | 
 |  | 
 |   gdb_assert (gdbarch == get_frame_arch (frame)); | 
 |  | 
 |   fctrl_p = read_frame_register_unsigned (frame, | 
 | 					  I387_FCTRL_REGNUM (tdep), &fctrl); | 
 |   fstat_p = read_frame_register_unsigned (frame, | 
 | 					  I387_FSTAT_REGNUM (tdep), &fstat); | 
 |   ftag_p = read_frame_register_unsigned (frame, | 
 | 					 I387_FTAG_REGNUM (tdep), &ftag); | 
 |   fiseg_p = read_frame_register_unsigned (frame, | 
 | 					  I387_FISEG_REGNUM (tdep), &fiseg); | 
 |   fioff_p = read_frame_register_unsigned (frame, | 
 | 					  I387_FIOFF_REGNUM (tdep), &fioff); | 
 |   foseg_p = read_frame_register_unsigned (frame, | 
 | 					  I387_FOSEG_REGNUM (tdep), &foseg); | 
 |   fooff_p = read_frame_register_unsigned (frame, | 
 | 					  I387_FOOFF_REGNUM (tdep), &fooff); | 
 |   fop_p = read_frame_register_unsigned (frame, | 
 | 					I387_FOP_REGNUM (tdep), &fop); | 
 |  | 
 |   if (fstat_p) | 
 |     { | 
 |       top = ((fstat >> 11) & 7); | 
 |  | 
 |       for (fpreg = 7; fpreg >= 0; fpreg--) | 
 | 	{ | 
 | 	  struct value *regval; | 
 | 	  int regnum; | 
 | 	  int i; | 
 | 	  int tag = -1; | 
 |  | 
 | 	  gdb_printf (file, "%sR%d: ", fpreg == top ? "=>" : "  ", fpreg); | 
 |  | 
 | 	  if (ftag_p) | 
 | 	    { | 
 | 	      tag = (ftag >> (fpreg * 2)) & 3; | 
 |  | 
 | 	      switch (tag) | 
 | 		{ | 
 | 		case 0: | 
 | 		  gdb_puts ("Valid   ", file); | 
 | 		  break; | 
 | 		case 1: | 
 | 		  gdb_puts ("Zero    ", file); | 
 | 		  break; | 
 | 		case 2: | 
 | 		  gdb_puts ("Special ", file); | 
 | 		  break; | 
 | 		case 3: | 
 | 		  gdb_puts ("Empty   ", file); | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    gdb_puts ("Unknown ", file); | 
 |  | 
 | 	  regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM (tdep); | 
 | 	  regval = get_frame_register_value (frame, regnum); | 
 |  | 
 | 	  if (regval->entirely_available ()) | 
 | 	    { | 
 | 	      const gdb_byte *raw = regval->contents ().data (); | 
 |  | 
 | 	      gdb_puts ("0x", file); | 
 | 	      for (i = 9; i >= 0; i--) | 
 | 		gdb_printf (file, "%02x", raw[i]); | 
 |  | 
 | 	      if (tag != -1 && tag != 3) | 
 | 		print_i387_ext (gdbarch, raw, file); | 
 | 	    } | 
 | 	  else | 
 | 	    gdb_printf (file, "%s", _("<unavailable>")); | 
 |  | 
 | 	  gdb_puts ("\n", file); | 
 | 	} | 
 |     } | 
 |  | 
 |   gdb_puts ("\n", file); | 
 |   print_i387_status_word (fstat_p, fstat, file); | 
 |   print_i387_control_word (fctrl_p, fctrl, file); | 
 |   gdb_printf (file, "Tag Word:            %s\n", | 
 | 	      ftag_p ? hex_string_custom (ftag, 4) : _("<unavailable>")); | 
 |   gdb_printf (file, "Instruction Pointer: %s:", | 
 | 	      fiseg_p ? hex_string_custom (fiseg, 2) : _("<unavailable>")); | 
 |   gdb_printf (file, "%s\n", | 
 | 	      fioff_p ? hex_string_custom (fioff, 8) : _("<unavailable>")); | 
 |   gdb_printf (file, "Operand Pointer:     %s:", | 
 | 	      foseg_p ? hex_string_custom (foseg, 2) : _("<unavailable>")); | 
 |   gdb_printf (file, "%s\n", | 
 | 	      fooff_p ? hex_string_custom (fooff, 8) : _("<unavailable>")); | 
 |   gdb_printf (file, "Opcode:              %s\n", | 
 | 	      fop_p | 
 | 	      ? (hex_string_custom (fop ? (fop | 0xd800) : 0, 4)) | 
 | 	      : _("<unavailable>")); | 
 | } | 
 |  | 
 |  | 
 | /* Return nonzero if a value of type TYPE stored in register REGNUM | 
 |    needs any special handling.  */ | 
 |  | 
 | int | 
 | i387_convert_register_p (struct gdbarch *gdbarch, int regnum, | 
 | 			 struct type *type) | 
 | { | 
 |   if (i386_fp_regnum_p (gdbarch, regnum)) | 
 |     { | 
 |       /* Floating point registers must be converted unless we are | 
 | 	 accessing them in their hardware type or TYPE is not float.  */ | 
 |       if (type == i387_ext_type (gdbarch) | 
 | 	  || type->code () != TYPE_CODE_FLT) | 
 | 	return 0; | 
 |       else | 
 | 	return 1; | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Read a value of type TYPE from register REGNUM in frame FRAME, and | 
 |    return its contents in TO.  */ | 
 |  | 
 | int | 
 | i387_register_to_value (frame_info_ptr frame, int regnum, | 
 | 			struct type *type, gdb_byte *to, | 
 | 			int *optimizedp, int *unavailablep) | 
 | { | 
 |   struct gdbarch *gdbarch = get_frame_arch (frame); | 
 |   gdb_byte from[I386_MAX_REGISTER_SIZE]; | 
 |  | 
 |   gdb_assert (i386_fp_regnum_p (gdbarch, regnum)); | 
 |  | 
 |   /* We only support floating-point values.  */ | 
 |   if (type->code () != TYPE_CODE_FLT) | 
 |     { | 
 |       warning (_("Cannot convert floating-point register value " | 
 | 	       "to non-floating-point type.")); | 
 |       *optimizedp = *unavailablep = 0; | 
 |       return 0; | 
 |     } | 
 |  | 
 |   /* Convert to TYPE.  */ | 
 |   if (!get_frame_register_bytes (frame, regnum, 0, | 
 | 				 gdb::make_array_view (from, | 
 | 						       register_size (gdbarch, | 
 | 								      regnum)), | 
 | 				 optimizedp, unavailablep)) | 
 |     return 0; | 
 |  | 
 |   target_float_convert (from, i387_ext_type (gdbarch), to, type); | 
 |   *optimizedp = *unavailablep = 0; | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Write the contents FROM of a value of type TYPE into register | 
 |    REGNUM in frame FRAME.  */ | 
 |  | 
 | void | 
 | i387_value_to_register (frame_info_ptr frame, int regnum, | 
 | 			struct type *type, const gdb_byte *from) | 
 | { | 
 |   struct gdbarch *gdbarch = get_frame_arch (frame); | 
 |   gdb_byte to[I386_MAX_REGISTER_SIZE]; | 
 |  | 
 |   gdb_assert (i386_fp_regnum_p (gdbarch, regnum)); | 
 |  | 
 |   /* We only support floating-point values.  */ | 
 |   if (type->code () != TYPE_CODE_FLT) | 
 |     { | 
 |       warning (_("Cannot convert non-floating-point type " | 
 | 	       "to floating-point register value.")); | 
 |       return; | 
 |     } | 
 |  | 
 |   /* Convert from TYPE.  */ | 
 |   target_float_convert (from, type, to, i387_ext_type (gdbarch)); | 
 |   put_frame_register (frame, regnum, to); | 
 | } | 
 |  | 
 |  | 
 | /* Handle FSAVE and FXSAVE formats.  */ | 
 |  | 
 | /* At fsave_offset[REGNUM] you'll find the offset to the location in | 
 |    the data structure used by the "fsave" instruction where GDB | 
 |    register REGNUM is stored.  */ | 
 |  | 
 | static int fsave_offset[] = | 
 | { | 
 |   28 + 0 * 10,			/* %st(0) ...  */ | 
 |   28 + 1 * 10, | 
 |   28 + 2 * 10, | 
 |   28 + 3 * 10, | 
 |   28 + 4 * 10, | 
 |   28 + 5 * 10, | 
 |   28 + 6 * 10, | 
 |   28 + 7 * 10,			/* ... %st(7).  */ | 
 |   0,				/* `fctrl' (16 bits).  */ | 
 |   4,				/* `fstat' (16 bits).  */ | 
 |   8,				/* `ftag' (16 bits).  */ | 
 |   16,				/* `fiseg' (16 bits).  */ | 
 |   12,				/* `fioff'.  */ | 
 |   24,				/* `foseg' (16 bits).  */ | 
 |   20,				/* `fooff'.  */ | 
 |   18				/* `fop' (bottom 11 bits).  */ | 
 | }; | 
 |  | 
 | #define FSAVE_ADDR(tdep, fsave, regnum) \ | 
 |   (fsave + fsave_offset[regnum - I387_ST0_REGNUM (tdep)]) | 
 |  | 
 |  | 
 | /* Fill register REGNUM in REGCACHE with the appropriate value from | 
 |    *FSAVE.  This function masks off any of the reserved bits in | 
 |    *FSAVE.  */ | 
 |  | 
 | void | 
 | i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave) | 
 | { | 
 |   struct gdbarch *gdbarch = regcache->arch (); | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); | 
 |   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | 
 |   const gdb_byte *regs = (const gdb_byte *) fsave; | 
 |   int i; | 
 |  | 
 |   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); | 
 |  | 
 |   for (i = I387_ST0_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++) | 
 |     if (regnum == -1 || regnum == i) | 
 |       { | 
 | 	if (fsave == NULL) | 
 | 	  { | 
 | 	    regcache->raw_supply (i, NULL); | 
 | 	    continue; | 
 | 	  } | 
 |  | 
 | 	/* Most of the FPU control registers occupy only 16 bits in the | 
 | 	   fsave area.  Give those a special treatment.  */ | 
 | 	if (i >= I387_FCTRL_REGNUM (tdep) | 
 | 	    && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep)) | 
 | 	  { | 
 | 	    gdb_byte val[4]; | 
 |  | 
 | 	    memcpy (val, FSAVE_ADDR (tdep, regs, i), 2); | 
 | 	    val[2] = val[3] = 0; | 
 | 	    if (i == I387_FOP_REGNUM (tdep)) | 
 | 	      val[1] &= ((1 << 3) - 1); | 
 | 	    regcache->raw_supply (i, val); | 
 | 	  } | 
 | 	else | 
 | 	  regcache->raw_supply (i, FSAVE_ADDR (tdep, regs, i)); | 
 |       } | 
 |  | 
 |   /* Provide dummy values for the SSE registers.  */ | 
 |   for (i = I387_XMM0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++) | 
 |     if (regnum == -1 || regnum == i) | 
 |       regcache->raw_supply (i, NULL); | 
 |   if (regnum == -1 || regnum == I387_MXCSR_REGNUM (tdep)) | 
 |     { | 
 |       gdb_byte buf[4]; | 
 |  | 
 |       store_unsigned_integer (buf, 4, byte_order, I387_MXCSR_INIT_VAL); | 
 |       regcache->raw_supply (I387_MXCSR_REGNUM (tdep), buf); | 
 |     } | 
 | } | 
 |  | 
 | /* Fill register REGNUM (if it is a floating-point register) in *FSAVE | 
 |    with the value from REGCACHE.  If REGNUM is -1, do this for all | 
 |    registers.  This function doesn't touch any of the reserved bits in | 
 |    *FSAVE.  */ | 
 |  | 
 | void | 
 | i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave) | 
 | { | 
 |   gdbarch *arch = regcache->arch (); | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (arch); | 
 |   gdb_byte *regs = (gdb_byte *) fsave; | 
 |   int i; | 
 |  | 
 |   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); | 
 |  | 
 |   for (i = I387_ST0_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 fsave area.  Give those a special treatment.  */ | 
 | 	if (i >= I387_FCTRL_REGNUM (tdep) | 
 | 	    && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep)) | 
 | 	  { | 
 | 	    gdb_byte buf[4]; | 
 |  | 
 | 	    regcache->raw_collect (i, buf); | 
 |  | 
 | 	    if (i == I387_FOP_REGNUM (tdep)) | 
 | 	      { | 
 | 		/* The opcode occupies only 11 bits.  Make sure we | 
 | 		   don't touch the other bits.  */ | 
 | 		buf[1] &= ((1 << 3) - 1); | 
 | 		buf[1] |= ((FSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1)); | 
 | 	      } | 
 | 	    memcpy (FSAVE_ADDR (tdep, regs, i), buf, 2); | 
 | 	  } | 
 | 	else | 
 | 	  regcache->raw_collect (i, FSAVE_ADDR (tdep, regs, i)); | 
 |       } | 
 | } | 
 |  | 
 |  | 
 | /* At fxsave_offset[REGNUM] you'll find the offset to the location in | 
 |    the data structure used by the "fxsave" instruction where GDB | 
 |    register REGNUM is stored.  */ | 
 |  | 
 | static int fxsave_offset[] = | 
 | { | 
 |   32,				/* %st(0) through ...  */ | 
 |   48, | 
 |   64, | 
 |   80, | 
 |   96, | 
 |   112, | 
 |   128, | 
 |   144,				/* ... %st(7) (80 bits each).  */ | 
 |   0,				/* `fctrl' (16 bits).  */ | 
 |   2,				/* `fstat' (16 bits).  */ | 
 |   4,				/* `ftag' (16 bits).  */ | 
 |   12,				/* `fiseg' (16 bits).  */ | 
 |   8,				/* `fioff'.  */ | 
 |   20,				/* `foseg' (16 bits).  */ | 
 |   16,				/* `fooff'.  */ | 
 |   6,				/* `fop' (bottom 11 bits).  */ | 
 |   160 + 0 * 16,			/* %xmm0 through ...  */ | 
 |   160 + 1 * 16, | 
 |   160 + 2 * 16, | 
 |   160 + 3 * 16, | 
 |   160 + 4 * 16, | 
 |   160 + 5 * 16, | 
 |   160 + 6 * 16, | 
 |   160 + 7 * 16, | 
 |   160 + 8 * 16, | 
 |   160 + 9 * 16, | 
 |   160 + 10 * 16, | 
 |   160 + 11 * 16, | 
 |   160 + 12 * 16, | 
 |   160 + 13 * 16, | 
 |   160 + 14 * 16, | 
 |   160 + 15 * 16,		/* ... %xmm15 (128 bits each).  */ | 
 | }; | 
 |  | 
 | #define FXSAVE_ADDR(tdep, fxsave, regnum) \ | 
 |   (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM (tdep)]) | 
 |  | 
 | /* We made an unfortunate choice in putting %mxcsr after the SSE | 
 |    registers %xmm0-%xmm7 instead of before, since it makes supporting | 
 |    the registers %xmm8-%xmm15 on AMD64 a bit involved.  Therefore we | 
 |    don't include the offset for %mxcsr here above.  */ | 
 |  | 
 | #define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24) | 
 |  | 
 | static int i387_tag (const gdb_byte *raw); | 
 |  | 
 |  | 
 | /* Fill register REGNUM in REGCACHE with the appropriate | 
 |    floating-point or SSE register value from *FXSAVE.  This function | 
 |    masks off any of the reserved bits in *FXSAVE.  */ | 
 |  | 
 | void | 
 | i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave) | 
 | { | 
 |   gdbarch *arch = regcache->arch (); | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (arch); | 
 |   const gdb_byte *regs = (const gdb_byte *) fxsave; | 
 |   int i; | 
 |  | 
 |   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); | 
 |   gdb_assert (tdep->num_xmm_regs > 0); | 
 |  | 
 |   for (i = I387_ST0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++) | 
 |     if (regnum == -1 || regnum == i) | 
 |       { | 
 | 	if (regs == NULL) | 
 | 	  { | 
 | 	    regcache->raw_supply (i, NULL); | 
 | 	    continue; | 
 | 	  } | 
 |  | 
 | 	/* Most of the FPU control registers occupy only 16 bits in | 
 | 	   the fxsave area.  Give those a special treatment.  */ | 
 | 	if (i >= I387_FCTRL_REGNUM (tdep) && i < I387_XMM0_REGNUM (tdep) | 
 | 	    && 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 (i, val); | 
 | 	  } | 
 | 	else | 
 | 	  regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i)); | 
 |       } | 
 |  | 
 |   if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1) | 
 |     { | 
 |       if (regs == NULL) | 
 | 	regcache->raw_supply (I387_MXCSR_REGNUM (tdep), NULL); | 
 |       else | 
 | 	regcache->raw_supply (I387_MXCSR_REGNUM (tdep), | 
 | 			     FXSAVE_MXCSR_ADDR (regs)); | 
 |     } | 
 | } | 
 |  | 
 | /* 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 | 
 |    bits in *FXSAVE.  */ | 
 |  | 
 | void | 
 | i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave) | 
 | { | 
 |   gdbarch *arch = regcache->arch (); | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (arch); | 
 |   gdb_byte *regs = (gdb_byte *) fxsave; | 
 |   int i; | 
 |  | 
 |   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); | 
 |   gdb_assert (tdep->num_xmm_regs > 0); | 
 |  | 
 |   for (i = I387_ST0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++) | 
 |     if (regnum == -1 || regnum == i) | 
 |       { | 
 | 	/* Most of the FPU control registers occupy only 16 bits in | 
 | 	   the fxsave area.  Give those a special treatment.  */ | 
 | 	if (i >= I387_FCTRL_REGNUM (tdep) && i < I387_XMM0_REGNUM (tdep) | 
 | 	    && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep)) | 
 | 	  { | 
 | 	    gdb_byte buf[4]; | 
 |  | 
 | 	    regcache->raw_collect (i, buf); | 
 |  | 
 | 	    if (i == I387_FOP_REGNUM (tdep)) | 
 | 	      { | 
 | 		/* The opcode occupies only 11 bits.  Make sure we | 
 | 		   don't touch the other bits.  */ | 
 | 		buf[1] &= ((1 << 3) - 1); | 
 | 		buf[1] |= ((FXSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1)); | 
 | 	      } | 
 | 	    else if (i == I387_FTAG_REGNUM (tdep)) | 
 | 	      { | 
 | 		/* Converting back is much easier.  */ | 
 |  | 
 | 		unsigned short ftag; | 
 | 		int fpreg; | 
 |  | 
 | 		ftag = (buf[1] << 8) | buf[0]; | 
 | 		buf[0] = 0; | 
 | 		buf[1] = 0; | 
 |  | 
 | 		for (fpreg = 7; fpreg >= 0; fpreg--) | 
 | 		  { | 
 | 		    int tag = (ftag >> (fpreg * 2)) & 3; | 
 |  | 
 | 		    if (tag != 3) | 
 | 		      buf[0] |= (1 << fpreg); | 
 | 		  } | 
 | 	      } | 
 | 	    memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2); | 
 | 	  } | 
 | 	else | 
 | 	  regcache->raw_collect (i, FXSAVE_ADDR (tdep, regs, i)); | 
 |       } | 
 |  | 
 |   if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1) | 
 |     regcache->raw_collect (I387_MXCSR_REGNUM (tdep), | 
 | 			  FXSAVE_MXCSR_ADDR (regs)); | 
 | } | 
 |  | 
 | /* `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)]) | 
 |  | 
 |  | 
 | /* 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; | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_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 | 
 | 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); | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); | 
 |   const gdb_byte *regs = (const gdb_byte *) xsave; | 
 |   int i; | 
 |   /* In 64-bit mode the split between "low" and "high" ZMM registers is at | 
 |      ZMM16.  Outside of 64-bit mode there are no "high" ZMM registers at all. | 
 |      Precalculate the number to be used for the split point, with the all | 
 |      registers in the "low" portion outside of 64-bit mode.  */ | 
 |   unsigned int zmm_endlo_regnum = I387_ZMM0H_REGNUM (tdep) | 
 | 				  + std::min (tdep->num_zmm_regs, 16); | 
 |   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; | 
 |  | 
 |   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 | 
 |      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 (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, XSAVE_PKEYS_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case avx512_zmm_h: | 
 |       if ((clear_bv & (regnum < zmm_endlo_regnum ? X86_XSTATE_ZMM_H | 
 | 						 : X86_XSTATE_ZMM))) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, | 
 | 			      XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case avx512_k: | 
 |       if ((clear_bv & X86_XSTATE_K)) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, XSAVE_AVX512_K_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case avx512_ymmh_avx512: | 
 |       if ((clear_bv & X86_XSTATE_ZMM)) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, | 
 | 			      XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case avx512_xmm_avx512: | 
 |       if ((clear_bv & X86_XSTATE_ZMM)) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, | 
 | 			      XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case avxh: | 
 |       if ((clear_bv & X86_XSTATE_AVX)) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, XSAVE_AVXH_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case mpx: | 
 |       if ((clear_bv & X86_XSTATE_BNDREGS)) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, XSAVE_MPX_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case sse: | 
 |       if ((clear_bv & X86_XSTATE_SSE)) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (regnum, FXSAVE_ADDR (tdep, regs, regnum)); | 
 |       return; | 
 |  | 
 |     case x87: | 
 |       if ((clear_bv & X86_XSTATE_X87)) | 
 | 	regcache->raw_supply (regnum, zero); | 
 |       else | 
 | 	regcache->raw_supply (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 (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_PKRU_REGNUM (tdep); | 
 | 		   i < I387_PKEYSEND_REGNUM (tdep); | 
 | 		   i++) | 
 | 		regcache->raw_supply (i, XSAVE_PKEYS_ADDR (tdep, regs, i)); | 
 | 	    } | 
 | 	} | 
 |  | 
 |       /* Handle the upper halves of the low 8/16 ZMM registers.  */ | 
 |       if ((tdep->xcr0 & X86_XSTATE_ZMM_H)) | 
 | 	{ | 
 | 	  if ((clear_bv & X86_XSTATE_ZMM_H)) | 
 | 	    { | 
 | 	      for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++) | 
 | 		regcache->raw_supply (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++) | 
 | 		regcache->raw_supply (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 (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_K0_REGNUM (tdep); | 
 | 		   i < I387_KEND_REGNUM (tdep); | 
 | 		   i++) | 
 | 		regcache->raw_supply (i, XSAVE_AVX512_K_ADDR (tdep, regs, i)); | 
 | 	    } | 
 | 	} | 
 |  | 
 |       /* Handle the upper 16 ZMM/YMM/XMM registers (if any).  */ | 
 |       if ((tdep->xcr0 & X86_XSTATE_ZMM)) | 
 | 	{ | 
 | 	  if ((clear_bv & X86_XSTATE_ZMM)) | 
 | 	    { | 
 | 	      for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++) | 
 | 		regcache->raw_supply (i, zero); | 
 | 	      for (i = I387_YMM16H_REGNUM (tdep); | 
 | 		   i < I387_YMMH_AVX512_END_REGNUM (tdep); | 
 | 		   i++) | 
 | 		regcache->raw_supply (i, zero); | 
 | 	      for (i = I387_XMM16_REGNUM (tdep); | 
 | 		   i < I387_XMM_AVX512_END_REGNUM (tdep); | 
 | 		   i++) | 
 | 		regcache->raw_supply (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++) | 
 | 		regcache->raw_supply (i, | 
 | 				      XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i)); | 
 | 	      for (i = I387_YMM16H_REGNUM (tdep); | 
 | 		   i < I387_YMMH_AVX512_END_REGNUM (tdep); | 
 | 		   i++) | 
 | 		regcache->raw_supply (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 (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 (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_YMM0H_REGNUM (tdep); | 
 | 		   i < I387_YMMENDH_REGNUM (tdep); | 
 | 		   i++) | 
 | 		regcache->raw_supply (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 (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_BND0R_REGNUM (tdep); | 
 | 		   i < I387_BNDCFGU_REGNUM (tdep); i++) | 
 | 		regcache->raw_supply (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 (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_BNDCFGU_REGNUM (tdep); | 
 | 		   i < I387_MPXEND_REGNUM (tdep); i++) | 
 | 		regcache->raw_supply (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 (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_XMM0_REGNUM (tdep); | 
 | 		   i < I387_MXCSR_REGNUM (tdep); i++) | 
 | 		regcache->raw_supply (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 (i, zero); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      for (i = I387_ST0_REGNUM (tdep); | 
 | 		   i < I387_FCTRL_REGNUM (tdep); | 
 | 		   i++) | 
 | 		regcache->raw_supply (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) | 
 |       { | 
 | 	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 (i, buf); | 
 | 	      } | 
 | 	    else if (i == I387_FTAG_REGNUM (tdep)) | 
 | 	      { | 
 | 		gdb_byte buf[4]; | 
 |  | 
 | 		store_unsigned_integer (buf, 4, byte_order, 0xffff); | 
 | 		regcache->raw_supply (i, buf); | 
 | 	      } | 
 | 	    else | 
 | 	      regcache->raw_supply (i, zero); | 
 | 	  } | 
 | 	/* Most of the FPU control registers occupy only 16 bits in | 
 | 	   the xsave extended state.  Give those a special treatment.  */ | 
 | 	else 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 (i, val); | 
 | 	  } | 
 | 	else | 
 | 	  regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i)); | 
 |       } | 
 |  | 
 |   if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1) | 
 |     { | 
 |       /* 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 (I387_MXCSR_REGNUM (tdep), buf); | 
 | 	} | 
 |       else | 
 | 	regcache->raw_supply (I387_MXCSR_REGNUM (tdep), | 
 | 			      FXSAVE_MXCSR_ADDR (regs)); | 
 |     } | 
 | } | 
 |  | 
 | /* Similar to i387_collect_fxsave, but use XSAVE extended state.  */ | 
 |  | 
 | void | 
 | 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); | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); | 
 |   gdb_byte *p, *regs = (gdb_byte *) xsave; | 
 |   gdb_byte raw[I386_MAX_REGISTER_SIZE]; | 
 |   ULONGEST initial_xstate_bv, clear_bv, xstate_bv = 0; | 
 |   unsigned int i; | 
 |   /* See the comment in i387_supply_xsave().  */ | 
 |   unsigned int zmm_endlo_regnum = I387_ZMM0H_REGNUM (tdep) | 
 | 				  + std::min (tdep->num_zmm_regs, 16); | 
 |   enum | 
 |     { | 
 |       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; | 
 |  | 
 |   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 if ((regnum >= I387_FCTRL_REGNUM (tdep) | 
 | 	    && regnum < I387_XMM0_REGNUM (tdep)) | 
 | 	   || regnum == I387_MXCSR_REGNUM (tdep)) | 
 |     regclass = x87_ctrl_or_mxcsr; | 
 |   else | 
 |     internal_error (_("invalid i387 regnum %d"), regnum); | 
 |  | 
 |   if (gcore) | 
 |     { | 
 |       /* Clear XSAVE extended state.  */ | 
 |       memset (regs, 0, X86_XSTATE_SIZE (tdep->xcr0)); | 
 |  | 
 |       /* Update XCR0 and `xstate_bv' with XCR0 for gcore.  */ | 
 |       if (tdep->xsave_xcr0_offset != -1) | 
 | 	memcpy (regs + tdep->xsave_xcr0_offset, &tdep->xcr0, 8); | 
 |       memcpy (XSAVE_XSTATE_BV_ADDR (regs), &tdep->xcr0, 8); | 
 |     } | 
 |  | 
 |   /* 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) | 
 |     { | 
 |       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_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)) | 
 | 	for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; 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_ZMM)) | 
 | 	{ | 
 | 	  for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++) | 
 | 	    memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32); | 
 | 	  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_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_MXCSR_ADDR (regs), 2, byte_order, | 
 | 				I387_MXCSR_INIT_VAL); | 
 |  | 
 |       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++) | 
 | 	  { | 
 | 	    regcache->raw_collect (i, raw); | 
 | 	    p = XSAVE_PKEYS_ADDR (tdep, regs, i); | 
 | 	    if (memcmp (raw, p, 4) != 0) | 
 | 	      { | 
 | 		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++) | 
 | 	  { | 
 | 	    regcache->raw_collect (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); | 
 | 	      } | 
 | 	  } | 
 |  | 
 |       /* 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 (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); | 
 | 	      } | 
 | 	  } | 
 |  | 
 |       /* 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++) | 
 | 	    { | 
 | 	      regcache->raw_collect (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); | 
 | 		} | 
 | 	    } | 
 | 	  for (i = I387_XMM16_REGNUM (tdep); | 
 | 	       i < I387_XMM_AVX512_END_REGNUM (tdep); i++) | 
 | 	    { | 
 | 	      regcache->raw_collect (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); | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |  | 
 |       /* 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 (i, raw); | 
 | 	    p = XSAVE_MPX_ADDR (tdep, regs, i); | 
 | 	    if (memcmp (raw, p, 16)) | 
 | 	      { | 
 | 		xstate_bv |= X86_XSTATE_BNDREGS; | 
 | 		memcpy (p, raw, 16); | 
 | 	      } | 
 | 	  } | 
 |  | 
 |       /* 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 (i, raw); | 
 | 	    p = XSAVE_MPX_ADDR (tdep, regs, i); | 
 | 	    if (memcmp (raw, p, 8)) | 
 | 	      { | 
 | 		xstate_bv |= X86_XSTATE_BNDCFG; | 
 | 		memcpy (p, raw, 8); | 
 | 	      } | 
 | 	  } | 
 |  | 
 |       /* 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 (i, raw); | 
 | 	    p = XSAVE_AVXH_ADDR (tdep, regs, i); | 
 | 	    if (memcmp (raw, p, 16)) | 
 | 	      { | 
 | 		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++) | 
 | 	  { | 
 | 	    regcache->raw_collect (i, raw); | 
 | 	    p = FXSAVE_ADDR (tdep, regs, i); | 
 | 	    if (memcmp (raw, p, 16)) | 
 | 	      { | 
 | 		xstate_bv |= X86_XSTATE_SSE; | 
 | 		memcpy (p, raw, 16); | 
 | 	      } | 
 | 	  } | 
 |  | 
 |       if ((tdep->xcr0 & X86_XSTATE_AVX) || (tdep->xcr0 & X86_XSTATE_SSE)) | 
 | 	{ | 
 | 	  i = I387_MXCSR_REGNUM (tdep); | 
 | 	  regcache->raw_collect (i, raw); | 
 | 	  p = FXSAVE_MXCSR_ADDR (regs); | 
 | 	  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 (i, raw); | 
 | 	    p = FXSAVE_ADDR (tdep, regs, i); | 
 | 	    if (memcmp (raw, p, 10)) | 
 | 	      { | 
 | 		xstate_bv |= X86_XSTATE_X87; | 
 | 		memcpy (p, raw, 10); | 
 | 	      } | 
 | 	  } | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Check if REGNUM is changed.  */ | 
 |       regcache->raw_collect (regnum, raw); | 
 |  | 
 |       switch (regclass) | 
 | 	{ | 
 | 	default: | 
 | 	  internal_error (_("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; | 
 |  | 
 | 	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_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 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 mpx: | 
 | 	  if (regnum < I387_BNDCFGU_REGNUM (tdep)) | 
 | 	    { | 
 | 	      regcache->raw_collect (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 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; | 
 |  | 
 | 	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 x87_ctrl_or_mxcsr: | 
 | 	  /* We only handle MXCSR here.  All other x87 control registers | 
 | 	     are handled separately below.  */ | 
 | 	  if (regnum == I387_MXCSR_REGNUM (tdep)) | 
 | 	    { | 
 | 	      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); | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   /* 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 buf[4]; | 
 |  | 
 | 	    regcache->raw_collect (i, buf); | 
 |  | 
 | 	    if (i == I387_FOP_REGNUM (tdep)) | 
 | 	      { | 
 | 		/* The opcode occupies only 11 bits.  Make sure we | 
 | 		   don't touch the other bits.  */ | 
 | 		buf[1] &= ((1 << 3) - 1); | 
 | 		buf[1] |= ((FXSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1)); | 
 | 	      } | 
 | 	    else if (i == I387_FTAG_REGNUM (tdep)) | 
 | 	      { | 
 | 		/* Converting back is much easier.  */ | 
 |  | 
 | 		unsigned short ftag; | 
 | 		int fpreg; | 
 |  | 
 | 		ftag = (buf[1] << 8) | buf[0]; | 
 | 		buf[0] = 0; | 
 | 		buf[1] = 0; | 
 |  | 
 | 		for (fpreg = 7; fpreg >= 0; fpreg--) | 
 | 		  { | 
 | 		    int tag = (ftag >> (fpreg * 2)) & 3; | 
 |  | 
 | 		    if (tag != 3) | 
 | 		      buf[0] |= (1 << fpreg); | 
 | 		  } | 
 | 	      } | 
 | 	    p = FXSAVE_ADDR (tdep, regs, i); | 
 | 	    if (memcmp (p, buf, 2)) | 
 | 	      { | 
 | 		xstate_bv |= X86_XSTATE_X87; | 
 | 		memcpy (p, buf, 2); | 
 | 	      } | 
 | 	  } | 
 | 	else | 
 | 	  { | 
 | 	    int regsize; | 
 |  | 
 | 	    regcache->raw_collect (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); | 
 | 	      } | 
 | 	  } | 
 |       } | 
 |  | 
 |   /* 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 | 
 |    *RAW.  */ | 
 |  | 
 | static int | 
 | i387_tag (const gdb_byte *raw) | 
 | { | 
 |   int integer; | 
 |   unsigned int exponent; | 
 |   unsigned long fraction[2]; | 
 |  | 
 |   integer = raw[7] & 0x80; | 
 |   exponent = (((raw[9] & 0x7f) << 8) | raw[8]); | 
 |   fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); | 
 |   fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) | 
 | 		 | (raw[5] << 8) | raw[4]); | 
 |  | 
 |   if (exponent == 0x7fff) | 
 |     { | 
 |       /* Special.  */ | 
 |       return (2); | 
 |     } | 
 |   else if (exponent == 0x0000) | 
 |     { | 
 |       if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) | 
 | 	{ | 
 | 	  /* Zero.  */ | 
 | 	  return (1); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Special.  */ | 
 | 	  return (2); | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       if (integer) | 
 | 	{ | 
 | 	  /* Valid.  */ | 
 | 	  return (0); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Special.  */ | 
 | 	  return (2); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Prepare the FPU stack in REGCACHE for a function return.  */ | 
 |  | 
 | void | 
 | i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache) | 
 | { | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); | 
 |   ULONGEST fstat; | 
 |  | 
 |   /* Set the top of the floating-point register stack to 7.  The | 
 |      actual value doesn't really matter, but 7 is what a normal | 
 |      function return would end up with if the program started out with | 
 |      a freshly initialized FPU.  */ | 
 |   regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM (tdep), &fstat); | 
 |   fstat |= (7 << 11); | 
 |   regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM (tdep), fstat); | 
 |  | 
 |   /* Mark %st(1) through %st(7) as empty.  Since we set the top of the | 
 |      floating-point register stack to 7, the appropriate value for the | 
 |      tag word is 0x3fff.  */ | 
 |   regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM (tdep), 0x3fff); | 
 |  | 
 | } | 
 |  | 
 | /* See i387-tdep.h.  */ | 
 |  | 
 | void | 
 | i387_reset_bnd_regs (struct gdbarch *gdbarch, struct regcache *regcache) | 
 | { | 
 |   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); | 
 |  | 
 |   if (I387_BND0R_REGNUM (tdep) > 0) | 
 |     { | 
 |       gdb_byte bnd_buf[16]; | 
 |  | 
 |       memset (bnd_buf, 0, 16); | 
 |       for (int i = 0; i < I387_NUM_BND_REGS; i++) | 
 | 	regcache->raw_write (I387_BND0R_REGNUM (tdep) + i, bnd_buf); | 
 |     } | 
 | } |