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

Reply via email to