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>
This commit is contained in:
Evgeniy Didin 2020-03-16 20:38:00 +03:00 committed by Oleksij Rempel
parent c693508f77
commit da41bce3ae
2 changed files with 162 additions and 2 deletions

View File

@ -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,

View File

@ -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];