2002-09-18 Andrew Cagney <ac131313@redhat.com>
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 6d32f4e519d6e3da5e0e6d7b2e70242123fd3db6..f54f19c2ad702be0bbd7679550925b9476ff1698 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,97 @@ mips_saved_regsize (void)
     return 4;
 }
 
+/* Functions for setting and testing a bit in a minimal symbol that
+   marks it as 16-bit function.  The MSB of the minimal symbol's
+   "info" field is used for this purpose. This field is already
+   being used to store the symbol size, so the assumption is
+   that the symbol size cannot exceed 2^31.
+
+   ELF_MAKE_MSYMBOL_SPECIAL tests whether an ELF symbol is "special",
+   i.e. refers to a 16-bit function, and sets a "special" bit in a
+   minimal symbol to mark it as a 16-bit function
+
+   MSYMBOL_IS_SPECIAL   tests the "special" bit in a minimal symbol
+   MSYMBOL_SIZE         returns the size of the minimal symbol, i.e.
+   the "info" field with the "special" bit masked out */
+
+static void
+mips_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
+{
+  if (((elf_symbol_type *)(sym))->internal_elf_sym.st_other == STO_MIPS16) 
+    { 
+      MSYMBOL_INFO (msym) = (char *) 
+       (((long) MSYMBOL_INFO (msym)) | 0x80000000); 
+      SYMBOL_VALUE_ADDRESS (msym) |= 1; 
+    } 
+}
+
+static int
+msymbol_is_special (struct minimal_symbol *msym)
+{
+  return (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0);
+}
+
+static long
+msymbol_size (struct minimal_symbol *msym)
+{
+  return ((long) MSYMBOL_INFO (msym) & 0x7fffffff);
+}
+
+/* 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;
+  /* Need to transfer the left or right part of the register, based on
+     the targets byte order.  */
+  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, reg offset %d, buf offset %d, length %d, ",
+                       reg_num, reg_offset, buf_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[buf_offset + 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[buf_offset + 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 +296,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. */
@@ -249,7 +334,7 @@ static CORE_ADDR heuristic_proc_start (CORE_ADDR);
 
 static CORE_ADDR read_next_frame_reg (struct frame_info *, int);
 
-int mips_set_processor_type (char *);
+static int mips_set_processor_type (char *);
 
 static void mips_show_processor_type_command (char *, int);
 
@@ -285,7 +370,7 @@ static struct cmd_list_element *showmipscmdlist = NULL;
 char *mips_generic_reg_names[] = MIPS_REGISTER_NAMES;
 char **mips_processor_reg_names = mips_generic_reg_names;
 
-const char *
+static const char *
 mips_register_name (int i)
 {
   return mips_processor_reg_names[i];
@@ -303,7 +388,7 @@ char *mips_r3041_reg_names[] = {
        "f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15",
        "f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",
        "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31",
-       "fsr",  "fir",  "fp",   "",
+       "fsr",  "fir",  "",/*"fp"*/     "",
        "",     "",     "bus",  "ccfg", "",     "",     "",     "",
        "",     "",     "port", "cmp",  "",     "",     "epc",  "prid",
 };
@@ -320,7 +405,7 @@ char *mips_r3051_reg_names[] = {
        "f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15",
        "f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",
        "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31",
-       "fsr",  "fir",  "fp",   "",
+       "fsr",  "fir",  ""/*"fp"*/,     "",
        "inx",  "rand", "elo",  "",     "ctxt", "",     "",     "",
        "",     "",     "ehi",  "",     "",     "",     "epc",  "prid",
 };
@@ -337,7 +422,7 @@ char *mips_r3081_reg_names[] = {
        "f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15",
        "f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23",
        "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31",
-       "fsr",  "fir",  "fp",   "",
+       "fsr",  "fir",  ""/*"fp"*/,     "",
        "inx",  "rand", "elo",  "cfg",  "ctxt", "",     "",     "",
        "",     "",     "ehi",  "",     "",     "",     "epc",  "prid",
 };
@@ -428,7 +513,7 @@ mips_print_extra_frame_info (struct frame_info *fi)
 
 static int mips64_transfers_32bit_regs_p = 0;
 
-int
+static int
 mips_register_raw_size (int reg_nr)
 {
   if (mips64_transfers_32bit_regs_p)
@@ -445,7 +530,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 +539,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 +553,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 +568,82 @@ 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.  
+   
+   Note: kevinb/2002-08-01: The definition below should faithfully
+   reproduce the behavior of each of the REGISTER_VIRTUAL_TYPE
+   definitions found in config/mips/tm-*.h.  I'm concerned about
+   the ``FCRCS_REGNUM <= reg && reg <= LAST_EMBED_REGNUM'' clause
+   though.  In some cases FP_REGNUM is in this range, and I doubt
+   that this code is correct for the 64-bit case.  */
+
+static struct type *
+mips_register_virtual_type (int reg)
+{
+  if (FP0_REGNUM <= reg && reg < FP0_REGNUM + 32)
+    {
+      /* Floating point registers...  */
+      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+       return builtin_type_ieee_double_big;
+      else
+       return builtin_type_ieee_double_little;
+    }
+  else if (reg == PS_REGNUM /* CR */)
+    return builtin_type_uint32;
+  else if (FCRCS_REGNUM <= reg && reg <= LAST_EMBED_REGNUM)
+    return builtin_type_uint32;
+  else
+    {
+      /* Everything else...
+         Return type appropriate for width of register.  */
+      if (MIPS_REGSIZE == TYPE_LENGTH (builtin_type_uint64))
+       return builtin_type_uint64;
+      else
+       return builtin_type_uint32;
+    }
+}
+
+/* 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;
 
@@ -528,13 +689,51 @@ show_mask_address (char *cmd, int from_tty, struct cmd_list_element *c)
 }
 
 /* Should call_function allocate stack space for a struct return?  */
-int
-mips_use_struct_convention (int gcc_p, struct type *type)
+
+static int
+mips_eabi_use_struct_convention (int gcc_p, struct type *type)
 {
-  if (MIPS_EABI)
-    return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
-  else
-    return 1;                  /* Structures are returned by ref in extra arg0 */
+  return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
+}
+
+static int
+mips_n32n64_use_struct_convention (int gcc_p, struct type *type)
+{
+  return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
+}
+
+static int
+mips_o32_use_struct_convention (int gcc_p, struct type *type)
+{
+  return 1;    /* Structures are returned by ref in extra arg0.  */
+}
+
+/* Should call_function pass struct by reference? 
+   For each architecture, structs are passed either by
+   value or by reference, depending on their size.  */
+
+static int
+mips_eabi_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+  enum type_code typecode = TYPE_CODE (check_typedef (type));
+  int len = TYPE_LENGTH (check_typedef (type));
+
+  if (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)
+    return (len > MIPS_SAVED_REGSIZE);
+
+  return 0;
+}
+
+static int
+mips_n32n64_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+  return 0;    /* Assumption: N32/N64 never passes struct by ref.  */
+}
+
+static int
+mips_o32_reg_struct_has_addr (int gcc_p, struct type *type)
+{
+  return 0;    /* Assumption: O32/O64 never passes struct by ref.  */
 }
 
 /* Tell if the program counter value in MEMADDR is in a MIPS16 function.  */
@@ -553,7 +752,7 @@ pc_is_mips16 (bfd_vma memaddr)
      MIPS16 or normal MIPS.  */
   sym = lookup_minimal_symbol_by_pc (memaddr);
   if (sym)
-    return MSYMBOL_IS_SPECIAL (sym);
+    return msymbol_is_special (sym);
   else
     return 0;
 }
@@ -721,7 +920,7 @@ mips32_relative_offset (unsigned long inst)
 
 /* Determine whate to set a single step breakpoint while considering
    branch prediction */
-CORE_ADDR
+static CORE_ADDR
 mips32_next_pc (CORE_ADDR pc)
 {
   unsigned long inst;
@@ -1037,7 +1236,6 @@ static CORE_ADDR
 add_offset_16 (CORE_ADDR pc, int offset)
 {
   return ((offset << 2) | ((pc + 2) & (0xf0000000)));
-
 }
 
 static CORE_ADDR
@@ -1161,7 +1359,7 @@ extended_mips16_next_pc (CORE_ADDR pc,
   return pc;
 }
 
-CORE_ADDR
+static CORE_ADDR
 mips16_next_pc (CORE_ADDR pc)
 {
   unsigned int insn = fetch_mips_16 (pc);
@@ -1183,9 +1381,17 @@ mips_next_pc (CORE_ADDR pc)
 }
 
 /* Guaranteed to set fci->saved_regs to some values (it never leaves it
-   NULL).  */
+   NULL).
 
-void
+   Note: kevinb/2002-08-09: The only caller of this function is (and
+   should remain) mips_frame_init_saved_regs().  In fact,
+   aside from calling mips_find_saved_regs(), mips_frame_init_saved_regs()
+   does nothing more than set frame->saved_regs[SP_REGNUM].  These two
+   functions should really be combined and now that there is only one
+   caller, it should be straightforward.  (Watch out for multiple returns
+   though.)  */
+
+static void
 mips_find_saved_regs (struct frame_info *fci)
 {
   int ireg;
@@ -1335,9 +1541,20 @@ mips_find_saved_regs (struct frame_info *fci)
      were saved.  */
   reg_position = fci->frame + PROC_FREG_OFFSET (proc_desc);
 
-  /* The freg_offset points to where the first *double* register
-     is saved.  So skip to the high-order word. */
-  if (!GDB_TARGET_IS_MIPS64)
+  /* Apparently, the freg_offset gives the offset to the first 64 bit
+     saved.
+
+     When the ABI specifies 64 bit saved registers, the FREG_OFFSET
+     designates the first saved 64 bit register.
+
+     When the ABI specifies 32 bit saved registers, the ``64 bit saved
+     DOUBLE'' consists of two adjacent 32 bit registers, Hence
+     FREG_OFFSET, designates the address of the lower register of the
+     register pair.  Adjust the offset so that it designates the upper
+     register of the pair -- i.e., the address of the first saved 32
+     bit register.  */
+
+  if (MIPS_SAVED_REGSIZE == 4)
     reg_position += MIPS_SAVED_REGSIZE;
 
   /* Fill in the offsets for the float registers which float_mask says
@@ -1352,24 +1569,49 @@ mips_find_saved_regs (struct frame_info *fci)
   fci->saved_regs[PC_REGNUM] = fci->saved_regs[RA_REGNUM];
 }
 
+/* Set up the 'saved_regs' array.  This is a data structure containing
+   the addresses on the stack where each register has been saved, for
+   each stack frame.  Registers that have not been saved will have
+   zero here.  The stack pointer register is special:  rather than the
+   address where the stack register has been saved, saved_regs[SP_REGNUM]
+   will have the actual value of the previous frame's stack register.  */
+
+static void
+mips_frame_init_saved_regs (struct frame_info *frame)
+{
+  if (frame->saved_regs == NULL)
+    {
+      mips_find_saved_regs (frame);
+    }
+  frame->saved_regs[SP_REGNUM] = frame->frame;
+}
+
 static CORE_ADDR
 read_next_frame_reg (struct frame_info *fi, int regno)
 {
-  for (; fi; fi = fi->next)
+  int optimized;
+  CORE_ADDR addr;
+  int realnum;
+  enum lval_type lval;
+  void *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+  frame_register_unwind (fi, regno, &optimized, &lval, &addr, &realnum,
+                        raw_buffer);
+  /* FIXME: cagney/2002-09-13: This is just soooo bad.  The MIPS
+     should have a pseudo register range that correspons to the ABI's,
+     rather than the ISA's, view of registers.  These registers would
+     then implicitly describe their size and hence could be used
+     without the below munging.  */
+  if (lval == lval_memory)
     {
-      /* We have to get the saved sp from the sigcontext
-         if it is a signal handler frame.  */
-      if (regno == SP_REGNUM && !fi->signal_handler_caller)
-       return fi->frame;
-      else
+      if (regno < 32)
        {
-         if (fi->saved_regs == NULL)
-           mips_find_saved_regs (fi);
-         if (fi->saved_regs[regno])
-           return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), MIPS_SAVED_REGSIZE);
+         /* Only MIPS_SAVED_REGSIZE bytes of GP registers are
+            saved. */
+         return read_memory_integer (addr, MIPS_SAVED_REGSIZE);
        }
     }
-  return read_signed_register (regno);
+
+  return extract_signed_integer (raw_buffer, REGISTER_VIRTUAL_SIZE (regno));
 }
 
 /* mips_addr_bits_remove - remove useless address bits  */
@@ -1447,12 +1689,12 @@ mips_init_frame_pc_first (int fromleaf, struct frame_info *prev)
 
   pc = ((fromleaf) ? SAVED_PC_AFTER_CALL (prev->next) :
        prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
-  tmp = mips_skip_stub (pc);
+  tmp = SKIP_TRAMPOLINE_CODE (pc);
   prev->pc = tmp ? tmp : pc;
 }
 
 
-CORE_ADDR
+static CORE_ADDR
 mips_frame_saved_pc (struct frame_info *frame)
 {
   CORE_ADDR saved_pc;
@@ -2110,7 +2352,7 @@ find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
        {
          struct symtab_and_line val;
          struct symbol *proc_symbol =
-         PROC_DESC_IS_DUMMY (proc_desc) ? 0 : PROC_SYMBOL (proc_desc);
+           PROC_DESC_IS_DUMMY (proc_desc) ? 0 : PROC_SYMBOL (proc_desc);
 
          if (proc_symbol)
            {
@@ -2122,8 +2364,8 @@ find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
          if (!proc_symbol || pc < val.pc)
            {
              mips_extra_func_info_t found_heuristic =
-             heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
-                                  pc, next_frame, cur_frame);
+               heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
+                                    pc, next_frame, cur_frame);
              if (found_heuristic)
                proc_desc = found_heuristic;
            }
@@ -2156,14 +2398,15 @@ static CORE_ADDR
 get_frame_pointer (struct frame_info *frame,
                   mips_extra_func_info_t proc_desc)
 {
-  return ADDR_BITS_REMOVE (
-                  read_next_frame_reg (frame, PROC_FRAME_REG (proc_desc)) +
-            PROC_FRAME_OFFSET (proc_desc) - PROC_FRAME_ADJUST (proc_desc));
+  return ADDR_BITS_REMOVE (read_next_frame_reg (frame, 
+                                               PROC_FRAME_REG (proc_desc)) +
+                          PROC_FRAME_OFFSET (proc_desc) - 
+                          PROC_FRAME_ADJUST (proc_desc));
 }
 
-mips_extra_func_info_t cached_proc_desc;
+static mips_extra_func_info_t cached_proc_desc;
 
-CORE_ADDR
+static CORE_ADDR
 mips_frame_chain (struct frame_info *frame)
 {
   mips_extra_func_info_t proc_desc;
@@ -2175,7 +2418,7 @@ mips_frame_chain (struct frame_info *frame)
 
   /* Check if the PC is inside a call stub.  If it is, fetch the
      PC of the caller of that stub.  */
-  if ((tmp = mips_skip_stub (saved_pc)) != 0)
+  if ((tmp = SKIP_TRAMPOLINE_CODE (saved_pc)) != 0)
     saved_pc = tmp;
 
   /* Look up the procedure descriptor for this PC.  */
@@ -2190,22 +2433,24 @@ 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 != CALL_DUMMY_ADDRESS ())
     return 0;
   else
     return get_frame_pointer (frame, proc_desc);
 }
 
-void
+static void
 mips_init_extra_frame_info (int fromleaf, struct frame_info *fci)
 {
   int regnum;
 
   /* Use proc_desc calculated in frame_chain */
   mips_extra_func_info_t proc_desc =
-  fci->next ? cached_proc_desc : find_proc_desc (fci->pc, fci->next, 1);
+    fci->next ? cached_proc_desc : find_proc_desc (fci->pc, fci->next, 1);
 
   fci->extra_info = (struct frame_extra_info *)
     frame_obstack_alloc (sizeof (struct frame_extra_info));
@@ -2240,6 +2485,12 @@ mips_init_extra_frame_info (int fromleaf, struct frame_info *fci)
              memcpy (fci->saved_regs, temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
              fci->saved_regs[PC_REGNUM]
                = fci->saved_regs[RA_REGNUM];
+             /* Set value of previous frame's stack pointer.  Remember that
+                saved_regs[SP_REGNUM] is special in that it contains the
+                value of the stack pointer register.  The other saved_regs
+                values are addresses (in the inferior) at which a given
+                register's value may be found.  */
+             fci->saved_regs[SP_REGNUM] = fci->frame;
            }
        }
 
@@ -2295,7 +2546,7 @@ fp_register_arg_p (enum type_code typecode, struct type *arg_type)
               && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)
               && TYPE_NFIELDS (arg_type) == 1
               && TYPE_CODE (TYPE_FIELD_TYPE (arg_type, 0)) == TYPE_CODE_FLT))
-          && MIPS_FPU_TYPE != MIPS_FPU_NONE);
+         && MIPS_FPU_TYPE != MIPS_FPU_NONE);
 }
 
 /* On o32, argument passing in GPRs depends on the alignment of the type being
@@ -2324,15 +2575,803 @@ mips_type_needs_double_align (struct type *type)
          return 1;
       return 0;
     }
-  return 0;
+  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))
+
+/* Adjust the address downward (direction of stack growth) so that it
+   is correctly aligned for a new stack frame.  */
+static CORE_ADDR
+mips_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return ROUND_DOWN (addr, 16);
+}
+
+static CORE_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;
+
+  /* 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.  We allocate more
+     than necessary for EABI, because the first few arguments are
+     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);
+  sp -= ROUND_UP (len, 16);
+
+  if (mips_debug)
+    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.  */
+  if (struct_return)
+    {
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_eabi_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_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.  */
+      if (len > MIPS_SAVED_REGSIZE
+         && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
+       {
+         store_address (valbuf, MIPS_SAVED_REGSIZE, VALUE_ADDRESS (arg));
+         typecode = TYPE_CODE_PTR;
+         len = MIPS_SAVED_REGSIZE;
+         val = valbuf;
+         if (mips_debug)
+           fprintf_unfiltered (gdb_stdlog, " push");
+       }
+      else
+       val = (char *) VALUE_CONTENTS (arg);
+
+      /* 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.  */
+      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 non-EABI processors, 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.  */
+      /* MIPS_EABI squeezes a struct that contains a single floating
+         point value into an FP register instead of pushing it onto the
+         stack.  */
+      if (fp_register_arg_p (typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+       {
+         if (!FP_REGISTER_DOUBLE && len == 8)
+           {
+             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);
+
+             /* 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);
+           }
+         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);
+           }
+       }
+      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)
+           {
+             /* 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;
+                     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);
+
+                 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 the new EABI (and the NABI32), 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;
+}
+
+/* N32/N64 version of push_arguments.  */
+
+static 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;
+                   }
+
+                 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;
+}
+
+/* O32 version of push_arguments.  */
+
+static CORE_ADDR
+mips_o32_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_o32_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_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;
+    }
+
+  /* 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_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;
 }
 
-CORE_ADDR
-mips_push_arguments (int nargs,
-                    struct value **args,
-                    CORE_ADDR sp,
-                    int struct_return,
-                    CORE_ADDR struct_addr)
+/* 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;
@@ -2340,44 +3379,39 @@ mips_push_arguments (int nargs,
   int len = 0;
   int stack_offset = 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))
-
   /* 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);
 
-  /* 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. */
+  /* 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);
+    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%lx allocated %d\n",
-                       (long) sp, ROUND_UP (len, 16));
+    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 */
+  /* 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%lx\n",
-                           argreg, (long) struct_addr);
+                           "mips_o64_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;
+      stack_offset += MIPS_STACK_ARGSIZE;
     }
 
   /* Now load as many as possible of the first arguments into
@@ -2386,7 +3420,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);
@@ -2394,30 +3428,16 @@ mips_push_arguments (int nargs,
 
       if (mips_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "mips_push_arguments: %d len=%d type=%d",
+                           "mips_o64_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
-         && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
-       {
-         store_address (valbuf, MIPS_SAVED_REGSIZE, VALUE_ADDRESS (arg));
-         typecode = TYPE_CODE_PTR;
-         len = MIPS_SAVED_REGSIZE;
-         val = valbuf;
-         if (mips_debug)
-           fprintf_unfiltered (gdb_stdlog, " push");
-       }
-      else
-       val = (char *) VALUE_CONTENTS (arg);
+      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. Non MIPS_EABI targets also pass the FP in the integer
-         registers so also round up normal 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))
        {
@@ -2429,14 +3449,12 @@ mips_push_arguments (int nargs,
          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 non-EABI processors, the first two floating point arguments are
+         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.  */
-      /* MIPS_EABI squeezes a struct that contains a single floating
-         point value into an FP register instead of pushing it onto the
-         stack. */
+
       if (fp_register_arg_p (typecode, arg_type)
          && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
        {
@@ -2451,13 +3469,10 @@ 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);
-               }
+             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);
@@ -2465,42 +3480,35 @@ 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);
-               }
 
+             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;
-               }
+             /* 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);
+         /* Reserve space for the FP register.  */
+         stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
        }
       else
        {
@@ -2514,20 +3522,21 @@ mips_push_arguments (int nargs,
          int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
                                  (len % MIPS_SAVED_REGSIZE != 0));
          /* Structures should be aligned to eight bytes (even arg registers)
-            on MIPS_ABI_O32 if their first member has double precision. */
-         if (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_O32
+            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. */
+             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",
@@ -2550,18 +3559,14 @@ mips_push_arguments (int nargs,
                           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%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;
@@ -2569,10 +3574,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);
@@ -2580,13 +3587,15 @@ 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);
+                 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
@@ -2597,8 +3606,7 @@ mips_push_arguments (int nargs,
                     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.
+                    Also don't do this adjustment on O64 binaries.
 
                     cagney/2001-07-23: gdb/179: Also, GCC, when
                     outputting LE O32 with sizeof (struct) <
@@ -2613,8 +3621,7 @@ mips_push_arguments (int nargs,
                     left shift OR this new ABI gets identified as
                     such and GDB gets tweaked accordingly.  */
 
-                 if (!MIPS_EABI
-                     && MIPS_SAVED_REGSIZE < 8
+                 if (MIPS_SAVED_REGSIZE < 8
                      && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
                      && partial_len < MIPS_SAVED_REGSIZE
                      && (typecode == TYPE_CODE_STRUCT ||
@@ -2629,11 +3636,9 @@ mips_push_arguments (int nargs,
                  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;
+                 /* Prevent subsequent floating point arguments from
+                    being passed in floating point registers.  */
+                 float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
                }
 
              len -= partial_len;
@@ -2645,13 +3650,9 @@ mips_push_arguments (int nargs,
                 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.. */
+                always allocated.  */
 
-             if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
-               stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+             stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
            }
        }
       if (mips_debug)
@@ -2662,7 +3663,7 @@ mips_push_arguments (int nargs,
   return sp;
 }
 
-CORE_ADDR
+static CORE_ADDR
 mips_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
 {
   /* Set the return address register to point to the entry
@@ -2674,7 +3675,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))
@@ -2697,7 +3698,7 @@ mips_push_register (CORE_ADDR * sp, int regno)
 /* 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
+static void
 mips_push_dummy_frame (void)
 {
   int ireg;
@@ -2776,7 +3777,7 @@ mips_push_dummy_frame (void)
   PROC_PC_REG (proc_desc) = RA_REGNUM;
 }
 
-void
+static void
 mips_pop_frame (void)
 {
   register int regnum;
@@ -2787,15 +3788,24 @@ mips_pop_frame (void)
 
   write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
   if (frame->saved_regs == NULL)
-    mips_find_saved_regs (frame);
+    FRAME_INIT_SAVED_REGS (frame);
   for (regnum = 0; regnum < NUM_REGS; regnum++)
-    {
-      if (regnum != SP_REGNUM && regnum != PC_REGNUM
-         && frame->saved_regs[regnum])
-       write_register (regnum,
-                       read_memory_integer (frame->saved_regs[regnum],
-                                            MIPS_SAVED_REGSIZE));
-    }
+    if (regnum != SP_REGNUM && regnum != PC_REGNUM
+       && frame->saved_regs[regnum])
+      {
+       /* Floating point registers must not be sign extended, 
+          in case MIPS_SAVED_REGSIZE = 4 but sizeof (FP0_REGNUM) == 8.  */
+
+       if (FP0_REGNUM <= regnum && regnum < FP0_REGNUM + 32)
+         write_register (regnum,
+                         read_memory_unsigned_integer (frame->saved_regs[regnum],
+                                                       MIPS_SAVED_REGSIZE));
+       else
+         write_register (regnum,
+                         read_memory_integer (frame->saved_regs[regnum],
+                                              MIPS_SAVED_REGSIZE));
+      }
+
   write_register (SP_REGNUM, new_sp);
   flush_cached_frames ();
 
@@ -2834,6 +3844,13 @@ mips_pop_frame (void)
     }
 }
 
+static void
+mips_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, 
+                    struct value **args, struct type *type, int gcc_p)
+{
+  write_register(T9_REGNUM, fun);
+}
+
 /* Floating point register management.
 
    Background: MIPS1 & 2 fp registers are 32 bits wide.  To support
@@ -2953,7 +3970,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 = alloca (MAX_REGISTER_RAW_SIZE);
 
   /* Get the data in raw format.  */
   if (!frame_register_read (selected_frame, regnum, raw_buffer))
@@ -2970,7 +3987,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);
 
@@ -3105,7 +4122,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;
@@ -3163,7 +4180,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 */
@@ -3191,15 +4208,6 @@ mips_do_registers_info (int regnum, int fpregs)
     }
 }
 
-/* Return number of args passed to a frame. described by FIP.
-   Can return -1, meaning no way to tell.  */
-
-int
-mips_frame_num_args (struct frame_info *frame)
-{
-  return -1;
-}
-
 /* Is this a branch with a delay slot?  */
 
 static int is_delayed (unsigned long);
@@ -3438,7 +4446,7 @@ mips16_skip_prologue (CORE_ADDR pc)
    We must skip more in the case where part of the prologue is in the
    delay slot of a non-prologue instruction).  */
 
-CORE_ADDR
+static CORE_ADDR
 mips_skip_prologue (CORE_ADDR pc)
 {
   /* See if we can determine the end of the prologue via the symbol table.
@@ -3573,10 +4581,29 @@ 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_o64_extract_return_value (struct type *valtype,
+                              char regbuf[REGISTER_BYTES],
+                              char *valbuf)
 {
   struct return_value_word lo;
   struct return_value_word hi;
@@ -3595,10 +4622,10 @@ 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[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);
@@ -3619,10 +4646,301 @@ mips_store_return_value (struct type *valtype, char *valbuf)
     }
 }
 
+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;
+  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));
+    }
+}
+
+/* O32 ABI stuff.  */
+
+static void
+mips_o32_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
+      && TYPE_LENGTH (type) == 4
+      && tdep->mips_fpu_type != MIPS_FPU_NONE)
+    {
+      /* A single-precision floating-point value.  It fits 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_FLT
+          && TYPE_LENGTH (type) == 8
+          && tdep->mips_fpu_type != MIPS_FPU_NONE)
+    {
+      /* A double-precision floating-point value.  It fits in the
+         least significant part of FP0/FP1 but with byte ordering
+         based on the target (???).  */
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stderr, "Return float in $fp0/$fp1\n");
+      switch (TARGET_BYTE_ORDER)
+       {
+       case BFD_ENDIAN_LITTLE:
+         mips_xfer_register (regcache, FP0_REGNUM + 0, 4,
+                             TARGET_BYTE_ORDER, in, out, 0);
+         mips_xfer_register (regcache, FP0_REGNUM + 1, 4,
+                             TARGET_BYTE_ORDER, in, out, 4);
+         break;
+       case BFD_ENDIAN_BIG:
+         mips_xfer_register (regcache, FP0_REGNUM + 1, 4,
+                             TARGET_BYTE_ORDER, in, out, 0);
+         mips_xfer_register (regcache, FP0_REGNUM + 0, 4,
+                             TARGET_BYTE_ORDER, in, out, 4);
+         break;
+       default:
+         internal_error (__FILE__, __LINE__, "bad switch");
+       }
+    }
+#if 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);
+       }
+    }
+#endif
+#if 0
+  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);
+       }
+    }
+#endif
+  else
+    {
+      /* A scalar extract each part but least-significant-byte
+         justified.  o32 thinks registers are 4 byte, regardless of
+         the ISA.  mips_stack_argsize controls this.  */
+      int offset;
+      int regnum;
+      for (offset = 0, regnum = V0_REGNUM;
+          offset < TYPE_LENGTH (type);
+          offset += mips_stack_argsize (), regnum++)
+       {
+         int xfer = mips_stack_argsize ();
+         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_o32_extract_return_value (struct type *type,
+                              struct regcache *regcache,
+                              void *valbuf)
+{
+  mips_o32_xfer_return_value (type, regcache, valbuf, NULL); 
+}
+
+static void
+mips_o32_store_return_value (struct type *type, char *valbuf)
+{
+  mips_o32_xfer_return_value (type, current_regcache, NULL, valbuf); 
+}
+
+/* N32/N44 ABI stuff.  */
+
+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,
+                                 void *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);
+}
+
+static void
+mips_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+  /* Nothing to do -- push_arguments does all the work.  */
+}
+
+static CORE_ADDR
+mips_extract_struct_value_address (struct regcache *regcache)
+{
+  /* FIXME: This will only work at random.  The caller passes the
+     struct_return address in V0, but it is not preserved.  It may
+     still be there, or this may be a random value.  */
+  LONGEST val;
+
+  regcache_cooked_read_signed (regcache, V0_REGNUM, &val);
+  return val;
+}
+
 /* 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 ();
@@ -3745,7 +5063,7 @@ mips_show_processor_type_command (char *args, int from_tty)
 
 /* Modify the actual processor type. */
 
-int
+static int
 mips_set_processor_type (char *str)
 {
   int i;
@@ -3847,7 +5165,7 @@ gdb_print_insn_mips (bfd_vma memaddr, disassemble_info *info)
    (if necessary) to point to the actual memory location where the
    breakpoint should be inserted.  */
 
-const unsigned char *
+static const unsigned char *
 mips_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
 {
   if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
@@ -3929,7 +5247,7 @@ mips_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
    This function implements the SKIP_TRAMPOLINE_CODE macro.
  */
 
-CORE_ADDR
+static CORE_ADDR
 mips_skip_stub (CORE_ADDR pc)
 {
   char *name;
@@ -4012,7 +5330,7 @@ mips_skip_stub (CORE_ADDR pc)
 /* Return non-zero if the PC is inside a call thunk (aka stub or trampoline).
    This implements the IN_SOLIB_CALL_TRAMPOLINE macro.  */
 
-int
+static int
 mips_in_call_stub (CORE_ADDR pc, char *name)
 {
   CORE_ADDR start_addr;
@@ -4040,7 +5358,7 @@ mips_in_call_stub (CORE_ADDR pc, char *name)
 /* Return non-zero if the PC is inside a return thunk (aka stub or trampoline).
    This implements the IN_SOLIB_RETURN_TRAMPOLINE macro.  */
 
-int
+static int
 mips_in_return_stub (CORE_ADDR pc, char *name)
 {
   CORE_ADDR start_addr;
@@ -4090,7 +5408,7 @@ mips_ignore_helper (CORE_ADDR pc)
    point (e.g. programs in ROM) should define a symbol __CALL_DUMMY_ADDRESS
    whose address is the location where the breakpoint should be placed.  */
 
-CORE_ADDR
+static CORE_ADDR
 mips_call_dummy_address (void)
 {
   struct minimal_symbol *sym;
@@ -4132,59 +5450,47 @@ mips_coerce_float_to_double (struct type *formal, struct type *actual)
 
 static void
 mips_get_saved_register (char *raw_buffer,
-                        int *optimized,
+                        int *optimizedp,
                         CORE_ADDR *addrp,
                         struct frame_info *frame,
                         int regnum,
-                        enum lval_type *lval)
+                        enum lval_type *lvalp)
 {
-  CORE_ADDR addr;
+  CORE_ADDR addrx;
+  enum lval_type lvalx;
+  int optimizedx;
+  int realnum;
 
   if (!target_has_registers)
     error ("No registers.");
 
-  /* Normal systems don't optimize out things with register numbers.  */
-  if (optimized != NULL)
-    *optimized = 0;
-  addr = find_saved_register (frame, regnum);
-  if (addr != 0)
+  /* Make certain that all needed parameters are present.  */
+  if (addrp == NULL)
+    addrp = &addrx;
+  if (lvalp == NULL)
+    lvalp = &lvalx;
+  if (optimizedp == NULL)
+    optimizedp = &optimizedx;
+  frame_register_unwind (get_next_frame (frame), regnum, optimizedp, lvalp,
+                        addrp, &realnum, raw_buffer);
+  /* FIXME: cagney/2002-09-13: This is just so bad.  The MIPS should
+     have a pseudo register range that correspons to the ABI's, rather
+     than the ISA's, view of registers.  These registers would then
+     implicitly describe their size and hence could be used without
+     the below munging.  */
+  if ((*lvalp) == lval_memory)
     {
-      if (lval != NULL)
-       *lval = lval_memory;
-      if (regnum == SP_REGNUM)
-       {
-         if (raw_buffer != NULL)
-           {
-             /* Put it back in target format.  */
-             store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
-                            (LONGEST) addr);
-           }
-         if (addrp != NULL)
-           *addrp = 0;
-         return;
-       }
       if (raw_buffer != NULL)
        {
-         LONGEST val;
          if (regnum < 32)
-           /* Only MIPS_SAVED_REGSIZE bytes of GP registers are
-               saved. */
-           val = read_memory_integer (addr, MIPS_SAVED_REGSIZE);
-         else
-           val = read_memory_integer (addr, REGISTER_RAW_SIZE (regnum));
-         store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), val);
+           {
+             /* Only MIPS_SAVED_REGSIZE bytes of GP registers are
+                saved. */
+             LONGEST val = read_memory_integer ((*addrp), MIPS_SAVED_REGSIZE);
+             store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), val);
+           }
        }
     }
-  else
-    {
-      if (lval != NULL)
-       *lval = lval_register;
-      addr = REGISTER_BYTE (regnum);
-      if (raw_buffer != NULL)
-       read_register_gen (regnum, raw_buffer);
-    }
-  if (addrp != NULL)
-    *addrp = addr;
 }
 
 /* Immediately after a function call, return the saved pc.
@@ -4252,6 +5558,8 @@ mips_find_abi_section (bfd *abfd, asection *sect, void *obj)
     *abip = MIPS_ABI_O32;
   else if (strcmp (name, ".mdebug.abiN32") == 0)
     *abip = MIPS_ABI_N32;
+  else if (strcmp (name, ".mdebug.abiN64") == 0)
+    *abip = MIPS_ABI_N64;
   else if (strcmp (name, ".mdebug.abiO64") == 0)
     *abip = MIPS_ABI_O64;
   else if (strcmp (name, ".mdebug.eabi32") == 0)
@@ -4306,7 +5614,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:
@@ -4338,7 +5646,7 @@ mips_gdbarch_init (struct gdbarch_info info,
   if (info.abfd == NULL && arches != NULL)
     mips_abi = gdbarch_tdep (arches->gdbarch)->found_abi;
 
-  /* Try the architecture for any hint of the corect ABI */
+  /* Try the architecture for any hint of the correct ABI.  */
   if (mips_abi == MIPS_ABI_UNKNOWN
       && info.bfd_arch_info != NULL
       && info.bfd_arch_info->arch == bfd_arch_mips)
@@ -4354,6 +5662,9 @@ mips_gdbarch_init (struct gdbarch_info info,
          break;
        case bfd_mach_mips8000:
        case bfd_mach_mips10000:
+         /* On Irix, ELF64 executables use the N64 ABI.  The
+            pseudo-sections which describe the ABI aren't present
+            on IRIX.  (Even for executables created by gcc.)  */
          if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour
              && elf_elfheader (info.abfd)->e_ident[EI_CLASS] == ELFCLASS64)
            mips_abi = MIPS_ABI_N64;
@@ -4363,11 +5674,6 @@ mips_gdbarch_init (struct gdbarch_info info,
        }
     }
 
-#ifdef MIPS_DEFAULT_ABI
-  if (mips_abi == MIPS_ABI_UNKNOWN)
-    mips_abi = MIPS_DEFAULT_ABI;
-#endif
-
   if (mips_abi == MIPS_ABI_UNKNOWN)
     mips_abi = MIPS_ABI_O32;
 
@@ -4397,7 +5703,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)
@@ -4406,84 +5712,115 @@ 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;
 
+  set_gdbarch_elf_make_msymbol_special (gdbarch, 
+                                       mips_elf_make_msymbol_special);
+
   switch (mips_abi)
     {
     case MIPS_ABI_O32:
+      set_gdbarch_push_arguments (gdbarch, mips_o32_push_arguments);
+      set_gdbarch_deprecated_store_return_value (gdbarch, mips_o32_store_return_value);
+      set_gdbarch_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);
       set_gdbarch_ptr_bit (gdbarch, 32);
       set_gdbarch_long_long_bit (gdbarch, 64);
+      set_gdbarch_reg_struct_has_addr (gdbarch, 
+                                      mips_o32_reg_struct_has_addr);
+      set_gdbarch_use_struct_convention (gdbarch, 
+                                        mips_o32_use_struct_convention);
       break;
     case MIPS_ABI_O64:
+      set_gdbarch_push_arguments (gdbarch, mips_o64_push_arguments);
+      set_gdbarch_deprecated_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);
       set_gdbarch_ptr_bit (gdbarch, 32);
       set_gdbarch_long_long_bit (gdbarch, 64);
+      set_gdbarch_reg_struct_has_addr (gdbarch, 
+                                      mips_o32_reg_struct_has_addr);
+      set_gdbarch_use_struct_convention (gdbarch, 
+                                        mips_o32_use_struct_convention);
       break;
     case MIPS_ABI_EABI32:
+      set_gdbarch_push_arguments (gdbarch, mips_eabi_push_arguments);
+      set_gdbarch_deprecated_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);
       set_gdbarch_ptr_bit (gdbarch, 32);
       set_gdbarch_long_long_bit (gdbarch, 64);
+      set_gdbarch_reg_struct_has_addr (gdbarch, 
+                                      mips_eabi_reg_struct_has_addr);
+      set_gdbarch_use_struct_convention (gdbarch, 
+                                        mips_eabi_use_struct_convention);
       break;
     case MIPS_ABI_EABI64:
+      set_gdbarch_push_arguments (gdbarch, mips_eabi_push_arguments);
+      set_gdbarch_deprecated_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);
       set_gdbarch_ptr_bit (gdbarch, 64);
       set_gdbarch_long_long_bit (gdbarch, 64);
+      set_gdbarch_reg_struct_has_addr (gdbarch, 
+                                      mips_eabi_reg_struct_has_addr);
+      set_gdbarch_use_struct_convention (gdbarch, 
+                                        mips_eabi_use_struct_convention);
       break;
     case MIPS_ABI_N32:
-      tdep->mips_default_saved_regsize = 4;
+      set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+      set_gdbarch_deprecated_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 = 0;
+      tdep->gdb_target_is_mips64 = 1;
       tdep->default_mask_address_p = 0;
       set_gdbarch_long_bit (gdbarch, 32);
       set_gdbarch_ptr_bit (gdbarch, 32);
@@ -4499,14 +5836,21 @@ mips_gdbarch_init (struct gdbarch_info info,
        tm_print_insn_info.mach = info.bfd_arch_info->mach;
       else
        tm_print_insn_info.mach = bfd_mach_mips8000;
+
+      set_gdbarch_use_struct_convention (gdbarch, 
+                                        mips_n32n64_use_struct_convention);
+      set_gdbarch_reg_struct_has_addr (gdbarch, 
+                                      mips_n32n64_reg_struct_has_addr);
       break;
     case MIPS_ABI_N64:
+      set_gdbarch_push_arguments (gdbarch, mips_n32n64_push_arguments);
+      set_gdbarch_deprecated_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);
@@ -4523,6 +5867,11 @@ mips_gdbarch_init (struct gdbarch_info info,
        tm_print_insn_info.mach = info.bfd_arch_info->mach;
       else
        tm_print_insn_info.mach = bfd_mach_mips8000;
+
+      set_gdbarch_use_struct_convention (gdbarch, 
+                                        mips_n32n64_use_struct_convention);
+      set_gdbarch_reg_struct_has_addr (gdbarch, 
+                                      mips_n32n64_reg_struct_has_addr);
       break;
     default:
       internal_error (__FILE__, __LINE__,
@@ -4535,7 +5884,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,
@@ -4545,10 +5894,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)
@@ -4575,16 +5924,19 @@ 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.  */
+  /* NOTE: many targets (esp. embedded) do not go thru the
+     gdbarch_register_name vector at all, instead bypassing it
+     by defining REGISTER_NAMES.  */
   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_fp (gdbarch, mips_read_sp); /* Draft FRAME base.  */
+  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
@@ -4592,12 +5944,13 @@ 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);
 
   /* Initialize a frame */
   set_gdbarch_init_extra_frame_info (gdbarch, mips_init_extra_frame_info);
+  set_gdbarch_frame_init_saved_regs (gdbarch, mips_frame_init_saved_regs);
 
   /* MIPS version of CALL_DUMMY */
 
@@ -4606,19 +5959,37 @@ mips_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
   set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
   set_gdbarch_call_dummy_address (gdbarch, mips_call_dummy_address);
+  set_gdbarch_push_return_address (gdbarch, mips_push_return_address);
+  set_gdbarch_push_dummy_frame (gdbarch, mips_push_dummy_frame);
+  set_gdbarch_pop_frame (gdbarch, mips_pop_frame);
   set_gdbarch_call_dummy_start_offset (gdbarch, 0);
   set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
   set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
   set_gdbarch_call_dummy_length (gdbarch, 0);
+  set_gdbarch_fix_call_dummy (gdbarch, mips_fix_call_dummy);
   set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
   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_frame_align (gdbarch, mips_frame_align);
+  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 (gdbarch, mips_frame_chain);
   set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+  set_gdbarch_frameless_function_invocation (gdbarch, 
+                                            generic_frameless_function_invocation_not);
+  set_gdbarch_frame_saved_pc (gdbarch, mips_frame_saved_pc);
+  set_gdbarch_frame_args_address (gdbarch, default_frame_address);
+  set_gdbarch_frame_locals_address (gdbarch, default_frame_address);
+  set_gdbarch_frame_num_args (gdbarch, frame_num_args_unknown);
+  set_gdbarch_frame_args_skip (gdbarch, 0);
+
   set_gdbarch_get_saved_register (gdbarch, mips_get_saved_register);
 
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
@@ -4632,9 +6003,28 @@ 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);
 
+  set_gdbarch_store_struct_return (gdbarch, mips_store_struct_return);
+  set_gdbarch_extract_struct_value_address (gdbarch, 
+                                           mips_extract_struct_value_address);
+  
+  set_gdbarch_skip_trampoline_code (gdbarch, mips_skip_stub);
+
+  set_gdbarch_in_solib_call_trampoline (gdbarch, mips_in_call_stub);
+  set_gdbarch_in_solib_return_trampoline (gdbarch, mips_in_return_stub);
+
   return gdbarch;
 }
 
@@ -4727,9 +6117,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);
@@ -4759,9 +6146,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: CPLUS_MARKER = %c\n",
                      CPLUS_MARKER);
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: DEFAULT_MIPS_TYPE = %s\n",
-                     DEFAULT_MIPS_TYPE);
   fprintf_unfiltered (file,
                      "mips_dump_tdep: DO_REGISTERS_INFO # %s\n",
                      XSTRING (DO_REGISTERS_INFO));
@@ -4771,9 +6155,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: ECOFF_REG_TO_REGNUM # %s\n",
                      XSTRING (ECOFF_REG_TO_REGNUM (REGNUM)));
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: ELF_MAKE_MSYMBOL_SPECIAL # %s\n",
-                     XSTRING (ELF_MAKE_MSYMBOL_SPECIAL (SYM, MSYM)));
   fprintf_unfiltered (file,
                      "mips_dump_tdep: FCRCS_REGNUM = %d\n",
                      FCRCS_REGNUM);
@@ -4870,11 +6251,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: MIPS_SAVED_REGSIZE = %d\n",
                      MIPS_SAVED_REGSIZE);
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: MSYMBOL_IS_SPECIAL = function?\n");
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: MSYMBOL_SIZE # %s\n",
-                     XSTRING (MSYMBOL_SIZE (MSYM)));
   fprintf_unfiltered (file,
                      "mips_dump_tdep: OP_LDFPR = used?\n");
   fprintf_unfiltered (file,
@@ -5123,6 +6499,7 @@ This option can be set to one of:\n\
      "  o32\n"
      "  o64\n"
      "  n32\n"
+     "  n64\n"
      "  eabi32\n"
      "  eabi64",
      &setmipscmdlist);
This page took 0.054639 seconds and 4 git commands to generate.