2002-08-09 Michael Snyder <msnyder@redhat.com>
authorMichael Snyder <msnyder@vmware.com>
Sat, 10 Aug 2002 00:34:04 +0000 (00:34 +0000)
committerMichael Snyder <msnyder@vmware.com>
Sat, 10 Aug 2002 00:34:04 +0000 (00:34 +0000)
* mips-tdep.c (ROUND_DOWN, ROUND_UP): Move to global scope.
(mips_push_arguments): Correct some comments.  Use paddr_nz
for printing addresses in debug output.  Replace static
allocation using MAX_REGISTER_RAW_SIZE with alloca.
(mips_n32n64_push_arguments): New function, cloned from
mips_push_arguments and tuned for the n32/n64 ABI.
(mips_push_register): Buffer needs dynamic allocation.
(mips_print_register): Ditto.
(do_gp_register_row): Ditto.
(mips_store_return_value): Ditto.
(mips_gdbarch_init): Set gdbarch_push_arguments per ABI.

gdb/ChangeLog
gdb/mips-tdep.c

index 42d2bb06ded842f9d3daa8965fe6b5110ab4a317..af49ea708778df0a3cb574c2d70e6977c322f918 100644 (file)
@@ -1,3 +1,17 @@
+2002-08-09  Michael Snyder  <msnyder@redhat.com>
+
+       * mips-tdep.c (ROUND_DOWN, ROUND_UP): Move to global scope.
+       (mips_push_arguments): Correct some comments.  Use paddr_nz
+       for printing addresses in debug output.  Replace static
+       allocation using MAX_REGISTER_RAW_SIZE with alloca.
+       (mips_n32n64_push_arguments): New function, cloned from
+       mips_push_arguments and tuned for the n32/n64 ABI.
+       (mips_push_register): Buffer needs dynamic allocation.
+       (mips_print_register): Ditto.
+       (do_gp_register_row): Ditto.
+       (mips_store_return_value): Ditto.
+       (mips_gdbarch_init): Set gdbarch_push_arguments per ABI.
+
 2002-08-09  Don Howard  <dhoward@redhat.com>
 
        * memattr.c (mem_info_command): Print special case of upper bound
index 1faf071ab5cb652f80c9bd66fc32d03afdd103eb..c57a03b26096d3f1932f9206cc40b9aff5699433 100644 (file)
@@ -2443,6 +2443,12 @@ mips_type_needs_double_align (struct type *type)
   return 0;
 }
 
+/* Macros to round N up or down to the next A boundary; 
+   A must be a power of two.  */
+
+#define ROUND_DOWN(n,a) ((n) & ~((a)-1))
+#define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
+
 CORE_ADDR
 mips_push_arguments (int nargs,
                     struct value **args,
@@ -2457,16 +2463,12 @@ mips_push_arguments (int nargs,
   int stack_offset = 0;
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
 
-  /* Macros to round N up or down to the next A boundary; A must be
-     a power of two. */
-#define ROUND_DOWN(n,a) ((n) & ~((a)-1))
-#define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
-
   /* First ensure that the stack and structure return address (if any)
-     are properly aligned. The stack has to be at least 64-bit aligned
-     even on 32-bit machines, because doubles must be 64-bit aligned.
-     On at least one MIPS variant, stack frames need to be 128-bit
-     aligned, so we round to this widest known alignment. */
+     are properly aligned.  The stack has to be at least 64-bit
+     aligned even on 32-bit machines, because doubles must be 64-bit
+     aligned.  For n32 and n64, stack frames need to be 128-bit
+     aligned, so we round to this widest known alignment.  */
+
   sp = ROUND_DOWN (sp, 16);
   struct_addr = ROUND_DOWN (struct_addr, 16);
 
@@ -2478,8 +2480,8 @@ mips_push_arguments (int nargs,
   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));
+    fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%s allocated %d\n",
+                       paddr_nz (sp), ROUND_UP (len, 16));
 
   /* Initialize the integer and float register pointers.  */
   argreg = A0_REGNUM;
@@ -2490,8 +2492,8 @@ mips_push_arguments (int nargs,
     {
       if (mips_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "mips_push_arguments: struct_return reg=%d 0x%lx\n",
-                           argreg, (long) struct_addr);
+                           "mips_push_arguments: struct_return reg=%d 0x%s\n",
+                           argreg, paddr_nz (struct_addr));
       write_register (argreg++, struct_addr);
       if (MIPS_REGS_HAVE_HOME_P)
        stack_offset += MIPS_STACK_ARGSIZE;
@@ -2503,7 +2505,7 @@ mips_push_arguments (int nargs,
   for (argnum = 0; argnum < nargs; argnum++)
     {
       char *val;
-      char valbuf[MAX_REGISTER_RAW_SIZE];
+      char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
       struct value *arg = args[argnum];
       struct type *arg_type = check_typedef (VALUE_TYPE (arg));
       int len = TYPE_LENGTH (arg_type);
@@ -2675,10 +2677,10 @@ mips_push_arguments (int nargs,
 
                  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);
+                     fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+                                         paddr_nz (stack_offset));
+                     fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+                                         paddr_nz (longword_offset));
                    }
 
                  addr = sp + stack_offset + longword_offset;
@@ -2686,10 +2688,12 @@ mips_push_arguments (int nargs,
                  if (mips_debug)
                    {
                      int i;
-                     fprintf_unfiltered (gdb_stdlog, " @0x%lx ", (long) addr);
+                     fprintf_unfiltered (gdb_stdlog, " @0x%s ", 
+                                         paddr_nz (addr));
                      for (i = 0; i < partial_len; i++)
                        {
-                         fprintf_unfiltered (gdb_stdlog, "%02x", val[i] & 0xff);
+                         fprintf_unfiltered (gdb_stdlog, "%02x", 
+                                             val[i] & 0xff);
                        }
                    }
                  write_memory (addr, val, partial_len);
@@ -2779,6 +2783,230 @@ mips_push_arguments (int nargs,
   return sp;
 }
 
+CORE_ADDR
+mips_n32n64_push_arguments (int nargs,
+                           struct value **args,
+                           CORE_ADDR sp,
+                           int struct_return,
+                           CORE_ADDR struct_addr)
+{
+  int argreg;
+  int float_argreg;
+  int argnum;
+  int len = 0;
+  int stack_offset = 0;
+
+  /* First ensure that the stack and structure return address (if any)
+     are properly aligned.  The stack has to be at least 64-bit
+     aligned even on 32-bit machines, because doubles must be 64-bit
+     aligned.  For n32 and n64, stack frames need to be 128-bit
+     aligned, so we round to this widest known alignment.  */
+
+  sp = ROUND_DOWN (sp, 16);
+  struct_addr = ROUND_DOWN (struct_addr, 16);
+
+  /* Now make space on the stack for the args.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), 
+                    MIPS_STACK_ARGSIZE);
+  sp -= ROUND_UP (len, 16);
+
+  if (mips_debug)
+    fprintf_unfiltered (gdb_stdlog, 
+                       "mips_n32n64_push_arguments: sp=0x%s allocated %d\n",
+                       paddr_nz (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)
+    {
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_n32n64_push_arguments: struct_return reg=%d 0x%s\n",
+                           argreg, paddr_nz (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
+     from first to last.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      char *val;
+      char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
+      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);
+
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_n32n64_push_arguments: %d len=%d type=%d",
+                           argnum + 1, len, (int) typecode);
+
+      val = (char *) VALUE_CONTENTS (arg);
+
+      if (fp_register_arg_p (typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+       {
+         /* This is a floating point value that fits entirely
+            in a single register.  */
+         /* On 32 bit ABI's the float_argreg is further adjusted
+            above to ensure that it is even register aligned.  */
+         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_debug)
+           fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+                               argreg, phex (regval, len));
+         write_register (argreg, regval);
+         argreg += 1;
+       }
+      else
+       {
+         /* Copy the argument to general registers or the stack in
+            register-sized pieces.  Large arguments are split between
+            registers and stack.  */
+         /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+            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 (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
+                                   partial_len);
+
+             /* 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))
+               {
+                 /* 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 == BFD_ENDIAN_BIG)
+                   {
+                     if (MIPS_STACK_ARGSIZE == 8 &&
+                         (typecode == TYPE_CODE_INT ||
+                          typecode == TYPE_CODE_PTR ||
+                          typecode == TYPE_CODE_FLT) && len <= 4)
+                       longword_offset = MIPS_STACK_ARGSIZE - len;
+                     else if ((typecode == TYPE_CODE_STRUCT ||
+                               typecode == TYPE_CODE_UNION) &&
+                              TYPE_LENGTH (arg_type) < MIPS_STACK_ARGSIZE)
+                       longword_offset = MIPS_STACK_ARGSIZE - len;
+                   }
+
+                 if (mips_debug)
+                   {
+                     fprintf_unfiltered (gdb_stdlog, " - stack_offset=0x%s",
+                                         paddr_nz (stack_offset));
+                     fprintf_unfiltered (gdb_stdlog, " longword_offset=0x%s",
+                                         paddr_nz (longword_offset));
+                   }
+
+                 addr = sp + stack_offset + longword_offset;
+
+                 if (mips_debug)
+                   {
+                     int i;
+                     fprintf_unfiltered (gdb_stdlog, " @0x%s ", 
+                                         paddr_nz (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.  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))
+               {
+                 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
+                    the remaining length is smaller than the register
+                    size, we have to adjust the register value on
+                    big endian targets.
+
+                    It does not seem to be necessary to do the
+                    same for integral types.
+
+                    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 (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+                     && partial_len < MIPS_SAVED_REGSIZE
+                     && (typecode == TYPE_CODE_STRUCT ||
+                         typecode == TYPE_CODE_UNION))
+                   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++;
+               }
+
+             len -= partial_len;
+             val += partial_len;
+
+             /* Compute the the offset into the stack at which we
+                will copy the next parameter.
+
+                In N32 (N64?), the stack_offset only needs to be
+                adjusted when it has been used.  */
+
+             if (stack_used_p)
+               stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+           }
+       }
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog, "\n");
+    }
+
+  /* Return adjusted stack pointer.  */
+  return sp;
+}
+
 CORE_ADDR
 mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
 {
@@ -2791,7 +3019,7 @@ mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
 static void
 mips_push_register (CORE_ADDR * sp, int regno)
 {
-  char buffer[MAX_REGISTER_RAW_SIZE];
+  char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
   int regsize;
   int offset;
   if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
@@ -3070,7 +3298,7 @@ mips_read_fp_register_double (int regno, char *rare_buffer)
 static void
 mips_print_register (int regnum, int all)
 {
-  char raw_buffer[MAX_REGISTER_RAW_SIZE];
+  char *raw_buffer (MAX_REGISTER_RAW_SIZE);
 
   /* Get the data in raw format.  */
   if (!frame_register_read (selected_frame, regnum, raw_buffer))
@@ -3087,7 +3315,7 @@ mips_print_register (int regnum, int all)
          || mips2_fp_compat ())
       && !((regnum - FP0_REGNUM) & 1))
     {
-      char dbuffer[2 * MAX_REGISTER_RAW_SIZE];
+      char *dbuffer = alloca (2 * MAX_REGISTER_RAW_SIZE);
 
       mips_read_fp_register_double (regnum, dbuffer);
 
@@ -3222,7 +3450,7 @@ static int
 do_gp_register_row (int regnum)
 {
   /* do values for GP (int) regs */
-  char raw_buffer[MAX_REGISTER_RAW_SIZE];
+  char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
   int ncols = (MIPS_REGSIZE == 8 ? 4 : 8);     /* display cols per row */
   int col, byte;
   int start_regnum = regnum;
@@ -3715,7 +3943,7 @@ mips_extract_return_value (struct type *valtype,
 void
 mips_store_return_value (struct type *valtype, char *valbuf)
 {
-  char raw_buffer[MAX_REGISTER_RAW_SIZE];
+  char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
   struct return_value_word lo;
   struct return_value_word hi;
   return_value_location (valtype, &hi, &lo);
@@ -4547,6 +4775,7 @@ mips_gdbarch_init (struct gdbarch_info info,
   switch (mips_abi)
     {
     case MIPS_ABI_O32:
+      set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
       tdep->mips_default_saved_regsize = 4;
       tdep->mips_default_stack_argsize = 4;
       tdep->mips_fp_register_double = 0;
@@ -4564,6 +4793,7 @@ mips_gdbarch_init (struct gdbarch_info info,
                                         mips_o32_use_struct_convention);
       break;
     case MIPS_ABI_O64:
+      set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
@@ -4581,6 +4811,7 @@ mips_gdbarch_init (struct gdbarch_info info,
                                         mips_o32_use_struct_convention);
       break;
     case MIPS_ABI_EABI32:
+      set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
       tdep->mips_default_saved_regsize = 4;
       tdep->mips_default_stack_argsize = 4;
       tdep->mips_fp_register_double = 0;
@@ -4598,6 +4829,7 @@ mips_gdbarch_init (struct gdbarch_info info,
                                         mips_eabi_use_struct_convention);
       break;
     case MIPS_ABI_EABI64:
+      set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
@@ -4615,6 +4847,7 @@ mips_gdbarch_init (struct gdbarch_info info,
                                         mips_eabi_use_struct_convention);
       break;
     case MIPS_ABI_N32:
+      set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
@@ -4644,6 +4877,7 @@ mips_gdbarch_init (struct gdbarch_info info,
                                       mips_n32n64_reg_struct_has_addr);
       break;
     case MIPS_ABI_N64:
+      set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
@@ -4763,7 +4997,6 @@ mips_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_call_dummy_words (gdbarch, mips_call_dummy_words);
   set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (mips_call_dummy_words));
   set_gdbarch_push_return_address (gdbarch, mips_push_return_address);
-  set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
   set_gdbarch_register_convertible (gdbarch, generic_register_convertible_not);
   set_gdbarch_coerce_float_to_double (gdbarch, mips_coerce_float_to_double);