From ace6b7e49ac0b54961fd363343c702b1c5172062 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 7 Feb 2018 12:16:22 -0800 Subject: [PATCH] Handle resuming from a trigger... ... by disabling all triggers, single stepping, enabling them, and then resuming as usual. Without this change, you'd just be stuck on an address trigger and would have to manually disable it. Change-Id: I5834984671baa6b64f72e533c4aa94555c64617e --- src/rtos/riscv_debug.c | 2 +- src/target/riscv/riscv-013.c | 3 +- src/target/riscv/riscv.c | 63 +++++++++++++++++++++++++++--------- src/target/riscv/riscv.h | 6 +--- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index b1a714d48..90caf406f 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -248,7 +248,7 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet, if (strcmp(packet_stttrr, "vCont;c") == 0) { target_call_event_callbacks(target, TARGET_EVENT_GDB_START); target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); - riscv_resume_all_harts(target); + riscv_openocd_resume(target, 1, 0, 0, 0); target->state = TARGET_RUNNING; gdb_set_frontend_state_running(connection); target_call_event_callbacks(target, TARGET_EVENT_RESUMED); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 760adb381..3ad2e3fd1 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -2037,8 +2037,9 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_SWBP: - case CSR_DCSR_CAUSE_TRIGGER: return RISCV_HALT_BREAKPOINT; + case CSR_DCSR_CAUSE_TRIGGER: + return RISCV_HALT_TRIGGER; case CSR_DCSR_CAUSE_STEP: return RISCV_HALT_SINGLESTEP; case CSR_DCSR_CAUSE_DEBUGINT: diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index f8a273958..03fa46ba9 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -640,6 +640,7 @@ static int old_or_new_riscv_step( int handle_breakpoints ){ RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) return oldriscv_step(target, current, address, handle_breakpoints); else @@ -728,6 +729,7 @@ static int old_or_new_riscv_resume( int debug_execution ){ RISCV_INFO(r); + LOG_DEBUG("handle_breakpoints=%d", handle_breakpoints); if (r->is_halted == NULL) return oldriscv_resume(target, current, address, handle_breakpoints, debug_execution); else @@ -1027,6 +1029,9 @@ int riscv_openocd_poll(struct target *target) case RISCV_HALT_BREAKPOINT: target->debug_reason = DBG_REASON_BREAKPOINT; break; + case RISCV_HALT_TRIGGER: + target->debug_reason = DBG_REASON_WATCHPOINT; + break; case RISCV_HALT_INTERRUPT: target->debug_reason = DBG_REASON_DBGRQ; break; @@ -1077,13 +1082,53 @@ int riscv_openocd_resume( int current, target_addr_t address, int handle_breakpoints, - int debug_execution -) { - LOG_DEBUG("resuming all harts"); + int debug_execution) +{ + LOG_DEBUG("debug_reason=%d", target->debug_reason); if (!current) riscv_set_register(target, GDB_REGNO_PC, address); + if (target->debug_reason == DBG_REASON_WATCHPOINT) { + /* To be able to run off a trigger, disable all the triggers, step, and + * then resume as usual. */ + struct watchpoint *watchpoint = target->watchpoints; + bool trigger_temporarily_cleared[RISCV_MAX_HWBPS] = {0}; + + int i = 0; + int result = ERROR_OK; + while (watchpoint && result == ERROR_OK) { + LOG_DEBUG("watchpoint %d: set=%d", i, watchpoint->set); + trigger_temporarily_cleared[i] = watchpoint->set; + if (watchpoint->set) { + result = riscv_remove_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result == ERROR_OK) { + result = riscv_step_rtos_hart(target); + } + + watchpoint = target->watchpoints; + i = 0; + while (watchpoint) { + LOG_DEBUG("watchpoint %d: cleared=%d", i, trigger_temporarily_cleared[i]); + if (trigger_temporarily_cleared[i]) { + if (result == ERROR_OK) + result = riscv_add_watchpoint(target, watchpoint); + else + riscv_add_watchpoint(target, watchpoint); + } + watchpoint = watchpoint->next; + i++; + } + + if (result != ERROR_OK) + return result; + } + int out = riscv_resume_all_harts(target); if (out != ERROR_OK) { LOG_ERROR("unable to resume all harts"); @@ -1601,18 +1646,6 @@ enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) return r->halt_reason(target); } -int riscv_count_triggers(struct target *target) -{ - return riscv_count_triggers_of_hart(target, riscv_current_hartid(target)); -} - -int riscv_count_triggers_of_hart(struct target *target, int hartid) -{ - RISCV_INFO(r); - assert(hartid < riscv_count_harts(target)); - return r->trigger_count[hartid]; -} - size_t riscv_debug_buffer_size(struct target *target) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 5d3a21257..478731dd6 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -30,6 +30,7 @@ enum riscv_halt_reason { RISCV_HALT_INTERRUPT, RISCV_HALT_BREAKPOINT, RISCV_HALT_SINGLESTEP, + RISCV_HALT_TRIGGER, RISCV_HALT_UNKNOWN }; @@ -216,11 +217,6 @@ int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, bool riscv_is_halted(struct target *target); enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid); -/* Returns the number of triggers availiable to either the current hart or to - * the given hart. */ -int riscv_count_triggers(struct target *target); -int riscv_count_triggers_of_hart(struct target *target, int hartid); - /* These helper functions let the generic program interface get target-specific * information. */ size_t riscv_debug_buffer_size(struct target *target);