* target.h: Add enum target_waitkind, enum target_signal, and
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index f9193ea288c21d4239cac54d45f4b2dac3fc2dd2..454ab73364d6dee10d96253e4cb0a53846522a38 100644 (file)
@@ -34,7 +34,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #define VM_MIN_ADDRESS (unsigned)0x400000
 \f
+#if 0
 static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
+#endif
 
 /* Some MIPS boards don't support floating point, so we permit the
    user to turn it off.  */
@@ -76,17 +78,19 @@ read_next_frame_reg(fi, 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.
      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
 #define SIGFRAME_BASE          0x12c   /* sizeof(sigcontext) */
 #define SIGFRAME_PC_OFF                (-SIGFRAME_BASE + 2 * 4)
 #define SIGFRAME_REGSAVE_OFF   (-SIGFRAME_BASE + 3 * 4)
+#define SIGFRAME_REG_SIZE      4
 #endif
   for (; fi; fi = fi->next)
       if (in_sigtramp(fi->pc, 0)) {
          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;
          return read_memory_integer(fi->frame + offset, 4);
       }
@@ -183,7 +187,7 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame)
     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;
@@ -210,19 +214,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;
-           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 */
-           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);
-               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
-                   /* of an alloca or somethings similar.
+                    * of an alloca or somethings similar.
                     * Fix sp to "pre-alloca" value, and try again.
                     */
                    sp += alloca_adjust;
@@ -233,7 +237,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;
-           temp_saved_regs.regs[reg] = reg30 + (short)word;
+           temp_saved_regs.regs[reg] = reg30 + (word & 0xffff);
        }
     }
     if (has_frame_reg) {
@@ -346,7 +350,10 @@ mips_frame_chain(frame)
        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)
+       && 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))
@@ -371,7 +378,6 @@ init_extra_frame_info(fci)
     {
       int ireg;
       CORE_ADDR reg_position;
-      unsigned long mask;
       /* r0 bit means kernel trap */
       int kernel_trap = PROC_REG_MASK(proc_desc) & 1;
 
@@ -383,56 +389,98 @@ init_extra_frame_info(fci)
        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);
-       }
-
       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)
+         /* What registers have been saved?  Bitmasks.  */
+         unsigned long gen_mask, float_mask;
+
+         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)
+                   {
+                     /* 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)
+                   {
+                     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 -= 4;
              }
-         /* find which floating-point registers were saved */
-         reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc);
+         /* 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;
-         mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc);
-         for (ireg = 31; mask; --ireg, mask <<= 1)
-           if (mask & 0x80000000)
+         for (ireg = 31; float_mask; --ireg, float_mask <<= 1)
+           if (float_mask & 0x80000000)
              {
                fci->saved_regs->regs[FP0_REGNUM+ireg] = reg_position;
                reg_position -= 4;
@@ -521,7 +569,7 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr)
 }
 
 /* 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()
@@ -634,7 +682,7 @@ mips_pop_frame()
   /* 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;
 
@@ -668,7 +716,6 @@ mips_print_register (regnum, all)
      int regnum, all;
 {
   unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
-  REGISTER_TYPE val;
 
   /* Get the data in raw format.  */
   if (read_relative_register_raw_bytes (regnum, raw_buffer))
@@ -689,10 +736,10 @@ mips_print_register (regnum, all)
 #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 ("); ");
   }
-  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
@@ -707,7 +754,7 @@ mips_print_register (regnum, all)
   if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT
       && ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) {
     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
@@ -724,7 +771,7 @@ mips_print_register (regnum, all)
           registers line up.  */
        printf_filtered (local_hex_format(), val);
       else
-       printf_filtered ("%s=%d", local_hex_string(val), val);
+       printf_filtered ("%s=%ld", local_hex_string(val), val);
     }
 }
 
@@ -770,6 +817,7 @@ mips_frame_num_args(fip)
        return -1;
 }
 \f
+#if 0
 /* Is this a branch with a delay slot?  */
 static int
 is_delayed (insn)
@@ -785,6 +833,7 @@ is_delayed (insn)
                                       | INSN_COND_BRANCH_DELAY
                                       | INSN_COND_BRANCH_LIKELY)));
 }
+#endif
 
 /* To skip prologues, I use this predicate.  Returns either PC itself
    if the code at PC does not look like a function prologue; otherwise
@@ -800,8 +849,6 @@ mips_skip_prologue (pc, lenient)
      CORE_ADDR pc;
      int lenient;
 {
-    struct symbol *f;
-    struct block *b;
     unsigned long inst;
     int offset;
     int seen_sp_adjust = 0;
@@ -819,8 +866,10 @@ mips_skip_prologue (pc, lenient)
          memory_error (status, pc + offset);
        inst = extract_unsigned_integer (buf, 4);
 
+#if 0
        if (lenient && is_delayed (inst))
          continue;
+#endif
 
        if ((inst & 0xffff0000) == 0x27bd0000)  /* addiu $sp,$sp,offset */
            seen_sp_adjust = 1;
@@ -836,6 +885,13 @@ mips_skip_prologue (pc, lenient)
            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;
        else
            break;
     }
@@ -871,6 +927,11 @@ mips_skip_prologue (pc, lenient)
 #endif
 }
 
+#if 0
+/* 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?  */
 
@@ -882,6 +943,7 @@ mips_in_lenient_prologue (startaddr, pc)
   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'.  */
@@ -921,6 +983,22 @@ mips_store_return_value (valtype, valbuf)
   write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
 }
 
+/* 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);
+}
+
 static void reinit_frame_cache_sfunc PARAMS ((char *, int,
                                              struct cmd_list_element *));
 
This page took 0.028263 seconds and 4 git commands to generate.