{
void *value = arm11->arm.pc->value;
- if (!current)
- buf_set_u32(value, 0, 32, address);
- else
+ /* use the current program counter */
+ if (current)
address = buf_get_u32(value, 0, 32);
+ /* Make sure that the gdb thumb fixup does not
+ * kill the return address
+ */
+ switch (arm11->arm.core_state) {
+ case ARM_STATE_ARM:
+ address &= 0xFFFFFFFC;
+ break;
+ case ARM_STATE_THUMB:
+ /* When the return address is loaded into PC
+ * bit 0 must be 1 to stay in Thumb state
+ */
+ address |= 0x1;
+ break;
+
+ /* catch-all for JAZELLE and THUMB_EE */
+ default:
+ break;
+ }
+
+ buf_set_u32(value, 0, 32, address);
+ arm11->arm.pc->dirty = 1;
+ arm11->arm.pc->valid = 1;
+
return address;
}
return retval;
}
+/**
+ * Write to program counter and switch the core state (arm/thumb) according to
+ * the address.
+ */
+static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r)
+{
+ uint32_t value = buf_get_u32(r->value, 0, 32);
+
+ /* read r0 from DCC; then "BX r0" */
+ return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
+}
+
/**
* Read basic registers of the the current context: R0 to R15, and CPSR;
* sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
goto done;
arm->cpsr->dirty = false;
+ /* restore the PC, make sure to also switch the core state
+ * to whatever it was set to with "arm core_state" command.
+ * target code will have set PC to an appropriate resume address.
+ */
+ retval = dpm_write_pc_core_state(dpm, arm->pc);
+ if (retval != ERROR_OK)
+ goto done;
+ /* on Cortex-A5 (as found on NXP VF610 SoC), BX instruction
+ * executed in debug state doesn't appear to set the PC,
+ * explicitly set it with a "MOV pc, r0". This doesn't influence
+ * CPSR on Cortex-A9 so it should be OK. Maybe due to different
+ * debug version?
+ */
retval = dpm_write_reg(dpm, arm->pc, 15);
if (retval != ERROR_OK)
goto done;