diff mbox

[24/24] MIPS R6 forbidden slot support

Message ID 1467038991-6600-24-git-send-email-bhushan.attarde@imgtec.com
State New
Headers show

Commit Message

Bhushan Attarde June 27, 2016, 2:49 p.m. UTC
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 mbox

Patch

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
     {