This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Support functions for x86 fxsave area's


The attached patch adds some support routines for converting the
contents of the 512 byte area used by the fxsave instruction to GDB's
register cache.  I will be checking in a Linux/x86 patch shortly that
uses this stuff to add support for the SSE stuff that'll be in Linux
2.4.  Of course other x86 native debuggers that want to use the
functions are welcome to do so :-).

However, the functions are *untested*.  I don't own a machine that
support the necessary instructions, and I've been unable to get access
to a machine that does.  I hope that checking in the stuff will expose
any problems with it.  Only people using experimental stuff (kernel &
libc test versions) might encounter any problems (and then only on
Linux/x86 after I check in that stuff), so I guess that's not really a
problem.

Mark


2000-08-10  Mark Kettenis  <kettenis@gnu.org>

	* i387-nat.h (i387_supply_fsave, i387_fill_fsave): Make extern.
	(i387_supply_fxsave, i387_fill_fxsave): New prototypes.
	* i387-nat.c (i387_supply_fsave): Declare `val' as `unsigned int'.
	(fxsave_offset): New variable.
	(FXSAVE_ADDR): New macro.
	(i387_supply_fxsave, i387_fill_fxsave, i387_tag): New functions.


Index: i387-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i387-nat.c,v
retrieving revision 1.1
diff -u -p -r1.1 i387-nat.c
--- i387-nat.c	2000/05/23 23:44:44	1.1
+++ i387-nat.c	2000/08/10 14:51:07
@@ -1,5 +1,5 @@
 /* Native-dependent code for the i387.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright 2000 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -71,7 +71,7 @@ i387_supply_fsave (char *fsave)
       if (i >= FIRST_FPU_CTRL_REGNUM
 	  && i != FCOFF_REGNUM && i != FDOFF_REGNUM)
 	{
-	  unsigned val = *(unsigned short *) (FSAVE_ADDR (fsave, i));
+	  unsigned int val = *(unsigned short *) (FSAVE_ADDR (fsave, i));
 
 	  if (i == FOP_REGNUM)
 	    {
@@ -122,4 +122,211 @@ i387_fill_fsave (char *fsave, int regno)
 	  memcpy (FSAVE_ADDR (fsave, i), &registers[REGISTER_BYTE (i)],
 		  REGISTER_RAW_SIZE (i));
       }
+}
+
+
+/* At fxsave_offset[REGNO] you'll find the offset to the location in
+   the data structure used by the "fxsave" instruction where GDB
+   register REGNO is stored.  */
+
+static int fxsave_offset[] =
+{
+  32,				/* FP0_REGNUM through ...  */
+  48,
+  64,
+  80,
+  96,
+  112,
+  128,
+  144,				/* ... FP7_REGNUM (80 bits each).  */
+  0,				/* FCTRL_REGNUM (16 bits).  */
+  2,				/* FSTAT_REGNUM (16 bits).  */
+  4,				/* FTAG_REGNUM (16 bits).  */
+  12,				/* FCS_REGNUM (16 bits).  */
+  8,				/* FCOFF_REGNUM.  */
+  20,				/* FDS_REGNUM (16 bits).  */
+  16,				/* FDOFF_REGNUM.  */
+  6,				/* FOP_REGNUM (bottom 11 bits).  */
+  160,				/* XMM0_REGNUM through ...  */
+  176,
+  192,
+  208,
+  224,
+  240,
+  256,
+  272,				/* ... XMM7_REGNUM (128 bits each).  */
+  24,				/* MXCSR_REGNUM.  */
+};
+
+#define FXSAVE_ADDR(fxsave, regnum) \
+  (fxsave + fxsave_offset[regnum - FP0_REGNUM])
+
+static int i387_tag (unsigned char *raw);
+
+
+/* Fill GDB's register array with the floating-point and SSE register
+   values in *FXSAVE.  This function masks off any of the reserved
+   bits in *FXSAVE.  */
+
+void
+i387_supply_fxsave (char *fxsave)
+{
+  int i;
+
+  for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++)
+    {
+      /* Most of the FPU control registers occupy only 16 bits in
+	 the fxsave area.  Give those a special treatment.  */
+      if (i >= FIRST_FPU_CTRL_REGNUM && i < XMM0_REGNUM
+	  && i != FCOFF_REGNUM && i != FDOFF_REGNUM)
+	{
+	  unsigned long val = *(unsigned short *) (FXSAVE_ADDR (fxsave, i));
+
+	  if (i == FOP_REGNUM)
+	    {
+	      val &= ((1 << 11) - 1);
+	      supply_register (i, (char *) &val);
+	    }
+	  else if (i== FTAG_REGNUM)
+	    {
+	      /* The fxsave area contains a simplified version of the
+                 tag word.  We have to look at the actual 80-bit FP
+                 data to recreate the traditional i387 tag word.  */
+
+	      unsigned long ftag = 0;
+	      unsigned long fstat;
+	      int fpreg;
+	      int top;
+
+	      fstat = *(unsigned short *) (FXSAVE_ADDR (fxsave, FSTAT_REGNUM));
+	      top = ((fstat >> 11) & 0x111);
+
+	      for (fpreg = 7; fpreg >= 0; fpreg--)
+		{
+		  int tag = 0x11;
+
+		  if (val & (1 << fpreg))
+		    {
+		      int regnum = (fpreg + 8 - top) % 8 + FP0_REGNUM;
+		      tag = i387_tag (FXSAVE_ADDR (fxsave, regnum));
+		    }
+
+		  ftag |= tag << (2 * fpreg);
+		}
+	      supply_register (i, (char *) &ftag);
+	    }
+	  else
+	    supply_register (i, (char *) &val);
+	}
+      else
+	supply_register (i, FXSAVE_ADDR (fxsave, i));
+    }
+}
+
+/* Fill register REGNO (if it is a floating-point or SSE register) in
+   *FXSAVE with the value in GDB's register array.  If REGNO is -1, do
+   this for all registers.  This function doesn't touch any of the
+   reserved bits in *FXSAVE.  */
+
+void
+i387_fill_fxsave (char *fxsave, int regno)
+{
+  int i;
+
+  for (i = FP0_REGNUM; i <= MXCSR_REGNUM; i++)
+    if (regno == -1 || regno == i)
+      {
+	/* Most of the FPU control registers occupy only 16 bits in
+           the fxsave area.  Give those a special treatment.  */
+	if (i >= FIRST_FPU_CTRL_REGNUM && i < XMM0_REGNUM
+	    && i != FCOFF_REGNUM && i != FDOFF_REGNUM)
+	  {
+	    if (i == FOP_REGNUM)
+	      {
+		unsigned short oldval, newval;
+
+		/* The opcode occupies only 11 bits.  */
+		oldval = (*(unsigned short *) (FXSAVE_ADDR (fxsave, i)));
+		newval = *(unsigned short *) &registers[REGISTER_BYTE (i)];
+		newval &= ((1 << 11) - 1);
+		newval |= oldval & ~((1 << 11) - 1);
+		memcpy (FXSAVE_ADDR (fxsave, i), &newval, 2);
+	      }
+	    else if (i == FTAG_REGNUM)
+	      {
+		/* Converting back is much easier.  */
+
+		unsigned char val = 0;
+		unsigned short ftag;
+		int fpreg;
+
+		ftag = *(unsigned short *) &registers[REGISTER_BYTE (i)];
+
+		for (fpreg = 7; fpreg >= 0; fpreg--)
+		  {
+		    int tag = (ftag >> (fpreg * 2)) & 0x11;
+
+		    if (tag != 0x11)
+		      val |= (1 << fpreg);
+		  }
+
+		memcpy (FXSAVE_ADDR (fxsave, i), &val, 2);
+	      }
+	    else
+	      memcpy (FXSAVE_ADDR (fxsave, i),
+		      &registers[REGISTER_BYTE (i)], 2);
+	  }
+	else
+	  memcpy (FXSAVE_ADDR (fxsave, i), &registers[REGISTER_BYTE (i)],
+		  REGISTER_RAW_SIZE (i));
+      }
+}
+
+/* Recreate the FTW (tag word) valid bits from the 80-bit FP data in
+   *RAW.  */
+
+static int
+i387_tag (unsigned char *raw)
+{
+  int integer;
+  unsigned int exponent;
+  unsigned long fraction[2];
+
+  integer = raw[7] & 0x80;
+  exponent = (((raw[9] & 0x7f) << 8) | raw[8]);
+  fraction[0] = ((raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]);
+  fraction[1] = (((raw[7] & 0x7f) << 24) | (raw[6] << 16)
+		 | (raw[5] << 8) | raw[4]);
+
+  if (exponent == 0x7fff)
+    {
+      /* Special.  */
+      return (0x10);
+    }
+  else if (exponent == 0x0000)
+    {
+      if (integer)
+	{
+	  /* Valid.  */
+	  return (0x00);
+	}
+      else
+	{
+	  /* Special.  */
+	  return (0x10);
+	}
+    }
+  else
+    {
+      if (fraction[0] == 0x0000 && fraction[1] == 0x0000 && !integer)
+	{
+	  /* Zero.  */
+	  return (0x01);
+	}
+      else
+	{
+	  /* Special.  */
+	  return (0x10);
+	}
+    }
 }
Index: i387-nat.h
===================================================================
RCS file: /cvs/src/src/gdb/i387-nat.h,v
retrieving revision 1.1
diff -u -p -r1.1 i387-nat.h
--- i387-nat.h	2000/05/23 23:44:44	1.1
+++ i387-nat.h	2000/08/10 14:51:07
@@ -1,5 +1,5 @@
 /* Native-dependent code for the i387.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright 2000 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -25,13 +25,26 @@
    in *FSAVE.  This function masks off any of the reserved
    bits in *FSAVE.  */
 
-void i387_supply_fsave (char *fsave);
+extern void i387_supply_fsave (char *fsave);
 
 /* Fill register REGNO (if it is a floating-point register) in *FSAVE
    with the value in GDB's register array.  If REGNO is -1, do this
    for all registers.  This function doesn't touch any of the reserved
    bits in *FSAVE.  */
 
-void i387_fill_fsave (char *fsave, int regno);
+extern void i387_fill_fsave (char *fsave, int regno);
+
+/* Fill GDB's register array with the floating-point and SSE register
+   values in *FXSAVE.  This function masks off any of the reserved
+   bits in *FXSAVE.  */
+
+extern void i387_supply_fxsave (char *fxsave);
+
+/* Fill register REGNO (if it is a floating-point or SSE register) in
+   *FXSAVE with the value in GDB's register array.  If REGNO is -1, do
+   this for all registers.  This function doesn't touch any of the
+   reserved bits in *FXSAVE.  */
+
+extern void i387_fill_fxsave (char *fxsave, int regno);
 
 #endif /* i387-nat.h */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]