aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Horn <peter.horn@bluewin.ch>2012-10-08 22:06:07 +0200
committerSpencer Oliver <spen@spen-soft.co.uk>2012-11-06 16:26:54 +0000
commit79fa75e199ae7cafe0be9d71d7246464da34015e (patch)
tree18dc3d089ddc250bc04dc4cfd1b1a36e7ca7bbb9
parented3632d9c7b89ef2934d48806ada7b2b5ee54a42 (diff)
cortex_m: Fix single stepping will not return to debug mode sometimes
This occurs when stepping past a breakpoint on a even address with maskisr option set to auto With -d3 the following log message appears in this case: "Debug : Interrupt handlers didn't complete within time, leaving target running" Cause : Given a breakpoint is set on the lower half word and the PC is on the upper half word. When another breakpoint is now set on the current PC then resuming the core will not result in a break on the newly set breakpoint. This has been observed on a STM32F1x, STM32F2x (CM3) but not on a STM32F0x (CM0). It's not clear if this is a STM32F1/F2 only or a general CM3 problem. Change-Id: I384813f3bfdf935373b5e23cdb2d7f243c70cc00 Signed-off-by: Peter Horn <peter.horn@bluewin.ch> Reviewed-on: http://openocd.zylin.com/864 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
-rw-r--r--src/target/cortex_m.c97
1 files changed, 61 insertions, 36 deletions
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index 81d6ccf4..28824b8a 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -854,45 +854,70 @@ static int cortex_m3_step(struct target *target, int current,
*
*/
- /* Set a temporary break point */
- retval = breakpoint_add(target, pc_value, 2, BKPT_TYPE_BY_ADDR(pc_value));
- bool tmp_bp_set = (retval == ERROR_OK);
-
- /* No more breakpoints left, just do a step */
- if (!tmp_bp_set)
+ /* 2012-09-29 ph
+ *
+ * If a break point is already set on the lower half word then a break point on
+ * the upper half word will not break again when the core is restarted. So we
+ * just step over the instruction with interrupts disabled.
+ *
+ * The documentation has no information about this, it was found by observation
+ * on STM32F1 and STM32F2. Proper explanation welcome. STM32F0 dosen't seem to
+ * suffer from this problem.
+ *
+ * To add some confusion: pc_value has bit 0 always set, while the breakpoint
+ * address has it always cleared. The former is done to indicate thumb mode
+ * to gdb.
+ *
+ */
+ if ((pc_value & 0x02) && breakpoint_find(target, pc_value & ~0x03)) {
+ LOG_DEBUG("Stepping over next instruction with interrupts disabled");
+ cortex_m3_write_debug_halt_mask(target, C_HALT | C_MASKINTS, 0);
cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+ /* Re-enable interrupts */
+ cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
+ }
else {
- /* Start the core */
- LOG_DEBUG("Starting core to serve pending interrupts");
- int64_t t_start = timeval_ms();
- cortex_m3_write_debug_halt_mask(target, 0, C_HALT | C_STEP);
-
- /* Wait for pending handlers to complete or timeout */
- do {
- retval = mem_ap_read_atomic_u32(swjdp,
- DCB_DHCSR,
- &cortex_m3->dcb_dhcsr);
- if (retval != ERROR_OK) {
- target->state = TARGET_UNKNOWN;
- return retval;
- }
- isr_timed_out = ((timeval_ms() - t_start) > 500);
- } while (!((cortex_m3->dcb_dhcsr & S_HALT) || isr_timed_out));
-
- /* Remove the temporary breakpoint */
- breakpoint_remove(target, pc_value);
-
- if (isr_timed_out) {
- LOG_DEBUG("Interrupt handlers didn't complete within time, "
- "leaving target running");
- } else {
- /* Step over next instruction with interrupts disabled */
- cortex_m3_write_debug_halt_mask(target,
- C_HALT | C_MASKINTS,
- 0);
+
+ /* Set a temporary break point */
+ retval = breakpoint_add(target, pc_value, 2, BKPT_TYPE_BY_ADDR(pc_value));
+ bool tmp_bp_set = (retval == ERROR_OK);
+
+ /* No more breakpoints left, just do a step */
+ if (!tmp_bp_set)
cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
- /* Re-enable interrupts */
- cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
+ else {
+ /* Start the core */
+ LOG_DEBUG("Starting core to serve pending interrupts");
+ int64_t t_start = timeval_ms();
+ cortex_m3_write_debug_halt_mask(target, 0, C_HALT | C_STEP);
+
+ /* Wait for pending handlers to complete or timeout */
+ do {
+ retval = mem_ap_read_atomic_u32(swjdp,
+ DCB_DHCSR,
+ &cortex_m3->dcb_dhcsr);
+ if (retval != ERROR_OK) {
+ target->state = TARGET_UNKNOWN;
+ return retval;
+ }
+ isr_timed_out = ((timeval_ms() - t_start) > 500);
+ } while (!((cortex_m3->dcb_dhcsr & S_HALT) || isr_timed_out));
+
+ /* Remove the temporary breakpoint */
+ breakpoint_remove(target, pc_value);
+
+ if (isr_timed_out) {
+ LOG_DEBUG("Interrupt handlers didn't complete within time, "
+ "leaving target running");
+ } else {
+ /* Step over next instruction with interrupts disabled */
+ cortex_m3_write_debug_halt_mask(target,
+ C_HALT | C_MASKINTS,
+ 0);
+ cortex_m3_write_debug_halt_mask(target, C_STEP, C_HALT);
+ /* Re-enable interrupts */
+ cortex_m3_write_debug_halt_mask(target, C_HALT, C_MASKINTS);
+ }
}
}
}