*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 30079b58865ab03e1627f269c4be3abf02084ca2..1686ee45433705fb5626be87862cc341e8a7c1e1 100644 (file)
@@ -1,7 +1,7 @@
 /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
 
-   Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+   1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
    Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
    and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
 #include "target.h"
 #include "arch-utils.h"
 #include "regcache.h"
+#include "osabi.h"
+#include "mips-tdep.h"
 
 #include "opcode/mips.h"
 #include "elf/mips.h"
 #include "elf-bfd.h"
 #include "symcat.h"
 
+/* A useful bit in the CP0 status register (PS_REGNUM).  */
+/* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip.  */
+#define ST0_FR (1 << 26)
+
 /* The sizes of floating point registers.  */
 
 enum
@@ -52,17 +58,19 @@ enum
   MIPS_FPU_DOUBLE_REGSIZE = 8
 };
 
-/* All the possible MIPS ABIs. */
 
-enum mips_abi
-  {
-    MIPS_ABI_UNKNOWN,
-    MIPS_ABI_N32,
-    MIPS_ABI_O32,
-    MIPS_ABI_O64,
-    MIPS_ABI_EABI32,
-    MIPS_ABI_EABI64
-  };
+static const char *mips_abi_string;
+
+static const char *mips_abi_strings[] = {
+  "auto",
+  "n32",
+  "o32",
+  "n64",
+  "o64",
+  "eabi32",
+  "eabi64",
+  NULL
+};
 
 struct frame_extra_info
   {
@@ -101,12 +109,6 @@ enum mips_fpu_type
 #endif
 static int mips_fpu_type_auto = 1;
 static enum mips_fpu_type mips_fpu_type = MIPS_DEFAULT_FPU_TYPE;
-#define MIPS_FPU_TYPE mips_fpu_type
-
-/* Do not use "TARGET_IS_MIPS64" to test the size of floating point registers */
-#ifndef FP_REGISTER_DOUBLE
-#define FP_REGISTER_DOUBLE (REGISTER_VIRTUAL_SIZE(FP0_REGNUM) == 8)
-#endif
 
 static int mips_debug = 0;
 
@@ -115,54 +117,46 @@ struct gdbarch_tdep
   {
     /* from the elf header */
     int elf_flags;
+
     /* mips options */
     enum mips_abi mips_abi;
-    const char *mips_abi_string;
+    enum mips_abi found_abi;
     enum mips_fpu_type mips_fpu_type;
     int mips_last_arg_regnum;
     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;
+
+    enum gdb_osabi osabi;
   };
 
-#if GDB_MULTI_ARCH
-#undef MIPS_EABI
 #define MIPS_EABI (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI32 \
                   || gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_EABI64)
-#endif
 
-#if GDB_MULTI_ARCH
-#undef MIPS_LAST_FP_ARG_REGNUM
 #define MIPS_LAST_FP_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_fp_arg_regnum)
-#endif
 
-#if GDB_MULTI_ARCH
-#undef MIPS_LAST_ARG_REGNUM
 #define MIPS_LAST_ARG_REGNUM (gdbarch_tdep (current_gdbarch)->mips_last_arg_regnum)
-#endif
 
-#if GDB_MULTI_ARCH
-#undef MIPS_FPU_TYPE
 #define MIPS_FPU_TYPE (gdbarch_tdep (current_gdbarch)->mips_fpu_type)
-#endif
 
 /* Return the currently configured (or set) saved register size. */
 
-#if GDB_MULTI_ARCH
-#undef MIPS_DEFAULT_SAVED_REGSIZE
 #define MIPS_DEFAULT_SAVED_REGSIZE (gdbarch_tdep (current_gdbarch)->mips_default_saved_regsize)
-#elif !defined (MIPS_DEFAULT_SAVED_REGSIZE)
-#define MIPS_DEFAULT_SAVED_REGSIZE MIPS_REGSIZE
-#endif
 
 static const char *mips_saved_regsize_string = size_auto;
 
 #define MIPS_SAVED_REGSIZE (mips_saved_regsize())
 
+/* Return the MIPS ABI associated with GDBARCH.  */
+enum mips_abi
+mips_abi (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep (gdbarch)->mips_abi;
+}
+
 static unsigned int
 mips_saved_regsize (void)
 {
@@ -174,36 +168,134 @@ 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.  */
+
+static int
+mips2_fp_compat (void)
+{
+  /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not
+     meaningful.  */
+  if (REGISTER_RAW_SIZE (FP0_REGNUM) == 4)
+    return 0;
+
+#if 0
+  /* FIXME drow 2002-03-10: This is disabled until we can do it consistently,
+     in all the places we deal with FP registers.  PR gdb/413.  */
+  /* Otherwise check the FR bit in the status register - it controls
+     the FP compatiblity mode.  If it is clear we are in compatibility
+     mode.  */
+  if ((read_register (PS_REGNUM) & ST0_FR) == 0)
+    return 1;
+#endif
+
+  return 0;
+}
+
 /* Indicate that the ABI makes use of double-precision registers
    provided by the FPU (rather than combining pairs of registers to
    form double-precision values).  Do not use "TARGET_IS_MIPS64" to
    determine if the ABI is using double-precision registers.  See also
    MIPS_FPU_TYPE. */
-#if GDB_MULTI_ARCH
-#undef FP_REGISTER_DOUBLE
 #define FP_REGISTER_DOUBLE (gdbarch_tdep (current_gdbarch)->mips_fp_register_double)
-#endif
-
-/* 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. */
-
-#if GDB_MULTI_ARCH
-#undef MIPS_REGS_HAVE_HOME_P
-#define MIPS_REGS_HAVE_HOME_P (gdbarch_tdep (current_gdbarch)->mips_regs_have_home_p)
-#elif !defined (MIPS_REGS_HAVE_HOME_P)
-#define MIPS_REGS_HAVE_HOME_P (!MIPS_EABI)
-#endif
 
 /* 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. */
 
-#if GDB_MULTI_ARCH
-#undef MIPS_DEFAULT_STACK_ARGSIZE
 #define MIPS_DEFAULT_STACK_ARGSIZE (gdbarch_tdep (current_gdbarch)->mips_default_stack_argsize)
-#elif !defined (MIPS_DEFAULT_STACK_ARGSIZE)
-#define MIPS_DEFAULT_STACK_ARGSIZE (MIPS_DEFAULT_SAVED_REGSIZE)
-#endif
 
 #define MIPS_STACK_ARGSIZE (mips_stack_argsize ())
 
@@ -220,17 +312,9 @@ mips_stack_argsize (void)
     return 4;
 }
 
-#if GDB_MULTI_ARCH
-#undef GDB_TARGET_IS_MIPS64
 #define GDB_TARGET_IS_MIPS64 (gdbarch_tdep (current_gdbarch)->gdb_target_is_mips64 + 0)
-#endif
 
-#if GDB_MULTI_ARCH
-#undef MIPS_DEFAULT_MASK_ADDRESS_P
 #define MIPS_DEFAULT_MASK_ADDRESS_P (gdbarch_tdep (current_gdbarch)->default_mask_address_p)
-#elif !defined (MIPS_DEFAULT_MASK_ADDRESS_P)
-#define MIPS_DEFAULT_MASK_ADDRESS_P (0)
-#endif
 
 #define VM_MIN_ADDRESS (CORE_ADDR)0x400000
 
@@ -245,7 +329,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);
 
@@ -257,6 +341,12 @@ find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame);
 static CORE_ADDR after_prologue (CORE_ADDR pc,
                                 mips_extra_func_info_t proc_desc);
 
+static void mips_read_fp_register_single (int regno, char *rare_buffer);
+static void mips_read_fp_register_double (int regno, char *rare_buffer);
+
+static struct type *mips_float_register_type (void);
+static struct type *mips_double_register_type (void);
+
 /* This value is the model of MIPS in use.  It is derived from the value
    of the PrID register.  */
 
@@ -275,7 +365,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;
 
-char *
+static const char *
 mips_register_name (int i)
 {
   return mips_processor_reg_names[i];
@@ -293,7 +383,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",
 };
@@ -310,7 +400,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",
 };
@@ -327,7 +417,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",
 };
@@ -386,6 +476,8 @@ static unsigned int heuristic_fence_post = 0;
 #define PROC_REG_OFFSET(proc) ((proc)->pdr.regoffset)
 #define PROC_FREG_OFFSET(proc) ((proc)->pdr.fregoffset)
 #define PROC_PC_REG(proc) ((proc)->pdr.pcreg)
+/* FIXME drow/2002-06-10: If a pointer on the host is bigger than a long,
+   this will corrupt pdr.iline.  Fortunately we don't use it.  */
 #define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->pdr.isym)
 #define _PROC_MAGIC_ 0x0F0F0F0F
 #define PROC_DESC_IS_DUMMY(proc) ((proc)->pdr.isym == _PROC_MAGIC_)
@@ -416,7 +508,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)
@@ -433,7 +525,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)
@@ -442,7 +534,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)
 {
@@ -456,7 +548,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)
 {
@@ -471,40 +563,116 @@ 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 cmd_auto_boolean mask_address_var = CMD_AUTO_BOOLEAN_AUTO;
+enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
 
 static int
 mips_mask_address_p (void)
 {
   switch (mask_address_var)
     {
-    case CMD_AUTO_BOOLEAN_TRUE:
+    case AUTO_BOOLEAN_TRUE:
       return 1;
-    case CMD_AUTO_BOOLEAN_FALSE:
+    case AUTO_BOOLEAN_FALSE:
       return 0;
       break;
-    case CMD_AUTO_BOOLEAN_AUTO:
+    case AUTO_BOOLEAN_AUTO:
       return MIPS_DEFAULT_MASK_ADDRESS_P;
     default:
       internal_error (__FILE__, __LINE__,
                      "mips_mask_address_p: bad switch");
       return -1;
-    }      
+    }
 }
 
 static void
-show_mask_address (char *cmd, int from_tty)
+show_mask_address (char *cmd, int from_tty, struct cmd_list_element *c)
 {
   switch (mask_address_var)
     {
-    case CMD_AUTO_BOOLEAN_TRUE:
+    case AUTO_BOOLEAN_TRUE:
       printf_filtered ("The 32 bit mips address mask is enabled\n");
       break;
-    case CMD_AUTO_BOOLEAN_FALSE:
+    case AUTO_BOOLEAN_FALSE:
       printf_filtered ("The 32 bit mips address mask is disabled\n");
       break;
-    case CMD_AUTO_BOOLEAN_AUTO:
+    case AUTO_BOOLEAN_AUTO:
       printf_filtered ("The 32 bit address mask is set automatically.  Currently %s\n",
                       mips_mask_address_p () ? "enabled" : "disabled");
       break;
@@ -512,17 +680,55 @@ show_mask_address (char *cmd, int from_tty)
       internal_error (__FILE__, __LINE__,
                      "show_mask_address: bad switch");
       break;
-    }      
+    }
 }
 
 /* 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.  */
@@ -541,7 +747,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;
 }
@@ -709,7 +915,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;
@@ -1025,7 +1231,6 @@ static CORE_ADDR
 add_offset_16 (CORE_ADDR pc, int offset)
 {
   return ((offset << 2) | ((pc + 2) & (0xf0000000)));
-
 }
 
 static CORE_ADDR
@@ -1149,7 +1354,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);
@@ -1171,9 +1376,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;
@@ -1205,7 +1418,7 @@ mips_find_saved_regs (struct frame_info *fci)
 /* FIXME!  Is this correct?? */
 #define SIGFRAME_REG_SIZE      MIPS_REGSIZE
 #endif
-  if (fci->signal_handler_caller)
+  if ((get_frame_type (fci) == SIGTRAMP_FRAME))
     {
       for (ireg = 0; ireg < MIPS_NUMREGS; ireg++)
        {
@@ -1238,7 +1451,7 @@ mips_find_saved_regs (struct frame_info *fci)
                                   a signal, we assume that all registers have been saved.
                                   This assumes that all register saves in a function happen before
                                   the first function call.  */
-       (fci->next == NULL || fci->next->signal_handler_caller)
+       (fci->next == NULL || (get_frame_type (fci->next) == SIGTRAMP_FRAME))
 
   /* In a dummy frame we know exactly where things are saved.  */
        && !PROC_DESC_IS_DUMMY (proc_desc)
@@ -1323,9 +1536,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
@@ -1340,24 +1564,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  */
@@ -1403,7 +1652,7 @@ mips_addr_bits_remove (CORE_ADDR addr)
 
 /* mips_software_single_step() is called just before we want to resume
    the inferior, if we want to single-step it but there is no hardware
-   or kernel single-step support (MIPS on Linux for example).  We find
+   or kernel single-step support (MIPS on GNU/Linux for example).  We find
    the target of the coming instruction and breakpoint it.
 
    single_step is also called just after the inferior stops.  If we had
@@ -1428,29 +1677,35 @@ mips_software_single_step (enum target_signal sig, int insert_breakpoints_p)
     target_remove_breakpoint (next_pc, break_mem);
 }
 
-static void
+static CORE_ADDR
 mips_init_frame_pc_first (int fromleaf, struct frame_info *prev)
 {
   CORE_ADDR pc, tmp;
 
   pc = ((fromleaf) ? SAVED_PC_AFTER_CALL (prev->next) :
        prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
-  tmp = mips_skip_stub (pc);
-  prev->pc = tmp ? tmp : pc;
+  tmp = SKIP_TRAMPOLINE_CODE (pc);
+  return tmp ? tmp : pc;
 }
 
 
-CORE_ADDR
+static CORE_ADDR
 mips_frame_saved_pc (struct frame_info *frame)
 {
   CORE_ADDR saved_pc;
   mips_extra_func_info_t proc_desc = frame->extra_info->proc_desc;
   /* We have to get the saved pc from the sigcontext
      if it is a signal handler frame.  */
-  int pcreg = frame->signal_handler_caller ? PC_REGNUM
+  int pcreg = (get_frame_type (frame) == SIGTRAMP_FRAME) ? PC_REGNUM
   : (proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM);
 
-  if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc))
+  if (DEPRECATED_PC_IN_CALL_DUMMY (frame->pc, 0, 0))
+    {
+      LONGEST tmp;
+      frame_unwind_signed_register (frame, PC_REGNUM, &tmp);
+      saved_pc = tmp;
+    }
+  else if (proc_desc && PROC_DESC_IS_DUMMY (proc_desc))
     saved_pc = read_memory_integer (frame->frame - MIPS_SAVED_REGSIZE, MIPS_SAVED_REGSIZE);
   else
     saved_pc = read_next_frame_reg (frame, pcreg);
@@ -1459,7 +1714,13 @@ mips_frame_saved_pc (struct frame_info *frame)
 }
 
 static struct mips_extra_func_info temp_proc_desc;
-static CORE_ADDR temp_saved_regs[NUM_REGS];
+
+/* This hack will go away once the get_prev_frame() code has been
+   modified to set the frame's type first.  That is BEFORE init extra
+   frame info et.al.  is called.  This is because it will become
+   possible to skip the init extra info call for sigtramp and dummy
+   frames.  */
+static CORE_ADDR *temp_saved_regs;
 
 /* Set a register's saved stack address in temp_saved_regs.  If an address
    has already been set for this register, do nothing; this way we will
@@ -1771,6 +2032,7 @@ mips32_heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   CORE_ADDR cur_pc;
   CORE_ADDR frame_addr = 0;    /* Value of $r30. Used by gcc for frame-pointer */
 restart:
+  temp_saved_regs = xrealloc (temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
   memset (temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
   PROC_FRAME_OFFSET (&temp_proc_desc) = 0;
   PROC_FRAME_ADJUST (&temp_proc_desc) = 0;     /* offset of FP from SP */
@@ -1879,7 +2141,8 @@ heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   if (start_pc == 0)
     return NULL;
   memset (&temp_proc_desc, '\0', sizeof (temp_proc_desc));
-  memset (&temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
+  temp_saved_regs = xrealloc (temp_saved_regs, SIZEOF_FRAME_SAVED_REGS);
+  memset (temp_saved_regs, '\0', SIZEOF_FRAME_SAVED_REGS);
   PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
   PROC_FRAME_REG (&temp_proc_desc) = SP_REGNUM;
   PROC_PC_REG (&temp_proc_desc) = RA_REGNUM;
@@ -1893,6 +2156,30 @@ heuristic_proc_desc (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   return &temp_proc_desc;
 }
 
+struct mips_objfile_private
+{
+  bfd_size_type size;
+  char *contents;
+};
+
+/* Global used to communicate between non_heuristic_proc_desc and
+   compare_pdr_entries within qsort ().  */
+static bfd *the_bfd;
+
+static int
+compare_pdr_entries (const void *a, const void *b)
+{
+  CORE_ADDR lhs = bfd_get_32 (the_bfd, (bfd_byte *) a);
+  CORE_ADDR rhs = bfd_get_32 (the_bfd, (bfd_byte *) b);
+
+  if (lhs < rhs)
+    return -1;
+  else if (lhs == rhs)
+    return 0;
+  else
+    return 1;
+}
+
 static mips_extra_func_info_t
 non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
 {
@@ -1900,23 +2187,145 @@ non_heuristic_proc_desc (CORE_ADDR pc, CORE_ADDR *addrptr)
   mips_extra_func_info_t proc_desc;
   struct block *b = block_for_pc (pc);
   struct symbol *sym;
+  struct obj_section *sec;
+  struct mips_objfile_private *priv;
+
+  if (DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+    return NULL;
 
   find_pc_partial_function (pc, NULL, &startaddr, NULL);
   if (addrptr)
     *addrptr = startaddr;
-  if (b == NULL || PC_IN_CALL_DUMMY (pc, 0, 0))
-    sym = NULL;
-  else
+
+  priv = NULL;
+
+  sec = find_pc_section (pc);
+  if (sec != NULL)
     {
-      if (startaddr > BLOCK_START (b))
-       /* This is the "pathological" case referred to in a comment in
-          print_frame_info.  It might be better to move this check into
-          symbol reading.  */
-       sym = NULL;
-      else
-       sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
+      priv = (struct mips_objfile_private *) sec->objfile->obj_private;
+
+      /* Search the ".pdr" section generated by GAS.  This includes most of
+        the information normally found in ECOFF PDRs.  */
+
+      the_bfd = sec->objfile->obfd;
+      if (priv == NULL
+         && (the_bfd->format == bfd_object
+             && bfd_get_flavour (the_bfd) == bfd_target_elf_flavour
+             && elf_elfheader (the_bfd)->e_ident[EI_CLASS] == ELFCLASS64))
+       {
+         /* Right now GAS only outputs the address as a four-byte sequence.
+            This means that we should not bother with this method on 64-bit
+            targets (until that is fixed).  */
+
+         priv = obstack_alloc (& sec->objfile->psymbol_obstack,
+                               sizeof (struct mips_objfile_private));
+         priv->size = 0;
+         sec->objfile->obj_private = priv;
+       }
+      else if (priv == NULL)
+       {
+         asection *bfdsec;
+
+         priv = obstack_alloc (& sec->objfile->psymbol_obstack,
+                               sizeof (struct mips_objfile_private));
+
+         bfdsec = bfd_get_section_by_name (sec->objfile->obfd, ".pdr");
+         if (bfdsec != NULL)
+           {
+             priv->size = bfd_section_size (sec->objfile->obfd, bfdsec);
+             priv->contents = obstack_alloc (& sec->objfile->psymbol_obstack,
+                                             priv->size);
+             bfd_get_section_contents (sec->objfile->obfd, bfdsec,
+                                       priv->contents, 0, priv->size);
+
+             /* In general, the .pdr section is sorted.  However, in the
+                presence of multiple code sections (and other corner cases)
+                it can become unsorted.  Sort it so that we can use a faster
+                binary search.  */
+             qsort (priv->contents, priv->size / 32, 32, compare_pdr_entries);
+           }
+         else
+           priv->size = 0;
+
+         sec->objfile->obj_private = priv;
+       }
+      the_bfd = NULL;
+
+      if (priv->size != 0)
+       {
+         int low, mid, high;
+         char *ptr;
+
+         low = 0;
+         high = priv->size / 32;
+
+         do
+           {
+             CORE_ADDR pdr_pc;
+
+             mid = (low + high) / 2;
+
+             ptr = priv->contents + mid * 32;
+             pdr_pc = bfd_get_signed_32 (sec->objfile->obfd, ptr);
+             pdr_pc += ANOFFSET (sec->objfile->section_offsets,
+                                 SECT_OFF_TEXT (sec->objfile));
+             if (pdr_pc == startaddr)
+               break;
+             if (pdr_pc > startaddr)
+               high = mid;
+             else
+               low = mid + 1;
+           }
+         while (low != high);
+
+         if (low != high)
+           {
+             struct symbol *sym = find_pc_function (pc);
+
+             /* Fill in what we need of the proc_desc.  */
+             proc_desc = (mips_extra_func_info_t)
+               obstack_alloc (&sec->objfile->psymbol_obstack,
+                              sizeof (struct mips_extra_func_info));
+             PROC_LOW_ADDR (proc_desc) = startaddr;
+
+             /* Only used for dummy frames.  */
+             PROC_HIGH_ADDR (proc_desc) = 0;
+
+             PROC_FRAME_OFFSET (proc_desc)
+               = bfd_get_32 (sec->objfile->obfd, ptr + 20);
+             PROC_FRAME_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+                                                      ptr + 24);
+             PROC_FRAME_ADJUST (proc_desc) = 0;
+             PROC_REG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+                                                     ptr + 4);
+             PROC_FREG_MASK (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+                                                      ptr + 12);
+             PROC_REG_OFFSET (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+                                                       ptr + 8);
+             PROC_FREG_OFFSET (proc_desc)
+               = bfd_get_32 (sec->objfile->obfd, ptr + 16);
+             PROC_PC_REG (proc_desc) = bfd_get_32 (sec->objfile->obfd,
+                                                   ptr + 28);
+             proc_desc->pdr.isym = (long) sym;
+
+             return proc_desc;
+           }
+       }
+    }
+
+  if (b == NULL)
+    return NULL;
+
+  if (startaddr > BLOCK_START (b))
+    {
+      /* This is the "pathological" case referred to in a comment in
+        print_frame_info.  It might be better to move this check into
+        symbol reading.  */
+      return NULL;
     }
 
+  sym = lookup_symbol (MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
+
   /* If we never found a PDR for this function in symbol reading, then
      examine prologues to find the information.  */
   if (sym)
@@ -1936,7 +2345,7 @@ static mips_extra_func_info_t
 find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
 {
   mips_extra_func_info_t proc_desc;
-  CORE_ADDR startaddr;
+  CORE_ADDR startaddr = 0;
 
   proc_desc = non_heuristic_proc_desc (pc, &startaddr);
 
@@ -1952,7 +2361,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)
            {
@@ -1964,8 +2373,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;
            }
@@ -1998,14 +2407,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;
@@ -2017,9 +2427,17 @@ 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;
 
+  if (DEPRECATED_PC_IN_CALL_DUMMY (saved_pc, 0, 0))
+    {
+      /* A dummy frame, uses SP not FP.  Get the old SP value.  If all
+         is well, frame->frame the bottom of the current frame will
+         contain that value.  */
+      return frame->frame;
+    }
+
   /* Look up the procedure descriptor for this PC.  */
   proc_desc = find_proc_desc (saved_pc, frame, 1);
   if (!proc_desc)
@@ -2032,22 +2450,25 @@ 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.  */
+      && !(get_frame_type (frame) == SIGTRAMP_FRAME)
+      /* For a generic dummy frame, let get_frame_pointer() unwind a
+         register value saved as part of the dummy frame call.  */
+      && !(DEPRECATED_PC_IN_CALL_DUMMY (frame->pc, 0, 0)))
     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));
@@ -2064,6 +2485,14 @@ mips_init_extra_frame_info (int fromleaf, struct frame_info *fci)
       if (fci->pc == PROC_LOW_ADDR (proc_desc)
          && !PROC_DESC_IS_DUMMY (proc_desc))
        fci->frame = read_next_frame_reg (fci->next, SP_REGNUM);
+      else if (DEPRECATED_PC_IN_CALL_DUMMY (fci->pc, 0, 0))
+       /* Do not ``fix'' fci->frame.  It will have the value of the
+           generic dummy frame's top-of-stack (since the draft
+           fci->frame is obtained by returning the unwound stack
+           pointer) and that is what we want.  That way the fci->frame
+           value will match the top-of-stack value that was saved as
+           part of the dummy frames data.  */
+       /* Do nothing.  */;
       else
        fci->frame = get_frame_pointer (fci->next, proc_desc);
 
@@ -2072,16 +2501,26 @@ mips_init_extra_frame_info (int fromleaf, struct frame_info *fci)
          char *name;
 
          /* Do not set the saved registers for a sigtramp frame,
-            mips_find_saved_registers will do that for us.
-            We can't use fci->signal_handler_caller, it is not yet set.  */
+            mips_find_saved_registers will do that for us.  We can't
+            use (get_frame_type (fci) == SIGTRAMP_FRAME), it is not
+            yet set.  */
+         /* FIXME: cagney/2002-11-18: This problem will go away once
+             frame.c:get_prev_frame() is modified to set the frame's
+             type before calling functions like this.  */
          find_pc_partial_function (fci->pc, &name,
                                    (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
-         if (!IN_SIGTRAMP (fci->pc, name))
+         if (!PC_IN_SIGTRAMP (fci->pc, name))
            {
              frame_saved_regs_zalloc (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;
            }
        }
 
@@ -2103,7 +2542,7 @@ mips_init_extra_frame_info (int fromleaf, struct frame_info *fci)
    we basically have to look at symbol information for the function
    that we stopped in, which tells us *which* register (if any) is
    the base of the frame pointer, and what offset from that register
-   the frame itself is at.  
+   the frame itself is at.
 
    This presents a problem when trying to examine a stack in memory
    (that isn't executing at the moment), using the "frame" command.  We
@@ -2137,7 +2576,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
@@ -2147,7 +2586,7 @@ static int
 mips_type_needs_double_align (struct type *type)
 {
   enum type_code typecode = TYPE_CODE (type);
-  
+
   if (typecode == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8)
     return 1;
   else if (typecode == TYPE_CODE_STRUCT)
@@ -2158,7 +2597,7 @@ mips_type_needs_double_align (struct type *type)
     }
   else if (typecode == TYPE_CODE_UNION)
     {
-      int i, n;    
+      int i, n;
 
       n = TYPE_NFIELDS (type);
       for (i = 0; i < n; i++)
@@ -2169,12 +2608,26 @@ mips_type_needs_double_align (struct type *type)
   return 0;
 }
 
-CORE_ADDR
-mips_push_arguments (int nargs,
-                    struct value **args,
-                    CORE_ADDR sp,
-                    int struct_return,
-                    CORE_ADDR struct_addr)
+/* 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;
@@ -2182,44 +2635,40 @@ 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
+  /* Now make space on the stack for the args.  We allocate more
      than necessary for EABI, because the first few arguments are
-     passed in registers, but that's OK. */
+     passed in registers, but that's OK.  */
   for (argnum = 0; argnum < nargs; argnum++)
-    len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), MIPS_STACK_ARGSIZE);
+    len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), 
+                    MIPS_STACK_ARGSIZE);
   sp -= ROUND_UP (len, 16);
 
   if (mips_debug)
-    fprintf_unfiltered (gdb_stdlog, "mips_push_arguments: sp=0x%lx allocated %d\n",
-                       (long) sp, ROUND_UP (len, 16));
+    fprintf_unfiltered (gdb_stdlog, 
+                       "mips_eabi_push_arguments: sp=0x%s allocated %d\n",
+                       paddr_nz (sp), ROUND_UP (len, 16));
 
   /* Initialize the integer and float register pointers.  */
   argreg = A0_REGNUM;
   float_argreg = FPA0_REGNUM;
 
-  /* the struct_return pointer occupies the first parameter-passing reg */
+  /* The struct_return pointer occupies the first parameter-passing reg.  */
   if (struct_return)
     {
       if (mips_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "mips_push_arguments: struct_return reg=%d 0x%lx\n",
-                           argreg, (long) struct_addr);
+                           "mips_eabi_push_arguments: struct_return reg=%d 0x%s\n",
+                           argreg, paddr_nz (struct_addr));
       write_register (argreg++, struct_addr);
-      if (MIPS_REGS_HAVE_HOME_P)
-       stack_offset += MIPS_STACK_ARGSIZE;
     }
 
   /* Now load as many as possible of the first arguments into
@@ -2228,7 +2677,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);
@@ -2236,13 +2685,12 @@ mips_push_arguments (int nargs,
 
       if (mips_debug)
        fprintf_unfiltered (gdb_stdlog,
-                           "mips_push_arguments: %d len=%d type=%d",
+                           "mips_eabi_push_arguments: %d len=%d type=%d",
                            argnum + 1, len, (int) typecode);
 
       /* The EABI passes structures that do not fit in a register by
-         reference. In all other cases, pass the structure by value.  */
-      if (MIPS_EABI
-         && len > MIPS_SAVED_REGSIZE
+         reference.  */
+      if (len > MIPS_SAVED_REGSIZE
          && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
        {
          store_address (valbuf, MIPS_SAVED_REGSIZE, VALUE_ADDRESS (arg));
@@ -2258,8 +2706,8 @@ mips_push_arguments (int nargs,
       /* 32-bit ABIs always start floating point arguments in an
          even-numbered floating point register.  Round the FP register
          up before the check to see if there are any FP registers
-         left. Non MIPS_EABI targets also pass the FP in the integer
-         registers so also round up normal registers. */
+         left.  Non MIPS_EABI targets also pass the FP in the integer
+         registers so also round up normal registers.  */
       if (!FP_REGISTER_DOUBLE
          && fp_register_arg_p (typecode, arg_type))
        {
@@ -2278,7 +2726,7 @@ mips_push_arguments (int nargs,
          because those registers are normally skipped.  */
       /* MIPS_EABI squeezes a struct that contains a single floating
          point value into an FP register instead of pushing it onto the
-         stack. */
+         stack.  */
       if (fp_register_arg_p (typecode, arg_type)
          && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
        {
@@ -2293,13 +2741,6 @@ mips_push_arguments (int nargs,
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
              write_register (float_argreg++, regval);
-             if (!MIPS_EABI)
-               {
-                 if (mips_debug)
-                   fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
-                                       argreg, phex (regval, 4));
-                 write_register (argreg++, regval);
-               }
 
              /* Write the high word of the double to the odd register(s).  */
              regval = extract_unsigned_integer (val + 4 - low_offset, 4);
@@ -2307,42 +2748,19 @@ mips_push_arguments (int nargs,
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
              write_register (float_argreg++, regval);
-             if (!MIPS_EABI)
-               {
-                 if (mips_debug)
-                   fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
-                                       argreg, phex (regval, 4));
-                 write_register (argreg++, regval);
-               }
-
            }
          else
            {
              /* This is a floating point value that fits entirely
                 in a single register.  */
              /* On 32 bit ABI's the float_argreg is further adjusted
-                 above to ensure that it is even register aligned. */
+                 above to ensure that it is even register aligned.  */
              LONGEST regval = extract_unsigned_integer (val, len);
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, len));
              write_register (float_argreg++, regval);
-             if (!MIPS_EABI)
-               {
-                 /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
-                     registers for each argument.  The below is (my
-                     guess) to ensure that the corresponding integer
-                     register has reserved the same space. */
-                 if (mips_debug)
-                   fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
-                                       argreg, phex (regval, len));
-                 write_register (argreg, regval);
-                 argreg += FP_REGISTER_DOUBLE ? 1 : 2;
-               }
            }
-         /* Reserve space for the FP register. */
-         if (MIPS_REGS_HAVE_HOME_P)
-           stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
        }
       else
        {
@@ -2355,21 +2773,800 @@ mips_push_arguments (int nargs,
             compatibility, we will put them in both places.  */
          int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
                                  (len % MIPS_SAVED_REGSIZE != 0));
-         /* Structures should be aligned to eight bytes (even arg registers)
-            on MIPS_ABI_O32 if their first member has double precision. */
-         if (gdbarch_tdep (current_gdbarch)->mips_abi == MIPS_ABI_O32
+
+         /* 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;
+}
+
+/* O64 version of push_arguments.  */
+
+static CORE_ADDR
+mips_o64_push_arguments (int nargs,
+                        struct value **args,
+                        CORE_ADDR sp,
+                        int struct_return,
+                        CORE_ADDR struct_addr)
+{
+  int argreg;
+  int float_argreg;
+  int argnum;
+  int len = 0;
+  int stack_offset = 0;
+
+  /* First ensure that the stack and structure return address (if any)
+     are properly aligned.  The stack has to be at least 64-bit
+     aligned even on 32-bit machines, because doubles must be 64-bit
+     aligned.  For n32 and n64, stack frames need to be 128-bit
+     aligned, so we round to this widest known alignment.  */
+
+  sp = ROUND_DOWN (sp, 16);
+  struct_addr = ROUND_DOWN (struct_addr, 16);
+
+  /* Now make space on the stack for the args.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    len += ROUND_UP (TYPE_LENGTH (VALUE_TYPE (args[argnum])), 
+                    MIPS_STACK_ARGSIZE);
+  sp -= ROUND_UP (len, 16);
+
+  if (mips_debug)
+    fprintf_unfiltered (gdb_stdlog, 
+                       "mips_o64_push_arguments: sp=0x%s allocated %d\n",
+                       paddr_nz (sp), ROUND_UP (len, 16));
+
+  /* Initialize the integer and float register pointers.  */
+  argreg = A0_REGNUM;
+  float_argreg = FPA0_REGNUM;
+
+  /* The struct_return pointer occupies the first parameter-passing reg.  */
+  if (struct_return)
+    {
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_o64_push_arguments: struct_return reg=%d 0x%s\n",
+                           argreg, paddr_nz (struct_addr));
+      write_register (argreg++, struct_addr);
+      stack_offset += MIPS_STACK_ARGSIZE;
+    }
+
+  /* Now load as many as possible of the first arguments into
+     registers, and push the rest onto the stack.  Loop thru args
+     from first to last.  */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      char *val;
+      char *valbuf = alloca (MAX_REGISTER_RAW_SIZE);
+      struct value *arg = args[argnum];
+      struct type *arg_type = check_typedef (VALUE_TYPE (arg));
+      int len = TYPE_LENGTH (arg_type);
+      enum type_code typecode = TYPE_CODE (arg_type);
+
+      if (mips_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "mips_o64_push_arguments: %d len=%d type=%d",
+                           argnum + 1, len, (int) typecode);
+
+      val = (char *) VALUE_CONTENTS (arg);
+
+      /* 32-bit ABIs always start floating point arguments in an
+         even-numbered floating point register.  Round the FP register
+         up before the check to see if there are any FP registers
+         left.  O32/O64 targets also pass the FP in the integer
+         registers so also round up normal registers.  */
+      if (!FP_REGISTER_DOUBLE
+         && fp_register_arg_p (typecode, arg_type))
+       {
+         if ((float_argreg & 1))
+           float_argreg++;
+       }
+
+      /* Floating point arguments passed in registers have to be
+         treated specially.  On 32-bit architectures, doubles
+         are passed in register pairs; the even register gets
+         the low word, and the odd register gets the high word.
+         On O32/O64, the first two floating point arguments are
+         also copied to general registers, because MIPS16 functions
+         don't use float registers for arguments.  This duplication of
+         arguments in general registers can't hurt non-MIPS16 functions
+         because those registers are normally skipped.  */
+
+      if (fp_register_arg_p (typecode, arg_type)
+         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+       {
+         if (!FP_REGISTER_DOUBLE && len == 8)
+           {
+             int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+             unsigned long regval;
+
+             /* Write the low word of the double to the even register(s).  */
+             regval = extract_unsigned_integer (val + low_offset, 4);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+                                   float_argreg, phex (regval, 4));
+             write_register (float_argreg++, regval);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+                                   argreg, phex (regval, 4));
+             write_register (argreg++, regval);
+
+             /* Write the high word of the double to the odd register(s).  */
+             regval = extract_unsigned_integer (val + 4 - low_offset, 4);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+                                   float_argreg, phex (regval, 4));
+             write_register (float_argreg++, regval);
+
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+                                   argreg, phex (regval, 4));
+             write_register (argreg++, regval);
+           }
+         else
+           {
+             /* This is a floating point value that fits entirely
+                in a single register.  */
+             /* On 32 bit ABI's the float_argreg is further adjusted
+                 above to ensure that it is even register aligned.  */
+             LONGEST regval = extract_unsigned_integer (val, len);
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
+                                   float_argreg, phex (regval, len));
+             write_register (float_argreg++, regval);
+             /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
+                registers for each argument.  The below is (my
+                guess) to ensure that the corresponding integer
+                register has reserved the same space.  */
+             if (mips_debug)
+               fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
+                                   argreg, phex (regval, len));
+             write_register (argreg, regval);
+             argreg += FP_REGISTER_DOUBLE ? 1 : 2;
+           }
+         /* Reserve space for the FP register.  */
+         stack_offset += ROUND_UP (len, MIPS_STACK_ARGSIZE);
+       }
+      else
+       {
+         /* Copy the argument to general registers or the stack in
+            register-sized pieces.  Large arguments are split between
+            registers and stack.  */
+         /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+            are treated specially: Irix cc passes them in registers
+            where gcc sometimes puts them on the stack.  For maximum
+            compatibility, we will put them in both places.  */
+         int odd_sized_struct = ((len > MIPS_SAVED_REGSIZE) &&
+                                 (len % MIPS_SAVED_REGSIZE != 0));
+         /* Structures should be aligned to eight bytes (even arg registers)
+            on MIPS_ABI_O32, if their first member has double precision.  */
+         if (MIPS_SAVED_REGSIZE < 8
              && mips_type_needs_double_align (arg_type))
            {
              if ((argreg & 1))
                argreg++;
            }
          /* Note: Floating-point values that didn't fit into an FP
-             register are only written to memory. */
+             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",
@@ -2392,29 +3589,27 @@ 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;
 
                  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);
@@ -2422,15 +3617,17 @@ 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 
+                 /* 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
@@ -2439,8 +3636,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) <
@@ -2455,8 +3651,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 ||
@@ -2471,11 +3666,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;
@@ -2487,13 +3680,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.
+                always allocated.  */
 
-                In the new EABI (and the NABI32), the stack_offset
-                only needs to be adjusted when it has been used.. */
-
-             if (MIPS_REGS_HAVE_HOME_P || stack_used_p)
-               stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
+             stack_offset += ROUND_UP (partial_len, MIPS_STACK_ARGSIZE);
            }
        }
       if (mips_debug)
@@ -2504,7 +3693,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
@@ -2516,7 +3705,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))
@@ -2532,14 +3721,14 @@ mips_push_register (CORE_ADDR * sp, int regno)
       offset = 0;
     }
   *sp -= regsize;
-  read_register_gen (regno, buffer);
+  deprecated_read_register_gen (regno, buffer);
   write_memory (*sp, buffer + offset, regsize);
 }
 
 /* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<(MIPS_NUMREGS-1). */
 #define MASK(i,j) (((1 << ((j)+1))-1) ^ ((1 << (i))-1))
 
-void
+static void
 mips_push_dummy_frame (void)
 {
   int ireg;
@@ -2562,7 +3751,7 @@ mips_push_dummy_frame (void)
    * procedure calls. Dest_Reg (see tm-mips.h) must also be saved.
    * In addition, we must save the PC, PUSH_FP_REGNUM, MMLO/-HI
    * and FP Control/Status registers.
-   * 
+   *
    *
    * Dummy frame layout:
    *  (high memory)
@@ -2618,26 +3807,41 @@ mips_push_dummy_frame (void)
   PROC_PC_REG (proc_desc) = RA_REGNUM;
 }
 
-void
+static void
 mips_pop_frame (void)
 {
   register int regnum;
   struct frame_info *frame = get_current_frame ();
-  CORE_ADDR new_sp = FRAME_FP (frame);
-
+  CORE_ADDR new_sp = get_frame_base (frame);
   mips_extra_func_info_t proc_desc = frame->extra_info->proc_desc;
 
+  if (DEPRECATED_PC_IN_CALL_DUMMY (frame->pc, 0, 0))
+    {
+      generic_pop_dummy_frame ();
+      flush_cached_frames ();
+      return;
+    }
+
   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 ();
 
@@ -2676,34 +3880,158 @@ 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
+   64bit operations, these early MIPS cpus treat fp register pairs
+   (f0,f1) as a single register (d0).  Later MIPS cpu's have 64 bit fp
+   registers and offer a compatibility mode that emulates the MIPS2 fp
+   model.  When operating in MIPS2 fp compat mode, later cpu's split
+   double precision floats into two 32-bit chunks and store them in
+   consecutive fp regs.  To display 64-bit floats stored in this
+   fashion, we have to combine 32 bits from f0 and 32 bits from f1.
+   Throw in user-configurable endianness and you have a real mess.
+
+   The way this works is:
+     - If we are in 32-bit mode or on a 32-bit processor, then a 64-bit
+       double-precision value will be split across two logical registers.
+       The lower-numbered logical register will hold the low-order bits,
+       regardless of the processor's endianness.
+     - If we are on a 64-bit processor, and we are looking for a
+       single-precision value, it will be in the low ordered bits
+       of a 64-bit GPR (after mfc1, for example) or a 64-bit register
+       save slot in memory.
+     - If we are in 64-bit mode, everything is straightforward.
+
+   Note that this code only deals with "live" registers at the top of the
+   stack.  We will attempt to deal with saved registers later, when
+   the raw/cooked register interface is in place. (We need a general
+   interface that can deal with dynamic saved register sizes -- fp
+   regs could be 32 bits wide in one frame and 64 on the frame above
+   and below).  */
+
+static struct type *
+mips_float_register_type (void)
+{
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    return builtin_type_ieee_single_big;
+  else
+    return builtin_type_ieee_single_little;
+}
+
+static struct type *
+mips_double_register_type (void)
+{
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    return builtin_type_ieee_double_big;
+  else
+    return builtin_type_ieee_double_little;
+}
+
+/* Copy a 32-bit single-precision value from the current frame
+   into rare_buffer.  */
+
+static void
+mips_read_fp_register_single (int regno, char *rare_buffer)
+{
+  int raw_size = REGISTER_RAW_SIZE (regno);
+  char *raw_buffer = alloca (raw_size);
+
+  if (!frame_register_read (deprecated_selected_frame, regno, raw_buffer))
+    error ("can't read register %d (%s)", regno, REGISTER_NAME (regno));
+  if (raw_size == 8)
+    {
+      /* We have a 64-bit value for this register.  Find the low-order
+        32 bits.  */
+      int offset;
+
+      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+       offset = 4;
+      else
+       offset = 0;
+
+      memcpy (rare_buffer, raw_buffer + offset, 4);
+    }
+  else
+    {
+      memcpy (rare_buffer, raw_buffer, 4);
+    }
+}
+
+/* Copy a 64-bit double-precision value from the current frame into
+   rare_buffer.  This may include getting half of it from the next
+   register.  */
+
+static void
+mips_read_fp_register_double (int regno, char *rare_buffer)
+{
+  int raw_size = REGISTER_RAW_SIZE (regno);
+
+  if (raw_size == 8 && !mips2_fp_compat ())
+    {
+      /* We have a 64-bit value for this register, and we should use
+        all 64 bits.  */
+      if (!frame_register_read (deprecated_selected_frame, regno, rare_buffer))
+       error ("can't read register %d (%s)", regno, REGISTER_NAME (regno));
+    }
+  else
+    {
+      if ((regno - FP0_REGNUM) & 1)
+       internal_error (__FILE__, __LINE__,
+                       "mips_read_fp_register_double: bad access to "
+                       "odd-numbered FP register");
+
+      /* mips_read_fp_register_single will find the correct 32 bits from
+        each register.  */
+      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+       {
+         mips_read_fp_register_single (regno, rare_buffer + 4);
+         mips_read_fp_register_single (regno + 1, rare_buffer);
+       }
+      else
+       {
+         mips_read_fp_register_single (regno, rare_buffer);
+         mips_read_fp_register_single (regno + 1, rare_buffer + 4);
+       }
+    }
+}
+
 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 (read_relative_register_raw_bytes (regnum, raw_buffer))
+  if (!frame_register_read (deprecated_selected_frame, regnum, raw_buffer))
     {
       printf_filtered ("%s: [Invalid]", REGISTER_NAME (regnum));
       return;
     }
 
-  /* If an even floating point register, also print as double. */
+  /* If we have a actual 32-bit floating point register (or we are in
+     32-bit compatibility mode), and the register is even-numbered,
+     also print it as a double (spanning two registers).  */
   if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
+      && (REGISTER_RAW_SIZE (regnum) == 4
+         || mips2_fp_compat ())
       && !((regnum - FP0_REGNUM) & 1))
-    if (REGISTER_RAW_SIZE (regnum) == 4)       /* this would be silly on MIPS64 or N32 (Irix 6) */
-      {
-       char dbuffer[2 * MAX_REGISTER_RAW_SIZE];
+    {
+      char *dbuffer = alloca (2 * MAX_REGISTER_RAW_SIZE);
 
-       read_relative_register_raw_bytes (regnum, dbuffer);
-       read_relative_register_raw_bytes (regnum + 1, dbuffer + MIPS_REGSIZE);
-       REGISTER_CONVERT_TO_TYPE (regnum, builtin_type_double, dbuffer);
+      mips_read_fp_register_double (regnum, dbuffer);
 
-       printf_filtered ("(d%d: ", regnum - FP0_REGNUM);
-       val_print (builtin_type_double, dbuffer, 0, 0,
-                  gdb_stdout, 0, 1, 0, Val_pretty_default);
-       printf_filtered ("); ");
-      }
+      printf_filtered ("(d%d: ", regnum - FP0_REGNUM);
+      val_print (mips_double_register_type (), dbuffer, 0, 0,
+                gdb_stdout, 0, 1, 0, Val_pretty_default);
+      printf_filtered ("); ");
+    }
   fputs_filtered (REGISTER_NAME (regnum), gdb_stdout);
 
   /* The problem with printing numeric register names (r26, etc.) is that
@@ -2717,15 +4045,17 @@ mips_print_register (int regnum, int all)
 
   /* If virtual format is floating, print it that way.  */
   if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
-    if (FP_REGISTER_DOUBLE)
-      {                                /* show 8-byte floats as float AND double: */
+    if (REGISTER_RAW_SIZE (regnum) == 8 && !mips2_fp_compat ())
+      {
+       /* We have a meaningful 64-bit value in this register.  Show
+          it as a 32-bit float and a 64-bit double.  */
        int offset = 4 * (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG);
 
        printf_filtered (" (float) ");
-       val_print (builtin_type_float, raw_buffer + offset, 0, 0,
+       val_print (mips_float_register_type (), raw_buffer + offset, 0, 0,
                   gdb_stdout, 0, 1, 0, Val_pretty_default);
        printf_filtered (", (double) ");
-       val_print (builtin_type_double, raw_buffer, 0, 0,
+       val_print (mips_double_register_type (), raw_buffer, 0, 0,
                   gdb_stdout, 0, 1, 0, Val_pretty_default);
       }
     else
@@ -2740,47 +4070,37 @@ mips_print_register (int regnum, int all)
         offset = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
       else
        offset = 0;
-       
+
       print_scalar_formatted (raw_buffer + offset,
                              REGISTER_VIRTUAL_TYPE (regnum),
                              'x', 0, gdb_stdout);
     }
 }
 
-/* Replacement for generic do_registers_info.  
+/* Replacement for generic do_registers_info.
    Print regs in pretty columns.  */
 
 static int
 do_fp_register_row (int regnum)
 {                              /* do values for FP (float) regs */
-  char *raw_buffer[2];
-  char *dbl_buffer;
-  /* use HI and LO to control the order of combining two flt regs */
-  int HI = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG);
-  int LO = (TARGET_BYTE_ORDER != BFD_ENDIAN_BIG);
+  char *raw_buffer;
   double doub, flt1, flt2;     /* doubles extracted from raw hex data */
   int inv1, inv2, inv3;
 
-  raw_buffer[0] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM));
-  raw_buffer[1] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM));
-  dbl_buffer = (char *) alloca (2 * REGISTER_RAW_SIZE (FP0_REGNUM));
+  raw_buffer = (char *) alloca (2 * REGISTER_RAW_SIZE (FP0_REGNUM));
 
-  /* Get the data in raw format.  */
-  if (read_relative_register_raw_bytes (regnum, raw_buffer[HI]))
-    error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
-  if (REGISTER_RAW_SIZE (regnum) == 4)
+  if (REGISTER_RAW_SIZE (regnum) == 4 || mips2_fp_compat ())
     {
-      /* 4-byte registers: we can fit two registers per row. */
-      /* Also print every pair of 4-byte regs as an 8-byte double. */
-      if (read_relative_register_raw_bytes (regnum + 1, raw_buffer[LO]))
-       error ("can't read register %d (%s)",
-              regnum + 1, REGISTER_NAME (regnum + 1));
-
-      /* copy the two floats into one double, and unpack both */
-      memcpy (dbl_buffer, raw_buffer, 2 * REGISTER_RAW_SIZE (FP0_REGNUM));
-      flt1 = unpack_double (builtin_type_float, raw_buffer[HI], &inv1);
-      flt2 = unpack_double (builtin_type_float, raw_buffer[LO], &inv2);
-      doub = unpack_double (builtin_type_double, dbl_buffer, &inv3);
+      /* 4-byte registers: we can fit two registers per row.  */
+      /* Also print every pair of 4-byte regs as an 8-byte double.  */
+      mips_read_fp_register_single (regnum, raw_buffer);
+      flt1 = unpack_double (mips_float_register_type (), raw_buffer, &inv1);
+
+      mips_read_fp_register_single (regnum + 1, raw_buffer);
+      flt2 = unpack_double (mips_float_register_type (), raw_buffer, &inv2);
+
+      mips_read_fp_register_double (regnum, raw_buffer);
+      doub = unpack_double (mips_double_register_type (), raw_buffer, &inv3);
 
       printf_filtered (" %-5s", REGISTER_NAME (regnum));
       if (inv1)
@@ -2805,13 +4125,13 @@ do_fp_register_row (int regnum)
       regnum += 2;
     }
   else
-    {                          /* eight byte registers: print each one as float AND as double. */
-      int offset = 4 * (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG);
+    {
+      /* Eight byte registers: print each one as float AND as double.  */
+      mips_read_fp_register_single (regnum, raw_buffer);
+      flt1 = unpack_double (mips_double_register_type (), raw_buffer, &inv1);
 
-      memcpy (dbl_buffer, raw_buffer[HI], 2 * REGISTER_RAW_SIZE (FP0_REGNUM));
-      flt1 = unpack_double (builtin_type_float,
-                           &raw_buffer[HI][offset], &inv1);
-      doub = unpack_double (builtin_type_double, dbl_buffer, &inv3);
+      mips_read_fp_register_double (regnum, raw_buffer);
+      doub = unpack_double (mips_double_register_type (), raw_buffer, &inv3);
 
       printf_filtered (" %-5s: ", REGISTER_NAME (regnum));
       if (inv1)
@@ -2838,7 +4158,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;
@@ -2869,7 +4189,7 @@ do_gp_register_row (int regnum)
       if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
        break;                  /* end row: reached FP register */
       /* OK: get the data in raw format.  */
-      if (read_relative_register_raw_bytes (regnum, raw_buffer))
+      if (!frame_register_read (deprecated_selected_frame, regnum, raw_buffer))
        error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
       /* pad small registers */
       for (byte = 0; byte < (MIPS_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++)
@@ -2896,7 +4216,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 */
@@ -2921,16 +4241,7 @@ mips_do_registers_info (int regnum, int fpregs)
          else
            regnum = do_gp_register_row (regnum);       /* GP (int) regs */
        }
-    }
-}
-
-/* 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?  */
@@ -3171,7 +4482,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.
@@ -3306,10 +4617,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;
@@ -3328,34 +4658,321 @@ mips_extract_return_value (struct type *valtype,
 /* Given a return value in `valbuf' with a type `valtype', write it's
    value into the appropriate register. */
 
-void
-mips_store_return_value (struct type *valtype, char *valbuf)
+static void
+mips_eabi_store_return_value (struct type *valtype, char *valbuf)
+{
+  char *raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
+  struct return_value_word lo;
+  struct return_value_word hi;
+  return_value_location (valtype, &hi, &lo);
+
+  memset (raw_buffer, 0, sizeof (raw_buffer));
+  memcpy (raw_buffer + lo.reg_offset, valbuf + lo.buf_offset, lo.len);
+  deprecated_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);
+      deprecated_write_register_bytes (REGISTER_BYTE (hi.reg), raw_buffer,
+                                      REGISTER_RAW_SIZE (hi.reg));
+    }
+}
+
+static void
+mips_o64_store_return_value (struct type *valtype, char *valbuf)
 {
-  char raw_buffer[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);
 
   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));
+  deprecated_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));
+      deprecated_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 ();
@@ -3419,10 +5036,7 @@ set_mipsfpu_single_command (char *args, int from_tty)
 {
   mips_fpu_type = MIPS_FPU_SINGLE;
   mips_fpu_type_auto = 0;
-  if (GDB_MULTI_ARCH)
-    {
-      gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_SINGLE;
-    }
+  gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_SINGLE;
 }
 
 static void
@@ -3430,10 +5044,7 @@ set_mipsfpu_double_command (char *args, int from_tty)
 {
   mips_fpu_type = MIPS_FPU_DOUBLE;
   mips_fpu_type_auto = 0;
-  if (GDB_MULTI_ARCH)
-    {
-      gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_DOUBLE;
-    }
+  gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_DOUBLE;
 }
 
 static void
@@ -3441,10 +5052,7 @@ set_mipsfpu_none_command (char *args, int from_tty)
 {
   mips_fpu_type = MIPS_FPU_NONE;
   mips_fpu_type_auto = 0;
-  if (GDB_MULTI_ARCH)
-    {
-      gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_NONE;
-    }
+  gdbarch_tdep (current_gdbarch)->mips_fpu_type = MIPS_FPU_NONE;
 }
 
 static void
@@ -3487,7 +5095,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;
@@ -3553,10 +5161,10 @@ gdb_print_insn_mips (bfd_vma memaddr, disassemble_info *info)
      it's definitely a 16-bit function.  Otherwise, we have to just
      guess that if the address passed in is odd, it's 16-bits.  */
   if (proc_desc)
-    info->mach = pc_is_mips16 (PROC_LOW_ADDR (proc_desc)) ? 
+    info->mach = pc_is_mips16 (PROC_LOW_ADDR (proc_desc)) ?
       bfd_mach_mips16 : TM_PRINT_INSN_MACH;
   else
-    info->mach = pc_is_mips16 (memaddr) ? 
+    info->mach = pc_is_mips16 (memaddr) ?
       bfd_mach_mips16 : TM_PRINT_INSN_MACH;
 
   /* Round down the instruction address to the appropriate boundary.  */
@@ -3589,7 +5197,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.  */
 
-unsigned char *
+static const unsigned char *
 mips_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
 {
   if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
@@ -3671,7 +5279,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;
@@ -3754,7 +5362,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;
@@ -3782,7 +5390,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;
@@ -3832,7 +5440,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;
@@ -3874,59 +5482,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.
@@ -3949,7 +5545,7 @@ mips_stab_reg_to_regnum (int num)
 {
   if (num < 32)
     return num;
-  else 
+  else
     return num + FP0_REGNUM - 38;
 }
 
@@ -3978,6 +5574,47 @@ mips_integer_to_address (struct type *type, void *buf)
                                 TYPE_LENGTH (builtin_type_void_data_ptr));
 }
 
+static void
+mips_find_abi_section (bfd *abfd, asection *sect, void *obj)
+{
+  enum mips_abi *abip = (enum mips_abi *) obj;
+  const char *name = bfd_get_section_name (abfd, sect);
+
+  if (*abip != MIPS_ABI_UNKNOWN)
+    return;
+
+  if (strncmp (name, ".mdebug.", 8) != 0)
+    return;
+
+  if (strcmp (name, ".mdebug.abi32") == 0)
+    *abip = MIPS_ABI_O32;
+  else if (strcmp (name, ".mdebug.abiN32") == 0)
+    *abip = MIPS_ABI_N32;
+  else if (strcmp (name, ".mdebug.abi64") == 0)
+    *abip = MIPS_ABI_N64;
+  else if (strcmp (name, ".mdebug.abiO64") == 0)
+    *abip = MIPS_ABI_O64;
+  else if (strcmp (name, ".mdebug.eabi32") == 0)
+    *abip = MIPS_ABI_EABI32;
+  else if (strcmp (name, ".mdebug.eabi64") == 0)
+    *abip = MIPS_ABI_EABI64;
+  else
+    warning ("unsupported ABI %s.", name + 8);
+}
+
+static enum mips_abi
+global_mips_abi (void)
+{
+  int i;
+
+  for (i = 0; mips_abi_strings[i] != NULL; i++)
+    if (mips_abi_strings[i] == mips_abi_string)
+      return (enum mips_abi) i;
+
+  internal_error (__FILE__, __LINE__,
+                 "unknown ABI string");
+}
+
 static struct gdbarch *
 mips_gdbarch_init (struct gdbarch_info info,
                   struct gdbarch_list *arches)
@@ -3987,7 +5624,8 @@ mips_gdbarch_init (struct gdbarch_info info,
   struct gdbarch *gdbarch;
   struct gdbarch_tdep *tdep;
   int elf_flags;
-  enum mips_abi mips_abi;
+  enum mips_abi mips_abi, found_abi, wanted_abi;
+  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
 
   /* Reset the disassembly info, in case it was set to something
      non-default.  */
@@ -3995,14 +5633,20 @@ mips_gdbarch_init (struct gdbarch_info info,
   tm_print_insn_info.arch = bfd_arch_unknown;
   tm_print_insn_info.mach = 0;
 
-  /* Extract the elf_flags if available */
-  if (info.abfd != NULL
-      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
-    elf_flags = elf_elfheader (info.abfd)->e_flags;
-  else
-    elf_flags = 0;
+  elf_flags = 0;
 
-  /* Check ELF_FLAGS to see if it specifies the ABI being used. */
+  if (info.abfd)
+    {
+      /* First of all, extract the elf_flags, if available.  */
+      if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+       elf_flags = elf_elfheader (info.abfd)->e_flags;
+
+      /* Try to determine the OS ABI of the object we are loading.  If
+        we end up with `unknown', just leave it that way.  */
+      osabi = gdbarch_lookup_osabi (info.abfd);
+    }
+
+  /* Check ELF_FLAGS to see if it specifies the ABI being used.  */
   switch ((elf_flags & EF_MIPS_ABI))
     {
     case E_MIPS_ABI_O32:
@@ -4025,7 +5669,16 @@ mips_gdbarch_init (struct gdbarch_info info,
       break;
     }
 
-  /* Try the architecture for any hint of the corect ABI */
+  /* GCC creates a pseudo-section whose name describes the ABI.  */
+  if (mips_abi == MIPS_ABI_UNKNOWN && info.abfd != NULL)
+    bfd_map_over_sections (info.abfd, mips_find_abi_section, &mips_abi);
+
+  /* If we have no bfd, then mips_abi will still be MIPS_ABI_UNKNOWN.
+     Use the ABI from the last architecture if there is one.  */
+  if (info.abfd == NULL && arches != NULL)
+    mips_abi = gdbarch_tdep (arches->gdbarch)->found_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)
@@ -4041,14 +5694,27 @@ mips_gdbarch_init (struct gdbarch_info info,
          break;
        case bfd_mach_mips8000:
        case bfd_mach_mips10000:
-         mips_abi = MIPS_ABI_N32;
+         /* 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;
+         else
+           mips_abi = MIPS_ABI_N32;
          break;
        }
     }
-#ifdef MIPS_DEFAULT_ABI
+
   if (mips_abi == MIPS_ABI_UNKNOWN)
-    mips_abi = MIPS_DEFAULT_ABI;
-#endif
+    mips_abi = MIPS_ABI_O32;
+
+  /* Now that we have found what the ABI for this binary would be,
+     check whether the user is overriding it.  */
+  found_abi = mips_abi;
+  wanted_abi = global_mips_abi ();
+  if (wanted_abi != MIPS_ABI_UNKNOWN)
+    mips_abi = wanted_abi;
 
   if (gdbarch_debug)
     {
@@ -4058,6 +5724,9 @@ mips_gdbarch_init (struct gdbarch_info info,
       fprintf_unfiltered (gdb_stdlog,
                          "mips_gdbarch_init: mips_abi = %d\n",
                          mips_abi);
+      fprintf_unfiltered (gdb_stdlog,
+                         "mips_gdbarch_init: found_mips_abi = %d\n",
+                         found_abi);
     }
 
   /* try to find a pre-existing architecture */
@@ -4066,95 +5735,129 @@ 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)
        continue;
-      return arches->gdbarch;
+      if (gdbarch_tdep (arches->gdbarch)->osabi == osabi)
+        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);
+
+  if (osabi == GDB_OSABI_IRIX)
+    set_gdbarch_num_regs (gdbarch, 71);
+  else
+    set_gdbarch_num_regs (gdbarch, 90);
+
   switch (mips_abi)
     {
     case MIPS_ABI_O32:
-      tdep->mips_abi_string = "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:
-      tdep->mips_abi_string = "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; 
+      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:
-      tdep->mips_abi_string = "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:
-      tdep->mips_abi_string = "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_abi_string = "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);
@@ -4170,21 +5873,46 @@ 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:
-      tdep->mips_abi_string = "default";
-      tdep->mips_default_saved_regsize = MIPS_REGSIZE;
-      tdep->mips_default_stack_argsize = MIPS_REGSIZE;
-      tdep->mips_fp_register_double = (REGISTER_VIRTUAL_SIZE (FP0_REGNUM) == 8);
+    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 = 1;
-      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);
+      set_gdbarch_long_bit (gdbarch, 64);
+      set_gdbarch_ptr_bit (gdbarch, 64);
       set_gdbarch_long_long_bit (gdbarch, 64);
+
+      /* Set up the disassembler info, so that we get the right
+        register names from libopcodes.  */
+      tm_print_insn_info.flavour = bfd_target_elf_flavour;
+      tm_print_insn_info.arch = bfd_arch_mips;
+      if (info.bfd_arch_info != NULL
+         && info.bfd_arch_info->arch == bfd_arch_mips
+         && info.bfd_arch_info->mach)
+       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__,
+                     "unknown ABI in switch");
     }
 
   /* FIXME: jlarmour/2000-04-07: There *is* a flag EF_MIPS_32BIT_MODE
@@ -4193,9 +5921,9 @@ 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,
      but to set this flag before gcc is built with such multilibs will
      break too many systems.''
@@ -4203,10 +5931,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)
@@ -4233,51 +5961,68 @@ 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_write_fp (gdbarch, generic_target_write_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
-     blockframe.c near reference to INIT_FRAME_PC_FIRST.  */
-  set_gdbarch_init_frame_pc_first (gdbarch, mips_init_frame_pc_first);
-  set_gdbarch_init_frame_pc (gdbarch, init_frame_pc_noop);
+     blockframe.c near reference to DEPRECATED_INIT_FRAME_PC_FIRST.  */
+  set_gdbarch_deprecated_init_frame_pc_first (gdbarch, mips_init_frame_pc_first);
+  set_gdbarch_deprecated_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 */
 
   set_gdbarch_call_dummy_p (gdbarch, 1);
   set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
-  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, generic_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_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
+  set_gdbarch_fix_call_dummy (gdbarch, mips_fix_call_dummy);
   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_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
+  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_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);
@@ -4290,9 +6035,44 @@ mips_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address);
   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_deprecated_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;
 }
 
+static void
+mips_abi_update (char *ignore_args, int from_tty, 
+                struct cmd_list_element *c)
+{
+  struct gdbarch_info info;
+
+  /* Force the architecture to update, and (if it's a MIPS architecture)
+     mips_gdbarch_init will take care of the rest.  */
+  gdbarch_info_init (&info);
+  gdbarch_update_p (info);
+}
+
 static void
 mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
 {
@@ -4334,7 +6114,7 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
       fprintf_unfiltered (file,
                          "mips_dump_tdep: tdep->mips_abi = %d (%s)\n",
                          tdep->mips_abi,
-                         tdep->mips_abi_string);
+                         mips_abi_strings[tdep->mips_abi]);
       fprintf_unfiltered (file,
                          "mips_dump_tdep: mips_mask_address_p() %d (default %d)\n",
                          mips_mask_address_p (),
@@ -4370,9 +6150,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);
@@ -4399,24 +6176,12 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: CAUSE_REGNUM = %d\n",
                      CAUSE_REGNUM);
-  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));
   fprintf_unfiltered (file,
                      "mips_dump_tdep: DWARF_REG_TO_REGNUM # %s\n",
                      XSTRING (DWARF_REG_TO_REGNUM (REGNUM)));
   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);
@@ -4432,12 +6197,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: GDB_TARGET_IS_MIPS64 = %d\n",
                      GDB_TARGET_IS_MIPS64);
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: GDB_TARGET_MASK_DISAS_PC # %s\n",
-                     XSTRING (GDB_TARGET_MASK_DISAS_PC (PC)));
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: GDB_TARGET_UNMASK_DISAS_PC # %s\n",
-                     XSTRING (GDB_TARGET_UNMASK_DISAS_PC (PC)));
   fprintf_unfiltered (file,
                      "mips_dump_tdep: GEN_REG_SAVE_MASK = %d\n",
                      GEN_REG_SAVE_MASK);
@@ -4454,9 +6213,6 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: IGNORE_HELPER_CALL # %s\n",
                      XSTRING (IGNORE_HELPER_CALL (PC)));
-  fprintf_unfiltered (file,
-                     "mips_dump_tdep: IN_SIGTRAMP # %s\n",
-                     XSTRING (IN_SIGTRAMP (PC, NAME)));
   fprintf_unfiltered (file,
                      "mips_dump_tdep: IN_SOLIB_CALL_TRAMPOLINE # %s\n",
                      XSTRING (IN_SOLIB_CALL_TRAMPOLINE (PC, NAME)));
@@ -4516,11 +6272,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,
@@ -4701,6 +6452,10 @@ mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                      "mips_dump_tdep: _PROC_MAGIC_ = %d\n",
                      _PROC_MAGIC_);
+
+  fprintf_unfiltered (file,
+                     "mips_dump_tdep: OS ABI = %s\n",
+                     gdbarch_osabi_name (tdep->osabi));
 }
 
 void
@@ -4709,6 +6464,11 @@ _initialize_mips_tdep (void)
   static struct cmd_list_element *mipsfpulist = NULL;
   struct cmd_list_element *c;
 
+  mips_abi_string = mips_abi_strings [MIPS_ABI_UNKNOWN];
+  if (MIPS_ABI_LAST + 1
+      != sizeof (mips_abi_strings) / sizeof (mips_abi_strings[0]))
+    internal_error (__FILE__, __LINE__, "mips_abi_strings out of sync");
+
   gdbarch_register (bfd_arch_mips, mips_gdbarch_init, mips_dump_tdep);
   if (!tm_print_insn)          /* Someone may have already set it */
     tm_print_insn = gdb_print_insn_mips;
@@ -4751,6 +6511,22 @@ This option can be set to one of:\n\
                                       &setmipscmdlist),
                     &showmipscmdlist);
 
+  /* Allow the user to override the ABI. */
+  c = add_set_enum_cmd
+    ("abi", class_obscure, mips_abi_strings, &mips_abi_string,
+     "Set the ABI used by this program.\n"
+     "This option can be set to one of:\n"
+     "  auto  - the default ABI associated with the current binary\n"
+     "  o32\n"
+     "  o64\n"
+     "  n32\n"
+     "  n64\n"
+     "  eabi32\n"
+     "  eabi64",
+     &setmipscmdlist);
+  add_show_from_set (c, &showmipscmdlist);
+  set_cmd_sfunc (c, mips_abi_update);
+
   /* Let the user turn off floating point and set the fence post for
      heuristic_proc_start.  */
 
@@ -4779,21 +6555,6 @@ This option can be set to one of:\n\
           "Show current use of MIPS floating-point coprocessor target.",
           &showlist);
 
-#if !GDB_MULTI_ARCH
-  c = add_set_cmd ("processor", class_support, var_string_noescape,
-                  (char *) &tmp_mips_processor_type,
-                  "Set the type of MIPS processor in use.\n\
-Set this to be able to access processor-type-specific registers.\n\
-",
-                  &setlist);
-  c->function.cfunc = mips_set_processor_type_command;
-  c = add_show_from_set (c, &showlist);
-  c->function.cfunc = mips_show_processor_type_command;
-
-  tmp_mips_processor_type = xstrdup (DEFAULT_MIPS_TYPE);
-  mips_set_processor_type_command (xstrdup (DEFAULT_MIPS_TYPE), 0);
-#endif
-
   /* We really would like to have both "0" and "unlimited" work, but
      command.c doesn't deal with that.  So make it a var_zinteger
      because the user can always use "999999" or some such for unlimited.  */
@@ -4807,18 +6568,18 @@ search.  The only need to set it is when debugging a stripped executable.",
                   &setlist);
   /* We need to throw away the frame cache when we set this, since it
      might change our ability to get backtraces.  */
-  c->function.sfunc = reinit_frame_cache_sfunc;
+  set_cmd_sfunc (c, reinit_frame_cache_sfunc);
   add_show_from_set (c, &showlist);
 
   /* Allow the user to control whether the upper bits of 64-bit
      addresses should be zeroed.  */
-  c = add_set_auto_boolean_cmd ("mask-address", no_class, &mask_address_var,
-                               "Set zeroing of upper 32 bits of 64-bit addresses.\n\
-Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to allow GDB to determine\n\
-the correct value.\n",
-                               &setmipscmdlist);
-  add_cmd ("mask-address", no_class, show_mask_address,
-              "Show current mask-address value", &showmipscmdlist);
+  add_setshow_auto_boolean_cmd ("mask-address", no_class, &mask_address_var, "\
+Set zeroing of upper 32 bits of 64-bit addresses.\n\
+Use \"on\" to enable the masking, \"off\" to disable it and \"auto\" to \n\
+allow GDB to determine the correct value.\n", "\
+Show zeroing of upper 32 bits of 64-bit addresses.",
+                               NULL, show_mask_address,
+                               &setmipscmdlist, &showmipscmdlist);
 
   /* Allow the user to control the size of 32 bit registers within the
      raw remote packet.  */
@@ -4839,4 +6600,3 @@ that would transfer 32 bits for some registers (e.g. SR, FSR) and\n\
 When non-zero, mips specific debugging is enabled.", &setdebuglist),
                     &showdebuglist);
 }
-
This page took 0.098929 seconds and 4 git commands to generate.