daily update
[binutils-gdb.git] / gdb / i387-tdep.c
index 27f3c5b6050c2685663c8ab9564084056279bef2..d24d322f3b3ff5d38550d10c28820f28d0efcc67 100644 (file)
@@ -1,7 +1,6 @@
 /* Intel 387 floating point stuff.
 
-   Copyright (C) 1988-1989, 1991-1994, 1998-2005, 2007-2012 Free
-   Software Foundation, Inc.
+   Copyright (C) 1988-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -29,7 +28,7 @@
 #include "value.h"
 
 #include "gdb_assert.h"
-#include "gdb_string.h"
+#include <string.h>
 
 #include "i386-tdep.h"
 #include "i387-tdep.h"
@@ -237,9 +236,7 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
   ULONGEST fop;
   int fop_p;
   int fpreg;
-  int fpreg_p;
   int top;
-  int top_p;
 
   gdb_assert (gdbarch == get_frame_arch (frame));
 
@@ -301,7 +298,7 @@ i387_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
 
          if (value_entirely_available (regval))
            {
-             const char *raw = value_contents (regval);
+             const gdb_byte *raw = value_contents (regval);
 
              fputs_filtered ("0x", file);
              for (i = 9; i >= 0; i--)
@@ -766,9 +763,22 @@ static int xsave_avxh_offset[] =
   576 + 15 * 16                /* Upper 128bit of ... %ymm15 (128 bits each).  */
 };
 
+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_AVXH_ADDR(tdep, xsave, regnum) \
   (xsave + xsave_avxh_offset[regnum - I387_YMM0H_REGNUM (tdep)])
 
+#define XSAVE_MPX_ADDR(tdep, xsave, regnum) \
+  (xsave + xsave_mpx_offset[regnum - I387_BND0R_REGNUM (tdep)])
+
 /* Similar to i387_supply_fxsave, but use XSAVE extended state.  */
 
 void
@@ -779,16 +789,18 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
   const gdb_byte *regs = xsave;
   int i;
   unsigned int clear_bv;
-  const gdb_byte *p;
+  static const gdb_byte zero[MAX_REGISTER_SIZE] = { 0 };
   enum
     {
       none = 0x0,
       x87 = 0x1,
       sse = 0x2,
       avxh = 0x4,
-      all = x87 | sse | avxh
+      mpx  = 0x8,
+      all = x87 | sse | avxh | mpx
     } regclass;
 
+  gdb_assert (regs != NULL);
   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
   gdb_assert (tdep->num_xmm_regs > 0);
 
@@ -797,6 +809,9 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
   else if (regnum >= I387_YMM0H_REGNUM (tdep)
           && regnum < I387_YMMENDH_REGNUM (tdep))
     regclass = avxh;
+  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;
@@ -806,7 +821,7 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
   else
     regclass = none;
 
-  if (regs != NULL && regclass != none)
+  if (regclass != none)
     {
       /* Get `xstat_bv'.  */
       const gdb_byte *xstate_bv_p = XSAVE_XSTATE_BV_ADDR (regs);
@@ -816,7 +831,16 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
       clear_bv = (~(*xstate_bv_p)) & tdep->xcr0;
     }
   else
-    clear_bv = I386_XSTATE_AVX_MASK;
+    clear_bv = I386_XSTATE_ALL_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)
     {
@@ -825,26 +849,34 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
 
     case avxh:
       if ((clear_bv & I386_XSTATE_AVX))
-       p = NULL;
+       regcache_raw_supply (regcache, regnum, zero);
+      else
+       regcache_raw_supply (regcache, regnum,
+                            XSAVE_AVXH_ADDR (tdep, regs, regnum));
+      return;
+
+    case mpx:
+      if ((clear_bv & I386_XSTATE_BNDREGS))
+       regcache_raw_supply (regcache, regnum, zero);
       else
-       p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
-      regcache_raw_supply (regcache, regnum, p);
+       regcache_raw_supply (regcache, regnum,
+                            XSAVE_MPX_ADDR (tdep, regs, regnum));
       return;
 
     case sse:
       if ((clear_bv & I386_XSTATE_SSE))
-       p = NULL;
+       regcache_raw_supply (regcache, regnum, zero);
       else
-       p = FXSAVE_ADDR (tdep, regs, regnum);
-      regcache_raw_supply (regcache, regnum, p);
+       regcache_raw_supply (regcache, regnum,
+                            FXSAVE_ADDR (tdep, regs, regnum));
       return;
 
     case x87:
       if ((clear_bv & I386_XSTATE_X87))
-       p = NULL;
+       regcache_raw_supply (regcache, regnum, zero);
       else
-       p = FXSAVE_ADDR (tdep, regs, regnum);
-      regcache_raw_supply (regcache, regnum, p);
+       regcache_raw_supply (regcache, regnum,
+                            FXSAVE_ADDR (tdep, regs, regnum));
       return;
 
     case all:
@@ -852,16 +884,55 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
       if ((tdep->xcr0 & I386_XSTATE_AVX))
        {
          if ((clear_bv & I386_XSTATE_AVX))
-           p = NULL;
+           {
+             for (i = I387_YMM0H_REGNUM (tdep);
+                  i < I387_YMMENDH_REGNUM (tdep);
+                  i++)
+               regcache_raw_supply (regcache, i, zero);
+           }
          else
-           p = regs;
+           {
+             for (i = I387_YMM0H_REGNUM (tdep);
+                  i < I387_YMMENDH_REGNUM (tdep);
+                  i++)
+               regcache_raw_supply (regcache, i,
+                                    XSAVE_AVXH_ADDR (tdep, regs, i));
+           }
+       }
 
-         for (i = I387_YMM0H_REGNUM (tdep);
-              i < I387_YMMENDH_REGNUM (tdep); i++)
+      /* Handle the MPX registers.  */
+      if ((tdep->xcr0 & I386_XSTATE_BNDREGS))
+       {
+         if (clear_bv & I386_XSTATE_BNDREGS)
            {
-             if (p != NULL)
-               p = XSAVE_AVXH_ADDR (tdep, regs, i);
-             regcache_raw_supply (regcache, i, p);
+             for (i = I387_BND0R_REGNUM (tdep);
+                  i < I387_BNDCFGU_REGNUM (tdep); i++)
+               regcache_raw_supply (regcache, i, zero);
+           }
+         else
+           {
+             for (i = I387_BND0R_REGNUM (tdep);
+                  i < I387_BNDCFGU_REGNUM (tdep); i++)
+               regcache_raw_supply (regcache, i,
+                                    XSAVE_MPX_ADDR (tdep, regs, i));
+           }
+       }
+
+      /* Handle the MPX registers.  */
+      if ((tdep->xcr0 & I386_XSTATE_BNDCFG))
+       {
+         if (clear_bv & I386_XSTATE_BNDCFG)
+           {
+             for (i = I387_BNDCFGU_REGNUM (tdep);
+                  i < I387_MPXEND_REGNUM (tdep); i++)
+               regcache_raw_supply (regcache, i, zero);
+           }
+         else
+           {
+             for (i = I387_BNDCFGU_REGNUM (tdep);
+                  i < I387_MPXEND_REGNUM (tdep); i++)
+               regcache_raw_supply (regcache, i,
+                                    XSAVE_MPX_ADDR (tdep, regs, i));
            }
        }
 
@@ -869,16 +940,18 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
       if ((tdep->xcr0 & I386_XSTATE_SSE))
        {
          if ((clear_bv & I386_XSTATE_SSE))
-           p = NULL;
+           {
+             for (i = I387_XMM0_REGNUM (tdep);
+                  i < I387_MXCSR_REGNUM (tdep);
+                  i++)
+               regcache_raw_supply (regcache, i, zero);
+           }
          else
-           p = regs;
-
-         for (i = I387_XMM0_REGNUM (tdep);
-              i < I387_MXCSR_REGNUM (tdep); i++)
            {
-             if (p != NULL)
-               p = FXSAVE_ADDR (tdep, regs, i);
-             regcache_raw_supply (regcache, i, p);
+             for (i = I387_XMM0_REGNUM (tdep);
+                  i < I387_MXCSR_REGNUM (tdep); i++)
+               regcache_raw_supply (regcache, i,
+                                    FXSAVE_ADDR (tdep, regs, i));
            }
        }
 
@@ -886,16 +959,18 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
       if ((tdep->xcr0 & I386_XSTATE_X87))
        {
          if ((clear_bv & I386_XSTATE_X87))
-           p = NULL;
+           {
+             for (i = I387_ST0_REGNUM (tdep);
+                  i < I387_FCTRL_REGNUM (tdep);
+                  i++)
+               regcache_raw_supply (regcache, i, zero);
+           }
          else
-           p = regs;
-
-         for (i = I387_ST0_REGNUM (tdep);
-              i < I387_FCTRL_REGNUM (tdep); i++)
            {
-             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 (regcache, i, FXSAVE_ADDR (tdep, regs, i));
            }
        }
       break;
@@ -905,12 +980,6 @@ 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)
-         {
-           regcache_raw_supply (regcache, i, NULL);
-           continue;
-         }
-
        /* 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)
@@ -961,10 +1030,8 @@ i387_supply_xsave (struct regcache *regcache, int regnum,
       }
 
   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);
-    }
+    regcache_raw_supply (regcache, I387_MXCSR_REGNUM (tdep),
+                        FXSAVE_MXCSR_ADDR (regs));
 }
 
 /* Similar to i387_collect_fxsave, but use XSAVE extended state.  */
@@ -983,7 +1050,8 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
       x87 = 0x2 | check,
       sse = 0x4 | check,
       avxh = 0x8 | check,
-      all = x87 | sse | avxh
+      mpx  = 0x10 | check,
+      all = x87 | sse | avxh | mpx
     } regclass;
 
   gdb_assert (tdep->st0_regnum >= I386_ST0_REGNUM);
@@ -994,7 +1062,10 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
   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)
@@ -1026,6 +1097,16 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
       /* Clear register set if its bit in xstat_bv is zero.  */
       if (clear_bv)
        {
+         if ((clear_bv & I386_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 & I386_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 & I386_XSTATE_AVX))
            for (i = I387_YMM0H_REGNUM (tdep);
                 i < I387_YMMENDH_REGNUM (tdep); i++)
@@ -1057,6 +1138,33 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
                    memcpy (p, raw, 16);
                  }
              }
+         /* Check if any upper MPX registers are changed.  */
+         if ((tdep->xcr0 & I386_XSTATE_BNDREGS))
+           for (i = I387_BND0R_REGNUM (tdep);
+                i < I387_BNDCFGU_REGNUM (tdep); i++)
+             {
+               regcache_raw_collect (regcache, i, raw);
+               p = XSAVE_MPX_ADDR (tdep, regs, i);
+               if (memcmp (raw, p, 16))
+                 {
+                   xstate_bv |= I386_XSTATE_BNDREGS;
+                   memcpy (p, raw, 16);
+                 }
+             }
+
+         /* Check if any upper MPX registers are changed.  */
+         if ((tdep->xcr0 & I386_XSTATE_BNDCFG))
+           for (i = I387_BNDCFGU_REGNUM (tdep);
+                i < I387_MPXEND_REGNUM (tdep); i++)
+             {
+               regcache_raw_collect (regcache, i, raw);
+               p = XSAVE_MPX_ADDR (tdep, regs, i);
+               if (memcmp (raw, p, 8))
+                 {
+                   xstate_bv |= I386_XSTATE_BNDCFG;
+                   memcpy (p, raw, 8);
+                 }
+             }
 
          /* Check if any SSE registers are changed.  */
          if ((tdep->xcr0 & I386_XSTATE_SSE))
@@ -1107,6 +1215,25 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
                }
              break;
 
+           case mpx:
+             if (regnum < I387_BNDCFGU_REGNUM (tdep))
+               {
+                 regcache_raw_collect (regcache, regnum, raw);
+                 p = XSAVE_MPX_ADDR (tdep, regs, regnum);
+                 if (memcmp (raw, p, 16))
+                   {
+                     xstate_bv |= I386_XSTATE_BNDREGS;
+                     memcpy (p, raw, 16);
+                   }
+               }
+             else
+               {
+                 p = XSAVE_MPX_ADDR (tdep, regs, regnum);
+                 xstate_bv |= I386_XSTATE_BNDCFG;
+                 memcpy (p, raw, 8);
+               }
+             break;
+
            case sse:
              /* This is an SSE register.  */
              p = FXSAVE_ADDR (tdep, regs, regnum);
@@ -1148,6 +1275,7 @@ i387_collect_xsave (const struct regcache *regcache, int regnum,
            case x87:
            case sse:
            case avxh:
+           case mpx:
              /* Register REGNUM has been updated.  Return.  */
              return;
            }