aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
authorEvgeniy Didin <didin@synopsys.com>2020-03-16 20:38:00 +0300
committerOleksij Rempel <linux@rempel-privat.de>2020-05-08 21:23:05 +0100
commitda41bce3aee99f1fd2c661f874c90d20b4fefa04 (patch)
treef23a9cc8d2b4bdcf739cf4d11bafc251a4c712b0 /src/target
parentc693508f7717d3e5cf118da38d4a5411c59cef1a (diff)
downloadriscv-openocd-da41bce3aee99f1fd2c661f874c90d20b4fefa04.zip
riscv-openocd-da41bce3aee99f1fd2c661f874c90d20b4fefa04.tar.gz
riscv-openocd-da41bce3aee99f1fd2c661f874c90d20b4fefa04.tar.bz2
target/arc: introduce breakpoint functionality
With this patch we introduce set/unset breakpoints routines and add/remove bp handlers. Currently soft breakpoints are only supported. Changes since v1: * Change if-statement in arc_remove_breakpoint * Squash changes from http://openocd.zylin.com/#/c/5641/ in this commit to fix build. Change-Id: Ib10ccdb02fd1606e4f407f012b1bee106a8ffccd Signed-off-by: Evgeniy Didin <didin@synopsys.com> Reviewed-on: http://openocd.zylin.com/5641 Tested-by: jenkins Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Diffstat (limited to 'src/target')
-rw-r--r--src/target/arc.c158
-rw-r--r--src/target/arc.h6
2 files changed, 162 insertions, 2 deletions
diff --git a/src/target/arc.c b/src/target/arc.c
index 5bc6134..bf74496 100644
--- a/src/target/arc.c
+++ b/src/target/arc.c
@@ -1342,6 +1342,158 @@ int arc_read_instruction_u32(struct target *target, uint32_t address,
return ERROR_OK;
}
+static int arc_set_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+
+ if (breakpoint->set) {
+ LOG_WARNING("breakpoint already set");
+ return ERROR_OK;
+ }
+
+ if (breakpoint->type == BKPT_SOFT) {
+ LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
+
+ if (breakpoint->length == 4) {
+ uint32_t verify = 0xffffffff;
+
+ CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length,
+ breakpoint->orig_instr));
+
+ CHECK_RETVAL(arc_write_instruction_u32(target, breakpoint->address,
+ ARC_SDBBP_32));
+
+ CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, &verify));
+
+ if (verify != ARC_SDBBP_32) {
+ LOG_ERROR("Unable to set 32bit breakpoint at address @0x%" TARGET_PRIxADDR
+ " - check that memory is read/writable", breakpoint->address);
+ return ERROR_FAIL;
+ }
+ } else if (breakpoint->length == 2) {
+ uint16_t verify = 0xffff;
+
+ CHECK_RETVAL(target_read_buffer(target, breakpoint->address, breakpoint->length,
+ breakpoint->orig_instr));
+ CHECK_RETVAL(target_write_u16(target, breakpoint->address, ARC_SDBBP_16));
+
+ CHECK_RETVAL(target_read_u16(target, breakpoint->address, &verify));
+ if (verify != ARC_SDBBP_16) {
+ LOG_ERROR("Unable to set 16bit breakpoint at address @0x%" TARGET_PRIxADDR
+ " - check that memory is read/writable", breakpoint->address);
+ return ERROR_FAIL;
+ }
+ } else {
+ LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ breakpoint->set = 64; /* Any nice value but 0 */
+ } else if (breakpoint->type == BKPT_HARD) {
+ LOG_DEBUG("Hardware breakpoints are not supported yet!");
+ return ERROR_FAIL;
+ } else {
+ LOG_DEBUG("ERROR: setting unknown breakpoint type");
+ return ERROR_FAIL;
+ }
+ /* core instruction cache is now invalid,
+ * TODO: add cache invalidation function here (when implemented). */
+
+ return ERROR_OK;
+}
+
+static int arc_unset_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ int retval = ERROR_OK;
+
+ if (!breakpoint->set) {
+ LOG_WARNING("breakpoint not set");
+ return ERROR_OK;
+ }
+
+ if (breakpoint->type == BKPT_SOFT) {
+ /* restore original instruction (kept in target endianness) */
+ LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
+ if (breakpoint->length == 4) {
+ uint32_t current_instr;
+
+ /* check that user program has not modified breakpoint instruction */
+ CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, &current_instr));
+
+ if (current_instr == ARC_SDBBP_32) {
+ retval = target_write_buffer(target, breakpoint->address,
+ breakpoint->length, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+ } else {
+ LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR
+ " has been overwritten outside of debugger."
+ "Expected: @0x%" PRIx32 ", got: @0x%" PRIx32,
+ breakpoint->address, ARC_SDBBP_32, current_instr);
+ }
+ } else if (breakpoint->length == 2) {
+ uint16_t current_instr;
+
+ /* check that user program has not modified breakpoint instruction */
+ CHECK_RETVAL(target_read_u16(target, breakpoint->address, &current_instr));
+ if (current_instr == ARC_SDBBP_16) {
+ retval = target_write_buffer(target, breakpoint->address,
+ breakpoint->length, breakpoint->orig_instr);
+ if (retval != ERROR_OK)
+ return retval;
+ } else {
+ LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR
+ " has been overwritten outside of debugger. "
+ "Expected: 0x%04" PRIx16 ", got: 0x%04" PRIx16,
+ breakpoint->address, ARC_SDBBP_16, current_instr);
+ }
+ } else {
+ LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+ breakpoint->set = 0;
+
+ } else if (breakpoint->type == BKPT_HARD) {
+ LOG_WARNING("Hardware breakpoints are not supported yet!");
+ return ERROR_FAIL;
+ } else {
+ LOG_DEBUG("ERROR: unsetting unknown breakpoint type");
+ return ERROR_FAIL;
+ }
+
+ /* core instruction cache is now invalid.
+ * TODO: Add cache invalidation function */
+
+ return retval;
+}
+
+
+static int arc_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ if (target->state == TARGET_HALTED) {
+ return arc_set_breakpoint(target, breakpoint);
+
+ } else {
+ LOG_WARNING(" > core was not halted, please try again.");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+}
+
+static int arc_remove_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ if (target->state == TARGET_HALTED) {
+ if (breakpoint->set)
+ CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint));
+ } else {
+ LOG_WARNING("target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ return ERROR_OK;
+}
+
/* Helper function which swiches core to single_step mode by
* doing aux r/w operations. */
int arc_config_step(struct target *target, int enable_step)
@@ -1443,6 +1595,8 @@ int arc_step(struct target *target, int current, target_addr_t address,
return ERROR_OK;
}
+
+
/* ARC v2 target */
struct target_type arcv2_target = {
.name = "arcv2",
@@ -1472,10 +1626,10 @@ struct target_type arcv2_target = {
.checksum_memory = NULL,
.blank_check_memory = NULL,
- .add_breakpoint = NULL,
+ .add_breakpoint = arc_add_breakpoint,
.add_context_breakpoint = NULL,
.add_hybrid_breakpoint = NULL,
- .remove_breakpoint = NULL,
+ .remove_breakpoint = arc_remove_breakpoint,
.add_watchpoint = NULL,
.remove_watchpoint = NULL,
.hit_watchpoint = NULL,
diff --git a/src/target/arc.h b/src/target/arc.h
index 55a1ead..defa3fa 100644
--- a/src/target/arc.h
+++ b/src/target/arc.h
@@ -54,6 +54,12 @@
/* Limit reg_type/reg_type_field name to 20 symbols */
#define REG_TYPE_MAX_NAME_LENGTH 20
+/* ARC 32bits opcodes */
+#define ARC_SDBBP_32 0x256F003F /* BRK */
+
+/* ARC 16bits opcodes */
+#define ARC_SDBBP_16 0x7FFF /* BRK_S */
+
struct arc_reg_bitfield {
struct reg_data_type_bitfield bitfield;
char name[REG_TYPE_MAX_NAME_LENGTH];