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>tags/v0.4.0-rc1
@@ -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 */ | |||||
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); | |||||
LOG_DEBUG("Configured %i hw breakpoints", cortex_a8->brp_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; | ||||