* mips-tdep.c (mips32_scan_prologue): Move the implementation up
authorJoel Brobecker <brobecker@gnat.com>
Fri, 15 Oct 2004 07:25:04 +0000 (07:25 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Fri, 15 Oct 2004 07:25:04 +0000 (07:25 +0000)
        a bit to avoid the necessity of an advance declaration. Remove
        declaration.
        (set_reg_offset): Move implemenation up.
        (mips16_get_imm): Likewise.
        (mips16_scan_prologue): Likewise.
        (reset_saved_regs): Likewise.
        (mips32_scan_prologue): Likewise.

gdb/ChangeLog
gdb/mips-tdep.c

index cbb02ba3e031ba6e4fbda17c6ac9d6bbdae065a1..4895c14a7bca8e68a7025a56c4d6c509ae52a442 100644 (file)
@@ -1,3 +1,14 @@
+2004-10-15  Joel Brobecker  <brobecker@gnat.com>
+
+       * mips-tdep.c (mips32_scan_prologue): Move the implementation up
+       a bit to avoid the necessity of an advance declaration. Remove
+       declaration.
+       (set_reg_offset): Move implemenation up.
+       (mips16_get_imm): Likewise.
+       (mips16_scan_prologue): Likewise.
+       (reset_saved_regs): Likewise.
+       (mips32_scan_prologue): Likewise.
+
 2004-10-14  Joel Brobecker  <brobecker@gnat.com>
 
        * mips-tdep.c (mips32_scan_prologue): Add advance declaration.
index 7ad6ad1e1b61dac7c6697d594d09364872d323e3..4f249b8e439c6d0503da7aa5739d8e485d747616 100644 (file)
@@ -442,17 +442,6 @@ static struct type *mips_double_register_type (void);
 static struct cmd_list_element *setmipscmdlist = NULL;
 static struct cmd_list_element *showmipscmdlist = NULL;
 
-/* FIXME: brobecker/2004-10-15: I suspect these two declarations can
-   be removed by a better ordering of the functions below.  But I want
-   to do that as a separate change later in order to separate real
-   changes and changes that just move some code around.  */
-static CORE_ADDR mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
-                                       struct frame_info *next_frame,
-                                       struct mips_frame_cache *this_cache);
-static CORE_ADDR mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
-                                       struct frame_info *next_frame,
-                                       struct mips_frame_cache *this_cache);
-
 /* Integer registers 0 thru 31 are handled explicitly by
    mips_register_name().  Processor specific registers 32 and above
    are listed in the followign tables.  */
@@ -1721,961 +1710,961 @@ mips_mdebug_frame_base_sniffer (struct frame_info *next_frame)
     return NULL;
 }
 
-/* Heuristic unwinder for 16-bit MIPS instruction set (aka MIPS16).
-   Procedures that use the 32-bit instruction set are handled by the
-   mips_insn32 unwinder.  */
-
-static struct mips_frame_cache *
-mips_insn16_frame_cache (struct frame_info *next_frame, void **this_cache)
-{
-  struct mips_frame_cache *cache;
-
-  if ((*this_cache) != NULL)
-    return (*this_cache);
-  cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
-  (*this_cache) = cache;
-  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
-
-  /* Analyze the function prologue.  */
-  {
-    const CORE_ADDR pc = frame_pc_unwind (next_frame);
-    CORE_ADDR start_addr;
-
-    find_pc_partial_function (pc, NULL, &start_addr, NULL);
-    if (start_addr == 0)
-      start_addr = heuristic_proc_start (pc);
-    /* We can't analyze the prologue if we couldn't find the begining
-       of the function.  */
-    if (start_addr == 0)
-      return cache;
-
-    mips16_scan_prologue (start_addr, pc, next_frame, *this_cache);
-  }
-  
-  /* SP_REGNUM, contains the value and not the address.  */
-  trad_frame_set_value (cache->saved_regs, NUM_REGS + MIPS_SP_REGNUM, cache->base);
-
-  return (*this_cache);
-}
+/* 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 only recognize the first save of a given register in a
+   function prologue.
 
-static void
-mips_insn16_frame_this_id (struct frame_info *next_frame, void **this_cache,
-                          struct frame_id *this_id)
-{
-  struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
-                                                          this_cache);
-  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
-}
+   For simplicity, save the address in both [0 .. NUM_REGS) and
+   [NUM_REGS .. 2*NUM_REGS).  Strictly speaking, only the second range
+   is used as it is only second range (the ABI instead of ISA
+   registers) that comes into play when finding saved registers in a
+   frame.  */
 
 static void
-mips_insn16_frame_prev_register (struct frame_info *next_frame,
-                                void **this_cache,
-                                int regnum, int *optimizedp,
-                                enum lval_type *lvalp, CORE_ADDR *addrp,
-                                int *realnump, void *valuep)
+set_reg_offset (struct mips_frame_cache *this_cache, int regnum,
+               CORE_ADDR offset)
 {
-  struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
-                                                          this_cache);
-  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
-                               optimizedp, lvalp, addrp, realnump, valuep);
+  if (this_cache != NULL
+      && this_cache->saved_regs[regnum].addr == -1)
+    {
+      this_cache->saved_regs[regnum + 0 * NUM_REGS].addr = offset;
+      this_cache->saved_regs[regnum + 1 * NUM_REGS].addr = offset;
+    }
 }
 
-static const struct frame_unwind mips_insn16_frame_unwind =
-{
-  NORMAL_FRAME,
-  mips_insn16_frame_this_id,
-  mips_insn16_frame_prev_register
-};
-
-static const struct frame_unwind *
-mips_insn16_frame_sniffer (struct frame_info *next_frame)
-{
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
-  if (pc_is_mips16 (pc))
-    return &mips_insn16_frame_unwind;
-  return NULL;
-}
 
-static CORE_ADDR
-mips_insn16_frame_base_address (struct frame_info *next_frame,
-                               void **this_cache)
-{
-  struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
-                                                          this_cache);
-  return info->base;
-}
+/* Fetch the immediate value from a MIPS16 instruction.
+   If the previous instruction was an EXTEND, use it to extend
+   the upper bits of the immediate value.  This is a helper function
+   for mips16_scan_prologue.  */
 
-static const struct frame_base mips_insn16_frame_base =
+static int
+mips16_get_imm (unsigned short prev_inst,      /* previous instruction */
+               unsigned short inst,    /* current instruction */
+               int nbits,      /* number of bits in imm field */
+               int scale,      /* scale factor to be applied to imm */
+               int is_signed)  /* is the imm field signed? */
 {
-  &mips_insn16_frame_unwind,
-  mips_insn16_frame_base_address,
-  mips_insn16_frame_base_address,
-  mips_insn16_frame_base_address
-};
+  int offset;
 
-static const struct frame_base *
-mips_insn16_frame_base_sniffer (struct frame_info *next_frame)
-{
-  if (mips_insn16_frame_sniffer (next_frame) != NULL)
-    return &mips_insn16_frame_base;
+  if ((prev_inst & 0xf800) == 0xf000)  /* prev instruction was EXTEND? */
+    {
+      offset = ((prev_inst & 0x1f) << 11) | (prev_inst & 0x7e0);
+      if (offset & 0x8000)     /* check for negative extend */
+       offset = 0 - (0x10000 - (offset & 0xffff));
+      return offset | (inst & 0x1f);
+    }
   else
-    return NULL;
-}
-
-/* Heuristic unwinder for procedures using 32-bit instructions (covers
-   both 32-bit and 64-bit MIPS ISAs).  Procedures using 16-bit
-   instructions (a.k.a. MIPS16) are handled by the mips_insn16
-   unwinder.  */
+    {
+      int max_imm = 1 << nbits;
+      int mask = max_imm - 1;
+      int sign_bit = max_imm >> 1;
 
-static struct mips_frame_cache *
-mips_insn32_frame_cache (struct frame_info *next_frame, void **this_cache)
-{
-  struct mips_frame_cache *cache;
+      offset = inst & mask;
+      if (is_signed && (offset & sign_bit))
+       offset = 0 - (max_imm - offset);
+      return offset * scale;
+    }
+}
 
-  if ((*this_cache) != NULL)
-    return (*this_cache);
 
-  cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
-  (*this_cache) = cache;
-  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+/* Analyze the function prologue from START_PC to LIMIT_PC. Builds
+   the associated FRAME_CACHE if not null.
+   Return the address of the first instruction past the prologue.  */
 
-  /* Analyze the function prologue.  */
-  {
-    const CORE_ADDR pc = frame_pc_unwind (next_frame);
-    CORE_ADDR start_addr;
+static CORE_ADDR
+mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+                      struct frame_info *next_frame,
+                      struct mips_frame_cache *this_cache)
+{
+  CORE_ADDR cur_pc;
+  CORE_ADDR frame_addr = 0;    /* Value of $r17, used as frame pointer */
+  CORE_ADDR sp;
+  long frame_offset = 0;        /* Size of stack frame.  */
+  long frame_adjust = 0;        /* Offset of FP from SP.  */
+  int frame_reg = MIPS_SP_REGNUM;
+  unsigned short prev_inst = 0;        /* saved copy of previous instruction */
+  unsigned inst = 0;           /* current instruction */
+  unsigned entry_inst = 0;     /* the entry instruction */
+  int reg, offset;
 
-    find_pc_partial_function (pc, NULL, &start_addr, NULL);
-    if (start_addr == 0)
-      start_addr = heuristic_proc_start (pc);
-    /* We can't analyze the prologue if we couldn't find the begining
-       of the function.  */
-    if (start_addr == 0)
-      return cache;
+  int extend_bytes = 0;
+  int prev_extend_bytes;
+  CORE_ADDR end_prologue_addr = 0;
 
-    mips32_scan_prologue (start_addr, pc, next_frame, *this_cache);
-  }
-  
-  /* SP_REGNUM, contains the value and not the address.  */
-  trad_frame_set_value (cache->saved_regs, NUM_REGS + MIPS_SP_REGNUM, cache->base);
+  /* Can be called when there's no process, and hence when there's no
+     NEXT_FRAME.  */
+  if (next_frame != NULL)
+    sp = read_next_frame_reg (next_frame, NUM_REGS + MIPS_SP_REGNUM);
+  else
+    sp = 0;
 
-  return (*this_cache);
-}
+  if (limit_pc > start_pc + 200)
+    limit_pc = start_pc + 200;
 
-static void
-mips_insn32_frame_this_id (struct frame_info *next_frame, void **this_cache,
-                          struct frame_id *this_id)
-{
-  struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
-                                                          this_cache);
-  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
-}
+  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS16_INSTLEN)
+    {
+      /* Save the previous instruction.  If it's an EXTEND, we'll extract
+         the immediate offset extension from it in mips16_get_imm.  */
+      prev_inst = inst;
 
-static void
-mips_insn32_frame_prev_register (struct frame_info *next_frame,
-                                void **this_cache,
-                                int regnum, int *optimizedp,
-                                enum lval_type *lvalp, CORE_ADDR *addrp,
-                                int *realnump, void *valuep)
-{
-  struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
-                                                          this_cache);
-  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
-                               optimizedp, lvalp, addrp, realnump, valuep);
-}
+      /* Fetch and decode the instruction.   */
+      inst = (unsigned short) mips_fetch_instruction (cur_pc);
 
-static const struct frame_unwind mips_insn32_frame_unwind =
-{
-  NORMAL_FRAME,
-  mips_insn32_frame_this_id,
-  mips_insn32_frame_prev_register
-};
+      /* Normally we ignore extend instructions.  However, if it is
+         not followed by a valid prologue instruction, then this
+         instruction is not part of the prologue either.  We must
+         remember in this case to adjust the end_prologue_addr back
+         over the extend.  */
+      if ((inst & 0xf800) == 0xf000)    /* extend */
+        {
+          extend_bytes = MIPS16_INSTLEN;
+          continue;
+        }
 
-static const struct frame_unwind *
-mips_insn32_frame_sniffer (struct frame_info *next_frame)
-{
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
-  if (! pc_is_mips16 (pc))
-    return &mips_insn32_frame_unwind;
-  return NULL;
-}
+      prev_extend_bytes = extend_bytes;
+      extend_bytes = 0;
 
-static CORE_ADDR
-mips_insn32_frame_base_address (struct frame_info *next_frame,
-                               void **this_cache)
-{
-  struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
-                                                          this_cache);
-  return info->base;
-}
+      if ((inst & 0xff00) == 0x6300    /* addiu sp */
+         || (inst & 0xff00) == 0xfb00) /* daddiu sp */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 8, 8, 1);
+         if (offset < 0)       /* negative stack adjustment? */
+           frame_offset -= offset;
+         else
+           /* Exit loop if a positive stack adjustment is found, which
+              usually means that the stack cleanup code in the function
+              epilogue is reached.  */
+           break;
+       }
+      else if ((inst & 0xf800) == 0xd000)      /* sw reg,n($sp) */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
+         reg = mips16_to_32_reg[(inst & 0x700) >> 8];
+         set_reg_offset (this_cache, reg, sp + offset);
+       }
+      else if ((inst & 0xff00) == 0xf900)      /* sd reg,n($sp) */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
+         reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
+         set_reg_offset (this_cache, reg, sp + offset);
+       }
+      else if ((inst & 0xff00) == 0x6200)      /* sw $ra,n($sp) */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
+         set_reg_offset (this_cache, RA_REGNUM, sp + offset);
+       }
+      else if ((inst & 0xff00) == 0xfa00)      /* sd $ra,n($sp) */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 8, 8, 0);
+         set_reg_offset (this_cache, RA_REGNUM, sp + offset);
+       }
+      else if (inst == 0x673d) /* move $s1, $sp */
+       {
+         frame_addr = sp;
+         frame_reg = 17;
+       }
+      else if ((inst & 0xff00) == 0x0100)      /* addiu $s1,sp,n */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
+         frame_addr = sp + offset;
+         frame_reg = 17;
+         frame_adjust = offset;
+       }
+      else if ((inst & 0xFF00) == 0xd900)      /* sw reg,offset($s1) */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 5, 4, 0);
+         reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
+         set_reg_offset (this_cache, reg, frame_addr + offset);
+       }
+      else if ((inst & 0xFF00) == 0x7900)      /* sd reg,offset($s1) */
+       {
+         offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
+         reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
+         set_reg_offset (this_cache, reg, frame_addr + offset);
+       }
+      else if ((inst & 0xf81f) == 0xe809
+               && (inst & 0x700) != 0x700)     /* entry */
+       entry_inst = inst;      /* save for later processing */
+      else if ((inst & 0xf800) == 0x1800)      /* jal(x) */
+       cur_pc += MIPS16_INSTLEN;       /* 32-bit instruction */
+      else if ((inst & 0xff1c) == 0x6704)      /* move reg,$a0-$a3 */
+        {
+          /* This instruction is part of the prologue, but we don't
+             need to do anything special to handle it.  */
+        }
+      else
+        {
+          /* This instruction is not an instruction typically found
+             in a prologue, so we must have reached the end of the
+             prologue.  */
+          if (end_prologue_addr == 0)
+            end_prologue_addr = cur_pc - prev_extend_bytes;
+        }
+    }
 
-static const struct frame_base mips_insn32_frame_base =
-{
-  &mips_insn32_frame_unwind,
-  mips_insn32_frame_base_address,
-  mips_insn32_frame_base_address,
-  mips_insn32_frame_base_address
-};
+  /* The entry instruction is typically the first instruction in a function,
+     and it stores registers at offsets relative to the value of the old SP
+     (before the prologue).  But the value of the sp parameter to this
+     function is the new SP (after the prologue has been executed).  So we
+     can't calculate those offsets until we've seen the entire prologue,
+     and can calculate what the old SP must have been. */
+  if (entry_inst != 0)
+    {
+      int areg_count = (entry_inst >> 8) & 7;
+      int sreg_count = (entry_inst >> 6) & 3;
 
-static const struct frame_base *
-mips_insn32_frame_base_sniffer (struct frame_info *next_frame)
-{
-  if (mips_insn32_frame_sniffer (next_frame) != NULL)
-    return &mips_insn32_frame_base;
-  else
-    return NULL;
+      /* The entry instruction always subtracts 32 from the SP.  */
+      frame_offset += 32;
+
+      /* Now we can calculate what the SP must have been at the
+         start of the function prologue.  */
+      sp += frame_offset;
+
+      /* Check if a0-a3 were saved in the caller's argument save area.  */
+      for (reg = 4, offset = 0; reg < areg_count + 4; reg++)
+       {
+         set_reg_offset (this_cache, reg, sp + offset);
+         offset += mips_abi_regsize (current_gdbarch);
+       }
+
+      /* Check if the ra register was pushed on the stack.  */
+      offset = -4;
+      if (entry_inst & 0x20)
+       {
+         set_reg_offset (this_cache, RA_REGNUM, sp + offset);
+         offset -= mips_abi_regsize (current_gdbarch);
+       }
+
+      /* Check if the s0 and s1 registers were pushed on the stack.  */
+      for (reg = 16; reg < sreg_count + 16; reg++)
+       {
+         set_reg_offset (this_cache, reg, sp + offset);
+         offset -= mips_abi_regsize (current_gdbarch);
+       }
+    }
+
+  if (this_cache != NULL)
+    {
+      this_cache->base =
+        (frame_unwind_register_signed (next_frame, NUM_REGS + frame_reg)
+         + frame_offset - frame_adjust);
+      /* FIXME: brobecker/2004-10-10: Just as in the mips32 case, we should
+         be able to get rid of the assignment below, evetually. But it's
+         still needed for now.  */
+      this_cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
+        = this_cache->saved_regs[NUM_REGS + RA_REGNUM];
+    }
+
+  /* If we didn't reach the end of the prologue when scanning the function
+     instructions, then set end_prologue_addr to the address of the
+     instruction immediately after the last one we scanned.  */
+  if (end_prologue_addr == 0)
+    end_prologue_addr = cur_pc;
+
+  return end_prologue_addr;
 }
 
-static struct trad_frame_cache *
-mips_stub_frame_cache (struct frame_info *next_frame, void **this_cache)
+/* Heuristic unwinder for 16-bit MIPS instruction set (aka MIPS16).
+   Procedures that use the 32-bit instruction set are handled by the
+   mips_insn32 unwinder.  */
+
+static struct mips_frame_cache *
+mips_insn16_frame_cache (struct frame_info *next_frame, void **this_cache)
 {
-  CORE_ADDR pc;
-  CORE_ADDR start_addr;
-  CORE_ADDR stack_addr;
-  struct trad_frame_cache *this_trad_cache;
+  struct mips_frame_cache *cache;
 
   if ((*this_cache) != NULL)
     return (*this_cache);
-  this_trad_cache = trad_frame_cache_zalloc (next_frame);
-  (*this_cache) = this_trad_cache;
+  cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
-  /* The return address is in the link register.  */
-  trad_frame_set_reg_realreg (this_trad_cache, PC_REGNUM, RA_REGNUM);
+  /* Analyze the function prologue.  */
+  {
+    const CORE_ADDR pc = frame_pc_unwind (next_frame);
+    CORE_ADDR start_addr;
 
-  /* Frame ID, since it's a frameless / stackless function, no stack
-     space is allocated and SP on entry is the current SP.  */
-  pc = frame_pc_unwind (next_frame);
-  find_pc_partial_function (pc, NULL, &start_addr, NULL);
-  stack_addr = frame_unwind_register_signed (next_frame, SP_REGNUM);
-  trad_frame_set_id (this_trad_cache, frame_id_build (start_addr, stack_addr));
+    find_pc_partial_function (pc, NULL, &start_addr, NULL);
+    if (start_addr == 0)
+      start_addr = heuristic_proc_start (pc);
+    /* We can't analyze the prologue if we couldn't find the begining
+       of the function.  */
+    if (start_addr == 0)
+      return cache;
 
-  /* Assume that the frame's base is the same as the
-     stack-pointer.  */
-  trad_frame_set_this_base (this_trad_cache, stack_addr);
+    mips16_scan_prologue (start_addr, pc, next_frame, *this_cache);
+  }
+  
+  /* SP_REGNUM, contains the value and not the address.  */
+  trad_frame_set_value (cache->saved_regs, NUM_REGS + MIPS_SP_REGNUM, cache->base);
 
-  return this_trad_cache;
+  return (*this_cache);
 }
 
 static void
-mips_stub_frame_this_id (struct frame_info *next_frame, void **this_cache,
-                        struct frame_id *this_id)
+mips_insn16_frame_this_id (struct frame_info *next_frame, void **this_cache,
+                          struct frame_id *this_id)
 {
-  struct trad_frame_cache *this_trad_cache
-    = mips_stub_frame_cache (next_frame, this_cache);
-  trad_frame_get_id (this_trad_cache, this_id);
+  struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
+                                                          this_cache);
+  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
 }
 
 static void
-mips_stub_frame_prev_register (struct frame_info *next_frame,
+mips_insn16_frame_prev_register (struct frame_info *next_frame,
                                 void **this_cache,
                                 int regnum, int *optimizedp,
                                 enum lval_type *lvalp, CORE_ADDR *addrp,
                                 int *realnump, void *valuep)
 {
-  struct trad_frame_cache *this_trad_cache
-    = mips_stub_frame_cache (next_frame, this_cache);
-  trad_frame_get_register (this_trad_cache, next_frame, regnum, optimizedp,
-                          lvalp, addrp, realnump, valuep);
+  struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
+                                                          this_cache);
+  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
+                               optimizedp, lvalp, addrp, realnump, valuep);
 }
 
-static const struct frame_unwind mips_stub_frame_unwind =
+static const struct frame_unwind mips_insn16_frame_unwind =
 {
   NORMAL_FRAME,
-  mips_stub_frame_this_id,
-  mips_stub_frame_prev_register
+  mips_insn16_frame_this_id,
+  mips_insn16_frame_prev_register
 };
 
 static const struct frame_unwind *
-mips_stub_frame_sniffer (struct frame_info *next_frame)
+mips_insn16_frame_sniffer (struct frame_info *next_frame)
 {
   CORE_ADDR pc = frame_pc_unwind (next_frame);
-  if (in_plt_section (pc, NULL))
-    return &mips_stub_frame_unwind;
-  else
-    return NULL;
+  if (pc_is_mips16 (pc))
+    return &mips_insn16_frame_unwind;
+  return NULL;
 }
 
 static CORE_ADDR
-mips_stub_frame_base_address (struct frame_info *next_frame,
-                             void **this_cache)
+mips_insn16_frame_base_address (struct frame_info *next_frame,
+                               void **this_cache)
 {
-  struct trad_frame_cache *this_trad_cache
-    = mips_stub_frame_cache (next_frame, this_cache);
-  return trad_frame_get_this_base (this_trad_cache);
+  struct mips_frame_cache *info = mips_insn16_frame_cache (next_frame,
+                                                          this_cache);
+  return info->base;
 }
 
-static const struct frame_base mips_stub_frame_base =
+static const struct frame_base mips_insn16_frame_base =
 {
-  &mips_stub_frame_unwind,
-  mips_stub_frame_base_address,
-  mips_stub_frame_base_address,
-  mips_stub_frame_base_address
+  &mips_insn16_frame_unwind,
+  mips_insn16_frame_base_address,
+  mips_insn16_frame_base_address,
+  mips_insn16_frame_base_address
 };
 
 static const struct frame_base *
-mips_stub_frame_base_sniffer (struct frame_info *next_frame)
+mips_insn16_frame_base_sniffer (struct frame_info *next_frame)
 {
-  if (mips_stub_frame_sniffer (next_frame) != NULL)
-    return &mips_stub_frame_base;
+  if (mips_insn16_frame_sniffer (next_frame) != NULL)
+    return &mips_insn16_frame_base;
   else
     return NULL;
 }
 
-static CORE_ADDR
-read_next_frame_reg (struct frame_info *fi, int regno)
+/* Mark all the registers as unset in the saved_regs array
+   of THIS_CACHE.  Do nothing if THIS_CACHE is null.  */
+
+void
+reset_saved_regs (struct mips_frame_cache *this_cache)
 {
-  /* Always a pseudo.  */
-  gdb_assert (regno >= NUM_REGS);
-  if (fi == NULL)
-    {
-      LONGEST val;
-      regcache_cooked_read_signed (current_regcache, regno, &val);
-      return val;
-    }
-  else
-    return frame_unwind_register_signed (fi, regno);
+  if (this_cache == NULL || this_cache->saved_regs == NULL)
+    return;
+
+  {
+    const int num_regs = NUM_REGS;
+    int i;
 
+    for (i = 0; i < num_regs; i++)
+      {
+        this_cache->saved_regs[i].addr = -1;
+      }
+  }
 }
 
-/* mips_addr_bits_remove - remove useless address bits  */
+/* Analyze the function prologue from START_PC to LIMIT_PC. Builds
+   the associated FRAME_CACHE if not null.  
+   Return the address of the first instruction past the prologue.  */
 
 static CORE_ADDR
-mips_addr_bits_remove (CORE_ADDR addr)
+mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+                      struct frame_info *next_frame,
+                      struct mips_frame_cache *this_cache)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-  if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
-    /* This hack is a work-around for existing boards using PMON, the
-       simulator, and any other 64-bit targets that doesn't have true
-       64-bit addressing.  On these targets, the upper 32 bits of
-       addresses are ignored by the hardware.  Thus, the PC or SP are
-       likely to have been sign extended to all 1s by instruction
-       sequences that load 32-bit addresses.  For example, a typical
-       piece of code that loads an address is this:
+  CORE_ADDR cur_pc;
+  CORE_ADDR frame_addr = 0; /* Value of $r30. Used by gcc for frame-pointer */
+  CORE_ADDR sp;
+  long frame_offset;
+  int  frame_reg = MIPS_SP_REGNUM;
 
-       lui $r2, <upper 16 bits>
-       ori $r2, <lower 16 bits>
+  CORE_ADDR end_prologue_addr = 0;
+  int seen_sp_adjust = 0;
+  int load_immediate_bytes = 0;
 
-       But the lui sign-extends the value such that the upper 32 bits
-       may be all 1s.  The workaround is simply to mask off these
-       bits.  In the future, gcc may be changed to support true 64-bit
-       addressing, and this masking will have to be disabled.  */
-    return addr &= 0xffffffffUL;
+  /* Can be called when there's no process, and hence when there's no
+     NEXT_FRAME.  */
+  if (next_frame != NULL)
+    sp = read_next_frame_reg (next_frame, NUM_REGS + MIPS_SP_REGNUM);
   else
-    return 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 GNU/Linux for example).  We find
-   the target of the coming instruction and breakpoint it.
+    sp = 0;
 
-   single_step is also called just after the inferior stops.  If we had
-   set up a simulated single-step, we undo our damage.  */
+  if (limit_pc > start_pc + 200)
+    limit_pc = start_pc + 200;
 
-void
-mips_software_single_step (enum target_signal sig, int insert_breakpoints_p)
-{
-  static CORE_ADDR next_pc;
-  typedef char binsn_quantum[BREAKPOINT_MAX];
-  static binsn_quantum break_mem;
-  CORE_ADDR pc;
+restart:
 
-  if (insert_breakpoints_p)
+  frame_offset = 0;
+  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSTLEN)
     {
-      pc = read_register (mips_regnum (current_gdbarch)->pc);
-      next_pc = mips_next_pc (pc);
+      unsigned long inst, high_word, low_word;
+      int reg;
 
-      target_insert_breakpoint (next_pc, break_mem);
-    }
-  else
-    target_remove_breakpoint (next_pc, break_mem);
-}
+      /* Fetch the instruction.   */
+      inst = (unsigned long) mips_fetch_instruction (cur_pc);
 
-static struct mips_extra_func_info temp_proc_desc;
+      /* Save some code by pre-extracting some useful fields.  */
+      high_word = (inst >> 16) & 0xffff;
+      low_word = inst & 0xffff;
+      reg = high_word & 0x1f;
 
-/* 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 only recognize the first save of a given register in a
-   function prologue.
+      if (high_word == 0x27bd  /* addiu $sp,$sp,-i */
+         || high_word == 0x23bd        /* addi $sp,$sp,-i */
+         || high_word == 0x67bd)       /* daddiu $sp,$sp,-i */
+       {
+         if (low_word & 0x8000)        /* negative stack adjustment? */
+            frame_offset += 0x10000 - low_word;
+         else
+           /* Exit loop if a positive stack adjustment is found, which
+              usually means that the stack cleanup code in the function
+              epilogue is reached.  */
+           break;
+          seen_sp_adjust = 1;
+       }
+      else if ((high_word & 0xFFE0) == 0xafa0) /* sw reg,offset($sp) */
+       {
+         set_reg_offset (this_cache, reg, sp + low_word);
+       }
+      else if ((high_word & 0xFFE0) == 0xffa0) /* sd reg,offset($sp) */
+       {
+         /* Irix 6.2 N32 ABI uses sd instructions for saving $gp and $ra.  */
+         set_reg_offset (this_cache, reg, sp + low_word);
+       }
+      else if (high_word == 0x27be)    /* addiu $30,$sp,size */
+       {
+         /* Old gcc frame, r30 is virtual frame pointer.  */
+         if ((long) low_word != frame_offset)
+           frame_addr = sp + low_word;
+         else if (frame_reg == MIPS_SP_REGNUM)
+           {
+             unsigned alloca_adjust;
 
-   For simplicity, save the address in both [0 .. NUM_REGS) and
-   [NUM_REGS .. 2*NUM_REGS).  Strictly speaking, only the second range
-   is used as it is only second range (the ABI instead of ISA
-   registers) that comes into play when finding saved registers in a
-   frame.  */
+             frame_reg = 30;
+             frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
+             alloca_adjust = (unsigned) (frame_addr - (sp + low_word));
+             if (alloca_adjust > 0)
+               {
+                  /* FP > SP + frame_size. This may be because of
+                     an alloca or somethings similar.  Fix sp to
+                     "pre-alloca" value, and try again.  */
+                 sp += alloca_adjust;
+                  /* Need to reset the status of all registers.  Otherwise,
+                     we will hit a guard that prevents the new address
+                     for each register to be recomputed during the second
+                     pass.  */
+                  reset_saved_regs (this_cache);
+                 goto restart;
+               }
+           }
+       }
+      /* move $30,$sp.  With different versions of gas this will be either
+         `addu $30,$sp,$zero' or `or $30,$sp,$zero' or `daddu 30,sp,$0'.
+         Accept any one of these.  */
+      else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
+       {
+         /* New gcc frame, virtual frame pointer is at r30 + frame_size.  */
+         if (frame_reg == MIPS_SP_REGNUM)
+           {
+             unsigned alloca_adjust;
 
-static void
-set_reg_offset (struct mips_frame_cache *this_cache, int regnum,
-               CORE_ADDR offset)
-{
-  if (this_cache != NULL
-      && this_cache->saved_regs[regnum].addr == -1)
-    {
-      this_cache->saved_regs[regnum + 0 * NUM_REGS].addr = offset;
-      this_cache->saved_regs[regnum + 1 * NUM_REGS].addr = offset;
+             frame_reg = 30;
+             frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
+             alloca_adjust = (unsigned) (frame_addr - sp);
+             if (alloca_adjust > 0)
+               {
+                  /* FP > SP + frame_size. This may be because of
+                     an alloca or somethings similar.  Fix sp to
+                     "pre-alloca" value, and try again.  */
+                 sp = frame_addr;
+                  /* Need to reset the status of all registers.  Otherwise,
+                     we will hit a guard that prevents the new address
+                     for each register to be recomputed during the second
+                     pass.  */
+                  reset_saved_regs (this_cache);
+                 goto restart;
+               }
+           }
+       }
+      else if ((high_word & 0xFFE0) == 0xafc0) /* sw reg,offset($30) */
+       {
+         set_reg_offset (this_cache, reg, frame_addr + low_word);
+       }
+      else if ((high_word & 0xFFE0) == 0xE7A0 /* swc1 freg,n($sp) */
+               || (high_word & 0xF3E0) == 0xA3C0 /* sx reg,n($s8) */
+               || (inst & 0xFF9F07FF) == 0x00800021 /* move reg,$a0-$a3 */
+               || high_word == 0x3c1c /* lui $gp,n */
+               || high_word == 0x279c /* addiu $gp,$gp,n */
+               || inst == 0x0399e021 /* addu $gp,$gp,$t9 */
+               || inst == 0x033ce021 /* addu $gp,$t9,$gp */
+              )
+       {
+         /* These instructions are part of the prologue, but we don't
+            need to do anything special to handle them.  */
+       }
+      /* The instructions below 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
+               && (high_word == 0x3c01 /* lui $at,n */
+                   || high_word == 0x3c08 /* lui $t0,n */
+                   || high_word == 0x3421 /* ori $at,$at,n */
+                   || high_word == 0x3508 /* ori $t0,$t0,n */
+                   || high_word == 0x3401 /* ori $at,$zero,n */
+                   || high_word == 0x3408 /* ori $t0,$zero,n */
+                  ))
+       {
+          load_immediate_bytes += MIPS_INSTLEN;     /* FIXME!! */
+       }
+      else
+       {
+         /* This instruction is not an instruction typically found
+            in a prologue, so we must have reached the end of the
+            prologue.  */
+         /* FIXME: brobecker/2004-10-10: Can't we just break out of this
+            loop now?  Why would we need to continue scanning the function
+            instructions?  */
+         if (end_prologue_addr == 0)
+           end_prologue_addr = cur_pc;
+       }
     }
-}
 
+  if (this_cache != NULL)
+    {
+      this_cache->base = 
+        (frame_unwind_register_signed (next_frame, NUM_REGS + frame_reg)
+         + frame_offset);
+      /* FIXME: brobecker/2004-09-15: We should be able to get rid of
+         this assignment below, eventually.  But it's still needed
+         for now.  */
+      this_cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
+        = this_cache->saved_regs[NUM_REGS + RA_REGNUM];
+    }
 
-/* Test whether the PC points to the return instruction at the
-   end of a function. */
+  /* If we didn't reach the end of the prologue when scanning the function
+     instructions, then set end_prologue_addr to the address of the
+     instruction immediately after the last one we scanned.  */
+  /* brobecker/2004-10-10: I don't think this would ever happen, but
+     we may as well be careful and do our best if we have a null
+     end_prologue_addr.  */
+  if (end_prologue_addr == 0)
+    end_prologue_addr = cur_pc;
+     
+  /* 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)
+    end_prologue_addr -= load_immediate_bytes;
 
-static int
-mips_about_to_return (CORE_ADDR pc)
-{
-  if (pc_is_mips16 (pc))
-    /* This mips16 case isn't necessarily reliable.  Sometimes the compiler
-       generates a "jr $ra"; other times it generates code to load
-       the return address from the stack to an accessible register (such
-       as $a3), then a "jr" using that register.  This second case
-       is almost impossible to distinguish from an indirect jump
-       used for switch statements, so we don't even try.  */
-    return mips_fetch_instruction (pc) == 0xe820;      /* jr $ra */
-  else
-    return mips_fetch_instruction (pc) == 0x3e00008;   /* jr $ra */
+  return end_prologue_addr;
 }
 
+/* Heuristic unwinder for procedures using 32-bit instructions (covers
+   both 32-bit and 64-bit MIPS ISAs).  Procedures using 16-bit
+   instructions (a.k.a. MIPS16) are handled by the mips_insn16
+   unwinder.  */
 
-/* This fencepost looks highly suspicious to me.  Removing it also
-   seems suspicious as it could affect remote debugging across serial
-   lines.  */
-
-static CORE_ADDR
-heuristic_proc_start (CORE_ADDR pc)
+static struct mips_frame_cache *
+mips_insn32_frame_cache (struct frame_info *next_frame, void **this_cache)
 {
-  CORE_ADDR start_pc;
-  CORE_ADDR fence;
-  int instlen;
-  int seen_adjsp = 0;
-
-  pc = ADDR_BITS_REMOVE (pc);
-  start_pc = pc;
-  fence = start_pc - heuristic_fence_post;
-  if (start_pc == 0)
-    return 0;
-
-  if (heuristic_fence_post == UINT_MAX || fence < VM_MIN_ADDRESS)
-    fence = VM_MIN_ADDRESS;
-
-  instlen = pc_is_mips16 (pc) ? MIPS16_INSTLEN : MIPS_INSTLEN;
+  struct mips_frame_cache *cache;
 
-  /* search back for previous return */
-  for (start_pc -= instlen;; start_pc -= instlen)
-    if (start_pc < fence)
-      {
-       /* It's not clear to me why we reach this point when
-          stop_soon, but with this test, at least we
-          don't print out warnings for every child forked (eg, on
-          decstation).  22apr93 rich@cygnus.com.  */
-       if (stop_soon == NO_STOP_QUIETLY)
-         {
-           static int blurb_printed = 0;
+  if ((*this_cache) != NULL)
+    return (*this_cache);
 
-           warning ("GDB can't find the start of the function at 0x%s.",
-                    paddr_nz (pc));
+  cache = FRAME_OBSTACK_ZALLOC (struct mips_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
-           if (!blurb_printed)
-             {
-               /* This actually happens frequently in embedded
-                  development, when you first connect to a board
-                  and your stack pointer and pc are nowhere in
-                  particular.  This message needs to give people
-                  in that situation enough information to
-                  determine that it's no big deal.  */
-               printf_filtered ("\n\
-    GDB is unable to find the start of the function at 0x%s\n\
-and thus can't determine the size of that function's stack frame.\n\
-This means that GDB may be unable to access that stack frame, or\n\
-the frames below it.\n\
-    This problem is most likely caused by an invalid program counter or\n\
-stack pointer.\n\
-    However, if you think GDB should simply search farther back\n\
-from 0x%s for code which looks like the beginning of a\n\
-function, you can increase the range of the search using the `set\n\
-heuristic-fence-post' command.\n", paddr_nz (pc), paddr_nz (pc));
-               blurb_printed = 1;
-             }
-         }
+  /* Analyze the function prologue.  */
+  {
+    const CORE_ADDR pc = frame_pc_unwind (next_frame);
+    CORE_ADDR start_addr;
 
-       return 0;
-      }
-    else if (pc_is_mips16 (start_pc))
-      {
-       unsigned short inst;
+    find_pc_partial_function (pc, NULL, &start_addr, NULL);
+    if (start_addr == 0)
+      start_addr = heuristic_proc_start (pc);
+    /* We can't analyze the prologue if we couldn't find the begining
+       of the function.  */
+    if (start_addr == 0)
+      return cache;
 
-       /* On MIPS16, any one of the following is likely to be the
-          start of a function:
-          entry
-          addiu sp,-n
-          daddiu sp,-n
-          extend -n followed by 'addiu sp,+n' or 'daddiu sp,+n'  */
-       inst = mips_fetch_instruction (start_pc);
-       if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700)      /* entry */
-           || (inst & 0xff80) == 0x6380        /* addiu sp,-n */
-           || (inst & 0xff80) == 0xfb80        /* daddiu sp,-n */
-           || ((inst & 0xf810) == 0xf010 && seen_adjsp))       /* extend -n */
-         break;
-       else if ((inst & 0xff00) == 0x6300      /* addiu sp */
-                || (inst & 0xff00) == 0xfb00)  /* daddiu sp */
-         seen_adjsp = 1;
-       else
-         seen_adjsp = 0;
-      }
-    else if (mips_about_to_return (start_pc))
-      {
-       start_pc += 2 * MIPS_INSTLEN;   /* skip return, and its delay slot */
-       break;
-      }
+    mips32_scan_prologue (start_addr, pc, next_frame, *this_cache);
+  }
+  
+  /* SP_REGNUM, contains the value and not the address.  */
+  trad_frame_set_value (cache->saved_regs, NUM_REGS + MIPS_SP_REGNUM, cache->base);
 
-  return start_pc;
+  return (*this_cache);
 }
 
-/* Fetch the immediate value from a MIPS16 instruction.
-   If the previous instruction was an EXTEND, use it to extend
-   the upper bits of the immediate value.  This is a helper function
-   for mips16_scan_prologue.  */
-
-static int
-mips16_get_imm (unsigned short prev_inst,      /* previous instruction */
-               unsigned short inst,    /* current instruction */
-               int nbits,      /* number of bits in imm field */
-               int scale,      /* scale factor to be applied to imm */
-               int is_signed)  /* is the imm field signed? */
+static void
+mips_insn32_frame_this_id (struct frame_info *next_frame, void **this_cache,
+                          struct frame_id *this_id)
 {
-  int offset;
-
-  if ((prev_inst & 0xf800) == 0xf000)  /* prev instruction was EXTEND? */
-    {
-      offset = ((prev_inst & 0x1f) << 11) | (prev_inst & 0x7e0);
-      if (offset & 0x8000)     /* check for negative extend */
-       offset = 0 - (0x10000 - (offset & 0xffff));
-      return offset | (inst & 0x1f);
-    }
-  else
-    {
-      int max_imm = 1 << nbits;
-      int mask = max_imm - 1;
-      int sign_bit = max_imm >> 1;
+  struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
+                                                          this_cache);
+  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+}
 
-      offset = inst & mask;
-      if (is_signed && (offset & sign_bit))
-       offset = 0 - (max_imm - offset);
-      return offset * scale;
-    }
+static void
+mips_insn32_frame_prev_register (struct frame_info *next_frame,
+                                void **this_cache,
+                                int regnum, int *optimizedp,
+                                enum lval_type *lvalp, CORE_ADDR *addrp,
+                                int *realnump, void *valuep)
+{
+  struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
+                                                          this_cache);
+  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
+                               optimizedp, lvalp, addrp, realnump, valuep);
 }
 
+static const struct frame_unwind mips_insn32_frame_unwind =
+{
+  NORMAL_FRAME,
+  mips_insn32_frame_this_id,
+  mips_insn32_frame_prev_register
+};
 
-/* Analyze the function prologue from START_PC to LIMIT_PC. Builds
-   the associated FRAME_CACHE if not null.
-   Return the address of the first instruction past the prologue.  */
+static const struct frame_unwind *
+mips_insn32_frame_sniffer (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  if (! pc_is_mips16 (pc))
+    return &mips_insn32_frame_unwind;
+  return NULL;
+}
 
 static CORE_ADDR
-mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
-                      struct frame_info *next_frame,
-                      struct mips_frame_cache *this_cache)
+mips_insn32_frame_base_address (struct frame_info *next_frame,
+                               void **this_cache)
 {
-  CORE_ADDR cur_pc;
-  CORE_ADDR frame_addr = 0;    /* Value of $r17, used as frame pointer */
-  CORE_ADDR sp;
-  long frame_offset = 0;        /* Size of stack frame.  */
-  long frame_adjust = 0;        /* Offset of FP from SP.  */
-  int frame_reg = MIPS_SP_REGNUM;
-  unsigned short prev_inst = 0;        /* saved copy of previous instruction */
-  unsigned inst = 0;           /* current instruction */
-  unsigned entry_inst = 0;     /* the entry instruction */
-  int reg, offset;
+  struct mips_frame_cache *info = mips_insn32_frame_cache (next_frame,
+                                                          this_cache);
+  return info->base;
+}
 
-  int extend_bytes = 0;
-  int prev_extend_bytes;
-  CORE_ADDR end_prologue_addr = 0;
+static const struct frame_base mips_insn32_frame_base =
+{
+  &mips_insn32_frame_unwind,
+  mips_insn32_frame_base_address,
+  mips_insn32_frame_base_address,
+  mips_insn32_frame_base_address
+};
 
-  /* Can be called when there's no process, and hence when there's no
-     NEXT_FRAME.  */
-  if (next_frame != NULL)
-    sp = read_next_frame_reg (next_frame, NUM_REGS + MIPS_SP_REGNUM);
+static const struct frame_base *
+mips_insn32_frame_base_sniffer (struct frame_info *next_frame)
+{
+  if (mips_insn32_frame_sniffer (next_frame) != NULL)
+    return &mips_insn32_frame_base;
   else
-    sp = 0;
-
-  if (limit_pc > start_pc + 200)
-    limit_pc = start_pc + 200;
+    return NULL;
+}
 
-  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS16_INSTLEN)
-    {
-      /* Save the previous instruction.  If it's an EXTEND, we'll extract
-         the immediate offset extension from it in mips16_get_imm.  */
-      prev_inst = inst;
+static struct trad_frame_cache *
+mips_stub_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+  CORE_ADDR pc;
+  CORE_ADDR start_addr;
+  CORE_ADDR stack_addr;
+  struct trad_frame_cache *this_trad_cache;
 
-      /* Fetch and decode the instruction.   */
-      inst = (unsigned short) mips_fetch_instruction (cur_pc);
+  if ((*this_cache) != NULL)
+    return (*this_cache);
+  this_trad_cache = trad_frame_cache_zalloc (next_frame);
+  (*this_cache) = this_trad_cache;
 
-      /* Normally we ignore extend instructions.  However, if it is
-         not followed by a valid prologue instruction, then this
-         instruction is not part of the prologue either.  We must
-         remember in this case to adjust the end_prologue_addr back
-         over the extend.  */
-      if ((inst & 0xf800) == 0xf000)    /* extend */
-        {
-          extend_bytes = MIPS16_INSTLEN;
-          continue;
-        }
+  /* The return address is in the link register.  */
+  trad_frame_set_reg_realreg (this_trad_cache, PC_REGNUM, RA_REGNUM);
 
-      prev_extend_bytes = extend_bytes;
-      extend_bytes = 0;
+  /* Frame ID, since it's a frameless / stackless function, no stack
+     space is allocated and SP on entry is the current SP.  */
+  pc = frame_pc_unwind (next_frame);
+  find_pc_partial_function (pc, NULL, &start_addr, NULL);
+  stack_addr = frame_unwind_register_signed (next_frame, SP_REGNUM);
+  trad_frame_set_id (this_trad_cache, frame_id_build (start_addr, stack_addr));
 
-      if ((inst & 0xff00) == 0x6300    /* addiu sp */
-         || (inst & 0xff00) == 0xfb00) /* daddiu sp */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 8, 8, 1);
-         if (offset < 0)       /* negative stack adjustment? */
-           frame_offset -= offset;
-         else
-           /* Exit loop if a positive stack adjustment is found, which
-              usually means that the stack cleanup code in the function
-              epilogue is reached.  */
-           break;
-       }
-      else if ((inst & 0xf800) == 0xd000)      /* sw reg,n($sp) */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
-         reg = mips16_to_32_reg[(inst & 0x700) >> 8];
-         set_reg_offset (this_cache, reg, sp + offset);
-       }
-      else if ((inst & 0xff00) == 0xf900)      /* sd reg,n($sp) */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
-         reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
-         set_reg_offset (this_cache, reg, sp + offset);
-       }
-      else if ((inst & 0xff00) == 0x6200)      /* sw $ra,n($sp) */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
-         set_reg_offset (this_cache, RA_REGNUM, sp + offset);
-       }
-      else if ((inst & 0xff00) == 0xfa00)      /* sd $ra,n($sp) */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 8, 8, 0);
-         set_reg_offset (this_cache, RA_REGNUM, sp + offset);
-       }
-      else if (inst == 0x673d) /* move $s1, $sp */
-       {
-         frame_addr = sp;
-         frame_reg = 17;
-       }
-      else if ((inst & 0xff00) == 0x0100)      /* addiu $s1,sp,n */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 8, 4, 0);
-         frame_addr = sp + offset;
-         frame_reg = 17;
-         frame_adjust = offset;
-       }
-      else if ((inst & 0xFF00) == 0xd900)      /* sw reg,offset($s1) */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 5, 4, 0);
-         reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
-         set_reg_offset (this_cache, reg, frame_addr + offset);
-       }
-      else if ((inst & 0xFF00) == 0x7900)      /* sd reg,offset($s1) */
-       {
-         offset = mips16_get_imm (prev_inst, inst, 5, 8, 0);
-         reg = mips16_to_32_reg[(inst & 0xe0) >> 5];
-         set_reg_offset (this_cache, reg, frame_addr + offset);
-       }
-      else if ((inst & 0xf81f) == 0xe809
-               && (inst & 0x700) != 0x700)     /* entry */
-       entry_inst = inst;      /* save for later processing */
-      else if ((inst & 0xf800) == 0x1800)      /* jal(x) */
-       cur_pc += MIPS16_INSTLEN;       /* 32-bit instruction */
-      else if ((inst & 0xff1c) == 0x6704)      /* move reg,$a0-$a3 */
-        {
-          /* This instruction is part of the prologue, but we don't
-             need to do anything special to handle it.  */
-        }
-      else
-        {
-          /* This instruction is not an instruction typically found
-             in a prologue, so we must have reached the end of the
-             prologue.  */
-          if (end_prologue_addr == 0)
-            end_prologue_addr = cur_pc - prev_extend_bytes;
-        }
-    }
+  /* Assume that the frame's base is the same as the
+     stack-pointer.  */
+  trad_frame_set_this_base (this_trad_cache, stack_addr);
 
-  /* The entry instruction is typically the first instruction in a function,
-     and it stores registers at offsets relative to the value of the old SP
-     (before the prologue).  But the value of the sp parameter to this
-     function is the new SP (after the prologue has been executed).  So we
-     can't calculate those offsets until we've seen the entire prologue,
-     and can calculate what the old SP must have been. */
-  if (entry_inst != 0)
-    {
-      int areg_count = (entry_inst >> 8) & 7;
-      int sreg_count = (entry_inst >> 6) & 3;
+  return this_trad_cache;
+}
 
-      /* The entry instruction always subtracts 32 from the SP.  */
-      frame_offset += 32;
+static void
+mips_stub_frame_this_id (struct frame_info *next_frame, void **this_cache,
+                        struct frame_id *this_id)
+{
+  struct trad_frame_cache *this_trad_cache
+    = mips_stub_frame_cache (next_frame, this_cache);
+  trad_frame_get_id (this_trad_cache, this_id);
+}
 
-      /* Now we can calculate what the SP must have been at the
-         start of the function prologue.  */
-      sp += frame_offset;
+static void
+mips_stub_frame_prev_register (struct frame_info *next_frame,
+                                void **this_cache,
+                                int regnum, int *optimizedp,
+                                enum lval_type *lvalp, CORE_ADDR *addrp,
+                                int *realnump, void *valuep)
+{
+  struct trad_frame_cache *this_trad_cache
+    = mips_stub_frame_cache (next_frame, this_cache);
+  trad_frame_get_register (this_trad_cache, next_frame, regnum, optimizedp,
+                          lvalp, addrp, realnump, valuep);
+}
 
-      /* Check if a0-a3 were saved in the caller's argument save area.  */
-      for (reg = 4, offset = 0; reg < areg_count + 4; reg++)
-       {
-         set_reg_offset (this_cache, reg, sp + offset);
-         offset += mips_abi_regsize (current_gdbarch);
-       }
+static const struct frame_unwind mips_stub_frame_unwind =
+{
+  NORMAL_FRAME,
+  mips_stub_frame_this_id,
+  mips_stub_frame_prev_register
+};
 
-      /* Check if the ra register was pushed on the stack.  */
-      offset = -4;
-      if (entry_inst & 0x20)
-       {
-         set_reg_offset (this_cache, RA_REGNUM, sp + offset);
-         offset -= mips_abi_regsize (current_gdbarch);
-       }
+static const struct frame_unwind *
+mips_stub_frame_sniffer (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  if (in_plt_section (pc, NULL))
+    return &mips_stub_frame_unwind;
+  else
+    return NULL;
+}
 
-      /* Check if the s0 and s1 registers were pushed on the stack.  */
-      for (reg = 16; reg < sreg_count + 16; reg++)
-       {
-         set_reg_offset (this_cache, reg, sp + offset);
-         offset -= mips_abi_regsize (current_gdbarch);
-       }
-    }
+static CORE_ADDR
+mips_stub_frame_base_address (struct frame_info *next_frame,
+                             void **this_cache)
+{
+  struct trad_frame_cache *this_trad_cache
+    = mips_stub_frame_cache (next_frame, this_cache);
+  return trad_frame_get_this_base (this_trad_cache);
+}
 
-  if (this_cache != NULL)
+static const struct frame_base mips_stub_frame_base =
+{
+  &mips_stub_frame_unwind,
+  mips_stub_frame_base_address,
+  mips_stub_frame_base_address,
+  mips_stub_frame_base_address
+};
+
+static const struct frame_base *
+mips_stub_frame_base_sniffer (struct frame_info *next_frame)
+{
+  if (mips_stub_frame_sniffer (next_frame) != NULL)
+    return &mips_stub_frame_base;
+  else
+    return NULL;
+}
+
+static CORE_ADDR
+read_next_frame_reg (struct frame_info *fi, int regno)
+{
+  /* Always a pseudo.  */
+  gdb_assert (regno >= NUM_REGS);
+  if (fi == NULL)
     {
-      this_cache->base =
-        (frame_unwind_register_signed (next_frame, NUM_REGS + frame_reg)
-         + frame_offset - frame_adjust);
-      /* FIXME: brobecker/2004-10-10: Just as in the mips32 case, we should
-         be able to get rid of the assignment below, evetually. But it's
-         still needed for now.  */
-      this_cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
-        = this_cache->saved_regs[NUM_REGS + RA_REGNUM];
+      LONGEST val;
+      regcache_cooked_read_signed (current_regcache, regno, &val);
+      return val;
     }
+  else
+    return frame_unwind_register_signed (fi, regno);
 
-  /* If we didn't reach the end of the prologue when scanning the function
-     instructions, then set end_prologue_addr to the address of the
-     instruction immediately after the last one we scanned.  */
-  if (end_prologue_addr == 0)
-    end_prologue_addr = cur_pc;
-
-  return end_prologue_addr;
 }
 
-/* Mark all the registers as unset in the saved_regs array
-   of THIS_CACHE.  Do nothing if THIS_CACHE is null.  */
+/* mips_addr_bits_remove - remove useless address bits  */
 
-void
-reset_saved_regs (struct mips_frame_cache *this_cache)
+static CORE_ADDR
+mips_addr_bits_remove (CORE_ADDR addr)
 {
-  if (this_cache == NULL || this_cache->saved_regs == NULL)
-    return;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
+    /* This hack is a work-around for existing boards using PMON, the
+       simulator, and any other 64-bit targets that doesn't have true
+       64-bit addressing.  On these targets, the upper 32 bits of
+       addresses are ignored by the hardware.  Thus, the PC or SP are
+       likely to have been sign extended to all 1s by instruction
+       sequences that load 32-bit addresses.  For example, a typical
+       piece of code that loads an address is this:
 
-  {
-    const int num_regs = NUM_REGS;
-    int i;
+       lui $r2, <upper 16 bits>
+       ori $r2, <lower 16 bits>
 
-    for (i = 0; i < num_regs; i++)
-      {
-        this_cache->saved_regs[i].addr = -1;
-      }
-  }
+       But the lui sign-extends the value such that the upper 32 bits
+       may be all 1s.  The workaround is simply to mask off these
+       bits.  In the future, gcc may be changed to support true 64-bit
+       addressing, and this masking will have to be disabled.  */
+    return addr &= 0xffffffffUL;
+  else
+    return addr;
 }
 
-/* Analyze the function prologue from START_PC to LIMIT_PC. Builds
-   the associated FRAME_CACHE if not null.  
-   Return the address of the first instruction past the prologue.  */
+/* 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 GNU/Linux for example).  We find
+   the target of the coming instruction and breakpoint it.
 
-static CORE_ADDR
-mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
-                      struct frame_info *next_frame,
-                      struct mips_frame_cache *this_cache)
+   single_step is also called just after the inferior stops.  If we had
+   set up a simulated single-step, we undo our damage.  */
+
+void
+mips_software_single_step (enum target_signal sig, int insert_breakpoints_p)
 {
-  CORE_ADDR cur_pc;
-  CORE_ADDR frame_addr = 0; /* Value of $r30. Used by gcc for frame-pointer */
-  CORE_ADDR sp;
-  long frame_offset;
-  int  frame_reg = MIPS_SP_REGNUM;
+  static CORE_ADDR next_pc;
+  typedef char binsn_quantum[BREAKPOINT_MAX];
+  static binsn_quantum break_mem;
+  CORE_ADDR pc;
 
-  CORE_ADDR end_prologue_addr = 0;
-  int seen_sp_adjust = 0;
-  int load_immediate_bytes = 0;
+  if (insert_breakpoints_p)
+    {
+      pc = read_register (mips_regnum (current_gdbarch)->pc);
+      next_pc = mips_next_pc (pc);
 
-  /* Can be called when there's no process, and hence when there's no
-     NEXT_FRAME.  */
-  if (next_frame != NULL)
-    sp = read_next_frame_reg (next_frame, NUM_REGS + MIPS_SP_REGNUM);
+      target_insert_breakpoint (next_pc, break_mem);
+    }
   else
-    sp = 0;
+    target_remove_breakpoint (next_pc, break_mem);
+}
 
-  if (limit_pc > start_pc + 200)
-    limit_pc = start_pc + 200;
+static struct mips_extra_func_info temp_proc_desc;
 
-restart:
+/* Test whether the PC points to the return instruction at the
+   end of a function. */
 
-  frame_offset = 0;
-  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSTLEN)
-    {
-      unsigned long inst, high_word, low_word;
-      int reg;
+static int
+mips_about_to_return (CORE_ADDR pc)
+{
+  if (pc_is_mips16 (pc))
+    /* This mips16 case isn't necessarily reliable.  Sometimes the compiler
+       generates a "jr $ra"; other times it generates code to load
+       the return address from the stack to an accessible register (such
+       as $a3), then a "jr" using that register.  This second case
+       is almost impossible to distinguish from an indirect jump
+       used for switch statements, so we don't even try.  */
+    return mips_fetch_instruction (pc) == 0xe820;      /* jr $ra */
+  else
+    return mips_fetch_instruction (pc) == 0x3e00008;   /* jr $ra */
+}
 
-      /* Fetch the instruction.   */
-      inst = (unsigned long) mips_fetch_instruction (cur_pc);
 
-      /* Save some code by pre-extracting some useful fields.  */
-      high_word = (inst >> 16) & 0xffff;
-      low_word = inst & 0xffff;
-      reg = high_word & 0x1f;
+/* This fencepost looks highly suspicious to me.  Removing it also
+   seems suspicious as it could affect remote debugging across serial
+   lines.  */
 
-      if (high_word == 0x27bd  /* addiu $sp,$sp,-i */
-         || high_word == 0x23bd        /* addi $sp,$sp,-i */
-         || high_word == 0x67bd)       /* daddiu $sp,$sp,-i */
-       {
-         if (low_word & 0x8000)        /* negative stack adjustment? */
-            frame_offset += 0x10000 - low_word;
-         else
-           /* Exit loop if a positive stack adjustment is found, which
-              usually means that the stack cleanup code in the function
-              epilogue is reached.  */
-           break;
-          seen_sp_adjust = 1;
-       }
-      else if ((high_word & 0xFFE0) == 0xafa0) /* sw reg,offset($sp) */
-       {
-         set_reg_offset (this_cache, reg, sp + low_word);
-       }
-      else if ((high_word & 0xFFE0) == 0xffa0) /* sd reg,offset($sp) */
-       {
-         /* Irix 6.2 N32 ABI uses sd instructions for saving $gp and $ra.  */
-         set_reg_offset (this_cache, reg, sp + low_word);
-       }
-      else if (high_word == 0x27be)    /* addiu $30,$sp,size */
-       {
-         /* Old gcc frame, r30 is virtual frame pointer.  */
-         if ((long) low_word != frame_offset)
-           frame_addr = sp + low_word;
-         else if (frame_reg == MIPS_SP_REGNUM)
-           {
-             unsigned alloca_adjust;
+static CORE_ADDR
+heuristic_proc_start (CORE_ADDR pc)
+{
+  CORE_ADDR start_pc;
+  CORE_ADDR fence;
+  int instlen;
+  int seen_adjsp = 0;
 
-             frame_reg = 30;
-             frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
-             alloca_adjust = (unsigned) (frame_addr - (sp + low_word));
-             if (alloca_adjust > 0)
-               {
-                  /* FP > SP + frame_size. This may be because of
-                     an alloca or somethings similar.  Fix sp to
-                     "pre-alloca" value, and try again.  */
-                 sp += alloca_adjust;
-                  /* Need to reset the status of all registers.  Otherwise,
-                     we will hit a guard that prevents the new address
-                     for each register to be recomputed during the second
-                     pass.  */
-                  reset_saved_regs (this_cache);
-                 goto restart;
-               }
-           }
-       }
-      /* move $30,$sp.  With different versions of gas this will be either
-         `addu $30,$sp,$zero' or `or $30,$sp,$zero' or `daddu 30,sp,$0'.
-         Accept any one of these.  */
-      else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
-       {
-         /* New gcc frame, virtual frame pointer is at r30 + frame_size.  */
-         if (frame_reg == MIPS_SP_REGNUM)
-           {
-             unsigned alloca_adjust;
+  pc = ADDR_BITS_REMOVE (pc);
+  start_pc = pc;
+  fence = start_pc - heuristic_fence_post;
+  if (start_pc == 0)
+    return 0;
 
-             frame_reg = 30;
-             frame_addr = read_next_frame_reg (next_frame, NUM_REGS + 30);
-             alloca_adjust = (unsigned) (frame_addr - sp);
-             if (alloca_adjust > 0)
-               {
-                  /* FP > SP + frame_size. This may be because of
-                     an alloca or somethings similar.  Fix sp to
-                     "pre-alloca" value, and try again.  */
-                 sp = frame_addr;
-                  /* Need to reset the status of all registers.  Otherwise,
-                     we will hit a guard that prevents the new address
-                     for each register to be recomputed during the second
-                     pass.  */
-                  reset_saved_regs (this_cache);
-                 goto restart;
-               }
-           }
-       }
-      else if ((high_word & 0xFFE0) == 0xafc0) /* sw reg,offset($30) */
-       {
-         set_reg_offset (this_cache, reg, frame_addr + low_word);
-       }
-      else if ((high_word & 0xFFE0) == 0xE7A0 /* swc1 freg,n($sp) */
-               || (high_word & 0xF3E0) == 0xA3C0 /* sx reg,n($s8) */
-               || (inst & 0xFF9F07FF) == 0x00800021 /* move reg,$a0-$a3 */
-               || high_word == 0x3c1c /* lui $gp,n */
-               || high_word == 0x279c /* addiu $gp,$gp,n */
-               || inst == 0x0399e021 /* addu $gp,$gp,$t9 */
-               || inst == 0x033ce021 /* addu $gp,$t9,$gp */
-              )
-       {
-         /* These instructions are part of the prologue, but we don't
-            need to do anything special to handle them.  */
-       }
-      /* The instructions below 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
-               && (high_word == 0x3c01 /* lui $at,n */
-                   || high_word == 0x3c08 /* lui $t0,n */
-                   || high_word == 0x3421 /* ori $at,$at,n */
-                   || high_word == 0x3508 /* ori $t0,$t0,n */
-                   || high_word == 0x3401 /* ori $at,$zero,n */
-                   || high_word == 0x3408 /* ori $t0,$zero,n */
-                  ))
-       {
-          load_immediate_bytes += MIPS_INSTLEN;     /* FIXME!! */
-       }
-      else
-       {
-         /* This instruction is not an instruction typically found
-            in a prologue, so we must have reached the end of the
-            prologue.  */
-         /* FIXME: brobecker/2004-10-10: Can't we just break out of this
-            loop now?  Why would we need to continue scanning the function
-            instructions?  */
-         if (end_prologue_addr == 0)
-           end_prologue_addr = cur_pc;
-       }
-    }
+  if (heuristic_fence_post == UINT_MAX || fence < VM_MIN_ADDRESS)
+    fence = VM_MIN_ADDRESS;
 
-  if (this_cache != NULL)
-    {
-      this_cache->base = 
-        (frame_unwind_register_signed (next_frame, NUM_REGS + frame_reg)
-         + frame_offset);
-      /* FIXME: brobecker/2004-09-15: We should be able to get rid of
-         this assignment below, eventually.  But it's still needed
-         for now.  */
-      this_cache->saved_regs[NUM_REGS + mips_regnum (current_gdbarch)->pc]
-        = this_cache->saved_regs[NUM_REGS + RA_REGNUM];
-    }
+  instlen = pc_is_mips16 (pc) ? MIPS16_INSTLEN : MIPS_INSTLEN;
 
-  /* If we didn't reach the end of the prologue when scanning the function
-     instructions, then set end_prologue_addr to the address of the
-     instruction immediately after the last one we scanned.  */
-  /* brobecker/2004-10-10: I don't think this would ever happen, but
-     we may as well be careful and do our best if we have a null
-     end_prologue_addr.  */
-  if (end_prologue_addr == 0)
-    end_prologue_addr = cur_pc;
-     
-  /* 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)
-    end_prologue_addr -= load_immediate_bytes;
+  /* search back for previous return */
+  for (start_pc -= instlen;; start_pc -= instlen)
+    if (start_pc < fence)
+      {
+       /* It's not clear to me why we reach this point when
+          stop_soon, but with this test, at least we
+          don't print out warnings for every child forked (eg, on
+          decstation).  22apr93 rich@cygnus.com.  */
+       if (stop_soon == NO_STOP_QUIETLY)
+         {
+           static int blurb_printed = 0;
 
-  return end_prologue_addr;
+           warning ("GDB can't find the start of the function at 0x%s.",
+                    paddr_nz (pc));
+
+           if (!blurb_printed)
+             {
+               /* This actually happens frequently in embedded
+                  development, when you first connect to a board
+                  and your stack pointer and pc are nowhere in
+                  particular.  This message needs to give people
+                  in that situation enough information to
+                  determine that it's no big deal.  */
+               printf_filtered ("\n\
+    GDB is unable to find the start of the function at 0x%s\n\
+and thus can't determine the size of that function's stack frame.\n\
+This means that GDB may be unable to access that stack frame, or\n\
+the frames below it.\n\
+    This problem is most likely caused by an invalid program counter or\n\
+stack pointer.\n\
+    However, if you think GDB should simply search farther back\n\
+from 0x%s for code which looks like the beginning of a\n\
+function, you can increase the range of the search using the `set\n\
+heuristic-fence-post' command.\n", paddr_nz (pc), paddr_nz (pc));
+               blurb_printed = 1;
+             }
+         }
+
+       return 0;
+      }
+    else if (pc_is_mips16 (start_pc))
+      {
+       unsigned short inst;
+
+       /* On MIPS16, any one of the following is likely to be the
+          start of a function:
+          entry
+          addiu sp,-n
+          daddiu sp,-n
+          extend -n followed by 'addiu sp,+n' or 'daddiu sp,+n'  */
+       inst = mips_fetch_instruction (start_pc);
+       if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700)      /* entry */
+           || (inst & 0xff80) == 0x6380        /* addiu sp,-n */
+           || (inst & 0xff80) == 0xfb80        /* daddiu sp,-n */
+           || ((inst & 0xf810) == 0xf010 && seen_adjsp))       /* extend -n */
+         break;
+       else if ((inst & 0xff00) == 0x6300      /* addiu sp */
+                || (inst & 0xff00) == 0xfb00)  /* daddiu sp */
+         seen_adjsp = 1;
+       else
+         seen_adjsp = 0;
+      }
+    else if (mips_about_to_return (start_pc))
+      {
+       start_pc += 2 * MIPS_INSTLEN;   /* skip return, and its delay slot */
+       break;
+      }
+
+  return start_pc;
 }
 
 static mips_extra_func_info_t