* mdebugread.c (parse_symbol): Use new variable
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index d2d712aff718548a396d4aae91a67cd581b9ff55..d708b6acabc7ec643592d6e09f46a7b4327e25ea 100644 (file)
@@ -1,5 +1,6 @@
 /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
 /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
-   Copyright 1988, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+   Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995
+   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.
 
    Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
    and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
 
@@ -29,20 +30,112 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "gdbcore.h"
 #include "symfile.h"
 #include "objfiles.h"
 #include "gdbcore.h"
 #include "symfile.h"
 #include "objfiles.h"
+#include "gdbtypes.h"
 
 #include "opcode/mips.h"
 
 #define VM_MIN_ADDRESS (unsigned)0x400000
 
 #include "opcode/mips.h"
 
 #define VM_MIN_ADDRESS (unsigned)0x400000
+
+/* FIXME: Put this declaration in frame.h.  */
+extern struct obstack frame_cache_obstack;
 \f
 \f
+#if 0
 static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
 static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+#endif
+
+void mips_set_processor_type_command PARAMS ((char *, int));
+
+int mips_set_processor_type PARAMS ((char *));
+
+static void mips_show_processor_type_command PARAMS ((char *, int));
+
+static void reinit_frame_cache_sfunc PARAMS ((char *, int,
+                                             struct cmd_list_element *));
+
+/* This value is the model of MIPS in use.  It is derived from the value
+   of the PrID register.  */
+
+char *mips_processor_type;
+
+char *tmp_mips_processor_type;
 
 /* Some MIPS boards don't support floating point, so we permit the
    user to turn it off.  */
 
 /* Some MIPS boards don't support floating point, so we permit the
    user to turn it off.  */
+
 int mips_fpu = 1;
 
 int mips_fpu = 1;
 
+/* A set of original names, to be used when restoring back to generic
+   registers from a specific set.  */
+
+char *mips_generic_reg_names[] = REGISTER_NAMES;
+
+/* Names of IDT R3041 registers.  */
+
+char *mips_r3041_reg_names[] = {
+       "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
+       "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
+       "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
+       "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra",
+       "sr",   "lo",   "hi",   "bad",  "cause","pc",
+       "f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7",
+       "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",   "",
+       "",     "",     "bus",  "ccfg", "",     "",     "",     "",
+       "",     "",     "port", "cmp",  "",     "",     "epc",  "prid",
+};
+
+/* Names of IDT R3051 registers.  */
+
+char *mips_r3051_reg_names[] = {
+       "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
+       "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
+       "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
+       "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra",
+       "sr",   "lo",   "hi",   "bad",  "cause","pc",
+       "f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7",
+       "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",   "",
+       "inx",  "rand", "elo",  "",     "ctxt", "",     "",     "",
+       "",     "",     "ehi",  "",     "",     "",     "epc",  "prid",
+};
+
+/* Names of IDT R3081 registers.  */
+
+char *mips_r3081_reg_names[] = {
+       "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
+       "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
+       "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
+       "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra",
+       "sr",   "lo",   "hi",   "bad",  "cause","pc",
+       "f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7",
+       "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",   "",
+       "inx",  "rand", "elo",  "cfg",  "ctxt", "",     "",     "",
+       "",     "",     "ehi",  "",     "",     "",     "epc",  "prid",
+};
+
+struct {
+  char *name;
+  char **regnames;
+} mips_processor_type_table[] = {
+  { "generic", mips_generic_reg_names },
+  { "r3041", mips_r3041_reg_names },
+  { "r3051", mips_r3051_reg_names },
+  { "r3071", mips_r3081_reg_names },
+  { "r3081", mips_r3081_reg_names },
+  { NULL, NULL }
+};
+
 /* Heuristic_proc_start may hunt through the text section for a long
    time across a 2400 baud serial line.  Allows the user to limit this
    search.  */
 /* Heuristic_proc_start may hunt through the text section for a long
    time across a 2400 baud serial line.  Allows the user to limit this
    search.  */
+
 static unsigned int heuristic_fence_post = 0;
 
 #define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */
 static unsigned int heuristic_fence_post = 0;
 
 #define PROC_LOW_ADDR(proc) ((proc)->pdr.adr) /* least address */
@@ -66,42 +159,184 @@ struct linked_proc_info
 } *linked_proc_desc_table = NULL;
 
 \f
 } *linked_proc_desc_table = NULL;
 
 \f
-#define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno)
+/* Guaranteed to set fci->saved_regs to some values (it never leaves it
+   NULL).  */
+
+void
+mips_find_saved_regs (fci)
+     struct frame_info *fci;
+{
+  int ireg;
+  CORE_ADDR reg_position;
+  /* r0 bit means kernel trap */
+  int kernel_trap;
+  /* What registers have been saved?  Bitmasks.  */
+  unsigned long gen_mask, float_mask;
+  mips_extra_func_info_t proc_desc;
+
+  fci->saved_regs = (struct frame_saved_regs *)
+    obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
+  memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
+
+  proc_desc = fci->proc_desc;
+  if (proc_desc == NULL)
+    /* I'm not sure how/whether this can happen.  Normally when we can't
+       find a proc_desc, we "synthesize" one using heuristic_proc_desc
+       and set the saved_regs right away.  */
+    return;
+
+  kernel_trap = PROC_REG_MASK(proc_desc) & 1;
+  gen_mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
+  float_mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
+
+  if (/* In any frame other than the innermost, 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
+
+      /* In a dummy frame we know exactly where things are saved.  */
+      && !PROC_DESC_IS_DUMMY (proc_desc)
+
+      /* Not sure exactly what kernel_trap means, but if it means
+        the kernel saves the registers without a prologue doing it,
+        we better not examine the prologue to see whether registers
+        have been saved yet.  */
+      && !kernel_trap)
+    {
+      /* We need to figure out whether the registers that the proc_desc
+        claims are saved have been saved yet.  */
+
+      CORE_ADDR addr;
+      int status;
+      char buf[4];
+      unsigned long inst;
+
+      /* Bitmasks; set if we have found a save for the register.  */
+      unsigned long gen_save_found = 0;
+      unsigned long float_save_found = 0;
+
+      for (addr = PROC_LOW_ADDR (proc_desc);
+          addr < fci->pc /*&& (gen_mask != gen_save_found
+                             || float_mask != float_save_found)*/;
+          addr += 4)
+       {
+         status = read_memory_nobpt (addr, buf, 4);
+         if (status)
+           memory_error (status, addr);
+         inst = extract_unsigned_integer (buf, 4);
+         if (/* sw reg,n($sp) */
+             (inst & 0xffe00000) == 0xafa00000
+
+             /* sw reg,n($r30) */
+             || (inst & 0xffe00000) == 0xafc00000
+
+             /* sd reg,n($sp) */
+             || (inst & 0xffe00000) == 0xffa00000)
+           {
+             /* It might be possible to use the instruction to
+                find the offset, rather than the code below which
+                is based on things being in a certain order in the
+                frame, but figuring out what the instruction's offset
+                is relative to might be a little tricky.  */
+             int reg = (inst & 0x001f0000) >> 16;
+             gen_save_found |= (1 << reg);
+           }
+         else if (/* swc1 freg,n($sp) */
+                  (inst & 0xffe00000) == 0xe7a00000
+
+                  /* swc1 freg,n($r30) */
+                  || (inst & 0xffe00000) == 0xe7c00000
+
+                   /* sdc1 freg,n($sp) */
+                   || (inst & 0xffe00000) == 0xf7a00000)
+
+           {
+             int reg = ((inst & 0x001f0000) >> 16);
+             float_save_found |= (1 << reg);
+           }
+       }
+      gen_mask = gen_save_found;
+      float_mask = float_save_found;
+    }
+
+  /* Fill in the offsets for the registers which gen_mask says
+     were saved.  */
+  reg_position = fci->frame + PROC_REG_OFFSET (proc_desc);
+  for (ireg= 31; gen_mask; --ireg, gen_mask <<= 1)
+    if (gen_mask & 0x80000000)
+      {
+       fci->saved_regs->regs[ireg] = reg_position;
+       reg_position -= MIPS_REGSIZE;
+      }
+  /* Fill in the offsets for the registers which float_mask says
+     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. */
+  reg_position += 4;
+  for (ireg = 31; float_mask; --ireg, float_mask <<= 1)
+    if (float_mask & 0x80000000)
+      {
+       fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
+       reg_position -= MIPS_REGSIZE;
+      }
+
+  fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
+}
 
 static int
 read_next_frame_reg(fi, regno)
 
 static int
 read_next_frame_reg(fi, regno)
-     FRAME fi;
+     struct frame_info *fi;
      int regno;
 {
   /* If it is the frame for sigtramp we have a complete sigcontext
      int regno;
 {
   /* If it is the frame for sigtramp we have a complete sigcontext
-     immediately below the frame and we get the saved registers from there.
+     somewhere above the frame and we get the saved registers from there.
      If the stack layout for sigtramp changes we might have to change these
      If the stack layout for sigtramp changes we might have to change these
-     constants and the companion fixup_sigtramp in mipsread.c  */
+     constants and the companion fixup_sigtramp in mdebugread.c  */
 #ifndef SIGFRAME_BASE
 #ifndef SIGFRAME_BASE
-#define SIGFRAME_BASE          0x12c   /* sizeof(sigcontext) */
-#define SIGFRAME_PC_OFF                (-SIGFRAME_BASE + 2 * 4)
-#define SIGFRAME_REGSAVE_OFF   (-SIGFRAME_BASE + 3 * 4)
+/* To satisfy alignment restrictions the sigcontext is located 4 bytes
+   above the sigtramp frame.  */
+#define SIGFRAME_BASE          4
+#define SIGFRAME_PC_OFF                (SIGFRAME_BASE + 2 * 4)
+#define SIGFRAME_REGSAVE_OFF   (SIGFRAME_BASE + 3 * 4)
+#endif
+#ifndef SIGFRAME_REG_SIZE
+#define SIGFRAME_REG_SIZE      4
 #endif
   for (; fi; fi = fi->next)
 #endif
   for (; fi; fi = fi->next)
-      if (in_sigtramp(fi->pc, 0)) {
+    {
+      if (fi->signal_handler_caller)
+       {
          int offset;
          if (regno == PC_REGNUM) offset = SIGFRAME_PC_OFF;
          int offset;
          if (regno == PC_REGNUM) offset = SIGFRAME_PC_OFF;
-         else if (regno < 32) offset = SIGFRAME_REGSAVE_OFF + regno * 4;
+         else if (regno < 32) offset = (SIGFRAME_REGSAVE_OFF
+                                        + regno * SIGFRAME_REG_SIZE);
          else return 0;
          else return 0;
-         return read_memory_integer(fi->frame + offset, 4);
-      }
+         return read_memory_integer(fi->frame + offset, MIPS_REGSIZE);
+       }
       else if (regno == SP_REGNUM) return fi->frame;
       else if (regno == SP_REGNUM) return fi->frame;
-      else if (fi->saved_regs->regs[regno])
-       return read_memory_integer(fi->saved_regs->regs[regno], 4);
-  return read_register(regno);
+      else
+       {
+         if (fi->saved_regs == NULL)
+           mips_find_saved_regs (fi);
+         if (fi->saved_regs->regs[regno])
+           return read_memory_integer(fi->saved_regs->regs[regno], MIPS_REGSIZE);
+       }
+    }
+  return read_register (regno);
 }
 
 int
 mips_frame_saved_pc(frame)
 }
 
 int
 mips_frame_saved_pc(frame)
-     FRAME frame;
+     struct frame_info *frame;
 {
   mips_extra_func_info_t proc_desc = frame->proc_desc;
 {
   mips_extra_func_info_t proc_desc = frame->proc_desc;
-  int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM;
+  /* 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
+             : (proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM);
 
   if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
       return read_memory_integer(frame->frame - 4, 4);
 
   if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
       return read_memory_integer(frame->frame - 4, 4);
@@ -177,21 +412,22 @@ Otherwise, you told GDB there was a function where there isn't one, or\n\
 static mips_extra_func_info_t
 heuristic_proc_desc(start_pc, limit_pc, next_frame)
     CORE_ADDR start_pc, limit_pc;
 static mips_extra_func_info_t
 heuristic_proc_desc(start_pc, limit_pc, next_frame)
     CORE_ADDR start_pc, limit_pc;
-    FRAME next_frame;
+    struct frame_info *next_frame;
 {
 {
-    CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM);
+    CORE_ADDR sp = read_next_frame_reg (next_frame, SP_REGNUM);
     CORE_ADDR cur_pc;
     int frame_size;
     int has_frame_reg = 0;
     CORE_ADDR cur_pc;
     int frame_size;
     int has_frame_reg = 0;
-    int reg30; /* Value of $r30. Used by gcc for frame-pointer */
+    int reg30 = 0; /* Value of $r30. Used by gcc for frame-pointer */
     unsigned long reg_mask = 0;
 
     if (start_pc == 0) return NULL;
     unsigned long reg_mask = 0;
 
     if (start_pc == 0) return NULL;
-    memset(&temp_proc_desc, '\0', sizeof(temp_proc_desc));
-    memset(&temp_saved_regs, '\0', sizeof(struct frame_saved_regs));
-    PROC_LOW_ADDR(&temp_proc_desc) = start_pc;
+    memset (&temp_proc_desc, '\0', sizeof(temp_proc_desc));
+    memset (&temp_saved_regs, '\0', sizeof(struct frame_saved_regs));
+    PROC_LOW_ADDR (&temp_proc_desc) = start_pc;
 
 
-    if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200;
+    if (start_pc + 200 < limit_pc)
+      limit_pc = start_pc + 200;
   restart:
     frame_size = 0;
     for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) {
   restart:
     frame_size = 0;
     for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) {
@@ -210,19 +446,19 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame)
        else if ((word & 0xFFE00000) == 0xafa00000) { /* sw reg,offset($sp) */
            int reg = (word & 0x001F0000) >> 16;
            reg_mask |= 1 << reg;
        else if ((word & 0xFFE00000) == 0xafa00000) { /* sw reg,offset($sp) */
            int reg = (word & 0x001F0000) >> 16;
            reg_mask |= 1 << reg;
-           temp_saved_regs.regs[reg] = sp + (short)word;
+           temp_saved_regs.regs[reg] = sp + (word & 0xffff);
        }
        else if ((word & 0xFFFF0000) == 0x27be0000) { /* addiu $30,$sp,size */
        }
        else if ((word & 0xFFFF0000) == 0x27be0000) { /* addiu $30,$sp,size */
-           if ((unsigned short)word != frame_size)
-               reg30 = sp + (unsigned short)word;
+           if ((word & 0xffff) != frame_size)
+               reg30 = sp + (word & 0xffff);
            else if (!has_frame_reg) {
                int alloca_adjust;
                has_frame_reg = 1;
                reg30 = read_next_frame_reg(next_frame, 30);
            else if (!has_frame_reg) {
                int alloca_adjust;
                has_frame_reg = 1;
                reg30 = read_next_frame_reg(next_frame, 30);
-               alloca_adjust = reg30 - (sp + (unsigned short)word);
+               alloca_adjust = reg30 - (sp + (word & 0xffff));
                if (alloca_adjust > 0) {
                    /* FP > SP + frame_size. This may be because
                if (alloca_adjust > 0) {
                    /* FP > SP + frame_size. This may be because
-                   /* of an alloca or somethings similar.
+                    * of an alloca or somethings similar.
                     * Fix sp to "pre-alloca" value, and try again.
                     */
                    sp += alloca_adjust;
                     * Fix sp to "pre-alloca" value, and try again.
                     */
                    sp += alloca_adjust;
@@ -233,7 +469,7 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame)
        else if ((word & 0xFFE00000) == 0xafc00000) { /* sw reg,offset($30) */
            int reg = (word & 0x001F0000) >> 16;
            reg_mask |= 1 << reg;
        else if ((word & 0xFFE00000) == 0xafc00000) { /* sw reg,offset($30) */
            int reg = (word & 0x001F0000) >> 16;
            reg_mask |= 1 << reg;
-           temp_saved_regs.regs[reg] = reg30 + (short)word;
+           temp_saved_regs.regs[reg] = reg30 + (word & 0xffff);
        }
     }
     if (has_frame_reg) {
        }
     }
     if (has_frame_reg) {
@@ -250,9 +486,9 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame)
 }
 
 static mips_extra_func_info_t
 }
 
 static mips_extra_func_info_t
-find_proc_desc(pc, next_frame)
-    CORE_ADDR pc;
-    FRAME next_frame;
+find_proc_desc (pc, next_frame)
+     CORE_ADDR pc;
+     struct frame_info *next_frame;
 {
   mips_extra_func_info_t proc_desc;
   struct block *b = block_for_pc(pc);
 {
   mips_extra_func_info_t proc_desc;
   struct block *b = block_for_pc(pc);
@@ -282,7 +518,7 @@ find_proc_desc(pc, next_frame)
         * THEN create a "heuristic" proc_desc (by analyzing
         * the actual code) to replace the "official" proc_desc.
         */
         * THEN create a "heuristic" proc_desc (by analyzing
         * the actual code) to replace the "official" proc_desc.
         */
-       proc_desc = (mips_extra_func_info_t)SYMBOL_VALUE(sym);
+       proc_desc = (mips_extra_func_info_t) SYMBOL_VALUE (sym);
        if (next_frame == NULL) {
            struct symtab_and_line val;
            struct symbol *proc_symbol =
        if (next_frame == NULL) {
            struct symtab_and_line val;
            struct symbol *proc_symbol =
@@ -296,9 +532,10 @@ find_proc_desc(pc, next_frame)
            }
            if (!proc_symbol || pc < val.pc) {
                mips_extra_func_info_t found_heuristic =
            }
            if (!proc_symbol || pc < val.pc) {
                mips_extra_func_info_t found_heuristic =
-                   heuristic_proc_desc(PROC_LOW_ADDR(proc_desc),
-                                       pc, next_frame);
-               if (found_heuristic) proc_desc = found_heuristic;
+                 heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
+                                      pc, next_frame);
+               if (found_heuristic)
+                 proc_desc = found_heuristic;
            }
        }
     }
            }
        }
     }
@@ -310,10 +547,11 @@ find_proc_desc(pc, next_frame)
         heuristic_proc_desc knows how to create them! */
 
       register struct linked_proc_info *link;
         heuristic_proc_desc knows how to create them! */
 
       register struct linked_proc_info *link;
+
       for (link = linked_proc_desc_table; link; link = link->next)
       for (link = linked_proc_desc_table; link; link = link->next)
-         if (PROC_LOW_ADDR(&link->info) <= pc
-             && PROC_HIGH_ADDR(&link->info) > pc)
-             return &link->info;
+       if (PROC_LOW_ADDR(&link->info) <= pc
+           && PROC_HIGH_ADDR(&link->info) > pc)
+         return &link->info;
 
       if (startaddr == 0)
        startaddr = heuristic_proc_start (pc);
 
       if (startaddr == 0)
        startaddr = heuristic_proc_start (pc);
@@ -326,9 +564,9 @@ find_proc_desc(pc, next_frame)
 
 mips_extra_func_info_t cached_proc_desc;
 
 
 mips_extra_func_info_t cached_proc_desc;
 
-FRAME_ADDR
+CORE_ADDR
 mips_frame_chain(frame)
 mips_frame_chain(frame)
-    FRAME frame;
+    struct frame_info *frame;
 {
     mips_extra_func_info_t proc_desc;
     CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
 {
     mips_extra_func_info_t proc_desc;
     CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
@@ -341,94 +579,53 @@ mips_frame_chain(frame)
       return 0;
 
     cached_proc_desc = proc_desc;
       return 0;
 
     cached_proc_desc = proc_desc;
-    return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
-      + PROC_FRAME_OFFSET(proc_desc);
+
+    /* If no frame pointer and frame size is zero, we must be at end
+       of stack (or otherwise hosed).  If we don't check frame size,
+       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)
+      return 0;
+    else
+      return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc))
+       + PROC_FRAME_OFFSET(proc_desc);
 }
 
 void
 init_extra_frame_info(fci)
      struct frame_info *fci;
 {
 }
 
 void
 init_extra_frame_info(fci)
      struct frame_info *fci;
 {
-  extern struct obstack frame_cache_obstack;
   /* 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);
 
   /* 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);
 
-  fci->saved_regs = (struct frame_saved_regs*)
-    obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
-  memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
+  fci->saved_regs = NULL;
   fci->proc_desc =
     proc_desc == &temp_proc_desc ? 0 : proc_desc;
   if (proc_desc)
     {
   fci->proc_desc =
     proc_desc == &temp_proc_desc ? 0 : proc_desc;
   if (proc_desc)
     {
-      int ireg;
-      CORE_ADDR reg_position;
-      unsigned long mask;
-      /* r0 bit means kernel trap */
-      int kernel_trap = PROC_REG_MASK(proc_desc) & 1;
-
       /* Fixup frame-pointer - only needed for top frame */
       /* Fixup frame-pointer - only needed for top frame */
-      /* This may not be quite right, if proc has a real frame register */
-      if (fci->pc == PROC_LOW_ADDR(proc_desc) && !PROC_DESC_IS_DUMMY(proc_desc))
-       fci->frame = read_register (SP_REGNUM);
+      /* This may not be quite right, if proc has a real frame register.
+        Get the value of the frame relative sp, procedure might have been
+        interrupted by a signal at it's very start.  */
+      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
       else
-       fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
-                     + PROC_FRAME_OFFSET(proc_desc);
-
-      /* If this is the innermost frame, and we are still in the
-        prologue (loosely defined), then the registers may not have
-        been saved yet.  */
-      if (fci->next == NULL
-          && !PROC_DESC_IS_DUMMY(proc_desc)
-         && mips_in_lenient_prologue (PROC_LOW_ADDR (proc_desc), fci->pc))
-       {
-         /* Can't just say that the registers are not saved, because they
-            might get clobbered halfway through the prologue.
-            heuristic_proc_desc already has the right code to figure out
-            exactly what has been saved, so use it.  As far as I know we
-            could be doing this (as we do on the 68k, for example)
-            regardless of whether we are in the prologue; I'm leaving in
-            the check for being in the prologue only out of conservatism
-            (I'm not sure whether heuristic_proc_desc handles all cases,
-            for example).
-
-            This stuff is ugly (and getting uglier by the minute).  Probably
-            the best way to clean it up is to ignore the proc_desc's from
-            the symbols altogher, and get all the information we need by
-            examining the prologue (provided we can make the prologue
-            examining code good enough to get all the cases...).  */
-         proc_desc =
-           heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
-                                fci->pc,
-                                fci->next);
-       }
+       fci->frame =
+         read_next_frame_reg (fci->next, PROC_FRAME_REG (proc_desc))
+           + PROC_FRAME_OFFSET (proc_desc);
 
       if (proc_desc == &temp_proc_desc)
 
       if (proc_desc == &temp_proc_desc)
-       *fci->saved_regs = temp_saved_regs;
-      else
        {
        {
-         /* find which general-purpose registers were saved */
-         reg_position = fci->frame + PROC_REG_OFFSET(proc_desc);
-         mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc);
-         for (ireg= 31; mask; --ireg, mask <<= 1)
-           if (mask & 0x80000000)
-             {
-               fci->saved_regs->regs[ireg] = reg_position;
-               reg_position -= 4;
-             }
-         /* find which floating-point registers 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. */
-         reg_position += 4;
-         mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
-         for (ireg = 31; mask; --ireg, mask <<= 1)
-           if (mask & 0x80000000)
-             {
-               fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
-               reg_position -= 4;
-             }
+         fci->saved_regs = (struct frame_saved_regs*)
+           obstack_alloc (&frame_cache_obstack,
+                          sizeof (struct frame_saved_regs));
+         *fci->saved_regs = temp_saved_regs;
+         fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
        }
 
       /* hack: if argument regs are saved, guess these contain args */
        }
 
       /* hack: if argument regs are saved, guess these contain args */
@@ -437,8 +634,6 @@ init_extra_frame_info(fci)
       else if ((PROC_REG_MASK(proc_desc) & 0x40) == 0) fci->num_args = 3;
       else if ((PROC_REG_MASK(proc_desc) & 0x20) == 0) fci->num_args = 2;
       else if ((PROC_REG_MASK(proc_desc) & 0x10) == 0) fci->num_args = 1;
       else if ((PROC_REG_MASK(proc_desc) & 0x40) == 0) fci->num_args = 3;
       else if ((PROC_REG_MASK(proc_desc) & 0x20) == 0) fci->num_args = 2;
       else if ((PROC_REG_MASK(proc_desc) & 0x10) == 0) fci->num_args = 1;
-
-      fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM];
     }
 }
 
     }
 }
 
@@ -457,10 +652,10 @@ init_extra_frame_info(fci)
    cache.  This allows the rest of info frame to extract the important
    arguments without difficulty.  */
 
    cache.  This allows the rest of info frame to extract the important
    arguments without difficulty.  */
 
-FRAME
+struct frame_info *
 setup_arbitrary_frame (argc, argv)
      int argc;
 setup_arbitrary_frame (argc, argv)
      int argc;
-     FRAME_ADDR *argv;
+     CORE_ADDR *argv;
 {
   if (argc != 2)
     error ("MIPS frame specifications require two arguments: sp and pc");
 {
   if (argc != 2)
     error ("MIPS frame specifications require two arguments: sp and pc");
@@ -472,21 +667,21 @@ setup_arbitrary_frame (argc, argv)
 CORE_ADDR
 mips_push_arguments(nargs, args, sp, struct_return, struct_addr)
   int nargs;
 CORE_ADDR
 mips_push_arguments(nargs, args, sp, struct_return, struct_addr)
   int nargs;
-  value *args;
+  value_ptr *args;
   CORE_ADDR sp;
   int struct_return;
   CORE_ADDR struct_addr;
 {
   CORE_ADDR sp;
   int struct_return;
   CORE_ADDR struct_addr;
 {
-  CORE_ADDR buf;
   register i;
   register i;
-  int accumulate_size = struct_return ? 4 : 0;
+  int accumulate_size = struct_return ? MIPS_REGSIZE : 0;
   struct mips_arg { char *contents; int len; int offset; };
   struct mips_arg *mips_args =
   struct mips_arg { char *contents; int len; int offset; };
   struct mips_arg *mips_args =
-      (struct mips_arg*)alloca(nargs * sizeof(struct mips_arg));
+      (struct mips_arg*)alloca((nargs + 4) * sizeof(struct mips_arg));
   register struct mips_arg *m_arg;
   register struct mips_arg *m_arg;
+  int fake_args = 0;
+
   for (i = 0, m_arg = mips_args; i < nargs; i++, m_arg++) {
   for (i = 0, m_arg = mips_args; i < nargs; i++, m_arg++) {
-    extern value value_arg_coerce();
-    value arg = value_arg_coerce (args[i]);
+    value_ptr arg = value_arg_coerce (args[i]);
     m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg));
     /* This entire mips-specific routine is because doubles must be aligned
      * on 8-byte boundaries. It still isn't quite right, because MIPS decided
     m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg));
     /* This entire mips-specific routine is because doubles must be aligned
      * on 8-byte boundaries. It still isn't quite right, because MIPS decided
@@ -494,37 +689,71 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr)
      * breaks their varargs implementation...). A correct solution
      * requires an simulation of gcc's 'alignof' (and use of 'alignof'
      * in stdarg.h/varargs.h).
      * breaks their varargs implementation...). A correct solution
      * requires an simulation of gcc's 'alignof' (and use of 'alignof'
      * in stdarg.h/varargs.h).
+     * On the 64 bit r4000 we always pass the first four arguments
+     * using eight bytes each, so that we can load them up correctly
+     * in CALL_DUMMY.
      */
      */
-    if (m_arg->len > 4) accumulate_size = (accumulate_size + 7) & -8;
+    if (m_arg->len > 4)
+      accumulate_size = (accumulate_size + 7) & -8;
     m_arg->offset = accumulate_size;
     m_arg->offset = accumulate_size;
-    accumulate_size = (accumulate_size + m_arg->len + 3) & -4;
     m_arg->contents = VALUE_CONTENTS(arg);
     m_arg->contents = VALUE_CONTENTS(arg);
+    if (! GDB_TARGET_IS_MIPS64)
+      accumulate_size = (accumulate_size + m_arg->len + 3) & -4;
+    else
+      {
+       if (accumulate_size >= 4 * MIPS_REGSIZE)
+         accumulate_size = (accumulate_size + m_arg->len + 3) &~ 4;
+       else
+         {
+           static char zeroes[8] = { 0 };
+           int len = m_arg->len;
+
+           if (len < 8)
+             {
+               if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+                 m_arg->offset += 8 - len;
+               ++m_arg;
+               m_arg->len = 8 - len;
+               m_arg->contents = zeroes;
+               if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+                 m_arg->offset = accumulate_size;
+               else
+                 m_arg->offset = accumulate_size + len;
+               ++fake_args;
+             }
+           accumulate_size = (accumulate_size + len + 7) & ~8;
+         }
+      }
   }
   accumulate_size = (accumulate_size + 7) & (-8);
   }
   accumulate_size = (accumulate_size + 7) & (-8);
-  if (accumulate_size < 16) accumulate_size = 16; 
+  if (accumulate_size < 4 * MIPS_REGSIZE)
+    accumulate_size = 4 * MIPS_REGSIZE;
   sp -= accumulate_size;
   sp -= accumulate_size;
-  for (i = nargs; m_arg--, --i >= 0; )
+  for (i = nargs + fake_args; m_arg--, --i >= 0; )
     write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len);
     write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len);
-  if (struct_return) {
-    buf = struct_addr;
-    write_memory(sp, (char *)&buf, sizeof(CORE_ADDR));
-  }
+  if (struct_return)
+    {
+      char buf[TARGET_PTR_BIT / HOST_CHAR_BIT];
+
+      store_address (buf, sizeof buf, struct_addr);
+      write_memory (sp, buf, sizeof buf);
+    }
   return sp;
 }
 
 /* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */
   return sp;
 }
 
 /* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */
-#define MASK(i,j) ((1 << (j)+1)-1 ^ (1 << (i))-1)
+#define MASK(i,j) (((1 << ((j)+1))-1) ^ ((1 << (i))-1))
 
 void
 mips_push_dummy_frame()
 {
 
 void
 mips_push_dummy_frame()
 {
+  char buffer[MAX_REGISTER_RAW_SIZE];
   int ireg;
   struct linked_proc_info *link = (struct linked_proc_info*)
       xmalloc(sizeof(struct linked_proc_info));
   mips_extra_func_info_t proc_desc = &link->info;
   CORE_ADDR sp = read_register (SP_REGNUM);
   CORE_ADDR save_address;
   int ireg;
   struct linked_proc_info *link = (struct linked_proc_info*)
       xmalloc(sizeof(struct linked_proc_info));
   mips_extra_func_info_t proc_desc = &link->info;
   CORE_ADDR sp = read_register (SP_REGNUM);
   CORE_ADDR save_address;
-  REGISTER_TYPE buffer;
   link->next = linked_proc_desc_table;
   linked_proc_desc_table = link;
 #define PUSH_FP_REGNUM 16 /* must be a register preserved across calls */
   link->next = linked_proc_desc_table;
   linked_proc_desc_table = link;
 #define PUSH_FP_REGNUM 16 /* must be a register preserved across calls */
@@ -565,8 +794,15 @@ mips_push_dummy_frame()
   for (ireg = 32; --ireg >= 0; )
     if (PROC_REG_MASK(proc_desc) & (1 << ireg))
       {
   for (ireg = 32; --ireg >= 0; )
     if (PROC_REG_MASK(proc_desc) & (1 << ireg))
       {
-       buffer = read_register (ireg);
-       write_memory (save_address, (char *)&buffer, sizeof(REGISTER_TYPE));
+       read_register_gen (ireg, buffer);
+
+       /* Need to fix the save_address decrement below, and also make sure
+          that we don't run into problems with the size of the dummy frame
+          or any of the offsets within it.  */
+       if (REGISTER_RAW_SIZE (ireg) > 4)
+         error ("Cannot call functions on mips64");
+
+       write_memory (save_address, buffer, REGISTER_RAW_SIZE (ireg));
        save_address -= 4;
       }
   /* save floating-points registers starting with high order word */
        save_address -= 4;
       }
   /* save floating-points registers starting with high order word */
@@ -574,21 +810,29 @@ mips_push_dummy_frame()
   for (ireg = 32; --ireg >= 0; )
     if (PROC_FREG_MASK(proc_desc) & (1 << ireg))
       {
   for (ireg = 32; --ireg >= 0; )
     if (PROC_FREG_MASK(proc_desc) & (1 << ireg))
       {
-       buffer = read_register (ireg + FP0_REGNUM);
-       write_memory (save_address, (char *)&buffer, 4);
+       read_register_gen (ireg + FP0_REGNUM, buffer);
+
+       if (REGISTER_RAW_SIZE (ireg + FP0_REGNUM) > 4)
+         error ("Cannot call functions on mips64");
+
+       write_memory (save_address, buffer,
+                     REGISTER_RAW_SIZE (ireg + FP0_REGNUM));
        save_address -= 4;
       }
   write_register (PUSH_FP_REGNUM, sp);
   PROC_FRAME_REG(proc_desc) = PUSH_FP_REGNUM;
   PROC_FRAME_OFFSET(proc_desc) = 0;
        save_address -= 4;
       }
   write_register (PUSH_FP_REGNUM, sp);
   PROC_FRAME_REG(proc_desc) = PUSH_FP_REGNUM;
   PROC_FRAME_OFFSET(proc_desc) = 0;
-  buffer = read_register (PC_REGNUM);
-  write_memory (sp - 4, (char *)&buffer, sizeof(REGISTER_TYPE));
-  buffer = read_register (HI_REGNUM);
-  write_memory (sp - 8, (char *)&buffer, sizeof(REGISTER_TYPE));
-  buffer = read_register (LO_REGNUM);
-  write_memory (sp - 12, (char *)&buffer, sizeof(REGISTER_TYPE));
-  buffer = read_register (mips_fpu ? FCRCS_REGNUM : ZERO_REGNUM);
-  write_memory (sp - 16, (char *)&buffer, sizeof(REGISTER_TYPE));
+  read_register_gen (PC_REGNUM, buffer);
+  write_memory (sp - 4, buffer, REGISTER_RAW_SIZE (PC_REGNUM));
+  read_register_gen (HI_REGNUM, buffer);
+  write_memory (sp - 8, buffer, REGISTER_RAW_SIZE (HI_REGNUM));
+  read_register_gen (LO_REGNUM, buffer);
+  write_memory (sp - 12, buffer, REGISTER_RAW_SIZE (LO_REGNUM));
+  if (mips_fpu)
+    read_register_gen (FCRCS_REGNUM, buffer);
+  else
+    memset (buffer, 0, REGISTER_RAW_SIZE (FCRCS_REGNUM));
+  write_memory (sp - 16, buffer, REGISTER_RAW_SIZE (FCRCS_REGNUM));
   sp -= 4 * (GEN_REG_SAVE_COUNT
             + (mips_fpu ? FLOAT_REG_SAVE_COUNT : 0)
             + SPECIAL_REG_SAVE_COUNT);
   sp -= 4 * (GEN_REG_SAVE_COUNT
             + (mips_fpu ? FLOAT_REG_SAVE_COUNT : 0)
             + SPECIAL_REG_SAVE_COUNT);
@@ -603,12 +847,14 @@ void
 mips_pop_frame()
 {
   register int regnum;
 mips_pop_frame()
 {
   register int regnum;
-  FRAME frame = get_current_frame ();
-  CORE_ADDR new_sp = frame->frame;
+  struct frame_info *frame = get_current_frame ();
+  CORE_ADDR new_sp = FRAME_FP (frame);
 
   mips_extra_func_info_t proc_desc = frame->proc_desc;
 
   write_register (PC_REGNUM, FRAME_SAVED_PC(frame));
 
   mips_extra_func_info_t proc_desc = frame->proc_desc;
 
   write_register (PC_REGNUM, FRAME_SAVED_PC(frame));
+  if (frame->saved_regs == NULL)
+    mips_find_saved_regs (frame);
   if (proc_desc)
     {
       for (regnum = 32; --regnum >= 0; )
   if (proc_desc)
     {
       for (regnum = 32; --regnum >= 0; )
@@ -623,10 +869,8 @@ mips_pop_frame()
     }
   write_register (SP_REGNUM, new_sp);
   flush_cached_frames ();
     }
   write_register (SP_REGNUM, new_sp);
   flush_cached_frames ();
-  /* We let mips_init_extra_frame_info figure out the frame pointer */
-  set_current_frame (create_new_frame (0, read_pc ()));
 
 
-  if (PROC_DESC_IS_DUMMY(proc_desc))
+  if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc))
     {
       struct linked_proc_info *pi_ptr, *prev_ptr;
 
     {
       struct linked_proc_info *pi_ptr, *prev_ptr;
 
@@ -660,7 +904,13 @@ mips_print_register (regnum, all)
      int regnum, all;
 {
   unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
      int regnum, all;
 {
   unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
-  REGISTER_TYPE val;
+  struct type *our_type =
+    init_type (TYPE_CODE_INT,
+              /* We will fill in the length for each register.  */
+              0,
+              TYPE_FLAG_UNSIGNED,
+              NULL,
+              NULL);
 
   /* Get the data in raw format.  */
   if (read_relative_register_raw_bytes (regnum, raw_buffer))
 
   /* Get the data in raw format.  */
   if (read_relative_register_raw_bytes (regnum, raw_buffer))
@@ -681,10 +931,10 @@ mips_print_register (regnum, all)
 #endif
     printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
     val_print (builtin_type_double, dbuffer, 0,
 #endif
     printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
     val_print (builtin_type_double, dbuffer, 0,
-              stdout, 0, 1, 0, Val_pretty_default);
+              gdb_stdout, 0, 1, 0, Val_pretty_default);
     printf_filtered ("); ");
   }
     printf_filtered ("); ");
   }
-  fputs_filtered (reg_names[regnum], stdout);
+  fputs_filtered (reg_names[regnum], gdb_stdout);
 
   /* The problem with printing numeric register names (r26, etc.) is that
      the user can't use them on input.  Probably the best solution is to
 
   /* The problem with printing numeric register names (r26, etc.) is that
      the user can't use them on input.  Probably the best solution is to
@@ -696,73 +946,78 @@ mips_print_register (regnum, all)
     printf_filtered (": ");
 
   /* If virtual format is floating, print it that way.  */
     printf_filtered (": ");
 
   /* If virtual format is floating, print it that way.  */
-  if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
-      && ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) {
+  if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT)
     val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0,
     val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0,
-              stdout, 0, 1, 0, Val_pretty_default);
-  }
+              gdb_stdout, 0, 1, 0, Val_pretty_default);
   /* Else print as integer in hex.  */
   else
   /* Else print as integer in hex.  */
   else
-    {
-      long val;
-
-      val = extract_signed_integer (raw_buffer,
-                                   REGISTER_RAW_SIZE (regnum));
-
-      if (val == 0)
-       printf_filtered ("0");
-      else if (all)
-       /* FIXME: We should be printing this in a fixed field width, so that
-          registers line up.  */
-       printf_filtered (local_hex_format(), val);
-      else
-       printf_filtered ("%s=%d", local_hex_string(val), val);
-    }
+    print_scalar_formatted (raw_buffer, REGISTER_VIRTUAL_TYPE (regnum),
+                           'x', 0, gdb_stdout);
 }
 
 /* Replacement for generic do_registers_info.  */
 }
 
 /* Replacement for generic do_registers_info.  */
+
 void
 mips_do_registers_info (regnum, fpregs)
      int regnum;
      int fpregs;
 {
 void
 mips_do_registers_info (regnum, fpregs)
      int regnum;
      int fpregs;
 {
-  if (regnum != -1) {
+  if (regnum != -1)
+    {
+      if (*(reg_names[regnum]) == '\0')
+       error ("Not a valid register for the current processor type");
+
       mips_print_register (regnum, 0);
       printf_filtered ("\n");
       mips_print_register (regnum, 0);
       printf_filtered ("\n");
-  }
-  else {
-      for (regnum = 0; regnum < NUM_REGS; ) {
-         if ((!fpregs) && regnum >= FP0_REGNUM && regnum <= FCRIR_REGNUM) {
-           regnum++;
-           continue;
-         }
+    }
+  else
+    {
+      int did_newline;
+
+      for (regnum = 0; regnum < NUM_REGS; )
+       {
+         if (((!fpregs) && regnum >= FP0_REGNUM && regnum <= FCRIR_REGNUM)
+             || *(reg_names[regnum]) == '\0')
+           {
+             regnum++;
+             continue;
+           }
          mips_print_register (regnum, 1);
          regnum++;
          mips_print_register (regnum, 1);
          regnum++;
-         if ((regnum & 3) == 0 || regnum == NUM_REGS)
-             printf_filtered (";\n");
-         else
-             printf_filtered ("; ");
-      }
-  }
+         printf_filtered ("; ");
+         did_newline = 0;
+         if ((regnum & 3) == 0)
+           {
+             printf_filtered ("\n");
+             did_newline = 1;
+           }
+       }
+      if (!did_newline)
+       printf_filtered ("\n");
+    }
 }
 }
+
 /* Return number of args passed to a frame. described by FIP.
    Can return -1, meaning no way to tell.  */
 
 int
 /* Return number of args passed to a frame. described by FIP.
    Can return -1, meaning no way to tell.  */
 
 int
-mips_frame_num_args(fip)
-       FRAME fip;
+mips_frame_num_args (frame)
+       struct frame_info *frame;
 {
 {
-#if 0
-       struct chain_info_t *p;
+#if 0 /* FIXME Use or lose this! */
+  struct chain_info_t *p;
 
 
-       p = mips_find_cached_frame(FRAME_FP(fip));
-       if (p->valid)
-               return p->the_info.numargs;
+  p = mips_find_cached_frame (FRAME_FP (frame));
+  if (p->valid)
+    return p->the_info.numargs;
 #endif
 #endif
-       return -1;
+  return -1;
 }
 \f
 /* Is this a branch with a delay slot?  */
 }
 \f
 /* Is this a branch with a delay slot?  */
+
+static int is_delayed PARAMS ((unsigned long));
+
 static int
 is_delayed (insn)
      unsigned long insn;
 static int
 is_delayed (insn)
      unsigned long insn;
@@ -778,6 +1033,18 @@ is_delayed (insn)
                                       | INSN_COND_BRANCH_LIKELY)));
 }
 
                                       | INSN_COND_BRANCH_LIKELY)));
 }
 
+int
+mips_step_skips_delay (pc)
+     CORE_ADDR pc;
+{
+  char buf[4];
+
+  if (target_read_memory (pc, buf, 4) != 0)
+    /* If error reading memory, guess that it is not a delayed branch.  */
+    return 0;
+  return is_delayed (extract_unsigned_integer (buf, 4));
+}
+
 /* To skip prologues, I use this predicate.  Returns either PC itself
    if the code at PC does not look like a function prologue; otherwise
    returns an address that (if we're lucky) follows the prologue.  If
 /* To skip prologues, I use this predicate.  Returns either PC itself
    if the code at PC does not look like a function prologue; otherwise
    returns an address that (if we're lucky) follows the prologue.  If
@@ -792,11 +1059,10 @@ mips_skip_prologue (pc, lenient)
      CORE_ADDR pc;
      int lenient;
 {
      CORE_ADDR pc;
      int lenient;
 {
-    struct symbol *f;
-    struct block *b;
     unsigned long inst;
     int offset;
     int seen_sp_adjust = 0;
     unsigned long inst;
     int offset;
     int seen_sp_adjust = 0;
+    int load_immediate_bytes = 0;
 
     /* Skip the typical prologue instructions. These are the stack adjustment
        instruction and the instructions that save registers on the stack
 
     /* Skip the typical prologue instructions. These are the stack adjustment
        instruction and the instructions that save registers on the stack
@@ -811,11 +1077,16 @@ mips_skip_prologue (pc, lenient)
          memory_error (status, pc + offset);
        inst = extract_unsigned_integer (buf, 4);
 
          memory_error (status, pc + offset);
        inst = extract_unsigned_integer (buf, 4);
 
+#if 0
        if (lenient && is_delayed (inst))
          continue;
        if (lenient && is_delayed (inst))
          continue;
+#endif
 
        if ((inst & 0xffff0000) == 0x27bd0000)  /* addiu $sp,$sp,offset */
            seen_sp_adjust = 1;
 
        if ((inst & 0xffff0000) == 0x27bd0000)  /* addiu $sp,$sp,offset */
            seen_sp_adjust = 1;
+       else if (inst == 0x03a1e823 ||          /* subu $sp,$sp,$at */
+                inst == 0x03a8e823)            /* subu $sp,$sp,$t0 */
+           seen_sp_adjust = 1;
        else if ((inst & 0xFFE00000) == 0xAFA00000 && (inst & 0x001F0000))
            continue;                           /* sw reg,n($sp) */
                                                /* reg != $zero */
        else if ((inst & 0xFFE00000) == 0xAFA00000 && (inst & 0x001F0000))
            continue;                           /* sw reg,n($sp) */
                                                /* reg != $zero */
@@ -824,44 +1095,61 @@ mips_skip_prologue (pc, lenient)
        else if ((inst & 0xF3E00000) == 0xA3C00000 && (inst & 0x001F0000))
                                                /* sx reg,n($s8) */
            continue;                           /* reg != $zero */
        else if ((inst & 0xF3E00000) == 0xA3C00000 && (inst & 0x001F0000))
                                                /* sx reg,n($s8) */
            continue;                           /* reg != $zero */
-       else if (inst == 0x03A0F021)            /* move $s8,$sp */
+        /* move $s8,$sp.  With different versions of gas this will be either
+           `addu $s8,$sp,$zero' or `or $s8,$sp,$zero'.  Accept either.  */
+        else if (inst == 0x03A0F021 || inst == 0x03a0f025)
            continue;
            continue;
+
        else if ((inst & 0xFF9F07FF) == 0x00800021) /* move reg,$a0-$a3 */
            continue;
        else if ((inst & 0xFF9F07FF) == 0x00800021) /* move reg,$a0-$a3 */
            continue;
+       else if ((inst & 0xffff0000) == 0x3c1c0000) /* lui $gp,n */
+           continue;
+       else if ((inst & 0xffff0000) == 0x279c0000) /* addiu $gp,$gp,n */
+           continue;
+       else if (inst == 0x0399e021             /* addu $gp,$gp,$t9 */
+                || inst == 0x033ce021)         /* addu $gp,$t9,$gp */
+         continue;
+       /* The following instructions load $at or $t0 with an immediate
+          value in preparation for a stack adjustment via
+          subu $sp,$sp,[$at,$t0]. These instructions could also initialize
+          a local variable, so we accept them only before a stack adjustment
+          instruction was seen.  */
+       else if (!seen_sp_adjust)
+         {
+           if ((inst & 0xffff0000) == 0x3c010000 ||      /* lui $at,n */
+               (inst & 0xffff0000) == 0x3c080000)        /* lui $t0,n */
+             {
+               load_immediate_bytes += 4;
+               continue;
+             }
+           else if ((inst & 0xffff0000) == 0x34210000 || /* ori $at,$at,n */
+                    (inst & 0xffff0000) == 0x35080000 || /* ori $t0,$t0,n */
+                    (inst & 0xffff0000) == 0x34010000 || /* ori $at,$zero,n */
+                    (inst & 0xffff0000) == 0x34080000)   /* ori $t0,$zero,n */
+             {
+               load_immediate_bytes += 4;
+               continue;
+             }
+           else
+             break;
+         }
        else
        else
-           break;
+         break;
     }
     }
-    return pc + offset;
 
 
-/* FIXME schauer. The following code seems no longer necessary if we
-   always skip the typical prologue instructions.  */
+    /* In a frameless function, we might have incorrectly
+       skipped some load immediate instructions. Undo the skipping
+       if the load immediate was not followed by a stack adjustment.  */
+    if (load_immediate_bytes && !seen_sp_adjust)
+      offset -= load_immediate_bytes;
+    return pc + offset;
+}
 
 #if 0
 
 #if 0
-    if (seen_sp_adjust)
-      return pc + offset;
-
-    /* Well, it looks like a frameless. Let's make sure.
-       Note that we are not called on the current PC,
-       but on the function`s start PC, and I have definitely
-       seen optimized code that adjusts the SP quite later */
-    b = block_for_pc(pc);
-    if (!b) return pc;
-
-    f = lookup_symbol(MIPS_EFI_SYMBOL_NAME, b, LABEL_NAMESPACE, 0, NULL);
-    if (!f) return pc;
-    /* Ideally, I would like to use the adjusted info
-       from mips_frame_info(), but for all practical
-       purposes it will not matter (and it would require
-       a different definition of SKIP_PROLOGUE())
-
-       Actually, it would not hurt to skip the storing
-       of arguments on the stack as well. */
-    if (((mips_extra_func_info_t)SYMBOL_VALUE(f))->pdr.frameoffset)
-       return pc + 4;
-
-    return pc;
-#endif
-}
+/* The lenient prologue stuff should be superceded by the code in
+   init_extra_frame_info which looks to see whether the stores mentioned
+   in the proc_desc have actually taken place.  */
 
 /* Is address PC in the prologue (loosely defined) for function at
    STARTADDR?  */
 
 /* Is address PC in the prologue (loosely defined) for function at
    STARTADDR?  */
@@ -874,6 +1162,7 @@ mips_in_lenient_prologue (startaddr, pc)
   CORE_ADDR end_prologue = mips_skip_prologue (startaddr, 1);
   return pc >= startaddr && pc < end_prologue;
 }
   CORE_ADDR end_prologue = mips_skip_prologue (startaddr, 1);
   return pc >= startaddr && pc < end_prologue;
 }
+#endif
 
 /* Given a return value in `regbuf' with a type `valtype', 
    extract and copy its value into `valbuf'.  */
 
 /* Given a return value in `regbuf' with a type `valtype', 
    extract and copy its value into `valbuf'.  */
@@ -913,11 +1202,106 @@ mips_store_return_value (valtype, valbuf)
   write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
 }
 
   write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
 }
 
-static void reinit_frame_cache_sfunc PARAMS ((char *, int
-                                             struct cmd_list_element *));
+/* These exist in mdebugread.c.  */
+extern CORE_ADDR sigtramp_address, sigtramp_end;
+extern void fixup_sigtramp PARAMS ((void));
+
+/* Exported procedure: Is PC in the signal trampoline code */
+
+int
+in_sigtramp (pc, ignore)
+     CORE_ADDR pc;
+     char *ignore;             /* function name */
+{
+  if (sigtramp_address == 0)
+    fixup_sigtramp ();
+  return (pc >= sigtramp_address && pc < sigtramp_end);
+}
+
+/* Command to set the processor type.  */
+
+void
+mips_set_processor_type_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  int i;
+
+  if (tmp_mips_processor_type == NULL || *tmp_mips_processor_type == '\0')
+    {
+      printf_unfiltered ("The known MIPS processor types are as follows:\n\n");
+      for (i = 0; mips_processor_type_table[i].name != NULL; ++i)
+       printf_unfiltered ("%s\n", mips_processor_type_table[i].name);
+
+      /* Restore the value.  */
+      tmp_mips_processor_type = strsave (mips_processor_type);
+
+      return;
+    }
+  
+  if (!mips_set_processor_type (tmp_mips_processor_type))
+    {
+      error ("Unknown processor type `%s'.", tmp_mips_processor_type);
+      /* Restore its value.  */
+      tmp_mips_processor_type = strsave (mips_processor_type);
+    }
+}
+
+static void
+mips_show_processor_type_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+}
+
+/* Modify the actual processor type. */
+
+int
+mips_set_processor_type (str)
+     char *str;
+{
+  int i, j;
+
+  if (str == NULL)
+    return 0;
+
+  for (i = 0; mips_processor_type_table[i].name != NULL; ++i)
+    {
+      if (strcasecmp (str, mips_processor_type_table[i].name) == 0)
+       {
+         mips_processor_type = str;
+
+         for (j = 0; j < NUM_REGS; ++j)
+           reg_names[j] = mips_processor_type_table[i].regnames[j];
+
+         return 1;
+
+         /* FIXME tweak fpu flag too */
+       }
+    }
+
+  return 0;
+}
+
+/* Attempt to identify the particular processor model by reading the
+   processor id.  */
+
+char *
+mips_read_processor_type ()
+{
+  int prid;
+
+  prid = read_register (PRID_REGNUM);
+
+  if (prid & ~0xf == 0x700)
+    return savestring ("r3041", strlen("r3041"));
+
+  return NULL;
+}
 
 /* Just like reinit_frame_cache, but with the right arguments to be
    callable as an sfunc.  */
 
 /* Just like reinit_frame_cache, but with the right arguments to be
    callable as an sfunc.  */
+
 static void
 reinit_frame_cache_sfunc (args, from_tty, c)
      char *args;
 static void
 reinit_frame_cache_sfunc (args, from_tty, c)
      char *args;
@@ -927,11 +1311,24 @@ reinit_frame_cache_sfunc (args, from_tty, c)
   reinit_frame_cache ();
 }
 
   reinit_frame_cache ();
 }
 
+int
+gdb_print_insn_mips (memaddr, info)
+     bfd_vma memaddr;
+     disassemble_info *info;
+{
+  if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+    return print_insn_big_mips (memaddr, info);
+  else
+    return print_insn_little_mips (memaddr, info);
+}
+
 void
 _initialize_mips_tdep ()
 {
   struct cmd_list_element *c;
 
 void
 _initialize_mips_tdep ()
 {
   struct cmd_list_element *c;
 
+  tm_print_insn = gdb_print_insn_mips;
+
   /* Let the user turn off floating point and set the fence post for
      heuristic_proc_start.  */
 
   /* Let the user turn off floating point and set the fence post for
      heuristic_proc_start.  */
 
@@ -943,7 +1340,23 @@ Turn off to avoid using floating point instructions when calling functions\n\
 or dealing with return values.", &setlist),
      &showlist);
 
 or dealing with return values.", &setlist),
      &showlist);
 
-  c = add_set_cmd ("heuristic-fence-post", class_support, var_uinteger,
+  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 = strsave (DEFAULT_MIPS_TYPE);
+  mips_set_processor_type_command (strsave (DEFAULT_MIPS_TYPE), 0);
+
+  /* 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.  */
+  c = add_set_cmd ("heuristic-fence-post", class_support, var_zinteger,
                   (char *) &heuristic_fence_post,
                   "\
 Set the distance searched for the start of a function.\n\
                   (char *) &heuristic_fence_post,
                   "\
 Set the distance searched for the start of a function.\n\
This page took 0.039085 seconds and 4 git commands to generate.