xref: /dragonfly/contrib/gdb-7/gdb/i387-tdep.c (revision ef5ccd6c)
15796c8dcSSimon Schubert /* Intel 387 floating point stuff.
25796c8dcSSimon Schubert 
3*ef5ccd6cSJohn Marino    Copyright (C) 1988-2013 Free Software Foundation, Inc.
45796c8dcSSimon Schubert 
55796c8dcSSimon Schubert    This file is part of GDB.
65796c8dcSSimon Schubert 
75796c8dcSSimon Schubert    This program is free software; you can redistribute it and/or modify
85796c8dcSSimon Schubert    it under the terms of the GNU General Public License as published by
95796c8dcSSimon Schubert    the Free Software Foundation; either version 3 of the License, or
105796c8dcSSimon Schubert    (at your option) any later version.
115796c8dcSSimon Schubert 
125796c8dcSSimon Schubert    This program is distributed in the hope that it will be useful,
135796c8dcSSimon Schubert    but WITHOUT ANY WARRANTY; without even the implied warranty of
145796c8dcSSimon Schubert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
155796c8dcSSimon Schubert    GNU General Public License for more details.
165796c8dcSSimon Schubert 
175796c8dcSSimon Schubert    You should have received a copy of the GNU General Public License
185796c8dcSSimon Schubert    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
195796c8dcSSimon Schubert 
205796c8dcSSimon Schubert #include "defs.h"
215796c8dcSSimon Schubert #include "doublest.h"
225796c8dcSSimon Schubert #include "floatformat.h"
235796c8dcSSimon Schubert #include "frame.h"
245796c8dcSSimon Schubert #include "gdbcore.h"
255796c8dcSSimon Schubert #include "inferior.h"
265796c8dcSSimon Schubert #include "language.h"
275796c8dcSSimon Schubert #include "regcache.h"
285796c8dcSSimon Schubert #include "value.h"
295796c8dcSSimon Schubert 
305796c8dcSSimon Schubert #include "gdb_assert.h"
315796c8dcSSimon Schubert #include "gdb_string.h"
325796c8dcSSimon Schubert 
335796c8dcSSimon Schubert #include "i386-tdep.h"
345796c8dcSSimon Schubert #include "i387-tdep.h"
35cf7f2e2dSJohn Marino #include "i386-xstate.h"
365796c8dcSSimon Schubert 
375796c8dcSSimon Schubert /* Print the floating point number specified by RAW.  */
385796c8dcSSimon Schubert 
395796c8dcSSimon Schubert static void
print_i387_value(struct gdbarch * gdbarch,const gdb_byte * raw,struct ui_file * file)405796c8dcSSimon Schubert print_i387_value (struct gdbarch *gdbarch,
415796c8dcSSimon Schubert 		  const gdb_byte *raw, struct ui_file *file)
425796c8dcSSimon Schubert {
435796c8dcSSimon Schubert   DOUBLEST value;
445796c8dcSSimon Schubert 
455796c8dcSSimon Schubert   /* Using extract_typed_floating here might affect the representation
465796c8dcSSimon Schubert      of certain numbers such as NaNs, even if GDB is running natively.
475796c8dcSSimon Schubert      This is fine since our caller already detects such special
485796c8dcSSimon Schubert      numbers and we print the hexadecimal representation anyway.  */
495796c8dcSSimon Schubert   value = extract_typed_floating (raw, i387_ext_type (gdbarch));
505796c8dcSSimon Schubert 
515796c8dcSSimon Schubert   /* We try to print 19 digits.  The last digit may or may not contain
525796c8dcSSimon Schubert      garbage, but we'd better print one too many.  We need enough room
535796c8dcSSimon Schubert      to print the value, 1 position for the sign, 1 for the decimal
545796c8dcSSimon Schubert      point, 19 for the digits and 6 for the exponent adds up to 27.  */
555796c8dcSSimon Schubert #ifdef PRINTF_HAS_LONG_DOUBLE
565796c8dcSSimon Schubert   fprintf_filtered (file, " %-+27.19Lg", (long double) value);
575796c8dcSSimon Schubert #else
585796c8dcSSimon Schubert   fprintf_filtered (file, " %-+27.19g", (double) value);
595796c8dcSSimon Schubert #endif
605796c8dcSSimon Schubert }
615796c8dcSSimon Schubert 
625796c8dcSSimon Schubert /* Print the classification for the register contents RAW.  */
635796c8dcSSimon Schubert 
645796c8dcSSimon Schubert static void
print_i387_ext(struct gdbarch * gdbarch,const gdb_byte * raw,struct ui_file * file)655796c8dcSSimon Schubert print_i387_ext (struct gdbarch *gdbarch,
665796c8dcSSimon Schubert 		const gdb_byte *raw, struct ui_file *file)
675796c8dcSSimon Schubert {
685796c8dcSSimon Schubert   int sign;
695796c8dcSSimon Schubert   int integer;
705796c8dcSSimon Schubert   unsigned int exponent;
715796c8dcSSimon Schubert   unsigned long fraction[2];
725796c8dcSSimon Schubert 
735796c8dcSSimon Schubert   sign = raw[9] & 0x80;
745796c8dcSSimon Schubert   integer = raw[7] & 0x80;
755796c8dcSSimon Schubert   exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
765796c8dcSSimon Schubert   fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
775796c8dcSSimon Schubert   fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
785796c8dcSSimon Schubert 		 | (raw[5] << 8) | raw[4]);
795796c8dcSSimon Schubert 
805796c8dcSSimon Schubert   if (exponent == 0x7fff && integer)
815796c8dcSSimon Schubert     {
825796c8dcSSimon Schubert       if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
835796c8dcSSimon Schubert 	/* Infinity.  */
845796c8dcSSimon Schubert 	fprintf_filtered (file, " %cInf", (sign ? '-' : '+'));
855796c8dcSSimon Schubert       else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
865796c8dcSSimon Schubert 	/* Real Indefinite (QNaN).  */
875796c8dcSSimon Schubert 	fputs_unfiltered (" Real Indefinite (QNaN)", file);
885796c8dcSSimon Schubert       else if (fraction[1] & 0x40000000)
895796c8dcSSimon Schubert 	/* QNaN.  */
905796c8dcSSimon Schubert 	fputs_filtered (" QNaN", file);
915796c8dcSSimon Schubert       else
925796c8dcSSimon Schubert 	/* SNaN.  */
935796c8dcSSimon Schubert 	fputs_filtered (" SNaN", file);
945796c8dcSSimon Schubert     }
955796c8dcSSimon Schubert   else if (exponent < 0x7fff && exponent > 0x0000 && integer)
965796c8dcSSimon Schubert     /* Normal.  */
975796c8dcSSimon Schubert     print_i387_value (gdbarch, raw, file);
985796c8dcSSimon Schubert   else if (exponent == 0x0000)
995796c8dcSSimon Schubert     {
1005796c8dcSSimon Schubert       /* Denormal or zero.  */
1015796c8dcSSimon Schubert       print_i387_value (gdbarch, raw, file);
1025796c8dcSSimon Schubert 
1035796c8dcSSimon Schubert       if (integer)
1045796c8dcSSimon Schubert 	/* Pseudo-denormal.  */
1055796c8dcSSimon Schubert 	fputs_filtered (" Pseudo-denormal", file);
1065796c8dcSSimon Schubert       else if (fraction[0] || fraction[1])
1075796c8dcSSimon Schubert 	/* Denormal.  */
1085796c8dcSSimon Schubert 	fputs_filtered (" Denormal", file);
1095796c8dcSSimon Schubert     }
1105796c8dcSSimon Schubert   else
1115796c8dcSSimon Schubert     /* Unsupported.  */
1125796c8dcSSimon Schubert     fputs_filtered (" Unsupported", file);
1135796c8dcSSimon Schubert }
1145796c8dcSSimon Schubert 
115*ef5ccd6cSJohn Marino /* Print the status word STATUS.  If STATUS_P is false, then STATUS
116*ef5ccd6cSJohn Marino    was unavailable.  */
1175796c8dcSSimon Schubert 
1185796c8dcSSimon Schubert static void
print_i387_status_word(int status_p,unsigned int status,struct ui_file * file)119*ef5ccd6cSJohn Marino print_i387_status_word (int status_p,
120*ef5ccd6cSJohn Marino 			unsigned int status, struct ui_file *file)
1215796c8dcSSimon Schubert {
122*ef5ccd6cSJohn Marino   fprintf_filtered (file, "Status Word:         ");
123*ef5ccd6cSJohn Marino   if (!status_p)
124*ef5ccd6cSJohn Marino     {
125*ef5ccd6cSJohn Marino       fprintf_filtered (file, "%s\n", _("<unavailable>"));
126*ef5ccd6cSJohn Marino       return;
127*ef5ccd6cSJohn Marino     }
128*ef5ccd6cSJohn Marino 
129*ef5ccd6cSJohn Marino   fprintf_filtered (file, "%s", hex_string_custom (status, 4));
1305796c8dcSSimon Schubert   fputs_filtered ("  ", file);
1315796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : "  ");
1325796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : "  ");
1335796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : "  ");
1345796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : "  ");
1355796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : "  ");
1365796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : "  ");
1375796c8dcSSimon Schubert   fputs_filtered ("  ", file);
1385796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : "  ");
1395796c8dcSSimon Schubert   fputs_filtered ("  ", file);
1405796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : "  ");
1415796c8dcSSimon Schubert   fputs_filtered ("  ", file);
1425796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : "  ");
1435796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : "  ");
1445796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : "  ");
1455796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : "  ");
1465796c8dcSSimon Schubert 
1475796c8dcSSimon Schubert   fputs_filtered ("\n", file);
1485796c8dcSSimon Schubert 
1495796c8dcSSimon Schubert   fprintf_filtered (file,
1505796c8dcSSimon Schubert 		    "                       TOP: %d\n", ((status >> 11) & 7));
1515796c8dcSSimon Schubert }
1525796c8dcSSimon Schubert 
153*ef5ccd6cSJohn Marino /* Print the control word CONTROL.  If CONTROL_P is false, then
154*ef5ccd6cSJohn Marino    CONTROL was unavailable.  */
1555796c8dcSSimon Schubert 
1565796c8dcSSimon Schubert static void
print_i387_control_word(int control_p,unsigned int control,struct ui_file * file)157*ef5ccd6cSJohn Marino print_i387_control_word (int control_p,
158*ef5ccd6cSJohn Marino 			 unsigned int control, struct ui_file *file)
1595796c8dcSSimon Schubert {
160*ef5ccd6cSJohn Marino   fprintf_filtered (file, "Control Word:        ");
161*ef5ccd6cSJohn Marino   if (!control_p)
162*ef5ccd6cSJohn Marino     {
163*ef5ccd6cSJohn Marino       fprintf_filtered (file, "%s\n", _("<unavailable>"));
164*ef5ccd6cSJohn Marino       return;
165*ef5ccd6cSJohn Marino     }
166*ef5ccd6cSJohn Marino 
167*ef5ccd6cSJohn Marino   fprintf_filtered (file, "%s", hex_string_custom (control, 4));
1685796c8dcSSimon Schubert   fputs_filtered ("  ", file);
1695796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : "  ");
1705796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : "  ");
1715796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : "  ");
1725796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : "  ");
1735796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : "  ");
1745796c8dcSSimon Schubert   fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : "  ");
1755796c8dcSSimon Schubert 
1765796c8dcSSimon Schubert   fputs_filtered ("\n", file);
1775796c8dcSSimon Schubert 
1785796c8dcSSimon Schubert   fputs_filtered ("                       PC: ", file);
1795796c8dcSSimon Schubert   switch ((control >> 8) & 3)
1805796c8dcSSimon Schubert     {
1815796c8dcSSimon Schubert     case 0:
1825796c8dcSSimon Schubert       fputs_filtered ("Single Precision (24-bits)\n", file);
1835796c8dcSSimon Schubert       break;
1845796c8dcSSimon Schubert     case 1:
1855796c8dcSSimon Schubert       fputs_filtered ("Reserved\n", file);
1865796c8dcSSimon Schubert       break;
1875796c8dcSSimon Schubert     case 2:
1885796c8dcSSimon Schubert       fputs_filtered ("Double Precision (53-bits)\n", file);
1895796c8dcSSimon Schubert       break;
1905796c8dcSSimon Schubert     case 3:
1915796c8dcSSimon Schubert       fputs_filtered ("Extended Precision (64-bits)\n", file);
1925796c8dcSSimon Schubert       break;
1935796c8dcSSimon Schubert     }
1945796c8dcSSimon Schubert 
1955796c8dcSSimon Schubert   fputs_filtered ("                       RC: ", file);
1965796c8dcSSimon Schubert   switch ((control >> 10) & 3)
1975796c8dcSSimon Schubert     {
1985796c8dcSSimon Schubert     case 0:
1995796c8dcSSimon Schubert       fputs_filtered ("Round to nearest\n", file);
2005796c8dcSSimon Schubert       break;
2015796c8dcSSimon Schubert     case 1:
2025796c8dcSSimon Schubert       fputs_filtered ("Round down\n", file);
2035796c8dcSSimon Schubert       break;
2045796c8dcSSimon Schubert     case 2:
2055796c8dcSSimon Schubert       fputs_filtered ("Round up\n", file);
2065796c8dcSSimon Schubert       break;
2075796c8dcSSimon Schubert     case 3:
2085796c8dcSSimon Schubert       fputs_filtered ("Round toward zero\n", file);
2095796c8dcSSimon Schubert       break;
2105796c8dcSSimon Schubert     }
2115796c8dcSSimon Schubert }
2125796c8dcSSimon Schubert 
2135796c8dcSSimon Schubert /* Print out the i387 floating point state.  Note that we ignore FRAME
2145796c8dcSSimon Schubert    in the code below.  That's OK since floating-point registers are
2155796c8dcSSimon Schubert    never saved on the stack.  */
2165796c8dcSSimon Schubert 
2175796c8dcSSimon Schubert void
i387_print_float_info(struct gdbarch * gdbarch,struct ui_file * file,struct frame_info * frame,const char * args)2185796c8dcSSimon Schubert i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
2195796c8dcSSimon Schubert 		       struct frame_info *frame, const char *args)
2205796c8dcSSimon Schubert {
2215796c8dcSSimon Schubert   struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
2225796c8dcSSimon Schubert   ULONGEST fctrl;
223*ef5ccd6cSJohn Marino   int fctrl_p;
2245796c8dcSSimon Schubert   ULONGEST fstat;
225*ef5ccd6cSJohn Marino   int fstat_p;
2265796c8dcSSimon Schubert   ULONGEST ftag;
227*ef5ccd6cSJohn Marino   int ftag_p;
2285796c8dcSSimon Schubert   ULONGEST fiseg;
229*ef5ccd6cSJohn Marino   int fiseg_p;
2305796c8dcSSimon Schubert   ULONGEST fioff;
231*ef5ccd6cSJohn Marino   int fioff_p;
2325796c8dcSSimon Schubert   ULONGEST foseg;
233*ef5ccd6cSJohn Marino   int foseg_p;
2345796c8dcSSimon Schubert   ULONGEST fooff;
235*ef5ccd6cSJohn Marino   int fooff_p;
2365796c8dcSSimon Schubert   ULONGEST fop;
237*ef5ccd6cSJohn Marino   int fop_p;
2385796c8dcSSimon Schubert   int fpreg;
2395796c8dcSSimon Schubert   int top;
2405796c8dcSSimon Schubert 
2415796c8dcSSimon Schubert   gdb_assert (gdbarch == get_frame_arch (frame));
2425796c8dcSSimon Schubert 
243*ef5ccd6cSJohn Marino   fctrl_p = read_frame_register_unsigned (frame,
244*ef5ccd6cSJohn Marino 					  I387_FCTRL_REGNUM (tdep), &fctrl);
245*ef5ccd6cSJohn Marino   fstat_p = read_frame_register_unsigned (frame,
246*ef5ccd6cSJohn Marino 					  I387_FSTAT_REGNUM (tdep), &fstat);
247*ef5ccd6cSJohn Marino   ftag_p = read_frame_register_unsigned (frame,
248*ef5ccd6cSJohn Marino 					 I387_FTAG_REGNUM (tdep), &ftag);
249*ef5ccd6cSJohn Marino   fiseg_p = read_frame_register_unsigned (frame,
250*ef5ccd6cSJohn Marino 					  I387_FISEG_REGNUM (tdep), &fiseg);
251*ef5ccd6cSJohn Marino   fioff_p = read_frame_register_unsigned (frame,
252*ef5ccd6cSJohn Marino 					  I387_FIOFF_REGNUM (tdep), &fioff);
253*ef5ccd6cSJohn Marino   foseg_p = read_frame_register_unsigned (frame,
254*ef5ccd6cSJohn Marino 					  I387_FOSEG_REGNUM (tdep), &foseg);
255*ef5ccd6cSJohn Marino   fooff_p = read_frame_register_unsigned (frame,
256*ef5ccd6cSJohn Marino 					  I387_FOOFF_REGNUM (tdep), &fooff);
257*ef5ccd6cSJohn Marino   fop_p = read_frame_register_unsigned (frame,
258*ef5ccd6cSJohn Marino 					I387_FOP_REGNUM (tdep), &fop);
2595796c8dcSSimon Schubert 
260*ef5ccd6cSJohn Marino   if (fstat_p)
261*ef5ccd6cSJohn Marino     {
2625796c8dcSSimon Schubert       top = ((fstat >> 11) & 7);
2635796c8dcSSimon Schubert 
2645796c8dcSSimon Schubert       for (fpreg = 7; fpreg >= 0; fpreg--)
2655796c8dcSSimon Schubert 	{
266*ef5ccd6cSJohn Marino 	  struct value *regval;
267*ef5ccd6cSJohn Marino 	  int regnum;
2685796c8dcSSimon Schubert 	  int i;
269*ef5ccd6cSJohn Marino 	  int tag = -1;
2705796c8dcSSimon Schubert 
2715796c8dcSSimon Schubert 	  fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : "  ", fpreg);
2725796c8dcSSimon Schubert 
273*ef5ccd6cSJohn Marino 	  if (ftag_p)
274*ef5ccd6cSJohn Marino 	    {
275*ef5ccd6cSJohn Marino 	      tag = (ftag >> (fpreg * 2)) & 3;
276*ef5ccd6cSJohn Marino 
2775796c8dcSSimon Schubert 	      switch (tag)
2785796c8dcSSimon Schubert 		{
2795796c8dcSSimon Schubert 		case 0:
2805796c8dcSSimon Schubert 		  fputs_filtered ("Valid   ", file);
2815796c8dcSSimon Schubert 		  break;
2825796c8dcSSimon Schubert 		case 1:
2835796c8dcSSimon Schubert 		  fputs_filtered ("Zero    ", file);
2845796c8dcSSimon Schubert 		  break;
2855796c8dcSSimon Schubert 		case 2:
2865796c8dcSSimon Schubert 		  fputs_filtered ("Special ", file);
2875796c8dcSSimon Schubert 		  break;
2885796c8dcSSimon Schubert 		case 3:
2895796c8dcSSimon Schubert 		  fputs_filtered ("Empty   ", file);
2905796c8dcSSimon Schubert 		  break;
2915796c8dcSSimon Schubert 		}
292*ef5ccd6cSJohn Marino 	    }
293*ef5ccd6cSJohn Marino 	  else
294*ef5ccd6cSJohn Marino 	    fputs_filtered ("Unknown ", file);
2955796c8dcSSimon Schubert 
296*ef5ccd6cSJohn Marino 	  regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM (tdep);
297*ef5ccd6cSJohn Marino 	  regval = get_frame_register_value (frame, regnum);
298*ef5ccd6cSJohn Marino 
299*ef5ccd6cSJohn Marino 	  if (value_entirely_available (regval))
300*ef5ccd6cSJohn Marino 	    {
301*ef5ccd6cSJohn Marino 	      const gdb_byte *raw = value_contents (regval);
3025796c8dcSSimon Schubert 
3035796c8dcSSimon Schubert 	      fputs_filtered ("0x", file);
3045796c8dcSSimon Schubert 	      for (i = 9; i >= 0; i--)
3055796c8dcSSimon Schubert 		fprintf_filtered (file, "%02x", raw[i]);
3065796c8dcSSimon Schubert 
307*ef5ccd6cSJohn Marino 	      if (tag != -1 && tag != 3)
3085796c8dcSSimon Schubert 		print_i387_ext (gdbarch, raw, file);
309*ef5ccd6cSJohn Marino 	    }
310*ef5ccd6cSJohn Marino 	  else
311*ef5ccd6cSJohn Marino 	    fprintf_filtered (file, "%s", _("<unavailable>"));
3125796c8dcSSimon Schubert 
3135796c8dcSSimon Schubert 	  fputs_filtered ("\n", file);
3145796c8dcSSimon Schubert 	}
315*ef5ccd6cSJohn Marino     }
3165796c8dcSSimon Schubert 
3175796c8dcSSimon Schubert   fputs_filtered ("\n", file);
318*ef5ccd6cSJohn Marino   print_i387_status_word (fstat_p, fstat, file);
319*ef5ccd6cSJohn Marino   print_i387_control_word (fctrl_p, fctrl, file);
3205796c8dcSSimon Schubert   fprintf_filtered (file, "Tag Word:            %s\n",
321*ef5ccd6cSJohn Marino 		    ftag_p ? hex_string_custom (ftag, 4) : _("<unavailable>"));
3225796c8dcSSimon Schubert   fprintf_filtered (file, "Instruction Pointer: %s:",
323*ef5ccd6cSJohn Marino 		    fiseg_p ? hex_string_custom (fiseg, 2) : _("<unavailable>"));
324*ef5ccd6cSJohn Marino   fprintf_filtered (file, "%s\n",
325*ef5ccd6cSJohn Marino 		    fioff_p ? hex_string_custom (fioff, 8) : _("<unavailable>"));
3265796c8dcSSimon Schubert   fprintf_filtered (file, "Operand Pointer:     %s:",
327*ef5ccd6cSJohn Marino 		    foseg_p ? hex_string_custom (foseg, 2) : _("<unavailable>"));
328*ef5ccd6cSJohn Marino   fprintf_filtered (file, "%s\n",
329*ef5ccd6cSJohn Marino 		    fooff_p ? hex_string_custom (fooff, 8) : _("<unavailable>"));
3305796c8dcSSimon Schubert   fprintf_filtered (file, "Opcode:              %s\n",
331*ef5ccd6cSJohn Marino 		    fop_p
332*ef5ccd6cSJohn Marino 		    ? (hex_string_custom (fop ? (fop | 0xd800) : 0, 4))
333*ef5ccd6cSJohn Marino 		    : _("<unavailable>"));
3345796c8dcSSimon Schubert }
3355796c8dcSSimon Schubert 
3365796c8dcSSimon Schubert 
3375796c8dcSSimon Schubert /* Return nonzero if a value of type TYPE stored in register REGNUM
3385796c8dcSSimon Schubert    needs any special handling.  */
3395796c8dcSSimon Schubert 
3405796c8dcSSimon Schubert int
i387_convert_register_p(struct gdbarch * gdbarch,int regnum,struct type * type)341c50c785cSJohn Marino i387_convert_register_p (struct gdbarch *gdbarch, int regnum,
342c50c785cSJohn Marino 			 struct type *type)
3435796c8dcSSimon Schubert {
3445796c8dcSSimon Schubert   if (i386_fp_regnum_p (gdbarch, regnum))
3455796c8dcSSimon Schubert     {
3465796c8dcSSimon Schubert       /* Floating point registers must be converted unless we are
3475796c8dcSSimon Schubert 	 accessing them in their hardware type.  */
3485796c8dcSSimon Schubert       if (type == i387_ext_type (gdbarch))
3495796c8dcSSimon Schubert 	return 0;
3505796c8dcSSimon Schubert       else
3515796c8dcSSimon Schubert 	return 1;
3525796c8dcSSimon Schubert     }
3535796c8dcSSimon Schubert 
3545796c8dcSSimon Schubert   return 0;
3555796c8dcSSimon Schubert }
3565796c8dcSSimon Schubert 
3575796c8dcSSimon Schubert /* Read a value of type TYPE from register REGNUM in frame FRAME, and
3585796c8dcSSimon Schubert    return its contents in TO.  */
3595796c8dcSSimon Schubert 
360c50c785cSJohn Marino int
i387_register_to_value(struct frame_info * frame,int regnum,struct type * type,gdb_byte * to,int * optimizedp,int * unavailablep)3615796c8dcSSimon Schubert i387_register_to_value (struct frame_info *frame, int regnum,
362c50c785cSJohn Marino 			struct type *type, gdb_byte *to,
363c50c785cSJohn Marino 			int *optimizedp, int *unavailablep)
3645796c8dcSSimon Schubert {
3655796c8dcSSimon Schubert   struct gdbarch *gdbarch = get_frame_arch (frame);
3665796c8dcSSimon Schubert   gdb_byte from[I386_MAX_REGISTER_SIZE];
3675796c8dcSSimon Schubert 
3685796c8dcSSimon Schubert   gdb_assert (i386_fp_regnum_p (gdbarch, regnum));
3695796c8dcSSimon Schubert 
3705796c8dcSSimon Schubert   /* We only support floating-point values.  */
3715796c8dcSSimon Schubert   if (TYPE_CODE (type) != TYPE_CODE_FLT)
3725796c8dcSSimon Schubert     {
3735796c8dcSSimon Schubert       warning (_("Cannot convert floating-point register value "
3745796c8dcSSimon Schubert 	       "to non-floating-point type."));
375c50c785cSJohn Marino       *optimizedp = *unavailablep = 0;
376c50c785cSJohn Marino       return 0;
3775796c8dcSSimon Schubert     }
3785796c8dcSSimon Schubert 
3795796c8dcSSimon Schubert   /* Convert to TYPE.  */
380c50c785cSJohn Marino   if (!get_frame_register_bytes (frame, regnum, 0, TYPE_LENGTH (type),
381c50c785cSJohn Marino 				 from, optimizedp, unavailablep))
382c50c785cSJohn Marino     return 0;
383c50c785cSJohn Marino 
3845796c8dcSSimon Schubert   convert_typed_floating (from, i387_ext_type (gdbarch), to, type);
385c50c785cSJohn Marino   *optimizedp = *unavailablep = 0;
386c50c785cSJohn Marino   return 1;
3875796c8dcSSimon Schubert }
3885796c8dcSSimon Schubert 
3895796c8dcSSimon Schubert /* Write the contents FROM of a value of type TYPE into register
3905796c8dcSSimon Schubert    REGNUM in frame FRAME.  */
3915796c8dcSSimon Schubert 
3925796c8dcSSimon Schubert void
i387_value_to_register(struct frame_info * frame,int regnum,struct type * type,const gdb_byte * from)3935796c8dcSSimon Schubert i387_value_to_register (struct frame_info *frame, int regnum,
3945796c8dcSSimon Schubert 			struct type *type, const gdb_byte *from)
3955796c8dcSSimon Schubert {
3965796c8dcSSimon Schubert   struct gdbarch *gdbarch = get_frame_arch (frame);
3975796c8dcSSimon Schubert   gdb_byte to[I386_MAX_REGISTER_SIZE];
3985796c8dcSSimon Schubert 
3995796c8dcSSimon Schubert   gdb_assert (i386_fp_regnum_p (gdbarch, regnum));
4005796c8dcSSimon Schubert 
4015796c8dcSSimon Schubert   /* We only support floating-point values.  */
4025796c8dcSSimon Schubert   if (TYPE_CODE (type) != TYPE_CODE_FLT)
4035796c8dcSSimon Schubert     {
4045796c8dcSSimon Schubert       warning (_("Cannot convert non-floating-point type "
4055796c8dcSSimon Schubert 	       "to floating-point register value."));
4065796c8dcSSimon Schubert       return;
4075796c8dcSSimon Schubert     }
4085796c8dcSSimon Schubert 
4095796c8dcSSimon Schubert   /* Convert from TYPE.  */
4105796c8dcSSimon Schubert   convert_typed_floating (from, type, to, i387_ext_type (gdbarch));
4115796c8dcSSimon Schubert   put_frame_register (frame, regnum, to);
4125796c8dcSSimon Schubert }
4135796c8dcSSimon Schubert 
4145796c8dcSSimon Schubert 
4155796c8dcSSimon Schubert /* Handle FSAVE and FXSAVE formats.  */
4165796c8dcSSimon Schubert 
4175796c8dcSSimon Schubert /* At fsave_offset[REGNUM] you'll find the offset to the location in
4185796c8dcSSimon Schubert    the data structure used by the "fsave" instruction where GDB
4195796c8dcSSimon Schubert    register REGNUM is stored.  */
4205796c8dcSSimon Schubert 
4215796c8dcSSimon Schubert static int fsave_offset[] =
4225796c8dcSSimon Schubert {
4235796c8dcSSimon Schubert   28 + 0 * 10,			/* %st(0) ...  */
4245796c8dcSSimon Schubert   28 + 1 * 10,
4255796c8dcSSimon Schubert   28 + 2 * 10,
4265796c8dcSSimon Schubert   28 + 3 * 10,
4275796c8dcSSimon Schubert   28 + 4 * 10,
4285796c8dcSSimon Schubert   28 + 5 * 10,
4295796c8dcSSimon Schubert   28 + 6 * 10,
4305796c8dcSSimon Schubert   28 + 7 * 10,			/* ... %st(7).  */
4315796c8dcSSimon Schubert   0,				/* `fctrl' (16 bits).  */
4325796c8dcSSimon Schubert   4,				/* `fstat' (16 bits).  */
4335796c8dcSSimon Schubert   8,				/* `ftag' (16 bits).  */
4345796c8dcSSimon Schubert   16,				/* `fiseg' (16 bits).  */
4355796c8dcSSimon Schubert   12,				/* `fioff'.  */
4365796c8dcSSimon Schubert   24,				/* `foseg' (16 bits).  */
4375796c8dcSSimon Schubert   20,				/* `fooff'.  */
4385796c8dcSSimon Schubert   18				/* `fop' (bottom 11 bits).  */
4395796c8dcSSimon Schubert };
4405796c8dcSSimon Schubert 
4415796c8dcSSimon Schubert #define FSAVE_ADDR(tdep, fsave, regnum) \
4425796c8dcSSimon Schubert   (fsave + fsave_offset[regnum - I387_ST0_REGNUM (tdep)])
4435796c8dcSSimon Schubert 
4445796c8dcSSimon Schubert 
4455796c8dcSSimon Schubert /* Fill register REGNUM in REGCACHE with the appropriate value from
4465796c8dcSSimon Schubert    *FSAVE.  This function masks off any of the reserved bits in
4475796c8dcSSimon Schubert    *FSAVE.  */
4485796c8dcSSimon Schubert 
4495796c8dcSSimon Schubert void
i387_supply_fsave(struct regcache * regcache,int regnum,const void * fsave)4505796c8dcSSimon Schubert i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave)
4515796c8dcSSimon Schubert {
4525796c8dcSSimon Schubert   struct gdbarch *gdbarch = get_regcache_arch (regcache);
4535796c8dcSSimon Schubert   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
4545796c8dcSSimon Schubert   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
4555796c8dcSSimon Schubert   const gdb_byte *regs = fsave;
4565796c8dcSSimon Schubert   int i;
4575796c8dcSSimon Schubert 
4585796c8dcSSimon Schubert   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
4595796c8dcSSimon Schubert 
4605796c8dcSSimon Schubert   for (i = I387_ST0_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
4615796c8dcSSimon Schubert     if (regnum == -1 || regnum == i)
4625796c8dcSSimon Schubert       {
4635796c8dcSSimon Schubert 	if (fsave == NULL)
4645796c8dcSSimon Schubert 	  {
4655796c8dcSSimon Schubert 	    regcache_raw_supply (regcache, i, NULL);
4665796c8dcSSimon Schubert 	    continue;
4675796c8dcSSimon Schubert 	  }
4685796c8dcSSimon Schubert 
4695796c8dcSSimon Schubert 	/* Most of the FPU control registers occupy only 16 bits in the
4705796c8dcSSimon Schubert 	   fsave area.  Give those a special treatment.  */
4715796c8dcSSimon Schubert 	if (i >= I387_FCTRL_REGNUM (tdep)
4725796c8dcSSimon Schubert 	    && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep))
4735796c8dcSSimon Schubert 	  {
4745796c8dcSSimon Schubert 	    gdb_byte val[4];
4755796c8dcSSimon Schubert 
4765796c8dcSSimon Schubert 	    memcpy (val, FSAVE_ADDR (tdep, regs, i), 2);
4775796c8dcSSimon Schubert 	    val[2] = val[3] = 0;
4785796c8dcSSimon Schubert 	    if (i == I387_FOP_REGNUM (tdep))
4795796c8dcSSimon Schubert 	      val[1] &= ((1 << 3) - 1);
4805796c8dcSSimon Schubert 	    regcache_raw_supply (regcache, i, val);
4815796c8dcSSimon Schubert 	  }
4825796c8dcSSimon Schubert 	else
4835796c8dcSSimon Schubert 	  regcache_raw_supply (regcache, i, FSAVE_ADDR (tdep, regs, i));
4845796c8dcSSimon Schubert       }
4855796c8dcSSimon Schubert 
4865796c8dcSSimon Schubert   /* Provide dummy values for the SSE registers.  */
4875796c8dcSSimon Schubert   for (i = I387_XMM0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++)
4885796c8dcSSimon Schubert     if (regnum == -1 || regnum == i)
4895796c8dcSSimon Schubert       regcache_raw_supply (regcache, i, NULL);
4905796c8dcSSimon Schubert   if (regnum == -1 || regnum == I387_MXCSR_REGNUM (tdep))
4915796c8dcSSimon Schubert     {
4925796c8dcSSimon Schubert       gdb_byte buf[4];
4935796c8dcSSimon Schubert 
4945796c8dcSSimon Schubert       store_unsigned_integer (buf, 4, byte_order, 0x1f80);
4955796c8dcSSimon Schubert       regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), buf);
4965796c8dcSSimon Schubert     }
4975796c8dcSSimon Schubert }
4985796c8dcSSimon Schubert 
4995796c8dcSSimon Schubert /* Fill register REGNUM (if it is a floating-point register) in *FSAVE
5005796c8dcSSimon Schubert    with the value from REGCACHE.  If REGNUM is -1, do this for all
5015796c8dcSSimon Schubert    registers.  This function doesn't touch any of the reserved bits in
5025796c8dcSSimon Schubert    *FSAVE.  */
5035796c8dcSSimon Schubert 
5045796c8dcSSimon Schubert void
i387_collect_fsave(const struct regcache * regcache,int regnum,void * fsave)5055796c8dcSSimon Schubert i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave)
5065796c8dcSSimon Schubert {
5075796c8dcSSimon Schubert   struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
5085796c8dcSSimon Schubert   gdb_byte *regs = fsave;
5095796c8dcSSimon Schubert   int i;
5105796c8dcSSimon Schubert 
5115796c8dcSSimon Schubert   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
5125796c8dcSSimon Schubert 
5135796c8dcSSimon Schubert   for (i = I387_ST0_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
5145796c8dcSSimon Schubert     if (regnum == -1 || regnum == i)
5155796c8dcSSimon Schubert       {
5165796c8dcSSimon Schubert 	/* Most of the FPU control registers occupy only 16 bits in
5175796c8dcSSimon Schubert            the fsave area.  Give those a special treatment.  */
5185796c8dcSSimon Schubert 	if (i >= I387_FCTRL_REGNUM (tdep)
5195796c8dcSSimon Schubert 	    && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep))
5205796c8dcSSimon Schubert 	  {
5215796c8dcSSimon Schubert 	    gdb_byte buf[4];
5225796c8dcSSimon Schubert 
5235796c8dcSSimon Schubert 	    regcache_raw_collect (regcache, i, buf);
5245796c8dcSSimon Schubert 
5255796c8dcSSimon Schubert 	    if (i == I387_FOP_REGNUM (tdep))
5265796c8dcSSimon Schubert 	      {
5275796c8dcSSimon Schubert 		/* The opcode occupies only 11 bits.  Make sure we
5285796c8dcSSimon Schubert                    don't touch the other bits.  */
5295796c8dcSSimon Schubert 		buf[1] &= ((1 << 3) - 1);
5305796c8dcSSimon Schubert 		buf[1] |= ((FSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1));
5315796c8dcSSimon Schubert 	      }
5325796c8dcSSimon Schubert 	    memcpy (FSAVE_ADDR (tdep, regs, i), buf, 2);
5335796c8dcSSimon Schubert 	  }
5345796c8dcSSimon Schubert 	else
5355796c8dcSSimon Schubert 	  regcache_raw_collect (regcache, i, FSAVE_ADDR (tdep, regs, i));
5365796c8dcSSimon Schubert       }
5375796c8dcSSimon Schubert }
5385796c8dcSSimon Schubert 
5395796c8dcSSimon Schubert 
5405796c8dcSSimon Schubert /* At fxsave_offset[REGNUM] you'll find the offset to the location in
5415796c8dcSSimon Schubert    the data structure used by the "fxsave" instruction where GDB
5425796c8dcSSimon Schubert    register REGNUM is stored.  */
5435796c8dcSSimon Schubert 
5445796c8dcSSimon Schubert static int fxsave_offset[] =
5455796c8dcSSimon Schubert {
5465796c8dcSSimon Schubert   32,				/* %st(0) through ...  */
5475796c8dcSSimon Schubert   48,
5485796c8dcSSimon Schubert   64,
5495796c8dcSSimon Schubert   80,
5505796c8dcSSimon Schubert   96,
5515796c8dcSSimon Schubert   112,
5525796c8dcSSimon Schubert   128,
5535796c8dcSSimon Schubert   144,				/* ... %st(7) (80 bits each).  */
5545796c8dcSSimon Schubert   0,				/* `fctrl' (16 bits).  */
5555796c8dcSSimon Schubert   2,				/* `fstat' (16 bits).  */
5565796c8dcSSimon Schubert   4,				/* `ftag' (16 bits).  */
5575796c8dcSSimon Schubert   12,				/* `fiseg' (16 bits).  */
5585796c8dcSSimon Schubert   8,				/* `fioff'.  */
5595796c8dcSSimon Schubert   20,				/* `foseg' (16 bits).  */
5605796c8dcSSimon Schubert   16,				/* `fooff'.  */
5615796c8dcSSimon Schubert   6,				/* `fop' (bottom 11 bits).  */
5625796c8dcSSimon Schubert   160 + 0 * 16,			/* %xmm0 through ...  */
5635796c8dcSSimon Schubert   160 + 1 * 16,
5645796c8dcSSimon Schubert   160 + 2 * 16,
5655796c8dcSSimon Schubert   160 + 3 * 16,
5665796c8dcSSimon Schubert   160 + 4 * 16,
5675796c8dcSSimon Schubert   160 + 5 * 16,
5685796c8dcSSimon Schubert   160 + 6 * 16,
5695796c8dcSSimon Schubert   160 + 7 * 16,
5705796c8dcSSimon Schubert   160 + 8 * 16,
5715796c8dcSSimon Schubert   160 + 9 * 16,
5725796c8dcSSimon Schubert   160 + 10 * 16,
5735796c8dcSSimon Schubert   160 + 11 * 16,
5745796c8dcSSimon Schubert   160 + 12 * 16,
5755796c8dcSSimon Schubert   160 + 13 * 16,
5765796c8dcSSimon Schubert   160 + 14 * 16,
5775796c8dcSSimon Schubert   160 + 15 * 16,		/* ... %xmm15 (128 bits each).  */
5785796c8dcSSimon Schubert };
5795796c8dcSSimon Schubert 
5805796c8dcSSimon Schubert #define FXSAVE_ADDR(tdep, fxsave, regnum) \
5815796c8dcSSimon Schubert   (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM (tdep)])
5825796c8dcSSimon Schubert 
5835796c8dcSSimon Schubert /* We made an unfortunate choice in putting %mxcsr after the SSE
5845796c8dcSSimon Schubert    registers %xmm0-%xmm7 instead of before, since it makes supporting
5855796c8dcSSimon Schubert    the registers %xmm8-%xmm15 on AMD64 a bit involved.  Therefore we
5865796c8dcSSimon Schubert    don't include the offset for %mxcsr here above.  */
5875796c8dcSSimon Schubert 
5885796c8dcSSimon Schubert #define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24)
5895796c8dcSSimon Schubert 
5905796c8dcSSimon Schubert static int i387_tag (const gdb_byte *raw);
5915796c8dcSSimon Schubert 
5925796c8dcSSimon Schubert 
5935796c8dcSSimon Schubert /* Fill register REGNUM in REGCACHE with the appropriate
5945796c8dcSSimon Schubert    floating-point or SSE register value from *FXSAVE.  This function
5955796c8dcSSimon Schubert    masks off any of the reserved bits in *FXSAVE.  */
5965796c8dcSSimon Schubert 
5975796c8dcSSimon Schubert void
i387_supply_fxsave(struct regcache * regcache,int regnum,const void * fxsave)5985796c8dcSSimon Schubert i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave)
5995796c8dcSSimon Schubert {
6005796c8dcSSimon Schubert   struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
6015796c8dcSSimon Schubert   const gdb_byte *regs = fxsave;
6025796c8dcSSimon Schubert   int i;
6035796c8dcSSimon Schubert 
6045796c8dcSSimon Schubert   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
6055796c8dcSSimon Schubert   gdb_assert (tdep->num_xmm_regs > 0);
6065796c8dcSSimon Schubert 
6075796c8dcSSimon Schubert   for (i = I387_ST0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++)
6085796c8dcSSimon Schubert     if (regnum == -1 || regnum == i)
6095796c8dcSSimon Schubert       {
6105796c8dcSSimon Schubert 	if (regs == NULL)
6115796c8dcSSimon Schubert 	  {
6125796c8dcSSimon Schubert 	    regcache_raw_supply (regcache, i, NULL);
6135796c8dcSSimon Schubert 	    continue;
6145796c8dcSSimon Schubert 	  }
6155796c8dcSSimon Schubert 
6165796c8dcSSimon Schubert 	/* Most of the FPU control registers occupy only 16 bits in
6175796c8dcSSimon Schubert 	   the fxsave area.  Give those a special treatment.  */
6185796c8dcSSimon Schubert 	if (i >= I387_FCTRL_REGNUM (tdep) && i < I387_XMM0_REGNUM (tdep)
6195796c8dcSSimon Schubert 	    && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep))
6205796c8dcSSimon Schubert 	  {
6215796c8dcSSimon Schubert 	    gdb_byte val[4];
6225796c8dcSSimon Schubert 
6235796c8dcSSimon Schubert 	    memcpy (val, FXSAVE_ADDR (tdep, regs, i), 2);
6245796c8dcSSimon Schubert 	    val[2] = val[3] = 0;
6255796c8dcSSimon Schubert 	    if (i == I387_FOP_REGNUM (tdep))
6265796c8dcSSimon Schubert 	      val[1] &= ((1 << 3) - 1);
6275796c8dcSSimon Schubert 	    else if (i== I387_FTAG_REGNUM (tdep))
6285796c8dcSSimon Schubert 	      {
6295796c8dcSSimon Schubert 		/* The fxsave area contains a simplified version of
6305796c8dcSSimon Schubert 		   the tag word.  We have to look at the actual 80-bit
6315796c8dcSSimon Schubert 		   FP data to recreate the traditional i387 tag word.  */
6325796c8dcSSimon Schubert 
6335796c8dcSSimon Schubert 		unsigned long ftag = 0;
6345796c8dcSSimon Schubert 		int fpreg;
6355796c8dcSSimon Schubert 		int top;
6365796c8dcSSimon Schubert 
6375796c8dcSSimon Schubert 		top = ((FXSAVE_ADDR (tdep, regs,
6385796c8dcSSimon Schubert 				     I387_FSTAT_REGNUM (tdep)))[1] >> 3);
6395796c8dcSSimon Schubert 		top &= 0x7;
6405796c8dcSSimon Schubert 
6415796c8dcSSimon Schubert 		for (fpreg = 7; fpreg >= 0; fpreg--)
6425796c8dcSSimon Schubert 		  {
6435796c8dcSSimon Schubert 		    int tag;
6445796c8dcSSimon Schubert 
6455796c8dcSSimon Schubert 		    if (val[0] & (1 << fpreg))
6465796c8dcSSimon Schubert 		      {
647c50c785cSJohn Marino 			int thisreg = (fpreg + 8 - top) % 8
6485796c8dcSSimon Schubert 			               + I387_ST0_REGNUM (tdep);
649c50c785cSJohn Marino 			tag = i387_tag (FXSAVE_ADDR (tdep, regs, thisreg));
6505796c8dcSSimon Schubert 		      }
6515796c8dcSSimon Schubert 		    else
6525796c8dcSSimon Schubert 		      tag = 3;		/* Empty */
6535796c8dcSSimon Schubert 
6545796c8dcSSimon Schubert 		    ftag |= tag << (2 * fpreg);
6555796c8dcSSimon Schubert 		  }
6565796c8dcSSimon Schubert 		val[0] = ftag & 0xff;
6575796c8dcSSimon Schubert 		val[1] = (ftag >> 8) & 0xff;
6585796c8dcSSimon Schubert 	      }
6595796c8dcSSimon Schubert 	    regcache_raw_supply (regcache, i, val);
6605796c8dcSSimon Schubert 	  }
6615796c8dcSSimon Schubert 	else
6625796c8dcSSimon Schubert 	  regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
6635796c8dcSSimon Schubert       }
6645796c8dcSSimon Schubert 
6655796c8dcSSimon Schubert   if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
6665796c8dcSSimon Schubert     {
6675796c8dcSSimon Schubert       if (regs == NULL)
6685796c8dcSSimon Schubert 	regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), NULL);
6695796c8dcSSimon Schubert       else
6705796c8dcSSimon Schubert 	regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
6715796c8dcSSimon Schubert 			     FXSAVE_MXCSR_ADDR (regs));
6725796c8dcSSimon Schubert     }
6735796c8dcSSimon Schubert }
6745796c8dcSSimon Schubert 
6755796c8dcSSimon Schubert /* Fill register REGNUM (if it is a floating-point or SSE register) in
6765796c8dcSSimon Schubert    *FXSAVE with the value from REGCACHE.  If REGNUM is -1, do this for
6775796c8dcSSimon Schubert    all registers.  This function doesn't touch any of the reserved
6785796c8dcSSimon Schubert    bits in *FXSAVE.  */
6795796c8dcSSimon Schubert 
6805796c8dcSSimon Schubert void
i387_collect_fxsave(const struct regcache * regcache,int regnum,void * fxsave)6815796c8dcSSimon Schubert i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave)
6825796c8dcSSimon Schubert {
6835796c8dcSSimon Schubert   struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
6845796c8dcSSimon Schubert   gdb_byte *regs = fxsave;
6855796c8dcSSimon Schubert   int i;
6865796c8dcSSimon Schubert 
6875796c8dcSSimon Schubert   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
6885796c8dcSSimon Schubert   gdb_assert (tdep->num_xmm_regs > 0);
6895796c8dcSSimon Schubert 
6905796c8dcSSimon Schubert   for (i = I387_ST0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++)
6915796c8dcSSimon Schubert     if (regnum == -1 || regnum == i)
6925796c8dcSSimon Schubert       {
6935796c8dcSSimon Schubert 	/* Most of the FPU control registers occupy only 16 bits in
6945796c8dcSSimon Schubert            the fxsave area.  Give those a special treatment.  */
6955796c8dcSSimon Schubert 	if (i >= I387_FCTRL_REGNUM (tdep) && i < I387_XMM0_REGNUM (tdep)
6965796c8dcSSimon Schubert 	    && i != I387_FIOFF_REGNUM (tdep) && i != I387_FOOFF_REGNUM (tdep))
6975796c8dcSSimon Schubert 	  {
6985796c8dcSSimon Schubert 	    gdb_byte buf[4];
6995796c8dcSSimon Schubert 
7005796c8dcSSimon Schubert 	    regcache_raw_collect (regcache, i, buf);
7015796c8dcSSimon Schubert 
7025796c8dcSSimon Schubert 	    if (i == I387_FOP_REGNUM (tdep))
7035796c8dcSSimon Schubert 	      {
7045796c8dcSSimon Schubert 		/* The opcode occupies only 11 bits.  Make sure we
7055796c8dcSSimon Schubert                    don't touch the other bits.  */
7065796c8dcSSimon Schubert 		buf[1] &= ((1 << 3) - 1);
7075796c8dcSSimon Schubert 		buf[1] |= ((FXSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1));
7085796c8dcSSimon Schubert 	      }
7095796c8dcSSimon Schubert 	    else if (i == I387_FTAG_REGNUM (tdep))
7105796c8dcSSimon Schubert 	      {
7115796c8dcSSimon Schubert 		/* Converting back is much easier.  */
7125796c8dcSSimon Schubert 
7135796c8dcSSimon Schubert 		unsigned short ftag;
7145796c8dcSSimon Schubert 		int fpreg;
7155796c8dcSSimon Schubert 
7165796c8dcSSimon Schubert 		ftag = (buf[1] << 8) | buf[0];
7175796c8dcSSimon Schubert 		buf[0] = 0;
7185796c8dcSSimon Schubert 		buf[1] = 0;
7195796c8dcSSimon Schubert 
7205796c8dcSSimon Schubert 		for (fpreg = 7; fpreg >= 0; fpreg--)
7215796c8dcSSimon Schubert 		  {
7225796c8dcSSimon Schubert 		    int tag = (ftag >> (fpreg * 2)) & 3;
7235796c8dcSSimon Schubert 
7245796c8dcSSimon Schubert 		    if (tag != 3)
7255796c8dcSSimon Schubert 		      buf[0] |= (1 << fpreg);
7265796c8dcSSimon Schubert 		  }
7275796c8dcSSimon Schubert 	      }
7285796c8dcSSimon Schubert 	    memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2);
7295796c8dcSSimon Schubert 	  }
7305796c8dcSSimon Schubert 	else
7315796c8dcSSimon Schubert 	  regcache_raw_collect (regcache, i, FXSAVE_ADDR (tdep, regs, i));
7325796c8dcSSimon Schubert       }
7335796c8dcSSimon Schubert 
7345796c8dcSSimon Schubert   if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
7355796c8dcSSimon Schubert     regcache_raw_collect (regcache, I387_MXCSR_REGNUM (tdep),
7365796c8dcSSimon Schubert 			  FXSAVE_MXCSR_ADDR (regs));
7375796c8dcSSimon Schubert }
7385796c8dcSSimon Schubert 
739cf7f2e2dSJohn Marino /* `xstate_bv' is at byte offset 512.  */
740cf7f2e2dSJohn Marino #define XSAVE_XSTATE_BV_ADDR(xsave) (xsave + 512)
741cf7f2e2dSJohn Marino 
742cf7f2e2dSJohn Marino /* At xsave_avxh_offset[REGNUM] you'll find the offset to the location in
743cf7f2e2dSJohn Marino    the upper 128bit of AVX register data structure used by the "xsave"
744cf7f2e2dSJohn Marino    instruction where GDB register REGNUM is stored.  */
745cf7f2e2dSJohn Marino 
746cf7f2e2dSJohn Marino static int xsave_avxh_offset[] =
747cf7f2e2dSJohn Marino {
748cf7f2e2dSJohn Marino   576 + 0 * 16,		/* Upper 128bit of %ymm0 through ...  */
749cf7f2e2dSJohn Marino   576 + 1 * 16,
750cf7f2e2dSJohn Marino   576 + 2 * 16,
751cf7f2e2dSJohn Marino   576 + 3 * 16,
752cf7f2e2dSJohn Marino   576 + 4 * 16,
753cf7f2e2dSJohn Marino   576 + 5 * 16,
754cf7f2e2dSJohn Marino   576 + 6 * 16,
755cf7f2e2dSJohn Marino   576 + 7 * 16,
756cf7f2e2dSJohn Marino   576 + 8 * 16,
757cf7f2e2dSJohn Marino   576 + 9 * 16,
758cf7f2e2dSJohn Marino   576 + 10 * 16,
759cf7f2e2dSJohn Marino   576 + 11 * 16,
760cf7f2e2dSJohn Marino   576 + 12 * 16,
761cf7f2e2dSJohn Marino   576 + 13 * 16,
762cf7f2e2dSJohn Marino   576 + 14 * 16,
763cf7f2e2dSJohn Marino   576 + 15 * 16		/* Upper 128bit of ... %ymm15 (128 bits each).  */
764cf7f2e2dSJohn Marino };
765cf7f2e2dSJohn Marino 
766cf7f2e2dSJohn Marino #define XSAVE_AVXH_ADDR(tdep, xsave, regnum) \
767cf7f2e2dSJohn Marino   (xsave + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
768cf7f2e2dSJohn Marino 
769cf7f2e2dSJohn Marino /* Similar to i387_supply_fxsave, but use XSAVE extended state.  */
770cf7f2e2dSJohn Marino 
771cf7f2e2dSJohn Marino void
i387_supply_xsave(struct regcache * regcache,int regnum,const void * xsave)772cf7f2e2dSJohn Marino i387_supply_xsave (struct regcache *regcache, int regnum,
773cf7f2e2dSJohn Marino 		   const void *xsave)
774cf7f2e2dSJohn Marino {
775cf7f2e2dSJohn Marino   struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
776cf7f2e2dSJohn Marino   const gdb_byte *regs = xsave;
777cf7f2e2dSJohn Marino   int i;
778cf7f2e2dSJohn Marino   unsigned int clear_bv;
779a45ae5f8SJohn Marino   static const gdb_byte zero[MAX_REGISTER_SIZE] = { 0 };
780cf7f2e2dSJohn Marino   enum
781cf7f2e2dSJohn Marino     {
782cf7f2e2dSJohn Marino       none = 0x0,
783cf7f2e2dSJohn Marino       x87 = 0x1,
784cf7f2e2dSJohn Marino       sse = 0x2,
785cf7f2e2dSJohn Marino       avxh = 0x4,
786cf7f2e2dSJohn Marino       all = x87 | sse | avxh
787cf7f2e2dSJohn Marino     } regclass;
788cf7f2e2dSJohn Marino 
789*ef5ccd6cSJohn Marino   gdb_assert (regs != NULL);
790cf7f2e2dSJohn Marino   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
791cf7f2e2dSJohn Marino   gdb_assert (tdep->num_xmm_regs > 0);
792cf7f2e2dSJohn Marino 
793cf7f2e2dSJohn Marino   if (regnum == -1)
794cf7f2e2dSJohn Marino     regclass = all;
795cf7f2e2dSJohn Marino   else if (regnum >= I387_YMM0H_REGNUM (tdep)
796cf7f2e2dSJohn Marino 	   && regnum < I387_YMMENDH_REGNUM (tdep))
797cf7f2e2dSJohn Marino     regclass = avxh;
798cf7f2e2dSJohn Marino   else if (regnum >= I387_XMM0_REGNUM(tdep)
799cf7f2e2dSJohn Marino 	   && regnum < I387_MXCSR_REGNUM (tdep))
800cf7f2e2dSJohn Marino     regclass = sse;
801cf7f2e2dSJohn Marino   else if (regnum >= I387_ST0_REGNUM (tdep)
802cf7f2e2dSJohn Marino 	   && regnum < I387_FCTRL_REGNUM (tdep))
803cf7f2e2dSJohn Marino     regclass = x87;
804cf7f2e2dSJohn Marino   else
805cf7f2e2dSJohn Marino     regclass = none;
806cf7f2e2dSJohn Marino 
807*ef5ccd6cSJohn Marino   if (regclass != none)
808cf7f2e2dSJohn Marino     {
809cf7f2e2dSJohn Marino       /* Get `xstat_bv'.  */
810cf7f2e2dSJohn Marino       const gdb_byte *xstate_bv_p = XSAVE_XSTATE_BV_ADDR (regs);
811cf7f2e2dSJohn Marino 
812cf7f2e2dSJohn Marino       /* The supported bits in `xstat_bv' are 1 byte.  Clear part in
813cf7f2e2dSJohn Marino 	 vector registers if its bit in xstat_bv is zero.  */
814cf7f2e2dSJohn Marino       clear_bv = (~(*xstate_bv_p)) & tdep->xcr0;
815cf7f2e2dSJohn Marino     }
816cf7f2e2dSJohn Marino   else
817cf7f2e2dSJohn Marino     clear_bv = I386_XSTATE_AVX_MASK;
818cf7f2e2dSJohn Marino 
819a45ae5f8SJohn Marino   /* With the delayed xsave mechanism, in between the program
820a45ae5f8SJohn Marino      starting, and the program accessing the vector registers for the
821a45ae5f8SJohn Marino      first time, the register's values are invalid.  The kernel
822a45ae5f8SJohn Marino      initializes register states to zero when they are set the first
823a45ae5f8SJohn Marino      time in a program.  This means that from the user-space programs'
824a45ae5f8SJohn Marino      perspective, it's the same as if the registers have always been
825a45ae5f8SJohn Marino      zero from the start of the program.  Therefore, the debugger
826*ef5ccd6cSJohn Marino      should provide the same illusion to the user.  */
827a45ae5f8SJohn Marino 
828cf7f2e2dSJohn Marino   switch (regclass)
829cf7f2e2dSJohn Marino     {
830cf7f2e2dSJohn Marino     case none:
831cf7f2e2dSJohn Marino       break;
832cf7f2e2dSJohn Marino 
833cf7f2e2dSJohn Marino     case avxh:
834cf7f2e2dSJohn Marino       if ((clear_bv & I386_XSTATE_AVX))
835*ef5ccd6cSJohn Marino 	regcache_raw_supply (regcache, regnum, zero);
836cf7f2e2dSJohn Marino       else
837a45ae5f8SJohn Marino 	regcache_raw_supply (regcache, regnum,
838a45ae5f8SJohn Marino 			     XSAVE_AVXH_ADDR (tdep, regs, regnum));
839cf7f2e2dSJohn Marino       return;
840cf7f2e2dSJohn Marino 
841cf7f2e2dSJohn Marino     case sse:
842cf7f2e2dSJohn Marino       if ((clear_bv & I386_XSTATE_SSE))
843*ef5ccd6cSJohn Marino 	regcache_raw_supply (regcache, regnum, zero);
844cf7f2e2dSJohn Marino       else
845a45ae5f8SJohn Marino 	regcache_raw_supply (regcache, regnum,
846a45ae5f8SJohn Marino 			     FXSAVE_ADDR (tdep, regs, regnum));
847cf7f2e2dSJohn Marino       return;
848cf7f2e2dSJohn Marino 
849cf7f2e2dSJohn Marino     case x87:
850cf7f2e2dSJohn Marino       if ((clear_bv & I386_XSTATE_X87))
851*ef5ccd6cSJohn Marino 	regcache_raw_supply (regcache, regnum, zero);
852cf7f2e2dSJohn Marino       else
853a45ae5f8SJohn Marino 	regcache_raw_supply (regcache, regnum,
854a45ae5f8SJohn Marino 			     FXSAVE_ADDR (tdep, regs, regnum));
855cf7f2e2dSJohn Marino       return;
856cf7f2e2dSJohn Marino 
857cf7f2e2dSJohn Marino     case all:
858a45ae5f8SJohn Marino       /* Handle the upper YMM registers.  */
859cf7f2e2dSJohn Marino       if ((tdep->xcr0 & I386_XSTATE_AVX))
860cf7f2e2dSJohn Marino 	{
861cf7f2e2dSJohn Marino 	  if ((clear_bv & I386_XSTATE_AVX))
862cf7f2e2dSJohn Marino 	    {
863a45ae5f8SJohn Marino 	      for (i = I387_YMM0H_REGNUM (tdep);
864a45ae5f8SJohn Marino 		   i < I387_YMMENDH_REGNUM (tdep);
865a45ae5f8SJohn Marino 		   i++)
866*ef5ccd6cSJohn Marino 		regcache_raw_supply (regcache, i, zero);
867a45ae5f8SJohn Marino 	    }
868a45ae5f8SJohn Marino 	  else
869a45ae5f8SJohn Marino 	    {
870a45ae5f8SJohn Marino 	      for (i = I387_YMM0H_REGNUM (tdep);
871a45ae5f8SJohn Marino 		   i < I387_YMMENDH_REGNUM (tdep);
872a45ae5f8SJohn Marino 		   i++)
873a45ae5f8SJohn Marino 		regcache_raw_supply (regcache, i,
874a45ae5f8SJohn Marino 				     XSAVE_AVXH_ADDR (tdep, regs, i));
875cf7f2e2dSJohn Marino 	    }
876cf7f2e2dSJohn Marino 	}
877cf7f2e2dSJohn Marino 
878cf7f2e2dSJohn Marino       /* Handle the XMM registers.  */
879cf7f2e2dSJohn Marino       if ((tdep->xcr0 & I386_XSTATE_SSE))
880cf7f2e2dSJohn Marino 	{
881cf7f2e2dSJohn Marino 	  if ((clear_bv & I386_XSTATE_SSE))
882a45ae5f8SJohn Marino 	    {
883a45ae5f8SJohn Marino 	      for (i = I387_XMM0_REGNUM (tdep);
884a45ae5f8SJohn Marino 		   i < I387_MXCSR_REGNUM (tdep);
885a45ae5f8SJohn Marino 		   i++)
886*ef5ccd6cSJohn Marino 		regcache_raw_supply (regcache, i, zero);
887a45ae5f8SJohn Marino 	    }
888cf7f2e2dSJohn Marino 	  else
889a45ae5f8SJohn Marino 	    {
890cf7f2e2dSJohn Marino 	      for (i = I387_XMM0_REGNUM (tdep);
891cf7f2e2dSJohn Marino 		   i < I387_MXCSR_REGNUM (tdep); i++)
892a45ae5f8SJohn Marino 		regcache_raw_supply (regcache, i,
893a45ae5f8SJohn Marino 				     FXSAVE_ADDR (tdep, regs, i));
894cf7f2e2dSJohn Marino 	    }
895cf7f2e2dSJohn Marino 	}
896cf7f2e2dSJohn Marino 
897cf7f2e2dSJohn Marino       /* Handle the x87 registers.  */
898cf7f2e2dSJohn Marino       if ((tdep->xcr0 & I386_XSTATE_X87))
899cf7f2e2dSJohn Marino 	{
900cf7f2e2dSJohn Marino 	  if ((clear_bv & I386_XSTATE_X87))
901cf7f2e2dSJohn Marino 	    {
902a45ae5f8SJohn Marino 	      for (i = I387_ST0_REGNUM (tdep);
903a45ae5f8SJohn Marino 		   i < I387_FCTRL_REGNUM (tdep);
904a45ae5f8SJohn Marino 		   i++)
905*ef5ccd6cSJohn Marino 		regcache_raw_supply (regcache, i, zero);
906a45ae5f8SJohn Marino 	    }
907a45ae5f8SJohn Marino 	  else
908a45ae5f8SJohn Marino 	    {
909a45ae5f8SJohn Marino 	      for (i = I387_ST0_REGNUM (tdep);
910a45ae5f8SJohn Marino 		   i < I387_FCTRL_REGNUM (tdep);
911a45ae5f8SJohn Marino 		   i++)
912a45ae5f8SJohn Marino 		regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
913cf7f2e2dSJohn Marino 	    }
914cf7f2e2dSJohn Marino 	}
915cf7f2e2dSJohn Marino       break;
916cf7f2e2dSJohn Marino     }
917cf7f2e2dSJohn Marino 
918cf7f2e2dSJohn Marino   /* Only handle x87 control registers.  */
919cf7f2e2dSJohn Marino   for (i = I387_FCTRL_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
920cf7f2e2dSJohn Marino     if (regnum == -1 || regnum == i)
921cf7f2e2dSJohn Marino       {
922cf7f2e2dSJohn Marino 	/* Most of the FPU control registers occupy only 16 bits in
923cf7f2e2dSJohn Marino 	   the xsave extended state.  Give those a special treatment.  */
924cf7f2e2dSJohn Marino 	if (i != I387_FIOFF_REGNUM (tdep)
925cf7f2e2dSJohn Marino 	    && i != I387_FOOFF_REGNUM (tdep))
926cf7f2e2dSJohn Marino 	  {
927cf7f2e2dSJohn Marino 	    gdb_byte val[4];
928cf7f2e2dSJohn Marino 
929cf7f2e2dSJohn Marino 	    memcpy (val, FXSAVE_ADDR (tdep, regs, i), 2);
930cf7f2e2dSJohn Marino 	    val[2] = val[3] = 0;
931cf7f2e2dSJohn Marino 	    if (i == I387_FOP_REGNUM (tdep))
932cf7f2e2dSJohn Marino 	      val[1] &= ((1 << 3) - 1);
933cf7f2e2dSJohn Marino 	    else if (i== I387_FTAG_REGNUM (tdep))
934cf7f2e2dSJohn Marino 	      {
935cf7f2e2dSJohn Marino 		/* The fxsave area contains a simplified version of
936cf7f2e2dSJohn Marino 		   the tag word.  We have to look at the actual 80-bit
937cf7f2e2dSJohn Marino 		   FP data to recreate the traditional i387 tag word.  */
938cf7f2e2dSJohn Marino 
939cf7f2e2dSJohn Marino 		unsigned long ftag = 0;
940cf7f2e2dSJohn Marino 		int fpreg;
941cf7f2e2dSJohn Marino 		int top;
942cf7f2e2dSJohn Marino 
943cf7f2e2dSJohn Marino 		top = ((FXSAVE_ADDR (tdep, regs,
944cf7f2e2dSJohn Marino 				     I387_FSTAT_REGNUM (tdep)))[1] >> 3);
945cf7f2e2dSJohn Marino 		top &= 0x7;
946cf7f2e2dSJohn Marino 
947cf7f2e2dSJohn Marino 		for (fpreg = 7; fpreg >= 0; fpreg--)
948cf7f2e2dSJohn Marino 		  {
949cf7f2e2dSJohn Marino 		    int tag;
950cf7f2e2dSJohn Marino 
951cf7f2e2dSJohn Marino 		    if (val[0] & (1 << fpreg))
952cf7f2e2dSJohn Marino 		      {
953c50c785cSJohn Marino 			int thisreg = (fpreg + 8 - top) % 8
954cf7f2e2dSJohn Marino 				       + I387_ST0_REGNUM (tdep);
955c50c785cSJohn Marino 			tag = i387_tag (FXSAVE_ADDR (tdep, regs, thisreg));
956cf7f2e2dSJohn Marino 		      }
957cf7f2e2dSJohn Marino 		    else
958cf7f2e2dSJohn Marino 		      tag = 3;		/* Empty */
959cf7f2e2dSJohn Marino 
960cf7f2e2dSJohn Marino 		    ftag |= tag << (2 * fpreg);
961cf7f2e2dSJohn Marino 		  }
962cf7f2e2dSJohn Marino 		val[0] = ftag & 0xff;
963cf7f2e2dSJohn Marino 		val[1] = (ftag >> 8) & 0xff;
964cf7f2e2dSJohn Marino 	      }
965cf7f2e2dSJohn Marino 	    regcache_raw_supply (regcache, i, val);
966cf7f2e2dSJohn Marino 	  }
967cf7f2e2dSJohn Marino 	else
968cf7f2e2dSJohn Marino 	  regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
969cf7f2e2dSJohn Marino       }
970cf7f2e2dSJohn Marino 
971cf7f2e2dSJohn Marino   if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
972*ef5ccd6cSJohn Marino     regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
973*ef5ccd6cSJohn Marino 			 FXSAVE_MXCSR_ADDR (regs));
974cf7f2e2dSJohn Marino }
975cf7f2e2dSJohn Marino 
976cf7f2e2dSJohn Marino /* Similar to i387_collect_fxsave, but use XSAVE extended state.  */
977cf7f2e2dSJohn Marino 
978cf7f2e2dSJohn Marino void
i387_collect_xsave(const struct regcache * regcache,int regnum,void * xsave,int gcore)979cf7f2e2dSJohn Marino i387_collect_xsave (const struct regcache *regcache, int regnum,
980cf7f2e2dSJohn Marino 		    void *xsave, int gcore)
981cf7f2e2dSJohn Marino {
982cf7f2e2dSJohn Marino   struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
983cf7f2e2dSJohn Marino   gdb_byte *regs = xsave;
984cf7f2e2dSJohn Marino   int i;
985cf7f2e2dSJohn Marino   enum
986cf7f2e2dSJohn Marino     {
987cf7f2e2dSJohn Marino       none = 0x0,
988cf7f2e2dSJohn Marino       check = 0x1,
989cf7f2e2dSJohn Marino       x87 = 0x2 | check,
990cf7f2e2dSJohn Marino       sse = 0x4 | check,
991cf7f2e2dSJohn Marino       avxh = 0x8 | check,
992cf7f2e2dSJohn Marino       all = x87 | sse | avxh
993cf7f2e2dSJohn Marino     } regclass;
994cf7f2e2dSJohn Marino 
995cf7f2e2dSJohn Marino   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
996cf7f2e2dSJohn Marino   gdb_assert (tdep->num_xmm_regs > 0);
997cf7f2e2dSJohn Marino 
998cf7f2e2dSJohn Marino   if (regnum == -1)
999cf7f2e2dSJohn Marino     regclass = all;
1000cf7f2e2dSJohn Marino   else if (regnum >= I387_YMM0H_REGNUM (tdep)
1001cf7f2e2dSJohn Marino 	   && regnum < I387_YMMENDH_REGNUM (tdep))
1002cf7f2e2dSJohn Marino     regclass = avxh;
1003cf7f2e2dSJohn Marino   else if (regnum >= I387_XMM0_REGNUM(tdep)
1004cf7f2e2dSJohn Marino 	   && regnum < I387_MXCSR_REGNUM (tdep))
1005cf7f2e2dSJohn Marino     regclass = sse;
1006cf7f2e2dSJohn Marino   else if (regnum >= I387_ST0_REGNUM (tdep)
1007cf7f2e2dSJohn Marino 	   && regnum < I387_FCTRL_REGNUM (tdep))
1008cf7f2e2dSJohn Marino     regclass = x87;
1009cf7f2e2dSJohn Marino   else
1010cf7f2e2dSJohn Marino     regclass = none;
1011cf7f2e2dSJohn Marino 
1012cf7f2e2dSJohn Marino   if (gcore)
1013cf7f2e2dSJohn Marino     {
1014cf7f2e2dSJohn Marino       /* Clear XSAVE extended state.  */
1015cf7f2e2dSJohn Marino       memset (regs, 0, I386_XSTATE_SIZE (tdep->xcr0));
1016cf7f2e2dSJohn Marino 
1017cf7f2e2dSJohn Marino       /* Update XCR0 and `xstate_bv' with XCR0 for gcore.  */
1018cf7f2e2dSJohn Marino       if (tdep->xsave_xcr0_offset != -1)
1019cf7f2e2dSJohn Marino 	memcpy (regs + tdep->xsave_xcr0_offset, &tdep->xcr0, 8);
1020cf7f2e2dSJohn Marino       memcpy (XSAVE_XSTATE_BV_ADDR (regs), &tdep->xcr0, 8);
1021cf7f2e2dSJohn Marino     }
1022cf7f2e2dSJohn Marino 
1023cf7f2e2dSJohn Marino   if ((regclass & check))
1024cf7f2e2dSJohn Marino     {
1025cf7f2e2dSJohn Marino       gdb_byte raw[I386_MAX_REGISTER_SIZE];
1026cf7f2e2dSJohn Marino       gdb_byte *xstate_bv_p = XSAVE_XSTATE_BV_ADDR (regs);
1027cf7f2e2dSJohn Marino       unsigned int xstate_bv = 0;
1028cf7f2e2dSJohn Marino       /* The supported bits in `xstat_bv' are 1 byte.  */
1029cf7f2e2dSJohn Marino       unsigned int clear_bv = (~(*xstate_bv_p)) & tdep->xcr0;
1030cf7f2e2dSJohn Marino       gdb_byte *p;
1031cf7f2e2dSJohn Marino 
1032cf7f2e2dSJohn Marino       /* Clear register set if its bit in xstat_bv is zero.  */
1033cf7f2e2dSJohn Marino       if (clear_bv)
1034cf7f2e2dSJohn Marino 	{
1035cf7f2e2dSJohn Marino 	  if ((clear_bv & I386_XSTATE_AVX))
1036cf7f2e2dSJohn Marino 	    for (i = I387_YMM0H_REGNUM (tdep);
1037cf7f2e2dSJohn Marino 		 i < I387_YMMENDH_REGNUM (tdep); i++)
1038cf7f2e2dSJohn Marino 	      memset (XSAVE_AVXH_ADDR (tdep, regs, i), 0, 16);
1039cf7f2e2dSJohn Marino 
1040cf7f2e2dSJohn Marino 	  if ((clear_bv & I386_XSTATE_SSE))
1041cf7f2e2dSJohn Marino 	    for (i = I387_XMM0_REGNUM (tdep);
1042cf7f2e2dSJohn Marino 		 i < I387_MXCSR_REGNUM (tdep); i++)
1043cf7f2e2dSJohn Marino 	      memset (FXSAVE_ADDR (tdep, regs, i), 0, 16);
1044cf7f2e2dSJohn Marino 
1045cf7f2e2dSJohn Marino 	  if ((clear_bv & I386_XSTATE_X87))
1046cf7f2e2dSJohn Marino 	    for (i = I387_ST0_REGNUM (tdep);
1047cf7f2e2dSJohn Marino 		 i < I387_FCTRL_REGNUM (tdep); i++)
1048cf7f2e2dSJohn Marino 	      memset (FXSAVE_ADDR (tdep, regs, i), 0, 10);
1049cf7f2e2dSJohn Marino 	}
1050cf7f2e2dSJohn Marino 
1051cf7f2e2dSJohn Marino       if (regclass == all)
1052cf7f2e2dSJohn Marino 	{
1053cf7f2e2dSJohn Marino 	  /* Check if any upper YMM registers are changed.  */
1054cf7f2e2dSJohn Marino 	  if ((tdep->xcr0 & I386_XSTATE_AVX))
1055cf7f2e2dSJohn Marino 	    for (i = I387_YMM0H_REGNUM (tdep);
1056cf7f2e2dSJohn Marino 		 i < I387_YMMENDH_REGNUM (tdep); i++)
1057cf7f2e2dSJohn Marino 	      {
1058cf7f2e2dSJohn Marino 		regcache_raw_collect (regcache, i, raw);
1059cf7f2e2dSJohn Marino 		p = XSAVE_AVXH_ADDR (tdep, regs, i);
1060cf7f2e2dSJohn Marino 		if (memcmp (raw, p, 16))
1061cf7f2e2dSJohn Marino 		  {
1062cf7f2e2dSJohn Marino 		    xstate_bv |= I386_XSTATE_AVX;
1063cf7f2e2dSJohn Marino 		    memcpy (p, raw, 16);
1064cf7f2e2dSJohn Marino 		  }
1065cf7f2e2dSJohn Marino 	      }
1066cf7f2e2dSJohn Marino 
1067cf7f2e2dSJohn Marino 	  /* Check if any SSE registers are changed.  */
1068cf7f2e2dSJohn Marino 	  if ((tdep->xcr0 & I386_XSTATE_SSE))
1069cf7f2e2dSJohn Marino 	    for (i = I387_XMM0_REGNUM (tdep);
1070cf7f2e2dSJohn Marino 		 i < I387_MXCSR_REGNUM (tdep); i++)
1071cf7f2e2dSJohn Marino 	      {
1072cf7f2e2dSJohn Marino 		regcache_raw_collect (regcache, i, raw);
1073cf7f2e2dSJohn Marino 		p = FXSAVE_ADDR (tdep, regs, i);
1074cf7f2e2dSJohn Marino 		if (memcmp (raw, p, 16))
1075cf7f2e2dSJohn Marino 		  {
1076cf7f2e2dSJohn Marino 		    xstate_bv |= I386_XSTATE_SSE;
1077cf7f2e2dSJohn Marino 		    memcpy (p, raw, 16);
1078cf7f2e2dSJohn Marino 		  }
1079cf7f2e2dSJohn Marino 	      }
1080cf7f2e2dSJohn Marino 
1081cf7f2e2dSJohn Marino 	  /* Check if any X87 registers are changed.  */
1082cf7f2e2dSJohn Marino 	  if ((tdep->xcr0 & I386_XSTATE_X87))
1083cf7f2e2dSJohn Marino 	    for (i = I387_ST0_REGNUM (tdep);
1084cf7f2e2dSJohn Marino 		 i < I387_FCTRL_REGNUM (tdep); i++)
1085cf7f2e2dSJohn Marino 	      {
1086cf7f2e2dSJohn Marino 		regcache_raw_collect (regcache, i, raw);
1087cf7f2e2dSJohn Marino 		p = FXSAVE_ADDR (tdep, regs, i);
1088cf7f2e2dSJohn Marino 		if (memcmp (raw, p, 10))
1089cf7f2e2dSJohn Marino 		  {
1090cf7f2e2dSJohn Marino 		    xstate_bv |= I386_XSTATE_X87;
1091cf7f2e2dSJohn Marino 		    memcpy (p, raw, 10);
1092cf7f2e2dSJohn Marino 		  }
1093cf7f2e2dSJohn Marino 	      }
1094cf7f2e2dSJohn Marino 	}
1095cf7f2e2dSJohn Marino       else
1096cf7f2e2dSJohn Marino 	{
1097cf7f2e2dSJohn Marino 	  /* Check if REGNUM is changed.  */
1098cf7f2e2dSJohn Marino 	  regcache_raw_collect (regcache, regnum, raw);
1099cf7f2e2dSJohn Marino 
1100cf7f2e2dSJohn Marino 	  switch (regclass)
1101cf7f2e2dSJohn Marino 	    {
1102cf7f2e2dSJohn Marino 	    default:
1103cf7f2e2dSJohn Marino 	      internal_error (__FILE__, __LINE__,
1104cf7f2e2dSJohn Marino 			      _("invalid i387 regclass"));
1105cf7f2e2dSJohn Marino 
1106cf7f2e2dSJohn Marino 	    case avxh:
1107cf7f2e2dSJohn Marino 	      /* This is an upper YMM register.  */
1108cf7f2e2dSJohn Marino 	      p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
1109cf7f2e2dSJohn Marino 	      if (memcmp (raw, p, 16))
1110cf7f2e2dSJohn Marino 		{
1111cf7f2e2dSJohn Marino 		  xstate_bv |= I386_XSTATE_AVX;
1112cf7f2e2dSJohn Marino 		  memcpy (p, raw, 16);
1113cf7f2e2dSJohn Marino 		}
1114cf7f2e2dSJohn Marino 	      break;
1115cf7f2e2dSJohn Marino 
1116cf7f2e2dSJohn Marino 	    case sse:
1117cf7f2e2dSJohn Marino 	      /* This is an SSE register.  */
1118cf7f2e2dSJohn Marino 	      p = FXSAVE_ADDR (tdep, regs, regnum);
1119cf7f2e2dSJohn Marino 	      if (memcmp (raw, p, 16))
1120cf7f2e2dSJohn Marino 		{
1121cf7f2e2dSJohn Marino 		  xstate_bv |= I386_XSTATE_SSE;
1122cf7f2e2dSJohn Marino 		  memcpy (p, raw, 16);
1123cf7f2e2dSJohn Marino 		}
1124cf7f2e2dSJohn Marino 	      break;
1125cf7f2e2dSJohn Marino 
1126cf7f2e2dSJohn Marino 	    case x87:
1127cf7f2e2dSJohn Marino 	      /* This is an x87 register.  */
1128cf7f2e2dSJohn Marino 	      p = FXSAVE_ADDR (tdep, regs, regnum);
1129cf7f2e2dSJohn Marino 	      if (memcmp (raw, p, 10))
1130cf7f2e2dSJohn Marino 		{
1131cf7f2e2dSJohn Marino 		  xstate_bv |= I386_XSTATE_X87;
1132cf7f2e2dSJohn Marino 		  memcpy (p, raw, 10);
1133cf7f2e2dSJohn Marino 		}
1134cf7f2e2dSJohn Marino 	      break;
1135cf7f2e2dSJohn Marino 	    }
1136cf7f2e2dSJohn Marino 	}
1137cf7f2e2dSJohn Marino 
1138cf7f2e2dSJohn Marino       /* Update the corresponding bits in `xstate_bv' if any SSE/AVX
1139cf7f2e2dSJohn Marino 	 registers are changed.  */
1140cf7f2e2dSJohn Marino       if (xstate_bv)
1141cf7f2e2dSJohn Marino 	{
1142cf7f2e2dSJohn Marino 	  /* The supported bits in `xstat_bv' are 1 byte.  */
1143cf7f2e2dSJohn Marino 	  *xstate_bv_p |= (gdb_byte) xstate_bv;
1144cf7f2e2dSJohn Marino 
1145cf7f2e2dSJohn Marino 	  switch (regclass)
1146cf7f2e2dSJohn Marino 	    {
1147cf7f2e2dSJohn Marino 	    default:
1148cf7f2e2dSJohn Marino 	      internal_error (__FILE__, __LINE__,
1149cf7f2e2dSJohn Marino 			      _("invalid i387 regclass"));
1150cf7f2e2dSJohn Marino 
1151cf7f2e2dSJohn Marino 	    case all:
1152cf7f2e2dSJohn Marino 	      break;
1153cf7f2e2dSJohn Marino 
1154cf7f2e2dSJohn Marino 	    case x87:
1155cf7f2e2dSJohn Marino 	    case sse:
1156cf7f2e2dSJohn Marino 	    case avxh:
1157cf7f2e2dSJohn Marino 	      /* Register REGNUM has been updated.  Return.  */
1158cf7f2e2dSJohn Marino 	      return;
1159cf7f2e2dSJohn Marino 	    }
1160cf7f2e2dSJohn Marino 	}
1161cf7f2e2dSJohn Marino       else
1162cf7f2e2dSJohn Marino 	{
1163cf7f2e2dSJohn Marino 	  /* Return if REGNUM isn't changed.  */
1164cf7f2e2dSJohn Marino 	  if (regclass != all)
1165cf7f2e2dSJohn Marino 	    return;
1166cf7f2e2dSJohn Marino 	}
1167cf7f2e2dSJohn Marino     }
1168cf7f2e2dSJohn Marino 
1169cf7f2e2dSJohn Marino   /* Only handle x87 control registers.  */
1170cf7f2e2dSJohn Marino   for (i = I387_FCTRL_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++)
1171cf7f2e2dSJohn Marino     if (regnum == -1 || regnum == i)
1172cf7f2e2dSJohn Marino       {
1173cf7f2e2dSJohn Marino 	/* Most of the FPU control registers occupy only 16 bits in
1174cf7f2e2dSJohn Marino 	   the xsave extended state.  Give those a special treatment.  */
1175cf7f2e2dSJohn Marino 	if (i != I387_FIOFF_REGNUM (tdep)
1176cf7f2e2dSJohn Marino 	    && i != I387_FOOFF_REGNUM (tdep))
1177cf7f2e2dSJohn Marino 	  {
1178cf7f2e2dSJohn Marino 	    gdb_byte buf[4];
1179cf7f2e2dSJohn Marino 
1180cf7f2e2dSJohn Marino 	    regcache_raw_collect (regcache, i, buf);
1181cf7f2e2dSJohn Marino 
1182cf7f2e2dSJohn Marino 	    if (i == I387_FOP_REGNUM (tdep))
1183cf7f2e2dSJohn Marino 	      {
1184cf7f2e2dSJohn Marino 		/* The opcode occupies only 11 bits.  Make sure we
1185cf7f2e2dSJohn Marino 		   don't touch the other bits.  */
1186cf7f2e2dSJohn Marino 		buf[1] &= ((1 << 3) - 1);
1187cf7f2e2dSJohn Marino 		buf[1] |= ((FXSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1));
1188cf7f2e2dSJohn Marino 	      }
1189cf7f2e2dSJohn Marino 	    else if (i == I387_FTAG_REGNUM (tdep))
1190cf7f2e2dSJohn Marino 	      {
1191cf7f2e2dSJohn Marino 		/* Converting back is much easier.  */
1192cf7f2e2dSJohn Marino 
1193cf7f2e2dSJohn Marino 		unsigned short ftag;
1194cf7f2e2dSJohn Marino 		int fpreg;
1195cf7f2e2dSJohn Marino 
1196cf7f2e2dSJohn Marino 		ftag = (buf[1] << 8) | buf[0];
1197cf7f2e2dSJohn Marino 		buf[0] = 0;
1198cf7f2e2dSJohn Marino 		buf[1] = 0;
1199cf7f2e2dSJohn Marino 
1200cf7f2e2dSJohn Marino 		for (fpreg = 7; fpreg >= 0; fpreg--)
1201cf7f2e2dSJohn Marino 		  {
1202cf7f2e2dSJohn Marino 		    int tag = (ftag >> (fpreg * 2)) & 3;
1203cf7f2e2dSJohn Marino 
1204cf7f2e2dSJohn Marino 		    if (tag != 3)
1205cf7f2e2dSJohn Marino 		      buf[0] |= (1 << fpreg);
1206cf7f2e2dSJohn Marino 		  }
1207cf7f2e2dSJohn Marino 	      }
1208cf7f2e2dSJohn Marino 	    memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2);
1209cf7f2e2dSJohn Marino 	  }
1210cf7f2e2dSJohn Marino 	else
1211cf7f2e2dSJohn Marino 	  regcache_raw_collect (regcache, i, FXSAVE_ADDR (tdep, regs, i));
1212cf7f2e2dSJohn Marino       }
1213cf7f2e2dSJohn Marino 
1214cf7f2e2dSJohn Marino   if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1)
1215cf7f2e2dSJohn Marino     regcache_raw_collect (regcache, I387_MXCSR_REGNUM (tdep),
1216cf7f2e2dSJohn Marino 			  FXSAVE_MXCSR_ADDR (regs));
1217cf7f2e2dSJohn Marino }
1218cf7f2e2dSJohn Marino 
12195796c8dcSSimon Schubert /* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
12205796c8dcSSimon Schubert    *RAW.  */
12215796c8dcSSimon Schubert 
12225796c8dcSSimon Schubert static int
i387_tag(const gdb_byte * raw)12235796c8dcSSimon Schubert i387_tag (const gdb_byte *raw)
12245796c8dcSSimon Schubert {
12255796c8dcSSimon Schubert   int integer;
12265796c8dcSSimon Schubert   unsigned int exponent;
12275796c8dcSSimon Schubert   unsigned long fraction[2];
12285796c8dcSSimon Schubert 
12295796c8dcSSimon Schubert   integer = raw[7] & 0x80;
12305796c8dcSSimon Schubert   exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
12315796c8dcSSimon Schubert   fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
12325796c8dcSSimon Schubert   fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
12335796c8dcSSimon Schubert 		 | (raw[5] << 8) | raw[4]);
12345796c8dcSSimon Schubert 
12355796c8dcSSimon Schubert   if (exponent == 0x7fff)
12365796c8dcSSimon Schubert     {
12375796c8dcSSimon Schubert       /* Special.  */
12385796c8dcSSimon Schubert       return (2);
12395796c8dcSSimon Schubert     }
12405796c8dcSSimon Schubert   else if (exponent == 0x0000)
12415796c8dcSSimon Schubert     {
12425796c8dcSSimon Schubert       if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
12435796c8dcSSimon Schubert 	{
12445796c8dcSSimon Schubert 	  /* Zero.  */
12455796c8dcSSimon Schubert 	  return (1);
12465796c8dcSSimon Schubert 	}
12475796c8dcSSimon Schubert       else
12485796c8dcSSimon Schubert 	{
12495796c8dcSSimon Schubert 	  /* Special.  */
12505796c8dcSSimon Schubert 	  return (2);
12515796c8dcSSimon Schubert 	}
12525796c8dcSSimon Schubert     }
12535796c8dcSSimon Schubert   else
12545796c8dcSSimon Schubert     {
12555796c8dcSSimon Schubert       if (integer)
12565796c8dcSSimon Schubert 	{
12575796c8dcSSimon Schubert 	  /* Valid.  */
12585796c8dcSSimon Schubert 	  return (0);
12595796c8dcSSimon Schubert 	}
12605796c8dcSSimon Schubert       else
12615796c8dcSSimon Schubert 	{
12625796c8dcSSimon Schubert 	  /* Special.  */
12635796c8dcSSimon Schubert 	  return (2);
12645796c8dcSSimon Schubert 	}
12655796c8dcSSimon Schubert     }
12665796c8dcSSimon Schubert }
12675796c8dcSSimon Schubert 
12685796c8dcSSimon Schubert /* Prepare the FPU stack in REGCACHE for a function return.  */
12695796c8dcSSimon Schubert 
12705796c8dcSSimon Schubert void
i387_return_value(struct gdbarch * gdbarch,struct regcache * regcache)12715796c8dcSSimon Schubert i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache)
12725796c8dcSSimon Schubert {
12735796c8dcSSimon Schubert   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
12745796c8dcSSimon Schubert   ULONGEST fstat;
12755796c8dcSSimon Schubert 
12765796c8dcSSimon Schubert   /* Set the top of the floating-point register stack to 7.  The
12775796c8dcSSimon Schubert      actual value doesn't really matter, but 7 is what a normal
12785796c8dcSSimon Schubert      function return would end up with if the program started out with
12795796c8dcSSimon Schubert      a freshly initialized FPU.  */
12805796c8dcSSimon Schubert   regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM (tdep), &fstat);
12815796c8dcSSimon Schubert   fstat |= (7 << 11);
12825796c8dcSSimon Schubert   regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM (tdep), fstat);
12835796c8dcSSimon Schubert 
12845796c8dcSSimon Schubert   /* Mark %st(1) through %st(7) as empty.  Since we set the top of the
12855796c8dcSSimon Schubert      floating-point register stack to 7, the appropriate value for the
12865796c8dcSSimon Schubert      tag word is 0x3fff.  */
12875796c8dcSSimon Schubert   regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM (tdep), 0x3fff);
12885796c8dcSSimon Schubert 
12895796c8dcSSimon Schubert }
1290