2001-09-20 Michael Snyder <msnyder@redhat.com>
[binutils-gdb.git] / gdb / i386-tdep.c
index 0e3e34057cefe6c913ccecd69bda196683080713..c55757e76a69a318507fdb6e91852dfd612b9bcb 100644 (file)
@@ -32,6 +32,9 @@
 #include "command.h"
 #include "arch-utils.h"
 #include "regcache.h"
+#include "doublest.h"
+
+#include "gdb_assert.h"
 
 /* i386_register_byte[i] is the offset into the register file of the
    start of register number i.  We initialize this from
@@ -57,6 +60,68 @@ int i386_register_raw_size[MAX_NUM_REGS] = {
 /* i386_register_virtual_size[i] is the size in bytes of the virtual
    type of register i.  */
 int i386_register_virtual_size[MAX_NUM_REGS];
+
+/* Convert stabs register number REG to the appropriate register
+   number used by GDB.  */
+
+int
+i386_stab_reg_to_regnum (int reg)
+{
+  /* This implements what GCC calls the "default" register map.  */
+  if (reg >= 0 && reg <= 7)
+    {
+      /* General registers.  */
+      return reg;
+    }
+  else if (reg >= 12 && reg <= 19)
+    {
+      /* Floating-point registers.  */
+      return reg - 12 + FP0_REGNUM;
+    }
+  else if (reg >= 21 && reg <= 28)
+    {
+      /* SSE registers.  */
+      return reg - 21 + XMM0_REGNUM;
+    }
+  else if (reg >= 29 && reg <= 36)
+    {
+      /* MMX registers.  */
+      /* FIXME: kettenis/2001-07-28: Should we have the MMX registers
+         as pseudo-registers?  */
+      return reg - 29 + FP0_REGNUM;
+    }
+
+  /* This will hopefully provoke a warning.  */
+  return NUM_REGS + NUM_PSEUDO_REGS;
+}
+
+/* Convert Dwarf register number REG to the appropriate register
+   number used by GDB.  */
+
+int
+i386_dwarf_reg_to_regnum (int reg)
+{
+  /* The DWARF register numbering includes %eip and %eflags, and
+     numbers the floating point registers differently.  */
+  if (reg >= 0 && reg <= 9)
+    {
+      /* General registers.  */
+      return reg;
+    }
+  else if (reg >= 11 && reg <= 18)
+    {
+      /* Floating-point registers.  */
+      return reg - 11 + FP0_REGNUM;
+    }
+  else if (reg >= 21)
+    {
+      /* The SSE and MMX registers have identical numbers as in stabs.  */
+      return i386_stab_reg_to_regnum (reg);
+    }
+
+  /* This will hopefully provoke a warning.  */
+  return NUM_REGS + NUM_PSEUDO_REGS;
+}
 \f
 
 /* This is the variable that is set with "set disassembly-flavor", and
@@ -669,7 +734,7 @@ i386_push_dummy_frame (void)
 
 void
 i386_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
-                    value_ptr *args, struct type *type, int gcc_p)
+                    struct value **args, struct type *type, int gcc_p)
 {
   int from, to, delta, loc;
 
@@ -749,7 +814,7 @@ get_longjmp_target (CORE_ADDR *pc)
 \f
 
 CORE_ADDR
-i386_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
+i386_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
                     int struct_return, CORE_ADDR struct_addr)
 {
   sp = default_push_arguments (nargs, args, sp, struct_return, struct_addr);
@@ -861,13 +926,18 @@ i386_store_return_value (struct type *type, char *valbuf)
 
   if (TYPE_CODE (type) == TYPE_CODE_FLT)
     {
+      unsigned int fstat;
+
       if (NUM_FREGS == 0)
        {
          warning ("Cannot set floating-point return value.");
          return;
        }
 
-      /* Floating-point return values can be found in %st(0).  */
+      /* Returning floating-point values is a bit tricky.  Apart from
+         storing the return value in %st(0), we have to simulate the
+         state of the FPU at function return point.  */
+
       if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT
          && TARGET_LONG_DOUBLE_FORMAT == &floatformat_i387_ext)
        {
@@ -881,7 +951,7 @@ i386_store_return_value (struct type *type, char *valbuf)
          DOUBLEST val;
 
          /* Convert the value found in VALBUF to the extended
-             floating point format used by the FPU.  This is probably
+             floating-point format used by the FPU.  This is probably
              not exactly how it would happen on the target itself, but
              it is the best we can do.  */
          val = extract_floating (valbuf, TYPE_LENGTH (type));
@@ -889,6 +959,19 @@ i386_store_return_value (struct type *type, char *valbuf)
          write_register_bytes (REGISTER_BYTE (FP0_REGNUM), buf,
                                FPU_REG_RAW_SIZE);
        }
+
+      /* Set the top of the floating-point register stack to 7.  The
+         actual value doesn't really matter, but 7 is what a normal
+         function return would end up with if the program started out
+         with a freshly initialized FPU.  */
+      fstat = read_register (FSTAT_REGNUM);
+      fstat |= (7 << 11);
+      write_register (FSTAT_REGNUM, fstat);
+
+      /* Mark %st(1) through %st(7) as empty.  Since we set the top of
+         the floating-point register stack to 7, the appropriate value
+         for the tag word is 0x3fff.  */
+      write_register (FTAG_REGNUM, 0x3fff);
     }
   else
     {
@@ -954,27 +1037,45 @@ i386_register_convertible (int regnum)
 }
 
 /* Convert data from raw format for register REGNUM in buffer FROM to
-   virtual format with type TYPE in buffer TO.  In principle both
-   formats are identical except that the virtual format has two extra
-   bytes appended that aren't used.  We set these to zero.  */
+   virtual format with type TYPE in buffer TO.  */
 
 void
 i386_register_convert_to_virtual (int regnum, struct type *type,
                                  char *from, char *to)
 {
-  /* Copy straight over, but take care of the padding.  */
-  memcpy (to, from, FPU_REG_RAW_SIZE);
-  memset (to + FPU_REG_RAW_SIZE, 0, TYPE_LENGTH (type) - FPU_REG_RAW_SIZE);
+  char buf[12];
+  DOUBLEST d;
+
+  /* We only support floating-point values.  */
+  if (TYPE_CODE (type) != TYPE_CODE_FLT)
+    {
+      warning ("Cannot convert floating-point register value "
+              "to non-floating-point type.");
+      memset (to, 0, TYPE_LENGTH (type));
+      return;
+    }
+
+  /* First add the necessary padding.  */
+  memcpy (buf, from, FPU_REG_RAW_SIZE);
+  memset (buf + FPU_REG_RAW_SIZE, 0, sizeof buf - FPU_REG_RAW_SIZE);
+
+  /* Convert to TYPE.  This should be a no-op, if TYPE is equivalent
+     to the extended floating-point format used by the FPU.  */
+  d = extract_floating (buf, sizeof buf);
+  store_floating (to, TYPE_LENGTH (type), d);
 }
 
 /* Convert data from virtual format with type TYPE in buffer FROM to
-   raw format for register REGNUM in buffer TO.  Simply omit the two
-   unused bytes.  */
+   raw format for register REGNUM in buffer TO.  */
 
 void
 i386_register_convert_to_raw (struct type *type, int regnum,
                              char *from, char *to)
 {
+  gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT
+             && TYPE_LENGTH (type) == 12);
+
+  /* Simply omit the two unused bytes.  */
   memcpy (to, from, FPU_REG_RAW_SIZE);
 }
 \f