Doco LE O32 sizeof(struct) < 4 problem.
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index f723e4603f9532f89004c9a15a57cf2298c04b0e..a6e06bbf394b5657bd30a66dde035c5153f52816 100644 (file)
@@ -2126,9 +2126,38 @@ fp_register_arg_p (enum type_code typecode, struct type *arg_type)
           && MIPS_FPU_TYPE != MIPS_FPU_NONE);
 }
 
+/* On o32, argument passing in GPRs depends on the alignment of the type being
+   passed.  Return 1 if this type must be aligned to a doubleword boundary. */
+
+static int
+mips_type_needs_double_align (struct type *type)
+{
+  enum type_code typecode = TYPE_CODE (type);
+  
+  if (typecode == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8)
+    return 1;
+  else if (typecode == TYPE_CODE_STRUCT)
+    {
+      if (TYPE_NFIELDS (type) < 1)
+       return 0;
+      return mips_type_needs_double_align (TYPE_FIELD_TYPE (type, 0));
+    }
+  else if (typecode == TYPE_CODE_UNION)
+    {
+      int i, n;    
+
+      n = TYPE_NFIELDS (type);
+      for (i = 0; i < n; i++)
+       if (mips_type_needs_double_align (TYPE_FIELD_TYPE (type, i)))
+         return 1;
+      return 0;
+    }
+  return 0;
+}
+
 CORE_ADDR
 mips_push_arguments (int nargs,
-                    value_ptr *args,
+                    struct value **args,
                     CORE_ADDR sp,
                     int struct_return,
                     CORE_ADDR struct_addr)
@@ -2186,7 +2215,7 @@ mips_push_arguments (int nargs,
     {
       char *val;
       char valbuf[MAX_REGISTER_RAW_SIZE];
-      value_ptr arg = args[argnum];
+      struct value *arg = args[argnum];
       struct type *arg_type = check_typedef (VALUE_TYPE (arg));
       int len = TYPE_LENGTH (arg_type);
       enum type_code typecode = TYPE_CODE (arg_type);
@@ -2312,6 +2341,14 @@ mips_push_arguments (int nargs,
             compatibility, we will put them in both places.  */
          int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
                                  (len % MIPS_SAVED_REGSIZE != 0));
+         /* Structures should be aligned to eight bytes (even arg registers)
+            on MIPS_ABI_O32 if their first member has double precision. */
+         if (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_O32
+             && mips_type_needs_double_align (arg_type))
+           {
+             if ((argreg & 1))
+               argreg++;
+           }
          /* Note: Floating-point values that didn't fit into an FP
              register are only written to memory. */
          while (len > 0)
@@ -2389,7 +2426,20 @@ mips_push_arguments (int nargs,
                     same for integral types.
 
                     Also don't do this adjustment on EABI and O64
-                    binaries. */
+                    binaries.
+
+                    cagney/2001-07-23: gdb/179: Also, GCC, when
+                    outputting LE O32 with sizeof (struct) <
+                    MIPS_SAVED_REGSIZE, generates a left shift as
+                    part of storing the argument in a register a
+                    register (the left shift isn't generated when
+                    sizeof (struct) >= MIPS_SAVED_REGSIZE).  Since it
+                    is quite possible that this is GCC contradicting
+                    the LE/O32 ABI, GDB has not been adjusted to
+                    accommodate this.  Either someone needs to
+                    demonstrate that the LE/O32 ABI specifies such a
+                    left shift OR this new ABI gets identified as
+                    such and GDB gets tweaked accordingly.  */
 
                  if (!MIPS_EABI
                      && MIPS_SAVED_REGSIZE < 8
This page took 0.024412 seconds and 4 git commands to generate.