This is the mail archive of the gdb-patches@sourceware.cygnus.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 for new i386 `info float' command


Here is a patch that implements the new generic i386 `info float'
command.  The new i387-tdep.c is a bit of a mess since it still
contains code that used by some of the old target specific `info
float' implementation and the Linux `long double' kludges.  These bits
of code should be removed eventually and I added some comments saying
so.

The new `info float' command uses the *_filtered functions as
suggested by Andrew Cagney.  The way the floating point values are
printed means that on some hosts there is a partial precision loss.  I
think this is OK since full information is still available (as
hexadecimal output) and even partial information can be useful.

Mark


1999-11-13  Mark Kettenis  <kettenis@gnu.org>

	* config/i386/tm-i386.h (FLOAT_INFO): New define.
	* i387-tdep.c (print_i387_value, print_i387_ext,
	print_i387_status_word, print_i387_control_word, i387_float_info):
	New functions, used to implement generic `info float' command.


Index: config/i386/tm-i386.h
===================================================================
RCS file: /var/cvsroot/gdb/gdb/config/i386/tm-i386.h,v
retrieving revision 1.1.1.8
diff -u -r1.1.1.8 tm-i386.h
--- config/i386/tm-i386.h	1999/11/13 14:31:07	1.1.1.8
+++ config/i386/tm-i386.h	1999/11/13 17:30:39
@@ -259,6 +259,13 @@
   double_to_i387((char *)&val, (TO));				\
 }
 
+/* Print out the i387 floating point state.  */
+#ifdef HAVE_I387_REGS
+extern void i387_float_info (void);
+#define FLOAT_INFO { i387_float_info (); }
+#endif
+
+
 /* Store the address of the place in which to copy the structure the
    subroutine will return.  This is called from call_function. */
 
Index: i387-tdep.c
===================================================================
RCS file: /var/cvsroot/gdb/gdb/i387-tdep.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 i387-tdep.c
--- i387-tdep.c	1999/10/02 19:51:09	1.1.1.4
+++ i387-tdep.c	1999/11/13 17:27:21
@@ -1,5 +1,5 @@
 /* Intel 387 floating point stuff.
-   Copyright (C) 1988, 1989, 1991, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1989, 1991, 1998, 1999 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -26,14 +26,12 @@
 #include "gdbcore.h"
 #include "floatformat.h"
 
-void i387_to_double PARAMS ((char *, char *));
-void double_to_i387 PARAMS ((char *, char *));
 
-static void print_387_control_bits PARAMS ((unsigned int control));
-static void print_387_status_bits  PARAMS ((unsigned int status));
+/* FIXME: Eliminate the next two functions when we have the time to
+   change all the callers.  */
 
-/* FIXME:  Eliminate these routines when we have the time to change all
-   the callers.  */
+void i387_to_double PARAMS ((char *from, char *to));
+void double_to_i387 PARAMS ((char *from, char *to));
 
 void
 i387_to_double (from, to)
@@ -51,6 +49,16 @@
   floatformat_from_double (&floatformat_i387_ext, (double *) from, to);
 }
 
+
+/* FIXME: The functions on this page are used by the old `info float'
+   implementations that a few of the i386 targets provide.  These
+   functions should be removed if all of these have been converted to
+   use the generic implementation based on the new register file
+   layout.  */
+
+static void print_387_control_bits PARAMS ((unsigned int control));
+static void print_387_status_bits PARAMS ((unsigned int status));
+
 static void
 print_387_control_bits (control)
      unsigned int control;
@@ -149,6 +157,243 @@
   puts_unfiltered ("\n");
 }
 
+
+/* Implement the `info float' layout based on the register definitions
+   in `tm-i386.h'.  */
+
+/* Print the floating point number specified by RAW.  */
+static void
+print_i387_value (char *raw)
+{
+  DOUBLEST value;
+  
+  floatformat_to_doublest (&floatformat_i387_ext, raw, &value);
+
+  /* We try to print 19 digits.  The last digit may or may not contain
+     garbage, but we'd better print one too many.  We need enough room
+     to print the value, 1 position for the sign, 1 for the decimal
+     point, 19 for the digits and 6 for the exponent adds up to 27.  */
+#ifdef PRINTF_HAS_LONG_DOUBLE
+  printf_filtered (" %-+27.19Lg", (long double) value);
+#else
+  printf_filtered (" %-+27.19g", (double) value);
+#endif
+}
+
+/* Print the classification for the register contents RAW.  */
+static void
+print_i387_ext (unsigned char *raw)
+{
+  int sign;
+  int integer;
+  unsigned int exponent;
+  unsigned long fraction[2];
+
+  sign = raw[9] & 0x80;
+  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 && integer)
+    {
+      if (fraction[0] == 0x00000000 && fraction[1] == 0x00000000)
+	/* Infinity.  */
+	printf_filtered (" %cInf", (sign ? '-' : '+'));
+      else if (sign && fraction[0] == 0x00000000 && fraction[1] == 0x40000000)
+	/* Real Indefinite (QNaN).  */
+	puts_unfiltered (" Real Indefinite (QNaN)");
+      else if (fraction[1] & 0x40000000)
+	/* QNaN.  */
+	puts_filtered (" QNaN");
+      else
+	/* SNaN.  */
+	puts_filtered (" SNaN");
+    }
+  else if (exponent < 0x7fff && exponent > 0x0000 && integer)
+    /* Normal.  */
+    print_i387_value (raw);
+  else if (exponent == 0x0000)
+    {
+      /* Denormal or zero.  */
+      print_i387_value (raw);
+      
+      if (integer)
+	/* Pseudo-denormal.  */
+	puts_filtered (" Pseudo-denormal");
+      else if (fraction[0] || fraction[1])
+	/* Denormal.  */
+	puts_filtered (" Denormal");
+    }
+  else
+    /* Unsupported.  */
+    puts_filtered (" Unsupported");
+}
+
+/* Print the status word STATUS.  */
+static void
+print_i387_status_word (unsigned int status)
+{
+  printf_filtered ("Status Word:         %s",
+		   local_hex_string_custom (status, "04"));
+  puts_filtered ("  ");
+  printf_filtered (" %s", (status & 0x0001) ? "IE" : "  ");
+  printf_filtered (" %s", (status & 0x0002) ? "DE" : "  ");
+  printf_filtered (" %s", (status & 0x0004) ? "ZE" : "  ");
+  printf_filtered (" %s", (status & 0x0008) ? "OE" : "  ");
+  printf_filtered (" %s", (status & 0x0010) ? "UE" : "  ");
+  printf_filtered (" %s", (status & 0x0020) ? "PE" : "  ");
+  puts_filtered ("  ");
+  printf_filtered (" %s", (status & 0x0080) ? "ES" : "  ");
+  puts_filtered ("  ");
+  printf_filtered (" %s", (status & 0x0080) ? "SF" : "  ");
+  puts_filtered ("  ");
+  printf_filtered (" %s", (status & 0x0100) ? "C0" : "  ");
+  printf_filtered (" %s", (status & 0x0200) ? "C1" : "  ");
+  printf_filtered (" %s", (status & 0x0400) ? "C2" : "  ");
+  printf_filtered (" %s", (status & 0x4000) ? "C3" : "  ");
+
+  puts_filtered ("\n");
+
+  printf_filtered ("                       TOP: %d\n", ((status >> 11) & 7));
+}
+
+/* Print the control word CONTROL.  */
+static void
+print_i387_control_word (unsigned int control)
+{
+  printf_filtered ("Control Word:        %s",
+		   local_hex_string_custom (control, "04"));
+  puts_filtered ("  ");
+  printf_filtered (" %s", (control & 0x0001) ? "IM" : "  ");
+  printf_filtered (" %s", (control & 0x0002) ? "DM" : "  ");
+  printf_filtered (" %s", (control & 0x0004) ? "ZM" : "  ");
+  printf_filtered (" %s", (control & 0x0008) ? "OM" : "  ");
+  printf_filtered (" %s", (control & 0x0010) ? "UM" : "  ");
+  printf_filtered (" %s", (control & 0x0020) ? "PM" : "  ");
+
+  puts_filtered ("\n");
+
+  puts_filtered ("                       PC: ");
+  switch ((control >> 8) & 3)
+    {
+    case 0:
+      puts_filtered ("Single Precision (24-bits)\n");
+      break;
+    case 1:
+      puts_filtered ("Reserved\n");
+      break;
+    case 2:
+      puts_filtered ("Double Precision (53-bits)\n");
+      break;
+    case 3:
+      puts_filtered ("Extended Precision (64-bits)\n");
+      break;
+    }
+      
+  puts_filtered ("                       RC: ");
+  switch ((control >> 10) & 3)
+    {
+    case 0:
+      puts_filtered ("Round to nearest\n");
+      break;
+    case 1:
+      puts_filtered ("Round down\n");
+      break;
+    case 2:
+      puts_filtered ("Round up\n");
+      break;
+    case 3:
+      puts_filtered ("Round toward zero\n");
+      break;
+    }
+}
+
+/* Print out the i387 floating poin state.  */
+void
+i387_float_info (void)
+{
+  unsigned int fctrl;
+  unsigned int fstat;
+  unsigned int ftag;
+  unsigned int fiseg;
+  unsigned int fioff;
+  unsigned int foseg;
+  unsigned int fooff;
+  unsigned int fop;
+  int fpreg;
+  int top;
+
+  fctrl = read_register (FCTRL_REGNUM);
+  fstat = read_register (FSTAT_REGNUM);
+  ftag  = read_register (FTAG_REGNUM);
+  fiseg = read_register (FCS_REGNUM);
+  fioff = read_register (FCOFF_REGNUM);
+  foseg = read_register (FDS_REGNUM);
+  fooff = read_register (FDOFF_REGNUM);
+  fop   = read_register (FOP_REGNUM);
+  
+  top = ((fstat >> 11) & 7);
+
+  for (fpreg = 7; fpreg >= 0; fpreg--)
+    {
+      unsigned char raw[FPU_REG_RAW_SIZE];
+      int tag = (ftag >> (fpreg * 2)) & 3;
+      int i;
+
+      printf_filtered ("%sR%d: ", fpreg == top ? "=>" : "  ", fpreg);
+
+      switch (tag)
+	{
+	case 0:
+	  puts_filtered ("Valid   ");
+	  break;
+	case 1:
+	  puts_filtered ("Zero    ");
+	  break;
+	case 2:
+	  puts_filtered ("Special ");
+	  break;
+	case 3:
+	  puts_filtered ("Empty   ");
+	  break;
+	}
+
+      read_register_gen ((fpreg + 8 - top) % 8 + FP0_REGNUM, raw);
+
+      puts_filtered ("0x");
+      for (i = 9; i >= 0; i--)
+	printf_filtered ("%02x", raw[i]);
+
+      if (tag != 3)
+	print_i387_ext (raw);
+
+      puts_filtered ("\n");
+    }
+
+  puts_filtered ("\n");
+
+  print_i387_status_word (fstat);
+  print_i387_control_word (fctrl);
+  printf_filtered ("Tag Word:            %s\n",
+		   local_hex_string_custom (ftag, "04"));
+  printf_filtered ("Instruction Pointer: %s:",
+		   local_hex_string_custom (fiseg, "02"));
+  printf_filtered ("%s\n", local_hex_string_custom (fioff, "08"));
+  printf_filtered ("Operand Pointer:     %s:",
+		   local_hex_string_custom (foseg, "02"));
+  printf_filtered ("%s\n", local_hex_string_custom (fooff, "08"));
+  printf_filtered ("Opcode:              %s\n",
+		   local_hex_string_custom (fop ? (fop | 0xd800) : 0, "04"));
+}
+
+
+/* FIXME: The functions on this page are used to provide `long double'
+   support for Linux.  However, the approach does not seem to be the
+   right one, and we are planning to solve this in a way that should
+   work for all i386 targets.  These functions will disappear in the
+   near future, so please don't use them.  */
 #ifdef LD_I387
 int
 i387_extract_floating (PTR addr, int len, DOUBLEST *dretptr)

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