Revert previous ser-unix change. Locks up serial device.
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 94e96ca117ebef36b72be3e2f004b29d23ff395b..88ba0cddc86327543b06b63c8998193d3d9bb20d 100644 (file)
@@ -107,6 +107,7 @@ static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE;
 #define FP_REGISTER_DOUBLE (REGISTER_VIRTUAL_SIZE(FP0_REGNUM) == 8)
 #endif
 
+static int mips_debug = 0;
 
 /* MIPS specific per-architecture information */
 struct gdbarch_tdep
@@ -2061,6 +2062,23 @@ setup_arbitrary_frame (argc, argv)
   return create_new_frame (argv[0], argv[1]);
 }
 
+/* According to the current ABI, should the type be passed in a
+   floating-point register (assuming that there is space)?  When there
+   is no FPU, FP are not even considered as possibile candidates for
+   FP registers and, consequently this returns false - forces FP
+   arguments into integer registers. */
+
+static int
+fp_register_arg_p (enum type_code typecode, struct type *arg_type)
+{
+  return ((typecode == TYPE_CODE_FLT
+          || (MIPS_EABI
+              && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)
+              && TYPE_NFIELDS (arg_type) == 1
+              && TYPE_CODE (TYPE_FIELD_TYPE (arg_type, 0)) == TYPE_CODE_FLT))
+          && MIPS_FPU_TYPE != MIPS_FPU_NONE);
+}
+
 CORE_ADDR
 mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
      int nargs;
@@ -2095,13 +2113,23 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
     len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), MIPS_SAVED_REGSIZE);
   sp -= ROUND_UP (len, 16);
 
+  if (mips_debug)
+    fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%lx allocated %d\n",
+                       (long) sp, ROUND_UP (len, 16));
+
   /* Initialize the integer and float register pointers.  */
   argreg = A0_REGNUM;
   float_argreg = FPA0_REGNUM;
 
   /* the struct_return pointer occupies the first parameter-passing reg */
   if (struct_return)
-    write_register (argreg++, struct_addr);
+    {
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_push_arguments: struct_return at r%d 0x%lx\n",
+                           argreg, (long) struct_addr);
+      write_register (argreg++, struct_addr);
+    }
 
   /* Now load as many as possible of the first arguments into
      registers, and push the rest onto the stack.  Loop thru args
@@ -2115,15 +2143,23 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
       int len = TYPE_LENGTH (arg_type);
       enum type_code typecode = TYPE_CODE (arg_type);
 
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_push_arguments: %d len=%d type=%d",
+                           argnum, len, (int) typecode);
+
       /* The EABI passes structures that do not fit in a register by
          reference. In all other cases, pass the structure by value.  */
-      if (MIPS_EABI && len > MIPS_SAVED_REGSIZE &&
-         (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
+      if (MIPS_EABI
+         && len > MIPS_SAVED_REGSIZE
+         && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
        {
          store_address (valbuf, MIPS_SAVED_REGSIZE, VALUE_ADDRESS (arg));
          typecode = TYPE_CODE_PTR;
          len = MIPS_SAVED_REGSIZE;
          val = valbuf;
+         if (mips_debug)
+           fprintf_unfiltered (gdb_stdlog, " push");
        }
       else
        val = (char *) VALUE_CONTENTS (arg);
@@ -2143,9 +2179,11 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
          don't use float registers for arguments.  This duplication of
          arguments in general registers can't hurt non-MIPS16 functions
          because those registers are normally skipped.  */
-      if (typecode == TYPE_CODE_FLT
-         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM
-         && MIPS_FPU_TYPE != MIPS_FPU_NONE)
+      /* MIPS_EABI squeeses a struct that contains a single floating
+         point value into an FP register instead of pusing it onto the
+         stack. */
+      if (fp_register_arg_p (typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
        {
          if (!FP_REGISTER_DOUBLE && len == 8)
            {
@@ -2154,17 +2192,30 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
 
              /* Write the low word of the double to the even register(s).  */
              regval = extract_unsigned_integer (val + low_offset, 4);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " fpreg=%d val=%s",
+                                   float_argreg, phex (regval, 4));
              write_register (float_argreg++, regval);
              if (!MIPS_EABI)
-               write_register (argreg + 1, regval);
+               {
+                 if (mips_debug)
+                   fprintf_unfiltered (gdb_stdlog, " reg=%d val=%s",
+                                       argreg, phex (regval, 4));
+                 write_register (argreg++, regval);
+               }
 
              /* Write the high word of the double to the odd register(s).  */
              regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " fpreg=%d val=%s",
+                                   float_argreg, phex (regval, 4));
              write_register (float_argreg++, regval);
              if (!MIPS_EABI)
                {
-                 write_register (argreg, regval);
-                 argreg += 2;
+                 if (mips_debug)
+                   fprintf_unfiltered (gdb_stdlog, " reg=%d val=%s",
+                                       argreg, phex (regval, 4));
+                 write_register (argreg++, regval);
                }
 
            }
@@ -2174,7 +2225,10 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
                 in a single register.  */
              /* On 32 bit ABI's the float_argreg is further adjusted
                  above to ensure that it is even register aligned. */
-             CORE_ADDR regval = extract_address (val, len);
+             LONGEST regval = extract_unsigned_integer (val, len);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " fpreg=%d val=%s",
+                                   float_argreg, phex (regval, len));
              write_register (float_argreg++, regval);
              if (!MIPS_EABI)
                {
@@ -2182,6 +2236,9 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
                      registers for each argument.  The below is (my
                      guess) to ensure that the corresponding integer
                      register has reserved the same space. */
+                 if (mips_debug)
+                   fprintf_unfiltered (gdb_stdlog, " reg=%d val=%s",
+                                       argreg, phex (regval, len));
                  write_register (argreg, regval);
                  argreg += FP_REGISTER_DOUBLE ? 1 : 2;
                }
@@ -2196,20 +2253,26 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
             are treated specially: Irix cc passes them in registers
             where gcc sometimes puts them on the stack.  For maximum
             compatibility, we will put them in both places.  */
-
          int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
                                  (len % MIPS_SAVED_REGSIZE != 0));
+         /* Note: Floating-point values that didn't fit into an FP
+             register are only written to memory. */
          while (len > 0)
            {
+             /* Rememer if the argument was written to the stack. */
+             int stack_used_p = 0;
              int partial_len = len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE;
 
-             if (argreg > MIPS_LAST_ARG_REGNUM || odd_sized_struct)
+             /* Write this portion of the argument to the stack.  */
+             if (argreg > MIPS_LAST_ARG_REGNUM
+                 || odd_sized_struct
+                 || fp_register_arg_p (typecode, arg_type))
                {
-                 /* Write this portion of the argument to the stack.  */
                  /* Should shorter than int integer values be
                     promoted to int before being stored? */
-
                  int longword_offset = 0;
+                 CORE_ADDR addr;
+                 stack_used_p = 1;
                  if (TARGET_BYTE_ORDER == BIG_ENDIAN)
                    {
                      if (MIPS_STACK_ARGSIZE == 8 &&
@@ -2223,15 +2286,37 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
                        longword_offset = MIPS_STACK_ARGSIZE - len;
                    }
 
-                 write_memory (sp + stack_offset + longword_offset,
-                               val, partial_len);
+                 if (mips_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog, " stack_offset=0x%lx",
+                                         (long) stack_offset);
+                     fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%lx",
+                                         (long) longword_offset);
+                   }
+                   
+                 addr = sp + stack_offset + longword_offset;
+
+                 if (mips_debug)
+                   {
+                     int i;
+                     fprintf_unfiltered (gdb_stdlog, " @0x%lx ", (long) addr);
+                     for (i = 0; i < partial_len; i++)
+                       {
+                         fprintf_unfiltered (gdb_stdlog, "%02x", val[i] & 0xff);
+                       }
+                   }
+                 write_memory (addr, val, partial_len);
                }
 
-             /* Note!!! This is NOT an else clause.
-                Odd sized structs may go thru BOTH paths.  */
-             if (argreg <= MIPS_LAST_ARG_REGNUM)
+             /* Note!!! This is NOT an else clause.  Odd sized
+                structs may go thru BOTH paths.  Floating point
+                arguments will not. */
+             /* Write this portion of the argument to a general
+                 purpose register. */
+             if (argreg <= MIPS_LAST_ARG_REGNUM
+                 && !fp_register_arg_p (typecode, arg_type))
                {
-                 CORE_ADDR regval = extract_address (val, partial_len);
+                 LONGEST regval = extract_unsigned_integer (val, partial_len);
 
                  /* A non-floating-point argument being passed in a 
                     general register.  If a struct or union, and if
@@ -2254,6 +2339,10 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
                    regval <<= ((MIPS_SAVED_REGSIZE - partial_len) *
                                TARGET_CHAR_BIT);
 
+                 if (mips_debug)
+                   fprintf_filtered (gdb_stdlog, " reg=%d val=%s",
+                                     argreg,
+                                     phex (regval, MIPS_SAVED_REGSIZE));
                  write_register (argreg, regval);
                  argreg++;
 
@@ -2267,20 +2356,23 @@ mips_push_arguments (nargs, args, sp, struct_return, struct_addr)
              len -= partial_len;
              val += partial_len;
 
-             /* The offset onto the stack at which we will start
-                copying parameters (after the registers are used up) 
-                begins at (4 * MIPS_REGSIZE) in the old ABI.  This 
-                leaves room for the "home" area for register parameters.
+             /* Compute the the offset into the stack at which we
+                will copy the next parameter.
+
+                In older ABIs, the caller reserved space for
+                registers that contained arguments.  This was loosely
+                refered to as their "home".  Consequently, space is
+                always allocated.
 
-                In the new EABI (and the NABI32), the 8 register parameters 
-                do not have "home" stack space reserved for them, so the
-                stack offset does not get incremented until after
-                we have used up the 8 parameter registers.  */
+                In the new EABI (and the NABI32), the stack_offset
+                only needs to be adjusted when it has been used.. */
 
-             if (MIPS_REGS_HAVE_HOME_P || argnum >= 8)
+             if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
                stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
            }
        }
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog, "\n");
     }
 
   /* Return adjusted stack pointer.  */
@@ -3847,8 +3939,12 @@ mips_gdbarch_init (info, arches)
   struct gdbarch *gdbarch;
   struct gdbarch_tdep *tdep;
   int elf_flags;
+#if 0
   int ef_mips_bitptrs;
+#endif
+#if 0
   int ef_mips_arch;
+#endif
   enum mips_abi mips_abi;
 
   /* Extract the elf_flags if available */
@@ -3901,14 +3997,18 @@ mips_gdbarch_init (info, arches)
   if (gdbarch_debug)
     {
       fprintf_unfiltered (gdb_stdlog,
-                         "mips_gdbarch_init: elf_flags = %08x\n",
+                         "mips_gdbarch_init: elf_flags = 0x%08x\n",
                          elf_flags);
+#if 0
       fprintf_unfiltered (gdb_stdlog,
                          "mips_gdbarch_init: ef_mips_arch = %d\n",
                          ef_mips_arch);
+#endif
+#if 0
       fprintf_unfiltered (gdb_stdlog,
                          "mips_gdbarch_init: ef_mips_bitptrs = %d\n",
                          ef_mips_bitptrs);
+#endif
       fprintf_unfiltered (gdb_stdlog,
                          "mips_gdbarch_init: mips_abi = %d\n",
                          mips_abi);
@@ -4037,6 +4137,7 @@ mips_gdbarch_init (info, arches)
      the current gcc - it would make GDB treat these 64-bit programs
      as 32-bit programs by default. */
 
+#if 0
   /* determine the ISA */
   switch (elf_flags & EF_MIPS_ARCH)
     {
@@ -4055,6 +4156,7 @@ mips_gdbarch_init (info, arches)
     default:
       break;
     }
+#endif
 
 #if 0
   /* determine the size of a pointer */
@@ -4645,4 +4747,11 @@ that would transfer 32 bits for some registers (e.g. SR, FSR) and\n\
 64 bits for others.  Use \"off\" to disable compatibility mode",
                                  &setlist),
                     &showlist);
+
+  /* Debug this files internals. */
+  add_show_from_set (add_set_cmd ("mips", class_maintenance, var_zinteger,
+                                 &mips_debug, "Set mips debugging.\n\
+When non-zero, mips specific debugging is enabled.", &setdebuglist),
+                    &showdebuglist);
 }
+
This page took 0.026644 seconds and 4 git commands to generate.