119370Spst/* Intel 387 floating point stuff. 219370Spst 3130803Smarcel Copyright 1988, 1989, 1991, 1992, 1993, 1994, 1998, 1999, 2000, 4130803Smarcel 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 5130803Smarcel 698944Sobrien This file is part of GDB. 719370Spst 898944Sobrien This program is free software; you can redistribute it and/or modify 998944Sobrien it under the terms of the GNU General Public License as published by 1098944Sobrien the Free Software Foundation; either version 2 of the License, or 1198944Sobrien (at your option) any later version. 1219370Spst 1398944Sobrien This program is distributed in the hope that it will be useful, 1498944Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1598944Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1698944Sobrien GNU General Public License for more details. 1719370Spst 1898944Sobrien You should have received a copy of the GNU General Public License 1998944Sobrien along with this program; if not, write to the Free Software 2098944Sobrien Foundation, Inc., 59 Temple Place - Suite 330, 2198944Sobrien Boston, MA 02111-1307, USA. */ 2219370Spst 2319370Spst#include "defs.h" 24130803Smarcel#include "doublest.h" 25130803Smarcel#include "floatformat.h" 2619370Spst#include "frame.h" 27130803Smarcel#include "gdbcore.h" 2819370Spst#include "inferior.h" 2919370Spst#include "language.h" 30130803Smarcel#include "regcache.h" 3198944Sobrien#include "value.h" 32130803Smarcel 3398944Sobrien#include "gdb_assert.h" 34130803Smarcel#include "gdb_string.h" 3519370Spst 3698944Sobrien#include "i386-tdep.h" 37130803Smarcel#include "i387-tdep.h" 3846283Sdfr 3998944Sobrien/* Implement the `info float' layout based on the register definitions 4098944Sobrien in `tm-i386.h'. */ 4198944Sobrien 4298944Sobrien/* Print the floating point number specified by RAW. */ 43130803Smarcel 4498944Sobrienstatic void 45130803Smarcelprint_i387_value (char *raw, struct ui_file *file) 4698944Sobrien{ 4798944Sobrien DOUBLEST value; 4898944Sobrien 4998944Sobrien /* Using extract_typed_floating here might affect the representation 5098944Sobrien of certain numbers such as NaNs, even if GDB is running natively. 5198944Sobrien This is fine since our caller already detects such special 5298944Sobrien numbers and we print the hexadecimal representation anyway. */ 5398944Sobrien value = extract_typed_floating (raw, builtin_type_i387_ext); 5498944Sobrien 5598944Sobrien /* We try to print 19 digits. The last digit may or may not contain 5698944Sobrien garbage, but we'd better print one too many. We need enough room 5798944Sobrien to print the value, 1 position for the sign, 1 for the decimal 5898944Sobrien point, 19 for the digits and 6 for the exponent adds up to 27. */ 5998944Sobrien#ifdef PRINTF_HAS_LONG_DOUBLE 60130803Smarcel fprintf_filtered (file, " %-+27.19Lg", (long double) value); 6198944Sobrien#else 62130803Smarcel fprintf_filtered (file, " %-+27.19g", (double) value); 6398944Sobrien#endif 6498944Sobrien} 6598944Sobrien 6698944Sobrien/* Print the classification for the register contents RAW. */ 67130803Smarcel 6898944Sobrienstatic void 69130803Smarcelprint_i387_ext (unsigned char *raw, struct ui_file *file) 7098944Sobrien{ 7198944Sobrien int sign; 7298944Sobrien int integer; 7398944Sobrien unsigned int exponent; 7498944Sobrien unsigned long fraction[2]; 7598944Sobrien 7698944Sobrien sign = raw[9] & 0x80; 7798944Sobrien integer = raw[7] & 0x80; 7898944Sobrien exponent = (((raw[9] & 0x7f) << 8) | raw[8]); 7998944Sobrien fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); 8098944Sobrien fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) 8198944Sobrien | (raw[5] << 8) | raw[4]); 8298944Sobrien 8398944Sobrien if (exponent == 0x7fff && integer) 8498944Sobrien { 8598944Sobrien if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000) 8698944Sobrien /* Infinity. */ 87130803Smarcel fprintf_filtered (file, " %cInf", (sign ? '-' : '+')); 8898944Sobrien else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000) 8998944Sobrien /* Real Indefinite (QNaN). */ 90130803Smarcel fputs_unfiltered (" Real Indefinite (QNaN)", file); 9198944Sobrien else if (fraction[1] & 0x40000000) 9298944Sobrien /* QNaN. */ 93130803Smarcel fputs_filtered (" QNaN", file); 9498944Sobrien else 9598944Sobrien /* SNaN. */ 96130803Smarcel fputs_filtered (" SNaN", file); 9798944Sobrien } 9898944Sobrien else if (exponent < 0x7fff && exponent > 0x0000 && integer) 9998944Sobrien /* Normal. */ 100130803Smarcel print_i387_value (raw, file); 10198944Sobrien else if (exponent == 0x0000) 10298944Sobrien { 10398944Sobrien /* Denormal or zero. */ 104130803Smarcel print_i387_value (raw, file); 10598944Sobrien 10698944Sobrien if (integer) 10798944Sobrien /* Pseudo-denormal. */ 108130803Smarcel fputs_filtered (" Pseudo-denormal", file); 10998944Sobrien else if (fraction[0] || fraction[1]) 11098944Sobrien /* Denormal. */ 111130803Smarcel fputs_filtered (" Denormal", file); 11298944Sobrien } 11398944Sobrien else 11498944Sobrien /* Unsupported. */ 115130803Smarcel fputs_filtered (" Unsupported", file); 11698944Sobrien} 11798944Sobrien 11898944Sobrien/* Print the status word STATUS. */ 119130803Smarcel 12098944Sobrienstatic void 121130803Smarcelprint_i387_status_word (unsigned int status, struct ui_file *file) 12298944Sobrien{ 123130803Smarcel fprintf_filtered (file, "Status Word: %s", 12498944Sobrien local_hex_string_custom (status, "04")); 125130803Smarcel fputs_filtered (" ", file); 126130803Smarcel fprintf_filtered (file, " %s", (status & 0x0001) ? "IE" : " "); 127130803Smarcel fprintf_filtered (file, " %s", (status & 0x0002) ? "DE" : " "); 128130803Smarcel fprintf_filtered (file, " %s", (status & 0x0004) ? "ZE" : " "); 129130803Smarcel fprintf_filtered (file, " %s", (status & 0x0008) ? "OE" : " "); 130130803Smarcel fprintf_filtered (file, " %s", (status & 0x0010) ? "UE" : " "); 131130803Smarcel fprintf_filtered (file, " %s", (status & 0x0020) ? "PE" : " "); 132130803Smarcel fputs_filtered (" ", file); 133130803Smarcel fprintf_filtered (file, " %s", (status & 0x0080) ? "ES" : " "); 134130803Smarcel fputs_filtered (" ", file); 135130803Smarcel fprintf_filtered (file, " %s", (status & 0x0040) ? "SF" : " "); 136130803Smarcel fputs_filtered (" ", file); 137130803Smarcel fprintf_filtered (file, " %s", (status & 0x0100) ? "C0" : " "); 138130803Smarcel fprintf_filtered (file, " %s", (status & 0x0200) ? "C1" : " "); 139130803Smarcel fprintf_filtered (file, " %s", (status & 0x0400) ? "C2" : " "); 140130803Smarcel fprintf_filtered (file, " %s", (status & 0x4000) ? "C3" : " "); 14198944Sobrien 142130803Smarcel fputs_filtered ("\n", file); 14398944Sobrien 144130803Smarcel fprintf_filtered (file, 145130803Smarcel " TOP: %d\n", ((status >> 11) & 7)); 14698944Sobrien} 14798944Sobrien 14898944Sobrien/* Print the control word CONTROL. */ 149130803Smarcel 15098944Sobrienstatic void 151130803Smarcelprint_i387_control_word (unsigned int control, struct ui_file *file) 15298944Sobrien{ 153130803Smarcel fprintf_filtered (file, "Control Word: %s", 15498944Sobrien local_hex_string_custom (control, "04")); 155130803Smarcel fputs_filtered (" ", file); 156130803Smarcel fprintf_filtered (file, " %s", (control & 0x0001) ? "IM" : " "); 157130803Smarcel fprintf_filtered (file, " %s", (control & 0x0002) ? "DM" : " "); 158130803Smarcel fprintf_filtered (file, " %s", (control & 0x0004) ? "ZM" : " "); 159130803Smarcel fprintf_filtered (file, " %s", (control & 0x0008) ? "OM" : " "); 160130803Smarcel fprintf_filtered (file, " %s", (control & 0x0010) ? "UM" : " "); 161130803Smarcel fprintf_filtered (file, " %s", (control & 0x0020) ? "PM" : " "); 16298944Sobrien 163130803Smarcel fputs_filtered ("\n", file); 16498944Sobrien 165130803Smarcel fputs_filtered (" PC: ", file); 16698944Sobrien switch ((control >> 8) & 3) 16798944Sobrien { 16898944Sobrien case 0: 169130803Smarcel fputs_filtered ("Single Precision (24-bits)\n", file); 17098944Sobrien break; 17198944Sobrien case 1: 172130803Smarcel fputs_filtered ("Reserved\n", file); 17398944Sobrien break; 17498944Sobrien case 2: 175130803Smarcel fputs_filtered ("Double Precision (53-bits)\n", file); 17698944Sobrien break; 17798944Sobrien case 3: 178130803Smarcel fputs_filtered ("Extended Precision (64-bits)\n", file); 17998944Sobrien break; 18098944Sobrien } 18198944Sobrien 182130803Smarcel fputs_filtered (" RC: ", file); 18398944Sobrien switch ((control >> 10) & 3) 18498944Sobrien { 18598944Sobrien case 0: 186130803Smarcel fputs_filtered ("Round to nearest\n", file); 18798944Sobrien break; 18898944Sobrien case 1: 189130803Smarcel fputs_filtered ("Round down\n", file); 19098944Sobrien break; 19198944Sobrien case 2: 192130803Smarcel fputs_filtered ("Round up\n", file); 19398944Sobrien break; 19498944Sobrien case 3: 195130803Smarcel fputs_filtered ("Round toward zero\n", file); 19698944Sobrien break; 19798944Sobrien } 19898944Sobrien} 19998944Sobrien 200130803Smarcel/* Print out the i387 floating point state. Note that we ignore FRAME 201130803Smarcel in the code below. That's OK since floating-point registers are 202130803Smarcel never saved on the stack. */ 203130803Smarcel 20498944Sobrienvoid 205130803Smarceli387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file, 206130803Smarcel struct frame_info *frame, const char *args) 20798944Sobrien{ 208130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame)); 209130803Smarcel char buf[4]; 210130803Smarcel ULONGEST fctrl; 211130803Smarcel ULONGEST fstat; 212130803Smarcel ULONGEST ftag; 213130803Smarcel ULONGEST fiseg; 214130803Smarcel ULONGEST fioff; 215130803Smarcel ULONGEST foseg; 216130803Smarcel ULONGEST fooff; 217130803Smarcel ULONGEST fop; 21898944Sobrien int fpreg; 21998944Sobrien int top; 22098944Sobrien 221130803Smarcel gdb_assert (gdbarch == get_frame_arch (frame)); 222130803Smarcel 223130803Smarcel /* Define I387_ST0_REGNUM such that we use the proper definitions 224130803Smarcel for FRAME's architecture. */ 225130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum 226130803Smarcel 227130803Smarcel fctrl = get_frame_register_unsigned (frame, I387_FCTRL_REGNUM); 228130803Smarcel fstat = get_frame_register_unsigned (frame, I387_FSTAT_REGNUM); 229130803Smarcel ftag = get_frame_register_unsigned (frame, I387_FTAG_REGNUM); 230130803Smarcel fiseg = get_frame_register_unsigned (frame, I387_FISEG_REGNUM); 231130803Smarcel fioff = get_frame_register_unsigned (frame, I387_FIOFF_REGNUM); 232130803Smarcel foseg = get_frame_register_unsigned (frame, I387_FOSEG_REGNUM); 233130803Smarcel fooff = get_frame_register_unsigned (frame, I387_FOOFF_REGNUM); 234130803Smarcel fop = get_frame_register_unsigned (frame, I387_FOP_REGNUM); 235130803Smarcel 23698944Sobrien top = ((fstat >> 11) & 7); 23798944Sobrien 23898944Sobrien for (fpreg = 7; fpreg >= 0; fpreg--) 23998944Sobrien { 240130803Smarcel unsigned char raw[I386_MAX_REGISTER_SIZE]; 24198944Sobrien int tag = (ftag >> (fpreg * 2)) & 3; 24298944Sobrien int i; 24398944Sobrien 244130803Smarcel fprintf_filtered (file, "%sR%d: ", fpreg == top ? "=>" : " ", fpreg); 24598944Sobrien 24698944Sobrien switch (tag) 24798944Sobrien { 24898944Sobrien case 0: 249130803Smarcel fputs_filtered ("Valid ", file); 25098944Sobrien break; 25198944Sobrien case 1: 252130803Smarcel fputs_filtered ("Zero ", file); 25398944Sobrien break; 25498944Sobrien case 2: 255130803Smarcel fputs_filtered ("Special ", file); 25698944Sobrien break; 25798944Sobrien case 3: 258130803Smarcel fputs_filtered ("Empty ", file); 25998944Sobrien break; 26098944Sobrien } 26198944Sobrien 262130803Smarcel get_frame_register (frame, (fpreg + 8 - top) % 8 + I387_ST0_REGNUM, raw); 26398944Sobrien 264130803Smarcel fputs_filtered ("0x", file); 26598944Sobrien for (i = 9; i >= 0; i--) 266130803Smarcel fprintf_filtered (file, "%02x", raw[i]); 26798944Sobrien 26898944Sobrien if (tag != 3) 269130803Smarcel print_i387_ext (raw, file); 27098944Sobrien 271130803Smarcel fputs_filtered ("\n", file); 27298944Sobrien } 27398944Sobrien 274130803Smarcel fputs_filtered ("\n", file); 27598944Sobrien 276130803Smarcel print_i387_status_word (fstat, file); 277130803Smarcel print_i387_control_word (fctrl, file); 278130803Smarcel fprintf_filtered (file, "Tag Word: %s\n", 279130803Smarcel local_hex_string_custom (ftag, "04")); 280130803Smarcel fprintf_filtered (file, "Instruction Pointer: %s:", 281130803Smarcel local_hex_string_custom (fiseg, "02")); 282130803Smarcel fprintf_filtered (file, "%s\n", local_hex_string_custom (fioff, "08")); 283130803Smarcel fprintf_filtered (file, "Operand Pointer: %s:", 284130803Smarcel local_hex_string_custom (foseg, "02")); 285130803Smarcel fprintf_filtered (file, "%s\n", local_hex_string_custom (fooff, "08")); 286130803Smarcel fprintf_filtered (file, "Opcode: %s\n", 287130803Smarcel local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04")); 288130803Smarcel 289130803Smarcel#undef I387_ST0_REGNUM 29098944Sobrien} 291130803Smarcel 292130803Smarcel 293130803Smarcel/* Read a value of type TYPE from register REGNUM in frame FRAME, and 294130803Smarcel return its contents in TO. */ 295130803Smarcel 296130803Smarcelvoid 297130803Smarceli387_register_to_value (struct frame_info *frame, int regnum, 298130803Smarcel struct type *type, void *to) 299130803Smarcel{ 300130803Smarcel char from[I386_MAX_REGISTER_SIZE]; 301130803Smarcel 302130803Smarcel gdb_assert (i386_fp_regnum_p (regnum)); 303130803Smarcel 304130803Smarcel /* We only support floating-point values. */ 305130803Smarcel if (TYPE_CODE (type) != TYPE_CODE_FLT) 306130803Smarcel { 307130803Smarcel warning ("Cannot convert floating-point register value " 308130803Smarcel "to non-floating-point type."); 309130803Smarcel return; 310130803Smarcel } 311130803Smarcel 312130803Smarcel /* Convert to TYPE. This should be a no-op if TYPE is equivalent to 313130803Smarcel the extended floating-point format used by the FPU. */ 314130803Smarcel get_frame_register (frame, regnum, from); 315130803Smarcel convert_typed_floating (from, builtin_type_i387_ext, to, type); 316130803Smarcel} 317130803Smarcel 318130803Smarcel/* Write the contents FROM of a value of type TYPE into register 319130803Smarcel REGNUM in frame FRAME. */ 320130803Smarcel 321130803Smarcelvoid 322130803Smarceli387_value_to_register (struct frame_info *frame, int regnum, 323130803Smarcel struct type *type, const void *from) 324130803Smarcel{ 325130803Smarcel char to[I386_MAX_REGISTER_SIZE]; 326130803Smarcel 327130803Smarcel gdb_assert (i386_fp_regnum_p (regnum)); 328130803Smarcel 329130803Smarcel /* We only support floating-point values. */ 330130803Smarcel if (TYPE_CODE (type) != TYPE_CODE_FLT) 331130803Smarcel { 332130803Smarcel warning ("Cannot convert non-floating-point type " 333130803Smarcel "to floating-point register value."); 334130803Smarcel return; 335130803Smarcel } 336130803Smarcel 337130803Smarcel /* Convert from TYPE. This should be a no-op if TYPE is equivalent 338130803Smarcel to the extended floating-point format used by the FPU. */ 339130803Smarcel convert_typed_floating (from, type, to, builtin_type_i387_ext); 340130803Smarcel put_frame_register (frame, regnum, to); 341130803Smarcel} 342130803Smarcel 343130803Smarcel 344130803Smarcel 345130803Smarcel/* Handle FSAVE and FXSAVE formats. */ 346130803Smarcel 347130803Smarcel/* FIXME: kettenis/20030927: The functions below should accept a 348130803Smarcel `regcache' argument, but I don't want to change the function 349130803Smarcel signature just yet. There's some band-aid in the functions below 350130803Smarcel in the form of the `regcache' local variables. This will ease the 351130803Smarcel transition later on. */ 352130803Smarcel 353130803Smarcel/* At fsave_offset[REGNUM] you'll find the offset to the location in 354130803Smarcel the data structure used by the "fsave" instruction where GDB 355130803Smarcel register REGNUM is stored. */ 356130803Smarcel 357130803Smarcelstatic int fsave_offset[] = 358130803Smarcel{ 359130803Smarcel 28 + 0 * 10, /* %st(0) ... */ 360130803Smarcel 28 + 1 * 10, 361130803Smarcel 28 + 2 * 10, 362130803Smarcel 28 + 3 * 10, 363130803Smarcel 28 + 4 * 10, 364130803Smarcel 28 + 5 * 10, 365130803Smarcel 28 + 6 * 10, 366130803Smarcel 28 + 7 * 10, /* ... %st(7). */ 367130803Smarcel 0, /* `fctrl' (16 bits). */ 368130803Smarcel 4, /* `fstat' (16 bits). */ 369130803Smarcel 8, /* `ftag' (16 bits). */ 370130803Smarcel 16, /* `fiseg' (16 bits). */ 371130803Smarcel 12, /* `fioff'. */ 372130803Smarcel 24, /* `foseg' (16 bits). */ 373130803Smarcel 20, /* `fooff'. */ 374130803Smarcel 18 /* `fop' (bottom 11 bits). */ 375130803Smarcel}; 376130803Smarcel 377130803Smarcel#define FSAVE_ADDR(fsave, regnum) \ 378130803Smarcel (fsave + fsave_offset[regnum - I387_ST0_REGNUM]) 379130803Smarcel 380130803Smarcel 381130803Smarcel/* Fill register REGNUM in REGCACHE with the appropriate value from 382130803Smarcel *FSAVE. This function masks off any of the reserved bits in 383130803Smarcel *FSAVE. */ 384130803Smarcel 385130803Smarcelvoid 386130803Smarceli387_supply_fsave (struct regcache *regcache, int regnum, const void *fsave) 387130803Smarcel{ 388130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); 389130803Smarcel const char *regs = fsave; 390130803Smarcel int i; 391130803Smarcel 392130803Smarcel gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); 393130803Smarcel 394130803Smarcel /* Define I387_ST0_REGNUM such that we use the proper definitions 395130803Smarcel for REGCACHE's architecture. */ 396130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum 397130803Smarcel 398130803Smarcel for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++) 399130803Smarcel if (regnum == -1 || regnum == i) 400130803Smarcel { 401130803Smarcel if (fsave == NULL) 402130803Smarcel { 403130803Smarcel regcache_raw_supply (regcache, i, NULL); 404130803Smarcel continue; 405130803Smarcel } 406130803Smarcel 407130803Smarcel /* Most of the FPU control registers occupy only 16 bits in the 408130803Smarcel fsave area. Give those a special treatment. */ 409130803Smarcel if (i >= I387_FCTRL_REGNUM 410130803Smarcel && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM) 411130803Smarcel { 412130803Smarcel unsigned char val[4]; 413130803Smarcel 414130803Smarcel memcpy (val, FSAVE_ADDR (regs, i), 2); 415130803Smarcel val[2] = val[3] = 0; 416130803Smarcel if (i == I387_FOP_REGNUM) 417130803Smarcel val[1] &= ((1 << 3) - 1); 418130803Smarcel regcache_raw_supply (regcache, i, val); 419130803Smarcel } 420130803Smarcel else 421130803Smarcel regcache_raw_supply (regcache, i, FSAVE_ADDR (regs, i)); 422130803Smarcel } 423130803Smarcel#undef I387_ST0_REGNUM 424130803Smarcel} 425130803Smarcel 426130803Smarcel/* Fill register REGNUM (if it is a floating-point register) in *FSAVE 427130803Smarcel with the value in GDB's register cache. If REGNUM is -1, do this 428130803Smarcel for all registers. This function doesn't touch any of the reserved 429130803Smarcel bits in *FSAVE. */ 430130803Smarcel 431130803Smarcelvoid 432130803Smarceli387_fill_fsave (void *fsave, int regnum) 433130803Smarcel{ 434130803Smarcel struct regcache *regcache = current_regcache; 435130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); 436130803Smarcel char *regs = fsave; 437130803Smarcel int i; 438130803Smarcel 439130803Smarcel gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); 440130803Smarcel 441130803Smarcel /* Define I387_ST0_REGNUM such that we use the proper definitions 442130803Smarcel for REGCACHE's architecture. */ 443130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum 444130803Smarcel 445130803Smarcel for (i = I387_ST0_REGNUM; i < I387_XMM0_REGNUM; i++) 446130803Smarcel if (regnum == -1 || regnum == i) 447130803Smarcel { 448130803Smarcel /* Most of the FPU control registers occupy only 16 bits in 449130803Smarcel the fsave area. Give those a special treatment. */ 450130803Smarcel if (i >= I387_FCTRL_REGNUM 451130803Smarcel && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM) 452130803Smarcel { 453130803Smarcel unsigned char buf[4]; 454130803Smarcel 455130803Smarcel regcache_raw_collect (regcache, i, buf); 456130803Smarcel 457130803Smarcel if (i == I387_FOP_REGNUM) 458130803Smarcel { 459130803Smarcel /* The opcode occupies only 11 bits. Make sure we 460130803Smarcel don't touch the other bits. */ 461130803Smarcel buf[1] &= ((1 << 3) - 1); 462130803Smarcel buf[1] |= ((FSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1)); 463130803Smarcel } 464130803Smarcel memcpy (FSAVE_ADDR (regs, i), buf, 2); 465130803Smarcel } 466130803Smarcel else 467130803Smarcel regcache_raw_collect (regcache, i, FSAVE_ADDR (regs, i)); 468130803Smarcel } 469130803Smarcel#undef I387_ST0_REGNUM 470130803Smarcel} 471130803Smarcel 472130803Smarcel 473130803Smarcel/* At fxsave_offset[REGNUM] you'll find the offset to the location in 474130803Smarcel the data structure used by the "fxsave" instruction where GDB 475130803Smarcel register REGNUM is stored. */ 476130803Smarcel 477130803Smarcelstatic int fxsave_offset[] = 478130803Smarcel{ 479130803Smarcel 32, /* %st(0) through ... */ 480130803Smarcel 48, 481130803Smarcel 64, 482130803Smarcel 80, 483130803Smarcel 96, 484130803Smarcel 112, 485130803Smarcel 128, 486130803Smarcel 144, /* ... %st(7) (80 bits each). */ 487130803Smarcel 0, /* `fctrl' (16 bits). */ 488130803Smarcel 2, /* `fstat' (16 bits). */ 489130803Smarcel 4, /* `ftag' (16 bits). */ 490130803Smarcel 12, /* `fiseg' (16 bits). */ 491130803Smarcel 8, /* `fioff'. */ 492130803Smarcel 20, /* `foseg' (16 bits). */ 493130803Smarcel 16, /* `fooff'. */ 494130803Smarcel 6, /* `fop' (bottom 11 bits). */ 495130803Smarcel 160 + 0 * 16, /* %xmm0 through ... */ 496130803Smarcel 160 + 1 * 16, 497130803Smarcel 160 + 2 * 16, 498130803Smarcel 160 + 3 * 16, 499130803Smarcel 160 + 4 * 16, 500130803Smarcel 160 + 5 * 16, 501130803Smarcel 160 + 6 * 16, 502130803Smarcel 160 + 7 * 16, 503130803Smarcel 160 + 8 * 16, 504130803Smarcel 160 + 9 * 16, 505130803Smarcel 160 + 10 * 16, 506130803Smarcel 160 + 11 * 16, 507130803Smarcel 160 + 12 * 16, 508130803Smarcel 160 + 13 * 16, 509130803Smarcel 160 + 14 * 16, 510130803Smarcel 160 + 15 * 16, /* ... %xmm15 (128 bits each). */ 511130803Smarcel}; 512130803Smarcel 513130803Smarcel#define FXSAVE_ADDR(fxsave, regnum) \ 514130803Smarcel (fxsave + fxsave_offset[regnum - I387_ST0_REGNUM]) 515130803Smarcel 516130803Smarcel/* We made an unfortunate choice in putting %mxcsr after the SSE 517130803Smarcel registers %xmm0-%xmm7 instead of before, since it makes supporting 518130803Smarcel the registers %xmm8-%xmm15 on AMD64 a bit involved. Therefore we 519130803Smarcel don't include the offset for %mxcsr here above. */ 520130803Smarcel 521130803Smarcel#define FXSAVE_MXCSR_ADDR(fxsave) (fxsave + 24) 522130803Smarcel 523130803Smarcelstatic int i387_tag (const unsigned char *raw); 524130803Smarcel 525130803Smarcel 526130803Smarcel/* Fill register REGNUM in REGCACHE with the appropriate 527130803Smarcel floating-point or SSE register value from *FXSAVE. This function 528130803Smarcel masks off any of the reserved bits in *FXSAVE. */ 529130803Smarcel 530130803Smarcelvoid 531130803Smarceli387_supply_fxsave (struct regcache *regcache, int regnum, const void *fxsave) 532130803Smarcel{ 533130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache)); 534130803Smarcel const char *regs = fxsave; 535130803Smarcel int i; 536130803Smarcel 537130803Smarcel gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); 538130803Smarcel gdb_assert (tdep->num_xmm_regs > 0); 539130803Smarcel 540130803Smarcel /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the 541130803Smarcel proper definitions for REGCACHE's architecture. */ 542130803Smarcel 543130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum 544130803Smarcel#define I387_NUM_XMM_REGS tdep->num_xmm_regs 545130803Smarcel 546130803Smarcel for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++) 547130803Smarcel if (regnum == -1 || regnum == i) 548130803Smarcel { 549130803Smarcel if (regs == NULL) 550130803Smarcel { 551130803Smarcel regcache_raw_supply (regcache, i, NULL); 552130803Smarcel continue; 553130803Smarcel } 554130803Smarcel 555130803Smarcel /* Most of the FPU control registers occupy only 16 bits in 556130803Smarcel the fxsave area. Give those a special treatment. */ 557130803Smarcel if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM 558130803Smarcel && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM) 559130803Smarcel { 560130803Smarcel unsigned char val[4]; 561130803Smarcel 562130803Smarcel memcpy (val, FXSAVE_ADDR (regs, i), 2); 563130803Smarcel val[2] = val[3] = 0; 564130803Smarcel if (i == I387_FOP_REGNUM) 565130803Smarcel val[1] &= ((1 << 3) - 1); 566130803Smarcel else if (i== I387_FTAG_REGNUM) 567130803Smarcel { 568130803Smarcel /* The fxsave area contains a simplified version of 569130803Smarcel the tag word. We have to look at the actual 80-bit 570130803Smarcel FP data to recreate the traditional i387 tag word. */ 571130803Smarcel 572130803Smarcel unsigned long ftag = 0; 573130803Smarcel int fpreg; 574130803Smarcel int top; 575130803Smarcel 576130803Smarcel top = ((FXSAVE_ADDR (regs, I387_FSTAT_REGNUM))[1] >> 3); 577130803Smarcel top &= 0x7; 578130803Smarcel 579130803Smarcel for (fpreg = 7; fpreg >= 0; fpreg--) 580130803Smarcel { 581130803Smarcel int tag; 582130803Smarcel 583130803Smarcel if (val[0] & (1 << fpreg)) 584130803Smarcel { 585130803Smarcel int regnum = (fpreg + 8 - top) % 8 + I387_ST0_REGNUM; 586130803Smarcel tag = i387_tag (FXSAVE_ADDR (regs, regnum)); 587130803Smarcel } 588130803Smarcel else 589130803Smarcel tag = 3; /* Empty */ 590130803Smarcel 591130803Smarcel ftag |= tag << (2 * fpreg); 592130803Smarcel } 593130803Smarcel val[0] = ftag & 0xff; 594130803Smarcel val[1] = (ftag >> 8) & 0xff; 595130803Smarcel } 596130803Smarcel regcache_raw_supply (regcache, i, val); 597130803Smarcel } 598130803Smarcel else 599130803Smarcel regcache_raw_supply (regcache, i, FXSAVE_ADDR (regs, i)); 600130803Smarcel } 601130803Smarcel 602130803Smarcel if (regnum == I387_MXCSR_REGNUM || regnum == -1) 603130803Smarcel { 604130803Smarcel if (regs == NULL) 605130803Smarcel regcache_raw_supply (regcache, I387_MXCSR_REGNUM, NULL); 606130803Smarcel else 607130803Smarcel regcache_raw_supply (regcache, I387_MXCSR_REGNUM, 608130803Smarcel FXSAVE_MXCSR_ADDR (regs)); 609130803Smarcel } 610130803Smarcel 611130803Smarcel#undef I387_ST0_REGNUM 612130803Smarcel#undef I387_NUM_XMM_REGS 613130803Smarcel} 614130803Smarcel 615130803Smarcel/* Fill register REGNUM (if it is a floating-point or SSE register) in 616130803Smarcel *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for 617130803Smarcel all registers. This function doesn't touch any of the reserved 618130803Smarcel bits in *FXSAVE. */ 619130803Smarcel 620130803Smarcelvoid 621130803Smarceli387_collect_fxsave (const struct regcache *regcache, int regnum, void *fxsave) 622130803Smarcel{ 623130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); 624130803Smarcel char *regs = fxsave; 625130803Smarcel int i; 626130803Smarcel 627130803Smarcel gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM); 628130803Smarcel gdb_assert (tdep->num_xmm_regs > 0); 629130803Smarcel 630130803Smarcel /* Define I387_ST0_REGNUM and I387_NUM_XMM_REGS such that we use the 631130803Smarcel proper definitions for REGCACHE's architecture. */ 632130803Smarcel 633130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum 634130803Smarcel#define I387_NUM_XMM_REGS tdep->num_xmm_regs 635130803Smarcel 636130803Smarcel for (i = I387_ST0_REGNUM; i < I387_MXCSR_REGNUM; i++) 637130803Smarcel if (regnum == -1 || regnum == i) 638130803Smarcel { 639130803Smarcel /* Most of the FPU control registers occupy only 16 bits in 640130803Smarcel the fxsave area. Give those a special treatment. */ 641130803Smarcel if (i >= I387_FCTRL_REGNUM && i < I387_XMM0_REGNUM 642130803Smarcel && i != I387_FIOFF_REGNUM && i != I387_FOOFF_REGNUM) 643130803Smarcel { 644130803Smarcel unsigned char buf[4]; 645130803Smarcel 646130803Smarcel regcache_raw_collect (regcache, i, buf); 647130803Smarcel 648130803Smarcel if (i == I387_FOP_REGNUM) 649130803Smarcel { 650130803Smarcel /* The opcode occupies only 11 bits. Make sure we 651130803Smarcel don't touch the other bits. */ 652130803Smarcel buf[1] &= ((1 << 3) - 1); 653130803Smarcel buf[1] |= ((FXSAVE_ADDR (regs, i))[1] & ~((1 << 3) - 1)); 654130803Smarcel } 655130803Smarcel else if (i == I387_FTAG_REGNUM) 656130803Smarcel { 657130803Smarcel /* Converting back is much easier. */ 658130803Smarcel 659130803Smarcel unsigned short ftag; 660130803Smarcel int fpreg; 661130803Smarcel 662130803Smarcel ftag = (buf[1] << 8) | buf[0]; 663130803Smarcel buf[0] = 0; 664130803Smarcel buf[1] = 0; 665130803Smarcel 666130803Smarcel for (fpreg = 7; fpreg >= 0; fpreg--) 667130803Smarcel { 668130803Smarcel int tag = (ftag >> (fpreg * 2)) & 3; 669130803Smarcel 670130803Smarcel if (tag != 3) 671130803Smarcel buf[0] |= (1 << fpreg); 672130803Smarcel } 673130803Smarcel } 674130803Smarcel memcpy (FXSAVE_ADDR (regs, i), buf, 2); 675130803Smarcel } 676130803Smarcel else 677130803Smarcel regcache_raw_collect (regcache, i, FXSAVE_ADDR (regs, i)); 678130803Smarcel } 679130803Smarcel 680130803Smarcel if (regnum == I387_MXCSR_REGNUM || regnum == -1) 681130803Smarcel regcache_raw_collect (regcache, I387_MXCSR_REGNUM, 682130803Smarcel FXSAVE_MXCSR_ADDR (regs)); 683130803Smarcel 684130803Smarcel#undef I387_ST0_REGNUM 685130803Smarcel#undef I387_NUM_XMM_REGS 686130803Smarcel} 687130803Smarcel 688130803Smarcel/* Fill register REGNUM (if it is a floating-point or SSE register) in 689130803Smarcel *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do 690130803Smarcel this for all registers. This function doesn't touch any of the 691130803Smarcel reserved bits in *FXSAVE. */ 692130803Smarcel 693130803Smarcelvoid 694130803Smarceli387_fill_fxsave (void *fxsave, int regnum) 695130803Smarcel{ 696130803Smarcel i387_collect_fxsave (current_regcache, regnum, fxsave); 697130803Smarcel} 698130803Smarcel 699130803Smarcel/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in 700130803Smarcel *RAW. */ 701130803Smarcel 702130803Smarcelstatic int 703130803Smarceli387_tag (const unsigned char *raw) 704130803Smarcel{ 705130803Smarcel int integer; 706130803Smarcel unsigned int exponent; 707130803Smarcel unsigned long fraction[2]; 708130803Smarcel 709130803Smarcel integer = raw[7] & 0x80; 710130803Smarcel exponent = (((raw[9] & 0x7f) << 8) | raw[8]); 711130803Smarcel fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]); 712130803Smarcel fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16) 713130803Smarcel | (raw[5] << 8) | raw[4]); 714130803Smarcel 715130803Smarcel if (exponent == 0x7fff) 716130803Smarcel { 717130803Smarcel /* Special. */ 718130803Smarcel return (2); 719130803Smarcel } 720130803Smarcel else if (exponent == 0x0000) 721130803Smarcel { 722130803Smarcel if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer) 723130803Smarcel { 724130803Smarcel /* Zero. */ 725130803Smarcel return (1); 726130803Smarcel } 727130803Smarcel else 728130803Smarcel { 729130803Smarcel /* Special. */ 730130803Smarcel return (2); 731130803Smarcel } 732130803Smarcel } 733130803Smarcel else 734130803Smarcel { 735130803Smarcel if (integer) 736130803Smarcel { 737130803Smarcel /* Valid. */ 738130803Smarcel return (0); 739130803Smarcel } 740130803Smarcel else 741130803Smarcel { 742130803Smarcel /* Special. */ 743130803Smarcel return (2); 744130803Smarcel } 745130803Smarcel } 746130803Smarcel} 747130803Smarcel 748130803Smarcel/* Prepare the FPU stack in REGCACHE for a function return. */ 749130803Smarcel 750130803Smarcelvoid 751130803Smarceli387_return_value (struct gdbarch *gdbarch, struct regcache *regcache) 752130803Smarcel{ 753130803Smarcel struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 754130803Smarcel ULONGEST fstat; 755130803Smarcel 756130803Smarcel /* Define I387_ST0_REGNUM such that we use the proper 757130803Smarcel definitions for the architecture. */ 758130803Smarcel#define I387_ST0_REGNUM tdep->st0_regnum 759130803Smarcel 760130803Smarcel /* Set the top of the floating-point register stack to 7. The 761130803Smarcel actual value doesn't really matter, but 7 is what a normal 762130803Smarcel function return would end up with if the program started out with 763130803Smarcel a freshly initialized FPU. */ 764130803Smarcel regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat); 765130803Smarcel fstat |= (7 << 11); 766130803Smarcel regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat); 767130803Smarcel 768130803Smarcel /* Mark %st(1) through %st(7) as empty. Since we set the top of the 769130803Smarcel floating-point register stack to 7, the appropriate value for the 770130803Smarcel tag word is 0x3fff. */ 771130803Smarcel regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff); 772130803Smarcel 773130803Smarcel#undef I387_ST0_REGNUM 774130803Smarcel} 775