#include "arm.h"
#include "arm_dpm.h"
+#include "armv8_dpm.h"
#include <jtag/jtag.h>
#include "register.h"
#include "breakpoints.h"
/* Toggles between recorded core mode (USR, SVC, etc) and a temporary one.
* Routines *must* restore the original mode before returning!!
*/
-int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
+int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
{
int retval;
uint32_t cpsr;
return retval;
}
+/* Read 64bit VFP registers */
+static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+{
+ int retval = ERROR_FAIL;
+ uint32_t value_r0, value_r1;
+
+ switch (regnum) {
+ case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+ /* move from double word register to r0:r1: "vmov r0, r1, vm"
+ * then read r0 via dcc
+ */
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV4_5_VMOV(1, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
+ ((regnum - ARM_VFP_V3_D0) & 0xf)), &value_r0);
+ if (retval != ERROR_OK)
+ break;
+
+ /* read r1 via dcc */
+ retval = dpm->instr_read_data_dcc(dpm,
+ ARMV4_5_MCR(14, 0, 1, 0, 5, 0),
+ &value_r1);
+ break;
+ default:
+
+ break;
+ }
-static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+ if (retval == ERROR_OK) {
+ buf_set_u32(r->value, 0, 32, value_r0);
+ buf_set_u32(r->value + 4, 0, 32, value_r1);
+ r->valid = true;
+ r->dirty = false;
+ LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name,
+ (unsigned) value_r0, (unsigned) value_r1);
+ }
+
+ return retval;
+}
+
+/* just read the register -- rely on the core mode being right */
+int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
uint32_t value;
- int retval = ERROR_FAIL;
+ int retval;
switch (regnum) {
case 0 ... 14:
/* core-specific ... ? */
LOG_WARNING("Jazelle PC adjustment unknown");
break;
- case ARM_STATE_AARCH64:
- LOG_ERROR("AARCH64: 32bit read requested");
+ default:
+ LOG_WARNING("unknown core state");
break;
}
break;
+ case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+ return dpm_read_reg_u64(dpm, r, regnum);
+ case ARM_VFP_V3_FPSCR:
+ /* "VMRS r0, FPSCR"; then return via DCC */
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV4_5_VMRS(0), &value);
+ break;
default:
/* 16: "MRS r0, CPSR"; then return via DCC
* 17: "MRS r0, SPSR"; then return via DCC
return retval;
}
-static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* Write 64bit VFP registers */
+static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
- uint64_t value;
- uint32_t i;
int retval = ERROR_FAIL;
+ uint32_t value_r0 = buf_get_u32(r->value, 0, 32);
+ uint32_t value_r1 = buf_get_u32(r->value + 4, 0, 32);
switch (regnum) {
- case 0 ... 30:
- i = 0xd5130400 + regnum; /* msr dbgdtr_el0,reg */
- retval = dpm->instr_read_data_dcc_64(dpm, i, &value);
- break;
- case 31: /* SP */
- i = 0x910003e0;
- retval = dpm->instr_read_data_r0_64(dpm, i, &value);
- break;
- case 32: /* PC */
- i = 0xd53b4520;
- retval = dpm->instr_read_data_r0_64(dpm, i, &value);
- break;
- case 33: /* CPSR */
- i = 0xd53b4500;
- retval = dpm->instr_read_data_r0_64(dpm, i, &value);
- break;
+ case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+ /* write value_r1 to r1 via dcc */
+ retval = dpm->instr_write_data_dcc(dpm,
+ ARMV4_5_MRC(14, 0, 1, 0, 5, 0),
+ value_r1);
+ if (retval != ERROR_OK)
+ break;
+ /* write value_r0 to r0 via dcc then,
+ * move to double word register from r0:r1: "vmov vm, r0, r1"
+ */
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_VMOV(0, 1, 0, ((regnum - ARM_VFP_V3_D0) >> 4),
+ ((regnum - ARM_VFP_V3_D0) & 0xf)), value_r0);
+ break;
default:
+
break;
}
if (retval == ERROR_OK) {
- buf_set_u64(r->value, 0, 64, value);
- r->valid = true;
r->dirty = false;
- LOG_DEBUG("READ: %s, %16.16llx", r->name, (long long)value);
+ LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name,
+ (unsigned) value_r0, (unsigned) value_r1);
}
return retval;
}
-
-/* just read the register -- rely on the core mode being right */
-static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
- if (r->size == 64)
- return dpm_read_reg64(dpm, r, regnum);
- else
- return dpm_read_reg32(dpm, r, regnum);
-}
-
-static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just write the register -- rely on the core mode being right */
+static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
- int retval = ERROR_FAIL;
+ int retval;
uint32_t value = buf_get_u32(r->value, 0, 32);
switch (regnum) {
* read r0 from DCC; then "MOV pc, r0" */
retval = dpm->instr_write_data_r0(dpm, 0xe1a0f000, value);
break;
+ case ARM_VFP_V3_D0 ... ARM_VFP_V3_D31:
+ return dpm_write_reg_u64(dpm, r, regnum);
+ case ARM_VFP_V3_FPSCR:
+ /* move to r0 from DCC, then "VMSR FPSCR, r0" */
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_VMSR(0), value);
+ break;
default:
/* 16: read r0 from DCC, then "MSR r0, CPSR_cxsf"
* 17: read r0 from DCC, then "MSR r0, SPSR_cxsf"
return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
}
-static int dpm_write_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
- int retval = ERROR_FAIL;
- uint32_t i;
- uint64_t value = buf_get_u64(r->value, 0, 64);
-
- switch (regnum) {
- case 0 ... 30:
- i = 0xd5330400 + regnum;
- retval = dpm->instr_write_data_dcc_64(dpm, i, value);
- break;
- case 32: /* PC */
- i = 0xd51b4520;
- retval = dpm->instr_write_data_r0_64(dpm, i, value);
- break;
- default:
- LOG_DEBUG("register %s (%16.16llx) not defined", r->name,
- (unsigned long long)value);
- break;
- }
-
- if (retval == ERROR_OK) {
- r->dirty = false;
- LOG_DEBUG("WRITE: %s, %16.16llx", r->name, (unsigned long long)value);
- }
-
- return retval;
-}
-
-/* just write the register -- rely on the core mode being right */
-static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
- if (r->size == 64)
- return dpm_write_reg64(dpm, r, regnum);
- else
- return dpm_write_reg32(dpm, r, regnum);
-}
-
-static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm)
+/**
+ * Read basic registers of the current context: R0 to R15, and CPSR;
+ * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
+ * In normal operation this is called on entry to halting debug state,
+ * possibly after some other operations supporting restore of debug state
+ * or making sure the CPU is fully idle (drain write buffer, etc).
+ */
+int arm_dpm_read_current_registers(struct arm_dpm *dpm)
{
struct arm *arm = dpm->arm;
- uint32_t cpsr, instr, core_regs;
+ uint32_t cpsr;
int retval;
struct reg *r;
- enum arm_state core_state = arm->core_state;
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
return retval;
- /* read R0 first (it's used for scratch), then CPSR */
- r = arm->core_cache->reg_list + 0;
- if (!r->valid) {
- retval = dpm_read_reg(dpm, r, 0);
- if (retval != ERROR_OK)
- goto fail;
+ /* read R0 and R1 first (it's used for scratch), then CPSR */
+ for (unsigned i = 0; i < 2; i++) {
+ r = arm->core_cache->reg_list + i;
+ if (!r->valid) {
+ retval = arm_dpm_read_reg(dpm, r, i);
+ if (retval != ERROR_OK)
+ goto fail;
+ }
+ r->dirty = true;
}
- r->dirty = true;
- if (core_state == ARM_STATE_AARCH64)
- instr = 0xd53b4500; /* mrs x0, dspsr_el0 */
- else
- instr = ARMV4_5_MRS(0, 0);
- retval = dpm->instr_read_data_r0(dpm, instr, &cpsr);
+ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
if (retval != ERROR_OK)
goto fail;
/* update core mode and state, plus shadow mapping for R8..R14 */
arm_set_cpsr(arm, cpsr);
- if (core_state == ARM_STATE_AARCH64)
- /* arm_set_cpsr changes core_state, restore it for now */
- arm->core_state = ARM_STATE_AARCH64;
-
- core_regs = arm->core_cache->num_regs;
/* REVISIT we can probably avoid reading R1..R14, saving time... */
- for (unsigned i = 1; i < core_regs; i++) {
- r = dpm->arm_reg_current(arm, i);
+ for (unsigned i = 2; i < 16; i++) {
+ r = arm_reg_current(arm, i);
if (r->valid)
continue;
- retval = dpm_read_reg(dpm, r, i);
+ retval = arm_dpm_read_reg(dpm, r, i);
if (retval != ERROR_OK)
goto fail;
}
return retval;
}
-/**
- * Read basic registers of the the current context: R0 to R15, and CPSR;
- * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
- * In normal operation this is called on entry to halting debug state,
- * possibly after some other operations supporting restore of debug state
- * or making sure the CPU is fully idle (drain write buffer, etc).
- */
-int arm_dpm_read_current_registers(struct arm_dpm *dpm)
-{
- return arm_dpm_read_current_registers_i(dpm);
-}
-
-int arm_dpm_read_current_registers_64(struct arm_dpm *dpm)
-{
- return arm_dpm_read_current_registers_i(dpm);
-}
-
/* Avoid needless I/O ... leave breakpoints and watchpoints alone
* unless they're removed, or need updating because of single-stepping
* or running debugger code.
static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp);
-
-static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
+/**
+ * Writes all modified core registers for all processor modes. In normal
+ * operation this is called on exit from halting debug state.
+ *
+ * @param dpm: represents the processor
+ * @param bpwp: true ensures breakpoints and watchpoints are set,
+ * false ensures they are cleared
+ */
+int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
{
struct arm *arm = dpm->arm;
struct reg_cache *cache = arm->core_cache;
int retval;
bool did_write;
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ goto done;
+
+ /* If we're managing hardware breakpoints for this core, enable
+ * or disable them as requested.
+ *
+ * REVISIT We don't yet manage them for ANY cores. Eventually
+ * we should be able to assume we handle them; but until then,
+ * cope with the hand-crafted breakpoint code.
+ */
+ if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
+ for (unsigned i = 0; i < dpm->nbp; i++) {
+ struct dpm_bp *dbp = dpm->dbp + i;
+ struct breakpoint *bp = dbp->bp;
+
+ retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
+ bp ? &bp->set : NULL);
+ if (retval != ERROR_OK)
+ goto done;
+ }
+ }
+
+ /* enable/disable watchpoints */
+ for (unsigned i = 0; i < dpm->nwp; i++) {
+ struct dpm_wp *dwp = dpm->dwp + i;
+ struct watchpoint *wp = dwp->wp;
+
+ retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
+ wp ? &wp->set : NULL);
+ if (retval != ERROR_OK)
+ goto done;
+ }
+
+ /* NOTE: writes to breakpoint and watchpoint registers might
+ * be queued, and need (efficient/batched) flushing later.
+ */
+
/* Scan the registers until we find one that's both dirty and
* eligible for flushing. Flush that and everything else that
* shares the same core mode setting. Typically this won't
did_write = false;
- /* check everything except our scratch register R0 */
- for (unsigned i = 1; i < cache->num_regs; i++) {
+ /* check everything except our scratch registers R0 and R1 */
+ for (unsigned i = 2; i < cache->num_regs; i++) {
struct arm_reg *r;
unsigned regnum;
continue;
if (arm->cpsr == cache->reg_list + i)
continue;
- if (!cache->reg_list[i].dirty)
+ if (!cache->reg_list[i].exist || !cache->reg_list[i].dirty)
continue;
r = cache->reg_list[i].arch_info;
/* REVISIT error checks */
if (tmode != ARM_MODE_ANY) {
- retval = dpm_modeswitch(dpm, tmode);
+ retval = arm_dpm_modeswitch(dpm, tmode);
if (retval != ERROR_OK)
goto done;
}
* or it's dirty. Must write PC to ensure the return address is
* defined, and must not write it before CPSR.
*/
- retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
+ retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
if (retval != ERROR_OK)
goto done;
arm->cpsr->dirty = false;
goto done;
arm->pc->dirty = false;
- /* flush R0 -- it's *very* dirty by now */
- retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
- if (retval != ERROR_OK)
- goto done;
- cache->reg_list[0].dirty = false;
-
-done:
- return retval;
-}
-
-static int arm_dpm_write_dirty_registers_64(struct arm_dpm *dpm)
-{
- struct arm *arm = dpm->arm;
- struct reg_cache *cache = arm->core_cache;
- int retval;
-
- /* Scan the registers until we find one that's both dirty and
- * eligible for flushing. Flush that and everything else that
- * shares the same core mode setting. Typically this won't
- * actually find anything to do...
- */
-
- /* check everything except our scratch register R0 */
- for (unsigned i = 1; i <= 32; i++) {
- struct arm_reg *r;
- unsigned regnum;
-
- if (!cache->reg_list[i].dirty)
- continue;
-
- r = cache->reg_list[i].arch_info;
- regnum = r->num;
- retval = dpm_write_reg(dpm,
- &cache->reg_list[i],
- regnum);
- if (retval != ERROR_OK)
- goto done;
- }
-
- /* flush R0 -- it's *very* dirty by now */
- retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
- if (retval != ERROR_OK)
- goto done;
- cache->reg_list[0].dirty = false;
-
-done:
- return retval;
-}
-
-/**
- * Writes all modified core registers for all processor modes. In normal
- * operation this is called on exit from halting debug state.
- *
- * @param dpm: represents the processor
- * @param bpwp: true ensures breakpoints and watchpoints are set,
- * false ensures they are cleared
- */
-int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
-{
- struct arm *arm = dpm->arm;
- struct reg_cache *cache = arm->core_cache;
- int retval;
-
- retval = dpm->prepare(dpm);
- if (retval != ERROR_OK)
- goto done;
-
- /* If we're managing hardware breakpoints for this core, enable
- * or disable them as requested.
- *
- * REVISIT We don't yet manage them for ANY cores. Eventually
- * we should be able to assume we handle them; but until then,
- * cope with the hand-crafted breakpoint code.
- */
- if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
- for (unsigned i = 0; i < dpm->nbp; i++) {
- struct dpm_bp *dbp = dpm->dbp + i;
- struct breakpoint *bp = dbp->bp;
-
- retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
- bp ? &bp->set : NULL);
- if (retval != ERROR_OK)
- goto done;
- }
- }
-
- /* enable/disable watchpoints */
- for (unsigned i = 0; i < dpm->nwp; i++) {
- struct dpm_wp *dwp = dpm->dwp + i;
- struct watchpoint *wp = dwp->wp;
-
- retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
- wp ? &wp->set : NULL);
+ /* flush R0 and R1 (our scratch registers) */
+ for (unsigned i = 0; i < 2; i++) {
+ retval = dpm_write_reg(dpm, &cache->reg_list[i], i);
if (retval != ERROR_OK)
goto done;
+ cache->reg_list[i].dirty = false;
}
- /* NOTE: writes to breakpoint and watchpoint registers might
- * be queued, and need (efficient/batched) flushing later.
- */
-
- if (cache->reg_list[0].size == 64)
- retval = arm_dpm_write_dirty_registers_64(dpm);
- else
- retval = arm_dpm_write_dirty_registers_32(dpm);
-
/* (void) */ dpm->finish(dpm);
done:
return retval;
/* r13/sp, and r14/lr are always shadowed */
case 13:
case 14:
+ case ARM_VFP_V3_D0 ... ARM_VFP_V3_FPSCR:
return mode;
default:
LOG_WARNING("invalid register #%u", num);
struct arm_dpm *dpm = target_to_arm(target)->dpm;
int retval;
- if (regnum < 0 || regnum > 16)
+ if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
+ (regnum > ARM_VFP_V3_FPSCR))
return ERROR_COMMAND_SYNTAX_ERROR;
if (regnum == 16) {
return retval;
if (mode != ARM_MODE_ANY) {
- retval = dpm_modeswitch(dpm, mode);
+ retval = arm_dpm_modeswitch(dpm, mode);
if (retval != ERROR_OK)
goto fail;
}
- retval = dpm_read_reg(dpm, r, regnum);
+ retval = arm_dpm_read_reg(dpm, r, regnum);
if (retval != ERROR_OK)
goto fail;
/* always clean up, regardless of error */
if (mode != ARM_MODE_ANY)
- /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY);
+ /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
fail:
/* (void) */ dpm->finish(dpm);
int retval;
- if (regnum < 0 || regnum > 16)
+ if (regnum < 0 || (regnum > 16 && regnum < ARM_VFP_V3_D0) ||
+ (regnum > ARM_VFP_V3_FPSCR))
return ERROR_COMMAND_SYNTAX_ERROR;
if (regnum == 16) {
return retval;
if (mode != ARM_MODE_ANY) {
- retval = dpm_modeswitch(dpm, mode);
+ retval = arm_dpm_modeswitch(dpm, mode);
if (retval != ERROR_OK)
goto fail;
}
/* always clean up, regardless of error */
if (mode != ARM_MODE_ANY)
- /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY);
+ /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
fail:
/* (void) */ dpm->finish(dpm);
for (unsigned i = 0; i < cache->num_regs; i++) {
struct arm_reg *r;
- if (cache->reg_list[i].valid)
+ if (!cache->reg_list[i].exist || cache->reg_list[i].valid)
continue;
r = cache->reg_list[i].arch_info;
* in FIQ mode we need to patch mode.
*/
if (mode != ARM_MODE_ANY)
- retval = dpm_modeswitch(dpm, mode);
+ retval = arm_dpm_modeswitch(dpm, mode);
else
- retval = dpm_modeswitch(dpm, ARM_MODE_USR);
+ retval = arm_dpm_modeswitch(dpm, ARM_MODE_USR);
if (retval != ERROR_OK)
goto done;
continue;
/* CPSR was read, so "R16" must mean SPSR */
- retval = dpm_read_reg(dpm,
+ retval = arm_dpm_read_reg(dpm,
&cache->reg_list[i],
(r->num == 16) ? 17 : r->num);
if (retval != ERROR_OK)
} while (did_read);
- retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
+ retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
/* (void) */ dpm->finish(dpm);
done:
return retval;
/* ?? */
break;
}
- dpm->wp_pc = addr;
+ dpm->wp_addr = addr;
}
/*----------------------------------------------------------------------*/
/* Examine debug reason */
switch (DSCR_ENTRY(dscr)) {
- case 6: /* Data abort (v6 only) */
- case 7: /* Prefetch abort (v6 only) */
- /* FALL THROUGH -- assume a v6 core in abort mode */
- case 0: /* HALT request from debugger */
- case 4: /* EDBGRQ */
+ case DSCR_ENTRY_HALT_REQ: /* HALT request from debugger */
+ case DSCR_ENTRY_EXT_DBG_REQ: /* EDBGRQ */
target->debug_reason = DBG_REASON_DBGRQ;
break;
- case 1: /* HW breakpoint */
- case 3: /* SW BKPT */
- case 5: /* vector catch */
+ case DSCR_ENTRY_BREAKPOINT: /* HW breakpoint */
+ case DSCR_ENTRY_BKPT_INSTR: /* vector catch */
target->debug_reason = DBG_REASON_BREAKPOINT;
break;
- case 2: /* asynch watchpoint */
- case 10:/* precise watchpoint */
+ case DSCR_ENTRY_IMPRECISE_WATCHPT: /* asynch watchpoint */
+ case DSCR_ENTRY_PRECISE_WATCHPT:/* precise watchpoint */
target->debug_reason = DBG_REASON_WATCHPOINT;
break;
default:
/* register access setup */
arm->full_context = arm_dpm_full_context;
- arm->read_core_reg = arm->read_core_reg ? : arm_dpm_read_core_reg;
- arm->write_core_reg = arm->write_core_reg ? : arm_dpm_write_core_reg;
-
- if (arm->core_cache != NULL) {
- if (arm->core_state == ARM_STATE_AARCH64) {
- cache = armv8_build_reg_cache(target);
- target->reg_cache = cache;
- } else {
- cache = arm_build_reg_cache(target, arm);
- *register_get_last_cache_p(&target->reg_cache) = cache;
- }
+ arm->read_core_reg = arm_dpm_read_core_reg;
+ arm->write_core_reg = arm_dpm_write_core_reg;
+ if (arm->core_cache == NULL) {
+ cache = arm_build_reg_cache(target, arm);
if (!cache)
return ERROR_FAIL;
+
+ *register_get_last_cache_p(&target->reg_cache) = cache;
}
/* coprocessor access setup */
target->type->remove_breakpoint = dpm_remove_breakpoint;
}
- /* watchpoint setup */
- target->type->add_watchpoint = dpm_add_watchpoint;
- target->type->remove_watchpoint = dpm_remove_watchpoint;
-
-
- if (dpm->arm_reg_current == 0)
- dpm->arm_reg_current = arm_reg_current;
+ /* watchpoint setup -- optional until it works everywhere */
+ if (!target->type->add_watchpoint) {
+ target->type->add_watchpoint = dpm_add_watchpoint;
+ target->type->remove_watchpoint = dpm_remove_watchpoint;
+ }
/* FIXME add vector catch support */
- if (arm->core_state == ARM_STATE_AARCH64) {
- dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
- dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
- } else {
- dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf);
- dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf);
- }
-
- dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
- dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);
+ dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
+ dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
+ dpm->dbp = calloc(dpm->nbp, sizeof(*dpm->dbp));
+ dpm->dwp = calloc(dpm->nwp, sizeof(*dpm->dwp));
if (!dpm->dbp || !dpm->dwp) {
+ arm_free_reg_cache(arm);
free(dpm->dbp);
free(dpm->dwp);
return ERROR_FAIL;