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