ARMv7a/Cortex-A8: report watchpoint trigger insn
Save and display the address of the instruction which triggered the watchpoint. Because of pipelining, that's well behind the PC value when debug entry completes. (Example in a subroutine that had been returned from...) Remove unused A8 stuff, mostly watchpoint hooks from the header. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
This commit is contained in:
parent
03c103d56a
commit
55eeea7fce
|
@ -736,6 +736,23 @@ static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr)
|
||||||
|
{
|
||||||
|
switch (dpm->arm->core_state) {
|
||||||
|
case ARMV4_5_STATE_ARM:
|
||||||
|
addr -= 8;
|
||||||
|
break;
|
||||||
|
case ARMV4_5_STATE_THUMB:
|
||||||
|
case ARM_STATE_THUMB_EE:
|
||||||
|
addr -= 4;
|
||||||
|
break;
|
||||||
|
case ARMV4_5_STATE_JAZELLE:
|
||||||
|
/* ?? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dpm->wp_pc = addr;
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -122,6 +122,9 @@ struct arm_dpm {
|
||||||
struct dpm_bp *dbp;
|
struct dpm_bp *dbp;
|
||||||
struct dpm_wp *dwp;
|
struct dpm_wp *dwp;
|
||||||
|
|
||||||
|
/** Address of the instruction which triggered a watchpoint. */
|
||||||
|
uint32_t wp_pc;
|
||||||
|
|
||||||
// FIXME -- read/write DCSR methods and symbols
|
// FIXME -- read/write DCSR methods and symbols
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,4 +134,6 @@ int arm_dpm_reinitialize(struct arm_dpm *dpm);
|
||||||
int arm_dpm_read_current_registers(struct arm_dpm *);
|
int arm_dpm_read_current_registers(struct arm_dpm *);
|
||||||
int arm_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp);
|
int arm_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp);
|
||||||
|
|
||||||
|
void arm_dpm_report_wfar(struct arm_dpm *, uint32_t wfar);
|
||||||
|
|
||||||
#endif /* __ARM_DPM_H */
|
#endif /* __ARM_DPM_H */
|
||||||
|
|
|
@ -113,6 +113,9 @@ int armv7a_arch_state(struct target *target)
|
||||||
|
|
||||||
if (armv4_5->core_mode == ARMV4_5_MODE_ABT)
|
if (armv4_5->core_mode == ARMV4_5_MODE_ABT)
|
||||||
armv7a_show_fault_registers(target);
|
armv7a_show_fault_registers(target);
|
||||||
|
else if (target->debug_reason == DBG_REASON_WATCHPOINT)
|
||||||
|
LOG_USER("Watchpoint triggered at PC %#08x",
|
||||||
|
(unsigned) armv7a->dpm.wp_pc);
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -772,7 +772,7 @@ static int cortex_a8_resume(struct target *target, int current,
|
||||||
static int cortex_a8_debug_entry(struct target *target)
|
static int cortex_a8_debug_entry(struct target *target)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint32_t regfile[16], pc, cpsr, dscr;
|
uint32_t regfile[16], wfar, cpsr, dscr;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
struct working_area *regfile_working_area = NULL;
|
struct working_area *regfile_working_area = NULL;
|
||||||
struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target);
|
struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target);
|
||||||
|
@ -811,9 +811,12 @@ static int cortex_a8_debug_entry(struct target *target)
|
||||||
case 2: /* asynch watchpoint */
|
case 2: /* asynch watchpoint */
|
||||||
case 10: /* precise watchpoint */
|
case 10: /* precise watchpoint */
|
||||||
target->debug_reason = DBG_REASON_WATCHPOINT;
|
target->debug_reason = DBG_REASON_WATCHPOINT;
|
||||||
/* REVISIT could collect WFAR later, to see just
|
|
||||||
* which instruction triggered the watchpoint.
|
/* save address of faulting instruction */
|
||||||
*/
|
retval = mem_ap_read_atomic_u32(swjdp,
|
||||||
|
armv7a->debug_base + CPUDBG_WFAR,
|
||||||
|
&wfar);
|
||||||
|
arm_dpm_report_wfar(&armv7a->dpm, wfar);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
target->debug_reason = DBG_REASON_UNDEFINED;
|
target->debug_reason = DBG_REASON_UNDEFINED;
|
||||||
|
@ -841,7 +844,6 @@ static int cortex_a8_debug_entry(struct target *target)
|
||||||
|
|
||||||
/* read Current PSR */
|
/* read Current PSR */
|
||||||
cortex_a8_dap_read_coreregister_u32(target, &cpsr, 16);
|
cortex_a8_dap_read_coreregister_u32(target, &cpsr, 16);
|
||||||
pc = regfile[15];
|
|
||||||
dap_ap_select(swjdp, swjdp_debugap);
|
dap_ap_select(swjdp, swjdp_debugap);
|
||||||
LOG_DEBUG("cpsr: %8.8" PRIx32, cpsr);
|
LOG_DEBUG("cpsr: %8.8" PRIx32, cpsr);
|
||||||
|
|
||||||
|
@ -892,10 +894,7 @@ static int cortex_a8_debug_entry(struct target *target)
|
||||||
if (armv7a->post_debug_entry)
|
if (armv7a->post_debug_entry)
|
||||||
armv7a->post_debug_entry(target);
|
armv7a->post_debug_entry(target);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cortex_a8_post_debug_entry(struct target *target)
|
static void cortex_a8_post_debug_entry(struct target *target)
|
||||||
|
@ -1527,20 +1526,7 @@ static int cortex_a8_examine_first(struct target *target)
|
||||||
cortex_a8->brp_list[i].BRPn = i;
|
cortex_a8->brp_list[i].BRPn = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup Watchpoint Register Pairs */
|
LOG_DEBUG("Configured %i hw breakpoints", cortex_a8->brp_num);
|
||||||
cortex_a8->wrp_num = ((didr >> 28) & 0x0F) + 1;
|
|
||||||
cortex_a8->wrp_num_available = cortex_a8->wrp_num;
|
|
||||||
cortex_a8->wrp_list = calloc(cortex_a8->wrp_num, sizeof(struct cortex_a8_wrp));
|
|
||||||
for (i = 0; i < cortex_a8->wrp_num; i++)
|
|
||||||
{
|
|
||||||
cortex_a8->wrp_list[i].used = 0;
|
|
||||||
cortex_a8->wrp_list[i].type = 0;
|
|
||||||
cortex_a8->wrp_list[i].value = 0;
|
|
||||||
cortex_a8->wrp_list[i].control = 0;
|
|
||||||
cortex_a8->wrp_list[i].WRPn = i;
|
|
||||||
}
|
|
||||||
LOG_DEBUG("Configured %i hw breakpoint pairs and %i hw watchpoint pairs",
|
|
||||||
cortex_a8->brp_num , cortex_a8->wrp_num);
|
|
||||||
|
|
||||||
target_set_examined(target);
|
target_set_examined(target);
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
|
|
|
@ -54,15 +54,6 @@ struct cortex_a8_brp
|
||||||
uint8_t BRPn;
|
uint8_t BRPn;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cortex_a8_wrp
|
|
||||||
{
|
|
||||||
int used;
|
|
||||||
int type;
|
|
||||||
uint32_t value;
|
|
||||||
uint32_t control;
|
|
||||||
uint8_t WRPn;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cortex_a8_common
|
struct cortex_a8_common
|
||||||
{
|
{
|
||||||
int common_magic;
|
int common_magic;
|
||||||
|
@ -70,29 +61,16 @@ struct cortex_a8_common
|
||||||
|
|
||||||
/* Context information */
|
/* Context information */
|
||||||
uint32_t cpudbg_dscr;
|
uint32_t cpudbg_dscr;
|
||||||
uint32_t nvic_dfsr; /* Debug Fault Status Register - shows reason for debug halt */
|
|
||||||
uint32_t nvic_icsr; /* Interrupt Control State Register - shows active and pending IRQ */
|
|
||||||
|
|
||||||
/* Saved cp15 registers */
|
/* Saved cp15 registers */
|
||||||
uint32_t cp15_control_reg;
|
uint32_t cp15_control_reg;
|
||||||
uint32_t cp15_aux_control_reg;
|
|
||||||
|
|
||||||
/* Breakpoint register pairs */
|
/* Breakpoint register pairs */
|
||||||
int brp_num_context;
|
int brp_num_context;
|
||||||
int brp_num;
|
int brp_num;
|
||||||
int brp_num_available;
|
int brp_num_available;
|
||||||
// int brp_enabled;
|
|
||||||
struct cortex_a8_brp *brp_list;
|
struct cortex_a8_brp *brp_list;
|
||||||
|
|
||||||
/* Watchpoint register pairs */
|
|
||||||
int wrp_num;
|
|
||||||
int wrp_num_available;
|
|
||||||
struct cortex_a8_wrp *wrp_list;
|
|
||||||
|
|
||||||
/* Interrupts */
|
|
||||||
int intlinesnum;
|
|
||||||
uint32_t *intsetenable;
|
|
||||||
|
|
||||||
/* Use cortex_a8_read_regs_through_mem for fast register reads */
|
/* Use cortex_a8_read_regs_through_mem for fast register reads */
|
||||||
int fast_reg_read;
|
int fast_reg_read;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue