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
