return retval;
}
+/*
+ * Single-step on ARMv7a/r is implemented through a HW breakpoint that hits
+ * every instruction at any address except the address of the current
+ * instruction.
+ * Such HW breakpoint is never hit in case of a single instruction that jumps
+ * on itself (infinite loop), or a WFI or a WFE. In this case, halt the CPU
+ * after a timeout.
+ * The jump on itself would be executed several times before the timeout forces
+ * the halt, but this is not an issue. In ARMv7a/r there are few "pathological"
+ * instructions, listed below, that jumps on itself and that can have side
+ * effects if executed more than once; but they are not considered as real use
+ * cases generated by a compiler.
+ * Some example:
+ * - 'pop {pc}' or multi register 'pop' including PC, when the new PC value is
+ * the same value of current PC. The single step will not stop at the first
+ * 'pop' and will continue taking values from the stack, modifying SP at each
+ * iteration.
+ * - 'rfeda', 'rfedb', 'rfeia', 'rfeib', when the new PC value is the same
+ * value of current PC. The register provided to the instruction (usually SP)
+ * will be incremented or decremented at each iteration.
+ *
+ * TODO: fix exit in case of error, cleaning HW breakpoints.
+ */
static int cortex_a_step(struct target *target, bool current, target_addr_t address,
bool handle_breakpoints)
{
if (retval != ERROR_OK)
return retval;
- int64_t then = timeval_ms();
+ // poll at least once before starting the timeout
+ retval = cortex_a_poll(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ int64_t then = timeval_ms() + 100;
while (target->state != TARGET_HALTED) {
+ if (timeval_ms() > then)
+ break;
+
retval = cortex_a_poll(target);
if (retval != ERROR_OK)
return retval;
- if (target->state == TARGET_HALTED)
- break;
- if (timeval_ms() > then + 1000) {
- LOG_ERROR("timeout waiting for target halt");
+ }
+
+ if (target->state != TARGET_HALTED) {
+ LOG_TARGET_DEBUG(target, "timeout waiting for target halt, try halt");
+
+ retval = cortex_a_halt(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = cortex_a_poll(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_TARGET_ERROR(target, "timeout waiting for target halt");
return ERROR_FAIL;
}
}
if (breakpoint)
cortex_a_set_breakpoint(target, breakpoint, 0);
- if (target->state != TARGET_HALTED)
- LOG_DEBUG("target stepped");
-
return ERROR_OK;
}