<rdar://problem/15172417>

Added two new GDB server packets to debugserver: "QSaveRegisterState" and "QRestoreRegiterState".

"QSaveRegisterState" makes the remote GDB server save all register values and it returns a save identifier as an unsigned integer. This packet can be used prior to running expressions to save all registers.

All registers can them we later restored with "QRestoreRegiterState:SAVEID" what SAVEID is the integer identifier that was returned from the call to QSaveRegisterState.

Cleaned up redundant code in lldb_private::Thread, lldb_private::ThreadPlanCallFunction.
Moved the lldb_private::Thread::RegisterCheckpoint into its own header file and it is now in the lldb_private namespace. Trimmed down the RegisterCheckpoint class to omit stuff that wasn't used (the stack ID).

Added a few new virtual methods to lldb_private::RegisterContext that allow subclasses to efficiently save/restore register states and changed the RegisterContextGDBRemote to take advantage of these new calls.

llvm-svn: 194621
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 2ac7d20..da2299a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -65,6 +65,7 @@
     m_attach_or_wait_reply(eLazyBoolCalculate),
     m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
     m_supports_p (eLazyBoolCalculate),
+    m_supports_QSaveRegisterState (eLazyBoolCalculate),
     m_supports_qProcessInfoPID (true),
     m_supports_qfProcessInfo (true),
     m_supports_qUserName (true),
@@ -208,6 +209,7 @@
     m_supports_vCont_s = eLazyBoolCalculate;
     m_supports_vCont_S = eLazyBoolCalculate;
     m_supports_p = eLazyBoolCalculate;
+    m_supports_QSaveRegisterState = eLazyBoolCalculate;
     m_qHostInfo_is_valid = eLazyBoolCalculate;
     m_qProcessInfo_is_valid = eLazyBoolCalculate;
     m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
@@ -2809,3 +2811,134 @@
     }
     return false;
 }
+
+bool
+GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
+{
+    Mutex::Locker locker;
+    if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet."))
+    {
+        const bool thread_suffix_supported = GetThreadSuffixSupported();
+        
+        if (thread_suffix_supported || SetCurrentThread(tid))
+        {
+            char packet[64];
+            int packet_len = 0;
+            if (thread_suffix_supported)
+                packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid);
+            else
+                packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
+            assert (packet_len < ((int)sizeof(packet) - 1));
+            return SendPacketAndWaitForResponse(packet, response, false);
+        }
+    }
+    return false;
+
+}
+
+
+bool
+GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response)
+{
+    Mutex::Locker locker;
+    if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet."))
+    {
+        const bool thread_suffix_supported = GetThreadSuffixSupported();
+
+        if (thread_suffix_supported || SetCurrentThread(tid))
+        {
+            char packet[64];
+            int packet_len = 0;
+            // Get all registers in one packet
+            if (thread_suffix_supported)
+                packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid);
+            else
+                packet_len = ::snprintf (packet, sizeof(packet), "g");
+            assert (packet_len < ((int)sizeof(packet) - 1));
+            return SendPacketAndWaitForResponse(packet, response, false);
+        }
+    }
+    return false;
+}
+bool
+GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id)
+{
+    save_id = 0; // Set to invalid save ID
+    if (m_supports_QSaveRegisterState == eLazyBoolNo)
+        return false;
+    
+    m_supports_QSaveRegisterState = eLazyBoolYes;
+    Mutex::Locker locker;
+    if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState."))
+    {
+        const bool thread_suffix_supported = GetThreadSuffixSupported();
+        if (thread_suffix_supported || SetCurrentThread(tid))
+        {
+            char packet[256];
+            if (thread_suffix_supported)
+                ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid);
+            else
+                ::strncpy (packet, "QSaveRegisterState", sizeof(packet));
+            
+            StringExtractorGDBRemote response;
+
+            if (SendPacketAndWaitForResponse(packet, response, false))
+            {
+                if (response.IsUnsupportedResponse())
+                {
+                    // This packet isn't supported, don't try calling it again
+                    m_supports_QSaveRegisterState = eLazyBoolNo;
+                }
+                    
+                const uint32_t response_save_id = response.GetU32(0);
+                if (response_save_id != 0)
+                {
+                    save_id = response_save_id;
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+bool
+GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id)
+{
+    // We use the "m_supports_QSaveRegisterState" variable here becuase the
+    // QSaveRegisterState and QRestoreRegisterState packets must both be supported in
+    // order to be useful
+    if (m_supports_QSaveRegisterState == eLazyBoolNo)
+        return false;
+    
+    Mutex::Locker locker;
+    if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState."))
+    {
+        const bool thread_suffix_supported = GetThreadSuffixSupported();
+        if (thread_suffix_supported || SetCurrentThread(tid))
+        {
+            char packet[256];
+            if (thread_suffix_supported)
+                ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid);
+            else
+                ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id);
+            
+            StringExtractorGDBRemote response;
+            
+            if (SendPacketAndWaitForResponse(packet, response, false))
+            {
+                if (response.IsOKResponse())
+                {
+                    return true;
+                }
+                else if (response.IsUnsupportedResponse())
+                {
+                    // This packet isn't supported, don't try calling this packet or
+                    // QSaveRegisterState again...
+                    m_supports_QSaveRegisterState = eLazyBoolNo;
+                }
+            }
+        }
+    }
+    return false;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index d5535bb..530655b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -411,6 +411,21 @@
     HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
                                       StringExtractorGDBRemote &inputStringExtractor);
 
+    bool
+    ReadRegister(lldb::tid_t tid,
+                 uint32_t reg_num,
+                 StringExtractorGDBRemote &response);
+
+    bool
+    ReadAllRegisters (lldb::tid_t tid,
+                      StringExtractorGDBRemote &response);
+
+    bool
+    SaveRegisterState (lldb::tid_t tid, uint32_t &save_id);
+    
+    bool
+    RestoreRegisterState (lldb::tid_t tid, uint32_t save_id);
+    
 protected:
 
     bool
@@ -438,6 +453,7 @@
     lldb_private::LazyBool m_attach_or_wait_reply;
     lldb_private::LazyBool m_prepare_for_reg_writing_reply;
     lldb_private::LazyBool m_supports_p;
+    lldb_private::LazyBool m_supports_QSaveRegisterState;
     
     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 c4e468f..c291df7 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -153,20 +153,13 @@
 GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
                                                 GDBRemoteCommunicationClient &gdb_comm)
 {
-    char packet[64];
-    StringExtractorGDBRemote response;
-    int packet_len = 0;
     const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
-    if (gdb_comm.GetThreadSuffixSupported())
-        packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetProtocolID());
-    else
-        packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
-    assert (packet_len < ((int)sizeof(packet) - 1));
-    if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
+    StringExtractorGDBRemote response;
+    if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), reg, response))
         return PrivateSetRegisterValue (reg, response);
-
     return false;
 }
+
 bool
 GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data)
 {
@@ -185,93 +178,51 @@
 
     if (!GetRegisterIsValid(reg))
     {
-        Mutex::Locker locker;
-        if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register."))
+        if (m_read_all_at_once)
         {
-            const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
-            ProcessSP process_sp (m_thread.GetProcess());
-            if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+            StringExtractorGDBRemote response;
+            if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response))
+                return false;
+            if (response.IsNormalResponse())
+                if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
+                    SetAllRegisterValid (true);
+        }
+        else if (reg_info->value_regs)
+        {
+            // Process this composite register request by delegating to the constituent
+            // primordial registers.
+            
+            // Index of the primordial register.
+            bool success = true;
+            for (uint32_t idx = 0; success; ++idx)
             {
-                char packet[64];
-                StringExtractorGDBRemote response;
-                int packet_len = 0;
-                if (m_read_all_at_once)
-                {
-                    // Get all registers in one packet
-                    if (thread_suffix_supported)
-                        packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
-                    else
-                        packet_len = ::snprintf (packet, sizeof(packet), "g");
-                    assert (packet_len < ((int)sizeof(packet) - 1));
-                    if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
-                    {
-                        if (response.IsNormalResponse())
-                            if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
-                                SetAllRegisterValid (true);
-                    }
-                }
-                else if (reg_info->value_regs)
-                {
-                    // Process this composite register request by delegating to the constituent
-                    // primordial registers.
-                    
-                    // Index of the primordial register.
-                    bool success = true;
-                    for (uint32_t idx = 0; success; ++idx)
-                    {
-                        const uint32_t prim_reg = reg_info->value_regs[idx];
-                        if (prim_reg == LLDB_INVALID_REGNUM)
-                            break;
-                        // We have a valid primordial regsiter as our constituent.
-                        // Grab the corresponding register info.
-                        const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
-                        if (prim_reg_info == NULL)
-                            success = false;
-                        else
-                        {
-                            // Read the containing register if it hasn't already been read
-                            if (!GetRegisterIsValid(prim_reg))
-                                success = GetPrimordialRegister(prim_reg_info, gdb_comm);
-                        }
-                    }
-
-                    if (success)
-                    {
-                        // If we reach this point, all primordial register requests have succeeded.
-                        // Validate this composite register.
-                        SetRegisterIsValid (reg_info, true);
-                    }
-                }
+                const uint32_t prim_reg = reg_info->value_regs[idx];
+                if (prim_reg == LLDB_INVALID_REGNUM)
+                    break;
+                // We have a valid primordial regsiter as our constituent.
+                // Grab the corresponding register info.
+                const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
+                if (prim_reg_info == NULL)
+                    success = false;
                 else
                 {
-                    // Get each register individually
-                    GetPrimordialRegister(reg_info, gdb_comm);
+                    // Read the containing register if it hasn't already been read
+                    if (!GetRegisterIsValid(prim_reg))
+                        success = GetPrimordialRegister(prim_reg_info, gdb_comm);
                 }
             }
+
+            if (success)
+            {
+                // If we reach this point, all primordial register requests have succeeded.
+                // Validate this composite register.
+                SetRegisterIsValid (reg_info, true);
+            }
         }
         else
         {
-#if LLDB_CONFIGURATION_DEBUG
-            StreamString strm;
-            gdb_comm.DumpHistory(strm);
-            Host::SetCrashDescription (strm.GetData());
-            assert (!"Didn't get sequence mutex for read register.");
-#else
-            Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
-            if (log)
-            {
-                if (log->GetVerbose())
-                {
-                    StreamString strm;
-                    gdb_comm.DumpHistory(strm);
-                    log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData());
-                }
-                else
-                {
-                    log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name);
-                }
-            }
-#endif
+            // Get each register individually
+            GetPrimordialRegister(reg_info, gdb_comm);
         }
 
         // Make sure we got a valid register value after reading it
@@ -488,6 +439,54 @@
     return false;
 }
 
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint)
+{
+    ExecutionContext exe_ctx (CalculateThread());
+    
+    Process *process = exe_ctx.GetProcessPtr();
+    Thread *thread = exe_ctx.GetThreadPtr();
+    if (process == NULL || thread == NULL)
+        return false;
+    
+    GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+    uint32_t save_id = 0;
+    if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id))
+    {
+        reg_checkpoint.SetID(save_id);
+        reg_checkpoint.GetData().reset();
+        return true;
+    }
+    else
+    {
+        reg_checkpoint.SetID(0); // Invalid save ID is zero
+        return ReadAllRegisterValues(reg_checkpoint.GetData());
+    }
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint)
+{
+    uint32_t save_id = reg_checkpoint.GetID();
+    if (save_id != 0)
+    {
+        ExecutionContext exe_ctx (CalculateThread());
+        
+        Process *process = exe_ctx.GetProcessPtr();
+        Thread *thread = exe_ctx.GetThreadPtr();
+        if (process == NULL || thread == NULL)
+            return false;
+        
+        GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+        
+        return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id);
+    }
+    else
+    {
+        return WriteAllRegisterValues(reg_checkpoint.GetData());
+    }
+}
 
 bool
 GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index 7a49d69..38f29bb 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -91,6 +91,12 @@
     virtual bool
     WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
 
+    virtual bool
+    ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint);
+
+    virtual bool
+    WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint);
+
     virtual uint32_t
     ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);