2002-08-14 Michael Snyder <msnyder@redhat.com>
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 421b45f42c5e615873fbdddcb85d9e1fc5793118..296dea672c4cbd7d96dacfa890f605e6f4adf403 100644 (file)
@@ -138,7 +138,6 @@ struct gdbarch_tdep
     int mips_last_fp_arg_regnum;
     int mips_default_saved_regsize;
     int mips_fp_register_double;
-    int mips_regs_have_home_p;
     int mips_default_stack_argsize;
     int gdb_target_is_mips64;
     int default_mask_address_p;
@@ -174,6 +173,57 @@ mips_saved_regsize (void)
     return 4;
 }
 
+/* XFER a value from the big/little/left end of the register.
+   Depending on the size of the value it might occupy the entire
+   register or just part of it.  Make an allowance for this, aligning
+   things accordingly.  */
+
+static void
+mips_xfer_register (struct regcache *regcache, int reg_num, int length,
+                   enum bfd_endian endian, bfd_byte *in, const bfd_byte *out,
+                   int buf_offset)
+{
+  bfd_byte *reg = alloca (MAX_REGISTER_RAW_SIZE);
+  int reg_offset = 0;
+  switch (endian)
+    {
+    case BFD_ENDIAN_BIG:
+      reg_offset = REGISTER_RAW_SIZE (reg_num) - length;
+      break;
+    case BFD_ENDIAN_LITTLE:
+      reg_offset = 0;
+      break;
+    case BFD_ENDIAN_UNKNOWN: /* Indicates no alignment.  */
+      reg_offset = 0;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, "bad switch");
+    }
+  if (mips_debug)
+    fprintf_unfiltered (gdb_stderr, "xfer $%d[%d..%d] ",
+                       reg_num, reg_offset, reg_offset + length);
+  if (mips_debug && out != NULL)
+    {
+      int i;
+      fprintf_unfiltered (gdb_stdlog, "out: ");
+      for (i = 0; i < length; i++)
+       fprintf_unfiltered (gdb_stdlog, "%02x", out[i]);
+    }
+  if (in != NULL)
+    regcache_raw_read_part (regcache, reg_num, reg_offset, length, in + buf_offset);
+  if (out != NULL)
+    regcache_raw_write_part (regcache, reg_num, reg_offset, length, out + buf_offset);
+  if (mips_debug && in != NULL)
+    {
+      int i;
+      fprintf_unfiltered (gdb_stdlog, "in: ");
+      for (i = 0; i < length; i++)
+       fprintf_unfiltered (gdb_stdlog, "%02x", in[i]);
+    }
+  if (mips_debug)
+    fprintf_unfiltered (gdb_stdlog, "\n");
+}
+
 /* Determine if a MIPS3 or later cpu is operating in MIPS{1,2} FPU
    compatiblity mode.  A return value of 1 means that we have
    physical 64-bit registers, but should treat them as 32-bit registers.  */
@@ -206,11 +256,6 @@ mips2_fp_compat (void)
    MIPS_FPU_TYPE. */
 #define FP_REGISTER_DOUBLE (gdbarch_tdep (current_gdbarch)->mips_fp_register_double)
 
-/* Does the caller allocate a ``home'' for each register used in the
-   function call?  The N32 ABI and MIPS_EABI do not, the others do. */
-
-#define MIPS_REGS_HAVE_HOME_P (gdbarch_tdep (current_gdbarch)->mips_regs_have_home_p)
-
 /* The amount of space reserved on the stack for registers. This is
    different to MIPS_SAVED_REGSIZE as it determines the alignment of
    data allocated after the registers have run out. */
@@ -445,7 +490,7 @@ mips_register_raw_size (int reg_nr)
 /* Convert between RAW and VIRTUAL registers.  The RAW register size
    defines the remote-gdb packet. */
 
-int
+static int
 mips_register_convertible (int reg_nr)
 {
   if (mips64_transfers_32bit_regs_p)
@@ -454,7 +499,7 @@ mips_register_convertible (int reg_nr)
     return (REGISTER_RAW_SIZE (reg_nr) > REGISTER_VIRTUAL_SIZE (reg_nr));
 }
 
-void
+static void
 mips_register_convert_to_virtual (int n, struct type *virtual_type,
                                  char *raw_buf, char *virt_buf)
 {
@@ -468,7 +513,7 @@ mips_register_convert_to_virtual (int n, struct type *virtual_type,
            TYPE_LENGTH (virtual_type));
 }
 
-void
+static void
 mips_register_convert_to_raw (struct type *virtual_type, int n,
                              char *virt_buf, char *raw_buf)
 {
@@ -483,6 +528,38 @@ mips_register_convert_to_raw (struct type *virtual_type, int n,
            TYPE_LENGTH (virtual_type));
 }
 
+void
+mips_register_convert_to_type (int regnum, struct type *type, char *buffer)
+{
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+      && REGISTER_RAW_SIZE (regnum) == 4
+      && (regnum) >= FP0_REGNUM && (regnum) < FP0_REGNUM + 32
+      && TYPE_CODE(type) == TYPE_CODE_FLT
+      && TYPE_LENGTH(type) == 8) 
+    {
+      char temp[4];
+      memcpy (temp, ((char *)(buffer))+4, 4);
+      memcpy (((char *)(buffer))+4, (buffer), 4);
+      memcpy (((char *)(buffer)), temp, 4); 
+    }
+}
+
+void
+mips_register_convert_from_type (int regnum, struct type *type, char *buffer)
+{
+if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+    && REGISTER_RAW_SIZE (regnum) == 4
+    && (regnum) >= FP0_REGNUM && (regnum) < FP0_REGNUM + 32
+    && TYPE_CODE(type) == TYPE_CODE_FLT
+    && TYPE_LENGTH(type) == 8) 
+  {
+    char temp[4];
+    memcpy (temp, ((char *)(buffer))+4, 4);
+    memcpy (((char *)(buffer))+4, (buffer), 4);
+    memcpy (((char *)(buffer)), temp, 4);
+  }
+}
+
 /* Return the GDB type object for the "standard" data type
    of data in register REG.  
    
@@ -519,6 +596,14 @@ mips_register_virtual_type (int reg)
     }
 }
 
+/* TARGET_READ_SP -- Remove useless bits from the stack pointer.  */
+
+static CORE_ADDR
+mips_read_sp (void)
+{
+  return ADDR_BITS_REMOVE (read_register (SP_REGNUM));
+}
+
 /* Should the upper word of 64-bit addresses be zeroed? */
 enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
 
@@ -2300,9 +2385,11 @@ mips_frame_chain (struct frame_info *frame)
      we loop forever if we see a zero size frame.  */
   if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
       && PROC_FRAME_OFFSET (proc_desc) == 0
-  /* The previous frame from a sigtramp frame might be frameless
-     and have frame size zero.  */
-      && !frame->signal_handler_caller)
+      /* The previous frame from a sigtramp frame might be frameless
+        and have frame size zero.  */
+      && !frame->signal_handler_caller
+      /* Check if this is a call dummy frame.  */
+      && frame->pc != mips_call_dummy_address ())
     return 0;
   else
     return get_frame_pointer (frame, proc_desc);
@@ -2450,18 +2537,17 @@ mips_type_needs_double_align (struct type *type)
 #define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
 
 CORE_ADDR
-mips_push_arguments (int nargs,
-                    struct value **args,
-                    CORE_ADDR sp,
-                    int struct_return,
-                    CORE_ADDR struct_addr)
+mips_eabi_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;
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
 
   /* First ensure that the stack and structure return address (if any)
      are properly aligned.  The stack has to be at least 64-bit
@@ -2472,31 +2558,31 @@ mips_push_arguments (int nargs,
   sp = ROUND_DOWN (sp, 16);
   struct_addr = ROUND_DOWN (struct_addr, 16);
 
-  /* Now make space on the stack for the args. We allocate more
+  /* Now make space on the stack for the args.  We allocate more
      than necessary for EABI, because the first few arguments are
-     passed in registers, but that's OK. */
+     passed in registers, but that's OK.  */
   for (argnum = 0; argnum < nargs; argnum++)
-    len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), MIPS_STACK_ARGSIZE);
+    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_push_arguments: sp=0x%s allocated %d\n",
+    fprintf_unfiltered (gdb_stdlog, 
+                       "mips_eabi_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 */
+  /* The struct_return pointer occupies the first parameter-passing reg.  */
   if (struct_return)
     {
       if (mips_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "mips_push_arguments: struct_return reg=%d 0x%s\n",
+                           "mips_eabi_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;
     }
 
   /* Now load as many as possible of the first arguments into
@@ -2513,13 +2599,12 @@ mips_push_arguments (int nargs,
 
       if (mips_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "mips_push_arguments: %d len=%d type=%d",
+                           "mips_eabi_push_arguments: %d len=%d type=%d",
                            argnum + 1, 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
+         reference.  */
+      if (len > MIPS_SAVED_REGSIZE
          && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
        {
          store_address (valbuf, MIPS_SAVED_REGSIZE, VALUE_ADDRESS (arg));
@@ -2535,8 +2620,8 @@ mips_push_arguments (int nargs,
       /* 32-bit ABIs always start floating point arguments in an
          even-numbered floating point register.  Round the FP register
          up before the check to see if there are any FP registers
-         left. Non MIPS_EABI targets also pass the FP in the integer
-         registers so also round up normal registers. */
+         left.  Non MIPS_EABI targets also pass the FP in the integer
+         registers so also round up normal registers.  */
       if (!FP_REGISTER_DOUBLE
          && fp_register_arg_p (typecode, arg_type))
        {
@@ -2555,7 +2640,7 @@ mips_push_arguments (int nargs,
          because those registers are normally skipped.  */
       /* MIPS_EABI squeezes a struct that contains a single floating
          point value into an FP register instead of pushing it onto the
-         stack. */
+         stack.  */
       if (fp_register_arg_p (typecode, arg_type)
          && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
        {
@@ -2570,13 +2655,6 @@ mips_push_arguments (int nargs,
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
              write_register (float_argreg++, regval);
-             if (!MIPS_EABI)
-               {
-                 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);
@@ -2584,42 +2662,19 @@ mips_push_arguments (int nargs,
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
              write_register (float_argreg++, regval);
-             if (!MIPS_EABI)
-               {
-                 if (mips_debug)
-                   fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
-                                       argreg, phex (regval, 4));
-                 write_register (argreg++, regval);
-               }
-
            }
          else
            {
              /* 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. */
+                 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_EABI)
-               {
-                 /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
-                     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;
-               }
            }
-         /* Reserve space for the FP register. */
-         if (MIPS_REGS_HAVE_HOME_P)
-           stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
        }
       else
        {
@@ -2632,21 +2687,15 @@ 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 (tdep->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. */
+             register are only written to memory.  */
          while (len > 0)
            {
-             /* Rememer if the argument was written to the stack. */
+             /* Remember if the argument was written to the stack.  */
              int stack_used_p = 0;
-             int partial_len = len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE;
+             int partial_len = 
+               len < MIPS_SAVED_REGSIZE ? len : MIPS_SAVED_REGSIZE;
 
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
@@ -2701,60 +2750,20 @@ mips_push_arguments (int nargs,
 
              /* Note!!! This is NOT an else clause.  Odd sized
                 structs may go thru BOTH paths.  Floating point
-                arguments will not. */
+                arguments will not.  */
              /* Write this portion of the argument to a general
-                 purpose register. */
+                 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.
-
-                    Also don't do this adjustment on EABI and O64
-                    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
-                     && 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++;
-
-                 /* If this is the old ABI, prevent subsequent floating
-                    point arguments from being passed in floating point
-                    registers.  */
-                 if (!MIPS_EABI)
-                   float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
                }
 
              len -= partial_len;
@@ -2763,15 +2772,10 @@ mips_push_arguments (int nargs,
              /* 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 stack_offset
-                only needs to be adjusted when it has been used.. */
+                only needs to be adjusted when it has been used.  */
 
-             if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
+             if (stack_used_p)
                stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
            }
        }
@@ -2783,6 +2787,8 @@ mips_push_arguments (int nargs,
   return sp;
 }
 
+/* N32/N64 version of push_arguments.  */
+
 CORE_ADDR
 mips_n32n64_push_arguments (int nargs,
                            struct value **args,
@@ -2820,7 +2826,7 @@ mips_n32n64_push_arguments (int nargs,
   argreg = A0_REGNUM;
   float_argreg = FPA0_REGNUM;
 
-  /* the struct_return pointer occupies the first parameter-passing reg */
+  /* The struct_return pointer occupies the first parameter-passing reg.  */
   if (struct_return)
     {
       if (mips_debug)
@@ -3007,123 +3013,721 @@ mips_n32n64_push_arguments (int nargs,
   return sp;
 }
 
-CORE_ADDR
-mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
-{
-  /* Set the return address register to point to the entry
-     point of the program, where a breakpoint lies in wait.  */
-  write_register (RA_REGNUM, CALL_DUMMY_ADDRESS ());
-  return sp;
-}
+/* O32 version of push_arguments.  */
 
-static void
-mips_push_register (CORE_ADDR * sp, int regno)
+static CORE_ADDR
+mips_o32_push_arguments (int nargs,
+                        struct value **args,
+                        CORE_ADDR sp,
+                        int struct_return,
+                        CORE_ADDR struct_addr)
 {
-  char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
-  int regsize;
-  int offset;
-  if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
-    {
-      regsize = MIPS_SAVED_REGSIZE;
-      offset = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
-               ? REGISTER_RAW_SIZE (regno) - MIPS_SAVED_REGSIZE
-               : 0);
-    }
-  else
-    {
-      regsize = REGISTER_RAW_SIZE (regno);
-      offset = 0;
-    }
-  *sp -= regsize;
-  read_register_gen (regno, buffer);
-  write_memory (*sp, buffer + offset, regsize);
-}
+  int argreg;
+  int float_argreg;
+  int argnum;
+  int len = 0;
+  int stack_offset = 0;
 
-/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<(MIPS_NUMREGS-1). */
-#define MASK(i,j) (((1 << ((j)+1))-1) ^ ((1 << (i))-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.  For n32 and n64, stack frames need to be 128-bit
+     aligned, so we round to this widest known alignment.  */
 
-void
-mips_push_dummy_frame (void)
-{
-  int ireg;
-  struct linked_proc_info *link = (struct linked_proc_info *)
-  xmalloc (sizeof (struct linked_proc_info));
-  mips_extra_func_info_t proc_desc = &link->info;
-  CORE_ADDR sp = ADDR_BITS_REMOVE (read_signed_register (SP_REGNUM));
-  CORE_ADDR old_sp = sp;
-  link->next = linked_proc_desc_table;
-  linked_proc_desc_table = link;
+  sp = ROUND_DOWN (sp, 16);
+  struct_addr = ROUND_DOWN (struct_addr, 16);
 
-/* FIXME!   are these correct ? */
-#define PUSH_FP_REGNUM 16      /* must be a register preserved across calls */
-#define GEN_REG_SAVE_MASK MASK(1,16)|MASK(24,28)|(1<<(MIPS_NUMREGS-1))
-#define FLOAT_REG_SAVE_MASK MASK(0,19)
-#define FLOAT_SINGLE_REG_SAVE_MASK \
-  ((1<<18)|(1<<16)|(1<<14)|(1<<12)|(1<<10)|(1<<8)|(1<<6)|(1<<4)|(1<<2)|(1<<0))
-  /*
-   * The registers we must save are all those not preserved across
-   * procedure calls. Dest_Reg (see tm-mips.h) must also be saved.
-   * In addition, we must save the PC, PUSH_FP_REGNUM, MMLO/-HI
-   * and FP Control/Status registers.
-   *
-   *
-   * Dummy frame layout:
-   *  (high memory)
-   *    Saved PC
-   *    Saved MMHI, MMLO, FPC_CSR
-   *    Saved R31
-   *    Saved R28
-   *    ...
-   *    Saved R1
-   *    Saved D18 (i.e. F19, F18)
-   *    ...
-   *    Saved D0 (i.e. F1, F0)
-   *    Argument build area and stack arguments written via mips_push_arguments
-   *  (low memory)
-   */
+  /* 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);
 
-  /* Save special registers (PC, MMHI, MMLO, FPC_CSR) */
-  PROC_FRAME_REG (proc_desc) = PUSH_FP_REGNUM;
-  PROC_FRAME_OFFSET (proc_desc) = 0;
-  PROC_FRAME_ADJUST (proc_desc) = 0;
-  mips_push_register (&sp, PC_REGNUM);
-  mips_push_register (&sp, HI_REGNUM);
-  mips_push_register (&sp, LO_REGNUM);
-  mips_push_register (&sp, MIPS_FPU_TYPE == MIPS_FPU_NONE ? 0 : FCRCS_REGNUM);
+  if (mips_debug)
+    fprintf_unfiltered (gdb_stdlog, 
+                       "mips_o32_push_arguments: sp=0x%s allocated %d\n",
+                       paddr_nz (sp), ROUND_UP (len, 16));
 
-  /* Save general CPU registers */
-  PROC_REG_MASK (proc_desc) = GEN_REG_SAVE_MASK;
-  /* PROC_REG_OFFSET is the offset of the first saved register from FP.  */
-  PROC_REG_OFFSET (proc_desc) = sp - old_sp - MIPS_SAVED_REGSIZE;
-  for (ireg = 32; --ireg >= 0;)
-    if (PROC_REG_MASK (proc_desc) & (1 << ireg))
-      mips_push_register (&sp, ireg);
+  /* Initialize the integer and float register pointers.  */
+  argreg = A0_REGNUM;
+  float_argreg = FPA0_REGNUM;
 
-  /* Save floating point registers starting with high order word */
-  PROC_FREG_MASK (proc_desc) =
-    MIPS_FPU_TYPE == MIPS_FPU_DOUBLE ? FLOAT_REG_SAVE_MASK
-    : MIPS_FPU_TYPE == MIPS_FPU_SINGLE ? FLOAT_SINGLE_REG_SAVE_MASK : 0;
-  /* PROC_FREG_OFFSET is the offset of the first saved *double* register
-     from FP.  */
-  PROC_FREG_OFFSET (proc_desc) = sp - old_sp - 8;
-  for (ireg = 32; --ireg >= 0;)
-    if (PROC_FREG_MASK (proc_desc) & (1 << ireg))
-      mips_push_register (&sp, ireg + FP0_REGNUM);
+  /* The struct_return pointer occupies the first parameter-passing reg.  */
+  if (struct_return)
+    {
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_o32_push_arguments: struct_return reg=%d 0x%s\n",
+                           argreg, paddr_nz (struct_addr));
+      write_register (argreg++, struct_addr);
+      stack_offset += MIPS_STACK_ARGSIZE;
+    }
 
-  /* Update the frame pointer for the call dummy and the stack pointer.
-     Set the procedure's starting and ending addresses to point to the
-     call dummy address at the entry point.  */
-  write_register (PUSH_FP_REGNUM, old_sp);
-  write_register (SP_REGNUM, sp);
-  PROC_LOW_ADDR (proc_desc) = CALL_DUMMY_ADDRESS ();
-  PROC_HIGH_ADDR (proc_desc) = CALL_DUMMY_ADDRESS () + 4;
-  SET_PROC_DESC_IS_DUMMY (proc_desc);
-  PROC_PC_REG (proc_desc) = RA_REGNUM;
-}
+  /* 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);
 
-void
-mips_pop_frame (void)
-{
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_o32_push_arguments: %d len=%d type=%d",
+                           argnum + 1, len, (int) typecode);
+
+      val = (char *) VALUE_CONTENTS (arg);
+
+      /* 32-bit ABIs always start floating point arguments in an
+         even-numbered floating point register.  Round the FP register
+         up before the check to see if there are any FP registers
+         left.  O32/O64 targets also pass the FP in the integer
+         registers so also round up normal registers.  */
+      if (!FP_REGISTER_DOUBLE
+         && fp_register_arg_p (typecode, arg_type))
+       {
+         if ((float_argreg & 1))
+           float_argreg++;
+       }
+
+      /* Floating point arguments passed in registers have to be
+         treated specially.  On 32-bit architectures, doubles
+         are passed in register pairs; the even register gets
+         the low word, and the odd register gets the high word.
+         On O32/O64, the first two floating point arguments are
+         also copied to general registers, because MIPS16 functions
+         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 (fp_register_arg_p (typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+       {
+         if (!FP_REGISTER_DOUBLE && len == 8)
+           {
+             int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+             unsigned long regval;
+
+             /* 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_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_debug)
+               fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+                                   argreg, phex (regval, 4));
+             write_register (argreg++, regval);
+           }
+         else
+           {
+             /* 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);
+             /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
+                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;
+           }
+         /* Reserve space for the FP register.  */
+         stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
+       }
+      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));
+         /* Structures should be aligned to eight bytes (even arg registers)
+            on MIPS_ABI_O32, if their first member has double precision.  */
+         if (MIPS_SAVED_REGSIZE < 8
+             && 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)
+           {
+             /* Remember 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;
+                   }
+
+                 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_signed_integer (val, partial_len);
+                 /* Value may need to be sign extended, because 
+                    MIPS_REGSIZE != MIPS_SAVED_REGSIZE.  */
+
+                 /* 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.
+
+                    Also don't do this adjustment on O64 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_SAVED_REGSIZE < 8
+                     && 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++;
+
+                 /* Prevent subsequent floating point arguments from
+                    being passed in floating point registers.  */
+                 float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+               }
+
+             len -= partial_len;
+             val += partial_len;
+
+             /* 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.  */
+
+             stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+           }
+       }
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog, "\n");
+    }
+
+  /* Return adjusted stack pointer.  */
+  return sp;
+}
+
+/* O64 version of push_arguments.  */
+
+static CORE_ADDR
+mips_o64_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_o64_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_o64_push_arguments: struct_return reg=%d 0x%s\n",
+                           argreg, paddr_nz (struct_addr));
+      write_register (argreg++, struct_addr);
+      stack_offset += MIPS_STACK_ARGSIZE;
+    }
+
+  /* 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_o64_push_arguments: %d len=%d type=%d",
+                           argnum + 1, len, (int) typecode);
+
+      val = (char *) VALUE_CONTENTS (arg);
+
+      /* 32-bit ABIs always start floating point arguments in an
+         even-numbered floating point register.  Round the FP register
+         up before the check to see if there are any FP registers
+         left.  O32/O64 targets also pass the FP in the integer
+         registers so also round up normal registers.  */
+      if (!FP_REGISTER_DOUBLE
+         && fp_register_arg_p (typecode, arg_type))
+       {
+         if ((float_argreg & 1))
+           float_argreg++;
+       }
+
+      /* Floating point arguments passed in registers have to be
+         treated specially.  On 32-bit architectures, doubles
+         are passed in register pairs; the even register gets
+         the low word, and the odd register gets the high word.
+         On O32/O64, the first two floating point arguments are
+         also copied to general registers, because MIPS16 functions
+         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 (fp_register_arg_p (typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+       {
+         if (!FP_REGISTER_DOUBLE && len == 8)
+           {
+             int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+             unsigned long regval;
+
+             /* 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_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_debug)
+               fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+                                   argreg, phex (regval, 4));
+             write_register (argreg++, regval);
+           }
+         else
+           {
+             /* 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);
+             /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
+                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;
+           }
+         /* Reserve space for the FP register.  */
+         stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
+       }
+      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));
+         /* Structures should be aligned to eight bytes (even arg registers)
+            on MIPS_ABI_O32, if their first member has double precision.  */
+         if (MIPS_SAVED_REGSIZE < 8
+             && 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)
+           {
+             /* Remember 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;
+                   }
+
+                 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_signed_integer (val, partial_len);
+                 /* Value may need to be sign extended, because 
+                    MIPS_REGSIZE != MIPS_SAVED_REGSIZE.  */
+
+                 /* 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.
+
+                    Also don't do this adjustment on O64 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_SAVED_REGSIZE < 8
+                     && 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++;
+
+                 /* Prevent subsequent floating point arguments from
+                    being passed in floating point registers.  */
+                 float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
+               }
+
+             len -= partial_len;
+             val += partial_len;
+
+             /* 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.  */
+
+             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)
+{
+  /* Set the return address register to point to the entry
+     point of the program, where a breakpoint lies in wait.  */
+  write_register (RA_REGNUM, CALL_DUMMY_ADDRESS ());
+  return sp;
+}
+
+static void
+mips_push_register (CORE_ADDR * sp, int regno)
+{
+  char *buffer = alloca (MAX_REGISTER_RAW_SIZE);
+  int regsize;
+  int offset;
+  if (MIPS_SAVED_REGSIZE < REGISTER_RAW_SIZE (regno))
+    {
+      regsize = MIPS_SAVED_REGSIZE;
+      offset = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+               ? REGISTER_RAW_SIZE (regno) - MIPS_SAVED_REGSIZE
+               : 0);
+    }
+  else
+    {
+      regsize = REGISTER_RAW_SIZE (regno);
+      offset = 0;
+    }
+  *sp -= regsize;
+  read_register_gen (regno, buffer);
+  write_memory (*sp, buffer + offset, regsize);
+}
+
+/* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<(MIPS_NUMREGS-1). */
+#define MASK(i,j) (((1 << ((j)+1))-1) ^ ((1 << (i))-1))
+
+void
+mips_push_dummy_frame (void)
+{
+  int ireg;
+  struct linked_proc_info *link = (struct linked_proc_info *)
+  xmalloc (sizeof (struct linked_proc_info));
+  mips_extra_func_info_t proc_desc = &link->info;
+  CORE_ADDR sp = ADDR_BITS_REMOVE (read_signed_register (SP_REGNUM));
+  CORE_ADDR old_sp = sp;
+  link->next = linked_proc_desc_table;
+  linked_proc_desc_table = link;
+
+/* FIXME!   are these correct ? */
+#define PUSH_FP_REGNUM 16      /* must be a register preserved across calls */
+#define GEN_REG_SAVE_MASK MASK(1,16)|MASK(24,28)|(1<<(MIPS_NUMREGS-1))
+#define FLOAT_REG_SAVE_MASK MASK(0,19)
+#define FLOAT_SINGLE_REG_SAVE_MASK \
+  ((1<<18)|(1<<16)|(1<<14)|(1<<12)|(1<<10)|(1<<8)|(1<<6)|(1<<4)|(1<<2)|(1<<0))
+  /*
+   * The registers we must save are all those not preserved across
+   * procedure calls. Dest_Reg (see tm-mips.h) must also be saved.
+   * In addition, we must save the PC, PUSH_FP_REGNUM, MMLO/-HI
+   * and FP Control/Status registers.
+   *
+   *
+   * Dummy frame layout:
+   *  (high memory)
+   *    Saved PC
+   *    Saved MMHI, MMLO, FPC_CSR
+   *    Saved R31
+   *    Saved R28
+   *    ...
+   *    Saved R1
+   *    Saved D18 (i.e. F19, F18)
+   *    ...
+   *    Saved D0 (i.e. F1, F0)
+   *    Argument build area and stack arguments written via mips_push_arguments
+   *  (low memory)
+   */
+
+  /* Save special registers (PC, MMHI, MMLO, FPC_CSR) */
+  PROC_FRAME_REG (proc_desc) = PUSH_FP_REGNUM;
+  PROC_FRAME_OFFSET (proc_desc) = 0;
+  PROC_FRAME_ADJUST (proc_desc) = 0;
+  mips_push_register (&sp, PC_REGNUM);
+  mips_push_register (&sp, HI_REGNUM);
+  mips_push_register (&sp, LO_REGNUM);
+  mips_push_register (&sp, MIPS_FPU_TYPE == MIPS_FPU_NONE ? 0 : FCRCS_REGNUM);
+
+  /* Save general CPU registers */
+  PROC_REG_MASK (proc_desc) = GEN_REG_SAVE_MASK;
+  /* PROC_REG_OFFSET is the offset of the first saved register from FP.  */
+  PROC_REG_OFFSET (proc_desc) = sp - old_sp - MIPS_SAVED_REGSIZE;
+  for (ireg = 32; --ireg >= 0;)
+    if (PROC_REG_MASK (proc_desc) & (1 << ireg))
+      mips_push_register (&sp, ireg);
+
+  /* Save floating point registers starting with high order word */
+  PROC_FREG_MASK (proc_desc) =
+    MIPS_FPU_TYPE == MIPS_FPU_DOUBLE ? FLOAT_REG_SAVE_MASK
+    : MIPS_FPU_TYPE == MIPS_FPU_SINGLE ? FLOAT_SINGLE_REG_SAVE_MASK : 0;
+  /* PROC_FREG_OFFSET is the offset of the first saved *double* register
+     from FP.  */
+  PROC_FREG_OFFSET (proc_desc) = sp - old_sp - 8;
+  for (ireg = 32; --ireg >= 0;)
+    if (PROC_FREG_MASK (proc_desc) & (1 << ireg))
+      mips_push_register (&sp, ireg + FP0_REGNUM);
+
+  /* Update the frame pointer for the call dummy and the stack pointer.
+     Set the procedure's starting and ending addresses to point to the
+     call dummy address at the entry point.  */
+  write_register (PUSH_FP_REGNUM, old_sp);
+  write_register (SP_REGNUM, sp);
+  PROC_LOW_ADDR (proc_desc) = CALL_DUMMY_ADDRESS ();
+  PROC_HIGH_ADDR (proc_desc) = CALL_DUMMY_ADDRESS () + 4;
+  SET_PROC_DESC_IS_DUMMY (proc_desc);
+  PROC_PC_REG (proc_desc) = RA_REGNUM;
+}
+
+void
+mips_pop_frame (void)
+{
   register int regnum;
   struct frame_info *frame = get_current_frame ();
   CORE_ADDR new_sp = FRAME_FP (frame);
@@ -3508,7 +4112,7 @@ do_gp_register_row (int regnum)
 
 /* MIPS_DO_REGISTERS_INFO(): called by "info register" command */
 
-void
+static void
 mips_do_registers_info (int regnum, int fpregs)
 {
   if (regnum != -1)            /* do one specified register */
@@ -3918,10 +4522,48 @@ return_value_location (struct type *valtype,
 /* Given a return value in `regbuf' with a type `valtype', extract and
    copy its value into `valbuf'. */
 
-void
-mips_extract_return_value (struct type *valtype,
-                          char regbuf[REGISTER_BYTES],
-                          char *valbuf)
+static void
+mips_eabi_extract_return_value (struct type *valtype,
+                               char regbuf[REGISTER_BYTES],
+                               char *valbuf)
+{
+  struct return_value_word lo;
+  struct return_value_word hi;
+  return_value_location (valtype, &hi, &lo);
+
+  memcpy (valbuf + lo.buf_offset,
+         regbuf + REGISTER_BYTE (lo.reg) + lo.reg_offset,
+         lo.len);
+
+  if (hi.len > 0)
+    memcpy (valbuf + hi.buf_offset,
+           regbuf + REGISTER_BYTE (hi.reg) + hi.reg_offset,
+           hi.len);
+}
+
+static void
+mips_o32_extract_return_value (struct type *valtype,
+                               char regbuf[REGISTER_BYTES],
+                               char *valbuf)
+{
+  struct return_value_word lo;
+  struct return_value_word hi;
+  return_value_location (valtype, &hi, &lo);
+
+  memcpy (valbuf + lo.buf_offset,
+         regbuf + REGISTER_BYTE (lo.reg) + lo.reg_offset,
+         lo.len);
+
+  if (hi.len > 0)
+    memcpy (valbuf + hi.buf_offset,
+           regbuf + REGISTER_BYTE (hi.reg) + hi.reg_offset,
+           hi.len);
+}
+
+static void
+mips_o64_extract_return_value (struct type *valtype,
+                              char regbuf[REGISTER_BYTES],
+                              char *valbuf)
 {
   struct return_value_word lo;
   struct return_value_word hi;
@@ -3940,8 +4582,56 @@ mips_extract_return_value (struct type *valtype,
 /* Given a return value in `valbuf' with a type `valtype', write it's
    value into the appropriate register. */
 
-void
-mips_store_return_value (struct type *valtype, char *valbuf)
+static void
+mips_eabi_store_return_value (struct type *valtype, char *valbuf)
+{
+  char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+  struct return_value_word lo;
+  struct return_value_word hi;
+  return_value_location (valtype, &hi, &lo);
+
+  memset (raw_buffer, 0, sizeof (raw_buffer));
+  memcpy (raw_buffer + lo.reg_offset, valbuf + lo.buf_offset, lo.len);
+  write_register_bytes (REGISTER_BYTE (lo.reg),
+                       raw_buffer,
+                       REGISTER_RAW_SIZE (lo.reg));
+
+  if (hi.len > 0)
+    {
+      memset (raw_buffer, 0, sizeof (raw_buffer));
+      memcpy (raw_buffer + hi.reg_offset, valbuf + hi.buf_offset, hi.len);
+      write_register_bytes (REGISTER_BYTE (hi.reg),
+                           raw_buffer,
+                           REGISTER_RAW_SIZE (hi.reg));
+    }
+}
+
+static void
+mips_o32_store_return_value (struct type *valtype, char *valbuf)
+{
+  char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+  struct return_value_word lo;
+  struct return_value_word hi;
+  return_value_location (valtype, &hi, &lo);
+
+  memset (raw_buffer, 0, sizeof (raw_buffer));
+  memcpy (raw_buffer + lo.reg_offset, valbuf + lo.buf_offset, lo.len);
+  write_register_bytes (REGISTER_BYTE (lo.reg),
+                       raw_buffer,
+                       REGISTER_RAW_SIZE (lo.reg));
+
+  if (hi.len > 0)
+    {
+      memset (raw_buffer, 0, sizeof (raw_buffer));
+      memcpy (raw_buffer + hi.reg_offset, valbuf + hi.buf_offset, hi.len);
+      write_register_bytes (REGISTER_BYTE (hi.reg),
+                           raw_buffer,
+                           REGISTER_RAW_SIZE (hi.reg));
+    }
+}
+
+static void
+mips_o64_store_return_value (struct type *valtype, char *valbuf)
 {
   char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
   struct return_value_word lo;
@@ -3964,10 +4654,116 @@ mips_store_return_value (struct type *valtype, char *valbuf)
     }
 }
 
+static void
+mips_n32n64_xfer_return_value (struct type *type,
+                              struct regcache *regcache,
+                              bfd_byte *in, const bfd_byte *out)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  if (TYPE_CODE (type) == TYPE_CODE_FLT
+      && tdep->mips_fpu_type != MIPS_FPU_NONE)
+    {
+      /* A floating-point value belongs in the least significant part
+         of FP0.  */
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+      mips_xfer_register (regcache, FP0_REGNUM, TYPE_LENGTH (type),
+                         TARGET_BYTE_ORDER, in, out, 0);
+    }
+  else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+          && TYPE_NFIELDS (type) <= 2
+          && TYPE_NFIELDS (type) >= 1
+          && ((TYPE_NFIELDS (type) == 1
+               && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+                   == TYPE_CODE_FLT))
+              || (TYPE_NFIELDS (type) == 2
+                  && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+                      == TYPE_CODE_FLT)
+                  && (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
+                      == TYPE_CODE_FLT)))
+          && tdep->mips_fpu_type != MIPS_FPU_NONE)
+    {
+      /* A struct that contains one or two floats.  Each value is part
+         in the least significant part of their floating point
+         register..  */
+      bfd_byte *reg = alloca (MAX_REGISTER_RAW_SIZE);
+      int regnum;
+      int field;
+      for (field = 0, regnum = FP0_REGNUM;
+          field < TYPE_NFIELDS (type);
+          field++, regnum += 2)
+       {
+         int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
+                       / TARGET_CHAR_BIT);
+         if (mips_debug)
+           fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n", offset);
+         mips_xfer_register (regcache, regnum, TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
+                             TARGET_BYTE_ORDER, in, out, offset);
+       }
+    }
+  else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+          || TYPE_CODE (type) == TYPE_CODE_UNION)
+    {
+      /* A structure or union.  Extract the left justified value,
+         regardless of the byte order.  I.e. DO NOT USE
+         mips_xfer_lower.  */
+      int offset;
+      int regnum;
+      for (offset = 0, regnum = V0_REGNUM;
+          offset < TYPE_LENGTH (type);
+          offset += REGISTER_RAW_SIZE (regnum), regnum++)
+       {
+         int xfer = REGISTER_RAW_SIZE (regnum);
+         if (offset + xfer > TYPE_LENGTH (type))
+           xfer = TYPE_LENGTH (type) - offset;
+         if (mips_debug)
+           fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
+                               offset, xfer, regnum);
+         mips_xfer_register (regcache, regnum, xfer, BFD_ENDIAN_UNKNOWN,
+                             in, out, offset);
+       }
+    }
+  else
+    {
+      /* A scalar extract each part but least-significant-byte
+         justified.  */
+      int offset;
+      int regnum;
+      for (offset = 0, regnum = V0_REGNUM;
+          offset < TYPE_LENGTH (type);
+          offset += REGISTER_RAW_SIZE (regnum), regnum++)
+       {
+         int xfer = REGISTER_RAW_SIZE (regnum);
+         int pos = 0;
+         if (offset + xfer > TYPE_LENGTH (type))
+           xfer = TYPE_LENGTH (type) - offset;
+         if (mips_debug)
+           fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
+                               offset, xfer, regnum);
+         mips_xfer_register (regcache, regnum, xfer, TARGET_BYTE_ORDER,
+                             in, out, offset);
+       }
+    }
+}
+
+static void
+mips_n32n64_extract_return_value (struct type *type,
+                                 struct regcache *regcache,
+                                 char *valbuf)
+{
+  mips_n32n64_xfer_return_value (type, regcache, valbuf, NULL);
+}
+
+static void
+mips_n32n64_store_return_value (struct type *type, char *valbuf)
+{
+  mips_n32n64_xfer_return_value (type, current_regcache, NULL, valbuf);
+}
+
 /* Exported procedure: Is PC in the signal trampoline code */
 
-int
-in_sigtramp (CORE_ADDR pc, char *ignore)
+static int
+mips_pc_in_sigtramp (CORE_ADDR pc, char *ignore)
 {
   if (sigtramp_address == 0)
     fixup_sigtramp ();
@@ -4653,7 +5449,7 @@ mips_gdbarch_init (struct gdbarch_info info,
       osabi = gdbarch_lookup_osabi (info.abfd);
     }
 
-  /* Check ELF_FLAGS to see if it specifies the ABI being used. */
+  /* Check ELF_FLAGS to see if it specifies the ABI being used.  */
   switch ((elf_flags & EF_MIPS_ABI))
     {
     case E_MIPS_ABI_O32:
@@ -4747,7 +5543,7 @@ mips_gdbarch_init (struct gdbarch_info info,
        arches = gdbarch_list_lookup_by_info (arches->next, &info))
     {
       /* MIPS needs to be pedantic about which ABI the object is
-         using. */
+         using.  */
       if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
        continue;
       if (gdbarch_tdep (arches->gdbarch)->mips_abi != mips_abi)
@@ -4756,32 +5552,35 @@ mips_gdbarch_init (struct gdbarch_info info,
         return arches->gdbarch;
     }
 
-  /* Need a new architecture. Fill in a target specific vector. */
+  /* Need a new architecture.  Fill in a target specific vector.  */
   tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
   tdep->elf_flags = elf_flags;
   tdep->osabi = osabi;
 
-  /* Initially set everything according to the default ABI/ISA. */
+  /* Initially set everything according to the default ABI/ISA.  */
   set_gdbarch_short_bit (gdbarch, 16);
   set_gdbarch_int_bit (gdbarch, 32);
   set_gdbarch_float_bit (gdbarch, 32);
   set_gdbarch_double_bit (gdbarch, 64);
   set_gdbarch_long_double_bit (gdbarch, 64);
   set_gdbarch_register_raw_size (gdbarch, mips_register_raw_size);
+  set_gdbarch_max_register_raw_size (gdbarch, 8);
+  set_gdbarch_max_register_virtual_size (gdbarch, 8);
   tdep->found_abi = found_abi;
   tdep->mips_abi = mips_abi;
 
   switch (mips_abi)
     {
     case MIPS_ABI_O32:
-      set_gdbarch_push_arguments (gdbarch, mips_push_arguments);
+      set_gdbarch_push_arguments (gdbarch, mips_o32_push_arguments);
+      set_gdbarch_store_return_value (gdbarch, mips_o32_store_return_value);
+      set_gdbarch_deprecated_extract_return_value (gdbarch, mips_o32_extract_return_value);
       tdep->mips_default_saved_regsize = 4;
       tdep->mips_default_stack_argsize = 4;
       tdep->mips_fp_register_double = 0;
       tdep->mips_last_arg_regnum = A0_REGNUM + 4 - 1;
       tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 4 - 1;
-      tdep->mips_regs_have_home_p = 1;
       tdep->gdb_target_is_mips64 = 0;
       tdep->default_mask_address_p = 0;
       set_gdbarch_long_bit (gdbarch, 32);
@@ -4793,13 +5592,14 @@ 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);
+      set_gdbarch_push_arguments (gdbarch, mips_o64_push_arguments);
+      set_gdbarch_store_return_value (gdbarch, mips_o64_store_return_value);
+      set_gdbarch_deprecated_extract_return_value (gdbarch, mips_o64_extract_return_value);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
       tdep->mips_last_arg_regnum = A0_REGNUM + 4 - 1;
       tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 4 - 1;
-      tdep->mips_regs_have_home_p = 1;
       tdep->gdb_target_is_mips64 = 1;
       tdep->default_mask_address_p = 0;
       set_gdbarch_long_bit (gdbarch, 32);
@@ -4811,13 +5611,14 @@ 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);
+      set_gdbarch_push_arguments (gdbarch, mips_eabi_push_arguments);
+      set_gdbarch_store_return_value (gdbarch, mips_eabi_store_return_value);
+      set_gdbarch_deprecated_extract_return_value (gdbarch, mips_eabi_extract_return_value);
       tdep->mips_default_saved_regsize = 4;
       tdep->mips_default_stack_argsize = 4;
       tdep->mips_fp_register_double = 0;
       tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
       tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
-      tdep->mips_regs_have_home_p = 0;
       tdep->gdb_target_is_mips64 = 0;
       tdep->default_mask_address_p = 0;
       set_gdbarch_long_bit (gdbarch, 32);
@@ -4829,13 +5630,14 @@ 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);
+      set_gdbarch_push_arguments (gdbarch, mips_eabi_push_arguments);
+      set_gdbarch_store_return_value (gdbarch, mips_eabi_store_return_value);
+      set_gdbarch_deprecated_extract_return_value (gdbarch, mips_eabi_extract_return_value);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
       tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
       tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
-      tdep->mips_regs_have_home_p = 0;
       tdep->gdb_target_is_mips64 = 1;
       tdep->default_mask_address_p = 0;
       set_gdbarch_long_bit (gdbarch, 64);
@@ -4848,12 +5650,13 @@ mips_gdbarch_init (struct gdbarch_info info,
       break;
     case MIPS_ABI_N32:
       set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+      set_gdbarch_store_return_value (gdbarch, mips_n32n64_store_return_value);
+      set_gdbarch_extract_return_value (gdbarch, mips_n32n64_extract_return_value);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
       tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
       tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
-      tdep->mips_regs_have_home_p = 0;
       tdep->gdb_target_is_mips64 = 1;
       tdep->default_mask_address_p = 0;
       set_gdbarch_long_bit (gdbarch, 32);
@@ -4878,12 +5681,13 @@ mips_gdbarch_init (struct gdbarch_info info,
       break;
     case MIPS_ABI_N64:
       set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+      set_gdbarch_store_return_value (gdbarch, mips_n32n64_store_return_value);
+      set_gdbarch_extract_return_value (gdbarch, mips_n32n64_extract_return_value);
       tdep->mips_default_saved_regsize = 8;
       tdep->mips_default_stack_argsize = 8;
       tdep->mips_fp_register_double = 1;
       tdep->mips_last_arg_regnum = A0_REGNUM + 8 - 1;
       tdep->mips_last_fp_arg_regnum = FPA0_REGNUM + 8 - 1;
-      tdep->mips_regs_have_home_p = 0;
       tdep->gdb_target_is_mips64 = 1;
       tdep->default_mask_address_p = 0;
       set_gdbarch_long_bit (gdbarch, 64);
@@ -4917,7 +5721,7 @@ mips_gdbarch_init (struct gdbarch_info info,
 
      ``We deliberately don't allow "-gp32" to set the MIPS_32BITMODE
      flag in object files because to do so would make it impossible to
-     link with libraries compiled without "-gp32". This is
+     link with libraries compiled without "-gp32".  This is
      unnecessarily restrictive.
 
      We could solve this problem by adding "-gp32" multilibs to gcc,
@@ -4927,10 +5731,10 @@ mips_gdbarch_init (struct gdbarch_info info,
      But even more unhelpfully, the default linker output target for
      mips64-elf is elf32-bigmips, and has EF_MIPS_32BIT_MODE set, even
      for 64-bit programs - you need to change the ABI to change this,
-     and not all gcc targets support that currently. Therefore using
+     and not all gcc targets support that currently.  Therefore using
      this flag to detect 32-bit mode would do the wrong thing given
      the current gcc - it would make GDB treat these 64-bit programs
-     as 32-bit programs by default. */
+     as 32-bit programs by default.  */
 
   /* enable/disable the MIPS FPU */
   if (!mips_fpu_type_auto)
@@ -4957,16 +5761,16 @@ mips_gdbarch_init (struct gdbarch_info info,
   /* MIPS version of register names.  NOTE: At present the MIPS
      register name management is part way between the old -
      #undef/#define REGISTER_NAMES and the new REGISTER_NAME(nr).
-     Further work on it is required. */
+     Further work on it is required.  */
   set_gdbarch_register_name (gdbarch, mips_register_name);
   set_gdbarch_read_pc (gdbarch, mips_read_pc);
   set_gdbarch_write_pc (gdbarch, generic_target_write_pc);
   set_gdbarch_read_fp (gdbarch, generic_target_read_fp);
-  set_gdbarch_read_sp (gdbarch, generic_target_read_sp);
+  set_gdbarch_read_sp (gdbarch, mips_read_sp);
   set_gdbarch_write_sp (gdbarch, generic_target_write_sp);
 
-  /* Add/remove bits from an address. The MIPS needs be careful to
-     ensure that all 32 bit addresses are sign extended to 64 bits. */
+  /* Add/remove bits from an address.  The MIPS needs be careful to
+     ensure that all 32 bit addresses are sign extended to 64 bits.  */
   set_gdbarch_addr_bits_remove (gdbarch, mips_addr_bits_remove);
 
   /* There's a mess in stack frame creation.  See comments in
@@ -4974,7 +5778,7 @@ mips_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_init_frame_pc_first (gdbarch, mips_init_frame_pc_first);
   set_gdbarch_init_frame_pc (gdbarch, init_frame_pc_noop);
 
-  /* Map debug register numbers onto internal register numbers. */
+  /* Map debug register numbers onto internal register numbers.  */
   set_gdbarch_stab_reg_to_regnum (gdbarch, mips_stab_reg_to_regnum);
   set_gdbarch_ecoff_reg_to_regnum (gdbarch, mips_ecoff_reg_to_regnum);
 
@@ -4997,7 +5801,12 @@ 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_register_convertible (gdbarch, generic_register_convertible_not);
+  set_gdbarch_register_convertible (gdbarch, mips_register_convertible);
+  set_gdbarch_register_convert_to_virtual (gdbarch, 
+                                          mips_register_convert_to_virtual);
+  set_gdbarch_register_convert_to_raw (gdbarch, 
+                                      mips_register_convert_to_raw);
+
   set_gdbarch_coerce_float_to_double (gdbarch, mips_coerce_float_to_double);
 
   set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
@@ -5014,9 +5823,15 @@ mips_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer);
   set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address);
 
+  set_gdbarch_function_start_offset (gdbarch, 0);
+
   /* There are MIPS targets which do not yet use this since they still
      define REGISTER_VIRTUAL_TYPE.  */
   set_gdbarch_register_virtual_type (gdbarch, mips_register_virtual_type);
+  set_gdbarch_register_virtual_size (gdbarch, generic_register_size);
+
+  set_gdbarch_do_registers_info (gdbarch, mips_do_registers_info);
+  set_gdbarch_pc_in_sigtramp (gdbarch, mips_pc_in_sigtramp);
 
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch, osabi);
@@ -5113,9 +5928,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: FP_REGISTER_DOUBLE = %d\n",
                      FP_REGISTER_DOUBLE);
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: MIPS_REGS_HAVE_HOME_P = %d\n",
-                     MIPS_REGS_HAVE_HOME_P);
   fprintf_unfiltered (file,
                      "mips_dump_tdep: MIPS_DEFAULT_STACK_ARGSIZE = %d\n",
                      MIPS_DEFAULT_STACK_ARGSIZE);
This page took 0.0435 seconds and 4 git commands to generate.