omjavaid created this revision. omjavaid added reviewers: tberghammer, clayborg. omjavaid added a subscriber: lldb-commits. Herald added subscribers: rengolin, aemerson.
This patch provides fix for the cases where an expression or jump tries to update the value of PC in thumb mode. As precaution for an undefined behavior encountered while setting PC we will clear thumb bit of new PC if we are already in thumb mode; that is CPSR thumb mode bit is set. Also if intended behavior of setting new PC value is to change to ARM/Thumb mode then user must switch to arm or thumb mode by explicitly setting mode bit in CPSR. This update to CPSR should be done before writing new PC value. http://reviews.llvm.org/D15877 Files: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -973,7 +973,24 @@ if (error.Fail()) return error; - m_gpr_arm[offset / sizeof(uint32_t)] = value.GetAsUInt32(); + uint32_t reg_value = value.GetAsUInt32(); + // As precaution for an undefined behavior encountered while setting PC we + // will clear thumb bit of new PC if we are already in thumb mode; that is + // CPSR thumb mode bit is set. + if (offset / sizeof(uint32_t) == gpr_pc_arm) + { + // Check if we are already in thumb mode and + // thumb bit of current PC is read out to be zero and + // thumb bit of next PC is read out to be one. + if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && + !(m_gpr_arm[gpr_pc_arm] & 0x01) && + (value.GetAsUInt32() & 0x01)) + { + reg_value &= (~1ull); + } + } + + m_gpr_arm[offset / sizeof(uint32_t)] = reg_value; return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm)); }
Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp =================================================================== --- source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -973,7 +973,24 @@ if (error.Fail()) return error; - m_gpr_arm[offset / sizeof(uint32_t)] = value.GetAsUInt32(); + uint32_t reg_value = value.GetAsUInt32(); + // As precaution for an undefined behavior encountered while setting PC we + // will clear thumb bit of new PC if we are already in thumb mode; that is + // CPSR thumb mode bit is set. + if (offset / sizeof(uint32_t) == gpr_pc_arm) + { + // Check if we are already in thumb mode and + // thumb bit of current PC is read out to be zero and + // thumb bit of next PC is read out to be one. + if ((m_gpr_arm[gpr_cpsr_arm] & 0x20) && + !(m_gpr_arm[gpr_pc_arm] & 0x01) && + (value.GetAsUInt32() & 0x01)) + { + reg_value &= (~1ull); + } + } + + m_gpr_arm[offset / sizeof(uint32_t)] = reg_value; return DoWriteGPR(m_gpr_arm, sizeof(m_gpr_arm)); }
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits