From: <ge...@op...> - 2012-09-29 18:58:00
|
This is an automated email from Gerrit. Peter Horn (pet...@bl...) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/864 -- gerrit commit 22951f8f97935dd15e07a086e56cbe2bd63c80e8 Author: Peter Horn <pet...@bl...> Date: Sat Sep 29 20:57:23 2012 +0200 Fix: Single stepping will not return to debug mode when stepping past a breakpoint on a even address. This only happens for maskisr = 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 <pet...@bl...> diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 74505a8..fc13a3f 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); + } } } } -- |