Add a call to "sync" a thread state before checkpointing registers in preparation for 
calling functions.  This is necessary on Mac OS X, since bad things can happen if you set
the registers of a thread that's sitting in a kernel trap.

<rdar://problem/11145013>

llvm-svn: 160756
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index b4263d1..8225e69 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -51,6 +51,7 @@
     m_supports_watchpoint_support_info  (eLazyBoolCalculate),
     m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
     m_attach_or_wait_reply(eLazyBoolCalculate),
+    m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
     m_supports_qProcessInfoPID (true),
     m_supports_qfProcessInfo (true),
     m_supports_qUserName (true),
@@ -154,6 +155,26 @@
         return false;
 }
 
+bool
+GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()
+{
+    if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate)
+    {
+        m_prepare_for_reg_writing_reply = eLazyBoolNo;
+        
+        StringExtractorGDBRemote response;
+        if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false))
+        {
+            if (response.IsOKResponse())
+                m_prepare_for_reg_writing_reply = eLazyBoolYes;
+        }
+    }
+    if (m_prepare_for_reg_writing_reply == eLazyBoolYes)
+        return true;
+    else
+        return false;
+}
+
 
 void
 GDBRemoteCommunicationClient::ResetDiscoverableSettings()
@@ -168,6 +189,8 @@
     m_qHostInfo_is_valid = eLazyBoolCalculate;
     m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
     m_supports_memory_region_info = eLazyBoolCalculate;
+    m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
+    m_attach_or_wait_reply = eLazyBoolCalculate;
 
     m_supports_qProcessInfoPID = true;
     m_supports_qfProcessInfo = true;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index eee3aa5..adfec5b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -224,6 +224,9 @@
     bool
     GetVAttachOrWaitSupported ();
     
+    bool
+    GetSyncThreadStateSupported();
+    
     void
     ResetDiscoverableSettings();
 
@@ -369,6 +372,7 @@
     lldb_private::LazyBool m_supports_watchpoint_support_info;
     lldb_private::LazyBool m_watchpoints_trigger_after_instruction;
     lldb_private::LazyBool m_attach_or_wait_reply;
+    lldb_private::LazyBool m_prepare_for_reg_writing_reply;
     
     bool
         m_supports_qProcessInfoPID:1,
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 4247add..a1cac21 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -286,7 +286,6 @@
     return true;
 }
 
-
 bool
 GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info,
                                          const RegisterValue &value)
@@ -326,6 +325,29 @@
     }
     return false;
 }
+
+void
+GDBRemoteRegisterContext::SyncThreadState(Process *process)
+{
+    // NB.  We assume our caller has locked the sequence mutex.
+    
+    GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote());
+    if (!gdb_comm.GetSyncThreadStateSupported())
+        return;
+
+    StreamString packet;
+    StringExtractorGDBRemote response;
+    packet.Printf ("QSyncThreadState:%4.4llx;", m_thread.GetID());
+    if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+                                              packet.GetString().size(),
+                                              response,
+                                              false))
+    {
+        if (response.IsOKResponse())
+            InvalidateAllRegisters();
+    }
+}
+
 bool
 GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
 {
@@ -479,6 +501,8 @@
     Mutex::Locker locker;
     if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
     {
+        SyncThreadState(process);
+        
         char packet[32];
         const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
         ProcessSP process_sp (m_thread.GetProcess());
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index e39815a..e314176 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -243,6 +243,9 @@
     void
     SetAllRegisterValid (bool b);
 
+    void
+    SyncThreadState(lldb_private::Process *process);  // Assumes the sequence mutex has already been acquired.
+    
     GDBRemoteDynamicRegisterInfo &m_reg_info;
     std::vector<bool> m_reg_valid;
     lldb_private::DataExtractor m_reg_data;