2012-03-08 Stan Shebs <stan@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / gdbserver / i387-fp.c
index 7ef4ba3b7a1e6487ac5eb95a114f5591b64824c8..d2543b21327ee8d0ef0c5dfbea42e5e3196dae96 100644 (file)
@@ -1,6 +1,5 @@
 /* i387-specific utility functions, for the remote server for GDB.
-   Copyright (C) 2000, 2001, 2002, 2005, 2007, 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2000-2013 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -19,6 +18,7 @@
 
 #include "server.h"
 #include "i387-fp.h"
+#include "i386-xstate.h"
 
 int num_xmm_registers = 8;
 
@@ -72,6 +72,46 @@ struct i387_fxsave {
   unsigned char xmm_space[256];
 };
 
+struct i387_xsave {
+  /* All these are only sixteen bits, plus padding, except for fop (which
+     is only eleven bits), and fooff / fioff (which are 32 bits each).  */
+  unsigned short fctrl;
+  unsigned short fstat;
+  unsigned short ftag;
+  unsigned short fop;
+  unsigned int fioff;
+  unsigned short fiseg;
+  unsigned short pad1;
+  unsigned int fooff;
+  unsigned short foseg;
+  unsigned short pad12;
+
+  unsigned int mxcsr;
+  unsigned int mxcsr_mask;
+
+  /* Space for eight 80-bit FP values in 128-bit spaces.  */
+  unsigned char st_space[128];
+
+  /* Space for eight 128-bit XMM values, or 16 on x86-64.  */
+  unsigned char xmm_space[256];
+
+  unsigned char reserved1[48];
+
+  /* The extended control register 0 (the XFEATURE_ENABLED_MASK
+     register).  */
+  unsigned long long xcr0;
+
+  unsigned char reserved2[40];
+
+  /* The XSTATE_BV bit vector.  */
+  unsigned long long xstate_bv;
+
+  unsigned char reserved3[56];
+
+  /* Space for eight upper 128-bit YMM values, or 16 on x86-64.  */
+  unsigned char ymmh_space[256];
+};
+
 void
 i387_cache_to_fsave (struct regcache *regcache, void *buf)
 {
@@ -199,6 +239,128 @@ i387_cache_to_fxsave (struct regcache *regcache, void *buf)
   fp->foseg = val;
 }
 
+void
+i387_cache_to_xsave (struct regcache *regcache, void *buf)
+{
+  struct i387_xsave *fp = (struct i387_xsave *) buf;
+  int i;
+  unsigned long val, val2;
+  unsigned int clear_bv;
+  unsigned long long xstate_bv = 0;
+  char raw[16];
+  char *p;
+
+  /* The supported bits in `xstat_bv' are 1 byte.  Clear part in
+     vector registers if its bit in xstat_bv is zero.  */
+  clear_bv = (~fp->xstate_bv) & x86_xcr0;
+
+  /* Clear part in x87 and vector registers if its bit in xstat_bv is
+     zero.  */
+  if (clear_bv)
+    {
+      if ((clear_bv & I386_XSTATE_X87))
+       for (i = 0; i < 8; i++)
+         memset (((char *) &fp->st_space[0]) + i * 16, 0, 10);
+
+      if ((clear_bv & I386_XSTATE_SSE))
+       for (i = 0; i < num_xmm_registers; i++) 
+         memset (((char *) &fp->xmm_space[0]) + i * 16, 0, 16);
+
+      if ((clear_bv & I386_XSTATE_AVX))
+       for (i = 0; i < num_xmm_registers; i++) 
+         memset (((char *) &fp->ymmh_space[0]) + i * 16, 0, 16);
+    }
+
+  /* Check if any x87 registers are changed.  */
+  if ((x86_xcr0 & I386_XSTATE_X87))
+    {
+      int st0_regnum = find_regno ("st0");
+
+      for (i = 0; i < 8; i++)
+       {
+         collect_register (regcache, i + st0_regnum, raw);
+         p = ((char *) &fp->st_space[0]) + i * 16;
+         if (memcmp (raw, p, 10))
+           {
+             xstate_bv |= I386_XSTATE_X87;
+             memcpy (p, raw, 10);
+           }
+       }
+    }
+
+  /* Check if any SSE registers are changed.  */
+  if ((x86_xcr0 & I386_XSTATE_SSE))
+    {
+      int xmm0_regnum = find_regno ("xmm0");
+
+      for (i = 0; i < num_xmm_registers; i++) 
+       {
+         collect_register (regcache, i + xmm0_regnum, raw);
+         p = ((char *) &fp->xmm_space[0]) + i * 16;
+         if (memcmp (raw, p, 16))
+           {
+             xstate_bv |= I386_XSTATE_SSE;
+             memcpy (p, raw, 16);
+           }
+       }
+    }
+
+  /* Check if any AVX registers are changed.  */
+  if ((x86_xcr0 & I386_XSTATE_AVX))
+    {
+      int ymm0h_regnum = find_regno ("ymm0h");
+
+      for (i = 0; i < num_xmm_registers; i++) 
+       {
+         collect_register (regcache, i + ymm0h_regnum, raw);
+         p = ((char *) &fp->ymmh_space[0]) + i * 16;
+         if (memcmp (raw, p, 16))
+           {
+             xstate_bv |= I386_XSTATE_AVX;
+             memcpy (p, raw, 16);
+           }
+       }
+    }
+
+  /* Update the corresponding bits in xstate_bv if any SSE/AVX
+     registers are changed.  */
+  fp->xstate_bv |= xstate_bv;
+
+  collect_register_by_name (regcache, "fioff", &fp->fioff);
+  collect_register_by_name (regcache, "fooff", &fp->fooff);
+  collect_register_by_name (regcache, "mxcsr", &fp->mxcsr);
+
+  /* This one's 11 bits... */
+  collect_register_by_name (regcache, "fop", &val2);
+  fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
+
+  /* Some registers are 16-bit.  */
+  collect_register_by_name (regcache, "fctrl", &val);
+  fp->fctrl = val;
+
+  collect_register_by_name (regcache, "fstat", &val);
+  fp->fstat = val;
+
+  /* Convert to the simplifed tag form stored in fxsave data.  */
+  collect_register_by_name (regcache, "ftag", &val);
+  val &= 0xFFFF;
+  val2 = 0;
+  for (i = 7; i >= 0; i--)
+    {
+      int tag = (val >> (i * 2)) & 3;
+
+      if (tag != 3)
+       val2 |= (1 << i);
+    }
+  fp->ftag = val2;
+
+  collect_register_by_name (regcache, "fiseg", &val);
+  fp->fiseg = val;
+
+  collect_register_by_name (regcache, "foseg", &val);
+  fp->foseg = val;
+}
+
 static int
 i387_ftag (struct i387_fxsave *fp, int regno)
 {
@@ -296,3 +458,107 @@ i387_fxsave_to_cache (struct regcache *regcache, const void *buf)
   val = (fp->fop) & 0x7FF;
   supply_register_by_name (regcache, "fop", &val);
 }
+
+void
+i387_xsave_to_cache (struct regcache *regcache, const void *buf)
+{
+  struct i387_xsave *fp = (struct i387_xsave *) buf;
+  struct i387_fxsave *fxp = (struct i387_fxsave *) buf;
+  int i, top;
+  unsigned long val;
+  unsigned int clear_bv;
+  gdb_byte *p;
+
+  /* The supported bits in `xstat_bv' are 1 byte.  Clear part in
+     vector registers if its bit in xstat_bv is zero.  */
+  clear_bv = (~fp->xstate_bv) & x86_xcr0;
+
+  /* Check if any x87 registers are changed.  */
+  if ((x86_xcr0 & I386_XSTATE_X87) != 0)
+    {
+      int st0_regnum = find_regno ("st0");
+
+      if ((clear_bv & I386_XSTATE_X87) != 0)
+       {
+         for (i = 0; i < 8; i++)
+           supply_register_zeroed (regcache, i + st0_regnum);
+       }
+      else
+       {
+         p = (gdb_byte *) &fp->st_space[0];
+         for (i = 0; i < 8; i++)
+           supply_register (regcache, i + st0_regnum, p + i * 16);
+       }
+    }
+
+  if ((x86_xcr0 & I386_XSTATE_SSE) != 0)
+    {
+      int xmm0_regnum = find_regno ("xmm0");
+
+      if ((clear_bv & I386_XSTATE_SSE))
+       {
+         for (i = 0; i < num_xmm_registers; i++)
+           supply_register_zeroed (regcache, i + xmm0_regnum);
+       }
+      else
+       {
+         p = (gdb_byte *) &fp->xmm_space[0];
+         for (i = 0; i < num_xmm_registers; i++)
+           supply_register (regcache, i + xmm0_regnum, p + i * 16);
+       }
+    }
+
+  if ((x86_xcr0 & I386_XSTATE_AVX) != 0)
+    {
+      int ymm0h_regnum = find_regno ("ymm0h");
+
+      if ((clear_bv & I386_XSTATE_AVX) != 0)
+       {
+         for (i = 0; i < num_xmm_registers; i++)
+           supply_register_zeroed (regcache, i + ymm0h_regnum);
+       }
+      else
+       {
+         p = (gdb_byte *) &fp->ymmh_space[0];
+         for (i = 0; i < num_xmm_registers; i++)
+           supply_register (regcache, i + ymm0h_regnum, p + i * 16);
+       }
+    }
+
+  supply_register_by_name (regcache, "fioff", &fp->fioff);
+  supply_register_by_name (regcache, "fooff", &fp->fooff);
+  supply_register_by_name (regcache, "mxcsr", &fp->mxcsr);
+
+  /* Some registers are 16-bit.  */
+  val = fp->fctrl & 0xFFFF;
+  supply_register_by_name (regcache, "fctrl", &val);
+
+  val = fp->fstat & 0xFFFF;
+  supply_register_by_name (regcache, "fstat", &val);
+
+  /* Generate the form of ftag data that GDB expects.  */
+  top = (fp->fstat >> 11) & 0x7;
+  val = 0;
+  for (i = 7; i >= 0; i--)
+    {
+      int tag;
+      if (fp->ftag & (1 << i))
+       tag = i387_ftag (fxp, (i + 8 - top) % 8);
+      else
+       tag = 3;
+      val |= tag << (2 * i);
+    }
+  supply_register_by_name (regcache, "ftag", &val);
+
+  val = fp->fiseg & 0xFFFF;
+  supply_register_by_name (regcache, "fiseg", &val);
+
+  val = fp->foseg & 0xFFFF;
+  supply_register_by_name (regcache, "foseg", &val);
+
+  val = (fp->fop) & 0x7FF;
+  supply_register_by_name (regcache, "fop", &val);
+}
+
+/* Default to SSE.  */
+unsigned long long x86_xcr0 = I386_XSTATE_SSE_MASK;
This page took 0.027877 seconds and 4 git commands to generate.