X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fi387-tdep.c;h=6c3763d037f0d76dc4e5095baa8f82a836afa6ae;hb=d3ecddab5fc036fb57588a9bfff73575dc419052;hp=4c32e09ce5870c809c6ee50b7b04dcab4d59b191;hpb=31aeac7844e6e347a01fa69178fd1014e69578c0;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c index 4c32e09ce5..6c3763d037 100644 --- a/gdb/i387-tdep.c +++ b/gdb/i387-tdep.c @@ -1,8 +1,6 @@ /* Intel 387 floating point stuff. - Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 1988-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -20,21 +18,17 @@ along with this program. If not, see . */ #include "defs.h" -#include "doublest.h" -#include "floatformat.h" #include "frame.h" #include "gdbcore.h" #include "inferior.h" #include "language.h" #include "regcache.h" +#include "target-float.h" #include "value.h" -#include "gdb_assert.h" -#include "gdb_string.h" - #include "i386-tdep.h" #include "i387-tdep.h" -#include "i386-xstate.h" +#include "gdbsupport/x86-xstate.h" /* Print the floating point number specified by RAW. */ @@ -42,23 +36,13 @@ static void print_i387_value (struct gdbarch *gdbarch, const gdb_byte *raw, struct ui_file *file) { - DOUBLEST value; - - /* Using extract_typed_floating here might affect the representation - of certain numbers such as NaNs, even if GDB is running natively. - This is fine since our caller already detects such special - numbers and we print the hexadecimal representation anyway. */ - value = extract_typed_floating (raw, i387_ext_type (gdbarch)); - /* We try to print 19 digits. The last digit may or may not contain garbage, but we'd better print one too many. We need enough room to print the value, 1 position for the sign, 1 for the decimal point, 19 for the digits and 6 for the exponent adds up to 27. */ -#ifdef PRINTF_HAS_LONG_DOUBLE - fprintf_filtered (file, " %-+27.19Lg", (long double) value); -#else - fprintf_filtered (file, " %-+27.19g", (double) value); -#endif + const struct type *type = i387_ext_type (gdbarch); + std::string str = target_float_to_string (raw, type, " %-+27.19g"); + fprintf_filtered (file, "%s", str.c_str ()); } /* Print the classification for the register contents RAW. */ @@ -114,13 +98,21 @@ print_i387_ext (struct gdbarch *gdbarch, fputs_filtered (" Unsupported", file); } -/* Print the status word STATUS. */ +/* Print the status word STATUS. If STATUS_P is false, then STATUS + was unavailable. */ static void -print_i387_status_word (unsigned int status, struct ui_file *file) +print_i387_status_word (int status_p, + unsigned int status, struct ui_file *file) { - fprintf_filtered (file, "Status Word: %s", - hex_string_custom (status, 4)); + fprintf_filtered (file, "Status Word: "); + if (!status_p) + { + fprintf_filtered (file, "%s\n", _("")); + return; + } + + fprintf_filtered (file, "%s", hex_string_custom (status, 4)); fputs_filtered (" ", file); fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : " "); fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : " "); @@ -144,13 +136,21 @@ print_i387_status_word (unsigned int status, struct ui_file *file) " TOP: %d\n", ((status >> 11) & 7)); } -/* Print the control word CONTROL. */ +/* Print the control word CONTROL. If CONTROL_P is false, then + CONTROL was unavailable. */ static void -print_i387_control_word (unsigned int control, struct ui_file *file) +print_i387_control_word (int control_p, + unsigned int control, struct ui_file *file) { - fprintf_filtered (file, "Control Word: %s", - hex_string_custom (control, 4)); + fprintf_filtered (file, "Control Word: "); + if (!control_p) + { + fprintf_filtered (file, "%s\n", _("")); + return; + } + + fprintf_filtered (file, "%s", hex_string_custom (control, 4)); fputs_filtered (" ", file); fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : " "); fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : " "); @@ -205,82 +205,118 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, const char *args) { struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame)); - gdb_byte buf[4]; ULONGEST fctrl; + int fctrl_p; ULONGEST fstat; + int fstat_p; ULONGEST ftag; + int ftag_p; ULONGEST fiseg; + int fiseg_p; ULONGEST fioff; + int fioff_p; ULONGEST foseg; + int foseg_p; ULONGEST fooff; + int fooff_p; ULONGEST fop; + int fop_p; int fpreg; int top; gdb_assert (gdbarch == get_frame_arch (frame)); - fctrl = get_frame_register_unsigned (frame, I387_FCTRL_REGNUM (tdep)); - fstat = get_frame_register_unsigned (frame, I387_FSTAT_REGNUM (tdep)); - ftag = get_frame_register_unsigned (frame, I387_FTAG_REGNUM (tdep)); - fiseg = get_frame_register_unsigned (frame, I387_FISEG_REGNUM (tdep)); - fioff = get_frame_register_unsigned (frame, I387_FIOFF_REGNUM (tdep)); - foseg = get_frame_register_unsigned (frame, I387_FOSEG_REGNUM (tdep)); - fooff = get_frame_register_unsigned (frame, I387_FOOFF_REGNUM (tdep)); - fop = get_frame_register_unsigned (frame, I387_FOP_REGNUM (tdep)); + fctrl_p = read_frame_register_unsigned (frame, + I387_FCTRL_REGNUM (tdep), &fctrl); + fstat_p = read_frame_register_unsigned (frame, + I387_FSTAT_REGNUM (tdep), &fstat); + ftag_p = read_frame_register_unsigned (frame, + I387_FTAG_REGNUM (tdep), &ftag); + fiseg_p = read_frame_register_unsigned (frame, + I387_FISEG_REGNUM (tdep), &fiseg); + fioff_p = read_frame_register_unsigned (frame, + I387_FIOFF_REGNUM (tdep), &fioff); + foseg_p = read_frame_register_unsigned (frame, + I387_FOSEG_REGNUM (tdep), &foseg); + fooff_p = read_frame_register_unsigned (frame, + I387_FOOFF_REGNUM (tdep), &fooff); + fop_p = read_frame_register_unsigned (frame, + I387_FOP_REGNUM (tdep), &fop); + + if (fstat_p) + { + top = ((fstat >> 11) & 7); - top = ((fstat >> 11) & 7); + for (fpreg = 7; fpreg >= 0; fpreg--) + { + struct value *regval; + int regnum; + int i; + int tag = -1; - for (fpreg = 7; fpreg >= 0; fpreg--) - { - gdb_byte raw[I386_MAX_REGISTER_SIZE]; - int tag = (ftag >> (fpreg * 2)) & 3; - int i; + fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : " ", fpreg); - fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : " ", fpreg); + if (ftag_p) + { + tag = (ftag >> (fpreg * 2)) & 3; - switch (tag) - { - case 0: - fputs_filtered ("Valid ", file); - break; - case 1: - fputs_filtered ("Zero ", file); - break; - case 2: - fputs_filtered ("Special ", file); - break; - case 3: - fputs_filtered ("Empty ", file); - break; - } + switch (tag) + { + case 0: + fputs_filtered ("Valid ", file); + break; + case 1: + fputs_filtered ("Zero ", file); + break; + case 2: + fputs_filtered ("Special ", file); + break; + case 3: + fputs_filtered ("Empty ", file); + break; + } + } + else + fputs_filtered ("Unknown ", file); - get_frame_register (frame, (fpreg + 8 - top) % 8 + I387_ST0_REGNUM (tdep), - raw); + regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM (tdep); + regval = get_frame_register_value (frame, regnum); - fputs_filtered ("0x", file); - for (i = 9; i >= 0; i--) - fprintf_filtered (file, "%02x", raw[i]); + if (value_entirely_available (regval)) + { + const gdb_byte *raw = value_contents (regval); - if (tag != 3) - print_i387_ext (gdbarch, raw, file); + fputs_filtered ("0x", file); + for (i = 9; i >= 0; i--) + fprintf_filtered (file, "%02x", raw[i]); - fputs_filtered ("\n", file); + if (tag != -1 && tag != 3) + print_i387_ext (gdbarch, raw, file); + } + else + fprintf_filtered (file, "%s", _("")); + + fputs_filtered ("\n", file); + } } fputs_filtered ("\n", file); - - print_i387_status_word (fstat, file); - print_i387_control_word (fctrl, file); + print_i387_status_word (fstat_p, fstat, file); + print_i387_control_word (fctrl_p, fctrl, file); fprintf_filtered (file, "Tag Word: %s\n", - hex_string_custom (ftag, 4)); + ftag_p ? hex_string_custom (ftag, 4) : _("")); fprintf_filtered (file, "Instruction Pointer: %s:", - hex_string_custom (fiseg, 2)); - fprintf_filtered (file, "%s\n", hex_string_custom (fioff, 8)); + fiseg_p ? hex_string_custom (fiseg, 2) : _("")); + fprintf_filtered (file, "%s\n", + fioff_p ? hex_string_custom (fioff, 8) : _("")); fprintf_filtered (file, "Operand Pointer: %s:", - hex_string_custom (foseg, 2)); - fprintf_filtered (file, "%s\n", hex_string_custom (fooff, 8)); + foseg_p ? hex_string_custom (foseg, 2) : _("")); + fprintf_filtered (file, "%s\n", + fooff_p ? hex_string_custom (fooff, 8) : _("")); fprintf_filtered (file, "Opcode: %s\n", - hex_string_custom (fop ? (fop | 0xd800) : 0, 4)); + fop_p + ? (hex_string_custom (fop ? (fop | 0xd800) : 0, 4)) + : _("")); } @@ -288,13 +324,15 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, needs any special handling. */ int -i387_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type) +i387_convert_register_p (struct gdbarch *gdbarch, int regnum, + struct type *type) { if (i386_fp_regnum_p (gdbarch, regnum)) { /* Floating point registers must be converted unless we are - accessing them in their hardware type. */ - if (type == i387_ext_type (gdbarch)) + accessing them in their hardware type or TYPE is not float. */ + if (type == i387_ext_type (gdbarch) + || TYPE_CODE (type) != TYPE_CODE_FLT) return 0; else return 1; @@ -306,9 +344,10 @@ i387_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type) /* Read a value of type TYPE from register REGNUM in frame FRAME, and return its contents in TO. */ -void +int i387_register_to_value (struct frame_info *frame, int regnum, - struct type *type, gdb_byte *to) + struct type *type, gdb_byte *to, + int *optimizedp, int *unavailablep) { struct gdbarch *gdbarch = get_frame_arch (frame); gdb_byte from[I386_MAX_REGISTER_SIZE]; @@ -320,12 +359,19 @@ i387_register_to_value (struct frame_info *frame, int regnum, { warning (_("Cannot convert floating-point register value " "to non-floating-point type.")); - return; + *optimizedp = *unavailablep = 0; + return 0; } /* Convert to TYPE. */ - get_frame_register (frame, regnum, from); - convert_typed_floating (from, i387_ext_type (gdbarch), to, type); + if (!get_frame_register_bytes (frame, regnum, 0, + register_size (gdbarch, regnum), + from, optimizedp, unavailablep)) + return 0; + + target_float_convert (from, i387_ext_type (gdbarch), to, type); + *optimizedp = *unavailablep = 0; + return 1; } /* Write the contents FROM of a value of type TYPE into register @@ -349,7 +395,7 @@ i387_value_to_register (struct frame_info *frame, int regnum, } /* Convert from TYPE. */ - convert_typed_floating (from, type, to, i387_ext_type (gdbarch)); + target_float_convert (from, type, to, i387_ext_type (gdbarch)); put_frame_register (frame, regnum, to); } @@ -391,10 +437,10 @@ static int fsave_offset[] = void i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); - const gdb_byte *regs = fsave; + const gdb_byte *regs = (const gdb_byte *) fsave; int i; gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); @@ -404,7 +450,7 @@ i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave) { if (fsave == NULL) { - regcache_raw_supply (regcache, i, NULL); + regcache->raw_supply (i, NULL); continue; } @@ -419,22 +465,22 @@ i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave) val[2] = val[3] = 0; if (i == I387_FOP_REGNUM (tdep)) val[1] &= ((1 << 3) - 1); - regcache_raw_supply (regcache, i, val); + regcache->raw_supply (i, val); } else - regcache_raw_supply (regcache, i, FSAVE_ADDR (tdep, regs, i)); + regcache->raw_supply (i, FSAVE_ADDR (tdep, regs, i)); } /* Provide dummy values for the SSE registers. */ for (i = I387_XMM0_REGNUM (tdep); i < I387_MXCSR_REGNUM (tdep); i++) if (regnum == -1 || regnum == i) - regcache_raw_supply (regcache, i, NULL); + regcache->raw_supply (i, NULL); if (regnum == -1 || regnum == I387_MXCSR_REGNUM (tdep)) { gdb_byte buf[4]; - store_unsigned_integer (buf, 4, byte_order, 0x1f80); - regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), buf); + store_unsigned_integer (buf, 4, byte_order, I387_MXCSR_INIT_VAL); + regcache->raw_supply (I387_MXCSR_REGNUM (tdep), buf); } } @@ -446,8 +492,8 @@ i387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave) void i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave) { - struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); - gdb_byte *regs = fsave; + struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + gdb_byte *regs = (gdb_byte *) fsave; int i; gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); @@ -462,7 +508,7 @@ i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave) { gdb_byte buf[4]; - regcache_raw_collect (regcache, i, buf); + regcache->raw_collect (i, buf); if (i == I387_FOP_REGNUM (tdep)) { @@ -474,7 +520,7 @@ i387_collect_fsave (const struct regcache *regcache, int regnum, void *fsave) memcpy (FSAVE_ADDR (tdep, regs, i), buf, 2); } else - regcache_raw_collect (regcache, i, FSAVE_ADDR (tdep, regs, i)); + regcache->raw_collect (i, FSAVE_ADDR (tdep, regs, i)); } } @@ -539,8 +585,8 @@ static int i387_tag (const gdb_byte *raw); void i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave) { - struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); - const gdb_byte *regs = fxsave; + struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + const gdb_byte *regs = (const gdb_byte *) fxsave; int i; gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); @@ -551,7 +597,7 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave) { if (regs == NULL) { - regcache_raw_supply (regcache, i, NULL); + regcache->raw_supply (i, NULL); continue; } @@ -586,9 +632,9 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave) if (val[0] & (1 << fpreg)) { - int regnum = (fpreg + 8 - top) % 8 - + I387_ST0_REGNUM (tdep); - tag = i387_tag (FXSAVE_ADDR (tdep, regs, regnum)); + int thisreg = (fpreg + 8 - top) % 8 + + I387_ST0_REGNUM (tdep); + tag = i387_tag (FXSAVE_ADDR (tdep, regs, thisreg)); } else tag = 3; /* Empty */ @@ -598,18 +644,18 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave) val[0] = ftag & 0xff; val[1] = (ftag >> 8) & 0xff; } - regcache_raw_supply (regcache, i, val); + regcache->raw_supply (i, val); } else - regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i)); + regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i)); } if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1) { if (regs == NULL) - regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), NULL); + regcache->raw_supply (I387_MXCSR_REGNUM (tdep), NULL); else - regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), + regcache->raw_supply (I387_MXCSR_REGNUM (tdep), FXSAVE_MXCSR_ADDR (regs)); } } @@ -622,8 +668,8 @@ i387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave) void i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave) { - struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); - gdb_byte *regs = fxsave; + struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); + gdb_byte *regs = (gdb_byte *) fxsave; int i; gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); @@ -639,7 +685,7 @@ i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave) { gdb_byte buf[4]; - regcache_raw_collect (regcache, i, buf); + regcache->raw_collect (i, buf); if (i == I387_FOP_REGNUM (tdep)) { @@ -670,11 +716,11 @@ i387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave) memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2); } else - regcache_raw_collect (regcache, i, FXSAVE_ADDR (tdep, regs, i)); + regcache->raw_collect (i, FXSAVE_ADDR (tdep, regs, i)); } if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1) - regcache_raw_collect (regcache, I387_MXCSR_REGNUM (tdep), + regcache->raw_collect (I387_MXCSR_REGNUM (tdep), FXSAVE_MXCSR_ADDR (regs)); } @@ -708,35 +754,228 @@ static int xsave_avxh_offset[] = #define XSAVE_AVXH_ADDR(tdep, xsave, regnum) \ (xsave + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)]) +/* At xsave_ymm_avx512_offset[REGNUM] you'll find the offset to the location in + the upper 128bit of ZMM register data structure used by the "xsave" + instruction where GDB register REGNUM is stored. */ + +static int xsave_ymm_avx512_offset[] = +{ + /* HI16_ZMM_area + 16 bytes + regnum* 64 bytes. */ + 1664 + 16 + 0 * 64, /* %ymm16 through... */ + 1664 + 16 + 1 * 64, + 1664 + 16 + 2 * 64, + 1664 + 16 + 3 * 64, + 1664 + 16 + 4 * 64, + 1664 + 16 + 5 * 64, + 1664 + 16 + 6 * 64, + 1664 + 16 + 7 * 64, + 1664 + 16 + 8 * 64, + 1664 + 16 + 9 * 64, + 1664 + 16 + 10 * 64, + 1664 + 16 + 11 * 64, + 1664 + 16 + 12 * 64, + 1664 + 16 + 13 * 64, + 1664 + 16 + 14 * 64, + 1664 + 16 + 15 * 64 /* ... %ymm31 (128 bits each). */ +}; + +#define XSAVE_YMM_AVX512_ADDR(tdep, xsave, regnum) \ + (xsave + xsave_ymm_avx512_offset[regnum - I387_YMM16H_REGNUM (tdep)]) + +static int xsave_xmm_avx512_offset[] = +{ + 1664 + 0 * 64, /* %ymm16 through... */ + 1664 + 1 * 64, + 1664 + 2 * 64, + 1664 + 3 * 64, + 1664 + 4 * 64, + 1664 + 5 * 64, + 1664 + 6 * 64, + 1664 + 7 * 64, + 1664 + 8 * 64, + 1664 + 9 * 64, + 1664 + 10 * 64, + 1664 + 11 * 64, + 1664 + 12 * 64, + 1664 + 13 * 64, + 1664 + 14 * 64, + 1664 + 15 * 64 /* ... %ymm31 (128 bits each). */ +}; + +#define XSAVE_XMM_AVX512_ADDR(tdep, xsave, regnum) \ + (xsave + xsave_xmm_avx512_offset[regnum - I387_XMM16_REGNUM (tdep)]) + +static int xsave_mpx_offset[] = { + 960 + 0 * 16, /* bnd0r...bnd3r registers. */ + 960 + 1 * 16, + 960 + 2 * 16, + 960 + 3 * 16, + 1024 + 0 * 8, /* bndcfg ... bndstatus. */ + 1024 + 1 * 8, +}; + +#define XSAVE_MPX_ADDR(tdep, xsave, regnum) \ + (xsave + xsave_mpx_offset[regnum - I387_BND0R_REGNUM (tdep)]) + + /* At xsave_avx512__h_offset[REGNUM] you find the offset to the location + of the AVX512 opmask register data structure used by the "xsave" + instruction where GDB register REGNUM is stored. */ + +static int xsave_avx512_k_offset[] = +{ + 1088 + 0 * 8, /* %k0 through... */ + 1088 + 1 * 8, + 1088 + 2 * 8, + 1088 + 3 * 8, + 1088 + 4 * 8, + 1088 + 5 * 8, + 1088 + 6 * 8, + 1088 + 7 * 8 /* %k7 (64 bits each). */ +}; + +#define XSAVE_AVX512_K_ADDR(tdep, xsave, regnum) \ + (xsave + xsave_avx512_k_offset[regnum - I387_K0_REGNUM (tdep)]) + +/* At xsave_avx512_zmm_h_offset[REGNUM] you find the offset to the location in + the upper 256bit of AVX512 ZMMH register data structure used by the "xsave" + instruction where GDB register REGNUM is stored. */ + +static int xsave_avx512_zmm_h_offset[] = +{ + 1152 + 0 * 32, + 1152 + 1 * 32, /* Upper 256bit of %zmmh0 through... */ + 1152 + 2 * 32, + 1152 + 3 * 32, + 1152 + 4 * 32, + 1152 + 5 * 32, + 1152 + 6 * 32, + 1152 + 7 * 32, + 1152 + 8 * 32, + 1152 + 9 * 32, + 1152 + 10 * 32, + 1152 + 11 * 32, + 1152 + 12 * 32, + 1152 + 13 * 32, + 1152 + 14 * 32, + 1152 + 15 * 32, /* Upper 256bit of... %zmmh15 (256 bits each). */ + 1664 + 32 + 0 * 64, /* Upper 256bit of... %zmmh16 (256 bits each). */ + 1664 + 32 + 1 * 64, + 1664 + 32 + 2 * 64, + 1664 + 32 + 3 * 64, + 1664 + 32 + 4 * 64, + 1664 + 32 + 5 * 64, + 1664 + 32 + 6 * 64, + 1664 + 32 + 7 * 64, + 1664 + 32 + 8 * 64, + 1664 + 32 + 9 * 64, + 1664 + 32 + 10 * 64, + 1664 + 32 + 11 * 64, + 1664 + 32 + 12 * 64, + 1664 + 32 + 13 * 64, + 1664 + 32 + 14 * 64, + 1664 + 32 + 15 * 64 /* Upper 256bit of... %zmmh31 (256 bits each). */ +}; + +#define XSAVE_AVX512_ZMM_H_ADDR(tdep, xsave, regnum) \ + (xsave + xsave_avx512_zmm_h_offset[regnum - I387_ZMM0H_REGNUM (tdep)]) + +/* At xsave_pkeys_offset[REGNUM] you find the offset to the location + of the PKRU register data structure used by the "xsave" + instruction where GDB register REGNUM is stored. */ + +static int xsave_pkeys_offset[] = +{ +2688 + 0 * 8 /* %pkru (64 bits in XSTATE, 32-bit actually used by + instructions and applications). */ +}; + +#define XSAVE_PKEYS_ADDR(tdep, xsave, regnum) \ + (xsave + xsave_pkeys_offset[regnum - I387_PKRU_REGNUM (tdep)]) + + +/* Extract from XSAVE a bitset of the features that are available on the + target, but which have not yet been enabled. */ + +ULONGEST +i387_xsave_get_clear_bv (struct gdbarch *gdbarch, const void *xsave) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + const gdb_byte *regs = (const gdb_byte *) xsave; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* Get `xstat_bv'. The supported bits in `xstat_bv' are 8 bytes. */ + ULONGEST xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs), + 8, byte_order); + + /* Clear part in vector registers if its bit in xstat_bv is zero. */ + ULONGEST clear_bv = (~(xstate_bv)) & tdep->xcr0; + + return clear_bv; +} + /* Similar to i387_supply_fxsave, but use XSAVE extended state. */ void i387_supply_xsave (struct regcache *regcache, int regnum, const void *xsave) { - struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); - const gdb_byte *regs = xsave; + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + const gdb_byte *regs = (const gdb_byte *) xsave; int i; - unsigned int clear_bv; - const gdb_byte *p; + /* In 64-bit mode the split between "low" and "high" ZMM registers is at + ZMM16. Outside of 64-bit mode there are no "high" ZMM registers at all. + Precalculate the number to be used for the split point, with the all + registers in the "low" portion outside of 64-bit mode. */ + unsigned int zmm_endlo_regnum = I387_ZMM0H_REGNUM (tdep) + + std::min (tdep->num_zmm_regs, 16); + ULONGEST clear_bv; + static const gdb_byte zero[I386_MAX_REGISTER_SIZE] = { 0 }; enum { none = 0x0, x87 = 0x1, sse = 0x2, avxh = 0x4, - all = x87 | sse | avxh + mpx = 0x8, + avx512_k = 0x10, + avx512_zmm_h = 0x20, + avx512_ymmh_avx512 = 0x40, + avx512_xmm_avx512 = 0x80, + pkeys = 0x100, + all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h + | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys } regclass; + gdb_assert (regs != NULL); gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); gdb_assert (tdep->num_xmm_regs > 0); if (regnum == -1) regclass = all; + else if (regnum >= I387_PKRU_REGNUM (tdep) + && regnum < I387_PKEYSEND_REGNUM (tdep)) + regclass = pkeys; + else if (regnum >= I387_ZMM0H_REGNUM (tdep) + && regnum < I387_ZMMENDH_REGNUM (tdep)) + regclass = avx512_zmm_h; + else if (regnum >= I387_K0_REGNUM (tdep) + && regnum < I387_KEND_REGNUM (tdep)) + regclass = avx512_k; + else if (regnum >= I387_YMM16H_REGNUM (tdep) + && regnum < I387_YMMH_AVX512_END_REGNUM (tdep)) + regclass = avx512_ymmh_avx512; + else if (regnum >= I387_XMM16_REGNUM (tdep) + && regnum < I387_XMM_AVX512_END_REGNUM (tdep)) + regclass = avx512_xmm_avx512; else if (regnum >= I387_YMM0H_REGNUM (tdep) && regnum < I387_YMMENDH_REGNUM (tdep)) regclass = avxh; - else if (regnum >= I387_XMM0_REGNUM(tdep) + else if (regnum >= I387_BND0R_REGNUM (tdep) + && regnum < I387_MPXEND_REGNUM (tdep)) + regclass = mpx; + else if (regnum >= I387_XMM0_REGNUM (tdep) && regnum < I387_MXCSR_REGNUM (tdep)) regclass = sse; else if (regnum >= I387_ST0_REGNUM (tdep) @@ -745,96 +984,262 @@ i387_supply_xsave (struct regcache *regcache, int regnum, else regclass = none; - if (regs != NULL && regclass != none) - { - /* Get `xstat_bv'. */ - const gdb_byte *xstate_bv_p = XSAVE_XSTATE_BV_ADDR (regs); + clear_bv = i387_xsave_get_clear_bv (gdbarch, xsave); - /* The supported bits in `xstat_bv' are 1 byte. Clear part in - vector registers if its bit in xstat_bv is zero. */ - clear_bv = (~(*xstate_bv_p)) & tdep->xcr0; - } - else - clear_bv = I386_XSTATE_AVX_MASK; + /* With the delayed xsave mechanism, in between the program + starting, and the program accessing the vector registers for the + first time, the register's values are invalid. The kernel + initializes register states to zero when they are set the first + time in a program. This means that from the user-space programs' + perspective, it's the same as if the registers have always been + zero from the start of the program. Therefore, the debugger + should provide the same illusion to the user. */ switch (regclass) { case none: break; + case pkeys: + if ((clear_bv & X86_XSTATE_PKRU)) + regcache->raw_supply (regnum, zero); + else + regcache->raw_supply (regnum, XSAVE_PKEYS_ADDR (tdep, regs, regnum)); + return; + + case avx512_zmm_h: + if ((clear_bv & (regnum < zmm_endlo_regnum ? X86_XSTATE_ZMM_H + : X86_XSTATE_ZMM))) + regcache->raw_supply (regnum, zero); + else + regcache->raw_supply (regnum, + XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum)); + return; + + case avx512_k: + if ((clear_bv & X86_XSTATE_K)) + regcache->raw_supply (regnum, zero); + else + regcache->raw_supply (regnum, XSAVE_AVX512_K_ADDR (tdep, regs, regnum)); + return; + + case avx512_ymmh_avx512: + if ((clear_bv & X86_XSTATE_ZMM)) + regcache->raw_supply (regnum, zero); + else + regcache->raw_supply (regnum, + XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum)); + return; + + case avx512_xmm_avx512: + if ((clear_bv & X86_XSTATE_ZMM)) + regcache->raw_supply (regnum, zero); + else + regcache->raw_supply (regnum, + XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum)); + return; + case avxh: - if ((clear_bv & I386_XSTATE_AVX)) - p = NULL; + if ((clear_bv & X86_XSTATE_AVX)) + regcache->raw_supply (regnum, zero); + else + regcache->raw_supply (regnum, XSAVE_AVXH_ADDR (tdep, regs, regnum)); + return; + + case mpx: + if ((clear_bv & X86_XSTATE_BNDREGS)) + regcache->raw_supply (regnum, zero); else - p = XSAVE_AVXH_ADDR (tdep, regs, regnum); - regcache_raw_supply (regcache, regnum, p); + regcache->raw_supply (regnum, XSAVE_MPX_ADDR (tdep, regs, regnum)); return; case sse: - if ((clear_bv & I386_XSTATE_SSE)) - p = NULL; + if ((clear_bv & X86_XSTATE_SSE)) + regcache->raw_supply (regnum, zero); else - p = FXSAVE_ADDR (tdep, regs, regnum); - regcache_raw_supply (regcache, regnum, p); + regcache->raw_supply (regnum, FXSAVE_ADDR (tdep, regs, regnum)); return; case x87: - if ((clear_bv & I386_XSTATE_X87)) - p = NULL; + if ((clear_bv & X86_XSTATE_X87)) + regcache->raw_supply (regnum, zero); else - p = FXSAVE_ADDR (tdep, regs, regnum); - regcache_raw_supply (regcache, regnum, p); + regcache->raw_supply (regnum, FXSAVE_ADDR (tdep, regs, regnum)); return; case all: - /* Hanle the upper YMM registers. */ - if ((tdep->xcr0 & I386_XSTATE_AVX)) + /* Handle PKEYS registers. */ + if ((tdep->xcr0 & X86_XSTATE_PKRU)) { - if ((clear_bv & I386_XSTATE_AVX)) - p = NULL; + if ((clear_bv & X86_XSTATE_PKRU)) + { + for (i = I387_PKRU_REGNUM (tdep); + i < I387_PKEYSEND_REGNUM (tdep); + i++) + regcache->raw_supply (i, zero); + } else - p = regs; + { + for (i = I387_PKRU_REGNUM (tdep); + i < I387_PKEYSEND_REGNUM (tdep); + i++) + regcache->raw_supply (i, XSAVE_PKEYS_ADDR (tdep, regs, i)); + } + } - for (i = I387_YMM0H_REGNUM (tdep); - i < I387_YMMENDH_REGNUM (tdep); i++) + /* Handle the upper halves of the low 8/16 ZMM registers. */ + if ((tdep->xcr0 & X86_XSTATE_ZMM_H)) + { + if ((clear_bv & X86_XSTATE_ZMM_H)) { - if (p != NULL) - p = XSAVE_AVXH_ADDR (tdep, regs, i); - regcache_raw_supply (regcache, i, p); + for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++) + regcache->raw_supply (i, zero); + } + else + { + for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++) + regcache->raw_supply (i, + XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i)); } } - /* Handle the XMM registers. */ - if ((tdep->xcr0 & I386_XSTATE_SSE)) + /* Handle AVX512 OpMask registers. */ + if ((tdep->xcr0 & X86_XSTATE_K)) { - if ((clear_bv & I386_XSTATE_SSE)) - p = NULL; + if ((clear_bv & X86_XSTATE_K)) + { + for (i = I387_K0_REGNUM (tdep); + i < I387_KEND_REGNUM (tdep); + i++) + regcache->raw_supply (i, zero); + } else - p = regs; + { + for (i = I387_K0_REGNUM (tdep); + i < I387_KEND_REGNUM (tdep); + i++) + regcache->raw_supply (i, XSAVE_AVX512_K_ADDR (tdep, regs, i)); + } + } - for (i = I387_XMM0_REGNUM (tdep); - i < I387_MXCSR_REGNUM (tdep); i++) + /* Handle the upper 16 ZMM/YMM/XMM registers (if any). */ + if ((tdep->xcr0 & X86_XSTATE_ZMM)) + { + if ((clear_bv & X86_XSTATE_ZMM)) + { + for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++) + regcache->raw_supply (i, zero); + for (i = I387_YMM16H_REGNUM (tdep); + i < I387_YMMH_AVX512_END_REGNUM (tdep); + i++) + regcache->raw_supply (i, zero); + for (i = I387_XMM16_REGNUM (tdep); + i < I387_XMM_AVX512_END_REGNUM (tdep); + i++) + regcache->raw_supply (i, zero); + } + else { - if (p != NULL) - p = FXSAVE_ADDR (tdep, regs, i); - regcache_raw_supply (regcache, i, p); + for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++) + regcache->raw_supply (i, + XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i)); + for (i = I387_YMM16H_REGNUM (tdep); + i < I387_YMMH_AVX512_END_REGNUM (tdep); + i++) + regcache->raw_supply (i, XSAVE_YMM_AVX512_ADDR (tdep, regs, i)); + for (i = I387_XMM16_REGNUM (tdep); + i < I387_XMM_AVX512_END_REGNUM (tdep); + i++) + regcache->raw_supply (i, XSAVE_XMM_AVX512_ADDR (tdep, regs, i)); + } + } + /* Handle the upper YMM registers. */ + if ((tdep->xcr0 & X86_XSTATE_AVX)) + { + if ((clear_bv & X86_XSTATE_AVX)) + { + for (i = I387_YMM0H_REGNUM (tdep); + i < I387_YMMENDH_REGNUM (tdep); + i++) + regcache->raw_supply (i, zero); + } + else + { + for (i = I387_YMM0H_REGNUM (tdep); + i < I387_YMMENDH_REGNUM (tdep); + i++) + regcache->raw_supply (i, XSAVE_AVXH_ADDR (tdep, regs, i)); } } - /* Handle the x87 registers. */ - if ((tdep->xcr0 & I386_XSTATE_X87)) + /* Handle the MPX registers. */ + if ((tdep->xcr0 & X86_XSTATE_BNDREGS)) { - if ((clear_bv & I386_XSTATE_X87)) - p = NULL; + if (clear_bv & X86_XSTATE_BNDREGS) + { + for (i = I387_BND0R_REGNUM (tdep); + i < I387_BNDCFGU_REGNUM (tdep); i++) + regcache->raw_supply (i, zero); + } else - p = regs; + { + for (i = I387_BND0R_REGNUM (tdep); + i < I387_BNDCFGU_REGNUM (tdep); i++) + regcache->raw_supply (i, XSAVE_MPX_ADDR (tdep, regs, i)); + } + } - for (i = I387_ST0_REGNUM (tdep); - i < I387_FCTRL_REGNUM (tdep); i++) + /* Handle the MPX registers. */ + if ((tdep->xcr0 & X86_XSTATE_BNDCFG)) + { + if (clear_bv & X86_XSTATE_BNDCFG) + { + for (i = I387_BNDCFGU_REGNUM (tdep); + i < I387_MPXEND_REGNUM (tdep); i++) + regcache->raw_supply (i, zero); + } + else + { + for (i = I387_BNDCFGU_REGNUM (tdep); + i < I387_MPXEND_REGNUM (tdep); i++) + regcache->raw_supply (i, XSAVE_MPX_ADDR (tdep, regs, i)); + } + } + + /* Handle the XMM registers. */ + if ((tdep->xcr0 & X86_XSTATE_SSE)) + { + if ((clear_bv & X86_XSTATE_SSE)) + { + for (i = I387_XMM0_REGNUM (tdep); + i < I387_MXCSR_REGNUM (tdep); + i++) + regcache->raw_supply (i, zero); + } + else + { + for (i = I387_XMM0_REGNUM (tdep); + i < I387_MXCSR_REGNUM (tdep); i++) + regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i)); + } + } + + /* Handle the x87 registers. */ + if ((tdep->xcr0 & X86_XSTATE_X87)) + { + if ((clear_bv & X86_XSTATE_X87)) { - if (p != NULL) - p = FXSAVE_ADDR (tdep, regs, i); - regcache_raw_supply (regcache, i, p); + for (i = I387_ST0_REGNUM (tdep); + i < I387_FCTRL_REGNUM (tdep); + i++) + regcache->raw_supply (i, zero); + } + else + { + for (i = I387_ST0_REGNUM (tdep); + i < I387_FCTRL_REGNUM (tdep); + i++) + regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i)); } } break; @@ -844,16 +1249,30 @@ i387_supply_xsave (struct regcache *regcache, int regnum, for (i = I387_FCTRL_REGNUM (tdep); i < I387_XMM0_REGNUM (tdep); i++) if (regnum == -1 || regnum == i) { - if (regs == NULL) + if (clear_bv & X86_XSTATE_X87) { - regcache_raw_supply (regcache, i, NULL); - continue; - } + if (i == I387_FCTRL_REGNUM (tdep)) + { + gdb_byte buf[4]; + + store_unsigned_integer (buf, 4, byte_order, + I387_FCTRL_INIT_VAL); + regcache->raw_supply (i, buf); + } + else if (i == I387_FTAG_REGNUM (tdep)) + { + gdb_byte buf[4]; + store_unsigned_integer (buf, 4, byte_order, 0xffff); + regcache->raw_supply (i, buf); + } + else + regcache->raw_supply (i, zero); + } /* Most of the FPU control registers occupy only 16 bits in the xsave extended state. Give those a special treatment. */ - if (i != I387_FIOFF_REGNUM (tdep) - && i != I387_FOOFF_REGNUM (tdep)) + else if (i != I387_FIOFF_REGNUM (tdep) + && i != I387_FOOFF_REGNUM (tdep)) { gdb_byte val[4]; @@ -861,7 +1280,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum, val[2] = val[3] = 0; if (i == I387_FOP_REGNUM (tdep)) val[1] &= ((1 << 3) - 1); - else if (i== I387_FTAG_REGNUM (tdep)) + else if (i == I387_FTAG_REGNUM (tdep)) { /* The fxsave area contains a simplified version of the tag word. We have to look at the actual 80-bit @@ -881,9 +1300,9 @@ i387_supply_xsave (struct regcache *regcache, int regnum, if (val[0] & (1 << fpreg)) { - int regnum = (fpreg + 8 - top) % 8 + int thisreg = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM (tdep); - tag = i387_tag (FXSAVE_ADDR (tdep, regs, regnum)); + tag = i387_tag (FXSAVE_ADDR (tdep, regs, thisreg)); } else tag = 3; /* Empty */ @@ -893,16 +1312,27 @@ i387_supply_xsave (struct regcache *regcache, int regnum, val[0] = ftag & 0xff; val[1] = (ftag >> 8) & 0xff; } - regcache_raw_supply (regcache, i, val); + regcache->raw_supply (i, val); } - else - regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i)); + else + regcache->raw_supply (i, FXSAVE_ADDR (tdep, regs, i)); } if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1) { - p = regs == NULL ? NULL : FXSAVE_MXCSR_ADDR (regs); - regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep), p); + /* The MXCSR register is placed into the xsave buffer if either the + AVX or SSE features are enabled. */ + if ((clear_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE)) + == (X86_XSTATE_AVX | X86_XSTATE_SSE)) + { + gdb_byte buf[4]; + + store_unsigned_integer (buf, 4, byte_order, I387_MXCSR_INIT_VAL); + regcache->raw_supply (I387_MXCSR_REGNUM (tdep), buf); + } + else + regcache->raw_supply (I387_MXCSR_REGNUM (tdep), + FXSAVE_MXCSR_ADDR (regs)); } } @@ -912,17 +1342,30 @@ void i387_collect_xsave (const struct regcache *regcache, int regnum, void *xsave, int gcore) { - struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); - gdb_byte *regs = xsave; - int i; + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + gdb_byte *p, *regs = (gdb_byte *) xsave; + gdb_byte raw[I386_MAX_REGISTER_SIZE]; + ULONGEST initial_xstate_bv, clear_bv, xstate_bv = 0; + unsigned int i; + /* See the comment in i387_supply_xsave(). */ + unsigned int zmm_endlo_regnum = I387_ZMM0H_REGNUM (tdep) + + std::min (tdep->num_zmm_regs, 16); enum { - none = 0x0, - check = 0x1, - x87 = 0x2 | check, - sse = 0x4 | check, - avxh = 0x8 | check, - all = x87 | sse | avxh + x87_ctrl_or_mxcsr = 0x1, + x87 = 0x2, + sse = 0x4, + avxh = 0x8, + mpx = 0x10, + avx512_k = 0x20, + avx512_zmm_h = 0x40, + avx512_ymmh_avx512 = 0x80, + avx512_xmm_avx512 = 0x100, + pkeys = 0x200, + all = x87 | sse | avxh | mpx | avx512_k | avx512_zmm_h + | avx512_ymmh_avx512 | avx512_xmm_avx512 | pkeys } regclass; gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); @@ -930,22 +1373,44 @@ i387_collect_xsave (const struct regcache *regcache, int regnum, if (regnum == -1) regclass = all; + else if (regnum >= I387_PKRU_REGNUM (tdep) + && regnum < I387_PKEYSEND_REGNUM (tdep)) + regclass = pkeys; + else if (regnum >= I387_ZMM0H_REGNUM (tdep) + && regnum < I387_ZMMENDH_REGNUM (tdep)) + regclass = avx512_zmm_h; + else if (regnum >= I387_K0_REGNUM (tdep) + && regnum < I387_KEND_REGNUM (tdep)) + regclass = avx512_k; + else if (regnum >= I387_YMM16H_REGNUM (tdep) + && regnum < I387_YMMH_AVX512_END_REGNUM (tdep)) + regclass = avx512_ymmh_avx512; + else if (regnum >= I387_XMM16_REGNUM (tdep) + && regnum < I387_XMM_AVX512_END_REGNUM (tdep)) + regclass = avx512_xmm_avx512; else if (regnum >= I387_YMM0H_REGNUM (tdep) && regnum < I387_YMMENDH_REGNUM (tdep)) regclass = avxh; - else if (regnum >= I387_XMM0_REGNUM(tdep) + else if (regnum >= I387_BND0R_REGNUM (tdep) + && regnum < I387_MPXEND_REGNUM (tdep)) + regclass = mpx; + else if (regnum >= I387_XMM0_REGNUM (tdep) && regnum < I387_MXCSR_REGNUM (tdep)) regclass = sse; else if (regnum >= I387_ST0_REGNUM (tdep) && regnum < I387_FCTRL_REGNUM (tdep)) regclass = x87; + else if ((regnum >= I387_FCTRL_REGNUM (tdep) + && regnum < I387_XMM0_REGNUM (tdep)) + || regnum == I387_MXCSR_REGNUM (tdep)) + regclass = x87_ctrl_or_mxcsr; else - regclass = none; + internal_error (__FILE__, __LINE__, _("invalid i387 regnum %d"), regnum); if (gcore) { /* Clear XSAVE extended state. */ - memset (regs, 0, I386_XSTATE_SIZE (tdep->xcr0)); + memset (regs, 0, X86_XSTATE_SIZE (tdep->xcr0)); /* Update XCR0 and `xstate_bv' with XCR0 for gcore. */ if (tdep->xsave_xcr0_offset != -1) @@ -953,148 +1418,388 @@ i387_collect_xsave (const struct regcache *regcache, int regnum, memcpy (XSAVE_XSTATE_BV_ADDR (regs), &tdep->xcr0, 8); } - if ((regclass & check)) + /* The supported bits in `xstat_bv' are 8 bytes. */ + initial_xstate_bv = extract_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs), + 8, byte_order); + clear_bv = (~(initial_xstate_bv)) & tdep->xcr0; + + /* The XSAVE buffer was filled lazily by the kernel. Only those + features that are enabled were written into the buffer, disabled + features left the buffer uninitialised. In order to identify if any + registers have changed we will be comparing the register cache + version to the version in the XSAVE buffer, it is important then that + at this point we initialise to the default values any features in + XSAVE that are not yet initialised. + + This could be made more efficient, we know which features (from + REGNUM) we will be potentially updating, and could limit ourselves to + only clearing that feature. However, the extra complexity does not + seem justified at this point. */ + if (clear_bv) { - gdb_byte raw[I386_MAX_REGISTER_SIZE]; - gdb_byte *xstate_bv_p = XSAVE_XSTATE_BV_ADDR (regs); - unsigned int xstate_bv = 0; - /* The supported bits in `xstat_bv' are 1 byte. */ - unsigned int clear_bv = (~(*xstate_bv_p)) & tdep->xcr0; - gdb_byte *p; - - /* Clear register set if its bit in xstat_bv is zero. */ - if (clear_bv) + if ((clear_bv & X86_XSTATE_PKRU)) + for (i = I387_PKRU_REGNUM (tdep); + i < I387_PKEYSEND_REGNUM (tdep); i++) + memset (XSAVE_PKEYS_ADDR (tdep, regs, i), 0, 4); + + if ((clear_bv & X86_XSTATE_BNDREGS)) + for (i = I387_BND0R_REGNUM (tdep); + i < I387_BNDCFGU_REGNUM (tdep); i++) + memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 16); + + if ((clear_bv & X86_XSTATE_BNDCFG)) + for (i = I387_BNDCFGU_REGNUM (tdep); + i < I387_MPXEND_REGNUM (tdep); i++) + memset (XSAVE_MPX_ADDR (tdep, regs, i), 0, 8); + + if ((clear_bv & X86_XSTATE_ZMM_H)) + for (i = I387_ZMM0H_REGNUM (tdep); i < zmm_endlo_regnum; i++) + memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32); + + if ((clear_bv & X86_XSTATE_K)) + for (i = I387_K0_REGNUM (tdep); + i < I387_KEND_REGNUM (tdep); i++) + memset (XSAVE_AVX512_K_ADDR (tdep, regs, i), 0, 8); + + if ((clear_bv & X86_XSTATE_ZMM)) { - if ((clear_bv & I386_XSTATE_AVX)) - for (i = I387_YMM0H_REGNUM (tdep); - i < I387_YMMENDH_REGNUM (tdep); i++) - memset (XSAVE_AVXH_ADDR (tdep, regs, i), 0, 16); - - if ((clear_bv & I386_XSTATE_SSE)) - for (i = I387_XMM0_REGNUM (tdep); - i < I387_MXCSR_REGNUM (tdep); i++) - memset (FXSAVE_ADDR (tdep, regs, i), 0, 16); - - if ((clear_bv & I386_XSTATE_X87)) - for (i = I387_ST0_REGNUM (tdep); - i < I387_FCTRL_REGNUM (tdep); i++) - memset (FXSAVE_ADDR (tdep, regs, i), 0, 10); + for (i = zmm_endlo_regnum; i < I387_ZMMENDH_REGNUM (tdep); i++) + memset (XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i), 0, 32); + for (i = I387_YMM16H_REGNUM (tdep); + i < I387_YMMH_AVX512_END_REGNUM (tdep); i++) + memset (XSAVE_YMM_AVX512_ADDR (tdep, regs, i), 0, 16); + for (i = I387_XMM16_REGNUM (tdep); + i < I387_XMM_AVX512_END_REGNUM (tdep); i++) + memset (XSAVE_XMM_AVX512_ADDR (tdep, regs, i), 0, 16); } - if (regclass == all) + if ((clear_bv & X86_XSTATE_AVX)) + for (i = I387_YMM0H_REGNUM (tdep); + i < I387_YMMENDH_REGNUM (tdep); i++) + memset (XSAVE_AVXH_ADDR (tdep, regs, i), 0, 16); + + if ((clear_bv & X86_XSTATE_SSE)) + for (i = I387_XMM0_REGNUM (tdep); + i < I387_MXCSR_REGNUM (tdep); i++) + memset (FXSAVE_ADDR (tdep, regs, i), 0, 16); + + /* The mxcsr register is written into the xsave buffer if either AVX + or SSE is enabled, so only clear it if both of those features + require clearing. */ + if ((clear_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE)) + == (X86_XSTATE_AVX | X86_XSTATE_SSE)) + store_unsigned_integer (FXSAVE_MXCSR_ADDR (regs), 2, byte_order, + I387_MXCSR_INIT_VAL); + + if ((clear_bv & X86_XSTATE_X87)) { - /* Check if any upper YMM registers are changed. */ - if ((tdep->xcr0 & I386_XSTATE_AVX)) - for (i = I387_YMM0H_REGNUM (tdep); - i < I387_YMMENDH_REGNUM (tdep); i++) + for (i = I387_ST0_REGNUM (tdep); + i < I387_FCTRL_REGNUM (tdep); i++) + memset (FXSAVE_ADDR (tdep, regs, i), 0, 10); + + for (i = I387_FCTRL_REGNUM (tdep); + i < I387_XMM0_REGNUM (tdep); i++) + { + if (i == I387_FCTRL_REGNUM (tdep)) + store_unsigned_integer (FXSAVE_ADDR (tdep, regs, i), 2, + byte_order, I387_FCTRL_INIT_VAL); + else + memset (FXSAVE_ADDR (tdep, regs, i), 0, + regcache_register_size (regcache, i)); + } + } + } + + if (regclass == all) + { + /* Check if any PKEYS registers are changed. */ + if ((tdep->xcr0 & X86_XSTATE_PKRU)) + for (i = I387_PKRU_REGNUM (tdep); + i < I387_PKEYSEND_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_PKEYS_ADDR (tdep, regs, i); + if (memcmp (raw, p, 4) != 0) { - regcache_raw_collect (regcache, i, raw); - p = XSAVE_AVXH_ADDR (tdep, regs, i); - if (memcmp (raw, p, 16)) - { - xstate_bv |= I386_XSTATE_AVX; - memcpy (p, raw, 16); - } + xstate_bv |= X86_XSTATE_PKRU; + memcpy (p, raw, 4); } + } - /* Check if any SSE registers are changed. */ - if ((tdep->xcr0 & I386_XSTATE_SSE)) - for (i = I387_XMM0_REGNUM (tdep); - i < I387_MXCSR_REGNUM (tdep); i++) + /* Check if any ZMMH registers are changed. */ + if ((tdep->xcr0 & (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM))) + for (i = I387_ZMM0H_REGNUM (tdep); + i < I387_ZMMENDH_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, i); + if (memcmp (raw, p, 32) != 0) { - regcache_raw_collect (regcache, i, raw); - p = FXSAVE_ADDR (tdep, regs, i); - if (memcmp (raw, p, 16)) - { - xstate_bv |= I386_XSTATE_SSE; - memcpy (p, raw, 16); - } + xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM); + memcpy (p, raw, 32); } + } - /* Check if any X87 registers are changed. */ - if ((tdep->xcr0 & I386_XSTATE_X87)) - for (i = I387_ST0_REGNUM (tdep); - i < I387_FCTRL_REGNUM (tdep); i++) + /* Check if any K registers are changed. */ + if ((tdep->xcr0 & X86_XSTATE_K)) + for (i = I387_K0_REGNUM (tdep); + i < I387_KEND_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_AVX512_K_ADDR (tdep, regs, i); + if (memcmp (raw, p, 8) != 0) { - regcache_raw_collect (regcache, i, raw); - p = FXSAVE_ADDR (tdep, regs, i); - if (memcmp (raw, p, 10)) - { - xstate_bv |= I386_XSTATE_X87; - memcpy (p, raw, 10); - } + xstate_bv |= X86_XSTATE_K; + memcpy (p, raw, 8); } - } - else + } + + /* Check if any XMM or upper YMM registers are changed. */ + if ((tdep->xcr0 & X86_XSTATE_ZMM)) { - /* Check if REGNUM is changed. */ - regcache_raw_collect (regcache, regnum, raw); + for (i = I387_YMM16H_REGNUM (tdep); + i < I387_YMMH_AVX512_END_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_YMM_AVX512_ADDR (tdep, regs, i); + if (memcmp (raw, p, 16) != 0) + { + xstate_bv |= X86_XSTATE_ZMM; + memcpy (p, raw, 16); + } + } + for (i = I387_XMM16_REGNUM (tdep); + i < I387_XMM_AVX512_END_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_XMM_AVX512_ADDR (tdep, regs, i); + if (memcmp (raw, p, 16) != 0) + { + xstate_bv |= X86_XSTATE_ZMM; + memcpy (p, raw, 16); + } + } + } + + /* Check if any upper MPX registers are changed. */ + if ((tdep->xcr0 & X86_XSTATE_BNDREGS)) + for (i = I387_BND0R_REGNUM (tdep); + i < I387_BNDCFGU_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_MPX_ADDR (tdep, regs, i); + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_BNDREGS; + memcpy (p, raw, 16); + } + } - switch (regclass) + /* Check if any upper MPX registers are changed. */ + if ((tdep->xcr0 & X86_XSTATE_BNDCFG)) + for (i = I387_BNDCFGU_REGNUM (tdep); + i < I387_MPXEND_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_MPX_ADDR (tdep, regs, i); + if (memcmp (raw, p, 8)) + { + xstate_bv |= X86_XSTATE_BNDCFG; + memcpy (p, raw, 8); + } + } + + /* Check if any upper YMM registers are changed. */ + if ((tdep->xcr0 & X86_XSTATE_AVX)) + for (i = I387_YMM0H_REGNUM (tdep); + i < I387_YMMENDH_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = XSAVE_AVXH_ADDR (tdep, regs, i); + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_AVX; + memcpy (p, raw, 16); + } + } + + /* Check if any SSE registers are changed. */ + if ((tdep->xcr0 & X86_XSTATE_SSE)) + for (i = I387_XMM0_REGNUM (tdep); + i < I387_MXCSR_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = FXSAVE_ADDR (tdep, regs, i); + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_SSE; + memcpy (p, raw, 16); + } + } + + if ((tdep->xcr0 & X86_XSTATE_AVX) || (tdep->xcr0 & X86_XSTATE_SSE)) + { + i = I387_MXCSR_REGNUM (tdep); + regcache->raw_collect (i, raw); + p = FXSAVE_MXCSR_ADDR (regs); + if (memcmp (raw, p, 4)) { - default: - abort (); - - case avxh: - /* This is an upper YMM register. */ - p = XSAVE_AVXH_ADDR (tdep, regs, regnum); - if (memcmp (raw, p, 16)) - { - xstate_bv |= I386_XSTATE_AVX; - memcpy (p, raw, 16); - } - break; + /* Now, we need to mark one of either SSE of AVX as enabled. + We could pick either. What we do is check to see if one + of the features is already enabled, if it is then we leave + it at that, otherwise we pick SSE. */ + if ((xstate_bv & (X86_XSTATE_SSE | X86_XSTATE_AVX)) == 0) + xstate_bv |= X86_XSTATE_SSE; + memcpy (p, raw, 4); + } + } - case sse: - /* This is an SSE register. */ - p = FXSAVE_ADDR (tdep, regs, regnum); - if (memcmp (raw, p, 16)) - { - xstate_bv |= I386_XSTATE_SSE; - memcpy (p, raw, 16); - } - break; + /* Check if any X87 registers are changed. Only the non-control + registers are handled here, the control registers are all handled + later on in this function. */ + if ((tdep->xcr0 & X86_XSTATE_X87)) + for (i = I387_ST0_REGNUM (tdep); + i < I387_FCTRL_REGNUM (tdep); i++) + { + regcache->raw_collect (i, raw); + p = FXSAVE_ADDR (tdep, regs, i); + if (memcmp (raw, p, 10)) + { + xstate_bv |= X86_XSTATE_X87; + memcpy (p, raw, 10); + } + } + } + else + { + /* Check if REGNUM is changed. */ + regcache->raw_collect (regnum, raw); - case x87: - /* This is an x87 register. */ - p = FXSAVE_ADDR (tdep, regs, regnum); - if (memcmp (raw, p, 10)) - { - xstate_bv |= I386_XSTATE_X87; - memcpy (p, raw, 10); - } - break; - } + switch (regclass) + { + default: + internal_error (__FILE__, __LINE__, + _("invalid i387 regclass")); + + case pkeys: + /* This is a PKEYS register. */ + p = XSAVE_PKEYS_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 4) != 0) + { + xstate_bv |= X86_XSTATE_PKRU; + memcpy (p, raw, 4); } + break; - /* Update the corresponding bits in `xstate_bv' if any SSE/AVX - registers are changed. */ - if (xstate_bv) + case avx512_zmm_h: + /* This is a ZMM register. */ + p = XSAVE_AVX512_ZMM_H_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 32) != 0) { - /* The supported bits in `xstat_bv' are 1 byte. */ - *xstate_bv_p |= (gdb_byte) xstate_bv; + xstate_bv |= (X86_XSTATE_ZMM_H | X86_XSTATE_ZMM); + memcpy (p, raw, 32); + } + break; + case avx512_k: + /* This is a AVX512 mask register. */ + p = XSAVE_AVX512_K_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 8) != 0) + { + xstate_bv |= X86_XSTATE_K; + memcpy (p, raw, 8); + } + break; - switch (regclass) - { - default: - abort (); + case avx512_ymmh_avx512: + /* This is an upper YMM16-31 register. */ + p = XSAVE_YMM_AVX512_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 16) != 0) + { + xstate_bv |= X86_XSTATE_ZMM; + memcpy (p, raw, 16); + } + break; - case all: - break; + case avx512_xmm_avx512: + /* This is an upper XMM16-31 register. */ + p = XSAVE_XMM_AVX512_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 16) != 0) + { + xstate_bv |= X86_XSTATE_ZMM; + memcpy (p, raw, 16); + } + break; - case x87: - case sse: - case avxh: - /* Register REGNUM has been updated. Return. */ - return; + case avxh: + /* This is an upper YMM register. */ + p = XSAVE_AVXH_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_AVX; + memcpy (p, raw, 16); + } + break; + + case mpx: + if (regnum < I387_BNDCFGU_REGNUM (tdep)) + { + regcache->raw_collect (regnum, raw); + p = XSAVE_MPX_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_BNDREGS; + memcpy (p, raw, 16); } } else { - /* Return if REGNUM isn't changed. */ - if (regclass != all) - return; + p = XSAVE_MPX_ADDR (tdep, regs, regnum); + xstate_bv |= X86_XSTATE_BNDCFG; + memcpy (p, raw, 8); } + break; + + case sse: + /* This is an SSE register. */ + p = FXSAVE_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 16)) + { + xstate_bv |= X86_XSTATE_SSE; + memcpy (p, raw, 16); + } + break; + + case x87: + /* This is an x87 register. */ + p = FXSAVE_ADDR (tdep, regs, regnum); + if (memcmp (raw, p, 10)) + { + xstate_bv |= X86_XSTATE_X87; + memcpy (p, raw, 10); + } + break; + + case x87_ctrl_or_mxcsr: + /* We only handle MXCSR here. All other x87 control registers + are handled separately below. */ + if (regnum == I387_MXCSR_REGNUM (tdep)) + { + p = FXSAVE_MXCSR_ADDR (regs); + if (memcmp (raw, p, 2)) + { + /* We're only setting MXCSR, so check the initial state + to see if either of AVX or SSE are already enabled. + If they are then we'll attribute this changed MXCSR to + that feature. If neither feature is enabled, then + we'll attribute this change to the SSE feature. */ + xstate_bv |= (initial_xstate_bv + & (X86_XSTATE_AVX | X86_XSTATE_SSE)); + if ((xstate_bv & (X86_XSTATE_AVX | X86_XSTATE_SSE)) == 0) + xstate_bv |= X86_XSTATE_SSE; + memcpy (p, raw, 2); + } + } + } } /* Only handle x87 control registers. */ @@ -1108,12 +1813,12 @@ i387_collect_xsave (const struct regcache *regcache, int regnum, { gdb_byte buf[4]; - regcache_raw_collect (regcache, i, buf); + regcache->raw_collect (i, buf); if (i == I387_FOP_REGNUM (tdep)) { /* The opcode occupies only 11 bits. Make sure we - don't touch the other bits. */ + don't touch the other bits. */ buf[1] &= ((1 << 3) - 1); buf[1] |= ((FXSAVE_ADDR (tdep, regs, i))[1] & ~((1 << 3) - 1)); } @@ -1136,15 +1841,38 @@ i387_collect_xsave (const struct regcache *regcache, int regnum, buf[0] |= (1 << fpreg); } } - memcpy (FXSAVE_ADDR (tdep, regs, i), buf, 2); + p = FXSAVE_ADDR (tdep, regs, i); + if (memcmp (p, buf, 2)) + { + xstate_bv |= X86_XSTATE_X87; + memcpy (p, buf, 2); + } } else - regcache_raw_collect (regcache, i, FXSAVE_ADDR (tdep, regs, i)); + { + int regsize; + + regcache->raw_collect (i, raw); + regsize = regcache_register_size (regcache, i); + p = FXSAVE_ADDR (tdep, regs, i); + if (memcmp (raw, p, regsize)) + { + xstate_bv |= X86_XSTATE_X87; + memcpy (p, raw, regsize); + } + } } - if (regnum == I387_MXCSR_REGNUM (tdep) || regnum == -1) - regcache_raw_collect (regcache, I387_MXCSR_REGNUM (tdep), - FXSAVE_MXCSR_ADDR (regs)); + /* Update the corresponding bits in `xstate_bv' if any + registers are changed. */ + if (xstate_bv) + { + /* The supported bits in `xstat_bv' are 8 bytes. */ + initial_xstate_bv |= xstate_bv; + store_unsigned_integer (XSAVE_XSTATE_BV_ADDR (regs), + 8, byte_order, + initial_xstate_bv); + } } /* Recreate the FTW (tag word) valid bits from the 80-bit FP data in @@ -1218,3 +1946,20 @@ i387_return_value (struct gdbarch *gdbarch, struct regcache *regcache) regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM (tdep), 0x3fff); } + +/* See i387-tdep.h. */ + +void +i387_reset_bnd_regs (struct gdbarch *gdbarch, struct regcache *regcache) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (I387_BND0R_REGNUM (tdep) > 0) + { + gdb_byte bnd_buf[16]; + + memset (bnd_buf, 0, 16); + for (int i = 0; i < I387_NUM_BND_REGS; i++) + regcache->raw_write (I387_BND0R_REGNUM (tdep) + i, bnd_buf); + } +}