Make sure we don't put a break point on a delay slot address.
If the server ask to break on a delay slot, just put the bp
at address - 4.

Signed-off-by: Franck Jullien <[email protected]>
---
 gdb/ChangeLog.or1k |    7 ++++
 gdb/or1k-tdep.c    |   96 +++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 87 insertions(+), 16 deletions(-)

diff --git a/gdb/ChangeLog.or1k b/gdb/ChangeLog.or1k
index f903b04..d3d5943 100644
--- a/gdb/ChangeLog.or1k
+++ b/gdb/ChangeLog.or1k
@@ -1,3 +1,10 @@
+2013-08-11  Franck Jullien  <[email protected]>
+
+       * or1k-tdep.c (or1k_instruction_has_delay_slot) : New function.
+       (or1k_single_step_through_delay) : Make use of the new
+       or1k_instruction_has_delay_slot function.
+       (set_gdbarch_adjust_breakpoint_address) : Add or1k handling function.
+
 2013-03-15  Stefan Kristiansson  <[email protected]>
 
        * or1k-tdep.c (or1k_regset_from_core_section) : Silence gcc warning
diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c
index f938077..50ac271 100644
--- a/gdb/or1k-tdep.c
+++ b/gdb/or1k-tdep.c
@@ -559,6 +559,83 @@ or1k_breakpoint_from_pc (struct gdbarch *gdbarch,
 
 }      /* or1k_breakpoint_from_pc() */
 
+/*----------------------------------------------------------------------------*/
+/*!Determine if the given instruction has delay slot
+
+   @param[in]  gdbarch  The GDB architecture being used
+   @param[in]  bp_addr  The instruction address in question
+
+   @return  1 (true) if this instruction has a delay slot, 0 (false)
+   otherwise. */
+/*---------------------------------------------------------------------------*/
+
+static int
+or1k_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  CGEN_FIELDS tmp_fields;
+  const CGEN_INSN *insns;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  insns = cgen_lookup_insn (tdep->gdb_cgen_cpu_desc,
+                           NULL,
+                           or1k_fetch_instruction (gdbarch, addr),
+                           NULL, 32, &tmp_fields, 0);
+
+  /* TODO: we should add a delay slot flag to the CGEN_INSN and remove
+   * this hard coded test. */
+  return ((CGEN_INSN_NUM (insns) == OR1K_INSN_L_J) ||
+         (CGEN_INSN_NUM (insns) == OR1K_INSN_L_JAL) ||
+         (CGEN_INSN_NUM (insns) == OR1K_INSN_L_JR) ||
+         (CGEN_INSN_NUM (insns) == OR1K_INSN_L_JALR) ||
+         (CGEN_INSN_NUM (insns) == OR1K_INSN_L_BNF) ||
+         (CGEN_INSN_NUM (insns) == OR1K_INSN_L_BF));
+}
+
+/*----------------------------------------------------------------------------*/
+/*!Move the breakpoint out of the delay slot
+
+   Move the breakpoint at BPADDR out of any branch delay slot by shifting
+   it backwards if necessary.
+
+   @param[in]  gdbarch  The GDB architecture being used
+   @param[in]  bp_addr  The breakpoint address in question
+
+   @return  The address of the new location */
+/*---------------------------------------------------------------------------*/
+
+static CORE_ADDR
+or1k_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
+{
+  CORE_ADDR prev_addr;
+  CORE_ADDR func_addr;
+
+  /* If a breakpoint is set on the instruction in a branch delay slot,
+     GDB gets confused.  When the breakpoint is hit, the PC isn't on
+     the instruction in the branch delay slot, the PC will point to
+     the branch instruction.  Since the PC doesn't match any known
+     breakpoints, GDB reports a trap exception.
+
+     When the user sets the breakpoint, don't allow him to set the
+     breakpoint on the instruction in the branch delay slot.  Instead
+     move the breakpoint to the branch instruction (which will have
+     the same result).  */
+
+  /* Make sure we don't scan back before the beginning of the current
+     function, since we may fetch constant data or insns that look like
+     a jump.  Of course we might do that anyway if the compiler has
+     moved constants inline. :-(  */
+  if (find_pc_partial_function (bpaddr, NULL, &func_addr, NULL)
+      && func_addr == bpaddr)
+    return bpaddr;
+
+  /* If the previous instruction has a branch delay slot, we have
+     to move the breakpoint to the branch instruction. */
+  prev_addr = bpaddr - 4;
+  if (or1k_instruction_has_delay_slot (gdbarch, prev_addr))
+    bpaddr = prev_addr;
+
+  return bpaddr;
+}
 
 
/*----------------------------------------------------------------------------*/
 /*!Determine if we are executing a delay slot
@@ -598,22 +675,7 @@ or1k_single_step_through_delay( struct gdbarch    *gdbarch,
       return  0;
     }
 
-  insns = cgen_lookup_insn (tdep->gdb_cgen_cpu_desc,
-                            NULL,
-                            or1k_fetch_instruction (gdbarch, ppc),
-                            NULL,
-                            32,
-                            &tmp_fields,
-                            0);
-
-  /* TODO: we should add a delay slot flag to the CGEN_INSN and remove
-   * this hard coded test. */
-  return ((CGEN_INSN_NUM(insns) == OR1K_INSN_L_J) ||
-          (CGEN_INSN_NUM(insns) == OR1K_INSN_L_JAL) ||
-          (CGEN_INSN_NUM(insns) == OR1K_INSN_L_JR) ||
-          (CGEN_INSN_NUM(insns) == OR1K_INSN_L_JALR) ||
-          (CGEN_INSN_NUM(insns) == OR1K_INSN_L_BNF) ||
-          (CGEN_INSN_NUM(insns) == OR1K_INSN_L_BF));
+  return or1k_instruction_has_delay_slot (gdbarch, ppc);
 
 }      /* or1k_single_step_through_delay() */
 
@@ -2046,6 +2108,8 @@ or1k_gdbarch_init (struct gdbarch_info  info,
   /* Information about the target architecture */
   set_gdbarch_return_value          (gdbarch, or1k_return_value);
   set_gdbarch_breakpoint_from_pc    (gdbarch, or1k_breakpoint_from_pc);
+  set_gdbarch_adjust_breakpoint_address
+                                    (gdbarch, or1k_adjust_breakpoint_address);
   set_gdbarch_have_nonsteppable_watchpoint
                                     (gdbarch, 1);
 
-- 
1.7.1

_______________________________________________
OpenRISC mailing list
[email protected]
http://lists.openrisc.net/listinfo/openrisc

Reply via email to