target/arc: skip over breakpoints in arc_resume()

When requested by the core code (handle_breakpoints = true),
arc_resume() should be able to advance over a potential breakpoint set
at the resume address instead of getting stuck in one place. This is
achieved by removing the breakpoint, executing one instruction,
resetting the breakpoint, then proceeding forward as normal.

With this patch applied, openocd is now able to resume from a
breakpoint halt when debugging ARCv2 targets via telnet.

This has previously been committed to the Zephyr project's openocd repo
(see https://github.com/zephyrproject-rtos/openocd/pull/31).

Change-Id: I17dba0dcea311d394b303c587bc2dfaa99d67859
Signed-off-by: Evgeniy Didin <didin@synopsys.com>
Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
Signed-off-by: Artemiy Volkov <artemiy@synopsys.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/7817
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Tested-by: jenkins
This commit is contained in:
Evgeniy Didin 2020-07-31 00:13:12 +03:00 committed by Antonio Borneo
parent 2c10e3e257
commit 0de852f561
1 changed files with 58 additions and 1 deletions

View File

@ -52,6 +52,11 @@ static int arc_remove_watchpoint(struct target *target,
struct watchpoint *watchpoint);
static int arc_enable_watchpoints(struct target *target);
static int arc_enable_breakpoints(struct target *target);
static int arc_unset_breakpoint(struct target *target,
struct breakpoint *breakpoint);
static int arc_set_breakpoint(struct target *target,
struct breakpoint *breakpoint);
static int arc_single_step_core(struct target *target);
void arc_reg_data_type_add(struct target *target,
struct arc_reg_data_type *data_type)
@ -750,6 +755,29 @@ static int arc_examine(struct target *target)
return ERROR_OK;
}
static int arc_exit_debug(struct target *target)
{
uint32_t value;
struct arc_common *arc = target_to_arc(target);
/* Do read-modify-write sequence, or DEBUG.UB will be reset unintentionally. */
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, &value));
value |= SET_CORE_FORCE_HALT; /* set the HALT bit */
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value));
alive_sleep(1);
target->state = TARGET_HALTED;
CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED));
if (debug_level >= LOG_LVL_DEBUG) {
LOG_DEBUG("core stopped (halted) debug-reg: 0x%08" PRIx32, value);
CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value));
LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value);
}
return ERROR_OK;
}
static int arc_halt(struct target *target)
{
uint32_t value, irq_state;
@ -1251,7 +1279,7 @@ static int arc_resume(struct target *target, int current, target_addr_t address,
uint32_t value;
struct reg *pc = &arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache];
LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints(not supported yet):%i,"
LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints:%i,"
" debug_execution:%i", current, address, handle_breakpoints, debug_execution);
/* We need to reset ARC cache variables so caches
@ -1296,6 +1324,19 @@ static int arc_resume(struct target *target, int current, target_addr_t address,
CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value));
}
/* the front-end may request us not to handle breakpoints here */
if (handle_breakpoints) {
/* Single step past breakpoint at current address */
struct breakpoint *breakpoint = breakpoint_find(target, resume_pc);
if (breakpoint) {
LOG_DEBUG("skipping past breakpoint at 0x%08" TARGET_PRIxADDR,
breakpoint->address);
CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint));
CHECK_RETVAL(arc_single_step_core(target));
CHECK_RETVAL(arc_set_breakpoint(target, breakpoint));
}
}
/* Restore IRQ state if not in debug_execution*/
if (!debug_execution)
CHECK_RETVAL(arc_enable_interrupts(target, arc->irq_state));
@ -2027,6 +2068,22 @@ static int arc_config_step(struct target *target, int enable_step)
return ERROR_OK;
}
static int arc_single_step_core(struct target *target)
{
CHECK_RETVAL(arc_debug_entry(target));
/* disable interrupts while stepping */
CHECK_RETVAL(arc_enable_interrupts(target, 0));
/* configure single step mode */
CHECK_RETVAL(arc_config_step(target, 1));
/* exit debug mode */
CHECK_RETVAL(arc_exit_debug(target));
return ERROR_OK;
}
static int arc_step(struct target *target, int current, target_addr_t address,
int handle_breakpoints)
{