target: Restructure internal break/watch handling.
cortexa: Implement soft breakpoints.
This commit is contained in:
parent
9136cf4c98
commit
9aacc18f60
|
@ -48,8 +48,8 @@ static void cortexa_reset(target *t);
|
||||||
static enum target_halt_reason cortexa_halt_poll(target *t, target_addr *watch);
|
static enum target_halt_reason cortexa_halt_poll(target *t, target_addr *watch);
|
||||||
static void cortexa_halt_request(target *t);
|
static void cortexa_halt_request(target *t);
|
||||||
|
|
||||||
static int cortexa_set_hw_bp(target *t, target_addr addr, uint8_t len);
|
static int cortexa_breakwatch_set(target *t, struct breakwatch *);
|
||||||
static int cortexa_clear_hw_bp(target *t, target_addr addr, uint8_t len);
|
static int cortexa_breakwatch_clear(target *t, struct breakwatch *);
|
||||||
static uint32_t bp_bas(uint32_t addr, uint8_t len);
|
static uint32_t bp_bas(uint32_t addr, uint8_t len);
|
||||||
|
|
||||||
static void apb_write(target *t, uint16_t reg, uint32_t val);
|
static void apb_write(target *t, uint16_t reg, uint32_t val);
|
||||||
|
@ -68,7 +68,7 @@ struct cortexa_priv {
|
||||||
uint64_t d[16];
|
uint64_t d[16];
|
||||||
} reg_cache;
|
} reg_cache;
|
||||||
unsigned hw_breakpoint_max;
|
unsigned hw_breakpoint_max;
|
||||||
unsigned hw_breakpoint[16];
|
bool hw_breakpoint[16];
|
||||||
uint32_t bpc0;
|
uint32_t bpc0;
|
||||||
bool mmu_fault;
|
bool mmu_fault;
|
||||||
};
|
};
|
||||||
|
@ -393,8 +393,8 @@ bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base)
|
||||||
t->halt_resume = cortexa_halt_resume;
|
t->halt_resume = cortexa_halt_resume;
|
||||||
t->regs_size = sizeof(priv->reg_cache);
|
t->regs_size = sizeof(priv->reg_cache);
|
||||||
|
|
||||||
t->set_hw_bp = cortexa_set_hw_bp;
|
t->breakwatch_set = cortexa_breakwatch_set;
|
||||||
t->clear_hw_bp = cortexa_clear_hw_bp;
|
t->breakwatch_clear = cortexa_breakwatch_clear;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -673,45 +673,75 @@ static uint32_t bp_bas(uint32_t addr, uint8_t len)
|
||||||
return DBGBCR_BAS_LOW_HW;
|
return DBGBCR_BAS_LOW_HW;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cortexa_set_hw_bp(target *t, target_addr addr, uint8_t len)
|
static int cortexa_breakwatch_set(target *t, struct breakwatch *bw)
|
||||||
{
|
{
|
||||||
struct cortexa_priv *priv = t->priv;
|
struct cortexa_priv *priv = t->priv;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for(i = 0; i < priv->hw_breakpoint_max; i++)
|
switch (bw->type) {
|
||||||
if((priv->hw_breakpoint[i] & 1) == 0) break;
|
case TARGET_BREAK_SOFT:
|
||||||
|
switch (bw->size) {
|
||||||
|
case 2:
|
||||||
|
bw->reserved[0] = target_mem_read16(t, bw->addr);
|
||||||
|
target_mem_write16(t, bw->addr, 0xBE00);
|
||||||
|
return 0;
|
||||||
|
case 4:
|
||||||
|
bw->reserved[0] = target_mem_read32(t, bw->addr);
|
||||||
|
target_mem_write32(t, bw->addr, 0xE1200070);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
case TARGET_BREAK_HARD:
|
||||||
|
if ((bw->size != 4) && (bw->size != 2))
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(i == priv->hw_breakpoint_max) return -1;
|
for (i = 0; i < priv->hw_breakpoint_max; i++)
|
||||||
|
if ((priv->hw_breakpoint[i] & 1) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
priv->hw_breakpoint[i] = addr | 1;
|
if (i == priv->hw_breakpoint_max)
|
||||||
|
return -1;
|
||||||
|
|
||||||
apb_write(t, DBGBVR(i), addr & ~3);
|
bw->reserved[0] = i;
|
||||||
uint32_t bpc = bp_bas(addr, len) | DBGBCR_EN;
|
|
||||||
|
priv->hw_breakpoint[i] = true;
|
||||||
|
|
||||||
|
apb_write(t, DBGBVR(i), bw->addr & ~3);
|
||||||
|
uint32_t bpc = bp_bas(bw->addr, bw->size) | DBGBCR_EN;
|
||||||
apb_write(t, DBGBCR(i), bpc);
|
apb_write(t, DBGBCR(i), bpc);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
priv->bpc0 = bpc;
|
priv->bpc0 = bpc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cortexa_clear_hw_bp(target *t, target_addr addr, uint8_t len)
|
static int cortexa_breakwatch_clear(target *t, struct breakwatch *bw)
|
||||||
{
|
{
|
||||||
struct cortexa_priv *priv = t->priv;
|
struct cortexa_priv *priv = t->priv;
|
||||||
unsigned i;
|
unsigned i = bw->reserved[0];
|
||||||
|
switch (bw->type) {
|
||||||
(void)len;
|
case TARGET_BREAK_SOFT:
|
||||||
|
switch (bw->size) {
|
||||||
for (i = 0; i < priv->hw_breakpoint_max; i++)
|
case 2:
|
||||||
if ((priv->hw_breakpoint[i] & ~1) == addr)
|
target_mem_write16(t, bw->addr, i);
|
||||||
break;
|
return 0;
|
||||||
if (i == priv->hw_breakpoint_max)
|
case 4:
|
||||||
|
target_mem_write32(t, bw->addr, i);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
priv->hw_breakpoint[i] = 0;
|
case TARGET_BREAK_HARD:
|
||||||
|
priv->hw_breakpoint[i] = false;
|
||||||
apb_write(t, DBGBCR(i), 0);
|
apb_write(t, DBGBCR(i), 0);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
priv->bpc0 = 0;
|
priv->bpc0 = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,12 +56,8 @@ static enum target_halt_reason cortexm_halt_poll(target *t, target_addr *watch);
|
||||||
static void cortexm_halt_request(target *t);
|
static void cortexm_halt_request(target *t);
|
||||||
static int cortexm_fault_unwind(target *t);
|
static int cortexm_fault_unwind(target *t);
|
||||||
|
|
||||||
static int cortexm_set_hw_bp(target *t, target_addr addr, uint8_t len);
|
static int cortexm_breakwatch_set(target *t, struct breakwatch *);
|
||||||
static int cortexm_clear_hw_bp(target *t, target_addr addr, uint8_t len);
|
static int cortexm_breakwatch_clear(target *t, struct breakwatch *);
|
||||||
|
|
||||||
static int cortexm_set_hw_wp(target *t, uint8_t type, target_addr addr, uint8_t len);
|
|
||||||
static int cortexm_clear_hw_wp(target *t, uint8_t type, target_addr addr, uint8_t len);
|
|
||||||
|
|
||||||
static target_addr cortexm_check_watch(target *t);
|
static target_addr cortexm_check_watch(target *t);
|
||||||
|
|
||||||
#define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */
|
#define CORTEXM_MAX_WATCHPOINTS 4 /* architecture says up to 15, no implementation has > 4 */
|
||||||
|
@ -74,15 +70,11 @@ struct cortexm_priv {
|
||||||
bool stepping;
|
bool stepping;
|
||||||
bool on_bkpt;
|
bool on_bkpt;
|
||||||
/* Watchpoint unit status */
|
/* Watchpoint unit status */
|
||||||
struct wp_unit_s {
|
bool hw_watchpoint[CORTEXM_MAX_WATCHPOINTS];
|
||||||
uint32_t addr;
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t size;
|
|
||||||
} hw_watchpoint[CORTEXM_MAX_WATCHPOINTS];
|
|
||||||
unsigned flash_patch_revision;
|
unsigned flash_patch_revision;
|
||||||
unsigned hw_watchpoint_max;
|
unsigned hw_watchpoint_max;
|
||||||
/* Breakpoint unit status */
|
/* Breakpoint unit status */
|
||||||
uint32_t hw_breakpoint[CORTEXM_MAX_BREAKPOINTS];
|
bool hw_breakpoint[CORTEXM_MAX_BREAKPOINTS];
|
||||||
unsigned hw_breakpoint_max;
|
unsigned hw_breakpoint_max;
|
||||||
/* Copy of DEMCR for vector-catch */
|
/* Copy of DEMCR for vector-catch */
|
||||||
uint32_t demcr;
|
uint32_t demcr;
|
||||||
|
@ -240,6 +232,9 @@ bool cortexm_probe(ADIv5_AP_t *ap)
|
||||||
t->halt_resume = cortexm_halt_resume;
|
t->halt_resume = cortexm_halt_resume;
|
||||||
t->regs_size = sizeof(regnum_cortex_m);
|
t->regs_size = sizeof(regnum_cortex_m);
|
||||||
|
|
||||||
|
t->breakwatch_set = cortexm_breakwatch_set;
|
||||||
|
t->breakwatch_clear = cortexm_breakwatch_clear;
|
||||||
|
|
||||||
target_add_commands(t, cortexm_cmd_list, cortexm_driver_str);
|
target_add_commands(t, cortexm_cmd_list, cortexm_driver_str);
|
||||||
|
|
||||||
/* Probe for FP extension */
|
/* Probe for FP extension */
|
||||||
|
@ -320,18 +315,12 @@ bool cortexm_attach(target *t)
|
||||||
/* Clear any stale watchpoints */
|
/* Clear any stale watchpoints */
|
||||||
for(i = 0; i < priv->hw_watchpoint_max; i++) {
|
for(i = 0; i < priv->hw_watchpoint_max; i++) {
|
||||||
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
|
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
|
||||||
priv->hw_watchpoint[i].type = 0;
|
priv->hw_watchpoint[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flash Patch Control Register: set ENABLE */
|
/* Flash Patch Control Register: set ENABLE */
|
||||||
target_mem_write32(t, CORTEXM_FPB_CTRL,
|
target_mem_write32(t, CORTEXM_FPB_CTRL,
|
||||||
CORTEXM_FPB_CTRL_KEY | CORTEXM_FPB_CTRL_ENABLE);
|
CORTEXM_FPB_CTRL_KEY | CORTEXM_FPB_CTRL_ENABLE);
|
||||||
t->set_hw_bp = cortexm_set_hw_bp;
|
|
||||||
t->clear_hw_bp = cortexm_clear_hw_bp;
|
|
||||||
|
|
||||||
/* Data Watchpoint and Trace */
|
|
||||||
t->set_hw_wp = cortexm_set_hw_wp;
|
|
||||||
t->clear_hw_wp = cortexm_clear_hw_wp;
|
|
||||||
|
|
||||||
platform_srst_set_val(false);
|
platform_srst_set_val(false);
|
||||||
|
|
||||||
|
@ -650,130 +639,110 @@ int cortexm_run_stub(target *t, uint32_t loadaddr,
|
||||||
return bkpt_instr & 0xff;
|
return bkpt_instr & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The following routines implement hardware breakpoints.
|
/* The following routines implement hardware breakpoints and watchpoints.
|
||||||
* The Flash Patch and Breakpoint (FPB) system is used. */
|
* The Flash Patch and Breakpoint (FPB) and Data Watch and Trace (DWT)
|
||||||
|
* systems are used. */
|
||||||
|
|
||||||
static int cortexm_set_hw_bp(target *t, target_addr addr, uint8_t len)
|
static uint32_t dwt_mask(size_t len)
|
||||||
{
|
{
|
||||||
(void)len;
|
switch (len) {
|
||||||
struct cortexm_priv *priv = t->priv;
|
case 1:
|
||||||
uint32_t val = addr;
|
return CORTEXM_DWT_MASK_BYTE;
|
||||||
unsigned i;
|
case 2:
|
||||||
|
return CORTEXM_DWT_MASK_HALFWORD;
|
||||||
|
case 4:
|
||||||
|
return CORTEXM_DWT_MASK_WORD;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dwt_func(target *t, enum target_breakwatch type)
|
||||||
|
{
|
||||||
|
uint32_t x = 0;
|
||||||
|
|
||||||
|
if ((t->target_options & TOPT_FLAVOUR_V6M) == 0)
|
||||||
|
x = CORTEXM_DWT_FUNC_DATAVSIZE_WORD;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TARGET_WATCH_WRITE:
|
||||||
|
return CORTEXM_DWT_FUNC_FUNC_WRITE | x;
|
||||||
|
case TARGET_WATCH_READ:
|
||||||
|
return CORTEXM_DWT_FUNC_FUNC_READ | x;
|
||||||
|
case TARGET_WATCH_ACCESS:
|
||||||
|
return CORTEXM_DWT_FUNC_FUNC_ACCESS | x;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cortexm_breakwatch_set(target *t, struct breakwatch *bw)
|
||||||
|
{
|
||||||
|
struct cortexm_priv *priv = t->priv;
|
||||||
|
unsigned i;
|
||||||
|
uint32_t val = bw->addr;
|
||||||
|
|
||||||
|
switch (bw->type) {
|
||||||
|
case TARGET_BREAK_HARD:
|
||||||
if (priv->flash_patch_revision == 0) {
|
if (priv->flash_patch_revision == 0) {
|
||||||
val = addr & 0x1FFFFFFC;
|
val &= 0x1FFFFFFC;
|
||||||
val |= (addr & 2)?0x80000000:0x40000000;
|
val |= (bw->addr & 2)?0x80000000:0x40000000;
|
||||||
}
|
}
|
||||||
val |= 1;
|
val |= 1;
|
||||||
|
|
||||||
for(i = 0; i < priv->hw_breakpoint_max; i++)
|
for(i = 0; i < priv->hw_breakpoint_max; i++)
|
||||||
if((priv->hw_breakpoint[i] & 1) == 0) break;
|
if (!priv->hw_breakpoint[i])
|
||||||
|
|
||||||
if(i == priv->hw_breakpoint_max) return -1;
|
|
||||||
|
|
||||||
priv->hw_breakpoint[i] = addr | 1;
|
|
||||||
|
|
||||||
target_mem_write32(t, CORTEXM_FPB_COMP(i), val);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cortexm_clear_hw_bp(target *t, target_addr addr, uint8_t len)
|
|
||||||
{
|
|
||||||
(void)len;
|
|
||||||
struct cortexm_priv *priv = t->priv;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for(i = 0; i < priv->hw_breakpoint_max; i++)
|
|
||||||
if((priv->hw_breakpoint[i] & ~1) == addr) break;
|
|
||||||
|
|
||||||
if(i == priv->hw_breakpoint_max) return -1;
|
|
||||||
|
|
||||||
priv->hw_breakpoint[i] = 0;
|
|
||||||
|
|
||||||
target_mem_write32(t, CORTEXM_FPB_COMP(i), 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The following routines implement hardware watchpoints.
|
|
||||||
* The Data Watch and Trace (DWT) system is used. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
cortexm_set_hw_wp(target *t, uint8_t type, target_addr addr, uint8_t len)
|
|
||||||
{
|
|
||||||
struct cortexm_priv *priv = t->priv;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
switch(len) { /* Convert bytes size to mask size */
|
|
||||||
case 1: len = CORTEXM_DWT_MASK_BYTE; break;
|
|
||||||
case 2: len = CORTEXM_DWT_MASK_HALFWORD; break;
|
|
||||||
case 4: len = CORTEXM_DWT_MASK_WORD; break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type) { /* Convert gdb type to function type */
|
|
||||||
case 2: type = CORTEXM_DWT_FUNC_FUNC_WRITE; break;
|
|
||||||
case 3: type = CORTEXM_DWT_FUNC_FUNC_READ; break;
|
|
||||||
case 4: type = CORTEXM_DWT_FUNC_FUNC_ACCESS; break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < priv->hw_watchpoint_max; i++)
|
|
||||||
if((priv->hw_watchpoint[i].type == 0) &&
|
|
||||||
((target_mem_read32(t, CORTEXM_DWT_FUNC(i)) & 0xF) == 0))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(i == priv->hw_watchpoint_max) return -2;
|
if (i == priv->hw_breakpoint_max)
|
||||||
|
return -1;
|
||||||
priv->hw_watchpoint[i].type = type;
|
|
||||||
priv->hw_watchpoint[i].addr = addr;
|
|
||||||
priv->hw_watchpoint[i].size = len;
|
|
||||||
|
|
||||||
target_mem_write32(t, CORTEXM_DWT_COMP(i), addr);
|
|
||||||
target_mem_write32(t, CORTEXM_DWT_MASK(i), len);
|
|
||||||
target_mem_write32(t, CORTEXM_DWT_FUNC(i), type |
|
|
||||||
((t->target_options & TOPT_FLAVOUR_V6M) ? 0: CORTEXM_DWT_FUNC_DATAVSIZE_WORD));
|
|
||||||
|
|
||||||
|
priv->hw_breakpoint[i] = true;
|
||||||
|
target_mem_write32(t, CORTEXM_FPB_COMP(i), val);
|
||||||
|
bw->reserved[0] = i;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case TARGET_WATCH_WRITE:
|
||||||
|
case TARGET_WATCH_READ:
|
||||||
|
case TARGET_WATCH_ACCESS:
|
||||||
|
for(i = 0; i < priv->hw_watchpoint_max; i++)
|
||||||
|
if (!priv->hw_watchpoint[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == priv->hw_watchpoint_max)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
priv->hw_watchpoint[i] = true;
|
||||||
|
|
||||||
|
target_mem_write32(t, CORTEXM_DWT_COMP(i), val);
|
||||||
|
target_mem_write32(t, CORTEXM_DWT_MASK(i), dwt_mask(bw->size));
|
||||||
|
target_mem_write32(t, CORTEXM_DWT_FUNC(i), dwt_func(t, bw->type));
|
||||||
|
|
||||||
|
bw->reserved[0] = i;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int cortexm_breakwatch_clear(target *t, struct breakwatch *bw)
|
||||||
cortexm_clear_hw_wp(target *t, uint8_t type, target_addr addr, uint8_t len)
|
|
||||||
{
|
{
|
||||||
struct cortexm_priv *priv = t->priv;
|
struct cortexm_priv *priv = t->priv;
|
||||||
unsigned i;
|
unsigned i = bw->reserved[0];
|
||||||
|
switch (bw->type) {
|
||||||
switch(len) {
|
case TARGET_BREAK_HARD:
|
||||||
case 1: len = CORTEXM_DWT_MASK_BYTE; break;
|
priv->hw_breakpoint[i] = false;
|
||||||
case 2: len = CORTEXM_DWT_MASK_HALFWORD; break;
|
target_mem_write32(t, CORTEXM_FPB_COMP(i), 0);
|
||||||
case 4: len = CORTEXM_DWT_MASK_WORD; break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case 2: type = CORTEXM_DWT_FUNC_FUNC_WRITE; break;
|
|
||||||
case 3: type = CORTEXM_DWT_FUNC_FUNC_READ; break;
|
|
||||||
case 4: type = CORTEXM_DWT_FUNC_FUNC_ACCESS; break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < priv->hw_watchpoint_max; i++)
|
|
||||||
if((priv->hw_watchpoint[i].addr == addr) &&
|
|
||||||
(priv->hw_watchpoint[i].type == type) &&
|
|
||||||
(priv->hw_watchpoint[i].size == len)) break;
|
|
||||||
|
|
||||||
if(i == priv->hw_watchpoint_max) return -2;
|
|
||||||
|
|
||||||
priv->hw_watchpoint[i].type = 0;
|
|
||||||
|
|
||||||
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
case TARGET_WATCH_WRITE:
|
||||||
|
case TARGET_WATCH_READ:
|
||||||
|
case TARGET_WATCH_ACCESS:
|
||||||
|
priv->hw_watchpoint[i] = false;
|
||||||
|
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static target_addr cortexm_check_watch(target *t)
|
static target_addr cortexm_check_watch(target *t)
|
||||||
|
@ -783,14 +752,15 @@ static target_addr cortexm_check_watch(target *t)
|
||||||
|
|
||||||
for(i = 0; i < priv->hw_watchpoint_max; i++)
|
for(i = 0; i < priv->hw_watchpoint_max; i++)
|
||||||
/* if SET and MATCHED then break */
|
/* if SET and MATCHED then break */
|
||||||
if(priv->hw_watchpoint[i].type &&
|
if(priv->hw_watchpoint[i] &&
|
||||||
(target_mem_read32(t, CORTEXM_DWT_FUNC(i)) &
|
(target_mem_read32(t, CORTEXM_DWT_FUNC(i)) &
|
||||||
CORTEXM_DWT_FUNC_MATCHED))
|
CORTEXM_DWT_FUNC_MATCHED))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(i == priv->hw_watchpoint_max) return 0;
|
if (i == priv->hw_watchpoint_max)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return priv->hw_watchpoint[i].addr;
|
return target_mem_read32(t, CORTEXM_DWT_COMP(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cortexm_vector_catch(target *t, int argc, char *argv[])
|
static bool cortexm_vector_catch(target *t, int argc, char *argv[])
|
||||||
|
|
|
@ -73,6 +73,11 @@ void target_list_free(void)
|
||||||
free(target_list->flash);
|
free(target_list->flash);
|
||||||
target_list->flash = next;
|
target_list->flash = next;
|
||||||
}
|
}
|
||||||
|
while (target_list->bw_list) {
|
||||||
|
void * next = target_list->bw_list->next;
|
||||||
|
free(target_list->bw_list);
|
||||||
|
target_list->bw_list = next;
|
||||||
|
}
|
||||||
free(target_list);
|
free(target_list);
|
||||||
target_list = t;
|
target_list = t;
|
||||||
}
|
}
|
||||||
|
@ -316,37 +321,53 @@ void target_halt_resume(target *t, bool step) { t->halt_resume(t, step); }
|
||||||
int target_breakwatch_set(target *t,
|
int target_breakwatch_set(target *t,
|
||||||
enum target_breakwatch type, target_addr addr, size_t len)
|
enum target_breakwatch type, target_addr addr, size_t len)
|
||||||
{
|
{
|
||||||
switch (type) {
|
struct breakwatch bw = {
|
||||||
case TARGET_BREAK_HARD:
|
.type = type,
|
||||||
if (t->set_hw_bp)
|
.addr = addr,
|
||||||
return t->set_hw_bp(t, addr, len);
|
.size = len,
|
||||||
case TARGET_WATCH_WRITE:
|
};
|
||||||
case TARGET_WATCH_READ:
|
int ret = 1;
|
||||||
case TARGET_WATCH_ACCESS:
|
|
||||||
if (t->set_hw_wp)
|
if (t->breakwatch_set)
|
||||||
return t->set_hw_wp(t, type, addr, len);
|
ret = t->breakwatch_set(t, &bw);
|
||||||
default:
|
|
||||||
break;
|
if (ret == 0) {
|
||||||
|
/* Success, make a heap copy and add to list */
|
||||||
|
struct breakwatch *bwm = malloc(sizeof bw);
|
||||||
|
memcpy(bwm, &bw, sizeof(bw));
|
||||||
|
bwm->next = t->bw_list;
|
||||||
|
t->bw_list = bwm;
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int target_breakwatch_clear(target *t,
|
int target_breakwatch_clear(target *t,
|
||||||
enum target_breakwatch type, target_addr addr, size_t len)
|
enum target_breakwatch type, target_addr addr, size_t len)
|
||||||
{
|
{
|
||||||
switch (type) {
|
struct breakwatch *bwp = NULL, *bw;
|
||||||
case TARGET_BREAK_HARD:
|
int ret = 1;
|
||||||
if (t->set_hw_bp)
|
for (bw = t->bw_list; bw; bw = bw->next, bwp = bw)
|
||||||
return t->set_hw_bp(t, addr, len);
|
if ((bw->type == type) &&
|
||||||
case TARGET_WATCH_WRITE:
|
(bw->addr == addr) &&
|
||||||
case TARGET_WATCH_READ:
|
(bw->size == len))
|
||||||
case TARGET_WATCH_ACCESS:
|
|
||||||
if (t->set_hw_wp)
|
|
||||||
return t->set_hw_wp(t, type, addr, len);
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (bw == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (t->breakwatch_clear)
|
||||||
|
ret = t->breakwatch_clear(t, bw);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
if (bwp == NULL) {
|
||||||
|
t->bw_list = bw->next;
|
||||||
|
} else {
|
||||||
|
bwp->next = bw->next;
|
||||||
}
|
}
|
||||||
return 1;
|
free(bw);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accessor functions */
|
/* Accessor functions */
|
||||||
|
|
|
@ -68,6 +68,14 @@ struct target_command_s {
|
||||||
struct target_command_s *next;
|
struct target_command_s *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct breakwatch {
|
||||||
|
struct breakwatch *next;
|
||||||
|
enum target_breakwatch type;
|
||||||
|
target_addr addr;
|
||||||
|
size_t size;
|
||||||
|
uint32_t reserved[4]; /* for use by the implementing driver */
|
||||||
|
};
|
||||||
|
|
||||||
struct target_s {
|
struct target_s {
|
||||||
bool attached;
|
bool attached;
|
||||||
struct target_controller *tc;
|
struct target_controller *tc;
|
||||||
|
@ -96,11 +104,9 @@ struct target_s {
|
||||||
void (*halt_resume)(target *t, bool step);
|
void (*halt_resume)(target *t, bool step);
|
||||||
|
|
||||||
/* Break-/watchpoint functions */
|
/* Break-/watchpoint functions */
|
||||||
int (*set_hw_bp)(target *t, target_addr addr, uint8_t len);
|
int (*breakwatch_set)(target *t, struct breakwatch*);
|
||||||
int (*clear_hw_bp)(target *t, target_addr addr, uint8_t len);
|
int (*breakwatch_clear)(target *t, struct breakwatch*);
|
||||||
|
struct breakwatch *bw_list;
|
||||||
int (*set_hw_wp)(target *t, uint8_t type, target_addr addr, uint8_t len);
|
|
||||||
int (*clear_hw_wp)(target *t, uint8_t type, target_addr addr, uint8_t len);
|
|
||||||
|
|
||||||
/* target-defined options */
|
/* target-defined options */
|
||||||
unsigned target_options;
|
unsigned target_options;
|
||||||
|
|
Loading…
Reference in New Issue