2012-03-06  Pedro Alves  <palves@redhat.com>

	PR gdb/13766

	* i387-tdep.c (i387_supply_xsave): If we have an xsave buffer, and
	the register state is clear, supply explicit zero, instead of
	marking the register unavailable.
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index c204b94..4a33075 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2012-03-06  Pedro Alves  <palves@redhat.com>
+
+	PR gdb/13766
+
+	* i387-tdep.c (i387_supply_xsave): If we have an xsave buffer, and
+	the register state is clear, supply explicit zero, instead of
+	marking the register unavailable.
+
 2011-10-20  Aleksandar Ristovski  <aristovski@qnx.com>
 
 	* cp-namespace.c (cp_scan_for_anonymous_namespaces): Changed function
diff --git a/gdb/i387-tdep.c b/gdb/i387-tdep.c
index 9eece41..cfb27ac 100644
--- a/gdb/i387-tdep.c
+++ b/gdb/i387-tdep.c
@@ -726,6 +726,7 @@
   const gdb_byte *regs = xsave;
   int i;
   unsigned int clear_bv;
+  static const gdb_byte zero[MAX_REGISTER_SIZE] = { 0 };
   const gdb_byte *p;
   enum
     {
@@ -765,6 +766,19 @@
   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.
+
+     Note however, the case when REGS is NULL is a different case.
+     That case means we do not have access to the x87 states, so we
+     should mark the registers as unavailable (by supplying NULL).  */
+
   switch (regclass)
     {
     case none:
@@ -772,26 +786,26 @@
 
     case avxh:
       if ((clear_bv & I386_XSTATE_AVX))
-	p = NULL;
+	regcache_raw_supply (regcache, regnum, regs == NULL ? NULL : zero);
       else
-	p = XSAVE_AVXH_ADDR (tdep, regs, regnum);
-      regcache_raw_supply (regcache, regnum, p);
+	regcache_raw_supply (regcache, regnum,
+			     XSAVE_AVXH_ADDR (tdep, regs, regnum));
       return;
 
     case sse:
       if ((clear_bv & I386_XSTATE_SSE))
-	p = NULL;
+	regcache_raw_supply (regcache, regnum, regs == NULL ? NULL : 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, regs == NULL ? NULL : 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:
@@ -799,16 +813,19 @@
       if ((tdep->xcr0 & I386_XSTATE_AVX))
 	{
 	  if ((clear_bv & I386_XSTATE_AVX))
-	    p = NULL;
-	  else
-	    p = regs;
-
-	  for (i = I387_YMM0H_REGNUM (tdep);
-	       i < I387_YMMENDH_REGNUM (tdep); i++)
 	    {
-	      if (p != NULL)
-		p = XSAVE_AVXH_ADDR (tdep, regs, i);
-	      regcache_raw_supply (regcache, i, p);
+	      for (i = I387_YMM0H_REGNUM (tdep);
+		   i < I387_YMMENDH_REGNUM (tdep);
+		   i++)
+		regcache_raw_supply (regcache, i, regs == NULL ? NULL : zero);
+	    }
+	  else
+	    {
+	      for (i = I387_YMM0H_REGNUM (tdep);
+		   i < I387_YMMENDH_REGNUM (tdep);
+		   i++)
+		regcache_raw_supply (regcache, i,
+				     XSAVE_AVXH_ADDR (tdep, regs, i));
 	    }
 	}
 
@@ -816,16 +833,18 @@
       if ((tdep->xcr0 & I386_XSTATE_SSE))
 	{
 	  if ((clear_bv & I386_XSTATE_SSE))
-	    p = NULL;
-	  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, regs == NULL ? NULL : zero);
+	    }
+	  else
+	    {
+	      for (i = I387_XMM0_REGNUM (tdep);
+		   i < I387_MXCSR_REGNUM (tdep); i++)
+		regcache_raw_supply (regcache, i,
+				     FXSAVE_ADDR (tdep, regs, i));
 	    }
 	}
 
@@ -833,16 +852,18 @@
       if ((tdep->xcr0 & I386_XSTATE_X87))
 	{
 	  if ((clear_bv & I386_XSTATE_X87))
-	    p = NULL;
-	  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, regs == NULL ? NULL : zero);
+	    }
+	  else
+	    {
+	      for (i = I387_ST0_REGNUM (tdep);
+		   i < I387_FCTRL_REGNUM (tdep);
+		   i++)
+		regcache_raw_supply (regcache, i, FXSAVE_ADDR (tdep, regs, i));
 	    }
 	}
       break;