[Lldb-commits] [lldb] r194621 - <rdar://problem/15172417>

Greg Clayton gclayton at apple.com
Wed Nov 13 15:28:32 PST 2013


Author: gclayton
Date: Wed Nov 13 17:28:31 2013
New Revision: 194621

URL: http://llvm.org/viewvc/llvm-project?rev=194621&view=rev
Log:
<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.


Added:
    lldb/trunk/include/lldb/Target/RegisterCheckpoint.h
Modified:
    lldb/trunk/include/lldb/Target/RegisterContext.h
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
    lldb/trunk/source/Target/RegisterContext.cpp
    lldb/trunk/source/Target/Thread.cpp
    lldb/trunk/tools/debugserver/source/DNB.cpp
    lldb/trunk/tools/debugserver/source/DNB.h
    lldb/trunk/tools/debugserver/source/DNBArch.h
    lldb/trunk/tools/debugserver/source/DNBLog.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachThread.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/MachThread.h
    lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.h
    lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
    lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h
    lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
    lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp
    lldb/trunk/tools/debugserver/source/RNBRemote.h

Added: lldb/trunk/include/lldb/Target/RegisterCheckpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/RegisterCheckpoint.h?rev=194621&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/RegisterCheckpoint.h (added)
+++ lldb/trunk/include/lldb/Target/RegisterCheckpoint.h Wed Nov 13 17:28:31 2013
@@ -0,0 +1,71 @@
+//===-- RegisterCheckpoint.h ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterCheckpoint_h_
+#define liblldb_RegisterCheckpoint_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Target/StackID.h"
+
+namespace lldb_private {
+
+    // Inherit from UserID in case pushing/popping all register values can be
+    // done using a 64 bit integer that holds a baton/cookie instead of actually
+    // having to read all register values into a buffer
+    class RegisterCheckpoint : public UserID
+    {
+    public:
+        
+        enum class Reason {
+            // An expression is about to be run on the thread if the protocol that
+            // talks to the debuggee supports checkpointing the registers using a
+            // push/pop then the UserID base class in the RegisterCheckpoint can
+            // be used to store the baton/cookie that refers to the remote saved
+            // state.
+            eExpression,
+            // The register checkpoint wants the raw register bytes, so they must
+            // be read into m_data_sp, or the save/restore checkpoint should fail.
+            eDataBackup
+        };
+        
+        RegisterCheckpoint(Reason reason) :
+            UserID(0),
+            m_data_sp (),
+            m_reason(reason)
+        {
+        }
+        
+        ~RegisterCheckpoint()
+        {
+        }
+        
+        lldb::DataBufferSP &
+        GetData()
+        {
+            return m_data_sp;
+        }
+        
+        const lldb::DataBufferSP &
+        GetData() const
+        {
+            return m_data_sp;
+        }
+        
+    protected:
+        lldb::DataBufferSP m_data_sp;
+        Reason m_reason;
+        
+        // Make RegisterCheckpointSP if you wish to share the data in this class.
+        DISALLOW_COPY_AND_ASSIGN(RegisterCheckpoint);
+    };
+    
+} // namespace lldb_private
+
+#endif  // liblldb_RegisterCheckpoint_h_

Modified: lldb/trunk/include/lldb/Target/RegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/RegisterContext.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/RegisterContext.h (original)
+++ lldb/trunk/include/lldb/Target/RegisterContext.h Wed Nov 13 17:28:31 2013
@@ -59,6 +59,18 @@ public:
     virtual bool
     WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) = 0;
     
+    virtual bool
+    ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+    {
+        return false;
+    }
+    
+    virtual bool
+    WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+    {
+        return false;
+    }
+
     // These two functions are used to implement "push" and "pop" of register states.  They are used primarily
     // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
     // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
@@ -67,10 +79,10 @@ public:
     // so these API's should only be used when this behavior is needed.
     
     virtual bool
-    ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0;
-
+    ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint);
+    
     virtual bool
-    WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0;
+    WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint);
     
     bool
     CopyFromRegisterContext (lldb::RegisterContextSP context);

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Wed Nov 13 17:28:31 2013
@@ -17,6 +17,7 @@
 #include "lldb/Core/UserID.h"
 #include "lldb/Core/UserSettingsController.h"
 #include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/RegisterCheckpoint.h"
 #include "lldb/Target/StackFrameList.h"
 
 #define LLDB_THREAD_MAX_STOP_EXC_DATA 8
@@ -130,79 +131,12 @@ public:
     DISALLOW_COPY_AND_ASSIGN (ThreadEventData);
     };
     
-    // TODO: You shouldn't just checkpoint the register state alone, so this should get
-    // moved to protected.  To do that ThreadStateCheckpoint needs to be returned as a token...
-    class RegisterCheckpoint
-    {
-    public:
-
-        RegisterCheckpoint() :
-            m_stack_id (),
-            m_data_sp ()
-        {
-        }
-
-        RegisterCheckpoint (const StackID &stack_id) :
-            m_stack_id (stack_id),
-            m_data_sp ()
-        {
-        }
-
-        ~RegisterCheckpoint()
-        {
-        }
-
-        const RegisterCheckpoint&
-        operator= (const RegisterCheckpoint &rhs)
-        {
-            if (this != &rhs)
-            {
-                this->m_stack_id = rhs.m_stack_id;
-                this->m_data_sp  = rhs.m_data_sp;
-            }
-            return *this;
-        }
-        
-        RegisterCheckpoint (const RegisterCheckpoint &rhs) :
-            m_stack_id (rhs.m_stack_id),
-            m_data_sp (rhs.m_data_sp)
-        {
-        }
-        
-        const StackID &
-        GetStackID()
-        {
-            return m_stack_id;
-        }
-
-        void
-        SetStackID (const StackID &stack_id)
-        {
-            m_stack_id = stack_id;
-        }
-
-        lldb::DataBufferSP &
-        GetData()
-        {
-            return m_data_sp;
-        }
-
-        const lldb::DataBufferSP &
-        GetData() const
-        {
-            return m_data_sp;
-        }
-
-    protected:
-        StackID m_stack_id;
-        lldb::DataBufferSP m_data_sp;
-    };
 
     struct ThreadStateCheckpoint
     {
         uint32_t           orig_stop_id;  // Dunno if I need this yet but it is an interesting bit of data.
         lldb::StopInfoSP   stop_info_sp;  // You have to restore the stop info or you might continue with the wrong signals.
-        RegisterCheckpoint register_backup;  // You need to restore the registers, of course...
+        lldb::RegisterCheckpointSP register_backup_sp;  // You need to restore the registers, of course...
         uint32_t           current_inlined_depth;
         lldb::addr_t       current_inlined_pc;
     };
@@ -1004,16 +938,6 @@ protected:
 
     typedef std::vector<lldb::ThreadPlanSP> plan_stack;
 
-    virtual bool
-    SaveFrameZeroState (RegisterCheckpoint &checkpoint);
-
-    virtual bool
-    RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
-    
-    // register_data_sp must be a DataSP passed to ReadAllRegisterValues.
-    bool
-    ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp);
-
     virtual lldb_private::Unwind *
     GetUnwinder ();
 
@@ -1035,12 +959,6 @@ protected:
     lldb::StackFrameListSP
     GetStackFrameList ();
     
-    struct ThreadState
-    {
-        uint32_t           orig_stop_id;
-        lldb::StopInfoSP   stop_info_sp;
-        RegisterCheckpoint register_backup;
-    };
 
     //------------------------------------------------------------------
     // Classes that inherit from Process can see and modify these

Modified: lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h Wed Nov 13 17:28:31 2013
@@ -163,7 +163,6 @@ private:
     Address                                         m_function_addr;
     Address                                         m_start_addr;
     lldb::addr_t                                    m_function_sp;
-    Thread::RegisterCheckpoint                      m_register_backup;
     lldb::ThreadPlanSP                              m_subplan_sp;
     LanguageRuntime                                *m_cxx_language_runtime;
     LanguageRuntime                                *m_objc_language_runtime;

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Wed Nov 13 17:28:31 2013
@@ -162,6 +162,7 @@ class   PythonDictionary;
 class   PythonInteger;
 class   PythonObject;
 class   PythonString;
+class   RegisterCheckpoint;
 class   RegisterContext;
 class   RegisterLocation;
 class   RegisterLocationList;
@@ -329,6 +330,7 @@ namespace lldb {
     typedef std::shared_ptr<lldb_private::ProcessLaunchInfo> ProcessLaunchInfoSP;
     typedef std::weak_ptr<lldb_private::Process> ProcessWP;
     typedef std::shared_ptr<lldb_private::Property> PropertySP;
+    typedef std::shared_ptr<lldb_private::RegisterCheckpoint> RegisterCheckpointSP;
     typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP;
     typedef std::shared_ptr<lldb_private::RegularExpression> RegularExpressionSP;
     typedef std::shared_ptr<lldb_private::ScriptInterpreterObject> ScriptInterpreterObjectSP;

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Wed Nov 13 17:28:31 2013
@@ -427,6 +427,7 @@
 		26A527C414E24F5F00F3A14A /* ThreadMachCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 26A527C014E24F5F00F3A14A /* ThreadMachCore.h */; };
 		26A69C5F137A17A500262477 /* RegisterValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C6886E137880C400407EDF /* RegisterValue.cpp */; };
 		26A7A035135E6E4200FB369E /* OptionValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A7A034135E6E4200FB369E /* OptionValue.cpp */; };
+		26AB54121832DC3400EADFF3 /* RegisterCheckpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 26AB54111832DC3400EADFF3 /* RegisterCheckpoint.h */; };
 		26AB92121819D74600E63F3E /* DWARFDataExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26AB92101819D74600E63F3E /* DWARFDataExtractor.cpp */; };
 		26AB92131819D74600E63F3E /* DWARFDataExtractor.h in Headers */ = {isa = PBXBuildFile; fileRef = 26AB92111819D74600E63F3E /* DWARFDataExtractor.h */; };
 		26ACEC2815E077AE00E94760 /* Property.h in Headers */ = {isa = PBXBuildFile; fileRef = 26ACEC2715E077AE00E94760 /* Property.h */; };
@@ -1090,6 +1091,7 @@
 		26A527C014E24F5F00F3A14A /* ThreadMachCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadMachCore.h; sourceTree = "<group>"; };
 		26A7A034135E6E4200FB369E /* OptionValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionValue.cpp; path = source/Interpreter/OptionValue.cpp; sourceTree = "<group>"; };
 		26A7A036135E6E5300FB369E /* OptionValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OptionValue.h; path = include/lldb/Interpreter/OptionValue.h; sourceTree = "<group>"; };
+		26AB54111832DC3400EADFF3 /* RegisterCheckpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterCheckpoint.h; path = include/lldb/Target/RegisterCheckpoint.h; sourceTree = "<group>"; };
 		26AB92101819D74600E63F3E /* DWARFDataExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFDataExtractor.cpp; sourceTree = "<group>"; };
 		26AB92111819D74600E63F3E /* DWARFDataExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFDataExtractor.h; sourceTree = "<group>"; };
 		26ACEC2715E077AE00E94760 /* Property.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Property.h; path = include/lldb/Interpreter/Property.h; sourceTree = "<group>"; };
@@ -3118,6 +3120,7 @@
 				264A43BD1320BCEB005B4096 /* Platform.cpp */,
 				26BC7DF310F1B81A00F91463 /* Process.h */,
 				26BC7F3610F1B90C00F91463 /* Process.cpp */,
+				26AB54111832DC3400EADFF3 /* RegisterCheckpoint.h */,
 				26BC7DF410F1B81A00F91463 /* RegisterContext.h */,
 				26BC7F3710F1B90C00F91463 /* RegisterContext.cpp */,
 				2618D78F1240115500F2B8FE /* SectionLoadList.h */,
@@ -3611,6 +3614,7 @@
 				AF254E32170CCC33007AE5C9 /* PlatformDarwinKernel.h in Headers */,
 				2694E99E14FC0BB30076DE67 /* PlatformFreeBSD.h in Headers */,
 				2694E9A514FC0BBD0076DE67 /* PlatformLinux.h in Headers */,
+				26AB54121832DC3400EADFF3 /* RegisterCheckpoint.h in Headers */,
 				26AB92131819D74600E63F3E /* DWARFDataExtractor.h in Headers */,
 				2663E379152BD1890091EC22 /* ReadWriteLock.h in Headers */,
 				945759681534941F005A9070 /* PlatformPOSIX.h in Headers */,

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Wed Nov 13 17:28:31 2013
@@ -65,6 +65,7 @@ GDBRemoteCommunicationClient::GDBRemoteC
     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 @@ GDBRemoteCommunicationClient::ResetDisco
     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 @@ GDBRemoteCommunicationClient::CalculateM
     }
     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;
+}

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h Wed Nov 13 17:28:31 2013
@@ -411,6 +411,21 @@ public:
     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 @@ protected:
     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,

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp Wed Nov 13 17:28:31 2013
@@ -153,20 +153,13 @@ bool
 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 @@ GDBRemoteRegisterContext::ReadRegisterBy
 
     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 @@ GDBRemoteRegisterContext::WriteRegisterB
     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)

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h Wed Nov 13 17:28:31 2013
@@ -91,6 +91,12 @@ public:
     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);
 

Modified: lldb/trunk/source/Target/RegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/RegisterContext.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/source/Target/RegisterContext.cpp (original)
+++ lldb/trunk/source/Target/RegisterContext.cpp Wed Nov 13 17:28:31 2013
@@ -440,6 +440,18 @@ RegisterContext::WriteRegisterValueToMem
 
 }
 
+bool
+RegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint)
+{
+    return ReadAllRegisterValues(reg_checkpoint.GetData());
+}
+
+bool
+RegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint)
+{
+    return WriteAllRegisterValues(reg_checkpoint.GetData());
+}
+
 TargetSP
 RegisterContext::CalculateTarget ()
 {

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Wed Nov 13 17:28:31 2013
@@ -496,7 +496,19 @@ Thread::ThreadStoppedForAReason (void)
 bool
 Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state)
 {
-    if (!SaveFrameZeroState(saved_state.register_backup))
+    saved_state.register_backup_sp.reset();
+    lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+    if (frame_sp)
+    {
+        lldb::RegisterCheckpointSP reg_checkpoint_sp(new RegisterCheckpoint(RegisterCheckpoint::Reason::eExpression));
+        if (reg_checkpoint_sp)
+        {
+            lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext());
+            if (reg_ctx_sp && reg_ctx_sp->ReadAllRegisterValues (*reg_checkpoint_sp))
+                saved_state.register_backup_sp = reg_checkpoint_sp;
+        }
+    }
+    if (!saved_state.register_backup_sp)
         return false;
 
     saved_state.stop_info_sp = GetStopInfo();
@@ -511,7 +523,26 @@ Thread::CheckpointThreadState (ThreadSta
 bool
 Thread::RestoreRegisterStateFromCheckpoint (ThreadStateCheckpoint &saved_state)
 {
-    return RestoreSaveFrameZero(saved_state.register_backup);
+    if (saved_state.register_backup_sp)
+    {
+        lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+        if (frame_sp)
+        {
+            lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext());
+            if (reg_ctx_sp)
+            {
+                bool ret = reg_ctx_sp->WriteAllRegisterValues (*saved_state.register_backup_sp);
+                
+                // Clear out all stack frames as our world just changed.
+                ClearStackFrames();
+                reg_ctx_sp->InvalidateIfNeeded(true);
+                if (m_unwinder_ap.get())
+                    m_unwinder_ap->Clear();
+                return ret;
+            }
+        }
+    }
+    return false;
 }
 
 bool
@@ -1966,48 +1997,6 @@ Thread::GetStackFrameStatus (Stream& str
                                            num_frames_with_source);
 }
 
-bool
-Thread::SaveFrameZeroState (RegisterCheckpoint &checkpoint)
-{
-    lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
-    if (frame_sp)
-    {
-        checkpoint.SetStackID(frame_sp->GetStackID());
-        lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext());
-        if (reg_ctx_sp)
-            return reg_ctx_sp->ReadAllRegisterValues (checkpoint.GetData());
-    }
-    return false;
-}
-
-bool
-Thread::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint)
-{
-    return ResetFrameZeroRegisters (checkpoint.GetData());
-}
-
-bool
-Thread::ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp)
-{
-    lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
-    if (frame_sp)
-    {
-        lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext());
-        if (reg_ctx_sp)
-        {
-            bool ret = reg_ctx_sp->WriteAllRegisterValues (register_data_sp);
-
-            // Clear out all stack frames as our world just changed.
-            ClearStackFrames();
-            reg_ctx_sp->InvalidateIfNeeded(true);
-            if (m_unwinder_ap.get())
-                m_unwinder_ap->Clear();
-            return ret;
-        }
-    }
-    return false;
-}
-
 Unwind *
 Thread::GetUnwinder ()
 {

Modified: lldb/trunk/tools/debugserver/source/DNB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.cpp (original)
+++ lldb/trunk/tools/debugserver/source/DNB.cpp Wed Nov 13 17:28:31 2013
@@ -1765,6 +1765,31 @@ DNBThreadSetRegisterContext (nub_process
     return 0;
 }
 
+uint32_t
+DNBThreadSaveRegisterState (nub_process_t pid, nub_thread_t tid)
+{
+    if (tid != INVALID_NUB_THREAD)
+    {
+        MachProcessSP procSP;
+        if (GetProcessSP (pid, procSP))
+            return procSP->GetThreadList().SaveRegisterState (tid);
+    }
+    return 0;    
+}
+nub_bool_t
+DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t tid, uint32_t save_id)
+{
+    if (tid != INVALID_NUB_THREAD)
+    {
+        MachProcessSP procSP;
+        if (GetProcessSP (pid, procSP))
+            return procSP->GetThreadList().RestoreRegisterState (tid, save_id);
+    }
+    return false;
+}
+
+
+
 //----------------------------------------------------------------------
 // Read a register value by name.
 //----------------------------------------------------------------------

Modified: lldb/trunk/tools/debugserver/source/DNB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNB.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNB.h (original)
+++ lldb/trunk/tools/debugserver/source/DNB.h Wed Nov 13 17:28:31 2013
@@ -18,8 +18,6 @@
 #include <mach/thread_info.h>
 #include <string>
 
-#define DNB_EXPORT __attribute__((visibility("default")))
-
 typedef bool (*DNBShouldCancelCallback) (void *);
 
 void            DNBInitialize ();
@@ -41,11 +39,11 @@ nub_process_t   DNBProcessLaunch
                                          nub_launch_flavor_t launch_flavor, 
                                          int disable_aslr, 
                                          char *err_str, 
-                                         size_t err_len) DNB_EXPORT;
+                                         size_t err_len);
 
-nub_process_t   DNBProcessAttach        (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
-nub_process_t   DNBProcessAttachByName  (const char *name, struct timespec *timeout, char *err_str, size_t err_len) DNB_EXPORT;
-nub_process_t   DNBProcessAttachWait    (const char *wait_name, nub_launch_flavor_t launch_flavor, bool ignore_existing, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL) DNB_EXPORT;
+nub_process_t   DNBProcessAttach        (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len);
+nub_process_t   DNBProcessAttachByName  (const char *name, struct timespec *timeout, char *err_str, size_t err_len);
+nub_process_t   DNBProcessAttachWait    (const char *wait_name, nub_launch_flavor_t launch_flavor, bool ignore_existing, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL);
 // Resume a process with exact instructions on what to do with each thread:
 // - If no thread actions are supplied (actions is NULL or num_actions is zero),
 //   then all threads are continued.
@@ -54,97 +52,99 @@ nub_process_t   DNBProcessAttachWait
 //   explicit thread action can be made by making a thread action with a tid of
 //   INVALID_NUB_THREAD. If there is no default action, those threads will
 //   remain stopped.
-nub_bool_t      DNBProcessResume        (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions) DNB_EXPORT;
-nub_bool_t      DNBProcessHalt          (nub_process_t pid) DNB_EXPORT;
-nub_bool_t      DNBProcessDetach        (nub_process_t pid) DNB_EXPORT;
-nub_bool_t      DNBProcessSignal        (nub_process_t pid, int signal) DNB_EXPORT;
-nub_bool_t      DNBProcessKill          (nub_process_t pid) DNB_EXPORT;
-nub_size_t      DNBProcessMemoryRead    (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) DNB_EXPORT;
-nub_size_t      DNBProcessMemoryWrite   (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT;
-nub_addr_t      DNBProcessMemoryAllocate    (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT;
-nub_bool_t      DNBProcessMemoryDeallocate  (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
-int             DNBProcessMemoryRegionInfo  (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) DNB_EXPORT;
-std::string     DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType) DNB_EXPORT;
-nub_bool_t      DNBProcessSetEnableAsyncProfiling   (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) DNB_EXPORT;
+nub_bool_t      DNBProcessResume        (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions);
+nub_bool_t      DNBProcessHalt          (nub_process_t pid);
+nub_bool_t      DNBProcessDetach        (nub_process_t pid);
+nub_bool_t      DNBProcessSignal        (nub_process_t pid, int signal);
+nub_bool_t      DNBProcessKill          (nub_process_t pid);
+nub_size_t      DNBProcessMemoryRead    (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf);
+nub_size_t      DNBProcessMemoryWrite   (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf);
+nub_addr_t      DNBProcessMemoryAllocate    (nub_process_t pid, nub_size_t size, uint32_t permissions);
+nub_bool_t      DNBProcessMemoryDeallocate  (nub_process_t pid, nub_addr_t addr);
+int             DNBProcessMemoryRegionInfo  (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info);
+std::string     DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType);
+nub_bool_t      DNBProcessSetEnableAsyncProfiling   (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type);
 
 //----------------------------------------------------------------------
 // Process status
 //----------------------------------------------------------------------
-nub_bool_t      DNBProcessIsAlive                       (nub_process_t pid) DNB_EXPORT;
-nub_state_t     DNBProcessGetState                      (nub_process_t pid) DNB_EXPORT;
-nub_bool_t      DNBProcessGetExitStatus                 (nub_process_t pid, int *status) DNB_EXPORT;
-nub_bool_t      DNBProcessSetExitStatus                 (nub_process_t pid, int status) DNB_EXPORT;
-nub_size_t      DNBProcessGetNumThreads                 (nub_process_t pid) DNB_EXPORT;
-nub_thread_t    DNBProcessGetCurrentThread              (nub_process_t pid) DNB_EXPORT;
-nub_thread_t    DNBProcessGetCurrentThreadMachPort      (nub_process_t pid) DNB_EXPORT;
-nub_thread_t    DNBProcessSetCurrentThread              (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
-nub_thread_t    DNBProcessGetThreadAtIndex              (nub_process_t pid, nub_size_t thread_idx) DNB_EXPORT;
-nub_bool_t      DNBProcessSyncThreadState               (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
-nub_addr_t      DNBProcessGetSharedLibraryInfoAddress   (nub_process_t pid) DNB_EXPORT;
-nub_bool_t      DNBProcessSharedLibrariesUpdated        (nub_process_t pid) DNB_EXPORT;
-nub_size_t      DNBProcessGetSharedLibraryInfo          (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos) DNB_EXPORT;
-nub_bool_t      DNBProcessSetNameToAddressCallback      (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) DNB_EXPORT;
-nub_bool_t      DNBProcessSetSharedLibraryInfoCallback  (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton) DNB_EXPORT;
-nub_addr_t      DNBProcessLookupAddress                 (nub_process_t pid, const char *name, const char *shlib) DNB_EXPORT;
-nub_size_t      DNBProcessGetAvailableSTDOUT            (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
-nub_size_t      DNBProcessGetAvailableSTDERR            (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
-nub_size_t      DNBProcessGetAvailableProfileData       (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT;
-nub_size_t      DNBProcessGetStopCount                  (nub_process_t pid) DNB_EXPORT;
-uint32_t        DNBProcessGetCPUType                    (nub_process_t pid) DNB_EXPORT; 
+nub_bool_t      DNBProcessIsAlive                       (nub_process_t pid);
+nub_state_t     DNBProcessGetState                      (nub_process_t pid);
+nub_bool_t      DNBProcessGetExitStatus                 (nub_process_t pid, int *status);
+nub_bool_t      DNBProcessSetExitStatus                 (nub_process_t pid, int status);
+nub_size_t      DNBProcessGetNumThreads                 (nub_process_t pid);
+nub_thread_t    DNBProcessGetCurrentThread              (nub_process_t pid);
+nub_thread_t    DNBProcessGetCurrentThreadMachPort      (nub_process_t pid);
+nub_thread_t    DNBProcessSetCurrentThread              (nub_process_t pid, nub_thread_t tid);
+nub_thread_t    DNBProcessGetThreadAtIndex              (nub_process_t pid, nub_size_t thread_idx);
+nub_bool_t      DNBProcessSyncThreadState               (nub_process_t pid, nub_thread_t tid);
+nub_addr_t      DNBProcessGetSharedLibraryInfoAddress   (nub_process_t pid);
+nub_bool_t      DNBProcessSharedLibrariesUpdated        (nub_process_t pid);
+nub_size_t      DNBProcessGetSharedLibraryInfo          (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos);
+nub_bool_t      DNBProcessSetNameToAddressCallback      (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton);
+nub_bool_t      DNBProcessSetSharedLibraryInfoCallback  (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton);
+nub_addr_t      DNBProcessLookupAddress                 (nub_process_t pid, const char *name, const char *shlib);
+nub_size_t      DNBProcessGetAvailableSTDOUT            (nub_process_t pid, char *buf, nub_size_t buf_size);
+nub_size_t      DNBProcessGetAvailableSTDERR            (nub_process_t pid, char *buf, nub_size_t buf_size);
+nub_size_t      DNBProcessGetAvailableProfileData       (nub_process_t pid, char *buf, nub_size_t buf_size);
+nub_size_t      DNBProcessGetStopCount                  (nub_process_t pid);
+uint32_t        DNBProcessGetCPUType                    (nub_process_t pid); 
 
 //----------------------------------------------------------------------
 // Process executable and arguments
 //----------------------------------------------------------------------
-const char *    DNBProcessGetExecutablePath     (nub_process_t pid) DNB_EXPORT;
-const char *    DNBProcessGetArgumentAtIndex    (nub_process_t pid, nub_size_t idx) DNB_EXPORT;
-nub_size_t      DNBProcessGetArgumentCount      (nub_process_t pid) DNB_EXPORT;
+const char *    DNBProcessGetExecutablePath     (nub_process_t pid);
+const char *    DNBProcessGetArgumentAtIndex    (nub_process_t pid, nub_size_t idx);
+nub_size_t      DNBProcessGetArgumentCount      (nub_process_t pid);
 
 //----------------------------------------------------------------------
 // Process events
 //----------------------------------------------------------------------
-nub_event_t     DNBProcessWaitForEvents         (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout) DNB_EXPORT;
-void            DNBProcessResetEvents           (nub_process_t pid, nub_event_t event_mask) DNB_EXPORT;
+nub_event_t     DNBProcessWaitForEvents         (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout);
+void            DNBProcessResetEvents           (nub_process_t pid, nub_event_t event_mask);
 
 //----------------------------------------------------------------------
 // Thread functions
 //----------------------------------------------------------------------
-const char *    DNBThreadGetName                (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
-nub_bool_t      DNBThreadGetIdentifierInfo      (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info) DNB_EXPORT;
-nub_state_t     DNBThreadGetState               (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
-nub_bool_t      DNBThreadGetRegisterValueByID   (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value) DNB_EXPORT;
-nub_bool_t      DNBThreadSetRegisterValueByID   (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) DNB_EXPORT;
-nub_size_t      DNBThreadGetRegisterContext     (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len) DNB_EXPORT;
-nub_size_t      DNBThreadSetRegisterContext     (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len) DNB_EXPORT;
-nub_bool_t      DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t set, const char *name, DNBRegisterValue *value) DNB_EXPORT;
-nub_bool_t      DNBThreadGetStopReason          (nub_process_t pid, nub_thread_t tid, DNBThreadStopInfo *stop_info) DNB_EXPORT;
-const char *    DNBThreadGetInfo                (nub_process_t pid, nub_thread_t tid) DNB_EXPORT;
+const char *    DNBThreadGetName                (nub_process_t pid, nub_thread_t tid);
+nub_bool_t      DNBThreadGetIdentifierInfo      (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info);
+nub_state_t     DNBThreadGetState               (nub_process_t pid, nub_thread_t tid);
+nub_bool_t      DNBThreadGetRegisterValueByID   (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value);
+nub_bool_t      DNBThreadSetRegisterValueByID   (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value);
+nub_size_t      DNBThreadGetRegisterContext     (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len);
+nub_size_t      DNBThreadSetRegisterContext     (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len);
+uint32_t        DNBThreadSaveRegisterState      (nub_process_t pid, nub_thread_t tid);
+nub_bool_t      DNBThreadRestoreRegisterState   (nub_process_t pid, nub_thread_t tid, uint32_t save_id);
+nub_bool_t      DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t set, const char *name, DNBRegisterValue *value);
+nub_bool_t      DNBThreadGetStopReason          (nub_process_t pid, nub_thread_t tid, DNBThreadStopInfo *stop_info);
+const char *    DNBThreadGetInfo                (nub_process_t pid, nub_thread_t tid);
 //----------------------------------------------------------------------
 // Breakpoint functions
 //----------------------------------------------------------------------
-nub_bool_t      DNBBreakpointSet                (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware) DNB_EXPORT;
-nub_bool_t      DNBBreakpointClear              (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
+nub_bool_t      DNBBreakpointSet                (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware);
+nub_bool_t      DNBBreakpointClear              (nub_process_t pid, nub_addr_t addr);
 
 //----------------------------------------------------------------------
 // Watchpoint functions
 //----------------------------------------------------------------------
-nub_bool_t      DNBWatchpointSet                (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware) DNB_EXPORT;
-nub_bool_t      DNBWatchpointClear              (nub_process_t pid, nub_addr_t addr) DNB_EXPORT;
-uint32_t        DNBWatchpointGetNumSupportedHWP (nub_process_t pid) DNB_EXPORT; 
+nub_bool_t      DNBWatchpointSet                (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware);
+nub_bool_t      DNBWatchpointClear              (nub_process_t pid, nub_addr_t addr);
+uint32_t        DNBWatchpointGetNumSupportedHWP (nub_process_t pid); 
 
 const DNBRegisterSetInfo *
-                DNBGetRegisterSetInfo           (nub_size_t *num_reg_sets) DNB_EXPORT;
-nub_bool_t      DNBGetRegisterInfoByName        (const char *reg_name, DNBRegisterInfo* info) DNB_EXPORT;
+                DNBGetRegisterSetInfo           (nub_size_t *num_reg_sets);
+nub_bool_t      DNBGetRegisterInfoByName        (const char *reg_name, DNBRegisterInfo* info);
 
 //----------------------------------------------------------------------
 // Printf style formatting for printing values in the inferior memory
 // space and registers.
 //----------------------------------------------------------------------
-nub_size_t      DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t addr, FILE *file, const char *format) DNB_EXPORT;
+nub_size_t      DNBPrintf (nub_process_t pid, nub_thread_t tid, nub_addr_t addr, FILE *file, const char *format);
 
 //----------------------------------------------------------------------
 // Other static nub information calls.
 //----------------------------------------------------------------------
-const char *    DNBStateAsString (nub_state_t state) DNB_EXPORT;
-nub_bool_t      DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size) DNB_EXPORT;
+const char *    DNBStateAsString (nub_state_t state);
+nub_bool_t      DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size);
 
 #endif

Modified: lldb/trunk/tools/debugserver/source/DNBArch.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNBArch.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNBArch.h (original)
+++ lldb/trunk/tools/debugserver/source/DNBArch.h Wed Nov 13 17:28:31 2013
@@ -58,10 +58,22 @@ public:
     static bool
     SetArchitecture (uint32_t cpu_type);
     
+    DNBArchProtocol () :
+        m_save_id(0)
+    {
+        
+    }
+    
+    virtual ~DNBArchProtocol ()
+    {
+        
+    }
     virtual bool            GetRegisterValue (int set, int reg, DNBRegisterValue *value) = 0;
     virtual bool            SetRegisterValue (int set, int reg, const DNBRegisterValue *value) = 0;
     virtual nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len) = 0;
     virtual nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len) = 0;
+    virtual uint32_t        SaveRegisterState () = 0;
+    virtual bool            RestoreRegisterState (uint32_t save_id) = 0;
 
     virtual kern_return_t   GetRegisterState (int set, bool force) = 0;
     virtual kern_return_t   SetRegisterState (int set) = 0;
@@ -85,6 +97,11 @@ public:
 protected:
     friend class MachThread;
 
+    uint32_t                GetNextRegisterStateSaveID ()
+                            {
+                                return ++m_save_id;
+                            }
+
     enum
     {
         Trans_Pending = 0,      // Transaction is pending, and checkpoint state has been snapshotted.
@@ -94,6 +111,9 @@ protected:
     virtual bool StartTransForHWP() { return true; }
     virtual bool RollbackTransForHWP() { return true; }
     virtual bool FinishTransForHWP() { return true; }
+    
+    uint32_t m_save_id;         // An always incrementing integer ID used with SaveRegisterState/RestoreRegisterState
+
 };
 
 

Modified: lldb/trunk/tools/debugserver/source/DNBLog.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/DNBLog.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/DNBLog.h (original)
+++ lldb/trunk/tools/debugserver/source/DNBLog.h Wed Nov 13 17:28:31 2013
@@ -34,29 +34,27 @@ extern "C" {
 
 #if defined (DNBLOG_ENABLED)
 
-#define DNB_EXPORT __attribute__((visibility("default")))
-
-void        _DNBLog(uint32_t flags, const char *format, ...) __attribute__ ((format (printf, 2, 3))) DNB_EXPORT;
-void        _DNBLogDebug (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT;
-void        _DNBLogDebugVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT;
-void        _DNBLogThreaded (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT;
-void        _DNBLogThreadedIf (uint32_t mask, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) DNB_EXPORT;
-void        _DNBLogError (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT;
-void        _DNBLogFatalError (int err, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) DNB_EXPORT;
-void        _DNBLogVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT;
-void        _DNBLogWarning (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT;
-void        _DNBLogWarningVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) DNB_EXPORT;
-bool        DNBLogCheckLogBit (uint32_t bit) DNB_EXPORT;
-uint32_t    DNBLogSetLogMask (uint32_t mask) DNB_EXPORT;
-uint32_t    DNBLogGetLogMask () DNB_EXPORT;
-void        DNBLogSetLogCallback (DNBCallbackLog callback, void *baton) DNB_EXPORT;
-DNBCallbackLog DNBLogGetLogCallback () DNB_EXPORT;
-bool        DNBLogEnabled () DNB_EXPORT;
-bool        DNBLogEnabledForAny (uint32_t mask) DNB_EXPORT;
-int         DNBLogGetDebug () DNB_EXPORT;
-void        DNBLogSetDebug (int g) DNB_EXPORT;
-int         DNBLogGetVerbose () DNB_EXPORT;
-void        DNBLogSetVerbose (int g) DNB_EXPORT;
+void        _DNBLog(uint32_t flags, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+void        _DNBLogDebug (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void        _DNBLogDebugVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) ;
+void        _DNBLogThreaded (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void        _DNBLogThreadedIf (uint32_t mask, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+void        _DNBLogError (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void        _DNBLogFatalError (int err, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+void        _DNBLogVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void        _DNBLogWarning (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void        _DNBLogWarningVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+bool        DNBLogCheckLogBit (uint32_t bit);
+uint32_t    DNBLogSetLogMask (uint32_t mask);
+uint32_t    DNBLogGetLogMask ();
+void        DNBLogSetLogCallback (DNBCallbackLog callback, void *baton);
+DNBCallbackLog DNBLogGetLogCallback ();
+bool        DNBLogEnabled ();
+bool        DNBLogEnabledForAny (uint32_t mask);
+int         DNBLogGetDebug ();
+void        DNBLogSetDebug (int g);
+int         DNBLogGetVerbose ();
+void        DNBLogSetVerbose (int g);
 
 #define     DNBLog(fmt, ...)                    do { if (DNBLogEnabled()) { _DNBLog(0, fmt, ## __VA_ARGS__);                 } } while (0)
 #define     DNBLogDebug(fmt, ...)               do { if (DNBLogEnabled()) { _DNBLogDebug(fmt, ## __VA_ARGS__);               } } while (0)

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachThread.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachThread.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachThread.cpp Wed Nov 13 17:28:31 2013
@@ -617,6 +617,18 @@ MachThread::SetRegisterContext (const vo
 }
 
 uint32_t
+MachThread::SaveRegisterState ()
+{
+    return m_arch_ap->SaveRegisterState();
+    
+}
+bool
+MachThread::RestoreRegisterState (uint32_t save_id)
+{
+    return m_arch_ap->RestoreRegisterState(save_id);
+}
+
+uint32_t
 MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp)
 {
     if (bp != NULL && bp->IsBreakpoint())

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachThread.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachThread.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachThread.h Wed Nov 13 17:28:31 2013
@@ -92,6 +92,9 @@ public:
     bool            SetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value );
     nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len);
     nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len);
+    uint32_t        SaveRegisterState ();
+    bool            RestoreRegisterState (uint32_t save_id);
+
     void            NotifyBreakpointChanged (const DNBBreakpoint *bp)
                     {
                     }

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.cpp Wed Nov 13 17:28:31 2013
@@ -200,6 +200,25 @@ MachThreadList::SetRegisterContext (nub_
     return 0;
 }
 
+uint32_t
+MachThreadList::SaveRegisterState (nub_thread_t tid)
+{
+    MachThreadSP thread_sp (GetThreadByID (tid));
+    if (thread_sp)
+        return thread_sp->SaveRegisterState ();
+    return 0;
+}
+
+bool
+MachThreadList::RestoreRegisterState (nub_thread_t tid, uint32_t save_id)
+{
+    MachThreadSP thread_sp (GetThreadByID (tid));
+    if (thread_sp)
+        return thread_sp->RestoreRegisterState (save_id);
+    return 0;
+}
+
+
 nub_size_t
 MachThreadList::NumThreads () const
 {

Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachThreadList.h Wed Nov 13 17:28:31 2013
@@ -30,6 +30,8 @@ public:
     bool            SetRegisterValue (nub_thread_t tid, uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value) const;
     nub_size_t      GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len);
     nub_size_t      SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len);
+    uint32_t        SaveRegisterState (nub_thread_t tid);
+    bool            RestoreRegisterState (nub_thread_t tid, uint32_t save_id);
     const char *    GetThreadInfo (nub_thread_t tid) const;
     void            ProcessWillResume (MachProcess *process, const DNBThreadResumeActions &thread_actions);
     uint32_t        ProcessDidStop (MachProcess *process);

Modified: lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp Wed Nov 13 17:28:31 2013
@@ -1805,5 +1805,57 @@ DNBArchMachARM::SetRegisterContext (cons
 }
 
 
+uint32_t
+DNBArchMachARM::SaveRegisterState ()
+{
+    kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
+    DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
+    
+    // Always re-read the registers because above we call thread_abort_safely();
+    bool force = true;
+    
+    if ((kret = GetGPRState(force)) != KERN_SUCCESS)
+    {
+        DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: GPR regs failed to read: %u ", kret);
+    }
+    else if ((kret = GetFPUState(force)) != KERN_SUCCESS)
+    {
+        DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret);
+    }
+    else
+    {
+        const uint32_t save_id = GetNextRegisterStateSaveID ();
+        m_saved_register_states[save_id] = m_state.context;
+        return save_id;
+    }
+    return UINT32_MAX;
+}
+bool
+DNBArchMachARM::RestoreRegisterState (uint32_t save_id)
+{
+    SaveRegiterStates::iterator pos = m_saved_register_states.find(save_id);
+    if (pos != m_saved_register_states.end())
+    {
+        m_state.context.gpr = pos->second.gpr;
+        m_state.context.vfp = pos->second.vfp;
+        kern_return_t kret;
+        bool success = true;
+        if ((kret = SetGPRState()) != KERN_SUCCESS)
+        {
+            DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret);
+            success = false;
+        }
+        else if ((kret = SetFPUState()) != KERN_SUCCESS)
+        {
+            DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret);
+            success = false;
+        }
+        m_saved_register_states.erase(pos);
+        return success;
+    }
+    return false;
+}
+
+
 #endif    // #if defined (__arm__)
 

Modified: lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h Wed Nov 13 17:28:31 2013
@@ -18,6 +18,8 @@
 
 #include "DNBArch.h"
 
+#include <map>
+
 class MachThread;
 
 class DNBArchMachARM : public DNBArchProtocol

Modified: lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp Wed Nov 13 17:28:31 2013
@@ -515,6 +515,10 @@ DNBArchImplI386::GetEXCState(bool force)
 kern_return_t
 DNBArchImplI386::SetGPRState()
 {
+    kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
+    DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
+    
+
     m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), __i386_THREAD_STATE, (thread_state_t)&m_state.context.gpr, e_regSetWordSizeGPR));
     return m_state.GetError(e_regSetGPR, Write);
 }
@@ -1793,6 +1797,60 @@ DNBArchImplI386::SetRegisterContext (con
 }
 
 
+uint32_t
+DNBArchImplI386::SaveRegisterState ()
+{
+    kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
+    DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
+
+    bool force = true;
+    
+    if ((kret = GetGPRState(force)) != KERN_SUCCESS)
+    {
+        DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: GPR regs failed to read: %u ", kret);
+    }
+    else if ((kret = GetFPUState(force)) != KERN_SUCCESS)
+    {
+        DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret);
+    }
+    else
+    {
+        const uint32_t save_id = GetNextRegisterStateSaveID ();
+        m_saved_register_states[save_id] = m_state.context;
+        return save_id;
+    }
+    return 0;
+}
+bool
+DNBArchImplI386::RestoreRegisterState (uint32_t save_id)
+{
+    SaveRegiterStates::iterator pos = m_saved_register_states.find(save_id);
+    if (pos != m_saved_register_states.end())
+    {
+        m_state.context.gpr = pos->second.gpr;
+        m_state.context.fpu = pos->second.fpu;
+        m_state.context.exc = pos->second.exc;
+        m_state.SetError(e_regSetGPR, Read, 0);
+        m_state.SetError(e_regSetFPU, Read, 0);
+        m_state.SetError(e_regSetEXC, Read, 0);
+        kern_return_t kret;
+        bool success = true;
+        if ((kret = SetGPRState()) != KERN_SUCCESS)
+        {
+            DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret);
+            success = false;
+        }
+        else if ((kret = SetFPUState()) != KERN_SUCCESS)
+        {
+            DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret);
+            success = false;
+        }
+        m_saved_register_states.erase(pos);
+        return success;
+    }
+    return false;
+}
+
 
 kern_return_t
 DNBArchImplI386::GetRegisterState(int set, bool force)

Modified: lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h Wed Nov 13 17:28:31 2013
@@ -20,16 +20,20 @@
 #include "../HasAVX.h"
 #include "MachRegisterStatesI386.h"
 
+#include <map>
+
 class MachThread;
 
 class DNBArchImplI386 : public DNBArchProtocol
 {
 public:
     DNBArchImplI386(MachThread *thread) :
+        DNBArchProtocol(),
         m_thread(thread),
         m_state(),
         m_2pc_dbg_checkpoint(),
-        m_2pc_trans_state(Trans_Done)
+        m_2pc_trans_state(Trans_Done),
+        m_saved_register_states()
     {
     }
     virtual ~DNBArchImplI386()
@@ -42,6 +46,9 @@ public:
     virtual bool            SetRegisterValue(int set, int reg, const DNBRegisterValue *value);
     virtual nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len);
     virtual nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len);
+    virtual uint32_t        SaveRegisterState ();
+    virtual bool            RestoreRegisterState (uint32_t save_id);
+
     virtual kern_return_t   GetRegisterState  (int set, bool force);
     virtual kern_return_t   SetRegisterState  (int set);
     virtual bool            RegisterSetStateIsValid (int set) const;
@@ -240,6 +247,8 @@ protected:
     State       m_state;
     DBG         m_2pc_dbg_checkpoint;
     uint32_t    m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)?
+    typedef std::map<uint32_t, Context> SaveRegiterStates;
+    SaveRegiterStates m_saved_register_states;
 };
 
 #endif    // #if defined (__i386__) || defined (__x86_64__)

Modified: lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp Wed Nov 13 17:28:31 2013
@@ -447,7 +447,7 @@ kern_return_t
 DNBArchImplX86_64::SetGPRState()
 {
     kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
-    DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());    
+    DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
 
     m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), __x86_64_THREAD_STATE, (thread_state_t)&m_state.context.gpr, e_regSetWordSizeGPR));
     DNBLogThreadedIf (LOG_THREAD, "::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x"
@@ -2189,6 +2189,59 @@ DNBArchImplX86_64::SetRegisterContext (c
     return size;
 }
 
+uint32_t
+DNBArchImplX86_64::SaveRegisterState ()
+{
+    kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber());
+    DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount());
+
+    // Always re-read the registers because above we call thread_abort_safely();
+    bool force = true;
+    
+    if ((kret = GetGPRState(force)) != KERN_SUCCESS)
+    {
+        DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () error: GPR regs failed to read: %u ", kret);
+    }
+    else if ((kret = GetFPUState(force)) != KERN_SUCCESS)
+    {
+        DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret);
+    }
+    else
+    {
+        const uint32_t save_id = GetNextRegisterStateSaveID ();
+        m_saved_register_states[save_id] = m_state.context;
+        return save_id;
+    }
+    return 0;
+}
+bool
+DNBArchImplX86_64::RestoreRegisterState (uint32_t save_id)
+{
+    SaveRegiterStates::iterator pos = m_saved_register_states.find(save_id);
+    if (pos != m_saved_register_states.end())
+    {
+        m_state.context.gpr = pos->second.gpr;
+        m_state.context.fpu = pos->second.fpu;
+        m_state.SetError(e_regSetGPR, Read, 0);
+        m_state.SetError(e_regSetFPU, Read, 0);
+        kern_return_t kret;
+        bool success = true;
+        if ((kret = SetGPRState()) != KERN_SUCCESS)
+        {
+            DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret);
+            success = false;
+        }
+        else if ((kret = SetFPUState()) != KERN_SUCCESS)
+        {
+            DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret);
+            success = false;
+        }
+        m_saved_register_states.erase(pos);
+        return success;
+    }
+    return false;
+}
+
 
 kern_return_t
 DNBArchImplX86_64::GetRegisterState(int set, bool force)

Modified: lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h Wed Nov 13 17:28:31 2013
@@ -19,16 +19,20 @@
 #include "../HasAVX.h"
 #include "MachRegisterStatesX86_64.h"
 
+#include <map>
+
 class MachThread;
 
 class DNBArchImplX86_64 : public DNBArchProtocol
 {
 public:
     DNBArchImplX86_64(MachThread *thread) :
+        DNBArchProtocol(),
         m_thread(thread),
         m_state(),
         m_2pc_dbg_checkpoint(),
-        m_2pc_trans_state(Trans_Done)
+        m_2pc_trans_state(Trans_Done),
+        m_saved_register_states()
     {
     }
     virtual ~DNBArchImplX86_64()
@@ -36,10 +40,13 @@ public:
     }
 
     static  void            Initialize();
+    
     virtual bool            GetRegisterValue(int set, int reg, DNBRegisterValue *value);
     virtual bool            SetRegisterValue(int set, int reg, const DNBRegisterValue *value);
     virtual nub_size_t      GetRegisterContext (void *buf, nub_size_t buf_len);
     virtual nub_size_t      SetRegisterContext (const void *buf, nub_size_t buf_len);
+    virtual uint32_t        SaveRegisterState ();
+    virtual bool            RestoreRegisterState (uint32_t save_id);
 
     virtual kern_return_t   GetRegisterState  (int set, bool force);
     virtual kern_return_t   SetRegisterState  (int set);
@@ -246,6 +253,8 @@ protected:
     State       m_state;
     DBG         m_2pc_dbg_checkpoint;
     uint32_t    m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)?
+    typedef std::map<uint32_t, Context> SaveRegiterStates;
+    SaveRegiterStates m_saved_register_states;
 };
 
 #endif    // #if defined (__i386__) || defined (__x86_64__)

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Wed Nov 13 17:28:31 2013
@@ -191,6 +191,8 @@ RNBRemote::CreatePacketTable  ()
 //  t.push_back (Packet (pass_signals_to_inferior,      &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify which signals are passed to the inferior"));
     t.push_back (Packet (allocate_memory,               &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process."));
     t.push_back (Packet (deallocate_memory,             &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process."));
+    t.push_back (Packet (save_register_state,           &RNBRemote::HandlePacket_SaveRegisterState, NULL, "QSaveRegisterState", "Save the register state for the current thread and return a decimal save ID."));
+    t.push_back (Packet (restore_register_state,        &RNBRemote::HandlePacket_RestoreRegisterState, NULL, "QRestoreRegisterState:", "Restore the register state given a save ID previosly returned from a call to QSaveRegisterState."));
     t.push_back (Packet (memory_region_info,            &RNBRemote::HandlePacket_MemoryRegionInfo, NULL, "qMemoryRegionInfo", "Return size and attributes of a memory region that contains the given address"));
     t.push_back (Packet (get_profile_data,              &RNBRemote::HandlePacket_GetProfileData, NULL, "qGetProfileData", "Return profiling data of the current target."));
     t.push_back (Packet (set_enable_profiling,          &RNBRemote::HandlePacket_SetEnableAsyncProfiling, NULL, "QSetEnableAsyncProfiling", "Enable or disable the profiling of current target."));
@@ -2730,6 +2732,88 @@ RNBRemote::HandlePacket_DeallocateMemory
     return SendPacket ("E54");
 }
 
+
+// FORMAT: QSaveRegisterState;thread:TTTT;  (when thread suffix is supported)
+// FORMAT: QSaveRegisterState               (when thread suffix is NOT supported)
+//      TTTT: thread ID in hex
+//
+// RESPONSE:
+//      SAVEID: Where SAVEID is a decimal number that represents the save ID
+//              that can be passed back into a "QRestoreRegisterState" packet
+//      EXX: error code
+//
+// EXAMPLES:
+//      QSaveRegisterState;thread:1E34;     (when thread suffix is supported)
+//      QSaveRegisterState                  (when thread suffix is NOT supported)
+
+rnb_err_t
+RNBRemote::HandlePacket_SaveRegisterState (const char *p)
+{
+    nub_process_t pid = m_ctx.ProcessID ();
+    nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p);
+    if (tid == INVALID_NUB_THREAD)
+    {
+        if (m_thread_suffix_supported)
+            return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in QSaveRegisterState packet");
+        else
+            return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread was is set with the Hg packet");
+    }
+    
+    // Get the register context size first by calling with NULL buffer
+    const uint32_t save_id = DNBThreadSaveRegisterState(pid, tid);
+    if (save_id != 0)
+    {
+        char response[64];
+        snprintf (response, sizeof(response), "%u", save_id);
+        return SendPacket (response);
+    }
+    else
+    {
+        return SendPacket ("E75");
+    }
+}
+// FORMAT: QRestoreRegisterState:SAVEID;thread:TTTT;  (when thread suffix is supported)
+// FORMAT: QRestoreRegisterState:SAVEID               (when thread suffix is NOT supported)
+//      TTTT: thread ID in hex
+//      SAVEID: a decimal number that represents the save ID that was
+//              returned from a call to "QSaveRegisterState"
+//
+// RESPONSE:
+//      OK: successfully restored registers for the specified thread
+//      EXX: error code
+//
+// EXAMPLES:
+//      QRestoreRegisterState:1;thread:1E34;     (when thread suffix is supported)
+//      QRestoreRegisterState:1                  (when thread suffix is NOT supported)
+
+rnb_err_t
+RNBRemote::HandlePacket_RestoreRegisterState (const char *p)
+{
+    nub_process_t pid = m_ctx.ProcessID ();
+    nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p);
+    if (tid == INVALID_NUB_THREAD)
+    {
+        if (m_thread_suffix_supported)
+            return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in QSaveRegisterState packet");
+        else
+            return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread was is set with the Hg packet");
+    }
+    
+    StringExtractor packet (p);
+    packet.SetFilePos(strlen("QRestoreRegisterState:")); // Skip the "QRestoreRegisterState:"
+    const uint32_t save_id = packet.GetU32(0);
+                      
+    if (save_id != 0)
+    {
+        // Get the register context size first by calling with NULL buffer
+        if (DNBThreadRestoreRegisterState(pid, tid, save_id))
+            return SendPacket ("OK");
+        else
+            return SendPacket ("E77");
+    }
+    return SendPacket ("E76");
+}
+
 static bool
 GetProcessNameFrom_vAttach (const char *&p, std::string &attach_name)
 {

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.h?rev=194621&r1=194620&r2=194621&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.h (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.h Wed Nov 13 17:28:31 2013
@@ -119,7 +119,9 @@ public:
         watchpoint_support_info,        // 'qWatchpointSupportInfo:'
         allocate_memory,                // '_M'
         deallocate_memory,              // '_m'
-
+        save_register_state,            // '_g'
+        restore_register_state,         // '_G'
+        
         unknown_type
     } PacketEnum;
 
@@ -216,6 +218,8 @@ public:
     rnb_err_t HandlePacket_ILLFORMED (const char *file, int line, const char *p, const char *description);
     rnb_err_t HandlePacket_AllocateMemory (const char *p);
     rnb_err_t HandlePacket_DeallocateMemory (const char *p);
+    rnb_err_t HandlePacket_SaveRegisterState (const char *p);
+    rnb_err_t HandlePacket_RestoreRegisterState (const char *p);
     rnb_err_t HandlePacket_MemoryRegionInfo (const char *p);
     rnb_err_t HandlePacket_GetProfileData(const char *p);
     rnb_err_t HandlePacket_SetEnableAsyncProfiling(const char *p);





More information about the lldb-commits mailing list