* mips-tdep.c (mips_skip_prologue): New argument lenient.
authorJim Kingdon <jkingdon@engr.sgi.com>
Mon, 19 Jul 1993 02:28:21 +0000 (02:28 +0000)
committerJim Kingdon <jkingdon@engr.sgi.com>
Mon, 19 Jul 1993 02:28:21 +0000 (02:28 +0000)
Use read_memory_nobpt.
(is_delayed, mips_in_lenient_prologue): New functions.
(init_extra_frame_info): If in the prologue, don't use saved registers.
* config/mips/tm-mips.h: Declare mips_skip_prologue.

gdb/ChangeLog
gdb/config/mips/tm-mips.h
gdb/mips-tdep.c

index 51faafb1a33a394116e907f103dee97ae9f155e6..e5cfd7002114538b5de43606e07b027241172734 100644 (file)
@@ -1,5 +1,11 @@
 Sun Jul 18 15:22:45 1993  Jim Kingdon  (kingdon@rtl.cygnus.com)
 
+       * mips-tdep.c (mips_skip_prologue): New argument lenient.
+       Use read_memory_nobpt.
+       (is_delayed, mips_in_lenient_prologue): New functions.
+       (init_extra_frame_info): If in the prologue, don't use saved registers.
+       * config/mips/tm-mips.h: Declare mips_skip_prologue.
+
        * partial-stab.h (N_SO): Add the text offset to valu before, not after,
        passing it to END_PSYMTAB.
 
index 0ee23c6c18a048d0f0664baec9a706cc165e12fb..9ab884dc6e4a64ba09476bce5eb7d813b7a63ac3 100644 (file)
@@ -42,7 +42,8 @@ extern int mips_fpu;
 /* Advance PC across any function entry prologue instructions
    to reach some "real" code.  */
 
-#define SKIP_PROLOGUE(pc)      pc = mips_skip_prologue(pc)
+#define SKIP_PROLOGUE(pc)      pc = mips_skip_prologue (pc, 0)
+extern CORE_ADDR mips_skip_prologue PARAMS ((CORE_ADDR addr, int lenient));
 
 /* Immediately after a function call, return the saved pc.
    Can't always go through the frames for this because on some machines
index 136c0c1406404298ba21598d7fa424f71b081ef8..e19850872b22cff6d22bbb7bf83190d18461fd94 100644 (file)
@@ -30,8 +30,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "symfile.h"
 #include "objfiles.h"
 
+#include "opcode/mips.h"
+
 #define VM_MIN_ADDRESS (unsigned)0x400000
 \f
+static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+
 /* Some MIPS boards don't support floating point, so we permit the
    user to turn it off.  */
 int mips_fpu = 1;
@@ -315,14 +319,14 @@ init_extra_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);
+  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));
-  bzero(fci->saved_regs, sizeof(struct frame_saved_regs));
+  memset (fci->saved_regs, 0, sizeof (struct frame_saved_regs));
   fci->proc_desc =
-      proc_desc == &temp_proc_desc ? 0 : proc_desc;
+    proc_desc == &temp_proc_desc ? 0 : proc_desc;
   if (proc_desc)
     {
       int ireg;
@@ -339,32 +343,41 @@ init_extra_frame_info(fci)
        fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc))
                      + PROC_FRAME_OFFSET(proc_desc);
 
-      if (proc_desc == &temp_proc_desc)
-         *fci->saved_regs = temp_saved_regs;
+      /* If this is the innermost frame, and we are still in the
+        prologue (loosely defined), then the registers may not have
+        been saved yet.  But they haven't been clobbered either, so
+        it's fine to say they have not been saved.  */
+      if (fci->next == NULL
+         && mips_in_lenient_prologue (PROC_LOW_ADDR (proc_desc), fci->pc))
+       /* We already zeroed the saved regs.  */
+       ;
+      else 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)
+           if (mask & 0x80000000)
              {
-                 fci->saved_regs->regs[ireg] = reg_position;
-                 reg_position -= 4;
+               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. */
+
+         /* 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)
+           if (mask & 0x80000000)
              {
-                 fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
-                 reg_position -= 4;
+               fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
+               reg_position -= 4;
              }
-      }
+       }
 
       /* hack: if argument regs are saved, guess these contain args */
       if ((PROC_REG_MASK(proc_desc) & 0xF0) == 0) fci->num_args = -1;
@@ -692,14 +705,32 @@ mips_frame_num_args(fip)
        return -1;
 }
 \f
-/* 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. */
+/* Does this instruction involve use of a delay slot?  */
+static int
+is_delayed (insn)
+     unsigned long insn;
+{
+  int i;
+  for (i = 0; i < NUMOPCODES; ++i)
+    if (mips_opcodes[i].pinfo != INSN_MACRO
+       && (insn & mips_opcodes[i].mask) == mips_opcodes[i].match)
+      break;
+  return i < NUMOPCODES && (mips_opcodes[i].pinfo & ANY_DELAY);
+}
+
+/* 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
+   LENIENT, then we must skip everything which is involved in setting
+   up the frame (it's OK to skip more, just so long as we don't skip
+   anything which might clobber the registers which are being saved.
+   We must skip more in the case where part of the prologue is in the
+   delay slot of a non-prologue instruction).  */
 
 CORE_ADDR
-mips_skip_prologue(pc)
+mips_skip_prologue (pc, lenient)
      CORE_ADDR pc;
+     int lenient;
 {
     struct symbol *f;
     struct block *b;
@@ -710,8 +741,19 @@ mips_skip_prologue(pc)
     /* Skip the typical prologue instructions. These are the stack adjustment
        instruction and the instructions that save registers on the stack
        or in the gcc frame.  */
-    for (offset = 0; offset < 100; offset += 4) {
-       inst = read_memory_integer(pc + offset, 4);
+    for (offset = 0; offset < 100; offset += 4)
+      {
+       char buf[4];
+       int status;
+
+       status = read_memory_nobpt (pc + offset, buf, 4);
+       if (status)
+         memory_error (status, pc + offset);
+       inst = extract_unsigned_integer (buf, 4);
+
+       if (lenient && is_delayed (inst))
+         continue;
+
        if ((inst & 0xffff0000) == 0x27bd0000)  /* addiu $sp,$sp,offset */
            seen_sp_adjust = 1;
        else if ((inst & 0xFFE00000) == 0xAFA00000 && (inst & 0x001F0000))
@@ -761,6 +803,18 @@ mips_skip_prologue(pc)
 #endif
 }
 
+/* Is address PC in the prologue (loosely defined) for function at
+   STARTADDR?  */
+
+static int
+mips_in_lenient_prologue (startaddr, pc)
+     CORE_ADDR startaddr;
+     CORE_ADDR pc;
+{
+  CORE_ADDR end_prologue = mips_skip_prologue (startaddr, 1);
+  return pc >= startaddr && pc < end_prologue;
+}
+
 /* Given a return value in `regbuf' with a type `valtype', 
    extract and copy its value into `valbuf'.  */
 void