This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 24/24] MIPS R6 forbidden slot support


    This approach leads to single step skipping forbidden slots.
    It also means that breakpoints cannot be set on forbidden slots and
    are instead moved to the next instruction.

    gdb/ChangeLog:
        * mips-tdep.c (mips32_next_pc): Step through the forbidden slot.
        (mips32_instruction_is_compact_branch): Add R6 compact branch
        instructions.
        (mips32_insn_at_pc_has_forbidden_slot): New function.
        (mips_adjust_breakpoint_address): Update comment and adjust
        breakpoint address in case of conditional compact branch
        instructions.
---
 gdb/mips-tdep.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 88 insertions(+), 18 deletions(-)

diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index d5dd668..50f7bac 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -2637,7 +2637,7 @@ mips32_blez_pc (struct gdbarch *gdbarch, struct frame_info *frame,
   ULONGEST uval_rs = get_frame_register_unsigned (frame, rs);
   ULONGEST uval_rt = get_frame_register_unsigned (frame, rt);
   int taken = 0;
-  int delay_slot_size = 0;
+  int delay_slot_size = 4;
 
   /* BLEZ, BLEZL, BGTZ, BGTZL */
   if (rt == 0)
@@ -2656,6 +2656,12 @@ mips32_blez_pc (struct gdbarch *gdbarch, struct frame_info *frame,
       /* BGEUC, BLTUC */
       else if (rs != rt && rs != 0 && rt != 0)
 	taken = (uval_rs >= uval_rt);
+
+      /* Step through the forbidden slot to avoid repeated exceptions we do
+	 not currently have access to the BD bit when hitting a breakpoint
+	 and therefore cannot tell if the breakpoint hit on the branch or the
+	 forbidden slot.  */
+      /* delay_slot_size = 0; */
     }
 
   if (invert)
@@ -2835,7 +2841,11 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
 	      if (taken)
 		pc += mips32_relative_offset (inst) + 4;
 	      else
-		pc += 4;
+		/* Step through the forbidden slot to avoid repeated exceptions
+		   we do not currently have access to the BD bit when hitting a
+		   breakpoint and therefore cannot tell if the breakpoint
+		   hit on the branch or the forbidden slot.  */
+		pc += 8;
 	    }
 	  /* BC1EQZ, BC1NEZ */
 	  else if (op == 17 && (itype_rs (inst) == 9 || itype_rs (inst) == 13))
@@ -2883,7 +2893,11 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
 	      if (taken)
 		pc += mips32_relative_offset (inst) + 4;
 	      else
-		pc += 4;
+		/* Step through the forbidden slot to avoid repeated exceptions
+		   we do not currently have access to the BD bit when hitting a
+		   breakpoint and therefore cannot tell if the breakpoint
+		   hit on the branch or the forbidden slot.  */
+		pc += 8;
 	    }
 	  else if (op == 50 || op == 58)
 	  /* BC, BALC */
@@ -2906,7 +2920,11 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
 	      if (taken)
 		pc += mips32_relative_offset21 (inst) + 4;
 	      else
-		pc += 4;
+		/* Step through the forbidden slot to avoid repeated exceptions
+		   we do not currently have access to the BD bit when hitting a
+		   breakpoint and therefore cannot tell if the breakpoint
+		   hit on the branch or the forbidden slot.  */
+		pc += 8;
 	    }
 	  else
 	    pc += 4;		/* Not a branch, next instruction is easy.  */
@@ -2988,7 +3006,13 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
 		      {
 			if (!is_mipsr6_isa (gdbarch))
 			  break;
-			delay_slot_size = 0;
+
+			/* Step through the forbidden slot to avoid repeated
+			   exceptions we do not currently have access to the BD
+			   bit when hitting a breakpoint and therefore cannot
+			   tell if the breakpoint hit on the branch or the
+			   forbidden slot.  */
+			/* delay_slot_size = 0; */
 		      }
 
 		    if ((get_frame_register_unsigned (frame,
@@ -3675,26 +3699,36 @@ micromips_instruction_is_compact_branch (unsigned short insn)
 }
 
 /* Return non-zero if the MIPS instruction INSN is a compact branch
-   or jump.  */
+   or jump.  A value of 1 indicates an unconditional compact branch
+   and a value of 2 indicates a conditional compact branch.  */
 
 static int
 mips32_instruction_is_compact_branch (struct gdbarch *gdbarch, ULONGEST insn)
 {
   switch (itype_op (insn))
     {
-    /* BOVC, BEQZALC, BEQC */
-    case 8:
-    /* BNVC, BNEZALC, BNEC */
-    case 24:
     /* BC */
     case 50:
     /* BALC */
     case 58:
+      if (is_mipsr6_isa (gdbarch))
+	return 1;
+      break;
+    /* BOVC, BEQZALC, BEQC */
+    case 8:
+    /* BNVC, BNEZALC, BNEC */
+    case 24:
+      if (is_mipsr6_isa (gdbarch))
+	return 2;
+      break;
     /* BEQZC, JIC */
     case 54:
     /* BNEZC, JIALC */
     case 62:
-      return is_mipsr6_isa (gdbarch);
+      if (is_mipsr6_isa (gdbarch))
+	/* JIC, JIALC are unconditional */
+	return (itype_rs (insn) == 0) ? 1 : 2;
+      break;
     /* BLEZC, BGEZC, BGEC */
     case 22:
     /* BGTZC, BLTZC, BLTC */
@@ -3703,15 +3737,33 @@ mips32_instruction_is_compact_branch (struct gdbarch *gdbarch, ULONGEST insn)
     case 6:
     /* BGTZALC, BLTZALC, BLTUC */
     case 7:
-      return (is_mipsr6_isa (gdbarch)
-	      && itype_rt (insn) != 0);
+      if (is_mipsr6_isa (gdbarch)
+	  && itype_rt (insn) != 0)
+	return 2;
+      break;
     /* BPOSGE32C */
     case 1:
-      return (is_mipsr6_isa (gdbarch)
-	      && itype_rt (insn) == 0x18 && itype_rs (insn) == 0);
-    default:
-      return 0;
+      if (is_mipsr6_isa (gdbarch)
+	  && itype_rt (insn) == 0x18 && itype_rs (insn) == 0)
+	return 2;
     }
+  return 0;
+}
+
+/* Return non-zero if a standard MIPS instruction at ADDR has a branch
+   forbidden slot (i.e. it is a conditional compact branch instruction).  */
+
+static int
+mips32_insn_at_pc_has_forbidden_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  ULONGEST insn;
+  int status;
+
+  insn = mips_fetch_instruction (gdbarch, ISA_MIPS, addr, &status);
+  if (status)
+    return 0;
+
+  return mips32_instruction_is_compact_branch (gdbarch, insn) == 2;
 }
 
 struct mips_frame_cache
@@ -9064,7 +9116,18 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 
      So, we'll use the second solution.  To do this we need to know if
      the instruction we're trying to set the breakpoint on is in the
-     branch delay slot.  */
+     branch delay slot.
+
+     A similar problem occurs for breakpoints on forbidden slots where
+     the trap will be reported for the branch with the BD bit set.
+     In this case it would be ideal to recover using solution 1 from
+     above as there is no problem with the branch being skipped
+     (since the forbidden slot only exists on not-taken branches).
+     However, the BD bit is not available in all scenarios currently
+     so instead we move the breakpoint on to the next instruction.
+     This means that it is not possible to stop on an instruction
+     that can be in a forbidden slot even if that instruction is
+     jumped to directly.  */
 
   boundary = mips_segment_boundary (bpaddr);
 
@@ -9086,6 +9149,13 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
       prev_addr = bpaddr - 4;
       if (mips32_insn_at_pc_has_delay_slot (gdbarch, prev_addr))
 	bpaddr = prev_addr;
+      /* If the previous instruction has a forbidden slot, we have to
+	 move the breakpoint to the following instruction to prevent
+	 breakpoints in forbidden slots being reported as unknown
+	 traps.  */
+      else if (mips32_insn_at_pc_has_forbidden_slot (gdbarch, prev_addr))
+
+	bpaddr += 4;
     }
   else
     {
-- 
1.9-rc2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]