[Lldb-commits] [lldb] r212069 - Add lldb-gdbserver support for Linux x86_64.

Todd Fiala todd.fiala at gmail.com
Mon Jun 30 14:05:19 PDT 2014


Author: tfiala
Date: Mon Jun 30 16:05:18 2014
New Revision: 212069

URL: http://llvm.org/viewvc/llvm-project?rev=212069&view=rev
Log:
Add lldb-gdbserver support for Linux x86_64.

This change brings in lldb-gdbserver (llgs) specifically for Linux x86_64.
(More architectures coming soon).

Not every debugserver option is covered yet.  Currently
the lldb-gdbserver command line can start unattached,
start attached to a pid (process-name attach not supported yet),
or accept lldb attaching and launching a process or connecting
by process id.

The history of this large change can be found here:
https://github.com/tfiala/lldb/tree/dev-tfiala-native-protocol-linux-x86_64

Until mid/late April, I was not sharing the work and continued
to rebase it off of head (developed via id tfiala at google.com).  I switched over to
user todd.fiala at gmail.com in the middle, and once I went to github, I did
merges rather than rebasing so I could share with others.

Added:
    lldb/trunk/include/lldb/Target/NativeRegisterContext.h
    lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h
    lldb/trunk/include/lldb/lldb-private-forward.h
    lldb/trunk/source/Host/common/NativeBreakpoint.cpp
    lldb/trunk/source/Host/common/NativeBreakpoint.h
    lldb/trunk/source/Host/common/NativeBreakpointList.cpp
    lldb/trunk/source/Host/common/NativeBreakpointList.h
    lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
    lldb/trunk/source/Host/common/NativeProcessProtocol.h
    lldb/trunk/source/Host/common/NativeThreadProtocol.cpp
    lldb/trunk/source/Host/common/NativeThreadProtocol.h
    lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp
    lldb/trunk/source/Host/common/SoftwareBreakpoint.h
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
    lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
    lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
    lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp
    lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h
    lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp
    lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h
    lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h
    lldb/trunk/source/Target/NativeRegisterContext.cpp
    lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp
Removed:
    lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp
    lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h
Modified:
    lldb/trunk/.gitignore
    lldb/trunk/docs/lldb-gdb-remote.txt
    lldb/trunk/include/lldb/Core/UserID.h
    lldb/trunk/include/lldb/Host/Debug.h
    lldb/trunk/include/lldb/Host/Host.h
    lldb/trunk/include/lldb/Target/MemoryRegionInfo.h
    lldb/trunk/include/lldb/Target/Platform.h
    lldb/trunk/include/lldb/Target/Process.h
    lldb/trunk/include/lldb/lldb-enumerations.h
    lldb/trunk/include/lldb/lldb-private-enumerations.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/Core/ModuleList.cpp
    lldb/trunk/source/Expression/IRMemoryMap.cpp
    lldb/trunk/source/Host/common/CMakeLists.txt
    lldb/trunk/source/Host/linux/Host.cpp
    lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
    lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
    lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp
    lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h
    lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt
    lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
    lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
    lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
    lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h
    lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
    lldb/trunk/source/Target/CMakeLists.txt
    lldb/trunk/source/Target/Platform.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Utility/StringExtractor.cpp
    lldb/trunk/source/Utility/StringExtractor.h
    lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
    lldb/trunk/source/Utility/StringExtractorGDBRemote.h
    lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py
    lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py
    lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py
    lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py
    lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py
    lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py
    lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
    lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
    lldb/trunk/test/tools/lldb-gdbserver/main.cpp
    lldb/trunk/tools/debugserver/source/RNBRemote.cpp
    lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp
    lldb/trunk/tools/lldb-platform/lldb-platform.cpp

Modified: lldb/trunk/.gitignore
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/.gitignore?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/.gitignore (original)
+++ lldb/trunk/.gitignore Mon Jun 30 16:05:18 2014
@@ -25,3 +25,6 @@ build/
 llvm-build/
 *xcuserdata
 test/20*
+
+# We should ignore Xcode-style embedding of llvm/ at lldb root dir.
+/llvm/

Modified: lldb/trunk/docs/lldb-gdb-remote.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/docs/lldb-gdb-remote.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/docs/lldb-gdb-remote.txt (original)
+++ lldb/trunk/docs/lldb-gdb-remote.txt Mon Jun 30 16:05:18 2014
@@ -207,7 +207,7 @@ With LLDB, for register information, rem
 support for the "qRegisterInfoN" packet where "N" is a zero based
 base16 register number that must start at zero and increase by one
 for each register that is supported.  The response is done in typical
-GDB remote fashion where a serious of "KEY:VALUE;" pairs are returned.
+GDB remote fashion where a series of "KEY:VALUE;" pairs are returned.
 An example for the x86_64 registers is included below:
 
 send packet: $qRegisterInfo0#00

Modified: lldb/trunk/include/lldb/Core/UserID.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/UserID.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/UserID.h (original)
+++ lldb/trunk/include/lldb/Core/UserID.h Mon Jun 30 16:05:18 2014
@@ -19,12 +19,12 @@ namespace lldb_private {
 /// @class UserID UserID.h "lldb/Core/UserID.h"
 /// @brief A mix in class that contains a generic user ID.
 ///
-/// UserID is desinged as a mix in class that can contain an integer
-/// based unique identifier for a varietly of objects in lldb.
+/// UserID is designed as a mix in class that can contain an integer
+/// based unique identifier for a variety of objects in lldb.
 ///
 /// The value for this identifier is chosen by each parser plug-in. A
 /// value should be chosen that makes sense for each kind of object
-/// should and allows quick access to further and more in depth parsing.
+/// and should allow quick access to further and more in depth parsing.
 ///
 /// Symbol table entries can use this to store the original symbol table
 /// index, functions can use it to store the symbol table index or the

Modified: lldb/trunk/include/lldb/Host/Debug.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Debug.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Debug.h (original)
+++ lldb/trunk/include/lldb/Host/Debug.h Mon Jun 30 16:05:18 2014
@@ -10,14 +10,11 @@
 #ifndef liblldb_Debug_h_
 #define liblldb_Debug_h_
 
-#include "lldb/lldb-private.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Core/StreamString.h"
-#include "lldb/Host/Mutex.h"
 #include <vector>
+#include "lldb/lldb-private.h"
 
 namespace lldb_private {
-    
+
     //------------------------------------------------------------------
     // Tells a thread what it needs to do when the process is resumed.
     //------------------------------------------------------------------
@@ -27,7 +24,7 @@ namespace lldb_private {
         lldb::StateType state;  // Valid values are eStateStopped/eStateSuspended, eStateRunning, and eStateStepping.
         int signal;             // When resuming this thread, resume it with this signal if this value is > 0
     };
-    
+
     //------------------------------------------------------------------
     // A class that contains instructions for all threads for
     // NativeProcessProtocol::Resume(). Each thread can either run, stay
@@ -43,15 +40,14 @@ namespace lldb_private {
             m_signal_handled ()
         {
         }
-        
+
         ResumeActionList (lldb::StateType default_action, int signal) :
             m_actions(),
             m_signal_handled ()
         {
             SetDefaultThreadActionIfNeeded (default_action, signal);
         }
-        
-        
+
         ResumeActionList (const ResumeAction *actions, size_t num_actions) :
             m_actions (),
             m_signal_handled ()
@@ -62,7 +58,7 @@ namespace lldb_private {
                 m_signal_handled.assign (num_actions, false);
             }
         }
-        
+
         ~ResumeActionList()
         {
         }
@@ -72,14 +68,14 @@ namespace lldb_private {
         {
             return m_actions.empty();
         }
-        
+
         void
         Append (const ResumeAction &action)
         {
             m_actions.push_back (action);
             m_signal_handled.push_back (false);
         }
-        
+
         void
         AppendAction (lldb::tid_t tid,
                       lldb::StateType state,
@@ -88,25 +84,25 @@ namespace lldb_private {
             ResumeAction action = { tid, state, signal };
             Append (action);
         }
-        
+
         void
         AppendResumeAll ()
         {
             AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateRunning);
         }
-        
+
         void
         AppendSuspendAll ()
         {
             AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStopped);
         }
-        
+
         void
         AppendStepAll ()
         {
             AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStepping);
         }
-        
+
         const ResumeAction *
         GetActionForThread (lldb::tid_t tid, bool default_ok) const
         {
@@ -120,7 +116,7 @@ namespace lldb_private {
                 return GetActionForThread (LLDB_INVALID_THREAD_ID, false);
             return NULL;
         }
-        
+
         size_t
         NumActionsWithState (lldb::StateType state) const
         {
@@ -133,7 +129,7 @@ namespace lldb_private {
             }
             return count;
         }
-        
+
         bool
         SetDefaultThreadActionIfNeeded (lldb::StateType action, int signal)
         {
@@ -147,7 +143,7 @@ namespace lldb_private {
             }
             return false;
         }
-        
+
         void
         SetSignalHandledForThread (lldb::tid_t tid) const
         {
@@ -161,26 +157,26 @@ namespace lldb_private {
                 }
             }
         }
-        
+
         const ResumeAction *
         GetFirst() const
         {
             return m_actions.data();
         }
-        
+
         size_t
         GetSize () const
         {
             return m_actions.size();
         }
-        
+
         void
         Clear()
         {
             m_actions.clear();
             m_signal_handled.clear();
         }
-        
+
     protected:
         std::vector<ResumeAction> m_actions;
         mutable std::vector<bool> m_signal_handled;
@@ -191,13 +187,13 @@ namespace lldb_private {
         lldb::StopReason reason;
         union
         {
-            // eStopTypeSignal
+            // eStopReasonSignal
             struct
             {
                 uint32_t signo;
             } signal;
-            
-            // eStopTypeException
+
+            // eStopReasonException
             struct
             {
                 uint64_t type;
@@ -206,201 +202,5 @@ namespace lldb_private {
             } exception;
         } details;
     };
-
-    //------------------------------------------------------------------
-    // NativeThreadProtocol
-    //------------------------------------------------------------------
-    class NativeThreadProtocol {
-        
-    public:
-        NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) :
-            m_process (process),
-            m_tid (tid)
-        {
-        }
-        
-        virtual ~NativeThreadProtocol()
-        {
-        }
-        virtual const char *GetName() = 0;
-        virtual lldb::StateType GetState () = 0;
-        virtual Error ReadRegister (uint32_t reg, RegisterValue &reg_value) = 0;
-        virtual Error WriteRegister (uint32_t reg, const RegisterValue &reg_value) = 0;
-        virtual Error SaveAllRegisters (lldb::DataBufferSP &data_sp) = 0;
-        virtual Error RestoreAllRegisters (lldb::DataBufferSP &data_sp) = 0;
-        virtual bool GetStopReason (ThreadStopInfo &stop_info) = 0;
-        
-        lldb::tid_t
-        GetID() const
-        {
-            return m_tid;
-        }
-    protected:
-        NativeProcessProtocol *m_process;
-        lldb::tid_t m_tid;
-    };
-
-    
-    //------------------------------------------------------------------
-    // NativeProcessProtocol
-    //------------------------------------------------------------------
-    class NativeProcessProtocol {
-    public:
-        
-        static NativeProcessProtocol *
-        CreateInstance (lldb::pid_t pid);
-
-        // lldb_private::Host calls should be used to launch a process for debugging, and
-        // then the process should be attached to. When attaching to a process
-        // lldb_private::Host calls should be used to locate the process to attach to,
-        // and then this function should be called.
-        NativeProcessProtocol (lldb::pid_t pid) :
-            m_pid (pid),
-            m_threads(),
-            m_threads_mutex (Mutex::eMutexTypeRecursive),
-            m_state (lldb::eStateInvalid),
-            m_exit_status(0),
-            m_exit_description()
-        {
-        }
-
-    public:
-        virtual ~NativeProcessProtocol ()
-        {
-        }
-        
-        virtual Error Resume (const ResumeActionList &resume_actions) = 0;
-        virtual Error Halt () = 0;
-        virtual Error Detach () = 0;
-        virtual Error Signal (int signo) = 0;
-        virtual Error Kill () = 0;
-        
-        virtual Error ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0;
-        virtual Error WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
-        virtual Error AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
-        virtual Error DeallocateMemory (lldb::addr_t addr) = 0;
-        
-        virtual lldb::addr_t GetSharedLibraryInfoAddress () = 0;
-        
-        virtual bool IsAlive () = 0;
-        virtual size_t UpdateThreads () = 0;
-        virtual bool GetArchitecture (ArchSpec &arch) = 0;
-
-        //----------------------------------------------------------------------
-        // Breakpoint functions
-        //----------------------------------------------------------------------
-        virtual Error SetBreakpoint (lldb::addr_t addr, size_t size, bool hardware) = 0;
-        virtual Error RemoveBreakpoint (lldb::addr_t addr, size_t size) = 0;
-        
-        //----------------------------------------------------------------------
-        // Watchpoint functions
-        //----------------------------------------------------------------------
-        virtual uint32_t GetMaxWatchpoints () = 0;
-        virtual Error SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0;
-        virtual Error RemoveWatchpoint (lldb::addr_t addr) = 0;
-        
-        
-        //----------------------------------------------------------------------
-        // Accessors
-        //----------------------------------------------------------------------
-        lldb::pid_t
-        GetID() const
-        {
-            return m_pid;
-        }
-        
-        lldb::StateType
-        GetState () const
-        {
-            return m_state;
-        }
-        
-        bool
-        IsRunning () const
-        {
-            return m_state == lldb::eStateRunning || IsStepping();
-        }
-        
-        bool
-        IsStepping () const
-        {
-            return m_state == lldb::eStateStepping;
-        }
-        
-        bool
-        CanResume () const
-        {
-            return m_state == lldb::eStateStopped;
-        }
-
-        
-        void
-        SetState (lldb::StateType state)
-        {
-            m_state = state;
-        }
-
-        //----------------------------------------------------------------------
-        // Exit Status
-        //----------------------------------------------------------------------
-        virtual bool
-        GetExitStatus (int *status)
-        {
-            if (m_state == lldb::eStateExited)
-            {
-                *status = m_exit_status;
-                return true;
-            }
-            *status = 0;
-            return false;
-        }
-        virtual bool
-        SetExitStatus (int status, const char *exit_description)
-        {
-            // Exit status already set
-            if (m_state == lldb::eStateExited)
-                return false;
-            m_state = lldb::eStateExited;
-            m_exit_status = status;
-            if (exit_description && exit_description[0])
-                m_exit_description = exit_description;
-            else
-                m_exit_description.clear();
-            return true;
-        }
-
-        //----------------------------------------------------------------------
-        // Access to threads
-        //----------------------------------------------------------------------
-        lldb::NativeThreadProtocolSP
-        GetThreadAtIndex (uint32_t idx)
-        {
-            Mutex::Locker locker(m_threads_mutex);
-            if (idx < m_threads.size())
-                return m_threads[idx];
-            return lldb::NativeThreadProtocolSP();
-        }
-
-        lldb::NativeThreadProtocolSP
-        GetThreadByID (lldb::tid_t tid)
-        {
-            Mutex::Locker locker(m_threads_mutex);
-            for (auto thread_sp : m_threads)
-            {
-                if (thread_sp->GetID() == tid)
-                    return thread_sp;
-            }
-            return lldb::NativeThreadProtocolSP();
-        }
-
-    protected:
-        lldb::pid_t m_pid;
-        std::vector<lldb::NativeThreadProtocolSP> m_threads;
-        mutable Mutex m_threads_mutex;
-        lldb::StateType m_state;
-        int m_exit_status;
-        std::string m_exit_description;
-    };
-
 }
 #endif // #ifndef liblldb_Debug_h_

Modified: lldb/trunk/include/lldb/Host/Host.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Host.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Host.h (original)
+++ lldb/trunk/include/lldb/Host/Host.h Mon Jun 30 16:05:18 2014
@@ -503,6 +503,9 @@ public:
     static lldb::DataBufferSP
     GetAuxvData (lldb_private::Process *process);
 
+    static lldb::DataBufferSP
+    GetAuxvData (lldb::pid_t pid);
+
     static lldb::TargetSP
     GetDummyTarget (Debugger &debugger);
     

Modified: lldb/trunk/include/lldb/Target/MemoryRegionInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/MemoryRegionInfo.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/MemoryRegionInfo.h (original)
+++ lldb/trunk/include/lldb/Target/MemoryRegionInfo.h Mon Jun 30 16:05:18 2014
@@ -10,6 +10,7 @@
 #ifndef lldb_MemoryRegionInfo_h
 #define lldb_MemoryRegionInfo_h
 
+#include "lldb/Core/RangeMap.h"
 #include "lldb/Utility/Range.h"
 
 namespace lldb_private

Added: lldb/trunk/include/lldb/Target/NativeRegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/NativeRegisterContext.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/NativeRegisterContext.h (added)
+++ lldb/trunk/include/lldb/Target/NativeRegisterContext.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,190 @@
+//===-- NativeRegisterContext.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_NativeRegisterContext_h_
+#define liblldb_NativeRegisterContext_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class NativeThreadProtocol;
+
+class NativeRegisterContext:
+    public std::enable_shared_from_this<NativeRegisterContext>
+{
+public:
+    //------------------------------------------------------------------
+    // Constructors and Destructors
+    //------------------------------------------------------------------
+    NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx);
+
+    virtual
+    ~NativeRegisterContext ();
+
+    // void
+    // InvalidateIfNeeded (bool force);
+
+    //------------------------------------------------------------------
+    // Subclasses must override these functions
+    //------------------------------------------------------------------
+    // virtual void
+    // InvalidateAllRegisters () = 0;
+
+    virtual uint32_t
+    GetRegisterCount () const = 0;
+
+    virtual const RegisterInfo *
+    GetRegisterInfoAtIndex (uint32_t reg) const = 0;
+
+    const char *
+    GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const;
+
+    virtual uint32_t
+    GetRegisterSetCount () const = 0;
+
+    virtual const RegisterSet *
+    GetRegisterSet (uint32_t set_index) const = 0;
+
+    virtual Error
+    ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) = 0;
+
+    virtual Error
+    WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) = 0;
+
+    virtual Error
+    ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0;
+
+    virtual Error
+    WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0;
+
+    uint32_t
+    ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+    //------------------------------------------------------------------
+    // Subclasses can override these functions if desired
+    //------------------------------------------------------------------
+    virtual uint32_t
+    NumSupportedHardwareBreakpoints ();
+
+    virtual uint32_t
+    SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+    virtual bool
+    ClearHardwareBreakpoint (uint32_t hw_idx);
+
+    virtual uint32_t
+    NumSupportedHardwareWatchpoints ();
+
+    virtual uint32_t
+    SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags);
+
+    virtual bool
+    ClearHardwareWatchpoint (uint32_t hw_index);
+
+    virtual bool
+    HardwareSingleStep (bool enable);
+
+    virtual Error
+    ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, lldb::addr_t src_len, RegisterValue &reg_value);
+
+    virtual Error
+    WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, lldb::addr_t dst_len, const RegisterValue &reg_value);
+
+    //------------------------------------------------------------------
+    // Subclasses should not override these
+    //------------------------------------------------------------------
+    virtual lldb::tid_t
+    GetThreadID() const;
+
+    virtual NativeThreadProtocol &
+    GetThread ()
+    {
+        return m_thread;
+    }
+
+    const RegisterInfo *
+    GetRegisterInfoByName (const char *reg_name, uint32_t start_idx = 0);
+
+    const RegisterInfo *
+    GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num);
+
+    lldb::addr_t
+    GetPC (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+    Error
+    SetPC (lldb::addr_t pc);
+
+    lldb::addr_t
+    GetSP (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+    Error
+    SetSP (lldb::addr_t sp);
+
+    lldb::addr_t
+    GetFP (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+    Error
+    SetFP (lldb::addr_t fp);
+
+    const char *
+    GetRegisterName (uint32_t reg);
+
+    lldb::addr_t
+    GetReturnAddress (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS);
+
+    lldb::addr_t
+    GetFlags (lldb::addr_t fail_value = 0);
+
+    lldb::addr_t
+    ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value);
+
+    lldb::addr_t
+    ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value);
+
+    Error
+    WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval);
+
+    Error
+    WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval);
+
+    // uint32_t
+    // GetStopID () const
+    // {
+    //     return m_stop_id;
+    // }
+
+    // void
+    // SetStopID (uint32_t stop_id)
+    // {
+    //     m_stop_id = stop_id;
+    // }
+
+protected:
+    //------------------------------------------------------------------
+    // Classes that inherit from RegisterContext can see and modify these
+    //------------------------------------------------------------------
+    NativeThreadProtocol &m_thread; // The thread that this register context belongs to.
+    uint32_t m_concrete_frame_idx;  // The concrete frame index for this register context
+    // uint32_t m_stop_id;             // The stop ID that any data in this context is valid for
+
+private:
+    //------------------------------------------------------------------
+    // For RegisterContext only
+    //------------------------------------------------------------------
+    DISALLOW_COPY_AND_ASSIGN (NativeRegisterContext);
+};
+
+} // namespace lldb_private
+
+#endif  // liblldb_NativeRegisterContext_h_

Added: lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h (added)
+++ lldb/trunk/include/lldb/Target/NativeRegisterContextRegisterInfo.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContextRegisterInfo.h ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextRegisterInfo_h
+#define lldb_NativeRegisterContextRegisterInfo_h
+
+#include <memory>
+
+#include "NativeRegisterContext.h"
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+
+namespace lldb_private
+{
+    class NativeRegisterContextRegisterInfo: public NativeRegisterContext
+    {
+    public:
+        ///
+        /// Construct a NativeRegisterContextRegisterInfo, taking ownership
+        /// of the register_info_interface pointer.
+        ///
+        NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+                                           uint32_t concrete_frame_idx,
+                                           RegisterInfoInterface *register_info_interface);
+
+        uint32_t
+        GetRegisterCount () const override;
+
+        const RegisterInfo *
+        GetRegisterInfoAtIndex (uint32_t reg_index) const override;
+
+        const RegisterInfoInterface&
+        GetRegisterInfoInterface () const;
+
+    private:
+        std::unique_ptr<RegisterInfoInterface> m_register_info_interface_up;
+    };
+}
+#endif

Modified: lldb/trunk/include/lldb/Target/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Platform.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Platform.h (original)
+++ lldb/trunk/include/lldb/Target/Platform.h Mon Jun 30 16:05:18 2014
@@ -18,6 +18,7 @@
 
 // Other libraries and framework includes
 // Project includes
+#include "lldb/lldb-private-forward.h"
 #include "lldb/lldb-public.h"
 #include "lldb/Core/ArchSpec.h"
 #include "lldb/Core/ConstString.h"
@@ -25,6 +26,10 @@
 #include "lldb/Interpreter/Options.h"
 #include "lldb/Host/Mutex.h"
 
+// TODO pull NativeDelegate class out of NativeProcessProtocol so we
+// can just forward ref the NativeDelegate rather than include it here.
+#include "../../../source/Host/common/NativeProcessProtocol.h"
+
 namespace lldb_private {
 
     //----------------------------------------------------------------------
@@ -858,6 +863,65 @@ namespace lldb_private {
         virtual const std::vector<ConstString> &
         GetTrapHandlerSymbolNames ();
 
+        //------------------------------------------------------------------
+        /// Launch a process for debugging.
+        ///
+        /// This differs from Launch in that it returns a NativeProcessProtocol.
+        /// Currently used by lldb-gdbserver.
+        ///
+        /// @param[in] launch_info
+        ///     Information required to launch the process.
+        ///
+        /// @param[in] native_delegate
+        ///     The delegate that will receive messages regarding the
+        ///     inferior.  Must outlive the NativeProcessProtocol
+        ///     instance.
+        ///
+        /// @param[out] process_sp
+        ///     On successful return from the method, this parameter
+        ///     contains the shared pointer to the
+        ///     NativeProcessProtocol that can be used to manipulate
+        ///     the native process.
+        ///
+        /// @return
+        ///     An error object indicating if the operation succeeded,
+        ///     and if not, what error occurred.
+        //------------------------------------------------------------------
+        virtual Error
+        LaunchNativeProcess (
+            ProcessLaunchInfo &launch_info,
+            lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+            NativeProcessProtocolSP &process_sp);
+
+        //------------------------------------------------------------------
+        /// Attach to an existing process on the given platform.
+        ///
+        /// This method differs from Attach() in that it returns a
+        /// NativeProcessProtocol.  Currently this is used by lldb-gdbserver.
+        ///
+        /// @param[in] pid
+        ///     pid of the process locatable by the platform.
+        ///
+        /// @param[in] native_delegate
+        ///     The delegate that will receive messages regarding the
+        ///     inferior.  Must outlive the NativeProcessProtocol
+        ///     instance.
+        ///
+        /// @param[out] process_sp
+        ///     On successful return from the method, this parameter
+        ///     contains the shared pointer to the
+        ///     NativeProcessProtocol that can be used to manipulate
+        ///     the native process.
+        ///
+        /// @return
+        ///     An error object indicating if the operation succeeded,
+        ///     and if not, what error occurred.
+        //------------------------------------------------------------------
+        virtual Error
+        AttachNativeProcess (lldb::pid_t pid,
+                             lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+                             NativeProcessProtocolSP &process_sp);
+
     protected:
         bool m_is_host;
         // Set to true when we are able to actually set the OS version while 

Modified: lldb/trunk/include/lldb/Target/Process.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Process.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Process.h (original)
+++ lldb/trunk/include/lldb/Target/Process.h Mon Jun 30 16:05:18 2014
@@ -1097,6 +1097,17 @@ public:
     virtual DynamicLoader *
     GetDynamicLoader ();
 
+    //------------------------------------------------------------------
+    // Returns AUXV structure found in many ELF-based environments.
+    //
+    // The default action is to return an empty data buffer.
+    //
+    // @return
+    //    A data buffer containing the contents of the AUXV data.
+    //------------------------------------------------------------------
+    virtual const lldb::DataBufferSP
+    GetAuxvData();
+
 protected:
     virtual JITLoaderList &
     GetJITLoaders ();

Modified: lldb/trunk/include/lldb/lldb-enumerations.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-enumerations.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-enumerations.h (original)
+++ lldb/trunk/include/lldb/lldb-enumerations.h Mon Jun 30 16:05:18 2014
@@ -788,6 +788,27 @@ namespace lldb {
     } ExpressionEvaluationPhase;
     
 
+    //----------------------------------------------------------------------
+    // Watchpoint Kind
+    // Indicates what types of events cause the watchpoint to fire.
+    // Used by Native*Protocol-related classes.
+    //----------------------------------------------------------------------
+    typedef enum WatchpointKind
+    {
+        eWatchpointKindRead = (1u << 0),
+        eWatchpointKindWrite = (1u << 1)
+    } WatchpointKind;
+
+    typedef enum GdbSignal
+    {
+        eGdbSignalBadAccess      = 0x91,
+        eGdbSignalBadInstruction = 0x92,
+        eGdbSignalArithmetic     = 0x93,
+        eGdbSignalEmulation      = 0x94,
+        eGdbSignalSoftware       = 0x95,
+        eGdbSignalBreakpoint     = 0x96
+    } GdbRemoteSignal;
+
 } // namespace lldb
 
 

Modified: lldb/trunk/include/lldb/lldb-private-enumerations.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-enumerations.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-enumerations.h (original)
+++ lldb/trunk/include/lldb/lldb-private-enumerations.h Mon Jun 30 16:05:18 2014
@@ -246,6 +246,16 @@ enum class LineStatus {
     Done        // Lines are complete
 };
 
+//----------------------------------------------------------------------
+// Exit Type for inferior processes
+//----------------------------------------------------------------------
+typedef enum ExitType {
+    eExitTypeInvalid,
+    eExitTypeExit,    // The exit status represents the return code from normal program exit (i.e. WIFEXITED() was true)
+    eExitTypeSignal,  // The exit status represents the signal number that caused the program to exit (i.e. WIFSIGNALED() was true)
+    eExitTypeStop,    // The exit status represents the stop signal that caused the program to exit (i.e. WIFSTOPPED() was true)
+} ExitType;
+
 } // namespace lldb_private
 
 

Added: lldb/trunk/include/lldb/lldb-private-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-forward.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-forward.h (added)
+++ lldb/trunk/include/lldb/lldb-private-forward.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,39 @@
+//===-- lldb-private-forward.h ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_private_forward_h_
+#define LLDB_lldb_private_forward_h_
+
+#if defined(__cplusplus)
+
+#include <memory>
+
+namespace lldb_private
+{
+    // ---------------------------------------------------------------
+    // Class forward decls.
+    // ---------------------------------------------------------------
+    class NativeBreakpoint;
+    class NativeBreakpointList;
+    class NativeProcessProtocol;
+    class NativeRegisterContext;
+    class NativeThreadProtocol;
+
+    // ---------------------------------------------------------------
+    // SP/WP decls.
+    // ---------------------------------------------------------------
+    typedef std::shared_ptr<NativeBreakpoint> NativeBreakpointSP;
+    typedef std::shared_ptr<lldb_private::NativeProcessProtocol> NativeProcessProtocolSP;
+    typedef std::weak_ptr<lldb_private::NativeProcessProtocol> NativeProcessProtocolWP;
+    typedef std::shared_ptr<lldb_private::NativeRegisterContext> NativeRegisterContextSP;
+    typedef std::shared_ptr<lldb_private::NativeThreadProtocol> NativeThreadProtocolSP;
+}
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef LLDB_lldb_private_forward_h_

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Jun 30 16:05:18 2014
@@ -51,20 +51,33 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+		23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23059A0519532B96007B8189 /* LinuxSignals.cpp */; };
 		23059A101958B319007B8189 /* SBUnixSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23059A0F1958B319007B8189 /* SBUnixSignals.cpp */; };
 		23059A121958B3B2007B8189 /* SBUnixSignals.h in Headers */ = {isa = PBXBuildFile; fileRef = 23059A111958B37B007B8189 /* SBUnixSignals.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		232CB615191E00CD00EF39FC /* NativeBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */; };
+		232CB616191E00CD00EF39FC /* NativeBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */; };
+		232CB617191E00CD00EF39FC /* NativeBreakpointList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */; };
+		232CB618191E00CD00EF39FC /* NativeBreakpointList.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */; };
+		232CB619191E00CD00EF39FC /* NativeProcessProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */; };
+		232CB61A191E00CD00EF39FC /* NativeProcessProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */; };
+		232CB61B191E00CD00EF39FC /* NativeThreadProtocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */; };
+		232CB61C191E00CD00EF39FC /* NativeThreadProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */; };
+		232CB61D191E00CD00EF39FC /* SoftwareBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */; };
+		232CB61E191E00CD00EF39FC /* SoftwareBreakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */; };
 		233B007D1960C9F90090E598 /* ProcessInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B007B1960C9E60090E598 /* ProcessInfo.cpp */; };
 		233B007F1960CB280090E598 /* ProcessLaunchInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B007E1960CB280090E598 /* ProcessLaunchInfo.cpp */; };
-		233B009419610B1F0090E598 /* LinuxSignals.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008C19610B1F0090E598 /* LinuxSignals.cpp */; };
-		233B009519610B1F0090E598 /* LinuxSignals.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008D19610B1F0090E598 /* LinuxSignals.h */; };
 		233B009619610B1F0090E598 /* LinuxThread.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008E19610B1F0090E598 /* LinuxThread.cpp */; };
 		233B009719610B1F0090E598 /* LinuxThread.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B008F19610B1F0090E598 /* LinuxThread.h */; };
 		233B009819610B1F0090E598 /* ProcessLinux.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009019610B1F0090E598 /* ProcessLinux.cpp */; };
 		233B009919610B1F0090E598 /* ProcessLinux.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009119610B1F0090E598 /* ProcessLinux.h */; };
 		233B009A19610B1F0090E598 /* ProcessMonitor.cpp in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009219610B1F0090E598 /* ProcessMonitor.cpp */; };
 		233B009B19610B1F0090E598 /* ProcessMonitor.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 233B009319610B1F0090E598 /* ProcessMonitor.h */; };
+		239F5B2F19296DC500083917 /* NativeRegisterContextLinux_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 239F5B2E19296DC500083917 /* NativeRegisterContextLinux_x86_64.h */; };
+		23EDE3321926843600F6A132 /* NativeRegisterContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 23EDE3311926843600F6A132 /* NativeRegisterContext.h */; };
+		23EDE33319269E7C00F6A132 /* NativeRegisterContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23EDE3301926839700F6A132 /* NativeRegisterContext.cpp */; };
 		23EFE389193D1ABC00E54E54 /* SBTypeEnumMember.h in Headers */ = {isa = PBXBuildFile; fileRef = 23EFE388193D1ABC00E54E54 /* SBTypeEnumMember.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		23EFE38B193D1AEC00E54E54 /* SBTypeEnumMember.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23EFE38A193D1AEC00E54E54 /* SBTypeEnumMember.cpp */; };
+		23F4034D1926E0F60046DC9B /* NativeRegisterContextRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23F403481926CC250046DC9B /* NativeRegisterContextRegisterInfo.cpp */; };
 		260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; };
 		260157C71885F52500F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; };
 		260157C81885F53100F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; };
@@ -692,7 +705,6 @@
 		AF1F7B07189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF1F7B05189C904B0087DB9C /* AppleGetPendingItemsHandler.cpp */; };
 		AF1F7B08189C904B0087DB9C /* AppleGetPendingItemsHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1F7B06189C904B0087DB9C /* AppleGetPendingItemsHandler.h */; };
 		AF23B4DB19009C66003E2A58 /* FreeBSDSignals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF23B4D919009C66003E2A58 /* FreeBSDSignals.cpp */; };
-		AF23B4DC19009C66003E2A58 /* FreeBSDSignals.h in Headers */ = {isa = PBXBuildFile; fileRef = AF23B4DA19009C66003E2A58 /* FreeBSDSignals.h */; };
 		AF254E31170CCC33007AE5C9 /* PlatformDarwinKernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF254E2F170CCC33007AE5C9 /* PlatformDarwinKernel.cpp */; };
 		AF254E32170CCC33007AE5C9 /* PlatformDarwinKernel.h in Headers */ = {isa = PBXBuildFile; fileRef = AF254E30170CCC33007AE5C9 /* PlatformDarwinKernel.h */; };
 		AF25AB26188F685C0030DEC3 /* AppleGetQueuesHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF25AB24188F685C0030DEC3 /* AppleGetQueuesHandler.cpp */; };
@@ -861,14 +873,13 @@
 			dstPath = "$(DEVELOPER_DIR)/usr/share/man/man1/";
 			dstSubfolderSpec = 0;
 			files = (
+				23EDE3321926843600F6A132 /* NativeRegisterContext.h in CopyFiles */,
 				233B009819610B1F0090E598 /* ProcessLinux.cpp in CopyFiles */,
 				233B009619610B1F0090E598 /* LinuxThread.cpp in CopyFiles */,
 				233B009A19610B1F0090E598 /* ProcessMonitor.cpp in CopyFiles */,
 				233B009719610B1F0090E598 /* LinuxThread.h in CopyFiles */,
 				233B009919610B1F0090E598 /* ProcessLinux.h in CopyFiles */,
 				233B009B19610B1F0090E598 /* ProcessMonitor.h in CopyFiles */,
-				233B009419610B1F0090E598 /* LinuxSignals.cpp in CopyFiles */,
-				233B009519610B1F0090E598 /* LinuxSignals.h in CopyFiles */,
 				AF90106515AB7D3600FF120D /* lldb.1 in CopyFiles */,
 			);
 			runOnlyForDeploymentPostprocessing = 1;
@@ -891,14 +902,29 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		23059A0519532B96007B8189 /* LinuxSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LinuxSignals.cpp; path = Utility/LinuxSignals.cpp; sourceTree = "<group>"; };
+		23059A0619532B96007B8189 /* LinuxSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LinuxSignals.h; path = Utility/LinuxSignals.h; sourceTree = "<group>"; };
 		23059A0F1958B319007B8189 /* SBUnixSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBUnixSignals.cpp; path = source/API/SBUnixSignals.cpp; sourceTree = "<group>"; };
 		23059A111958B37B007B8189 /* SBUnixSignals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBUnixSignals.h; path = include/lldb/API/SBUnixSignals.h; sourceTree = "<group>"; };
+		23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "lldb-x86-register-enums.h"; path = "Utility/lldb-x86-register-enums.h"; sourceTree = "<group>"; };
+		232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeBreakpoint.cpp; path = source/Host/common/NativeBreakpoint.cpp; sourceTree = "<group>"; };
+		232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeBreakpoint.h; path = source/Host/common/NativeBreakpoint.h; sourceTree = "<group>"; };
+		232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeBreakpointList.cpp; path = source/Host/common/NativeBreakpointList.cpp; sourceTree = "<group>"; };
+		232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeBreakpointList.h; path = source/Host/common/NativeBreakpointList.h; sourceTree = "<group>"; };
+		232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = NativeProcessProtocol.cpp; path = source/Host/common/NativeProcessProtocol.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+		232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeProcessProtocol.h; path = source/Host/common/NativeProcessProtocol.h; sourceTree = "<group>"; };
+		232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeThreadProtocol.cpp; path = source/Host/common/NativeThreadProtocol.cpp; sourceTree = "<group>"; };
+		232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeThreadProtocol.h; path = source/Host/common/NativeThreadProtocol.h; sourceTree = "<group>"; };
+		232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SoftwareBreakpoint.cpp; path = source/Host/common/SoftwareBreakpoint.cpp; sourceTree = "<group>"; };
+		232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SoftwareBreakpoint.h; path = source/Host/common/SoftwareBreakpoint.h; sourceTree = "<group>"; };
+		232CB62B19213AC200EF39FC /* NativeProcessLinux.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeProcessLinux.cpp; sourceTree = "<group>"; };
+		232CB62C19213AC200EF39FC /* NativeProcessLinux.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; path = NativeProcessLinux.h; sourceTree = "<group>"; };
+		232CB62D19213AC200EF39FC /* NativeThreadLinux.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeThreadLinux.cpp; sourceTree = "<group>"; };
+		232CB62E19213AC200EF39FC /* NativeThreadLinux.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativeThreadLinux.h; sourceTree = "<group>"; };
 		233B007919609DB40090E598 /* ProcessLaunchInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ProcessLaunchInfo.h; path = include/lldb/Target/ProcessLaunchInfo.h; sourceTree = "<group>"; };
 		233B007A1960A0440090E598 /* ProcessInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ProcessInfo.h; path = include/lldb/Target/ProcessInfo.h; sourceTree = "<group>"; };
 		233B007B1960C9E60090E598 /* ProcessInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessInfo.cpp; path = source/Target/ProcessInfo.cpp; sourceTree = "<group>"; };
 		233B007E1960CB280090E598 /* ProcessLaunchInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessLaunchInfo.cpp; path = source/Target/ProcessLaunchInfo.cpp; sourceTree = "<group>"; };
-		233B008C19610B1F0090E598 /* LinuxSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinuxSignals.cpp; sourceTree = "<group>"; };
-		233B008D19610B1F0090E598 /* LinuxSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinuxSignals.h; sourceTree = "<group>"; };
 		233B008E19610B1F0090E598 /* LinuxThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LinuxThread.cpp; sourceTree = "<group>"; };
 		233B008F19610B1F0090E598 /* LinuxThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinuxThread.h; sourceTree = "<group>"; };
 		233B009019610B1F0090E598 /* ProcessLinux.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProcessLinux.cpp; sourceTree = "<group>"; };
@@ -909,9 +935,15 @@
 		233B00A1196113730090E598 /* ProcFileReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ProcFileReader.cpp; sourceTree = "<group>"; };
 		233B00A2196113730090E598 /* ProcFileReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProcFileReader.h; sourceTree = "<group>"; };
 		2360092C193FB21500189DB1 /* MemoryRegionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MemoryRegionInfo.h; path = include/lldb/Target/MemoryRegionInfo.h; sourceTree = "<group>"; };
+		239F5B2E19296DC500083917 /* NativeRegisterContextLinux_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContextLinux_x86_64.h; path = Utility/NativeRegisterContextLinux_x86_64.h; sourceTree = "<group>"; };
+		239F5B3019298D4600083917 /* NativeRegisterContextLinux_x86_64.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContextLinux_x86_64.cpp; path = Utility/NativeRegisterContextLinux_x86_64.cpp; sourceTree = "<group>"; };
+		23EDE3301926839700F6A132 /* NativeRegisterContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContext.cpp; path = source/Target/NativeRegisterContext.cpp; sourceTree = "<group>"; };
+		23EDE3311926843600F6A132 /* NativeRegisterContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContext.h; path = include/lldb/Target/NativeRegisterContext.h; sourceTree = "<group>"; };
 		23EDE3371926AAD500F6A132 /* RegisterInfoInterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RegisterInfoInterface.h; path = Utility/RegisterInfoInterface.h; sourceTree = "<group>"; };
 		23EFE388193D1ABC00E54E54 /* SBTypeEnumMember.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBTypeEnumMember.h; path = include/lldb/API/SBTypeEnumMember.h; sourceTree = "<group>"; };
 		23EFE38A193D1AEC00E54E54 /* SBTypeEnumMember.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SBTypeEnumMember.cpp; path = source/API/SBTypeEnumMember.cpp; sourceTree = "<group>"; };
+		23F403471926C8D50046DC9B /* NativeRegisterContextRegisterInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeRegisterContextRegisterInfo.h; path = include/lldb/Target/NativeRegisterContextRegisterInfo.h; sourceTree = "<group>"; };
+		23F403481926CC250046DC9B /* NativeRegisterContextRegisterInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = NativeRegisterContextRegisterInfo.cpp; path = source/Target/NativeRegisterContextRegisterInfo.cpp; sourceTree = "<group>"; };
 		260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = "<absolute>"; };
 		260223E7115F06D500A601A2 /* SBCommunication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommunication.h; path = include/lldb/API/SBCommunication.h; sourceTree = "<group>"; };
 		260223E8115F06E500A601A2 /* SBCommunication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommunication.cpp; path = source/API/SBCommunication.cpp; sourceTree = "<group>"; };
@@ -2186,10 +2218,12 @@
 		233B008B196106E90090E598 /* Linux */ = {
 			isa = PBXGroup;
 			children = (
-				233B008C19610B1F0090E598 /* LinuxSignals.cpp */,
-				233B008D19610B1F0090E598 /* LinuxSignals.h */,
 				233B008E19610B1F0090E598 /* LinuxThread.cpp */,
 				233B008F19610B1F0090E598 /* LinuxThread.h */,
+				232CB62B19213AC200EF39FC /* NativeProcessLinux.cpp */,
+				232CB62C19213AC200EF39FC /* NativeProcessLinux.h */,
+				232CB62D19213AC200EF39FC /* NativeThreadLinux.cpp */,
+				232CB62E19213AC200EF39FC /* NativeThreadLinux.h */,
 				233B009019610B1F0090E598 /* ProcessLinux.cpp */,
 				233B009119610B1F0090E598 /* ProcessLinux.h */,
 				233B009219610B1F0090E598 /* ProcessMonitor.cpp */,
@@ -2882,6 +2916,8 @@
 				B28058A0139988B0002D96D0 /* InferiorCallPOSIX.cpp */,
 				B28058A2139988C6002D96D0 /* InferiorCallPOSIX.h */,
 				B2D3033612EFA5C500F84EB3 /* InstructionUtils.h */,
+				23059A0519532B96007B8189 /* LinuxSignals.cpp */,
+				23059A0619532B96007B8189 /* LinuxSignals.h */,
 				26474C9E18D0CAEC0073DEBA /* RegisterContext_mips64.h */,
 				26474C9F18D0CAEC0073DEBA /* RegisterContext_x86.h */,
 				26957D9213D381C900670048 /* RegisterContextDarwin_arm.cpp */,
@@ -2939,6 +2975,9 @@
 				26E3EEE411A9901300FBADB6 /* UnwindMacOSXFrameBackchain.h */,
 				26E3EEE311A9901300FBADB6 /* UnwindMacOSXFrameBackchain.cpp */,
 				23EDE3371926AAD500F6A132 /* RegisterInfoInterface.h */,
+				239F5B2E19296DC500083917 /* NativeRegisterContextLinux_x86_64.h */,
+				239F5B3019298D4600083917 /* NativeRegisterContextLinux_x86_64.cpp */,
+				23173F8B192BA93F005C708F /* lldb-x86-register-enums.h */,
 			);
 			name = Utility;
 			sourceTree = "<group>";
@@ -3376,10 +3415,20 @@
 				26FA4315130103F400E71120 /* FileSpec.h */,
 				26BC7DD410F1B7D500F91463 /* Host.h */,
 				26BC7DD510F1B7D500F91463 /* Mutex.h */,
+				232CB60B191E00CC00EF39FC /* NativeBreakpoint.cpp */,
+				232CB60C191E00CC00EF39FC /* NativeBreakpoint.h */,
+				232CB60D191E00CC00EF39FC /* NativeBreakpointList.cpp */,
+				232CB60E191E00CC00EF39FC /* NativeBreakpointList.h */,
+				232CB60F191E00CC00EF39FC /* NativeProcessProtocol.cpp */,
+				232CB610191E00CC00EF39FC /* NativeProcessProtocol.h */,
+				232CB611191E00CC00EF39FC /* NativeThreadProtocol.cpp */,
+				232CB612191E00CC00EF39FC /* NativeThreadProtocol.h */,
 				A36FF33D17D8E98800244D40 /* OptionParser.h */,
 				26BC7DD610F1B7D500F91463 /* Predicate.h */,
 				26D7E45B13D5E2F9007FD12B /* SocketAddress.h */,
 				26D7E45C13D5E30A007FD12B /* SocketAddress.cpp */,
+				232CB613191E00CC00EF39FC /* SoftwareBreakpoint.cpp */,
+				232CB614191E00CD00EF39FC /* SoftwareBreakpoint.h */,
 				2689B0A4113EE3CD00A4AEDB /* Symbols.h */,
 				268DA871130095D000C9483A /* Terminal.h */,
 				26B4E26E112F35F700AB3F64 /* TimeValue.h */,
@@ -3486,6 +3535,8 @@
 		26BC7DEF10F1B80200F91463 /* Target */ = {
 			isa = PBXGroup;
 			children = (
+				23EDE3311926843600F6A132 /* NativeRegisterContext.h */,
+				23EDE3301926839700F6A132 /* NativeRegisterContext.cpp */,
 				497E7B331188ED300065CCA1 /* ABI.h */,
 				497E7B9D1188F6690065CCA1 /* ABI.cpp */,
 				4CB443BB1249920C00C13DC2 /* CPPLanguageRuntime.h */,
@@ -3583,6 +3634,8 @@
 				26E3EEBD11A9870400FBADB6 /* Unwind.h */,
 				264D8D4E13661BCC003A368F /* UnwindAssembly.h */,
 				264D8D4F13661BD7003A368F /* UnwindAssembly.cpp */,
+				23F403471926C8D50046DC9B /* NativeRegisterContextRegisterInfo.h */,
+				23F403481926CC250046DC9B /* NativeRegisterContextRegisterInfo.cpp */,
 			);
 			name = Target;
 			sourceTree = "<group>";
@@ -4103,6 +4156,7 @@
 				26FFC19C14FC072100087D58 /* DYLDRendezvous.h in Headers */,
 				AF1F7B08189C904B0087DB9C /* AppleGetPendingItemsHandler.h in Headers */,
 				AF2BCA6D18C7EFDE005B4526 /* JITLoaderGDB.h in Headers */,
+				232CB61E191E00CD00EF39FC /* SoftwareBreakpoint.h in Headers */,
 				26BC17B218C7F4CB00D2196D /* ThreadElfCore.h in Headers */,
 				26FFC19E14FC072100087D58 /* DynamicLoaderPOSIXDYLD.h in Headers */,
 				AF254E32170CCC33007AE5C9 /* PlatformDarwinKernel.h in Headers */,
@@ -4120,6 +4174,7 @@
 				260CC63115D04377002BF2E0 /* OptionValueProperties.h in Headers */,
 				260CC63215D04377002BF2E0 /* OptionValueDictionary.h in Headers */,
 				262173A118395D3800C52091 /* SectionLoadHistory.h in Headers */,
+				232CB61A191E00CD00EF39FC /* NativeProcessProtocol.h in Headers */,
 				260CC63315D04377002BF2E0 /* OptionValueEnumeration.h in Headers */,
 				AF45FDE618A1F3AC0007051C /* AppleGetThreadItemInfoHandler.h in Headers */,
 				260A63171861008E00FECF8E /* IOHandler.h in Headers */,
@@ -4147,15 +4202,18 @@
 				260CC63A15D04377002BF2E0 /* OptionValueUUID.h in Headers */,
 				260A248E15D06C50009981B0 /* OptionValues.h in Headers */,
 				AF061F88182C97ED00B6A19C /* RegisterContextHistory.h in Headers */,
+				239F5B2F19296DC500083917 /* NativeRegisterContextLinux_x86_64.h in Headers */,
 				26DAED6015D327A200E15819 /* OptionValuePathMappings.h in Headers */,
 				26ACEC2815E077AE00E94760 /* Property.h in Headers */,
 				26491E3B15E1DB8600CBFFC2 /* OptionValueRegex.h in Headers */,
 				2697A39515E404BA003E682C /* OptionValueArch.h in Headers */,
-				AF23B4DC19009C66003E2A58 /* FreeBSDSignals.h in Headers */,
 				26474CBF18D0CB2D0073DEBA /* RegisterContextMach_i386.h in Headers */,
 				26474CC118D0CB2D0073DEBA /* RegisterContextMach_x86_64.h in Headers */,
 				2698699D15E6CBD0002415FF /* OperatingSystemPython.h in Headers */,
+				232CB618191E00CD00EF39FC /* NativeBreakpointList.h in Headers */,
 				260D9B2715EC369500960137 /* ModuleSpec.h in Headers */,
+				232CB61C191E00CD00EF39FC /* NativeThreadProtocol.h in Headers */,
+				232CB616191E00CD00EF39FC /* NativeBreakpoint.h in Headers */,
 				947A1D651616476B0017C8D1 /* CommandObjectPlugin.h in Headers */,
 				262ED0051631FA2800879631 /* OptionGroupString.h in Headers */,
 				26474CA918D0CB070073DEBA /* RegisterContextFreeBSD_i386.h in Headers */,
@@ -4606,6 +4664,7 @@
 				2689001813353DDE00698AC0 /* CommandObjectExpression.cpp in Sources */,
 				2689001A13353DDE00698AC0 /* CommandObjectFrame.cpp in Sources */,
 				2689001B13353DDE00698AC0 /* CommandObjectHelp.cpp in Sources */,
+				23F4034D1926E0F60046DC9B /* NativeRegisterContextRegisterInfo.cpp in Sources */,
 				2689001D13353DDE00698AC0 /* CommandObjectLog.cpp in Sources */,
 				262173A318395D4600C52091 /* SectionLoadHistory.cpp in Sources */,
 				2689001E13353DDE00698AC0 /* CommandObjectMemory.cpp in Sources */,
@@ -4652,6 +4711,7 @@
 				2689004313353E0400698AC0 /* Mangled.cpp in Sources */,
 				2689004413353E0400698AC0 /* Module.cpp in Sources */,
 				2689004513353E0400698AC0 /* ModuleChild.cpp in Sources */,
+				23EDE33319269E7C00F6A132 /* NativeRegisterContext.cpp in Sources */,
 				2689004613353E0400698AC0 /* ModuleList.cpp in Sources */,
 				2689004713353E0400698AC0 /* PluginManager.cpp in Sources */,
 				AF0C112818580CD800C4C45B /* QueueItem.cpp in Sources */,
@@ -4672,6 +4732,7 @@
 				2689005313353E0400698AC0 /* UserID.cpp in Sources */,
 				2689005413353E0400698AC0 /* UserSettingsController.cpp in Sources */,
 				2689005513353E0400698AC0 /* UUID.cpp in Sources */,
+				23059A0719532B96007B8189 /* LinuxSignals.cpp in Sources */,
 				2689005613353E0400698AC0 /* Value.cpp in Sources */,
 				2689005713353E0400698AC0 /* ValueObject.cpp in Sources */,
 				2689005813353E0400698AC0 /* ValueObjectChild.cpp in Sources */,
@@ -4829,13 +4890,17 @@
 				268900F913353E6F00698AC0 /* Thread.cpp in Sources */,
 				268900FA13353E6F00698AC0 /* ThreadList.cpp in Sources */,
 				268900FB13353E6F00698AC0 /* ThreadPlan.cpp in Sources */,
+				232CB619191E00CD00EF39FC /* NativeProcessProtocol.cpp in Sources */,
 				268900FC13353E6F00698AC0 /* ThreadPlanBase.cpp in Sources */,
 				268900FD13353E6F00698AC0 /* ThreadPlanCallFunction.cpp in Sources */,
 				268900FE13353E6F00698AC0 /* ThreadPlanCallUserExpression.cpp in Sources */,
 				268900FF13353E6F00698AC0 /* ThreadPlanShouldStopHere.cpp in Sources */,
 				2689010013353E6F00698AC0 /* ThreadPlanStepInstruction.cpp in Sources */,
+				232CB61B191E00CD00EF39FC /* NativeThreadProtocol.cpp in Sources */,
 				2689010113353E6F00698AC0 /* ThreadPlanStepOut.cpp in Sources */,
 				2689010213353E6F00698AC0 /* ThreadPlanStepOverBreakpoint.cpp in Sources */,
+				232CB617191E00CD00EF39FC /* NativeBreakpointList.cpp in Sources */,
+				232CB615191E00CD00EF39FC /* NativeBreakpoint.cpp in Sources */,
 				2689010313353E6F00698AC0 /* ThreadPlanStepRange.cpp in Sources */,
 				2689010413353E6F00698AC0 /* ThreadPlanStepInRange.cpp in Sources */,
 				2689010513353E6F00698AC0 /* ThreadPlanStepOverRange.cpp in Sources */,
@@ -4894,6 +4959,7 @@
 				26DB3E191379E7AD0080DC73 /* ABIMacOSX_arm64.cpp in Sources */,
 				26DB3E1C1379E7AD0080DC73 /* ABIMacOSX_i386.cpp in Sources */,
 				26DB3E1F1379E7AD0080DC73 /* ABISysV_x86_64.cpp in Sources */,
+				232CB61D191E00CD00EF39FC /* SoftwareBreakpoint.cpp in Sources */,
 				26D1803E16CEBFD300EDFB5B /* KQueue.cpp in Sources */,
 				26A69C5F137A17A500262477 /* RegisterValue.cpp in Sources */,
 				2690B3711381D5C300ECFBAE /* Memory.cpp in Sources */,

Modified: lldb/trunk/source/Core/ModuleList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ModuleList.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Core/ModuleList.cpp (original)
+++ lldb/trunk/source/Core/ModuleList.cpp Mon Jun 30 16:05:18 2014
@@ -1003,6 +1003,7 @@ ModuleList::GetSharedModule
             file_spec.GetPath(path, sizeof(path));
             if (path[0] == '\0')
                 module_file_spec.GetPath(path, sizeof(path));
+            // How can this check ever be true? This branch it is false, and we haven't modified file_spec.
             if (file_spec.Exists())
             {
                 std::string uuid_str;

Modified: lldb/trunk/source/Expression/IRMemoryMap.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRMemoryMap.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Expression/IRMemoryMap.cpp (original)
+++ lldb/trunk/source/Expression/IRMemoryMap.cpp Mon Jun 30 16:05:18 2014
@@ -249,6 +249,7 @@ IRMemoryMap::Allocation::Allocation (lld
 lldb::addr_t
 IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error)
 {
+    lldb_private::Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
     error.Clear();
     
     lldb::ProcessSP process_sp;
@@ -280,6 +281,8 @@ IRMemoryMap::Malloc (size_t size, uint8_
         break;
     case eAllocationPolicyMirror:
         process_sp = m_process_wp.lock();
+        if (log)
+            log->Printf ("IRMemoryMap::%s process_sp=0x%" PRIx64 ", process_sp->CanJIT()=%s, process_sp->IsAlive()=%s", __FUNCTION__, (lldb::addr_t) process_sp.get (), process_sp && process_sp->CanJIT () ? "true" : "false", process_sp && process_sp->IsAlive () ? "true" : "false");
         if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
         {
             allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
@@ -288,6 +291,8 @@ IRMemoryMap::Malloc (size_t size, uint8_
         }
         else
         {
+            if (log)
+                log->Printf ("IRMemoryMap::%s switching to eAllocationPolicyHostOnly due to failed condition (see previous expr log message)", __FUNCTION__);
             policy = eAllocationPolicyHostOnly;
             allocation_address = FindSpace(allocation_size);
             if (allocation_address == LLDB_INVALID_ADDRESS)
@@ -335,7 +340,7 @@ IRMemoryMap::Malloc (size_t size, uint8_
                                                 alignment,
                                                 policy);
     
-    if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+    if (log)
     {
         const char * policy_string;
         

Modified: lldb/trunk/source/Host/common/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/CMakeLists.txt (original)
+++ lldb/trunk/source/Host/common/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -8,9 +8,14 @@ add_lldb_library(lldbHostCommon
   FileSpec.cpp
   Host.cpp
   Mutex.cpp
+  NativeBreakpoint.cpp
+  NativeBreakpointList.cpp
+  NativeProcessProtocol.cpp
+  NativeThreadProtocol.cpp
   OptionParser.cpp
   ProcessRunLock.cpp
   SocketAddress.cpp
+  SoftwareBreakpoint.cpp
   Symbols.cpp
   Terminal.cpp
   TimeValue.cpp

Added: lldb/trunk/source/Host/common/NativeBreakpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpoint.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpoint.cpp (added)
+++ lldb/trunk/source/Host/common/NativeBreakpoint.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,116 @@
+//===-- NativeBreakpoint.cpp ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeBreakpoint.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+NativeBreakpoint::NativeBreakpoint (lldb::addr_t addr) :
+    m_addr (addr),
+    m_ref_count (1),
+    m_enabled (true)
+{
+    assert (addr != LLDB_INVALID_ADDRESS && "breakpoint set for invalid address");
+}
+
+NativeBreakpoint::~NativeBreakpoint ()
+{
+}
+
+void
+NativeBreakpoint::AddRef ()
+{
+    ++m_ref_count;
+
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " bumped up, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);  
+}
+
+int32_t
+NativeBreakpoint::DecRef ()
+{
+    --m_ref_count;
+
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " ref count decremented, new ref count %" PRIu32, __FUNCTION__, m_addr, m_ref_count);  
+
+    return m_ref_count;
+}
+
+Error
+NativeBreakpoint::Enable ()
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+    if (m_enabled)
+    {
+        // We're already enabled. Just log and exit.
+        if (log)
+            log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already enabled, ignoring.", __FUNCTION__, m_addr);
+        return Error ();
+    }
+
+    // Log and enable.
+    if (log)
+        log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enabling...", __FUNCTION__, m_addr);
+
+    Error error = DoEnable ();
+    if (error.Success ())
+    {
+        m_enabled = true;
+        if (log)
+            log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable SUCCESS.", __FUNCTION__, m_addr);  
+    }
+    else
+    {
+        if (log)
+            log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+    }
+
+    return error;
+}
+
+Error
+NativeBreakpoint::Disable ()
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+    if (!m_enabled)
+    {
+        // We're already disabled. Just log and exit.
+        if (log)
+            log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " already disabled, ignoring.", __FUNCTION__, m_addr);
+        return Error ();
+    }
+
+    // Log and disable.
+    if (log)
+        log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disabling...", __FUNCTION__, m_addr);
+
+    Error error = DoDisable ();
+    if (error.Success ())
+    {
+        m_enabled = false;
+        if (log)
+            log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable SUCCESS.", __FUNCTION__, m_addr);  
+    }
+    else
+    {
+        if (log)
+            log->Printf ("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable FAIL: %s", __FUNCTION__, m_addr, error.AsCString ());
+    }
+
+    return error;
+}

Added: lldb/trunk/source/Host/common/NativeBreakpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpoint.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpoint.h (added)
+++ lldb/trunk/source/Host/common/NativeBreakpoint.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,66 @@
+//===-- NativeBreakpoint.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_NativeBreakpoint_h_
+#define liblldb_NativeBreakpoint_h_
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private
+{
+    class NativeBreakpointList;
+
+    class NativeBreakpoint
+    {
+        friend class NativeBreakpointList;
+
+    public:
+        // The assumption is that derived breakpoints are enabled when created.
+        NativeBreakpoint (lldb::addr_t addr);
+
+        virtual
+        ~NativeBreakpoint ();
+
+        Error
+        Enable ();
+
+        Error
+        Disable ();
+
+        lldb::addr_t
+        GetAddress () const { return m_addr; }
+
+        bool
+        IsEnabled () const { return m_enabled; }
+
+        virtual bool
+        IsSoftwareBreakpoint () const = 0;
+
+    protected:
+        const lldb::addr_t m_addr;
+        int32_t m_ref_count;
+
+        virtual Error
+        DoEnable () = 0;
+
+        virtual Error
+        DoDisable () = 0;
+
+    private:
+        bool m_enabled;
+
+        // -----------------------------------------------------------
+        // interface for NativeBreakpointList
+        // -----------------------------------------------------------
+        void AddRef ();
+        int32_t DecRef ();
+    };
+}
+
+#endif // ifndef liblldb_NativeBreakpoint_h_

Added: lldb/trunk/source/Host/common/NativeBreakpointList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpointList.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpointList.cpp (added)
+++ lldb/trunk/source/Host/common/NativeBreakpointList.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,199 @@
+//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeBreakpointList.h"
+
+#include "lldb/Core/Log.h"
+
+#include "NativeBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeBreakpointList::NativeBreakpointList () :
+    m_mutex (Mutex::eMutexTypeRecursive)
+{
+}
+
+Error
+NativeBreakpointList::AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func)
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false");
+
+    Mutex::Locker locker (m_mutex);
+
+    // Check if the breakpoint is already set.
+    auto iter = m_breakpoints.find (addr);
+    if (iter != m_breakpoints.end ())
+    {
+        // Yes - bump up ref count.
+        if (log)
+            log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already enabled, upping ref count", __FUNCTION__, addr);
+
+        iter->second->AddRef ();
+        return Error ();
+    }
+
+    // Create a new breakpoint using the given create func.
+    if (log)
+        log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false");
+
+    NativeBreakpointSP breakpoint_sp;
+    Error error = create_func (addr, size_hint, hardware, breakpoint_sp);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64 ", size_hint = %lu, hardware = %s -- FAILED: %s", __FUNCTION__, addr, size_hint, hardware ? "true" : "false", error.AsCString ());
+        return error;
+    }
+
+    // Remember the breakpoint.
+    assert (breakpoint_sp && "NativeBreakpoint create function succeeded but returned NULL breakpoint");
+    m_breakpoints.insert (BreakpointMap::value_type (addr, breakpoint_sp));
+
+    return error;
+}
+
+Error
+NativeBreakpointList::DecRef (lldb::addr_t addr)
+{
+    Error error;
+
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+    Mutex::Locker locker (m_mutex);
+
+    // Check if the breakpoint is already set.
+    auto iter = m_breakpoints.find (addr);
+    if (iter == m_breakpoints.end ())
+    {
+        // Not found!
+        if (log)
+            log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+        error.SetErrorString ("breakpoint not found");
+        return error;
+    }
+
+    // Decrement ref count.
+    const int32_t new_ref_count = iter->second->DecRef ();
+    assert (new_ref_count >= 0 && "NativeBreakpoint ref count went negative");
+
+    if (new_ref_count > 0)
+    {
+        // Still references to this breakpoint.  Leave it alone.
+        if (log)
+            log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- new breakpoint ref count %" PRIu32, __FUNCTION__, addr, new_ref_count);
+        return error;
+    }
+
+    // Breakpoint has no more references.  Disable it if it's not
+    // already disabled.
+    if (log)
+        log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removing due to no remaining references", __FUNCTION__, addr);
+
+    // If it's enabled, we need to disable it.
+    if (iter->second->IsEnabled ())
+    {
+        if (log)
+            log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- currently enabled, now disabling", __FUNCTION__, addr);
+        error = iter->second->Disable ();
+        if (error.Fail ())
+        {
+            if (log)
+                log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removal FAILED: %s", __FUNCTION__, addr, error.AsCString ());
+            // Continue since we still want to take it out of the breakpoint list.
+        }
+    }
+    else
+    {
+        if (log)
+            log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- already disabled, nothing to do", __FUNCTION__, addr);
+    }
+
+    // Take the breakpoint out of the list.
+    if (log)
+        log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- removed from breakpoint map", __FUNCTION__, addr);
+
+    m_breakpoints.erase (iter);
+    return error;
+}
+
+Error
+NativeBreakpointList::EnableBreakpoint (lldb::addr_t addr)
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+    Mutex::Locker locker (m_mutex);
+
+    // Ensure we have said breakpoint.
+    auto iter = m_breakpoints.find (addr);
+    if (iter == m_breakpoints.end ())
+    {
+        // Not found!
+        if (log)
+            log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+        return Error ("breakpoint not found");
+    }
+
+    // Enable it.
+    return iter->second->Enable ();
+}
+
+Error
+NativeBreakpointList::DisableBreakpoint (lldb::addr_t addr)
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+    Mutex::Locker locker (m_mutex);
+
+    // Ensure we have said breakpoint.
+    auto iter = m_breakpoints.find (addr);
+    if (iter == m_breakpoints.end ())
+    {
+        // Not found!
+        if (log)
+            log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND", __FUNCTION__, addr);
+        return Error ("breakpoint not found");
+    }
+
+    // Disable it.
+    return iter->second->Disable ();
+}
+
+Error
+NativeBreakpointList::GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp)
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+    Mutex::Locker locker (m_mutex);
+
+    // Ensure we have said breakpoint.
+    auto iter = m_breakpoints.find (addr);
+    if (iter == m_breakpoints.end ())
+    {
+        // Not found!
+        breakpoint_sp.reset ();
+        return Error ("breakpoint not found");
+    }
+
+    // Disable it.
+    breakpoint_sp = iter->second;
+    return Error ();
+}
+

Added: lldb/trunk/source/Host/common/NativeBreakpointList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeBreakpointList.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeBreakpointList.h (added)
+++ lldb/trunk/source/Host/common/NativeBreakpointList.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,53 @@
+//===-- NativeBreakpointList.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_NativeBreakpointList_h_
+#define liblldb_NativeBreakpointList_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+// #include "lldb/Host/NativeBreakpoint.h"
+
+#include <functional>
+#include <map>
+
+namespace lldb_private
+{
+    class NativeBreakpointList
+    {
+    public:
+        typedef std::function<Error (lldb::addr_t addr, size_t size_hint, bool hardware, NativeBreakpointSP &breakpoint_sp)> CreateBreakpointFunc;
+
+        NativeBreakpointList ();
+
+        Error
+        AddRef (lldb::addr_t addr, size_t size_hint, bool hardware, CreateBreakpointFunc create_func);
+
+        Error
+        DecRef (lldb::addr_t addr);
+
+        Error
+        EnableBreakpoint (lldb::addr_t addr);
+
+        Error
+        DisableBreakpoint (lldb::addr_t addr);
+
+        Error
+        GetBreakpoint (lldb::addr_t addr, NativeBreakpointSP &breakpoint_sp);
+
+    private:
+        typedef std::map<lldb::addr_t, NativeBreakpointSP> BreakpointMap;
+
+        Mutex m_mutex;
+        BreakpointMap m_breakpoints;
+    };
+}
+
+#endif // ifndef liblldb_NativeBreakpointList_h_

Added: lldb/trunk/source/Host/common/NativeProcessProtocol.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeProcessProtocol.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeProcessProtocol.cpp (added)
+++ lldb/trunk/source/Host/common/NativeProcessProtocol.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,397 @@
+//===-- NativeProcessProtocol.cpp -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessProtocol.h"
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/NativeRegisterContext.h"
+
+#include "NativeThreadProtocol.h"
+#include "SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// -----------------------------------------------------------------------------
+// NativeProcessProtocol Members
+// -----------------------------------------------------------------------------
+
+NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) :
+    m_pid (pid),
+    m_threads (),
+    m_current_thread_id (LLDB_INVALID_THREAD_ID),
+    m_threads_mutex (Mutex::eMutexTypeRecursive),
+    m_state (lldb::eStateInvalid),
+    m_state_mutex (Mutex::eMutexTypeRecursive),
+    m_exit_type (eExitTypeInvalid),
+    m_exit_status (0),
+    m_exit_description (),
+    m_delegates_mutex (Mutex::eMutexTypeRecursive),
+    m_delegates (),
+    m_breakpoint_list (),
+    m_terminal_fd (-1),
+    m_stop_id (0)
+{
+}
+
+lldb_private::Error
+NativeProcessProtocol::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
+{
+    // Default: not implemented.
+    return Error ("not implemented");
+}
+
+bool
+NativeProcessProtocol::GetExitStatus (ExitType *exit_type, int *status, std::string &exit_description)
+{
+    if (m_state == lldb::eStateExited)
+    {
+        *exit_type = m_exit_type;
+        *status = m_exit_status;
+        exit_description = m_exit_description;
+        return true;
+    }
+
+    *status = 0;
+    return false;
+}
+
+bool
+NativeProcessProtocol::SetExitStatus (ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange)
+{
+    Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("NativeProcessProtocol::%s(%d, %d, %s, %s) called",
+                __FUNCTION__,
+                exit_type,
+                status,
+                exit_description ? exit_description : "nullptr",
+                bNotifyStateChange ? "true" : "false");
+
+    // Exit status already set
+    if (m_state == lldb::eStateExited)
+    {
+        if (log)
+            log->Printf ("NativeProcessProtocol::%s exit status already set to %d, ignoring new set to %d", __FUNCTION__, m_exit_status, status);
+        return false;
+    }
+
+    m_state = lldb::eStateExited;
+
+    m_exit_type = exit_type;
+    m_exit_status = status;
+    if (exit_description && exit_description[0])
+        m_exit_description = exit_description;
+    else
+        m_exit_description.clear();
+
+    if (bNotifyStateChange)
+        SynchronouslyNotifyProcessStateChanged (lldb::eStateExited);
+
+    return true;
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadAtIndex (uint32_t idx)
+{
+    Mutex::Locker locker (m_threads_mutex);
+    if (idx < m_threads.size ())
+        return m_threads[idx];
+    return NativeThreadProtocolSP ();
+}
+
+NativeThreadProtocolSP
+NativeProcessProtocol::GetThreadByID (lldb::tid_t tid)
+{
+    Mutex::Locker locker (m_threads_mutex);
+    for (auto thread_sp : m_threads)
+    {
+        if (thread_sp->GetID() == tid)
+            return thread_sp;
+    }
+    return NativeThreadProtocolSP ();
+}
+
+bool
+NativeProcessProtocol::IsAlive () const
+{
+    return m_state != eStateDetached
+        && m_state != eStateExited
+        && m_state != eStateInvalid
+        && m_state != eStateUnloaded;
+}
+
+bool
+NativeProcessProtocol::GetByteOrder (lldb::ByteOrder &byte_order) const
+{
+    ArchSpec process_arch;
+    if (!GetArchitecture (process_arch))
+        return false;
+    byte_order = process_arch.GetByteOrder ();
+    return true;
+}
+
+uint32_t
+NativeProcessProtocol::GetMaxWatchpoints () const
+{
+    // This default implementation will return the number of
+    // *hardware* breakpoints available.  MacOSX and other OS
+    // implementations that support software breakpoints will want to
+    // override this correctly for their implementation.
+    Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    // get any thread
+    NativeThreadProtocolSP thread_sp (const_cast<NativeProcessProtocol*> (this)->GetThreadAtIndex (0));
+    if (!thread_sp)
+    {
+        if (log)
+            log->Warning ("NativeProcessProtocol::%s (): failed to find a thread to grab a NativeRegisterContext!", __FUNCTION__);
+        return 0;
+    }
+
+    NativeRegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext ());
+    if (!reg_ctx_sp)
+    {
+        if (log)
+            log->Warning ("NativeProcessProtocol::%s (): failed to get a RegisterContextNativeProcess from the first thread!", __FUNCTION__);
+        return 0;
+    }
+
+    return reg_ctx_sp->NumSupportedHardwareWatchpoints ();
+}
+
+Error
+NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+    // This default implementation assumes setting the watchpoint for
+    // the process will require setting the watchpoint for each of the
+    // threads.  Furthermore, it will track watchpoints set for the
+    // process and will add them to each thread that is attached to
+    // via the (FIXME implement) OnThreadAttached () method.
+
+    Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    // FIXME save the watchpoint on the set of process watchpoint vars
+    // so we can add them to a thread each time a new thread is registered.
+
+    // Update the thread list
+    UpdateThreads ();
+
+    // Keep track of the threads we successfully set the watchpoint
+    // for.  If one of the thread watchpoint setting operations fails,
+    // back off and remove the watchpoint for all the threads that
+    // were successfully set so we get back to a consistent state.
+    std::vector<NativeThreadProtocolSP> watchpoint_established_threads;
+
+    // Tell each thread to set a watchpoint.  In the event that
+    // hardware watchpoints are requested but the SetWatchpoint fails,
+    // try to set a software watchpoint as a fallback.  It's
+    // conceivable that if there are more threads than hardware
+    // watchpoints available, some of the threads will fail to set
+    // hardware watchpoints while software ones may be available.
+    Mutex::Locker locker (m_threads_mutex);
+    for (auto thread_sp : m_threads)
+    {
+        assert (thread_sp && "thread list should not have a NULL thread!");
+        if (!thread_sp)
+            continue;
+
+        Error thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, hardware);
+        if (thread_error.Fail () && hardware)
+        {
+            // Try software watchpoints since we failed on hardware watchpoint setting
+            // and we may have just run out of hardware watchpoints.
+            thread_error = thread_sp->SetWatchpoint (addr, size, watch_flags, false);
+            if (thread_error.Success ())
+            {
+                if (log)
+                    log->Warning ("hardware watchpoint requested but software watchpoint set"); 
+            }
+        }
+
+        if (thread_error.Success ())
+        {
+            // Remember that we set this watchpoint successfully in
+            // case we need to clear it later.
+            watchpoint_established_threads.push_back (thread_sp);
+        }
+        else
+        {
+            // Unset the watchpoint for each thread we successfully
+            // set so that we get back to a consistent state of "not
+            // set" for the watchpoint.
+            for (auto unwatch_thread_sp : watchpoint_established_threads)
+            {
+                Error remove_error = unwatch_thread_sp->RemoveWatchpoint (addr);
+                if (remove_error.Fail () && log)
+                {
+                    log->Warning ("NativeProcessProtocol::%s (): RemoveWatchpoint failed for pid=%" PRIu64 ", tid=%" PRIu64 ": %s",
+                            __FUNCTION__, GetID (), unwatch_thread_sp->GetID (), remove_error.AsCString ());
+                }
+            }
+
+            return thread_error;
+        }
+    }
+    return Error ();
+}
+
+Error
+NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr)
+{
+    // FIXME remove the watchpoint on the set of process watchpoint vars
+    // so we can add them to a thread each time a new thread is registered.
+
+    // Update the thread list
+    UpdateThreads ();
+
+    Error overall_error;
+
+    Mutex::Locker locker (m_threads_mutex);
+    for (auto thread_sp : m_threads)
+    {
+        assert (thread_sp && "thread list should not have a NULL thread!");
+        if (!thread_sp)
+            continue;
+
+        const Error thread_error = thread_sp->RemoveWatchpoint (addr);
+        if (thread_error.Fail ())
+        {
+            // Keep track of the first thread error if any threads
+            // fail. We want to try to remove the watchpoint from
+            // every thread, though, even if one or more have errors.
+            if (!overall_error.Fail ())
+                overall_error = thread_error;
+        }
+    }
+    return overall_error;
+}
+
+bool
+NativeProcessProtocol::RegisterNativeDelegate (NativeDelegate &native_delegate)
+{
+    Mutex::Locker locker (m_delegates_mutex);
+    if (std::find (m_delegates.begin (), m_delegates.end (), &native_delegate) != m_delegates.end ())
+        return false;
+
+    m_delegates.push_back (&native_delegate);
+    native_delegate.InitializeDelegate (this);
+    return true;
+}
+
+bool
+NativeProcessProtocol::UnregisterNativeDelegate (NativeDelegate &native_delegate)
+{
+    Mutex::Locker locker (m_delegates_mutex);
+
+    const auto initial_size = m_delegates.size ();
+    m_delegates.erase (remove (m_delegates.begin (), m_delegates.end (), &native_delegate), m_delegates.end ());
+
+    // We removed the delegate if the count of delegates shrank after
+    // removing all copies of the given native_delegate from the vector.
+    return m_delegates.size () < initial_size;
+}
+
+void
+NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged (lldb::StateType state)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    Mutex::Locker locker (m_delegates_mutex);
+    for (auto native_delegate: m_delegates)
+        native_delegate->ProcessStateChanged (this, state);
+
+    if (log)
+    {
+        if (!m_delegates.empty ())
+        {
+            log->Printf ("NativeProcessProtocol::%s: sent state notification [%s] from process %" PRIu64,
+                    __FUNCTION__, lldb_private::StateAsCString (state),  GetID ());
+        }
+        else
+        {
+            log->Printf ("NativeProcessProtocol::%s: would send state notification [%s] from process %" PRIu64 ", but no delegates",
+                    __FUNCTION__, lldb_private::StateAsCString (state),  GetID ());
+        }
+    }
+}
+
+Error
+NativeProcessProtocol::SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint)
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+    return m_breakpoint_list.AddRef (addr, size_hint, false,
+            [this] (lldb::addr_t addr, size_t size_hint, bool /* hardware */, NativeBreakpointSP &breakpoint_sp)->Error
+            { return SoftwareBreakpoint::CreateSoftwareBreakpoint (*this, addr, size_hint, breakpoint_sp); });
+}
+
+Error
+NativeProcessProtocol::RemoveBreakpoint (lldb::addr_t addr)
+{
+    return m_breakpoint_list.DecRef (addr);
+}
+
+Error
+NativeProcessProtocol::EnableBreakpoint (lldb::addr_t addr)
+{
+    return m_breakpoint_list.EnableBreakpoint (addr);
+}
+
+Error
+NativeProcessProtocol::DisableBreakpoint (lldb::addr_t addr)
+{
+    return m_breakpoint_list.DisableBreakpoint (addr);
+}
+
+lldb::StateType
+NativeProcessProtocol::GetState () const
+{
+    Mutex::Locker locker (m_state_mutex);
+    return m_state;
+}
+
+void
+NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates)
+{
+    Mutex::Locker locker (m_state_mutex);
+    m_state = state;
+
+    if (StateIsStoppedState (state, false))
+    {
+        ++m_stop_id;
+
+        // Give process a chance to do any stop id bump processing, such as
+        // clearing cached data that is invalidated each time the process runs.
+        // Note if/when we support some threads running, we'll end up needing
+        // to manage this per thread and per process.
+        DoStopIDBumped (m_stop_id);
+    }
+
+    // Optionally notify delegates of the state change.
+    if (notify_delegates)
+        SynchronouslyNotifyProcessStateChanged (state);
+}
+
+uint32_t NativeProcessProtocol::GetStopID () const
+{
+   Mutex::Locker locker (m_state_mutex);
+   return m_stop_id;
+}
+
+void
+NativeProcessProtocol::DoStopIDBumped (uint32_t /* newBumpId */)
+{
+    // Default implementation does nothing.
+}

Added: lldb/trunk/source/Host/common/NativeProcessProtocol.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeProcessProtocol.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeProcessProtocol.h (added)
+++ lldb/trunk/source/Host/common/NativeProcessProtocol.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,321 @@
+//===-- NativeProcessProtocol.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_NativeProcessProtocol_h_
+#define liblldb_NativeProcessProtocol_h_
+
+#include <vector>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+
+#include "NativeBreakpointList.h"
+
+namespace lldb_private
+{
+    class MemoryRegionInfo;
+    class ResumeActionList;
+
+    //------------------------------------------------------------------
+    // NativeProcessProtocol
+    //------------------------------------------------------------------
+    class NativeProcessProtocol :
+        public std::enable_shared_from_this<NativeProcessProtocol>
+    {
+        friend class SoftwareBreakpoint;
+
+    public:
+        static NativeProcessProtocol *
+        CreateInstance (lldb::pid_t pid);
+
+        // lldb_private::Host calls should be used to launch a process for debugging, and
+        // then the process should be attached to. When attaching to a process
+        // lldb_private::Host calls should be used to locate the process to attach to,
+        // and then this function should be called.
+        NativeProcessProtocol (lldb::pid_t pid);
+
+    public:
+        virtual ~NativeProcessProtocol ()
+        {
+        }
+
+        virtual Error
+        Resume (const ResumeActionList &resume_actions) = 0;
+
+        virtual Error
+        Halt () = 0;
+
+        virtual Error
+        Detach () = 0;
+
+        //------------------------------------------------------------------
+        /// Sends a process a UNIX signal \a signal.
+        ///
+        /// Implementer note: the WillSignal ()/DidSignal () calls
+        /// from the Process class are not replicated here since no
+        /// concrete classes implemented any behavior for those and
+        /// put all the work in DoSignal (...).
+        ///
+        /// @return
+        ///     Returns an error object.
+        //------------------------------------------------------------------
+        virtual Error
+        Signal (int signo) = 0;
+
+        virtual Error
+        Kill () = 0;
+
+        //----------------------------------------------------------------------
+        // Memory and memory region functions
+        //----------------------------------------------------------------------
+
+        virtual Error
+        GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info);
+
+        virtual Error
+        ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0;
+
+        virtual Error
+        WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0;
+
+        virtual Error
+        AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0;
+
+        virtual Error
+        DeallocateMemory (lldb::addr_t addr) = 0;
+
+        virtual lldb::addr_t
+        GetSharedLibraryInfoAddress () = 0;
+
+        virtual bool
+        IsAlive () const;
+
+        virtual size_t
+        UpdateThreads () = 0;
+
+        virtual bool
+        GetArchitecture (ArchSpec &arch) const = 0;
+
+        //----------------------------------------------------------------------
+        // Breakpoint functions
+        //----------------------------------------------------------------------
+        virtual Error
+        SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) = 0;
+
+        virtual Error
+        RemoveBreakpoint (lldb::addr_t addr);
+
+        virtual Error
+        EnableBreakpoint (lldb::addr_t addr);
+
+        virtual Error
+        DisableBreakpoint (lldb::addr_t addr);
+
+        //----------------------------------------------------------------------
+        // Watchpoint functions
+        //----------------------------------------------------------------------
+        virtual uint32_t
+        GetMaxWatchpoints () const;
+
+        virtual Error
+        SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware);
+
+        virtual Error
+        RemoveWatchpoint (lldb::addr_t addr);
+
+        //----------------------------------------------------------------------
+        // Accessors
+        //----------------------------------------------------------------------
+        lldb::pid_t
+        GetID() const
+        {
+            return m_pid;
+        }
+
+        lldb::StateType
+        GetState () const;
+
+        bool
+        IsRunning () const
+        {
+            return m_state == lldb::eStateRunning || IsStepping();
+        }
+
+        bool
+        IsStepping () const
+        {
+            return m_state == lldb::eStateStepping;
+        }
+
+        bool
+        CanResume () const
+        {
+            return m_state == lldb::eStateStopped;
+        }
+
+        bool
+        GetByteOrder (lldb::ByteOrder &byte_order) const;
+
+        //----------------------------------------------------------------------
+        // Exit Status
+        //----------------------------------------------------------------------
+        virtual bool
+        GetExitStatus (lldb_private::ExitType *exit_type, int *status, std::string &exit_description);
+
+        virtual bool
+        SetExitStatus (lldb_private::ExitType exit_type, int status, const char *exit_description, bool bNotifyStateChange);
+
+        //----------------------------------------------------------------------
+        // Access to threads
+        //----------------------------------------------------------------------
+        NativeThreadProtocolSP
+        GetThreadAtIndex (uint32_t idx);
+
+        NativeThreadProtocolSP
+        GetThreadByID (lldb::tid_t tid);
+
+        void
+        SetCurrentThreadID (lldb::tid_t tid)
+        {
+            m_current_thread_id = tid;
+        }
+
+        lldb::tid_t
+        GetCurrentThreadID ()
+        {
+            return m_current_thread_id;
+        }
+
+        NativeThreadProtocolSP
+        GetCurrentThread ()
+        {
+            return GetThreadByID (m_current_thread_id);
+        }
+
+        //----------------------------------------------------------------------
+        // Access to inferior stdio
+        //----------------------------------------------------------------------
+        virtual
+        int GetTerminalFileDescriptor ()
+        {
+            return m_terminal_fd;
+        }
+
+        //----------------------------------------------------------------------
+        // Stop id interface
+        //----------------------------------------------------------------------
+
+        uint32_t
+        GetStopID () const;
+
+        // ---------------------------------------------------------------------
+        // Callbacks for low-level process state changes
+        // ---------------------------------------------------------------------
+        class NativeDelegate
+        {
+        public:
+            virtual
+            ~NativeDelegate () {}
+
+            virtual void
+            InitializeDelegate (NativeProcessProtocol *process) = 0;
+
+            virtual void
+            ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) = 0;
+        };
+
+        //------------------------------------------------------------------
+        /// Register a native delegate.
+        ///
+        /// Clients can register nofication callbacks by passing in a
+        /// NativeDelegate impl and passing it into this function.
+        ///
+        /// Note: it is required that the lifetime of the
+        /// native_delegate outlive the NativeProcessProtocol.
+        ///
+        /// @param[in] native_delegate
+        ///     A NativeDelegate impl to be called when certain events
+        ///     happen within the NativeProcessProtocol or related threads.
+        ///
+        /// @return
+        ///     true if the delegate was registered successfully;
+        ///     false if the delegate was already registered.
+        ///
+        /// @see NativeProcessProtocol::NativeDelegate.
+        //------------------------------------------------------------------
+        bool
+        RegisterNativeDelegate (NativeDelegate &native_delegate);
+
+        //------------------------------------------------------------------
+        /// Unregister a native delegate previously registered.
+        ///
+        /// @param[in] native_delegate
+        ///     A NativeDelegate impl previously registered with this process.
+        ///
+        /// @return Returns \b true if the NativeDelegate was
+        /// successfully removed from the process, \b false otherwise.
+        ///
+        /// @see NativeProcessProtocol::NativeDelegate
+        //------------------------------------------------------------------
+        bool
+        UnregisterNativeDelegate (NativeDelegate &native_delegate);
+
+    protected:
+        lldb::pid_t m_pid;
+
+        std::vector<NativeThreadProtocolSP> m_threads;
+        lldb::tid_t m_current_thread_id;
+        mutable Mutex m_threads_mutex;
+
+        lldb::StateType m_state;
+        mutable Mutex m_state_mutex;
+
+        lldb_private::ExitType m_exit_type;
+        int m_exit_status;
+        std::string m_exit_description;
+        Mutex m_delegates_mutex;
+        std::vector<NativeDelegate*> m_delegates;
+        NativeBreakpointList m_breakpoint_list;
+        int m_terminal_fd;
+        uint32_t m_stop_id;
+
+        // -----------------------------------------------------------
+        // Internal interface for state handling
+        // -----------------------------------------------------------
+        void
+        SetState (lldb::StateType state, bool notify_delegates = true);
+
+        // Derived classes need not impelment this.  It can be used as a
+        // hook to clear internal caches that should be invalidated when
+        // stop ids change.
+        //
+        // Note this function is called with the state mutex obtained
+        // by the caller.
+        virtual void
+        DoStopIDBumped (uint32_t newBumpId);
+
+        // -----------------------------------------------------------
+        // Internal interface for software breakpoints
+        // -----------------------------------------------------------
+        Error
+        SetSoftwareBreakpoint (lldb::addr_t addr, uint32_t size_hint);
+
+        virtual Error
+        GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) = 0;
+
+    private:
+
+        void
+        SynchronouslyNotifyProcessStateChanged (lldb::StateType state);
+    };
+}
+
+#endif // #ifndef liblldb_NativeProcessProtocol_h_

Added: lldb/trunk/source/Host/common/NativeThreadProtocol.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeThreadProtocol.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeThreadProtocol.cpp (added)
+++ lldb/trunk/source/Host/common/NativeThreadProtocol.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,97 @@
+//===-- NativeThreadProtocol.cpp --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadProtocol.h"
+
+#include "NativeProcessProtocol.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "SoftwareBreakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeThreadProtocol::NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) :
+    m_process_wp (process->shared_from_this ()),
+    m_tid (tid)
+{
+}
+
+Error
+NativeThreadProtocol::ReadRegister (uint32_t reg, RegisterValue &reg_value)
+{
+    NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+    if (!register_context_sp)
+        return Error ("no register context");
+
+    const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+    if (!reg_info)
+        return Error ("no register info for reg num %" PRIu32, reg);
+
+    return register_context_sp->ReadRegister (reg_info, reg_value);;
+}
+
+Error
+NativeThreadProtocol::WriteRegister (uint32_t reg, const RegisterValue &reg_value)
+{
+    NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+    if (!register_context_sp)
+        return Error ("no register context");
+
+    const RegisterInfo *const reg_info = register_context_sp->GetRegisterInfoAtIndex (reg);
+    if (!reg_info)
+        return Error ("no register info for reg num %" PRIu32, reg);
+
+    return register_context_sp->WriteRegister (reg_info, reg_value);
+}
+
+Error
+NativeThreadProtocol::SaveAllRegisters (lldb::DataBufferSP &data_sp)
+{
+    NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+    if (!register_context_sp)
+        return Error ("no register context");
+    return register_context_sp->WriteAllRegisterValues (data_sp);
+}
+
+Error
+NativeThreadProtocol::RestoreAllRegisters (lldb::DataBufferSP &data_sp)
+{
+    NativeRegisterContextSP register_context_sp = GetRegisterContext ();
+    if (!register_context_sp)
+        return Error ("no register context");
+    return register_context_sp->ReadAllRegisterValues (data_sp);
+}
+
+NativeProcessProtocolSP
+NativeThreadProtocol::GetProcess ()
+{
+    return m_process_wp.lock ();
+}
+
+uint32_t
+NativeThreadProtocol::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const
+{
+    // Default: no translation.  Do the real translation where there
+    // is access to the host signal numbers.
+    switch (stop_info.reason)
+    {
+        case eStopReasonSignal:
+            return stop_info.details.signal.signo;
+            break;
+
+        case eStopReasonException:
+            // FIXME verify the way to specify pass-thru here.
+            return static_cast<uint32_t> (stop_info.details.exception.type);
+            break;
+
+        default:
+            assert (0 && "unexpected stop_info.reason found");
+            return 0;
+    }
+}

Added: lldb/trunk/source/Host/common/NativeThreadProtocol.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/NativeThreadProtocol.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/NativeThreadProtocol.h (added)
+++ lldb/trunk/source/Host/common/NativeThreadProtocol.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,85 @@
+//===-- NativeThreadProtocol.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_NativeThreadProtocol_h_
+#define liblldb_NativeThreadProtocol_h_
+
+#include <memory>
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Debug.h"
+
+namespace lldb_private
+{
+    //------------------------------------------------------------------
+    // NativeThreadProtocol
+    //------------------------------------------------------------------
+    class NativeThreadProtocol:
+        public std::enable_shared_from_this<NativeThreadProtocol>
+    {
+    public:
+        NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid);
+
+        virtual ~NativeThreadProtocol()
+        {
+        }
+
+        virtual const char *
+        GetName() = 0;
+
+        virtual lldb::StateType
+        GetState () = 0;
+
+        virtual NativeRegisterContextSP
+        GetRegisterContext () = 0;
+
+        virtual Error
+        ReadRegister (uint32_t reg, RegisterValue &reg_value);
+
+        virtual Error
+        WriteRegister (uint32_t reg, const RegisterValue &reg_value);
+
+        virtual Error
+        SaveAllRegisters (lldb::DataBufferSP &data_sp);
+
+        virtual Error
+        RestoreAllRegisters (lldb::DataBufferSP &data_sp);
+
+        virtual bool
+        GetStopReason (ThreadStopInfo &stop_info) = 0;
+
+        virtual uint32_t
+        TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const;
+
+        lldb::tid_t
+        GetID() const
+        {
+            return m_tid;
+        }
+
+        NativeProcessProtocolSP
+        GetProcess ();
+
+        // ---------------------------------------------------------------------
+        // Thread-specific watchpoints
+        // ---------------------------------------------------------------------
+        virtual Error
+        SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0;
+
+        virtual Error
+        RemoveWatchpoint (lldb::addr_t addr) = 0;
+
+    protected:
+        NativeProcessProtocolWP m_process_wp;
+        lldb::tid_t m_tid;
+    };
+}
+
+#endif // #ifndef liblldb_NativeThreadProtocol_h_

Added: lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp (added)
+++ lldb/trunk/source/Host/common/SoftwareBreakpoint.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,296 @@
+//===-- SoftwareBreakpoint.cpp ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SoftwareBreakpoint.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/Mutex.h"
+
+#include "NativeProcessProtocol.h"
+
+using namespace lldb_private;
+
+// -------------------------------------------------------------------
+// static members
+// -------------------------------------------------------------------
+
+Error
+SoftwareBreakpoint::CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_sp)
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+    // Validate the address.
+    if (addr == LLDB_INVALID_ADDRESS)
+        return Error ("SoftwareBreakpoint::%s invalid load address specified.", __FUNCTION__);
+
+    // Ask the NativeProcessProtocol subclass to fill in the correct software breakpoint
+    // trap for the breakpoint site.
+    size_t bp_opcode_size = 0;
+    const uint8_t *bp_opcode_bytes = NULL;
+    Error error = process.GetSoftwareBreakpointTrapOpcode (size_hint, bp_opcode_size, bp_opcode_bytes);
+
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to retrieve software breakpoint trap opcode: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+
+    // Validate size of trap opcode.
+    if (bp_opcode_size == 0)
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to retrieve any trap opcodes", __FUNCTION__);
+        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+    }
+
+    if (bp_opcode_size > MAX_TRAP_OPCODE_SIZE)
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s cannot support %lu trapcode bytes, max size is %lu", __FUNCTION__, bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned too many trap opcode bytes: requires %lu but we only support a max of %lu", bp_opcode_size, MAX_TRAP_OPCODE_SIZE);
+    }
+
+    // Validate that we received opcodes.
+    if (!bp_opcode_bytes)
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to retrieve trap opcode bytes", __FUNCTION__);
+        return Error ("SoftwareBreakpoint::GetSoftwareBreakpointTrapOpcode() returned NULL trap opcode bytes, unable to get breakpoint trap for address 0x%" PRIx64, addr);
+    }
+
+    // Enable the breakpoint.
+    uint8_t saved_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+    error = EnableSoftwareBreakpoint (process, addr, bp_opcode_size, bp_opcode_bytes, saved_opcode_bytes);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s: failed to enable new breakpoint at 0x%" PRIx64 ": %s", __FUNCTION__, addr, error.AsCString ());
+        return error;
+    }
+
+    if (log)
+        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+    // Set the breakpoint and verified it was written properly.  Now
+    // create a breakpoint remover that understands how to undo this
+    // breakpoint.
+    breakpoint_sp.reset (new SoftwareBreakpoint (process, addr, saved_opcode_bytes, bp_opcode_bytes, bp_opcode_size));
+    return Error ();
+}
+
+Error
+SoftwareBreakpoint::EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes)
+{
+    assert (bp_opcode_size <= MAX_TRAP_OPCODE_SIZE && "bp_opcode_size out of valid range");
+    assert (bp_opcode_bytes && "bp_opcode_bytes is NULL");
+    assert (saved_opcode_bytes && "saved_opcode_bytes is NULL");
+
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+
+    // Save the original opcodes by reading them so we can restore later.
+    lldb::addr_t bytes_read = 0;
+
+    Error error = process.ReadMemory(addr, saved_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_read);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+
+    // Ensure we read as many bytes as we expected.
+    if (bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
+        return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to set breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_read);
+    }
+
+    // Write a software breakpoint in place of the original opcode.
+    lldb::addr_t bytes_written = 0;
+    error = process.WriteMemory (addr, bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), bytes_written);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to write memory while attempting to set breakpoint: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+
+    // Ensure we wrote as many bytes as we expected.
+    if (bytes_written != static_cast<lldb::addr_t> (bp_opcode_size))
+    {
+        error.SetErrorStringWithFormat("SoftwareBreakpoint::%s failed write memory while attempting to set breakpoint: attempted to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, bp_opcode_size, bytes_written);
+        if (log)
+            log->PutCString (error.AsCString ());
+        return error;
+    }
+
+    uint8_t verify_bp_opcode_bytes [MAX_TRAP_OPCODE_SIZE];
+    lldb::addr_t verify_bytes_read = 0;
+    error = process.ReadMemory(addr, verify_bp_opcode_bytes, static_cast<lldb::addr_t> (bp_opcode_size), verify_bytes_read);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify the breakpoint set: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+
+    // Ensure we read as many verification bytes as we expected.
+    if (verify_bytes_read != static_cast<lldb::addr_t> (bp_opcode_size))
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
+        return Error ("SoftwareBreakpoint::%s failed to read memory while attempting to verify breakpoint: attempted to read %lu bytes but only read %" PRIu64, __FUNCTION__, bp_opcode_size, verify_bytes_read);
+    }
+
+    if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) != 0)
+    {
+        if (log)
+            log->Printf ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+        return Error ("SoftwareBreakpoint::%s: verification of software breakpoint writing failed - trap opcodes not successfully read back after writing when setting breakpoint at 0x%" PRIx64, __FUNCTION__, addr);
+    }
+
+    if (log)
+        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, addr);
+
+    return Error ();
+}
+
+// -------------------------------------------------------------------
+// instance-level members
+// -------------------------------------------------------------------
+
+SoftwareBreakpoint::SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size) :
+    NativeBreakpoint (addr),
+    m_process (process),
+    m_saved_opcodes (),
+    m_trap_opcodes (),
+    m_opcode_size (opcode_size)
+{
+    assert ( opcode_size > 0 && "setting software breakpoint with no trap opcodes");
+    assert ( opcode_size <= MAX_TRAP_OPCODE_SIZE  && "trap opcode size too large");
+
+    ::memcpy (m_saved_opcodes, saved_opcodes, opcode_size);
+    ::memcpy (m_trap_opcodes, trap_opcodes, opcode_size);
+}
+
+Error
+SoftwareBreakpoint::DoEnable ()
+{
+    return EnableSoftwareBreakpoint (m_process, m_addr, m_opcode_size, m_trap_opcodes, m_saved_opcodes);
+}
+
+Error
+SoftwareBreakpoint::DoDisable ()
+{
+    Error error;
+    assert (m_addr && (m_addr != LLDB_INVALID_ADDRESS) && "can't remove a software breakpoint for an invalid address");
+
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+    if (log)
+        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, m_addr);
+
+    assert ( (m_opcode_size > 0) && "cannot restore opcodes when there are no opcodes");
+
+    if (m_opcode_size > 0)
+    {
+        // Clear a software breakoint instruction
+        uint8_t curr_break_op [MAX_TRAP_OPCODE_SIZE];
+        bool break_op_found = false;
+        assert (m_opcode_size <= sizeof (curr_break_op));
+
+        // Read the breakpoint opcode
+        lldb::addr_t bytes_read = 0;
+        error = m_process.ReadMemory (m_addr, curr_break_op, m_opcode_size, bytes_read);
+        if (error.Success () && (bytes_read < static_cast<lldb::addr_t> (m_opcode_size)))
+        {
+            error.SetErrorStringWithFormat ("SoftwareBreakpointr::%s addr=0x%" PRIx64 ": tried to read %lu bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_read);
+        }
+        if (error.Success ())
+        {
+            bool verify = false;
+            // Make sure we have the a breakpoint opcode exists at this address
+            if (::memcmp (curr_break_op, m_trap_opcodes, m_opcode_size) == 0)
+            {
+                break_op_found = true;
+                // We found a valid breakpoint opcode at this address, now restore
+                // the saved opcode.
+                lldb::addr_t bytes_written = 0;
+                error = m_process.WriteMemory (m_addr, m_saved_opcodes, m_opcode_size, bytes_written);
+                if (error.Success () && (bytes_written < static_cast<lldb::addr_t> (m_opcode_size)))
+                {
+                    error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to write %lu bytes but only wrote %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, bytes_written);
+                }
+                if (error.Success ())
+                {
+                    verify = true;
+                }
+            }
+            else
+            {
+                error.SetErrorString("Original breakpoint trap is no longer in memory.");
+                // Set verify to true and so we can check if the original opcode has already been restored
+                verify = true;
+            }
+
+            if (verify)
+            {
+                uint8_t verify_opcode [MAX_TRAP_OPCODE_SIZE];
+                assert (m_opcode_size <= sizeof (verify_opcode));
+                // Verify that our original opcode made it back to the inferior
+
+                lldb::addr_t verify_bytes_read = 0;
+                error = m_process.ReadMemory (m_addr, verify_opcode, m_opcode_size, verify_bytes_read);
+                if (error.Success () && (verify_bytes_read < static_cast<lldb::addr_t> (m_opcode_size)))
+                {
+                    error.SetErrorStringWithFormat ("SoftwareBreakpoint::%s addr=0x%" PRIx64 ": tried to read %lu verification bytes but only read %" PRIu64, __FUNCTION__, m_addr, m_opcode_size, verify_bytes_read);
+                }
+                if (error.Success ())
+                {
+                    // compare the memory we just read with the original opcode
+                    if (::memcmp (m_saved_opcodes, verify_opcode, m_opcode_size) == 0)
+                    {
+                        // SUCCESS
+                        if (log)
+                            log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- SUCCESS", __FUNCTION__, m_addr);
+                        return error;
+                    }
+                    else
+                    {
+                        if (break_op_found)
+                            error.SetErrorString("Failed to restore original opcode.");
+                    }
+                }
+                else
+                    error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+            }
+        }
+    }
+
+    if (log && error.Fail ())
+        log->Printf ("SoftwareBreakpoint::%s addr = 0x%" PRIx64 " -- FAILED: %s",
+                __FUNCTION__,
+                m_addr,
+                error.AsCString());
+    return error;
+}
+
+bool
+SoftwareBreakpoint::IsSoftwareBreakpoint () const
+{
+    return true;
+}
+

Added: lldb/trunk/source/Host/common/SoftwareBreakpoint.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/SoftwareBreakpoint.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Host/common/SoftwareBreakpoint.h (added)
+++ lldb/trunk/source/Host/common/SoftwareBreakpoint.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,51 @@
+//===-- SoftwareBreakpoint.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_SoftwareBreakpoint_h_
+#define liblldb_SoftwareBreakpoint_h_
+
+#include "lldb/lldb-private-forward.h"
+#include "NativeBreakpoint.h"
+
+namespace lldb_private
+{
+    class SoftwareBreakpoint : public NativeBreakpoint
+    {
+    public:
+        static Error
+        CreateSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t size_hint, NativeBreakpointSP &breakpoint_spn);
+
+        SoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, const uint8_t *saved_opcodes, const uint8_t *trap_opcodes, size_t opcode_size);
+
+    protected:
+        Error
+        DoEnable () override;
+
+        Error
+        DoDisable () override;
+
+        bool
+        IsSoftwareBreakpoint () const override;
+
+    private:
+        /// Max number of bytes that a software trap opcode sequence can occupy.
+        static const size_t MAX_TRAP_OPCODE_SIZE = 8;
+
+        NativeProcessProtocol &m_process;
+        uint8_t m_saved_opcodes [MAX_TRAP_OPCODE_SIZE];
+        uint8_t m_trap_opcodes [MAX_TRAP_OPCODE_SIZE];
+        const size_t m_opcode_size;
+
+        static Error
+        EnableSoftwareBreakpoint (NativeProcessProtocol &process, lldb::addr_t addr, size_t bp_opcode_size, const uint8_t *bp_opcode_bytes, uint8_t *saved_opcode_bytes);
+
+    };
+}
+
+#endif // #ifndef liblldb_SoftwareBreakpoint_h_

Modified: lldb/trunk/source/Host/linux/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/linux/Host.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Host/linux/Host.cpp (original)
+++ lldb/trunk/source/Host/linux/Host.cpp Mon Jun 30 16:05:18 2014
@@ -175,6 +175,12 @@ Host::GetAuxvData(lldb_private::Process
     return ProcFileReader::ReadIntoDataBuffer (process->GetID(), "auxv");
 }
 
+lldb::DataBufferSP
+Host::GetAuxvData (lldb::pid_t pid)
+{
+    return ProcFileReader::ReadIntoDataBuffer (pid, "auxv");
+}
+
 static bool
 IsDirNumeric(const char *dname)
 {

Modified: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp Mon Jun 30 16:05:18 2014
@@ -57,11 +57,10 @@ ParseAuxvEntry(DataExtractor &data,
 DataBufferSP
 AuxVector::GetAuxvData()
 {
-#if defined(__linux__) || defined(__FreeBSD__)
-    if (m_process->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
-        return static_cast<ProcessElfCore *>(m_process)->GetAuxvData();
-#endif
-    return lldb_private::Host::GetAuxvData(m_process);
+    if (m_process)
+        return m_process->GetAuxvData ();
+    else
+        return DataBufferSP ();
 }
 
 void

Modified: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp Mon Jun 30 16:05:18 2014
@@ -14,6 +14,7 @@
 #include "lldb/Core/Error.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/Symbol.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
@@ -28,21 +29,61 @@ using namespace lldb_private;
 static addr_t
 ResolveRendezvousAddress(Process *process)
 {
+    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
     addr_t info_location;
     addr_t info_addr;
     Error error;
 
+    // Try to get it from our process.  This might be a remote process and might
+    // grab it via some remote-specific mechanism.
     info_location = process->GetImageInfoAddress();
+    if (log)
+        log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
 
+    // If the process fails to return an address, fall back to seeing if the local object file can help us find it.
     if (info_location == LLDB_INVALID_ADDRESS)
+    {
+        Target *target = process ? &process->GetTarget() : nullptr;
+        if (target)
+        {
+            ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+            Address addr = obj_file->GetImageInfoAddress(target);
+
+            if (addr.IsValid())
+            {
+                info_location = addr.GetLoadAddress(target);
+                if (log)
+                    log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location);
+            }
+            else
+            {
+                if (log)
+                    log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__);
+            }
+        }
+    }
+
+    if (info_location == LLDB_INVALID_ADDRESS)
+    {
+        if (log)
+            log->Printf ("%s FAILED - invalid info address", __FUNCTION__);
         return LLDB_INVALID_ADDRESS;
+    }
 
     info_addr = process->ReadPointerFromMemory(info_location, error);
     if (error.Fail())
+    {
+        if (log)
+            log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ());
         return LLDB_INVALID_ADDRESS;
+    }
 
     if (info_addr == 0)
+    {
+        if (log)
+            log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location);
         return LLDB_INVALID_ADDRESS;
+    }
 
     return info_addr;
 }
@@ -56,6 +97,8 @@ DYLDRendezvous::DYLDRendezvous(Process *
       m_added_soentries(),
       m_removed_soentries()
 {
+    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
     m_thread_info.valid = false;
 
     // Cache a copy of the executable path
@@ -63,13 +106,24 @@ DYLDRendezvous::DYLDRendezvous(Process *
     {
         Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
         if (exe_mod)
+        {
             exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+            if (log)
+                log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'", __FUNCTION__, m_exe_path);
+        }
+        else
+        {
+            if (log)
+                log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__);
+        }
     }
 }
 
 bool
 DYLDRendezvous::Resolve()
 {
+    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
     const size_t word_size = 4;
     Rendezvous info;
     size_t address_size;
@@ -79,12 +133,16 @@ DYLDRendezvous::Resolve()
 
     address_size = m_process->GetAddressByteSize();
     padding = address_size - word_size;
+    if (log)
+        log->Printf ("DYLDRendezvous::%s address size: %zu, padding %zu", __FUNCTION__, address_size, padding);
 
     if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
         cursor = info_addr = ResolveRendezvousAddress(m_process);
     else
         cursor = info_addr = m_rendezvous_addr;
-    
+    if (log)
+        log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor);
+
     if (cursor == LLDB_INVALID_ADDRESS)
         return false;
 

Modified: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp Mon Jun 30 16:05:18 2014
@@ -33,6 +33,10 @@
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Process.h"
 
+#if defined(__linux__)
+#include "../../Process/Linux/NativeProcessLinux.h"
+#endif
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -487,3 +491,58 @@ PlatformLinux::CalculateTrapHandlerSymbo
 {   
     m_trap_handlers.push_back (ConstString ("_sigtramp"));
 }   
+
+Error
+PlatformLinux::LaunchNativeProcess (
+    ProcessLaunchInfo &launch_info,
+    lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+    NativeProcessProtocolSP &process_sp)
+{
+#if !defined(__linux__)
+    return Error("only implemented on Linux hosts");
+#else
+    if (!IsHost ())
+        return Error("PlatformLinux::%s (): cannot launch a debug process when not the host", __FUNCTION__);
+
+    // Retrieve the exe module.
+    lldb::ModuleSP exe_module_sp;
+
+    Error error = ResolveExecutable (
+        launch_info.GetExecutableFile (),
+        launch_info.GetArchitecture (),
+        exe_module_sp,
+        NULL);
+
+    if (!error.Success ())
+        return error;
+
+    if (!exe_module_sp)
+        return Error("exe_module_sp could not be resolved for %s", launch_info.GetExecutableFile ().GetPath ().c_str ());
+
+    // Launch it for debugging
+    error = NativeProcessLinux::LaunchProcess (
+        exe_module_sp.get (),
+        launch_info,
+        native_delegate,
+        process_sp);
+
+    return error;
+#endif
+}
+
+Error
+PlatformLinux::AttachNativeProcess (lldb::pid_t pid,
+                                    lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+                                    NativeProcessProtocolSP &process_sp)
+{
+#if !defined(__linux__)
+    return Error("only implemented on Linux hosts");
+#else
+    if (!IsHost ())
+        return Error("PlatformLinux::%s (): cannot attach to a debug process when not the host", __FUNCTION__);
+
+    // Launch it for debugging
+    return NativeProcessLinux::AttachToProcess (pid, native_delegate, process_sp);
+#endif
+}
+

Modified: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h (original)
+++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h Mon Jun 30 16:05:18 2014
@@ -103,9 +103,20 @@ namespace lldb_private {
         virtual void
         CalculateTrapHandlerSymbolNames ();
 
+        Error
+        LaunchNativeProcess (
+            ProcessLaunchInfo &launch_info,
+            lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+            NativeProcessProtocolSP &process_sp) override;
+
+        Error
+        AttachNativeProcess (lldb::pid_t pid,
+                             lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+                             NativeProcessProtocolSP &process_sp) override;
+
     protected:
         lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote darwin OS
-        
+
     private:
         DISALLOW_COPY_AND_ASSIGN (PlatformLinux);
     };

Modified: lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -5,10 +5,11 @@ include_directories(../POSIX)
 include_directories(../Utility)
 
 add_lldb_library(lldbPluginProcessLinux
+  NativeProcessLinux.cpp
+  NativeThreadLinux.cpp
   ProcessLinux.cpp
   ProcessMonitor.cpp
   ProcFileReader.cpp
-  LinuxSignals.cpp
   LinuxThread.cpp
   )
 

Removed: lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp?rev=212068&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.cpp (removed)
@@ -1,69 +0,0 @@
-//===-- LinuxSignals.cpp ----------------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// C Includes
-#include <signal.h>
-
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "LinuxSignals.h"
-
-LinuxSignals::LinuxSignals()
-    : UnixSignals()
-{
-    Reset();
-}
-
-void
-LinuxSignals::Reset()
-{
-    m_signals.clear();
-
-#define ADDSIGNAL(S, SUPPRESS, STOP, NOTIFY, DESCRIPTION) \
-    AddSignal(SIG ## S, "SIG" #S, #S, SUPPRESS, STOP, NOTIFY, DESCRIPTION)
-
-    ADDSIGNAL(HUP,    false,  true,  true, "hangup");
-    ADDSIGNAL(INT,    true,   true,  true, "interrupt");
-    ADDSIGNAL(QUIT,   false,  true,  true, "quit");
-    ADDSIGNAL(ILL,    false,  true,  true, "illegal instruction");
-    ADDSIGNAL(TRAP,   true,   true,  true, "trace trap (not reset when caught)");
-    ADDSIGNAL(ABRT,   false,  true,  true, "abort");
-    ADDSIGNAL(IOT,    false,  true,  true, "abort");
-    ADDSIGNAL(BUS,    false,  true,  true, "bus error");
-    ADDSIGNAL(FPE,    false,  true,  true, "floating point exception");
-    ADDSIGNAL(KILL,   false,  true,  true, "kill");
-    ADDSIGNAL(USR1,   false,  true,  true, "user defined signal 1");
-    ADDSIGNAL(SEGV,   false,  true,  true, "segmentation violation");
-    ADDSIGNAL(USR2,   false,  true,  true, "user defined signal 2");
-    ADDSIGNAL(PIPE,   false,  true,  true, "write to pipe with reading end closed");
-    ADDSIGNAL(ALRM,   false,  false, true, "alarm");
-    ADDSIGNAL(TERM,   false,  true,  true, "termination requested");
-#ifdef SIGSTKFLT
-    ADDSIGNAL(STKFLT, false,  true,  true, "stack fault");
-#endif
-    ADDSIGNAL(CHLD,   false,  false, true, "child process exit");
-    ADDSIGNAL(CONT,   false,  true,  true, "process continue");
-    ADDSIGNAL(STOP,   true,   true,  true, "process stop");
-    ADDSIGNAL(TSTP,   false,  true,  true, "tty stop");
-    ADDSIGNAL(TTIN,   false,  true,  true, "background tty read");
-    ADDSIGNAL(TTOU,   false,  true,  true, "background tty write");
-    ADDSIGNAL(URG,    false,  true,  true, "urgent data on socket");
-    ADDSIGNAL(XCPU,   false,  true,  true, "CPU resource exceeded");
-    ADDSIGNAL(XFSZ,   false,  true,  true, "file size limit exceeded");
-    ADDSIGNAL(VTALRM, false,  true,  true, "virtual alarm");
-    ADDSIGNAL(PROF,   false,  true,  true, "profiling alarm");
-    ADDSIGNAL(WINCH,  false,  true,  true, "window size change");
-    ADDSIGNAL(POLL,   false,  true,  true, "pollable event");
-    ADDSIGNAL(IO,     false,  true,  true, "input/output ready");
-    ADDSIGNAL(PWR,    false,  true,  true, "power failure");
-    ADDSIGNAL(SYS,    false,  true,  true, "invalid system call");
-
-#undef ADDSIGNAL
-}

Removed: lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h?rev=212068&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/LinuxSignals.h (removed)
@@ -1,31 +0,0 @@
-//===-- LinuxSignals.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_LinuxSignals_H_
-#define liblldb_LinuxSignals_H_
-
-// C Includes
-// C++ Includes
-// Other libraries and framework includes
-// Project includes
-#include "lldb/Target/UnixSignals.h"
-
-/// Linux specific set of Unix signals.
-class LinuxSignals
-    : public lldb_private::UnixSignals
-{
-public:
-    LinuxSignals();
-
-private:
-    void
-    Reset();
-};
-
-#endif

Added: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,3465 @@
+//===-- NativeProcessLinux.cpp -------------------------------- -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "NativeProcessLinux.h"
+
+// C Includes
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <linux/unistd.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+
+// C++ Includes
+#include <fstream>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include "Host/common/NativeBreakpoint.h"
+#include "Utility/StringExtractor.h"
+
+#include "Plugins/Process/Utility/LinuxSignals.h"
+#include "NativeThreadLinux.h"
+#include "ProcFileReader.h"
+#include "ProcessPOSIXLog.h"
+
+#define DEBUG_PTRACE_MAXBYTES 20
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS 12
+#endif
+#ifndef PTRACE_SETREGS
+  #define PTRACE_SETREGS 13
+#endif
+#ifndef PTRACE_GETREGSET
+  #define PTRACE_GETREGSET 0x4204
+#endif
+#ifndef PTRACE_SETREGSET
+  #define PTRACE_SETREGSET 0x4205
+#endif
+#ifndef PTRACE_GET_THREAD_AREA
+  #define PTRACE_GET_THREAD_AREA 25
+#endif
+#ifndef PTRACE_ARCH_PRCTL
+  #define PTRACE_ARCH_PRCTL      30
+#endif
+#ifndef ARCH_GET_FS
+  #define ARCH_SET_GS 0x1001
+  #define ARCH_SET_FS 0x1002
+  #define ARCH_GET_FS 0x1003
+  #define ARCH_GET_GS 0x1004
+#endif
+
+
+// Support hardware breakpoints in case it has not been defined
+#ifndef TRAP_HWBKPT
+  #define TRAP_HWBKPT 4
+#endif
+
+// Try to define a macro to encapsulate the tgkill syscall
+// fall back on kill() if tgkill isn't available
+#define tgkill(pid, tid, sig)  syscall(SYS_tgkill, pid, tid, sig)
+
+// We disable the tracing of ptrace calls for integration builds to
+// avoid the additional indirection and checks.
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+#define PTRACE(req, pid, addr, data, data_size) \
+    PtraceWrapper((req), (pid), (addr), (data), (data_size), #req, __FILE__, __LINE__)
+#else
+#define PTRACE(req, pid, addr, data, data_size) \
+    PtraceWrapper((req), (pid), (addr), (data), (data_size))
+#endif
+
+// Private bits we only need internally.
+namespace
+{
+    using namespace lldb;
+    using namespace lldb_private;
+
+    const UnixSignals&
+    GetUnixSignals ()
+    {
+        static process_linux::LinuxSignals signals;
+        return signals;
+    }
+
+    const char *
+    GetFilePath (const lldb_private::ProcessLaunchInfo::FileAction *file_action, const char *default_path)
+    {
+        const char *pts_name = "/dev/pts/";
+        const char *path = NULL;
+
+        if (file_action)
+        {
+            if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+            {
+                path = file_action->GetPath ();
+                // By default the stdio paths passed in will be pseudo-terminal
+                // (/dev/pts). If so, convert to using a different default path
+                // instead to redirect I/O to the debugger console. This should
+                //  also handle user overrides to /dev/null or a different file.
+                if (!path || ::strncmp (path, pts_name, ::strlen (pts_name)) == 0)
+                    path = default_path;
+            }
+        }
+
+        return path;
+    }
+
+    Error
+    ResolveProcessArchitecture (lldb::pid_t pid, Platform &platform, ArchSpec &arch)
+    {
+        // Grab process info for the running process.
+        ProcessInstanceInfo process_info;
+        if (!platform.GetProcessInfo (pid, process_info))
+            return lldb_private::Error("failed to get process info");
+
+        // Resolve the executable module.
+        ModuleSP exe_module_sp;
+        FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths ());
+        Error error = platform.ResolveExecutable(
+            process_info.GetExecutableFile (),
+            platform.GetSystemArchitecture (),
+            exe_module_sp,
+            executable_search_paths.GetSize () ? &executable_search_paths : NULL);
+
+        if (!error.Success ())
+            return error;
+
+        // Check if we've got our architecture from the exe_module.
+        arch = exe_module_sp->GetArchitecture ();
+        if (arch.IsValid ())
+            return Error();
+        else
+            return Error("failed to retrieve a valid architecture from the exe module");
+    }
+
+    void
+    DisplayBytes (lldb_private::StreamString &s, void *bytes, uint32_t count)
+    {
+        uint8_t *ptr = (uint8_t *)bytes;
+        const uint32_t loop_count = std::min<uint32_t>(DEBUG_PTRACE_MAXBYTES, count);
+        for(uint32_t i=0; i<loop_count; i++)
+        {
+            s.Printf ("[%x]", *ptr);
+            ptr++;
+        }
+    }
+
+    void
+    PtraceDisplayBytes(int &req, void *data, size_t data_size)
+    {
+        StreamString buf;
+        Log *verbose_log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (
+                    POSIX_LOG_PTRACE | POSIX_LOG_VERBOSE));
+
+        if (verbose_log)
+        {
+            switch(req)
+            {
+            case PTRACE_POKETEXT:
+            {
+                DisplayBytes(buf, &data, 8);
+                verbose_log->Printf("PTRACE_POKETEXT %s", buf.GetData());
+                break;
+            }
+            case PTRACE_POKEDATA:
+            {
+                DisplayBytes(buf, &data, 8);
+                verbose_log->Printf("PTRACE_POKEDATA %s", buf.GetData());
+                break;
+            }
+            case PTRACE_POKEUSER:
+            {
+                DisplayBytes(buf, &data, 8);
+                verbose_log->Printf("PTRACE_POKEUSER %s", buf.GetData());
+                break;
+            }
+            case PTRACE_SETREGS:
+            {
+                DisplayBytes(buf, data, data_size);
+                verbose_log->Printf("PTRACE_SETREGS %s", buf.GetData());
+                break;
+            }
+            case PTRACE_SETFPREGS:
+            {
+                DisplayBytes(buf, data, data_size);
+                verbose_log->Printf("PTRACE_SETFPREGS %s", buf.GetData());
+                break;
+            }
+            case PTRACE_SETSIGINFO:
+            {
+                DisplayBytes(buf, data, sizeof(siginfo_t));
+                verbose_log->Printf("PTRACE_SETSIGINFO %s", buf.GetData());
+                break;
+            }
+            case PTRACE_SETREGSET:
+            {
+                // Extract iov_base from data, which is a pointer to the struct IOVEC
+                DisplayBytes(buf, *(void **)data, data_size);
+                verbose_log->Printf("PTRACE_SETREGSET %s", buf.GetData());
+                break;
+            }
+            default:
+            {
+            }
+            }
+        }
+    }
+
+    // Wrapper for ptrace to catch errors and log calls.
+    // Note that ptrace sets errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*)
+    long
+    PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size,
+            const char* reqName, const char* file, int line)
+    {
+        long int result;
+
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE));
+
+        PtraceDisplayBytes(req, data, data_size);
+
+        errno = 0;
+        if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
+            result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), *(unsigned int *)addr, data);
+        else
+            result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), addr, data);
+
+        if (log)
+            log->Printf("ptrace(%s, %" PRIu64 ", %p, %p, %zu)=%lX called from file %s line %d",
+                    reqName, pid, addr, data, data_size, result, file, line);
+
+        PtraceDisplayBytes(req, data, data_size);
+
+        if (log && errno != 0)
+        {
+            const char* str;
+            switch (errno)
+            {
+            case ESRCH:  str = "ESRCH"; break;
+            case EINVAL: str = "EINVAL"; break;
+            case EBUSY:  str = "EBUSY"; break;
+            case EPERM:  str = "EPERM"; break;
+            default:     str = "<unknown>";
+            }
+            log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
+        }
+
+        return result;
+    }
+
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+    // Wrapper for ptrace when logging is not required.
+    // Sets errno to 0 prior to calling ptrace.
+    long
+    PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size)
+    {
+        long result = 0;
+        errno = 0;
+        if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
+            result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), *(unsigned int *)addr, data);
+        else
+            result = ptrace(static_cast<__ptrace_request>(req), static_cast<::pid_t>(pid), addr, data);
+        return result;
+    }
+#endif
+
+    //------------------------------------------------------------------------------
+    // Static implementations of NativeProcessLinux::ReadMemory and
+    // NativeProcessLinux::WriteMemory.  This enables mutual recursion between these
+    // functions without needed to go thru the thread funnel.
+
+    static lldb::addr_t
+    DoReadMemory (
+        lldb::pid_t pid,
+        lldb::addr_t vm_addr,
+        void *buf,
+        lldb::addr_t size,
+        Error &error)
+    {
+        // ptrace word size is determined by the host, not the child
+        static const unsigned word_size = sizeof(void*);
+        unsigned char *dst = static_cast<unsigned char*>(buf);
+        lldb::addr_t bytes_read;
+        lldb::addr_t remainder;
+        long data;
+
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL));
+        if (log)
+            ProcessPOSIXLog::IncNestLevel();
+        if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY))
+            log->Printf ("NativeProcessLinux::%s(%" PRIu64 ", %d, %p, %p, %zd, _)", __FUNCTION__,
+                    pid, word_size, (void*)vm_addr, buf, size);
+
+        assert(sizeof(data) >= word_size);
+        for (bytes_read = 0; bytes_read < size; bytes_read += remainder)
+        {
+            errno = 0;
+            data = PTRACE(PTRACE_PEEKDATA, pid, (void*)vm_addr, NULL, 0);
+            if (errno)
+            {
+                error.SetErrorToErrno();
+                if (log)
+                    ProcessPOSIXLog::DecNestLevel();
+                return bytes_read;
+            }
+
+            remainder = size - bytes_read;
+            remainder = remainder > word_size ? word_size : remainder;
+
+            // Copy the data into our buffer
+            for (unsigned i = 0; i < remainder; ++i)
+                dst[i] = ((data >> i*8) & 0xFF);
+
+            if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+                    (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+                            (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+                                    size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+            {
+                uintptr_t print_dst = 0;
+                // Format bytes from data by moving into print_dst for log output
+                for (unsigned i = 0; i < remainder; ++i)
+                    print_dst |= (((data >> i*8) & 0xFF) << i*8);
+                log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+                        (void*)vm_addr, print_dst, (unsigned long)data);
+            }
+
+            vm_addr += word_size;
+            dst += word_size;
+        }
+
+        if (log)
+            ProcessPOSIXLog::DecNestLevel();
+        return bytes_read;
+    }
+
+    static lldb::addr_t
+    DoWriteMemory(
+        lldb::pid_t pid,
+        lldb::addr_t vm_addr,
+        const void *buf,
+        lldb::addr_t size,
+        Error &error)
+    {
+        // ptrace word size is determined by the host, not the child
+        static const unsigned word_size = sizeof(void*);
+        const unsigned char *src = static_cast<const unsigned char*>(buf);
+        lldb::addr_t bytes_written = 0;
+        lldb::addr_t remainder;
+
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL));
+        if (log)
+            ProcessPOSIXLog::IncNestLevel();
+        if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY))
+            log->Printf ("NativeProcessLinux::%s(%" PRIu64 ", %u, %p, %p, %" PRIu64 ")", __FUNCTION__,
+                    pid, word_size, (void*)vm_addr, buf, size);
+
+        for (bytes_written = 0; bytes_written < size; bytes_written += remainder)
+        {
+            remainder = size - bytes_written;
+            remainder = remainder > word_size ? word_size : remainder;
+
+            if (remainder == word_size)
+            {
+                unsigned long data = 0;
+                assert(sizeof(data) >= word_size);
+                for (unsigned i = 0; i < word_size; ++i)
+                    data |= (unsigned long)src[i] << i*8;
+
+                if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+                        (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+                                (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+                                        size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+                    log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+                            (void*)vm_addr, *(unsigned long*)src, data);
+
+                if (PTRACE(PTRACE_POKEDATA, pid, (void*)vm_addr, (void*)data, 0))
+                {
+                    error.SetErrorToErrno();
+                    if (log)
+                        ProcessPOSIXLog::DecNestLevel();
+                    return bytes_written;
+                }
+            }
+            else
+            {
+                unsigned char buff[8];
+                if (DoReadMemory(pid, vm_addr,
+                                buff, word_size, error) != word_size)
+                {
+                    if (log)
+                        ProcessPOSIXLog::DecNestLevel();
+                    return bytes_written;
+                }
+
+                memcpy(buff, src, remainder);
+
+                if (DoWriteMemory(pid, vm_addr,
+                                buff, word_size, error) != word_size)
+                {
+                    if (log)
+                        ProcessPOSIXLog::DecNestLevel();
+                    return bytes_written;
+                }
+
+                if (log && ProcessPOSIXLog::AtTopNestLevel() &&
+                        (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) ||
+                                (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) &&
+                                        size <= POSIX_LOG_MEMORY_SHORT_BYTES)))
+                    log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__,
+                            (void*)vm_addr, *(unsigned long*)src, *(unsigned long*)buff);
+            }
+
+            vm_addr += word_size;
+            src += word_size;
+        }
+        if (log)
+            ProcessPOSIXLog::DecNestLevel();
+        return bytes_written;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class Operation
+    /// @brief Represents a NativeProcessLinux operation.
+    ///
+    /// Under Linux, it is not possible to ptrace() from any other thread but the
+    /// one that spawned or attached to the process from the start.  Therefore, when
+    /// a NativeProcessLinux is asked to deliver or change the state of an inferior
+    /// process the operation must be "funneled" to a specific thread to perform the
+    /// task.  The Operation class provides an abstract base for all services the
+    /// NativeProcessLinux must perform via the single virtual function Execute, thus
+    /// encapsulating the code that needs to run in the privileged context.
+    class Operation
+    {
+    public:
+        Operation () : m_error() { }
+
+        virtual
+        ~Operation() {}
+
+        virtual void
+        Execute (NativeProcessLinux *process) = 0;
+
+        const Error &
+        GetError () const { return m_error; }
+
+    protected:
+        Error m_error;
+    };
+
+    //------------------------------------------------------------------------------
+    /// @class ReadOperation
+    /// @brief Implements NativeProcessLinux::ReadMemory.
+    class ReadOperation : public Operation
+    {
+    public:
+        ReadOperation (
+            lldb::addr_t addr,
+            void *buff,
+            lldb::addr_t size,
+            size_t &result) :
+            Operation (),
+            m_addr (addr),
+            m_buff (buff),
+            m_size (size),
+            m_result (result)
+            {
+            }
+
+        void Execute (NativeProcessLinux *process) override;
+
+    private:
+        lldb::addr_t m_addr;
+        void *m_buff;
+        lldb::addr_t m_size;
+        lldb::addr_t &m_result;
+    };
+
+    void
+    ReadOperation::Execute (NativeProcessLinux *process)
+    {
+        m_result = DoReadMemory (process->GetID (), m_addr, m_buff, m_size, m_error);
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class WriteOperation
+    /// @brief Implements NativeProcessLinux::WriteMemory.
+    class WriteOperation : public Operation
+    {
+    public:
+        WriteOperation (
+            lldb::addr_t addr,
+            const void *buff,
+            lldb::addr_t size,
+            lldb::addr_t &result) :
+            Operation (),
+            m_addr (addr),
+            m_buff (buff),
+            m_size (size),
+            m_result (result)
+            {
+            }
+
+        void Execute (NativeProcessLinux *process) override;
+
+    private:
+        lldb::addr_t m_addr;
+        const void *m_buff;
+        lldb::addr_t m_size;
+        lldb::addr_t &m_result;
+    };
+
+    void
+    WriteOperation::Execute(NativeProcessLinux *process)
+    {
+        m_result = DoWriteMemory (process->GetID (), m_addr, m_buff, m_size, m_error);
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class ReadRegOperation
+    /// @brief Implements NativeProcessLinux::ReadRegisterValue.
+    class ReadRegOperation : public Operation
+    {
+    public:
+        ReadRegOperation(lldb::tid_t tid, uint32_t offset, const char *reg_name,
+                RegisterValue &value, bool &result)
+            : m_tid(tid), m_offset(static_cast<uintptr_t> (offset)), m_reg_name(reg_name),
+              m_value(value), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        uintptr_t m_offset;
+        const char *m_reg_name;
+        RegisterValue &m_value;
+        bool &m_result;
+    };
+
+    void
+    ReadRegOperation::Execute(NativeProcessLinux *monitor)
+    {
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+
+        // Set errno to zero so that we can detect a failed peek.
+        errno = 0;
+        lldb::addr_t data = PTRACE(PTRACE_PEEKUSER, m_tid, (void*)m_offset, NULL, 0);
+        if (errno)
+            m_result = false;
+        else
+        {
+            m_value = data;
+            m_result = true;
+        }
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() reg %s: 0x%" PRIx64, __FUNCTION__,
+                    m_reg_name, data);
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class WriteRegOperation
+    /// @brief Implements NativeProcessLinux::WriteRegisterValue.
+    class WriteRegOperation : public Operation
+    {
+    public:
+        WriteRegOperation(lldb::tid_t tid, unsigned offset, const char *reg_name,
+                const RegisterValue &value, bool &result)
+            : m_tid(tid), m_offset(offset), m_reg_name(reg_name),
+              m_value(value), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        uintptr_t m_offset;
+        const char *m_reg_name;
+        const RegisterValue &m_value;
+        bool &m_result;
+    };
+
+    void
+    WriteRegOperation::Execute(NativeProcessLinux *monitor)
+    {
+        void* buf;
+        Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+
+        buf = (void*) m_value.GetAsUInt64();
+
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() reg %s: %p", __FUNCTION__, m_reg_name, buf);
+        if (PTRACE(PTRACE_POKEUSER, m_tid, (void*)m_offset, buf, 0))
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class ReadGPROperation
+    /// @brief Implements NativeProcessLinux::ReadGPR.
+    class ReadGPROperation : public Operation
+    {
+    public:
+        ReadGPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+            : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        void *m_buf;
+        size_t m_buf_size;
+        bool &m_result;
+    };
+
+    void
+    ReadGPROperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_GETREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class ReadFPROperation
+    /// @brief Implements NativeProcessLinux::ReadFPR.
+    class ReadFPROperation : public Operation
+    {
+    public:
+        ReadFPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+            : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        void *m_buf;
+        size_t m_buf_size;
+        bool &m_result;
+    };
+
+    void
+    ReadFPROperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_GETFPREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class ReadRegisterSetOperation
+    /// @brief Implements NativeProcessLinux::ReadRegisterSet.
+    class ReadRegisterSetOperation : public Operation
+    {
+    public:
+        ReadRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result)
+            : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        void *m_buf;
+        size_t m_buf_size;
+        const unsigned int m_regset;
+        bool &m_result;
+    };
+
+    void
+    ReadRegisterSetOperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_GETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0)
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class WriteGPROperation
+    /// @brief Implements NativeProcessLinux::WriteGPR.
+    class WriteGPROperation : public Operation
+    {
+    public:
+        WriteGPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+            : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        void *m_buf;
+        size_t m_buf_size;
+        bool &m_result;
+    };
+
+    void
+    WriteGPROperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_SETREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class WriteFPROperation
+    /// @brief Implements NativeProcessLinux::WriteFPR.
+    class WriteFPROperation : public Operation
+    {
+    public:
+        WriteFPROperation(lldb::tid_t tid, void *buf, size_t buf_size, bool &result)
+            : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        void *m_buf;
+        size_t m_buf_size;
+        bool &m_result;
+    };
+
+    void
+    WriteFPROperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_SETFPREGS, m_tid, NULL, m_buf, m_buf_size) < 0)
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class WriteRegisterSetOperation
+    /// @brief Implements NativeProcessLinux::WriteRegisterSet.
+    class WriteRegisterSetOperation : public Operation
+    {
+    public:
+        WriteRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result)
+            : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result)
+            { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        void *m_buf;
+        size_t m_buf_size;
+        const unsigned int m_regset;
+        bool &m_result;
+    };
+
+    void
+    WriteRegisterSetOperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_SETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0)
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class ResumeOperation
+    /// @brief Implements NativeProcessLinux::Resume.
+    class ResumeOperation : public Operation
+    {
+    public:
+        ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) :
+            m_tid(tid), m_signo(signo), m_result(result) { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        uint32_t m_signo;
+        bool &m_result;
+    };
+
+    void
+    ResumeOperation::Execute(NativeProcessLinux *monitor)
+    {
+        intptr_t data = 0;
+
+        if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+            data = m_signo;
+
+        if (PTRACE(PTRACE_CONT, m_tid, NULL, (void*)data, 0))
+        {
+            Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+            if (log)
+                log->Printf ("ResumeOperation (%"  PRIu64 ") failed: %s", m_tid, strerror(errno));
+            m_result = false;
+        }
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class SingleStepOperation
+    /// @brief Implements NativeProcessLinux::SingleStep.
+    class SingleStepOperation : public Operation
+    {
+    public:
+        SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result)
+            : m_tid(tid), m_signo(signo), m_result(result) { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        uint32_t m_signo;
+        bool &m_result;
+    };
+
+    void
+    SingleStepOperation::Execute(NativeProcessLinux *monitor)
+    {
+        intptr_t data = 0;
+
+        if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+            data = m_signo;
+
+        if (PTRACE(PTRACE_SINGLESTEP, m_tid, NULL, (void*)data, 0))
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class SiginfoOperation
+    /// @brief Implements NativeProcessLinux::GetSignalInfo.
+    class SiginfoOperation : public Operation
+    {
+    public:
+        SiginfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err)
+            : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        void *m_info;
+        bool &m_result;
+        int &m_err;
+    };
+
+    void
+    SiginfoOperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_GETSIGINFO, m_tid, NULL, m_info, 0)) {
+            m_result = false;
+            m_err = errno;
+        }
+        else
+            m_result = true;
+    }
+
+    //------------------------------------------------------------------------------
+    /// @class EventMessageOperation
+    /// @brief Implements NativeProcessLinux::GetEventMessage.
+    class EventMessageOperation : public Operation
+    {
+    public:
+        EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result)
+            : m_tid(tid), m_message(message), m_result(result) { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        unsigned long *m_message;
+        bool &m_result;
+    };
+
+    void
+    EventMessageOperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (PTRACE(PTRACE_GETEVENTMSG, m_tid, NULL, m_message, 0))
+            m_result = false;
+        else
+            m_result = true;
+    }
+
+    class DetachOperation : public Operation
+    {
+    public:
+        DetachOperation(lldb::tid_t tid, Error &result) : m_tid(tid), m_error(result) { }
+
+        void Execute(NativeProcessLinux *monitor);
+
+    private:
+        lldb::tid_t m_tid;
+        Error &m_error;
+    };
+
+    void
+    DetachOperation::Execute(NativeProcessLinux *monitor)
+    {
+        if (ptrace(PT_DETACH, m_tid, NULL, 0) < 0)
+            m_error.SetErrorToErrno();
+    }
+
+}
+
+using namespace lldb_private;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static bool
+EnsureFDFlags(int fd, int flags, Error &error)
+{
+    int status;
+
+    if ((status = fcntl(fd, F_GETFL)) == -1)
+    {
+        error.SetErrorToErrno();
+        return false;
+    }
+
+    if (fcntl(fd, F_SETFL, status | flags) == -1)
+    {
+        error.SetErrorToErrno();
+        return false;
+    }
+
+    return true;
+}
+
+NativeProcessLinux::OperationArgs::OperationArgs(NativeProcessLinux *monitor)
+    : m_monitor(monitor)
+{
+    sem_init(&m_semaphore, 0, 0);
+}
+
+NativeProcessLinux::OperationArgs::~OperationArgs()
+{
+    sem_destroy(&m_semaphore);
+}
+
+NativeProcessLinux::LaunchArgs::LaunchArgs(NativeProcessLinux *monitor,
+                                       lldb_private::Module *module,
+                                       char const **argv,
+                                       char const **envp,
+                                       const char *stdin_path,
+                                       const char *stdout_path,
+                                       const char *stderr_path,
+                                       const char *working_dir)
+    : OperationArgs(monitor),
+      m_module(module),
+      m_argv(argv),
+      m_envp(envp),
+      m_stdin_path(stdin_path),
+      m_stdout_path(stdout_path),
+      m_stderr_path(stderr_path),
+      m_working_dir(working_dir) { }
+
+NativeProcessLinux::LaunchArgs::~LaunchArgs()
+{ }
+
+NativeProcessLinux::AttachArgs::AttachArgs(NativeProcessLinux *monitor,
+                                       lldb::pid_t pid)
+    : OperationArgs(monitor), m_pid(pid) { }
+
+NativeProcessLinux::AttachArgs::~AttachArgs()
+{ }
+
+// -----------------------------------------------------------------------------
+// Public Static Methods
+// -----------------------------------------------------------------------------
+
+lldb_private::Error
+NativeProcessLinux::LaunchProcess (
+    lldb_private::Module *exe_module,
+    lldb_private::ProcessLaunchInfo &launch_info,
+    lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+    NativeProcessProtocolSP &native_process_sp)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    Error error;
+
+    // Verify the working directory is valid if one was specified.
+    const char* working_dir = launch_info.GetWorkingDirectory ();
+    if (working_dir)
+    {
+      FileSpec working_dir_fs (working_dir, true);
+      if (!working_dir_fs || working_dir_fs.GetFileType () != FileSpec::eFileTypeDirectory)
+      {
+          error.SetErrorStringWithFormat ("No such file or directory: %s", working_dir);
+          return error;
+      }
+    }
+
+    const lldb_private::ProcessLaunchInfo::FileAction *file_action;
+
+    // Default of NULL will mean to use existing open file descriptors.
+    const char *stdin_path = NULL;
+    const char *stdout_path = NULL;
+    const char *stderr_path = NULL;
+
+    file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+    stdin_path = GetFilePath (file_action, stdin_path);
+
+    file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+    stdout_path = GetFilePath (file_action, stdout_path);
+
+    file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+    stderr_path = GetFilePath (file_action, stderr_path);
+
+    // Create the NativeProcessLinux in launch mode.
+    native_process_sp.reset (new NativeProcessLinux ());
+
+    if (log)
+    {
+        int i = 0;
+        for (const char **args = launch_info.GetArguments ().GetConstArgumentVector (); *args; ++args, ++i)
+        {
+            log->Printf ("NativeProcessLinux::%s arg %d: \"%s\"", __FUNCTION__, i, *args ? *args : "nullptr");
+            ++i;
+        }
+    }
+
+    if (!native_process_sp->RegisterNativeDelegate (native_delegate))
+    {
+        native_process_sp.reset ();
+        error.SetErrorStringWithFormat ("failed to register the native delegate");
+        return error;
+    }
+
+    reinterpret_cast<NativeProcessLinux*> (native_process_sp.get ())->LaunchInferior (
+            exe_module,
+            launch_info.GetArguments ().GetConstArgumentVector (),
+            launch_info.GetEnvironmentEntries ().GetConstArgumentVector (),
+            stdin_path,
+            stdout_path,
+            stderr_path,
+            working_dir,
+            error);
+
+    if (error.Fail ())
+    {
+        native_process_sp.reset ();
+        if (log)
+            log->Printf ("NativeProcessLinux::%s failed to launch process: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+
+    launch_info.SetProcessID (native_process_sp->GetID ());
+
+    return error;
+}
+
+lldb_private::Error
+NativeProcessLinux::AttachToProcess (
+    lldb::pid_t pid,
+    lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+    NativeProcessProtocolSP &native_process_sp)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log && log->GetMask ().Test (POSIX_LOG_VERBOSE))
+        log->Printf ("NativeProcessLinux::%s(pid = %" PRIi64 ")", __FUNCTION__, pid);
+
+    // Grab the current platform architecture.  This should be Linux,
+    // since this code is only intended to run on a Linux host.
+    PlatformSP platform_sp (Platform::GetDefaultPlatform ());
+    if (!platform_sp)
+        return Error("failed to get a valid default platform");
+
+    // Retrieve the architecture for the running process.
+    ArchSpec process_arch;
+    Error error = ResolveProcessArchitecture (pid, *platform_sp.get (), process_arch);
+    if (!error.Success ())
+        return error;
+
+    native_process_sp.reset (new NativeProcessLinux ());
+
+    if (!native_process_sp->RegisterNativeDelegate (native_delegate))
+    {
+        native_process_sp.reset (new NativeProcessLinux ());
+        error.SetErrorStringWithFormat ("failed to register the native delegate");
+        return error;
+    }
+
+    reinterpret_cast<NativeProcessLinux*> (native_process_sp.get ())->AttachToInferior (pid, error);
+    if (!error.Success ())
+    {
+        native_process_sp.reset ();
+        return error;
+    }
+
+    return error;
+}
+
+// -----------------------------------------------------------------------------
+// Public Instance Methods
+// -----------------------------------------------------------------------------
+
+NativeProcessLinux::NativeProcessLinux () :
+    NativeProcessProtocol (LLDB_INVALID_PROCESS_ID),
+    m_arch (),
+    m_operation_thread (LLDB_INVALID_HOST_THREAD),
+    m_monitor_thread (LLDB_INVALID_HOST_THREAD),
+    m_operation (nullptr),
+    m_operation_mutex (),
+    m_operation_pending (),
+    m_operation_done (),
+    m_wait_for_stop_tids (),
+    m_wait_for_stop_tids_mutex (),
+    m_supports_mem_region (eLazyBoolCalculate),
+    m_mem_region_cache (),
+    m_mem_region_cache_mutex ()
+{
+}
+
+//------------------------------------------------------------------------------
+/// The basic design of the NativeProcessLinux is built around two threads.
+///
+/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
+/// for changes in the debugee state.  When a change is detected a
+/// ProcessMessage is sent to the associated ProcessLinux instance.  This thread
+/// "drives" state changes in the debugger.
+///
+/// The second thread (@see OperationThread) is responsible for two things 1)
+/// launching or attaching to the inferior process, and then 2) servicing
+/// operations such as register reads/writes, stepping, etc.  See the comments
+/// on the Operation class for more info as to why this is needed.
+void
+NativeProcessLinux::LaunchInferior (
+    Module *module,
+    const char *argv[],
+    const char *envp[],
+    const char *stdin_path,
+    const char *stdout_path,
+    const char *stderr_path,
+    const char *working_dir,
+    lldb_private::Error &error)
+{
+    if (module)
+        m_arch = module->GetArchitecture ();
+
+    SetState(eStateLaunching);
+
+    std::unique_ptr<LaunchArgs> args(
+        new LaunchArgs(
+            this, module, argv, envp,
+            stdin_path, stdout_path, stderr_path,
+            working_dir));
+
+    sem_init(&m_operation_pending, 0, 0);
+    sem_init(&m_operation_done, 0, 0);
+
+    StartLaunchOpThread(args.get(), error);
+    if (!error.Success())
+        return;
+
+WAIT_AGAIN:
+    // Wait for the operation thread to initialize.
+    if (sem_wait(&args->m_semaphore))
+    {
+        if (errno == EINTR)
+            goto WAIT_AGAIN;
+        else
+        {
+            error.SetErrorToErrno();
+            return;
+        }
+    }
+
+    // Check that the launch was a success.
+    if (!args->m_error.Success())
+    {
+        StopOpThread();
+        error = args->m_error;
+        return;
+    }
+
+    // Finally, start monitoring the child process for change in state.
+    m_monitor_thread = Host::StartMonitoringChildProcess(
+        NativeProcessLinux::MonitorCallback, this, GetID(), true);
+    if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+    {
+        error.SetErrorToGenericError();
+        error.SetErrorString ("Process attach failed to create monitor thread for NativeProcessLinux::MonitorCallback.");
+        return;
+    }
+}
+
+void
+NativeProcessLinux::AttachToInferior (lldb::pid_t pid, lldb_private::Error &error)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ")", __FUNCTION__, pid);
+
+    // We can use the Host for everything except the ResolveExecutable portion.
+    PlatformSP platform_sp = Platform::GetDefaultPlatform ();
+    if (!platform_sp)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 "): no default platform set", __FUNCTION__, pid);
+        error.SetErrorString ("no default platform available");
+    }
+
+    // Gather info about the process.
+    ProcessInstanceInfo process_info;
+    platform_sp->GetProcessInfo (pid, process_info);
+
+    // Resolve the executable module
+    ModuleSP exe_module_sp;
+    FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+
+    error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(),
+                                    Host::GetArchitecture(),
+                                    exe_module_sp,
+                                    executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+    if (!error.Success())
+        return;
+
+    // Set the architecture to the exe architecture.
+    m_arch = exe_module_sp->GetArchitecture();
+    if (log)
+        log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ") detected architecture %s", __FUNCTION__, pid, m_arch.GetArchitectureName ());
+
+    m_pid = pid;
+    SetState(eStateAttaching);
+
+    sem_init (&m_operation_pending, 0, 0);
+    sem_init (&m_operation_done, 0, 0);
+
+    std::unique_ptr<AttachArgs> args (new AttachArgs (this, pid));
+
+    StartAttachOpThread(args.get (), error);
+    if (!error.Success ())
+        return;
+
+WAIT_AGAIN:
+    // Wait for the operation thread to initialize.
+    if (sem_wait (&args->m_semaphore))
+    {
+        if (errno == EINTR)
+            goto WAIT_AGAIN;
+        else
+        {
+            error.SetErrorToErrno ();
+            return;
+        }
+    }
+
+    // Check that the attach was a success.
+    if (!args->m_error.Success ())
+    {
+        StopOpThread ();
+        error = args->m_error;
+        return;
+    }
+
+    // Finally, start monitoring the child process for change in state.
+    m_monitor_thread = Host::StartMonitoringChildProcess (
+        NativeProcessLinux::MonitorCallback, this, GetID (), true);
+    if (!IS_VALID_LLDB_HOST_THREAD (m_monitor_thread))
+    {
+        error.SetErrorToGenericError ();
+        error.SetErrorString ("Process attach failed to create monitor thread for NativeProcessLinux::MonitorCallback.");
+        return;
+    }
+}
+
+NativeProcessLinux::~NativeProcessLinux()
+{
+    StopMonitor();
+}
+
+//------------------------------------------------------------------------------
+// Thread setup and tear down.
+
+void
+NativeProcessLinux::StartLaunchOpThread(LaunchArgs *args, Error &error)
+{
+    static const char *g_thread_name = "lldb.process.nativelinux.operation";
+
+    if (IS_VALID_LLDB_HOST_THREAD (m_operation_thread))
+        return;
+
+    m_operation_thread =
+        Host::ThreadCreate (g_thread_name, LaunchOpThread, args, &error);
+}
+
+void *
+NativeProcessLinux::LaunchOpThread(void *arg)
+{
+    LaunchArgs *args = static_cast<LaunchArgs*>(arg);
+
+    if (!Launch(args)) {
+        sem_post(&args->m_semaphore);
+        return NULL;
+    }
+
+    ServeOperation(args);
+    return NULL;
+}
+
+bool
+NativeProcessLinux::Launch(LaunchArgs *args)
+{
+    NativeProcessLinux *monitor = args->m_monitor;
+    assert (monitor && "monitor is NULL");
+    if (!monitor)
+        return false;
+
+    const char **argv = args->m_argv;
+    const char **envp = args->m_envp;
+    const char *stdin_path = args->m_stdin_path;
+    const char *stdout_path = args->m_stdout_path;
+    const char *stderr_path = args->m_stderr_path;
+    const char *working_dir = args->m_working_dir;
+
+    lldb_utility::PseudoTerminal terminal;
+    const size_t err_len = 1024;
+    char err_str[err_len];
+    lldb::pid_t pid;
+    NativeThreadProtocolSP thread_sp;
+
+    lldb::ThreadSP inferior;
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    // Propagate the environment if one is not supplied.
+    if (envp == NULL || envp[0] == NULL)
+        envp = const_cast<const char **>(environ);
+
+    if ((pid = terminal.Fork(err_str, err_len)) == static_cast<lldb::pid_t> (-1))
+    {
+        args->m_error.SetErrorToGenericError();
+        args->m_error.SetErrorString("Process fork failed.");
+        goto FINISH;
+    }
+
+    // Recognized child exit status codes.
+    enum {
+        ePtraceFailed = 1,
+        eDupStdinFailed,
+        eDupStdoutFailed,
+        eDupStderrFailed,
+        eChdirFailed,
+        eExecFailed,
+        eSetGidFailed
+    };
+
+    // Child process.
+    if (pid == 0)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s inferior process preparing to fork", __FUNCTION__);
+
+        // Trace this process.
+        if (log)
+            log->Printf ("NativeProcessLinux::%s inferior process issuing PTRACE_TRACEME", __FUNCTION__);
+
+        if (PTRACE(PTRACE_TRACEME, 0, NULL, NULL, 0) < 0)
+        {
+            if (log)
+                log->Printf ("NativeProcessLinux::%s inferior process PTRACE_TRACEME failed", __FUNCTION__);
+            exit(ePtraceFailed);
+        }
+
+        // Do not inherit setgid powers.
+        if (log)
+            log->Printf ("NativeProcessLinux::%s inferior process resetting gid", __FUNCTION__);
+
+        if (setgid(getgid()) != 0)
+        {
+            if (log)
+                log->Printf ("NativeProcessLinux::%s inferior process setgid() failed", __FUNCTION__);
+            exit(eSetGidFailed);
+        }
+
+        // Attempt to have our own process group.
+        // TODO verify if we really want this.
+        if (log)
+            log->Printf ("NativeProcessLinux::%s inferior process resetting process group", __FUNCTION__);
+
+        if (setpgid(0, 0) != 0)
+        {
+            if (log)
+            {
+                const int error_code = errno;
+                log->Printf ("NativeProcessLinux::%s inferior setpgid() failed, errno=%d (%s), continuing with existing proccess group %" PRIu64,
+                        __FUNCTION__,
+                        error_code,
+                        strerror (error_code),
+                        static_cast<lldb::pid_t> (getpgid (0)));
+            }
+            // Don't allow this to prevent an inferior exec.
+        }
+
+        // Dup file descriptors if needed.
+        //
+        // FIXME: If two or more of the paths are the same we needlessly open
+        // the same file multiple times.
+        if (stdin_path != NULL && stdin_path[0])
+            if (!DupDescriptor(stdin_path, STDIN_FILENO, O_RDONLY))
+                exit(eDupStdinFailed);
+
+        if (stdout_path != NULL && stdout_path[0])
+            if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+                exit(eDupStdoutFailed);
+
+        if (stderr_path != NULL && stderr_path[0])
+            if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
+                exit(eDupStderrFailed);
+
+        // Change working directory
+        if (working_dir != NULL && working_dir[0])
+          if (0 != ::chdir(working_dir))
+              exit(eChdirFailed);
+
+        // Execute.  We should never return.
+        execve(argv[0],
+               const_cast<char *const *>(argv),
+               const_cast<char *const *>(envp));
+        exit(eExecFailed);
+    }
+
+    // Wait for the child process to trap on its call to execve.
+    ::pid_t wpid;
+    int status;
+    if ((wpid = waitpid(pid, &status, 0)) < 0)
+    {
+        args->m_error.SetErrorToErrno();
+
+        if (log)
+            log->Printf ("NativeProcessLinux::%s waitpid for inferior failed with %s", __FUNCTION__, args->m_error.AsCString ());
+
+        // Mark the inferior as invalid.
+        // FIXME this could really use a new state - eStateLaunchFailure.  For now, using eStateInvalid.
+        monitor->SetState (StateType::eStateInvalid);
+
+        goto FINISH;
+    }
+    else if (WIFEXITED(status))
+    {
+        // open, dup or execve likely failed for some reason.
+        args->m_error.SetErrorToGenericError();
+        switch (WEXITSTATUS(status))
+        {
+            case ePtraceFailed:
+                args->m_error.SetErrorString("Child ptrace failed.");
+                break;
+            case eDupStdinFailed:
+                args->m_error.SetErrorString("Child open stdin failed.");
+                break;
+            case eDupStdoutFailed:
+                args->m_error.SetErrorString("Child open stdout failed.");
+                break;
+            case eDupStderrFailed:
+                args->m_error.SetErrorString("Child open stderr failed.");
+                break;
+            case eChdirFailed:
+                args->m_error.SetErrorString("Child failed to set working directory.");
+                break;
+            case eExecFailed:
+                args->m_error.SetErrorString("Child exec failed.");
+                break;
+            case eSetGidFailed:
+                args->m_error.SetErrorString("Child setgid failed.");
+                break;
+            default:
+                args->m_error.SetErrorString("Child returned unknown exit status.");
+                break;
+        }
+
+        if (log)
+        {
+            log->Printf ("NativeProcessLinux::%s inferior exited with status %d before issuing a STOP",
+                    __FUNCTION__,
+                    WEXITSTATUS(status));
+        }
+
+        // Mark the inferior as invalid.
+        // FIXME this could really use a new state - eStateLaunchFailure.  For now, using eStateInvalid.
+        monitor->SetState (StateType::eStateInvalid);
+
+        goto FINISH;
+    }
+    assert(WIFSTOPPED(status) && (wpid == static_cast<::pid_t> (pid)) &&
+           "Could not sync with inferior process.");
+
+    if (log)
+        log->Printf ("NativeProcessLinux::%s inferior started, now in stopped state", __FUNCTION__);
+
+    if (!SetDefaultPtraceOpts(pid))
+    {
+        args->m_error.SetErrorToErrno();
+        if (log)
+            log->Printf ("NativeProcessLinux::%s inferior failed to set default ptrace options: %s",
+                    __FUNCTION__,
+                    args->m_error.AsCString ());
+
+        // Mark the inferior as invalid.
+        // FIXME this could really use a new state - eStateLaunchFailure.  For now, using eStateInvalid.
+        monitor->SetState (StateType::eStateInvalid);
+
+        goto FINISH;
+    }
+
+    // Release the master terminal descriptor and pass it off to the
+    // NativeProcessLinux instance.  Similarly stash the inferior pid.
+    monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+    monitor->m_pid = pid;
+
+    // Set the terminal fd to be in non blocking mode (it simplifies the
+    // implementation of ProcessLinux::GetSTDOUT to have a non-blocking
+    // descriptor to read from).
+    if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s inferior EnsureFDFlags failed for ensuring terminal O_NONBLOCK setting: %s",
+                    __FUNCTION__,
+                    args->m_error.AsCString ());
+
+        // Mark the inferior as invalid.
+        // FIXME this could really use a new state - eStateLaunchFailure.  For now, using eStateInvalid.
+        monitor->SetState (StateType::eStateInvalid);
+
+        goto FINISH;
+    }
+
+    if (log)
+        log->Printf ("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
+
+    thread_sp = monitor->AddThread (static_cast<lldb::tid_t> (pid));
+    assert (thread_sp && "AddThread() returned a nullptr thread");
+    reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGSTOP);
+    monitor->SetCurrentThreadID (thread_sp->GetID ());
+
+    // Let our process instance know the thread has stopped.
+    monitor->SetState (StateType::eStateStopped);
+
+FINISH:
+    if (log)
+    {
+        if (args->m_error.Success ())
+        {
+            log->Printf ("NativeProcessLinux::%s inferior launching succeeded", __FUNCTION__);
+        }
+        else
+        {
+            log->Printf ("NativeProcessLinux::%s inferior launching failed: %s",
+                __FUNCTION__,
+                args->m_error.AsCString ());
+        }
+    }
+    return args->m_error.Success();
+}
+
+void
+NativeProcessLinux::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
+{
+    static const char *g_thread_name = "lldb.process.linux.operation";
+
+    if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+        return;
+
+    m_operation_thread =
+        Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
+}
+
+void *
+NativeProcessLinux::AttachOpThread(void *arg)
+{
+    AttachArgs *args = static_cast<AttachArgs*>(arg);
+
+    if (!Attach(args)) {
+        sem_post(&args->m_semaphore);
+        return NULL;
+    }
+
+    ServeOperation(args);
+    return NULL;
+}
+
+bool
+NativeProcessLinux::Attach(AttachArgs *args)
+{
+    lldb::pid_t pid = args->m_pid;
+
+    NativeProcessLinux *monitor = args->m_monitor;
+    lldb::ThreadSP inferior;
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    // Use a map to keep track of the threads which we have attached/need to attach.
+    Host::TidMap tids_to_attach;
+    if (pid <= 1)
+    {
+        args->m_error.SetErrorToGenericError();
+        args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
+        goto FINISH;
+    }
+
+    while (Host::FindProcessThreads(pid, tids_to_attach))
+    {
+        for (Host::TidMap::iterator it = tids_to_attach.begin();
+             it != tids_to_attach.end();)
+        {
+            if (it->second == false)
+            {
+                lldb::tid_t tid = it->first;
+
+                // Attach to the requested process.
+                // An attach will cause the thread to stop with a SIGSTOP.
+                if (PTRACE(PTRACE_ATTACH, tid, NULL, NULL, 0) < 0)
+                {
+                    // No such thread. The thread may have exited.
+                    // More error handling may be needed.
+                    if (errno == ESRCH)
+                    {
+                        it = tids_to_attach.erase(it);
+                        continue;
+                    }
+                    else
+                    {
+                        args->m_error.SetErrorToErrno();
+                        goto FINISH;
+                    }
+                }
+
+                int status;
+                // Need to use __WALL otherwise we receive an error with errno=ECHLD
+                // At this point we should have a thread stopped if waitpid succeeds.
+                if ((status = waitpid(tid, NULL, __WALL)) < 0)
+                {
+                    // No such thread. The thread may have exited.
+                    // More error handling may be needed.
+                    if (errno == ESRCH)
+                    {
+                        it = tids_to_attach.erase(it);
+                        continue;
+                    }
+                    else
+                    {
+                        args->m_error.SetErrorToErrno();
+                        goto FINISH;
+                    }
+                }
+
+                if (!SetDefaultPtraceOpts(tid))
+                {
+                    args->m_error.SetErrorToErrno();
+                    goto FINISH;
+                }
+
+
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
+
+                it->second = true;
+
+                // Create the thread, mark it as stopped.
+                NativeThreadProtocolSP thread_sp (monitor->AddThread (static_cast<lldb::tid_t> (tid)));
+                assert (thread_sp && "AddThread() returned a nullptr");
+                reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGSTOP);
+                monitor->SetCurrentThreadID (thread_sp->GetID ());
+            }
+
+            // move the loop forward
+            ++it;
+        }
+    }
+
+    if (tids_to_attach.size() > 0)
+    {
+        monitor->m_pid = pid;
+        // Let our process instance know the thread has stopped.
+        monitor->SetState (StateType::eStateStopped);
+    }
+    else
+    {
+        args->m_error.SetErrorToGenericError();
+        args->m_error.SetErrorString("No such process.");
+    }
+
+ FINISH:
+    return args->m_error.Success();
+}
+
+bool
+NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid)
+{
+    long ptrace_opts = 0;
+
+    // Have the child raise an event on exit.  This is used to keep the child in
+    // limbo until it is destroyed.
+    ptrace_opts |= PTRACE_O_TRACEEXIT;
+
+    // Have the tracer trace threads which spawn in the inferior process.
+    // TODO: if we want to support tracing the inferiors' child, add the
+    // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
+    ptrace_opts |= PTRACE_O_TRACECLONE;
+
+    // Have the tracer notify us before execve returns
+    // (needed to disable legacy SIGTRAP generation)
+    ptrace_opts |= PTRACE_O_TRACEEXEC;
+
+    return PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts, 0) >= 0;
+}
+
+static ExitType convert_pid_status_to_exit_type (int status)
+{
+    if (WIFEXITED (status))
+        return ExitType::eExitTypeExit;
+    else if (WIFSIGNALED (status))
+        return ExitType::eExitTypeSignal;
+    else if (WIFSTOPPED (status))
+        return ExitType::eExitTypeStop;
+    else
+    {
+        // We don't know what this is.
+        return ExitType::eExitTypeInvalid;
+    }
+}
+
+static int convert_pid_status_to_return_code (int status)
+{
+    if (WIFEXITED (status))
+        return WEXITSTATUS (status);
+    else if (WIFSIGNALED (status))
+        return WTERMSIG (status);
+    else if (WIFSTOPPED (status))
+        return WSTOPSIG (status);
+    else
+    {
+        // We don't know what this is.
+        return ExitType::eExitTypeInvalid;
+    }
+}
+
+// Main process monitoring waitpid-loop handler.
+bool
+NativeProcessLinux::MonitorCallback(void *callback_baton,
+                                lldb::pid_t pid,
+                                bool exited,
+                                int signal,
+                                int status)
+{
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    NativeProcessLinux *const process = static_cast<NativeProcessLinux*>(callback_baton);
+    assert (process && "process is null");
+    if (!process)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " callback_baton was null, can't determine process to use", __FUNCTION__, pid);
+        return true;
+    }
+
+    // Certain activities differ based on whether the pid is the tid of the main thread.
+    const bool is_main_thread = (pid == process->GetID ());
+
+    // Assume we keep monitoring by default.
+    bool stop_monitoring = false;
+
+    // Handle when the thread exits.
+    if (exited)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() got exit signal, tid = %"  PRIu64 " (%s main thread)", __FUNCTION__, pid, is_main_thread ? "is" : "is not");
+
+        // This is a thread that exited.  Ensure we're not tracking it anymore.
+        const bool thread_found = process->StopTrackingThread (pid);
+
+        if (is_main_thread)
+        {
+            // We only set the exit status and notify the delegate if we haven't already set the process
+            // state to an exited state.  We normally should have received a SIGTRAP | (PTRACE_EVENT_EXIT << 8)
+            // for the main thread.
+            const bool already_notified = (process->GetState() == StateType::eStateExited) | (process->GetState () == StateType::eStateCrashed);
+            if (!already_notified)
+            {
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s() tid = %"  PRIu64 " handling main thread exit (%s), expected exit state already set but state was %s instead, setting exit state now", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found", StateAsCString (process->GetState ()));
+                // The main thread exited.  We're done monitoring.  Report to delegate.
+                process->SetExitStatus (convert_pid_status_to_exit_type (status), convert_pid_status_to_return_code (status), nullptr, true);
+
+                // Notify delegate that our process has exited.
+                process->SetState (StateType::eStateExited, true);
+            }
+            else
+            {
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s() tid = %"  PRIu64 " main thread now exited (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found");
+            }
+            return true;
+        }
+        else
+        {
+            // Do we want to report to the delegate in this case?  I think not.  If this was an orderly
+            // thread exit, we would already have received the SIGTRAP | (PTRACE_EVENT_EXIT << 8) signal,
+            // and we would have done an all-stop then.
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() tid = %"  PRIu64 " handling non-main thread exit (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found");
+
+            // Not the main thread, we keep going.
+            return false;
+        }
+    }
+
+    // Get details on the signal raised.
+    siginfo_t info;
+    int ptrace_err = 0;
+
+    if (!process->GetSignalInfo (pid, &info, ptrace_err))
+    {
+        if (ptrace_err == EINVAL)
+        {
+            // This is the first part of the Linux ptrace group-stop mechanism.
+            // The tracer (i.e. NativeProcessLinux) is expected to inject the signal
+            // into the tracee (i.e. inferior) at this point.
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() resuming from group-stop", __FUNCTION__);
+
+            // The inferior process is in 'group-stop', so deliver the stopping signal.
+            const bool signal_delivered = process->Resume (pid, info.si_signo);
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " group-stop signal delivery of signal 0x%x (%s) - %s", __FUNCTION__, pid, info.si_signo, GetUnixSignals ().GetSignalAsCString (info.si_signo), signal_delivered ? "success" : "failed");
+
+            assert(signal_delivered && "SIGSTOP delivery failed while in 'group-stop' state");
+
+            stop_monitoring = false;
+        }
+        else
+        {
+            // ptrace(GETSIGINFO) failed (but not due to group-stop).
+
+            // A return value of ESRCH means the thread/process is no longer on the system,
+            // so it was killed somehow outside of our control.  Either way, we can't do anything
+            // with it anymore.
+
+            // We stop monitoring if it was the main thread.
+            stop_monitoring = is_main_thread;
+
+            // Stop tracking the metadata for the thread since it's entirely off the system now.
+            const bool thread_found = process->StopTrackingThread (pid);
+
+            if (log)
+                log->Printf ("NativeProcessLinux::%s GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d (%s, %s, %s)",
+                             __FUNCTION__, strerror(ptrace_err), pid, signal, status, ptrace_err == ESRCH ? "thread/process killed" : "unknown reason", is_main_thread ? "is main thread" : "is not main thread", thread_found ? "thread metadata removed" : "thread metadata not found");
+
+            if (is_main_thread)
+            {
+                // Notify the delegate - our process is not available but appears to have been killed outside
+                // our control.  Is eStateExited the right exit state in this case?
+                process->SetExitStatus (convert_pid_status_to_exit_type (status), convert_pid_status_to_return_code (status), nullptr, true);
+                process->SetState (StateType::eStateExited, true);
+            }
+            else
+            {
+                // This thread was pulled out from underneath us.  Anything to do here? Do we want to do an all stop?
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " non-main thread exit occurred, didn't tell delegate anything since thread disappeared out from underneath us", __FUNCTION__, process->GetID (), pid);
+            }
+        }
+    }
+    else
+    {
+        // We have retrieved the signal info.  Dispatch appropriately.
+        if (info.si_signo == SIGTRAP)
+            process->MonitorSIGTRAP(&info, pid);
+        else
+            process->MonitorSignal(&info, pid, exited);
+
+        stop_monitoring = false;
+    }
+
+    return stop_monitoring;
+}
+
+void
+NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    const bool is_main_thread = (pid == GetID ());
+
+    assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
+    if (!info)
+        return;
+
+    // See if we can find a thread for this signal.
+    NativeThreadProtocolSP thread_sp = GetThreadByID (pid);
+    if (!thread_sp)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " no thread found for tid %" PRIu64, __FUNCTION__, GetID (), pid);
+    }
+
+    switch (info->si_code)
+    {
+    // TODO: these two cases are required if we want to support tracing of the inferiors' children.  We'd need this to debug a monitor.
+    // case (SIGTRAP | (PTRACE_EVENT_FORK << 8)):
+    // case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)):
+
+    case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)):
+    {
+        lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+
+        unsigned long event_message = 0;
+        if (GetEventMessage(pid, &event_message))
+            tid = static_cast<lldb::tid_t> (event_message);
+
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " received thread creation event for tid %" PRIu64, __FUNCTION__, pid, tid);
+
+        // If we don't track the thread yet: create it, mark as stopped.
+        // If we do track it, this is the wait we needed.  Now resume the new thread.
+        // In all cases, resume the current (i.e. main process) thread.
+        bool already_tracked = false;
+        thread_sp = GetOrCreateThread (tid, already_tracked);
+        assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
+
+        // If the thread was already tracked, it means the created thread already received its SI_USER notification of creation.
+        if (already_tracked)
+        {
+            // FIXME loops like we want to stop all theads here.
+            // StopAllThreads
+
+            // We can now resume the newly created thread since it is fully created.
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+            Resume (tid, LLDB_INVALID_SIGNAL_NUMBER);
+        }
+        else
+        {
+            // Mark the thread as currently launching.  Need to wait for SIGTRAP clone on the main thread before
+            // this thread is ready to go.
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetLaunching ();
+        }
+
+        // In all cases, we can resume the main thread here.
+        Resume (pid, LLDB_INVALID_SIGNAL_NUMBER);
+        break;
+    }
+
+    case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)):
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() received exec event, code = %d", __FUNCTION__, info->si_code ^ SIGTRAP);
+        // FIXME stop all threads, mark thread stop reason as ThreadStopInfo.reason = eStopReasonExec;
+        break;
+
+    case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
+    {
+        // The inferior process or one of its threads is about to exit.
+        // Maintain the process or thread in a state of "limbo" until we are
+        // explicitly commanded to detach, destroy, resume, etc.
+        unsigned long data = 0;
+        if (!GetEventMessage(pid, &data))
+            data = -1;
+
+        if (log)
+        {
+            log->Printf ("NativeProcessLinux::%s() received PTRACE_EVENT_EXIT, data = %lx (WIFEXITED=%s,WIFSIGNALED=%s), pid = %" PRIu64 " (%s)",
+                         __FUNCTION__,
+                         data, WIFEXITED (data) ? "true" : "false", WIFSIGNALED (data) ? "true" : "false",
+                         pid,
+                    is_main_thread ? "is main thread" : "not main thread");
+        }
+
+        // Set the thread to exited.
+        if (thread_sp)
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetExited ();
+        else
+        {
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " failed to retrieve thread for tid %" PRIu64", cannot set thread state", __FUNCTION__, GetID (), pid);
+        }
+
+        if (is_main_thread)
+        {
+            SetExitStatus (convert_pid_status_to_exit_type (data), convert_pid_status_to_return_code (data), nullptr, true);
+            // Resume the thread so it completely exits.
+            Resume (pid, LLDB_INVALID_SIGNAL_NUMBER);
+        }
+        else
+        {
+            // FIXME figure out the path where we plan to reap the metadata for the thread.
+        }
+
+        break;
+    }
+
+    case 0:
+    case TRAP_TRACE:
+        // We receive this on single stepping.
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)", __FUNCTION__, pid);
+
+        if (thread_sp)
+        {
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+            SetCurrentThreadID (thread_sp->GetID ());
+        }
+        else
+        {
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 " single stepping received trace but thread not found", __FUNCTION__, GetID (), pid);
+        }
+
+        // Tell the process we have a stop (from single stepping).
+        SetState (StateType::eStateStopped, true);
+        break;
+
+    case SI_KERNEL:
+    case TRAP_BRKPT:
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
+
+        // Mark the thread as stopped at breakpoint.
+        if (thread_sp)
+        {
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+            Error error = FixupBreakpointPCAsNeeded (thread_sp);
+            if (error.Fail ())
+            {
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s", __FUNCTION__, pid, error.AsCString ());
+            }
+        }
+        else
+        {
+            if (log)
+                log->Printf ("NativeProcessLinux::%s()  pid = %" PRIu64 ": warning, cannot process software breakpoint since no thread metadata", __FUNCTION__, pid);
+        }
+
+
+        // Tell the process we have a stop from this thread.
+        SetCurrentThreadID (pid);
+        SetState (StateType::eStateStopped, true);
+        break;
+
+    case TRAP_HWBKPT:
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() received watchpoint event, pid = %" PRIu64, __FUNCTION__, pid);
+
+        // Mark the thread as stopped at watchpoint.
+        // The address is at (lldb::addr_t)info->si_addr if we need it.
+        if (thread_sp)
+            reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
+        else
+        {
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ": warning, cannot process hardware breakpoint since no thread metadata", __FUNCTION__, GetID (), pid);
+        }
+
+        // Tell the process we have a stop from this thread.
+        SetCurrentThreadID (pid);
+        SetState (StateType::eStateStopped, true);
+        break;
+
+    case SIGTRAP:
+    case (SIGTRAP | 0x80):
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() received system call stop event, pid %" PRIu64 "tid %" PRIu64, __FUNCTION__, GetID (), pid);
+        // Ignore these signals until we know more about them.
+        Resume(pid, 0);
+        break;
+
+    default:
+        assert(false && "Unexpected SIGTRAP code!");
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 "tid %" PRIu64 " received unhandled SIGTRAP code: 0x%" PRIx64, __FUNCTION__, GetID (), pid, static_cast<uint64_t> (SIGTRAP | (PTRACE_EVENT_CLONE << 8)));
+        break;
+        
+    }
+}
+
+void
+NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited)
+{
+    int signo = info->si_signo;
+
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+    // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
+    // kill(2) or raise(3).  Similarly for tgkill(2) on Linux.
+    //
+    // IOW, user generated signals never generate what we consider to be a
+    // "crash".
+    //
+    // Similarly, ACK signals generated by this monitor.
+
+    // See if we can find a thread for this signal.
+    NativeThreadProtocolSP thread_sp = GetThreadByID (pid);
+    if (!thread_sp)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " no thread found for tid %" PRIu64, __FUNCTION__, GetID (), pid);
+    }
+
+    // Handle the signal.
+    if (info->si_code == SI_TKILL || info->si_code == SI_USER)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s() received signal %s (%d) with code %s, (siginfo pid = %d (%s), waitpid pid = %" PRIu64 ")",
+                            __FUNCTION__,
+                            GetUnixSignals ().GetSignalAsCString (signo),
+                            signo,
+                            (info->si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"),
+                            info->si_pid,
+                            (info->si_pid == getpid ()) ? "is monitor" : "is not monitor",
+                            pid);
+
+        if ((info->si_pid == 0) && info->si_code == SI_USER)
+        {
+            // A new thread creation is being signaled.  This is one of two parts that come in
+            // a non-deterministic order.  pid is the thread id.
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": new thread notification",
+                         __FUNCTION__, GetID (), pid);
+
+            // Did we already create the thread?
+            bool already_tracked = false;
+            thread_sp = GetOrCreateThread (pid, already_tracked);
+            assert (thread_sp.get() && "failed to get or create the tracking data for newly created inferior thread");
+
+            // If the thread was already tracked, it means the main thread already received its SIGTRAP for the create.
+            if (already_tracked)
+            {
+                // We can now resume this thread up since it is fully created.
+                reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
+                Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
+            }
+            else
+            {
+                // Mark the thread as currently launching.  Need to wait for SIGTRAP clone on the main thread before
+                // this thread is ready to go.
+                reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetLaunching ();
+            }
+        }
+        else if (info->si_pid == getpid () && (signo == SIGSTOP))
+        {
+            // This is a tgkill()-based stop.
+            if (thread_sp)
+            {
+                // An inferior thread just stopped.  Mark it as such.
+                reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
+                SetCurrentThreadID (thread_sp->GetID ());
+
+                // Remove this tid from the wait-for-stop set.
+                Mutex::Locker locker (m_wait_for_stop_tids_mutex);
+
+                auto removed_count = m_wait_for_stop_tids.erase (thread_sp->GetID ());
+                if (removed_count < 1)
+                {
+                    log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 " tid %" PRIu64 ": tgkill()-stopped thread not in m_wait_for_stop_tids",
+                                 __FUNCTION__, GetID (), thread_sp->GetID ());
+
+                }
+
+                // If this is the last thread in the m_wait_for_stop_tids, we need to notify
+                // the delegate that a stop has occurred now that every thread that was supposed
+                // to stop has stopped.
+                if (m_wait_for_stop_tids.empty ())
+                {
+                    if (log)
+                    {
+                        log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", setting process state to stopped now that all tids marked for stop have completed",
+                                     __FUNCTION__,
+                                     GetID (),
+                                     pid);
+                    }
+                    SetState (StateType::eStateStopped, true);
+                }
+            }
+        }
+        else
+        {
+            // Hmm, not sure what to do with this.
+            if (log)
+                log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " unsure how to handle SI_KILL or SI_USER signal", __FUNCTION__, GetID ());
+        }
+
+        return;
+    }
+
+    if (log)
+        log->Printf ("NativeProcessLinux::%s() received signal %s", __FUNCTION__, GetUnixSignals ().GetSignalAsCString (signo));
+
+    switch (signo)
+    {
+    case SIGSEGV:
+        {
+            lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+
+            // FIXME figure out how to propagate this properly.  Seems like it
+            // should go in ThreadStopInfo.
+            // We can get more details on the exact nature of the crash here.
+            // ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
+            if (!exited)
+            {
+                // This is just a pre-signal-delivery notification of the incoming signal.
+                // Send a stop to the debugger.
+                if (thread_sp)
+                {
+                    reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
+                    SetCurrentThreadID (thread_sp->GetID ());
+                }
+                SetState (StateType::eStateStopped, true);
+            }
+            else
+            {
+                if (thread_sp)
+                {
+                    // FIXME figure out what type this is.
+                    const uint64_t exception_type = static_cast<uint64_t> (SIGSEGV);
+                    reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetCrashedWithException (exception_type, fault_addr);
+                }
+                SetState (StateType::eStateCrashed, true);
+            }
+        }
+        break;
+
+    case SIGILL:
+        {
+            // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+            // Can get the reason from here.
+            // ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info);
+            // FIXME save the crash reason
+            SetState (StateType::eStateCrashed, true);
+        }
+        break;
+
+    case SIGFPE:
+        {
+            // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+            // Can get the crash reason from below.
+            // ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info);
+            // FIXME save the crash reason
+            SetState (StateType::eStateCrashed, true);
+        }
+        break;
+
+    case SIGBUS:
+        {
+            // lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+            // Can get the crash reason from below.
+            // ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info);
+            // FIXME save the crash reason
+            SetState (StateType::eStateCrashed);
+        }
+        break;
+
+    default:
+        // FIXME Stop all threads here.
+        break;
+    }
+}
+
+Error
+NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
+{
+    Error error;
+
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("NativeProcessLinux::%s called: pid %" PRIu64, __FUNCTION__, GetID ());
+
+    int run_thread_count = 0;
+    int stop_thread_count = 0;
+    int step_thread_count = 0;
+
+    std::vector<NativeThreadProtocolSP> new_stop_threads;
+
+    Mutex::Locker locker (m_threads_mutex);
+    for (auto thread_sp : m_threads)
+    {
+        assert (thread_sp && "thread list should not contain NULL threads");
+        NativeThreadLinux *const linux_thread_p = reinterpret_cast<NativeThreadLinux*> (thread_sp.get ());
+
+        const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true);
+        assert (action && "NULL ResumeAction returned for thread during Resume ()");
+
+        if (log)
+        {
+            log->Printf ("NativeProcessLinux::%s processing resume action state %s for pid %" PRIu64 " tid %" PRIu64, 
+                    __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+        }
+
+        switch (action->state)
+        {
+        case eStateRunning:
+            // Run the thread, possibly feeding it the signal.
+            linux_thread_p->SetRunning ();
+            if (action->signal > 0)
+            {
+                // Resume the thread and deliver the given signal,
+                // then mark as delivered.
+                Resume (thread_sp->GetID (), action->signal);
+                resume_actions.SetSignalHandledForThread (thread_sp->GetID ());
+            }
+            else
+            {
+                // Just resume the thread with no signal.
+                Resume (thread_sp->GetID (), LLDB_INVALID_SIGNAL_NUMBER);
+            }
+            ++run_thread_count;
+            break;
+
+        case eStateStepping:
+            // Note: if we have multiple threads, we may need to stop
+            // the other threads first, then step this one.
+            linux_thread_p->SetStepping ();
+            if (SingleStep (thread_sp->GetID (), 0))
+            {
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step succeeded",
+                                 __FUNCTION__, GetID (), thread_sp->GetID ());
+            }
+            else
+            {
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " single step failed",
+                                 __FUNCTION__, GetID (), thread_sp->GetID ());
+            }
+            ++step_thread_count;
+            break;
+
+        case eStateSuspended:
+        case eStateStopped:
+            if (!StateIsStoppedState (linux_thread_p->GetState (), false))
+                new_stop_threads.push_back (thread_sp);
+            else
+            {
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s no need to stop pid %" PRIu64 " tid %" PRIu64 ", thread state already %s",
+                                 __FUNCTION__, GetID (), thread_sp->GetID (), StateAsCString (linux_thread_p->GetState ()));
+            }
+
+            ++stop_thread_count;
+            break;
+
+        default:
+            return Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64,
+                    __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ());
+        }
+    }
+
+    // If any thread was set to run, notify the process state as running.
+    if (run_thread_count > 0)
+        SetState (StateType::eStateRunning, true);
+
+    // Now do a tgkill SIGSTOP on each thread we want to stop.
+    if (!new_stop_threads.empty ())
+    {
+        // Lock the m_wait_for_stop_tids set so we can fill it with every thread we expect to have stopped.
+        Mutex::Locker stop_thread_id_locker (m_wait_for_stop_tids_mutex);
+        for (auto thread_sp : new_stop_threads)
+        {
+            // Send a stop signal to the thread.
+            const int result = tgkill (GetID (), thread_sp->GetID (), SIGSTOP);
+            if (result != 0)
+            {
+                // tgkill failed.
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s error: tgkill SIGSTOP for pid %" PRIu64 " tid %" PRIu64 "failed, retval %d",
+                                 __FUNCTION__, GetID (), thread_sp->GetID (), result);
+            }
+            else
+            {
+                // tgkill succeeded.  Don't mark the thread state, though.  Let the signal
+                // handling mark it.
+                if (log)
+                    log->Printf ("NativeProcessLinux::%s tgkill SIGSTOP for pid %" PRIu64 " tid %" PRIu64 " succeeded",
+                                 __FUNCTION__, GetID (), thread_sp->GetID ());
+
+                // Add it to the set of threads we expect to signal a stop.
+                // We won't tell the delegate about it until this list drains to empty.
+                m_wait_for_stop_tids.insert (thread_sp->GetID ());
+            }
+        }
+    }
+
+    return error;
+}
+
+Error
+NativeProcessLinux::Halt ()
+{
+    Error error;
+
+    // FIXME check if we're already stopped
+    const bool is_stopped = false;
+    if (is_stopped)
+        return error;
+
+    if (kill (GetID (), SIGSTOP) != 0)
+        error.SetErrorToErrno ();
+
+    return error;
+}
+
+Error
+NativeProcessLinux::Detach ()
+{
+    Error error;
+
+    // Tell ptrace to detach from the process.
+    if (GetID () != LLDB_INVALID_PROCESS_ID)
+        error = Detach (GetID ());
+
+    // Stop monitoring the inferior.
+    StopMonitor ();
+
+    // No error.
+    return error;
+}
+
+Error
+NativeProcessLinux::Signal (int signo)
+{
+    Error error;
+
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("NativeProcessLinux::%s: sending signal %d (%s) to pid %" PRIu64, 
+                __FUNCTION__, signo,  GetUnixSignals ().GetSignalAsCString (signo), GetID ());
+
+    if (kill(GetID(), signo))
+        error.SetErrorToErrno();
+
+    return error;
+}
+
+Error
+NativeProcessLinux::Kill ()
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("NativeProcessLinux::%s called for PID %" PRIu64, __FUNCTION__, GetID ());
+
+    Error error;
+
+    switch (m_state)
+    {
+        case StateType::eStateInvalid:
+        case StateType::eStateExited:
+        case StateType::eStateCrashed:
+        case StateType::eStateDetached:
+        case StateType::eStateUnloaded:
+            // Nothing to do - the process is already dead.
+            if (log)
+                log->Printf ("NativeProcessLinux::%s ignored for PID %" PRIu64 " due to current state: %s", __FUNCTION__, GetID (), StateAsCString (m_state));
+            return error;
+
+        case StateType::eStateConnected:
+        case StateType::eStateAttaching:
+        case StateType::eStateLaunching:
+        case StateType::eStateStopped:
+        case StateType::eStateRunning:
+        case StateType::eStateStepping:
+        case StateType::eStateSuspended:
+            // We can try to kill a process in these states.
+            break;
+    }
+
+    if (kill (GetID (), SIGKILL) != 0)
+    {
+        error.SetErrorToErrno ();
+        return error;
+    }
+
+    return error;
+}
+
+static Error
+ParseMemoryRegionInfoFromProcMapsLine (const std::string &maps_line, MemoryRegionInfo &memory_region_info)
+{
+    memory_region_info.Clear();
+
+    StringExtractor line_extractor (maps_line.c_str ());
+
+    // Format: {address_start_hex}-{address_end_hex} perms offset  dev   inode   pathname
+    // perms: rwxp   (letter is present if set, '-' if not, final character is p=private, s=shared).
+
+    // Parse out the starting address
+    lldb::addr_t start_address = line_extractor.GetHexMaxU64 (false, 0);
+
+    // Parse out hyphen separating start and end address from range.
+    if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != '-'))
+        return Error ("malformed /proc/{pid}/maps entry, missing dash between address range");
+
+    // Parse out the ending address
+    lldb::addr_t end_address = line_extractor.GetHexMaxU64 (false, start_address);
+
+    // Parse out the space after the address.
+    if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != ' '))
+        return Error ("malformed /proc/{pid}/maps entry, missing space after range");
+
+    // Save the range.
+    memory_region_info.GetRange ().SetRangeBase (start_address);
+    memory_region_info.GetRange ().SetRangeEnd (end_address);
+
+    // Parse out each permission entry.
+    if (line_extractor.GetBytesLeft () < 4)
+        return Error ("malformed /proc/{pid}/maps entry, missing some portion of permissions");
+
+    // Handle read permission.
+    const char read_perm_char = line_extractor.GetChar ();
+    if (read_perm_char == 'r')
+        memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eYes);
+    else
+    {
+        assert ( (read_perm_char == '-') && "unexpected /proc/{pid}/maps read permission char" );
+        memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
+    }
+
+    // Handle write permission.
+    const char write_perm_char = line_extractor.GetChar ();
+    if (write_perm_char == 'w')
+        memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eYes);
+    else
+    {
+        assert ( (write_perm_char == '-') && "unexpected /proc/{pid}/maps write permission char" );
+        memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
+    }
+
+    // Handle execute permission.
+    const char exec_perm_char = line_extractor.GetChar ();
+    if (exec_perm_char == 'x')
+        memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eYes);
+    else
+    {
+        assert ( (exec_perm_char == '-') && "unexpected /proc/{pid}/maps exec permission char" );
+        memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
+    }
+
+    return Error ();
+}
+
+Error
+NativeProcessLinux::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info)
+{
+    // FIXME review that the final memory region returned extends to the end of the virtual address space,
+    // with no perms if it is not mapped.
+
+    // Use an approach that reads memory regions from /proc/{pid}/maps.
+    // Assume proc maps entries are in ascending order.
+    // FIXME assert if we find differently.
+    Mutex::Locker locker (m_mem_region_cache_mutex);
+
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    Error error;
+
+    if (m_supports_mem_region == LazyBool::eLazyBoolNo)
+    {
+        // We're done.
+        error.SetErrorString ("unsupported");
+        return error;
+    }
+
+    // If our cache is empty, pull the latest.  There should always be at least one memory region
+    // if memory region handling is supported.
+    if (m_mem_region_cache.empty ())
+    {
+        error = ProcFileReader::ProcessLineByLine (GetID (), "maps",
+             [&] (const std::string &line) -> bool
+             {
+                 MemoryRegionInfo info;
+                 const Error parse_error = ParseMemoryRegionInfoFromProcMapsLine (line, info);
+                 if (parse_error.Success ())
+                 {
+                     m_mem_region_cache.push_back (info);
+                     return true;
+                 }
+                 else
+                 {
+                     if (log)
+                         log->Printf ("NativeProcessLinux::%s failed to parse proc maps line '%s': %s", __FUNCTION__, line.c_str (), error.AsCString ());
+                     return false;
+                 }
+             });
+
+        // If we had an error, we'll mark unsupported.
+        if (error.Fail ())
+        {
+            m_supports_mem_region = LazyBool::eLazyBoolNo;
+            return error;
+        }
+        else if (m_mem_region_cache.empty ())
+        {
+            // No entries after attempting to read them.  This shouldn't happen if /proc/{pid}/maps
+            // is supported.  Assume we don't support map entries via procfs.
+            if (log)
+                log->Printf ("NativeProcessLinux::%s failed to find any procfs maps entries, assuming no support for memory region metadata retrieval", __FUNCTION__);
+            m_supports_mem_region = LazyBool::eLazyBoolNo;
+            error.SetErrorString ("not supported");
+            return error;
+        }
+
+        if (log)
+            log->Printf ("NativeProcessLinux::%s read %" PRIu64 " memory region entries from /proc/%" PRIu64 "/maps", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()), GetID ());
+
+        // We support memory retrieval, remember that.
+        m_supports_mem_region = LazyBool::eLazyBoolYes;
+    }
+    else
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s reusing %" PRIu64 " cached memory region entries", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()));
+    }
+
+    lldb::addr_t prev_base_address = 0;
+
+    // FIXME start by finding the last region that is <= target address using binary search.  Data is sorted.
+    // There can be a ton of regions on pthreads apps with lots of threads.
+    for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end (); ++it)
+    {
+        MemoryRegionInfo &proc_entry_info = *it;
+
+        // Sanity check assumption that /proc/{pid}/maps entries are ascending.
+        assert ((proc_entry_info.GetRange ().GetRangeBase () >= prev_base_address) && "descending /proc/pid/maps entries detected, unexpected");
+        prev_base_address = proc_entry_info.GetRange ().GetRangeBase ();
+
+        // If the target address comes before this entry, indicate distance to next region.
+        if (load_addr < proc_entry_info.GetRange ().GetRangeBase ())
+        {
+            range_info.GetRange ().SetRangeBase (load_addr);
+            range_info.GetRange ().SetByteSize (proc_entry_info.GetRange ().GetRangeBase () - load_addr);
+            range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo);
+            range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo);
+            range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo);
+
+            return error;
+        }
+        else if (proc_entry_info.GetRange ().Contains (load_addr))
+        {
+            // The target address is within the memory region we're processing here.
+            range_info = proc_entry_info;
+            return error;
+        }
+
+        // The target memory address comes somewhere after the region we just parsed.
+    }
+
+    // If we made it here, we didn't find an entry that contained the given address.
+    error.SetErrorString ("address comes after final region");
+
+    if (log)
+        log->Printf ("NativeProcessLinux::%s failed to find map entry for address 0x%" PRIx64 ": %s", __FUNCTION__, load_addr, error.AsCString ());
+
+    return error;
+}
+
+void
+NativeProcessLinux::DoStopIDBumped (uint32_t newBumpId)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("NativeProcessLinux::%s(newBumpId=%" PRIu32 ") called", __FUNCTION__, newBumpId);
+
+    {
+        Mutex::Locker locker (m_mem_region_cache_mutex);
+        if (log)
+            log->Printf ("NativeProcessLinux::%s clearing %" PRIu64 " entries from the cache", __FUNCTION__, static_cast<uint64_t> (m_mem_region_cache.size ()));
+        m_mem_region_cache.clear ();
+    }
+}
+
+Error
+NativeProcessLinux::AllocateMemory (
+    lldb::addr_t size,
+    uint32_t permissions,
+    lldb::addr_t &addr)
+{
+    // FIXME implementing this requires the equivalent of
+    // InferiorCallPOSIX::InferiorCallMmap, which depends on
+    // functional ThreadPlans working with Native*Protocol.
+#if 1
+    return Error ("not implemented yet");
+#else
+    addr = LLDB_INVALID_ADDRESS;
+
+    unsigned prot = 0;
+    if (permissions & lldb::ePermissionsReadable)
+        prot |= eMmapProtRead;
+    if (permissions & lldb::ePermissionsWritable)
+        prot |= eMmapProtWrite;
+    if (permissions & lldb::ePermissionsExecutable)
+        prot |= eMmapProtExec;
+
+    // TODO implement this directly in NativeProcessLinux
+    // (and lift to NativeProcessPOSIX if/when that class is
+    // refactored out).
+    if (InferiorCallMmap(this, addr, 0, size, prot,
+                         eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
+        m_addr_to_mmap_size[addr] = size;
+        return Error ();
+    } else {
+        addr = LLDB_INVALID_ADDRESS;
+        return Error("unable to allocate %" PRIu64 " bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
+    }
+#endif
+}
+
+Error
+NativeProcessLinux::DeallocateMemory (lldb::addr_t addr)
+{
+    // FIXME see comments in AllocateMemory - required lower-level
+    // bits not in place yet (ThreadPlans)
+    return Error ("not implemented");
+}
+
+lldb::addr_t
+NativeProcessLinux::GetSharedLibraryInfoAddress ()
+{
+#if 1
+    // punt on this for now
+    return LLDB_INVALID_ADDRESS;
+#else
+    // Return the image info address for the exe module
+#if 1
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    ModuleSP module_sp;
+    Error error = GetExeModuleSP (module_sp);
+    if (error.Fail ())
+    {
+         if (log)
+            log->Warning ("NativeProcessLinux::%s failed to retrieve exe module: %s", __FUNCTION__, error.AsCString ());
+        return LLDB_INVALID_ADDRESS;
+    }
+
+    if (module_sp == nullptr)
+    {
+         if (log)
+            log->Warning ("NativeProcessLinux::%s exe module returned was NULL", __FUNCTION__);
+         return LLDB_INVALID_ADDRESS;
+    }
+
+    ObjectFileSP object_file_sp = module_sp->GetObjectFile ();
+    if (object_file_sp == nullptr)
+    {
+         if (log)
+            log->Warning ("NativeProcessLinux::%s exe module returned a NULL object file", __FUNCTION__);
+         return LLDB_INVALID_ADDRESS;
+    }
+
+    return obj_file_sp->GetImageInfoAddress();
+#else
+    Target *target = &GetTarget();
+    ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+    Address addr = obj_file->GetImageInfoAddress(target);
+
+    if (addr.IsValid())
+        return addr.GetLoadAddress(target);
+    return LLDB_INVALID_ADDRESS;
+#endif
+#endif // punt on this for now
+}
+
+size_t
+NativeProcessLinux::UpdateThreads ()
+{
+    // The NativeProcessLinux monitoring threads are always up to date
+    // with respect to thread state and they keep the thread list
+    // populated properly. All this method needs to do is return the
+    // thread count.
+    Mutex::Locker locker (m_threads_mutex);
+    return m_threads.size ();
+}
+
+bool
+NativeProcessLinux::GetArchitecture (ArchSpec &arch) const
+{
+    arch = m_arch;
+    return true;
+}
+
+Error
+NativeProcessLinux::GetSoftwareBreakpointSize (NativeRegisterContextSP context_sp, uint32_t &actual_opcode_size)
+{
+    // FIXME put this behind a breakpoint protocol class that can be
+    // set per architecture.  Need ARM, MIPS support here.
+    static const uint8_t g_i386_opcode [] = { 0xCC };
+
+    switch (m_arch.GetMachine ())
+    {
+        case llvm::Triple::x86:
+        case llvm::Triple::x86_64:
+            actual_opcode_size = static_cast<uint32_t> (sizeof(g_i386_opcode));
+            return Error ();
+
+        default:
+            assert(false && "CPU type not supported!");
+            return Error ("CPU type not supported");
+    }
+}
+
+Error
+NativeProcessLinux::SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware)
+{
+    if (hardware)
+        return Error ("NativeProcessLinux does not support hardware breakpoints");
+    else
+        return SetSoftwareBreakpoint (addr, size);
+}
+
+Error
+NativeProcessLinux::GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes)
+{
+    // FIXME put this behind a breakpoint protocol class that can be
+    // set per architecture.  Need ARM, MIPS support here.
+    static const uint8_t g_i386_opcode [] = { 0xCC };
+
+    switch (m_arch.GetMachine ())
+    {
+    case llvm::Triple::x86:
+    case llvm::Triple::x86_64:
+        trap_opcode_bytes = g_i386_opcode;
+        actual_opcode_size = sizeof(g_i386_opcode);
+        return Error ();
+
+    default:
+        assert(false && "CPU type not supported!");
+        return Error ("CPU type not supported");
+    }
+}
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGSEGV(const siginfo_t *info)
+{
+    ProcessMessage::CrashReason reason;
+    assert(info->si_signo == SIGSEGV);
+
+    reason = ProcessMessage::eInvalidCrashReason;
+
+    switch (info->si_code)
+    {
+    default:
+        assert(false && "unexpected si_code for SIGSEGV");
+        break;
+    case SI_KERNEL:
+        // Linux will occasionally send spurious SI_KERNEL codes.
+        // (this is poorly documented in sigaction)
+        // One way to get this is via unaligned SIMD loads.
+        reason = ProcessMessage::eInvalidAddress; // for lack of anything better
+        break;
+    case SEGV_MAPERR:
+        reason = ProcessMessage::eInvalidAddress;
+        break;
+    case SEGV_ACCERR:
+        reason = ProcessMessage::ePrivilegedAddress;
+        break;
+    }
+
+    return reason;
+}
+#endif
+
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGILL(const siginfo_t *info)
+{
+    ProcessMessage::CrashReason reason;
+    assert(info->si_signo == SIGILL);
+
+    reason = ProcessMessage::eInvalidCrashReason;
+
+    switch (info->si_code)
+    {
+    default:
+        assert(false && "unexpected si_code for SIGILL");
+        break;
+    case ILL_ILLOPC:
+        reason = ProcessMessage::eIllegalOpcode;
+        break;
+    case ILL_ILLOPN:
+        reason = ProcessMessage::eIllegalOperand;
+        break;
+    case ILL_ILLADR:
+        reason = ProcessMessage::eIllegalAddressingMode;
+        break;
+    case ILL_ILLTRP:
+        reason = ProcessMessage::eIllegalTrap;
+        break;
+    case ILL_PRVOPC:
+        reason = ProcessMessage::ePrivilegedOpcode;
+        break;
+    case ILL_PRVREG:
+        reason = ProcessMessage::ePrivilegedRegister;
+        break;
+    case ILL_COPROC:
+        reason = ProcessMessage::eCoprocessorError;
+        break;
+    case ILL_BADSTK:
+        reason = ProcessMessage::eInternalStackError;
+        break;
+    }
+
+    return reason;
+}
+#endif
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGFPE(const siginfo_t *info)
+{
+    ProcessMessage::CrashReason reason;
+    assert(info->si_signo == SIGFPE);
+
+    reason = ProcessMessage::eInvalidCrashReason;
+
+    switch (info->si_code)
+    {
+    default:
+        assert(false && "unexpected si_code for SIGFPE");
+        break;
+    case FPE_INTDIV:
+        reason = ProcessMessage::eIntegerDivideByZero;
+        break;
+    case FPE_INTOVF:
+        reason = ProcessMessage::eIntegerOverflow;
+        break;
+    case FPE_FLTDIV:
+        reason = ProcessMessage::eFloatDivideByZero;
+        break;
+    case FPE_FLTOVF:
+        reason = ProcessMessage::eFloatOverflow;
+        break;
+    case FPE_FLTUND:
+        reason = ProcessMessage::eFloatUnderflow;
+        break;
+    case FPE_FLTRES:
+        reason = ProcessMessage::eFloatInexactResult;
+        break;
+    case FPE_FLTINV:
+        reason = ProcessMessage::eFloatInvalidOperation;
+        break;
+    case FPE_FLTSUB:
+        reason = ProcessMessage::eFloatSubscriptRange;
+        break;
+    }
+
+    return reason;
+}
+#endif
+
+#if 0
+ProcessMessage::CrashReason
+NativeProcessLinux::GetCrashReasonForSIGBUS(const siginfo_t *info)
+{
+    ProcessMessage::CrashReason reason;
+    assert(info->si_signo == SIGBUS);
+
+    reason = ProcessMessage::eInvalidCrashReason;
+
+    switch (info->si_code)
+    {
+    default:
+        assert(false && "unexpected si_code for SIGBUS");
+        break;
+    case BUS_ADRALN:
+        reason = ProcessMessage::eIllegalAlignment;
+        break;
+    case BUS_ADRERR:
+        reason = ProcessMessage::eIllegalAddress;
+        break;
+    case BUS_OBJERR:
+        reason = ProcessMessage::eHardwareError;
+        break;
+    }
+
+    return reason;
+}
+#endif
+
+void
+NativeProcessLinux::ServeOperation(OperationArgs *args)
+{
+    NativeProcessLinux *monitor = args->m_monitor;
+
+    // We are finised with the arguments and are ready to go.  Sync with the
+    // parent thread and start serving operations on the inferior.
+    sem_post(&args->m_semaphore);
+
+    for(;;)
+    {
+        // wait for next pending operation
+        if (sem_wait(&monitor->m_operation_pending))
+        {
+            if (errno == EINTR)
+                continue;
+            assert(false && "Unexpected errno from sem_wait");
+        }
+
+        reinterpret_cast<Operation*>(monitor->m_operation)->Execute(monitor);
+
+        // notify calling thread that operation is complete
+        sem_post(&monitor->m_operation_done);
+    }
+}
+
+void
+NativeProcessLinux::DoOperation(void *op)
+{
+    Mutex::Locker lock(m_operation_mutex);
+
+    m_operation = op;
+
+    // notify operation thread that an operation is ready to be processed
+    sem_post(&m_operation_pending);
+
+    // wait for operation to complete
+    while (sem_wait(&m_operation_done))
+    {
+        if (errno == EINTR)
+            continue;
+        assert(false && "Unexpected errno from sem_wait");
+    }
+}
+
+Error
+NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read)
+{
+    ReadOperation op(addr, buf, size, bytes_read);
+    DoOperation(&op);
+    return op.GetError ();
+}
+
+Error
+NativeProcessLinux::WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written)
+{
+    WriteOperation op(addr, buf, size, bytes_written);
+    DoOperation(&op);
+    return op.GetError ();
+}
+
+bool
+NativeProcessLinux::ReadRegisterValue(lldb::tid_t tid, uint32_t offset, const char* reg_name,
+                                  uint32_t size, RegisterValue &value)
+{
+    bool result;
+    ReadRegOperation op(tid, offset, reg_name, value, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
+                                   const char* reg_name, const RegisterValue &value)
+{
+    bool result;
+    WriteRegOperation op(tid, offset, reg_name, value, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    bool result;
+    ReadGPROperation op(tid, buf, buf_size, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    bool result;
+    ReadFPROperation op(tid, buf, buf_size, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+    bool result;
+    ReadRegisterSetOperation op(tid, buf, buf_size, regset, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    bool result;
+    WriteGPROperation op(tid, buf, buf_size, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    bool result;
+    WriteFPROperation op(tid, buf, buf_size, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+    bool result;
+    WriteRegisterSetOperation op(tid, buf, buf_size, regset, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo)
+{
+    bool result;
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+    if (log)
+        log->Printf ("NativeProcessLinux::%s() resuming thread = %"  PRIu64 " with signal %s", __FUNCTION__, tid,
+                                 GetUnixSignals().GetSignalAsCString (signo));
+    ResumeOperation op (tid, signo, result);
+    DoOperation (&op);
+    if (log)
+        log->Printf ("NativeProcessLinux::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
+    return result;
+}
+
+bool
+NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
+{
+    bool result;
+    SingleStepOperation op(tid, signo, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo, int &ptrace_err)
+{
+    bool result;
+    SiginfoOperation op(tid, siginfo, result, ptrace_err);
+    DoOperation(&op);
+    return result;
+}
+
+bool
+NativeProcessLinux::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+    bool result;
+    EventMessageOperation op(tid, message, result);
+    DoOperation(&op);
+    return result;
+}
+
+lldb_private::Error
+NativeProcessLinux::Detach(lldb::tid_t tid)
+{
+    lldb_private::Error error;
+    if (tid != LLDB_INVALID_THREAD_ID)
+    {
+        DetachOperation op(tid, error);
+        DoOperation(&op);
+    }
+    return error;
+}
+
+bool
+NativeProcessLinux::DupDescriptor(const char *path, int fd, int flags)
+{
+    int target_fd = open(path, flags, 0666);
+
+    if (target_fd == -1)
+        return false;
+
+    return (dup2(target_fd, fd) == -1) ? false : true;
+}
+
+void
+NativeProcessLinux::StopMonitoringChildProcess()
+{
+    lldb::thread_result_t thread_result;
+
+    if (IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+    {
+        Host::ThreadCancel(m_monitor_thread, NULL);
+        Host::ThreadJoin(m_monitor_thread, &thread_result, NULL);
+        m_monitor_thread = LLDB_INVALID_HOST_THREAD;
+    }
+}
+
+void
+NativeProcessLinux::StopMonitor()
+{
+    StopMonitoringChildProcess();
+    StopOpThread();
+    sem_destroy(&m_operation_pending);
+    sem_destroy(&m_operation_done);
+
+    // TODO: validate whether this still holds, fix up comment.
+    // Note: ProcessPOSIX passes the m_terminal_fd file descriptor to
+    // Process::SetSTDIOFileDescriptor, which in turn transfers ownership of
+    // the descriptor to a ConnectionFileDescriptor object.  Consequently
+    // even though still has the file descriptor, we shouldn't close it here.
+}
+
+void
+NativeProcessLinux::StopOpThread()
+{
+    lldb::thread_result_t result;
+
+    if (!IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+        return;
+
+    Host::ThreadCancel(m_operation_thread, NULL);
+    Host::ThreadJoin(m_operation_thread, &result, NULL);
+    m_operation_thread = LLDB_INVALID_HOST_THREAD;
+}
+
+bool
+NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id)
+{
+    for (auto thread_sp : m_threads)
+    {
+        assert (thread_sp && "thread list should not contain NULL threads");
+        if (thread_sp->GetID () == thread_id)
+        {
+            // We have this thread.
+            return true;
+        }
+    }
+
+    // We don't have this thread.
+    return false;
+}
+
+NativeThreadProtocolSP
+NativeProcessLinux::MaybeGetThreadNoLock (lldb::tid_t thread_id)
+{
+    // CONSIDER organize threads by map - we can do better than linear.
+    for (auto thread_sp : m_threads)
+    {
+        if (thread_sp->GetID () == thread_id)
+            return thread_sp;
+    }
+
+    // We don't have this thread.
+    return NativeThreadProtocolSP ();
+}
+
+bool
+NativeProcessLinux::StopTrackingThread (lldb::tid_t thread_id)
+{
+    Mutex::Locker locker (m_threads_mutex);
+    for (auto it = m_threads.begin (); it != m_threads.end (); ++it)
+    {
+        if (*it && ((*it)->GetID () == thread_id))
+        {
+            m_threads.erase (it);
+            return true;
+        }
+    }
+
+    // Didn't find it.
+    return false;
+}
+
+NativeThreadProtocolSP
+NativeProcessLinux::AddThread (lldb::tid_t thread_id)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    Mutex::Locker locker (m_threads_mutex);
+
+    if (log)
+    {
+        log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " adding thread with tid %" PRIu64,
+                __FUNCTION__,
+                GetID (),
+                thread_id);
+    }
+
+    assert (!HasThreadNoLock (thread_id) && "attempted to add a thread by id that already exists");
+
+    // If this is the first thread, save it as the current thread
+    if (m_threads.empty ())
+        SetCurrentThreadID (thread_id);
+
+    NativeThreadProtocolSP thread_sp (new NativeThreadLinux (this, thread_id));
+    m_threads.push_back (thread_sp);
+
+    return thread_sp;
+}
+
+NativeThreadProtocolSP
+NativeProcessLinux::GetOrCreateThread (lldb::tid_t thread_id, bool &created)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    Mutex::Locker locker (m_threads_mutex);
+    if (log)
+    {
+        log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " get/create thread with tid %" PRIu64,
+                     __FUNCTION__,
+                     GetID (),
+                     thread_id);
+    }
+
+    // Retrieve the thread if it is already getting tracked.
+    NativeThreadProtocolSP thread_sp = MaybeGetThreadNoLock (thread_id);
+    if (thread_sp)
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": thread already tracked, returning",
+                         __FUNCTION__,
+                         GetID (),
+                         thread_id);
+        created = false;
+        return thread_sp;
+
+    }
+
+    // Create the thread metadata since it isn't being tracked.
+    if (log)
+        log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": thread didn't exist, tracking now",
+                     __FUNCTION__,
+                     GetID (),
+                     thread_id);
+
+    thread_sp.reset (new NativeThreadLinux (this, thread_id));
+    m_threads.push_back (thread_sp);
+    created = true;
+    
+    return thread_sp;
+}
+
+Error
+NativeProcessLinux::FixupBreakpointPCAsNeeded (NativeThreadProtocolSP &thread_sp)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    Error error;
+
+    // Get a linux thread pointer.
+    if (!thread_sp)
+    {
+        error.SetErrorString ("null thread_sp");
+        if (log)
+            log->Printf ("NativeProcessLinux::%s failed: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+    NativeThreadLinux *const linux_thread_p = reinterpret_cast<NativeThreadLinux*> (thread_sp.get());
+
+    // Find out the size of a breakpoint (might depend on where we are in the code).
+    NativeRegisterContextSP context_sp = linux_thread_p->GetRegisterContext ();
+    if (!context_sp)
+    {
+        error.SetErrorString ("cannot get a NativeRegisterContext for the thread");
+        if (log)
+            log->Printf ("NativeProcessLinux::%s failed: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+
+    uint32_t breakpoint_size = 0;
+    error = GetSoftwareBreakpointSize (context_sp, breakpoint_size);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s GetBreakpointSize() failed: %s", __FUNCTION__, error.AsCString ());
+        return error;
+    }
+    else
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s breakpoint size: %" PRIu32, __FUNCTION__, breakpoint_size);
+    }
+
+    // First try probing for a breakpoint at a software breakpoint location: PC - breakpoint size.
+    const lldb::addr_t initial_pc_addr = context_sp->GetPC ();
+    lldb::addr_t breakpoint_addr = initial_pc_addr;
+    if (breakpoint_size > static_cast<lldb::addr_t> (0))
+    {
+        // Do not allow breakpoint probe to wrap around.
+        if (breakpoint_addr >= static_cast<lldb::addr_t> (breakpoint_size))
+            breakpoint_addr -= static_cast<lldb::addr_t> (breakpoint_size);
+    }
+
+    // Check if we stopped because of a breakpoint.
+    NativeBreakpointSP breakpoint_sp;
+    error = m_breakpoint_list.GetBreakpoint (breakpoint_addr, breakpoint_sp);
+    if (!error.Success () || !breakpoint_sp)
+    {
+        // We didn't find one at a software probe location.  Nothing to do.
+        if (log)
+            log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " no lldb breakpoint found at current pc with adjustment: 0x%" PRIx64, __FUNCTION__, GetID (), breakpoint_addr);
+        return Error ();
+    }
+
+    // If the breakpoint is not a software breakpoint, nothing to do.
+    if (!breakpoint_sp->IsSoftwareBreakpoint ())
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", not software, nothing to adjust", __FUNCTION__, GetID (), breakpoint_addr);
+        return Error ();
+    }
+
+    //
+    // We have a software breakpoint and need to adjust the PC.
+    //
+
+    // Sanity check.
+    if (breakpoint_size == 0)
+    {
+        // Nothing to do!  How did we get here?
+        if (log)
+            log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", it is software, but the size is zero, nothing to do (unexpected)", __FUNCTION__, GetID (), breakpoint_addr);
+        return Error ();
+    }
+
+    // Change the program counter.
+    if (log)
+        log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": changing PC from 0x%" PRIx64 " to 0x%" PRIx64, __FUNCTION__, GetID (), linux_thread_p->GetID (), initial_pc_addr, breakpoint_addr);
+
+    error = context_sp->SetPC (breakpoint_addr);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": failed to set PC: %s", __FUNCTION__, GetID (), linux_thread_p->GetID (), error.AsCString ());
+        return error;
+    }
+
+    return error;
+}

Added: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,379 @@
+//===-- NativeProcessLinux.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_NativeProcessLinux_H_
+#define liblldb_NativeProcessLinux_H_
+
+// C Includes
+#include <semaphore.h>
+#include <signal.h>
+
+// C++ Includes
+#include <unordered_set>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+
+#include "Host/common/NativeProcessProtocol.h"
+
+namespace lldb_private
+{
+    class Error;
+    class Module;
+    class Scalar;
+
+    /// @class NativeProcessLinux
+    /// @brief Manages communication with the inferior (debugee) process.
+    ///
+    /// Upon construction, this class prepares and launches an inferior process for
+    /// debugging.
+    ///
+    /// Changes in the inferior process state are broadcasted.
+    class NativeProcessLinux: public NativeProcessProtocol
+    {
+    public:
+
+        // ---------------------------------------------------------------------
+        // Public Static Methods
+        // ---------------------------------------------------------------------
+        static lldb_private::Error
+        LaunchProcess (
+            Module *exe_module,
+            ProcessLaunchInfo &launch_info,
+            lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+            NativeProcessProtocolSP &native_process_sp);
+
+        static lldb_private::Error
+        AttachToProcess (
+            lldb::pid_t pid,
+            lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+            NativeProcessProtocolSP &native_process_sp);
+
+        // ---------------------------------------------------------------------
+        // Public Instance Methods
+        // ---------------------------------------------------------------------
+
+        ~NativeProcessLinux() override;
+
+        // ---------------------------------------------------------------------
+        // NativeProcessProtocol Interface
+        // ---------------------------------------------------------------------
+        Error
+        Resume (const ResumeActionList &resume_actions) override;
+
+        Error
+        Halt () override;
+
+        Error
+        Detach () override;
+
+        Error
+        Signal (int signo) override;
+
+        Error
+        Kill () override;
+
+        Error
+        GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info) override;
+
+        Error
+        ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) override;
+
+        Error
+        WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) override;
+
+        Error
+        AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) override;
+
+        Error
+        DeallocateMemory (lldb::addr_t addr) override;
+
+        lldb::addr_t
+        GetSharedLibraryInfoAddress () override;
+
+        size_t
+        UpdateThreads () override;
+
+        bool
+        GetArchitecture (ArchSpec &arch) const override;
+
+        Error
+        SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) override;
+
+        void
+        DoStopIDBumped (uint32_t newBumpId) override;
+
+        // ---------------------------------------------------------------------
+        // Interface used by NativeRegisterContext-derived classes.
+        // ---------------------------------------------------------------------
+
+        /// Reads the contents from the register identified by the given (architecture
+        /// dependent) offset.
+        ///
+        /// This method is provided for use by RegisterContextLinux derivatives.
+        bool
+        ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+                          unsigned size, lldb_private::RegisterValue &value);
+
+        /// Writes the given value to the register identified by the given
+        /// (architecture dependent) offset.
+        ///
+        /// This method is provided for use by RegisterContextLinux derivatives.
+        bool
+        WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+                           const lldb_private::RegisterValue &value);
+
+        /// Reads all general purpose registers into the specified buffer.
+        bool
+        ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+        /// Reads generic floating point registers into the specified buffer.
+        bool
+        ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+        /// Reads the specified register set into the specified buffer.
+        /// For instance, the extended floating-point register set.
+        bool
+        ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+        /// Writes all general purpose registers into the specified buffer.
+        bool
+        WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+        /// Writes generic floating point registers into the specified buffer.
+        bool
+        WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+        /// Writes the specified register set into the specified buffer.
+        /// For instance, the extended floating-point register set.
+        bool
+        WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+        
+    protected:
+        // ---------------------------------------------------------------------
+        // NativeProcessProtocol protected interface
+        // ---------------------------------------------------------------------
+        Error
+        GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) override;
+
+    private:
+
+        lldb_private::ArchSpec m_arch;
+
+        lldb::thread_t m_operation_thread;
+        lldb::thread_t m_monitor_thread;
+
+        // current operation which must be executed on the priviliged thread
+        void *m_operation;
+        lldb_private::Mutex m_operation_mutex;
+
+        // semaphores notified when Operation is ready to be processed and when
+        // the operation is complete.
+        sem_t m_operation_pending;
+        sem_t m_operation_done;
+
+        // Set of tids we're waiting to stop before we notify the delegate of
+        // the stopped state.  We only notify the delegate after all threads
+        // ordered to stop have signaled their stop.
+        std::unordered_set<lldb::tid_t> m_wait_for_stop_tids;
+        lldb_private::Mutex m_wait_for_stop_tids_mutex;
+
+        lldb_private::LazyBool m_supports_mem_region;
+        std::vector<MemoryRegionInfo> m_mem_region_cache;
+        lldb_private::Mutex m_mem_region_cache_mutex;
+
+
+        struct OperationArgs
+        {
+            OperationArgs(NativeProcessLinux *monitor);
+
+            ~OperationArgs();
+
+            NativeProcessLinux *m_monitor;      // The monitor performing the attach.
+            sem_t m_semaphore;              // Posted to once operation complete.
+            lldb_private::Error m_error;    // Set if process operation failed.
+        };
+
+        /// @class LauchArgs
+        ///
+        /// @brief Simple structure to pass data to the thread responsible for
+        /// launching a child process.
+        struct LaunchArgs : OperationArgs
+        {
+            LaunchArgs(NativeProcessLinux *monitor,
+                    lldb_private::Module *module,
+                    char const **argv,
+                    char const **envp,
+                    const char *stdin_path,
+                    const char *stdout_path,
+                    const char *stderr_path,
+                    const char *working_dir);
+
+            ~LaunchArgs();
+
+            lldb_private::Module *m_module; // The executable image to launch.
+            char const **m_argv;            // Process arguments.
+            char const **m_envp;            // Process environment.
+            const char *m_stdin_path;       // Redirect stdin or NULL.
+            const char *m_stdout_path;      // Redirect stdout or NULL.
+            const char *m_stderr_path;      // Redirect stderr or NULL.
+            const char *m_working_dir;      // Working directory or NULL.
+        };
+
+        struct AttachArgs : OperationArgs
+        {
+            AttachArgs(NativeProcessLinux *monitor,
+                       lldb::pid_t pid);
+
+            ~AttachArgs();
+
+            lldb::pid_t m_pid;              // pid of the process to be attached.
+        };
+
+        // ---------------------------------------------------------------------
+        // Private Instance Methods
+        // ---------------------------------------------------------------------
+        NativeProcessLinux ();
+
+        /// Launches an inferior process ready for debugging.  Forms the
+        /// implementation of Process::DoLaunch.
+        void
+        LaunchInferior (
+            Module *module,
+            char const *argv[],
+            char const *envp[],
+            const char *stdin_path,
+            const char *stdout_path,
+            const char *stderr_path,
+            const char *working_dir,
+            Error &error);
+
+        /// Attaches to an existing process.  Forms the
+        /// implementation of Process::DoLaunch.
+        void
+        AttachToInferior (lldb::pid_t pid, Error &error);
+
+        void
+        StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
+
+        static void *
+        LaunchOpThread(void *arg);
+
+        static bool
+        Launch(LaunchArgs *args);
+
+        void
+        StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+
+        static void *
+        AttachOpThread(void *args);
+
+        static bool
+        Attach(AttachArgs *args);
+
+        static bool
+        SetDefaultPtraceOpts(const lldb::pid_t);
+
+        static void
+        ServeOperation(OperationArgs *args);
+
+        static bool
+        DupDescriptor(const char *path, int fd, int flags);
+
+        static bool
+        MonitorCallback(void *callback_baton,
+                lldb::pid_t pid, bool exited, int signal, int status);
+
+        void
+        MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid);
+
+        void
+        MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool exited);
+
+#if 0
+        static ::ProcessMessage::CrashReason
+        GetCrashReasonForSIGSEGV(const siginfo_t *info);
+
+        static ::ProcessMessage::CrashReason
+        GetCrashReasonForSIGILL(const siginfo_t *info);
+
+        static ::ProcessMessage::CrashReason
+        GetCrashReasonForSIGFPE(const siginfo_t *info);
+
+        static ::ProcessMessage::CrashReason
+        GetCrashReasonForSIGBUS(const siginfo_t *info);
+#endif
+
+        void
+        DoOperation(void *op);
+
+        /// Stops the child monitor thread.
+        void
+        StopMonitoringChildProcess();
+
+        /// Stops the operation thread used to attach/launch a process.
+        void
+        StopOpThread();
+
+        /// Stops monitoring the child process thread.
+        void
+        StopMonitor();
+
+        bool
+        HasThreadNoLock (lldb::tid_t thread_id);
+
+        NativeThreadProtocolSP
+        MaybeGetThreadNoLock (lldb::tid_t thread_id);
+
+        bool
+        StopTrackingThread (lldb::tid_t thread_id);
+
+        NativeThreadProtocolSP
+        AddThread (lldb::tid_t thread_id);
+
+        NativeThreadProtocolSP
+        GetOrCreateThread (lldb::tid_t thread_id, bool &created);
+
+        Error
+        GetSoftwareBreakpointSize (NativeRegisterContextSP context_sp, uint32_t &actual_opcode_size);
+
+        Error
+        FixupBreakpointPCAsNeeded (NativeThreadProtocolSP &thread_sp);
+
+        /// Writes a siginfo_t structure corresponding to the given thread ID to the
+        /// memory region pointed to by @p siginfo.
+        bool
+        GetSignalInfo(lldb::tid_t tid, void *siginfo, int &ptrace_err);
+
+        /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+        /// corresponding to the given thread ID to the memory pointed to by @p
+        /// message.
+        bool
+        GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+        /// Resumes the given thread.  If @p signo is anything but
+        /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+        bool
+        Resume(lldb::tid_t tid, uint32_t signo);
+
+        /// Single steps the given thread.  If @p signo is anything but
+        /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+        bool
+        SingleStep(lldb::tid_t tid, uint32_t signo);
+
+        lldb_private::Error
+        Detach(lldb::tid_t tid);
+    };
+} // End lldb_private namespace.
+
+#endif // #ifndef liblldb_NativeProcessLinux_H_

Added: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,363 @@
+//===-- NativeThreadLinux.cpp --------------------------------- -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadLinux.h"
+
+#include <signal.h>
+
+#include "NativeProcessLinux.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private-log.h"
+#include "Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterInfoInterface.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+    void LogThreadStopInfo (Log &log, const ThreadStopInfo &stop_info, const char *const header)
+    {
+        switch (stop_info.reason)
+        {
+            case eStopReasonSignal:
+                log.Printf ("%s: %s: signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo);
+                return;
+            case eStopReasonException:
+                log.Printf ("%s: %s: exception type 0x%" PRIx64, __FUNCTION__, header, stop_info.details.exception.type);
+                return;
+            default:
+                log.Printf ("%s: %s: invalid stop reason %" PRIu32, __FUNCTION__, header, static_cast<uint32_t> (stop_info.reason));
+        }
+    }
+}
+
+NativeThreadLinux::NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid) :
+    NativeThreadProtocol (process, tid),
+    m_state (StateType::eStateInvalid),
+    m_stop_info (),
+    m_reg_context_sp ()
+{
+}
+
+const char *
+NativeThreadLinux::GetName()
+{
+    NativeProcessProtocolSP process_sp = m_process_wp.lock ();
+    if (!process_sp)
+        return "<unknown: no process>";
+
+    // const NativeProcessLinux *const process = reinterpret_cast<NativeProcessLinux*> (process_sp->get ());
+    return Host::GetThreadName (process_sp->GetID (), GetID ()).c_str ();
+}
+
+lldb::StateType
+NativeThreadLinux::GetState ()
+{
+    return m_state;
+}
+
+
+bool
+NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+    switch (m_state)
+    {
+    case eStateStopped:
+    case eStateCrashed:
+    case eStateExited:
+    case eStateSuspended:
+    case eStateUnloaded:
+        if (log)
+            LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread: ");
+        stop_info = m_stop_info;
+        if (log)
+            LogThreadStopInfo (*log, stop_info, "returned stop_info: ");
+        return true;
+
+    case eStateInvalid:
+    case eStateConnected:
+    case eStateAttaching:
+    case eStateLaunching:
+    case eStateRunning:
+    case eStateStepping:
+    case eStateDetached:
+    default:
+        if (log)
+        {
+            log->Printf ("NativeThreadLinux::%s tid %" PRIu64 " in state %s cannot answer stop reason",
+                    __FUNCTION__, GetID (), StateAsCString (m_state));
+        }
+        return false;
+    }
+}
+
+lldb_private::NativeRegisterContextSP
+NativeThreadLinux::GetRegisterContext ()
+{
+    // Return the register context if we already created it.
+    if (m_reg_context_sp)
+        return m_reg_context_sp;
+
+    // First select the appropriate RegisterInfoInterface.
+    RegisterInfoInterface *reg_interface = nullptr;
+    NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
+    if (!m_process_sp)
+        return NativeRegisterContextSP ();
+
+    ArchSpec target_arch;
+    if (!m_process_sp->GetArchitecture (target_arch))
+        return NativeRegisterContextSP ();
+
+    switch (target_arch.GetTriple().getOS())
+    {
+        case llvm::Triple::Linux:
+            switch (target_arch.GetMachine())
+            {
+            case llvm::Triple::x86:
+            case llvm::Triple::x86_64:
+                if (Host::GetArchitecture().GetAddressByteSize() == 4)
+                {
+                    // 32-bit hosts run with a RegisterContextLinux_i386 context.
+                    reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch));
+                }
+                else
+                {
+                    assert((Host::GetArchitecture ().GetAddressByteSize () == 8) && "Register setting path assumes this is a 64-bit host");
+                    // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
+                    reg_interface = static_cast<RegisterInfoInterface*> (new RegisterContextLinux_x86_64 (target_arch));
+                }
+                break;
+            default:
+                break;
+            }
+            break;
+        default:
+            break;
+    }
+
+    assert(reg_interface && "OS or CPU not supported!");
+    if (!reg_interface)
+        return NativeRegisterContextSP ();
+
+    // Now create the register context.
+    switch (target_arch.GetMachine())
+    {
+#if 0
+        case llvm::Triple::mips64:
+        {
+            RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
+            m_posix_thread = reg_ctx;
+            m_reg_context_sp.reset(reg_ctx);
+            break;
+        }
+#endif
+#if 0
+        case llvm::Triple::x86:
+#endif
+        case llvm::Triple::x86_64:
+        {
+            const uint32_t concrete_frame_idx = 0;
+            m_reg_context_sp.reset (new NativeRegisterContextLinux_x86_64(*this, concrete_frame_idx, reg_interface));
+            break;
+        }
+        default:
+            break;
+    }
+
+    return m_reg_context_sp;
+}
+
+Error
+NativeThreadLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware)
+{
+    // TODO implement
+    return Error ("not implemented");
+}
+
+Error
+NativeThreadLinux::RemoveWatchpoint (lldb::addr_t addr)
+{
+    // TODO implement
+    return Error ("not implemented");
+}
+
+void
+NativeThreadLinux::SetLaunching ()
+{
+    const StateType new_state = StateType::eStateLaunching;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    // Also mark it as stopped since launching temporarily stops the newly created thread
+    // in the ptrace machinery.
+    m_stop_info.reason = StopReason::eStopReasonSignal;
+    m_stop_info.details.signal.signo = SIGSTOP;
+}
+
+
+void
+NativeThreadLinux::SetRunning ()
+{
+    const StateType new_state = StateType::eStateRunning;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void
+NativeThreadLinux::SetStepping ()
+{
+    const StateType new_state = StateType::eStateStepping;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void
+NativeThreadLinux::SetStoppedBySignal (uint32_t signo)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("NativeThreadLinux::%s called with signal 0x%" PRIx32, __FUNCTION__, signo);
+
+    const StateType new_state = StateType::eStateStopped;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    m_stop_info.reason = StopReason::eStopReasonSignal;
+    m_stop_info.details.signal.signo = signo;
+}
+
+void
+NativeThreadLinux::SetStoppedByBreakpoint ()
+{
+    const StateType new_state = StateType::eStateStopped;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    m_stop_info.reason = StopReason::eStopReasonSignal;
+    m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+bool
+NativeThreadLinux::IsStoppedAtBreakpoint ()
+{
+    // Are we stopped? If not, this can't be a breakpoint.
+    if (GetState () != StateType::eStateStopped)
+        return false;
+
+    // Was the stop reason a signal with signal number SIGTRAP? If not, not a breakpoint.
+    return (m_stop_info.reason == StopReason::eStopReasonSignal) &&
+            (m_stop_info.details.signal.signo == SIGTRAP);
+}
+
+void
+NativeThreadLinux::SetCrashedWithException (uint64_t exception_type, lldb::addr_t exception_addr)
+{
+    const StateType new_state = StateType::eStateCrashed;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    m_stop_info.reason = StopReason::eStopReasonException;
+    m_stop_info.details.exception.type = exception_type;
+    m_stop_info.details.exception.data_count = 1;
+    m_stop_info.details.exception.data[0] = exception_addr;
+}
+
+
+void
+NativeThreadLinux::SetSuspended ()
+{
+    const StateType new_state = StateType::eStateSuspended;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    // FIXME what makes sense here? Do we need a suspended StopReason?
+    m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void
+NativeThreadLinux::SetExited ()
+{
+    const StateType new_state = StateType::eStateExited;
+    MaybeLogStateChange (new_state);
+    m_state = new_state;
+
+    m_stop_info.reason = StopReason::eStopReasonThreadExiting;
+}
+
+void
+NativeThreadLinux::MaybeLogStateChange (lldb::StateType new_state)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+    // If we're not logging, we're done.
+    if (!log)
+        return;
+
+    // If this is a state change to the same state, we're done.
+    lldb::StateType old_state = m_state;
+    if (new_state == old_state)
+        return;
+
+    NativeProcessProtocolSP m_process_sp = m_process_wp.lock ();
+    lldb::pid_t pid = m_process_sp ? m_process_sp->GetID () : LLDB_INVALID_PROCESS_ID;
+
+    // Log it.
+    log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 ") changing from state %s to %s", pid, GetID (), StateAsCString (old_state), StateAsCString (new_state));
+}
+
+static
+uint32_t MaybeTranslateHostSignoToGdbSigno (uint32_t host_signo)
+{
+    switch (host_signo)
+    {
+        case SIGSEGV: return eGdbSignalBadAccess;
+        case SIGILL:  return eGdbSignalBadInstruction;
+        case SIGFPE:  return eGdbSignalArithmetic;
+        // NOTE: debugserver sends SIGTRAP through unmodified.  Do the same here.
+        // case SIGTRAP: return eGdbSignalBreakpoint;
+
+        // Nothing for eGdbSignalSoftware (0x95).
+        // Nothing for eGdbSignalEmulation (0x94).
+
+        default:
+            // No translations.
+            return host_signo;
+    }
+}
+
+uint32_t
+NativeThreadLinux::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const
+{
+    switch (stop_info.reason)
+    {
+        case eStopReasonSignal:
+            return MaybeTranslateHostSignoToGdbSigno (stop_info.details.signal.signo);
+            break;
+
+        case eStopReasonException:
+            // FIXME verify how we handle exception type.
+            return MaybeTranslateHostSignoToGdbSigno (static_cast<uint32_t> (stop_info.details.exception.type));
+            break;
+
+        default:
+            assert (0 && "unexpected stop_info.reason found");
+            return 0;
+    }
+}
+

Added: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,97 @@
+//===-- NativeThreadLinux.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_NativeThreadLinux_H_
+#define liblldb_NativeThreadLinux_H_
+
+#include "lldb/lldb-private-forward.h"
+#include "../../../Host/common/NativeThreadProtocol.h"
+
+namespace lldb_private
+{
+    class NativeProcessLinux;
+
+    class NativeThreadLinux : public NativeThreadProtocol
+    {
+        friend class NativeProcessLinux;
+
+    public:
+        NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid);
+
+        // ---------------------------------------------------------------------
+        // NativeThreadProtocol Interface
+        // ---------------------------------------------------------------------
+        const char *
+        GetName() override;
+
+        lldb::StateType
+        GetState () override;
+
+        bool
+        GetStopReason (ThreadStopInfo &stop_info) override;
+
+        NativeRegisterContextSP
+        GetRegisterContext () override;
+
+        Error
+        SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) override;
+
+        Error
+        RemoveWatchpoint (lldb::addr_t addr) override;
+
+        uint32_t
+        TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const override;
+
+    private:
+        // ---------------------------------------------------------------------
+        // Interface for friend classes
+        // ---------------------------------------------------------------------
+        void
+        SetLaunching ();
+
+        void
+        SetRunning ();
+
+        void
+        SetStepping ();
+
+        void
+        SetStoppedBySignal (uint32_t signo);
+
+        void
+        SetStoppedByBreakpoint ();
+
+        bool
+        IsStoppedAtBreakpoint ();
+
+        void
+        SetCrashedWithException (uint64_t exception_type, lldb::addr_t exception_addr);
+
+        void
+        SetSuspended ();
+
+        void
+        SetExited ();
+
+        // ---------------------------------------------------------------------
+        // Private interface
+        // ---------------------------------------------------------------------
+        void
+        MaybeLogStateChange (lldb::StateType new_state);
+
+        // ---------------------------------------------------------------------
+        // Member Variables
+        // ---------------------------------------------------------------------
+        lldb::StateType m_state;
+        ThreadStopInfo m_stop_info;
+        NativeRegisterContextSP m_reg_context_sp;
+    };
+}
+
+#endif // #ifndef liblldb_NativeThreadLinux_H_

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h Mon Jun 30 16:05:18 2014
@@ -17,10 +17,11 @@
 
 // Other libraries and framework includes
 #include "lldb/Target/Process.h"
-#include "LinuxSignals.h"
 #include "ProcessMessage.h"
 #include "ProcessPOSIX.h"
 
+#include "Plugins/Process/Utility/LinuxSignals.h"
+
 class ProcessMonitor;
 
 class ProcessLinux :
@@ -107,7 +108,7 @@ public:
 private:
 
     /// Linux-specific signal set.
-    LinuxSignals m_linux_signals;
+    process_linux::LinuxSignals m_linux_signals;
 
     lldb_private::FileSpec *m_core_file;
 

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Mon Jun 30 16:05:18 2014
@@ -1228,8 +1228,12 @@ ProcessMonitor::Launch(LaunchArgs *args)
 
     // Wait for the child process to to trap on its call to execve.
     lldb::pid_t wpid;
+    ::pid_t raw_pid;
     int status;
-    if ((wpid = waitpid(pid, &status, 0)) < 0)
+
+    raw_pid = waitpid(pid, &status, 0);
+    wpid = static_cast <lldb::pid_t> (raw_pid);
+    if (raw_pid < 0)
     {
         args->m_error.SetErrorToErrno();
         goto FINISH;

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Mon Jun 30 16:05:18 2014
@@ -934,3 +934,16 @@ ProcessPOSIX::IsAThreadRunning()
     }
     return is_running;
 }
+
+const DataBufferSP
+ProcessPOSIX::GetAuxvData ()
+{
+    // If we're the local platform, we can ask the host for auxv data.
+    PlatformSP platform_sp = m_target.GetPlatform ();
+    if (platform_sp && platform_sp->IsHost ())
+        return lldb_private::Host::GetAuxvData(this);
+
+    // Somewhat unexpected - the process is not running locally or we don't have a platform.
+    assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?");
+    return DataBufferSP ();
+}

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.h Mon Jun 30 16:05:18 2014
@@ -141,6 +141,9 @@ public:
     virtual size_t
     PutSTDIN(const char *buf, size_t len, lldb_private::Error &error);
 
+    const lldb::DataBufferSP
+    GetAuxvData () override;
+
     //--------------------------------------------------------------------------
     // ProcessPOSIX internal API.
 

Modified: lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Utility/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -8,6 +8,8 @@ add_lldb_library(lldbPluginProcessUtilit
   HistoryThread.cpp
   HistoryUnwind.cpp
   InferiorCallPOSIX.cpp
+  LinuxSignals.cpp
+  NativeRegisterContextLinux_x86_64.cpp
   RegisterContextDarwin_arm.cpp
   RegisterContextDarwin_arm64.cpp
   RegisterContextDarwin_i386.cpp

Added: lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,79 @@
+//===-- LinuxSignals.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <signal.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "LinuxSignals.h"
+
+using namespace process_linux;
+
+LinuxSignals::LinuxSignals()
+    : UnixSignals()
+{
+    Reset();
+}
+
+void
+LinuxSignals::Reset()
+{
+    m_signals.clear();
+
+    // FIXME we now need *Signals classes on systems that are different OSes (e.g. LinuxSignals
+    // needed on MacOSX to debug Linux from MacOSX, and similar scenarios, used by ProcessGDBRemote).  These must be defined
+    // not based on OS includes and defines.
+
+#define ADDSIGNAL(S, SUPPRESS, STOP, NOTIFY, DESCRIPTION) \
+    AddSignal(SIG ## S, "SIG" #S, #S, SUPPRESS, STOP, NOTIFY, DESCRIPTION)
+
+    ADDSIGNAL(HUP,    false,  true,  true, "hangup");
+    ADDSIGNAL(INT,    true,   true,  true, "interrupt");
+    ADDSIGNAL(QUIT,   false,  true,  true, "quit");
+    ADDSIGNAL(ILL,    false,  true,  true, "illegal instruction");
+    ADDSIGNAL(TRAP,   true,   true,  true, "trace trap (not reset when caught)");
+    ADDSIGNAL(ABRT,   false,  true,  true, "abort");
+    ADDSIGNAL(IOT,    false,  true,  true, "abort");
+    ADDSIGNAL(BUS,    false,  true,  true, "bus error");
+    ADDSIGNAL(FPE,    false,  true,  true, "floating point exception");
+    ADDSIGNAL(KILL,   false,  true,  true, "kill");
+    ADDSIGNAL(USR1,   false,  true,  true, "user defined signal 1");
+    ADDSIGNAL(SEGV,   false,  true,  true, "segmentation violation");
+    ADDSIGNAL(USR2,   false,  true,  true, "user defined signal 2");
+    ADDSIGNAL(PIPE,   false,  true,  true, "write to pipe with reading end closed");
+    ADDSIGNAL(ALRM,   false,  false, true, "alarm");
+    ADDSIGNAL(TERM,   false,  true,  true, "termination requested");
+#ifdef SIGSTKFLT
+    ADDSIGNAL(STKFLT, false,  true,  true, "stack fault");
+#endif
+    ADDSIGNAL(CHLD,   false,  false, true, "child process exit");
+    ADDSIGNAL(CONT,   false,  true,  true, "process continue");
+    ADDSIGNAL(STOP,   true,   true,  true, "process stop");
+    ADDSIGNAL(TSTP,   false,  true,  true, "tty stop");
+    ADDSIGNAL(TTIN,   false,  true,  true, "background tty read");
+    ADDSIGNAL(TTOU,   false,  true,  true, "background tty write");
+    ADDSIGNAL(URG,    false,  true,  true, "urgent data on socket");
+    ADDSIGNAL(XCPU,   false,  true,  true, "CPU resource exceeded");
+    ADDSIGNAL(XFSZ,   false,  true,  true, "file size limit exceeded");
+    ADDSIGNAL(VTALRM, false,  true,  true, "virtual alarm");
+    ADDSIGNAL(PROF,   false,  true,  true, "profiling alarm");
+    ADDSIGNAL(WINCH,  false,  true,  true, "window size change");
+#ifdef SIGPOLL
+    ADDSIGNAL(POLL,   false,  true,  true, "pollable event");
+#endif
+    ADDSIGNAL(IO,     false,  true,  true, "input/output ready");
+#ifdef SIGPWR
+    ADDSIGNAL(PWR,    false,  true,  true, "power failure");
+#endif
+    ADDSIGNAL(SYS,    false,  true,  true, "invalid system call");
+
+#undef ADDSIGNAL
+}

Added: lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/LinuxSignals.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,35 @@
+//===-- LinuxSignals.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_LinuxSignals_H_
+#define liblldb_LinuxSignals_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace process_linux
+{
+
+    /// Linux specific set of Unix signals.
+    class LinuxSignals
+        : public lldb_private::UnixSignals
+    {
+    public:
+        LinuxSignals();
+
+    private:
+        void
+        Reset();
+    };
+}
+
+#endif

Added: lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,1040 @@
+//===-- NativeRegisterContextLinux_x86_64.cpp ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextLinux_x86_64.h"
+
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
+#include "Plugins/Process/Linux/NativeProcessLinux.h"
+
+using namespace lldb_private;
+
+// ----------------------------------------------------------------------------
+// Private namespace.
+// ----------------------------------------------------------------------------
+
+namespace
+{
+    // x86 32-bit general purpose registers.
+    const uint32_t
+    g_gpr_regnums_i386[] =
+    {
+        gpr_eax_i386,
+        gpr_ebx_i386,
+        gpr_ecx_i386,
+        gpr_edx_i386,
+        gpr_edi_i386,
+        gpr_esi_i386,
+        gpr_ebp_i386,
+        gpr_esp_i386,
+        gpr_eip_i386,
+        gpr_eflags_i386,
+        gpr_cs_i386,
+        gpr_fs_i386,
+        gpr_gs_i386,
+        gpr_ss_i386,
+        gpr_ds_i386,
+        gpr_es_i386,
+        gpr_ax_i386,
+        gpr_bx_i386,
+        gpr_cx_i386,
+        gpr_dx_i386,
+        gpr_di_i386,
+        gpr_si_i386,
+        gpr_bp_i386,
+        gpr_sp_i386,
+        gpr_ah_i386,
+        gpr_bh_i386,
+        gpr_ch_i386,
+        gpr_dh_i386,
+        gpr_al_i386,
+        gpr_bl_i386,
+        gpr_cl_i386,
+        gpr_dl_i386,
+        LLDB_INVALID_REGNUM // register sets need to end with this flag
+    };
+    static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - 1 == k_num_gpr_registers_i386,
+                  "g_gpr_regnums_i386 has wrong number of register infos");
+
+    // x86 32-bit floating point registers.
+    const uint32_t
+    g_fpu_regnums_i386[] =
+    {
+        fpu_fctrl_i386,
+        fpu_fstat_i386,
+        fpu_ftag_i386,
+        fpu_fop_i386,
+        fpu_fiseg_i386,
+        fpu_fioff_i386,
+        fpu_foseg_i386,
+        fpu_fooff_i386,
+        fpu_mxcsr_i386,
+        fpu_mxcsrmask_i386,
+        fpu_st0_i386,
+        fpu_st1_i386,
+        fpu_st2_i386,
+        fpu_st3_i386,
+        fpu_st4_i386,
+        fpu_st5_i386,
+        fpu_st6_i386,
+        fpu_st7_i386,
+        fpu_mm0_i386,
+        fpu_mm1_i386,
+        fpu_mm2_i386,
+        fpu_mm3_i386,
+        fpu_mm4_i386,
+        fpu_mm5_i386,
+        fpu_mm6_i386,
+        fpu_mm7_i386,
+        fpu_xmm0_i386,
+        fpu_xmm1_i386,
+        fpu_xmm2_i386,
+        fpu_xmm3_i386,
+        fpu_xmm4_i386,
+        fpu_xmm5_i386,
+        fpu_xmm6_i386,
+        fpu_xmm7_i386,
+        LLDB_INVALID_REGNUM // register sets need to end with this flag
+    };
+    static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
+                  "g_fpu_regnums_i386 has wrong number of register infos");
+
+    // x86 32-bit AVX registers.
+    const uint32_t
+    g_avx_regnums_i386[] =
+    {
+        fpu_ymm0_i386,
+        fpu_ymm1_i386,
+        fpu_ymm2_i386,
+        fpu_ymm3_i386,
+        fpu_ymm4_i386,
+        fpu_ymm5_i386,
+        fpu_ymm6_i386,
+        fpu_ymm7_i386,
+        LLDB_INVALID_REGNUM // register sets need to end with this flag
+    };
+    static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386,
+                  " g_avx_regnums_i386 has wrong number of register infos");
+
+    // x86 64-bit general purpose registers.
+    static const
+    uint32_t g_gpr_regnums_x86_64[] =
+    {
+        gpr_rax_x86_64,
+        gpr_rbx_x86_64,
+        gpr_rcx_x86_64,
+        gpr_rdx_x86_64,
+        gpr_rdi_x86_64,
+        gpr_rsi_x86_64,
+        gpr_rbp_x86_64,
+        gpr_rsp_x86_64,
+        gpr_r8_x86_64,
+        gpr_r9_x86_64,
+        gpr_r10_x86_64,
+        gpr_r11_x86_64,
+        gpr_r12_x86_64,
+        gpr_r13_x86_64,
+        gpr_r14_x86_64,
+        gpr_r15_x86_64,
+        gpr_rip_x86_64,
+        gpr_rflags_x86_64,
+        gpr_cs_x86_64,
+        gpr_fs_x86_64,
+        gpr_gs_x86_64,
+        gpr_ss_x86_64,
+        gpr_ds_x86_64,
+        gpr_es_x86_64,
+        gpr_eax_x86_64,
+        gpr_ebx_x86_64,
+        gpr_ecx_x86_64,
+        gpr_edx_x86_64,
+        gpr_edi_x86_64,
+        gpr_esi_x86_64,
+        gpr_ebp_x86_64,
+        gpr_esp_x86_64,
+        gpr_r8d_x86_64,    // Low 32 bits or r8
+        gpr_r9d_x86_64,    // Low 32 bits or r9
+        gpr_r10d_x86_64,   // Low 32 bits or r10
+        gpr_r11d_x86_64,   // Low 32 bits or r11
+        gpr_r12d_x86_64,   // Low 32 bits or r12
+        gpr_r13d_x86_64,   // Low 32 bits or r13
+        gpr_r14d_x86_64,   // Low 32 bits or r14
+        gpr_r15d_x86_64,   // Low 32 bits or r15
+        gpr_ax_x86_64,
+        gpr_bx_x86_64,
+        gpr_cx_x86_64,
+        gpr_dx_x86_64,
+        gpr_di_x86_64,
+        gpr_si_x86_64,
+        gpr_bp_x86_64,
+        gpr_sp_x86_64,
+        gpr_r8w_x86_64,    // Low 16 bits or r8
+        gpr_r9w_x86_64,    // Low 16 bits or r9
+        gpr_r10w_x86_64,   // Low 16 bits or r10
+        gpr_r11w_x86_64,   // Low 16 bits or r11
+        gpr_r12w_x86_64,   // Low 16 bits or r12
+        gpr_r13w_x86_64,   // Low 16 bits or r13
+        gpr_r14w_x86_64,   // Low 16 bits or r14
+        gpr_r15w_x86_64,   // Low 16 bits or r15
+        gpr_ah_x86_64,
+        gpr_bh_x86_64,
+        gpr_ch_x86_64,
+        gpr_dh_x86_64,
+        gpr_al_x86_64,
+        gpr_bl_x86_64,
+        gpr_cl_x86_64,
+        gpr_dl_x86_64,
+        gpr_dil_x86_64,
+        gpr_sil_x86_64,
+        gpr_bpl_x86_64,
+        gpr_spl_x86_64,
+        gpr_r8l_x86_64,    // Low 8 bits or r8
+        gpr_r9l_x86_64,    // Low 8 bits or r9
+        gpr_r10l_x86_64,   // Low 8 bits or r10
+        gpr_r11l_x86_64,   // Low 8 bits or r11
+        gpr_r12l_x86_64,   // Low 8 bits or r12
+        gpr_r13l_x86_64,   // Low 8 bits or r13
+        gpr_r14l_x86_64,   // Low 8 bits or r14
+        gpr_r15l_x86_64,   // Low 8 bits or r15
+        LLDB_INVALID_REGNUM // register sets need to end with this flag
+    };
+    static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - 1 == k_num_gpr_registers_x86_64,
+                  "g_gpr_regnums_x86_64 has wrong number of register infos");
+
+    // x86 64-bit floating point registers.
+    static const uint32_t
+    g_fpu_regnums_x86_64[] =
+    {
+        fpu_fctrl_x86_64,
+        fpu_fstat_x86_64,
+        fpu_ftag_x86_64,
+        fpu_fop_x86_64,
+        fpu_fiseg_x86_64,
+        fpu_fioff_x86_64,
+        fpu_foseg_x86_64,
+        fpu_fooff_x86_64,
+        fpu_mxcsr_x86_64,
+        fpu_mxcsrmask_x86_64,
+        fpu_st0_x86_64,
+        fpu_st1_x86_64,
+        fpu_st2_x86_64,
+        fpu_st3_x86_64,
+        fpu_st4_x86_64,
+        fpu_st5_x86_64,
+        fpu_st6_x86_64,
+        fpu_st7_x86_64,
+        fpu_mm0_x86_64,
+        fpu_mm1_x86_64,
+        fpu_mm2_x86_64,
+        fpu_mm3_x86_64,
+        fpu_mm4_x86_64,
+        fpu_mm5_x86_64,
+        fpu_mm6_x86_64,
+        fpu_mm7_x86_64,
+        fpu_xmm0_x86_64,
+        fpu_xmm1_x86_64,
+        fpu_xmm2_x86_64,
+        fpu_xmm3_x86_64,
+        fpu_xmm4_x86_64,
+        fpu_xmm5_x86_64,
+        fpu_xmm6_x86_64,
+        fpu_xmm7_x86_64,
+        fpu_xmm8_x86_64,
+        fpu_xmm9_x86_64,
+        fpu_xmm10_x86_64,
+        fpu_xmm11_x86_64,
+        fpu_xmm12_x86_64,
+        fpu_xmm13_x86_64,
+        fpu_xmm14_x86_64,
+        fpu_xmm15_x86_64,
+        LLDB_INVALID_REGNUM // register sets need to end with this flag
+    };
+    static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
+                  "g_fpu_regnums_x86_64 has wrong number of register infos");
+
+    // x86 64-bit AVX registers.
+    static const uint32_t
+    g_avx_regnums_x86_64[] =
+    {
+        fpu_ymm0_x86_64,
+        fpu_ymm1_x86_64,
+        fpu_ymm2_x86_64,
+        fpu_ymm3_x86_64,
+        fpu_ymm4_x86_64,
+        fpu_ymm5_x86_64,
+        fpu_ymm6_x86_64,
+        fpu_ymm7_x86_64,
+        fpu_ymm8_x86_64,
+        fpu_ymm9_x86_64,
+        fpu_ymm10_x86_64,
+        fpu_ymm11_x86_64,
+        fpu_ymm12_x86_64,
+        fpu_ymm13_x86_64,
+        fpu_ymm14_x86_64,
+        fpu_ymm15_x86_64,
+        LLDB_INVALID_REGNUM // register sets need to end with this flag
+    };
+    static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64,
+                  "g_avx_regnums_x86_64 has wrong number of register infos");
+
+    // Number of register sets provided by this context.
+    enum
+    {
+        k_num_extended_register_sets = 1,
+        k_num_register_sets = 3
+    };
+
+    // Register sets for x86 32-bit.
+    static const RegisterSet
+    g_reg_sets_i386[k_num_register_sets] =
+    {
+        { "General Purpose Registers",  "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 },
+        { "Floating Point Registers",   "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 },
+        { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }
+    };
+
+    // Register sets for x86 64-bit.
+    static const RegisterSet
+    g_reg_sets_x86_64[k_num_register_sets] =
+    {
+        { "General Purpose Registers",  "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 },
+        { "Floating Point Registers",   "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 },
+        { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }
+    };
+}
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR))
+
+// ----------------------------------------------------------------------------
+// Required ptrace defines.
+// ----------------------------------------------------------------------------
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+#define NT_X86_XSTATE 0x202
+#endif
+
+// ----------------------------------------------------------------------------
+// NativeRegisterContextLinux_x86_64 members.
+// ----------------------------------------------------------------------------
+
+NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p) :
+    NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p),
+    m_fpr_type (eFPRTypeNotValid),
+    m_fpr (),
+    m_iovec (),
+    m_ymm_set (),
+    m_reg_info (),
+    m_gpr_x86_64 ()
+{
+    // Set up data about ranges of valid registers.
+    switch (reg_info_interface_p->GetTargetArchitecture ().GetMachine ())
+    {
+        case llvm::Triple::x86:
+            m_reg_info.num_registers        = k_num_registers_i386;
+            m_reg_info.num_gpr_registers    = k_num_gpr_registers_i386;
+            m_reg_info.num_fpr_registers    = k_num_fpr_registers_i386;
+            m_reg_info.num_avx_registers    = k_num_avx_registers_i386;
+            m_reg_info.last_gpr             = k_last_gpr_i386;
+            m_reg_info.first_fpr            = k_first_fpr_i386;
+            m_reg_info.last_fpr             = k_last_fpr_i386;
+            m_reg_info.first_st             = fpu_st0_i386;
+            m_reg_info.last_st              = fpu_st7_i386;
+            m_reg_info.first_mm             = fpu_mm0_i386;
+            m_reg_info.last_mm              = fpu_mm7_i386;
+            m_reg_info.first_xmm            = fpu_xmm0_i386;
+            m_reg_info.last_xmm             = fpu_xmm7_i386;
+            m_reg_info.first_ymm            = fpu_ymm0_i386;
+            m_reg_info.last_ymm             = fpu_ymm7_i386;
+            m_reg_info.first_dr             = dr0_i386;
+            m_reg_info.gpr_flags            = gpr_eflags_i386;
+            break;
+        case llvm::Triple::x86_64:
+            m_reg_info.num_registers        = k_num_registers_x86_64;
+            m_reg_info.num_gpr_registers    = k_num_gpr_registers_x86_64;
+            m_reg_info.num_fpr_registers    = k_num_fpr_registers_x86_64;
+            m_reg_info.num_avx_registers    = k_num_avx_registers_x86_64;
+            m_reg_info.last_gpr             = k_last_gpr_x86_64;
+            m_reg_info.first_fpr            = k_first_fpr_x86_64;
+            m_reg_info.last_fpr             = k_last_fpr_x86_64;
+            m_reg_info.first_st             = fpu_st0_x86_64;
+            m_reg_info.last_st              = fpu_st7_x86_64;
+            m_reg_info.first_mm             = fpu_mm0_x86_64;
+            m_reg_info.last_mm              = fpu_mm7_x86_64;
+            m_reg_info.first_xmm            = fpu_xmm0_x86_64;
+            m_reg_info.last_xmm             = fpu_xmm15_x86_64;
+            m_reg_info.first_ymm            = fpu_ymm0_x86_64;
+            m_reg_info.last_ymm             = fpu_ymm15_x86_64;
+            m_reg_info.first_dr             = dr0_x86_64;
+            m_reg_info.gpr_flags            = gpr_rflags_x86_64;
+            break;
+        default:
+            assert(false && "Unhandled target architecture.");
+            break;
+    }
+
+    // Initialize m_iovec to point to the buffer and buffer size
+    // using the conventions of Berkeley style UIO structures, as required
+    // by PTRACE extensions.
+    m_iovec.iov_base = &m_fpr.xstate.xsave;
+    m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
+
+    // Clear out the FPR state.
+    ::memset(&m_fpr, 0, sizeof(FPR));
+}
+
+// CONSIDER after local and llgs debugging are merged, register set support can
+// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
+uint32_t
+NativeRegisterContextLinux_x86_64::GetRegisterSetCount () const
+{
+    uint32_t sets = 0;
+    for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
+    {
+        if (IsRegisterSetAvailable (set_index))
+            ++sets;
+    }
+
+    return sets;
+}
+
+const lldb_private::RegisterSet *
+NativeRegisterContextLinux_x86_64::GetRegisterSet (uint32_t set_index) const
+{
+    if (!IsRegisterSetAvailable (set_index))
+        return nullptr;
+
+    switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ())
+    {
+        case llvm::Triple::x86:
+            return &g_reg_sets_i386[set_index];
+        case llvm::Triple::x86_64:
+            return &g_reg_sets_x86_64[set_index];
+        default:
+            assert (false && "Unhandled target architecture.");
+            return nullptr;
+    }
+
+    return nullptr;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value)
+{
+    Error error;
+    const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index);
+    if (!reg_info)
+    {
+        error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index);
+        return error;
+    }
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+    {
+        error.SetErrorString ("NativeProcessProtocol is NULL");
+        return error;
+    }
+
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    if (!process_p->ReadRegisterValue(m_thread.GetID(),
+                                     reg_info->byte_offset,
+                                     reg_info->name,
+                                     reg_info->byte_size,
+                                     reg_value))
+        error.SetErrorString ("NativeProcessLinux::ReadRegisterValue() failed");
+
+    return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+    Error error;
+
+    if (!reg_info)
+    {
+        error.SetErrorString ("reg_info NULL");
+        return error;
+    }
+
+    const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+    if (reg == LLDB_INVALID_REGNUM)
+    {
+        // This is likely an internal register for lldb use only and should not be directly queried.
+        error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name);
+        return error;
+    }
+
+    if (IsFPR(reg, GetFPRType()))
+    {
+        if (!ReadFPR())
+        {
+            error.SetErrorString ("failed to read floating point register");
+            return error;
+        }
+    }
+    else
+    {
+        uint32_t full_reg = reg;
+        bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+        if (is_subreg)
+        {
+            // Read the full aligned 64-bit register.
+            full_reg = reg_info->invalidate_regs[0];
+        }
+
+        error = ReadRegisterRaw(full_reg, reg_value);
+
+        if (error.Success ())
+        {
+            // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+            if (is_subreg && (reg_info->byte_offset & 0x1))
+                reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8);
+
+            // If our return byte size was greater than the return value reg size, then
+            // use the type specified by reg_info rather than the uint64_t default
+            if (reg_value.GetByteSize() > reg_info->byte_size)
+                reg_value.SetType(reg_info);
+        }
+        return error;
+    }
+
+    if (reg_info->encoding == lldb::eEncodingVector)
+    {
+        lldb::ByteOrder byte_order = GetByteOrder();
+
+        if (byte_order != lldb::eByteOrderInvalid)
+        {
+            if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
+                reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
+            if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
+                reg_value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
+            if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
+                reg_value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
+            if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
+            {
+                // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
+                if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+                    reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
+                else
+                {
+                    error.SetErrorString ("failed to copy ymm register value");
+                    return error;
+                }
+            }
+
+            if (reg_value.GetType() != RegisterValue::eTypeBytes)
+                error.SetErrorString ("write failed - type was expected to be RegisterValue::eTypeBytes");
+
+            return error;
+        }
+
+        error.SetErrorString ("byte order is invalid");
+        return error;
+    }
+
+    // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
+    assert (reg_info->byte_offset < sizeof(m_fpr));
+    uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
+    switch (reg_info->byte_size)
+    {
+        case 2:
+            reg_value.SetUInt16(*(uint16_t *)src);
+            break;
+        case 4:
+            reg_value.SetUInt32(*(uint32_t *)src);
+            break;
+        case 8:
+            reg_value.SetUInt64(*(uint64_t *)src);
+            break;
+        default:
+            assert(false && "Unhandled data size.");
+            error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size);
+            break;
+    }
+
+    return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::WriteRegister(const uint32_t reg,
+                                                 const RegisterValue &value)
+{
+    Error error;
+
+    uint32_t reg_to_write = reg;
+    RegisterValue value_to_write = value;
+
+    // Check if this is a subregister of a full register.
+    const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+    if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+    {
+        RegisterValue full_value;
+        uint32_t full_reg = reg_info->invalidate_regs[0];
+        const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+        // Read the full register.
+        error = ReadRegister(full_reg_info, full_value);
+        if (error.Fail ())
+            return error;
+
+        lldb::ByteOrder byte_order = GetByteOrder();
+        uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+        // Get the bytes for the full register.
+        const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+                                                               dst,
+                                                               sizeof(dst),
+                                                               byte_order,
+                                                               error);
+        if (error.Success() && dest_size)
+        {
+            uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+            // Get the bytes for the source data.
+            const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+            if (error.Success() && src_size && (src_size < dest_size))
+            {
+                // Copy the src bytes to the destination.
+                memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+                // Set this full register as the value to write.
+                value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+                value_to_write.SetType(full_reg_info);
+                reg_to_write = full_reg;
+            }
+        }
+    }
+
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+    {
+        error.SetErrorString ("NativeProcessProtocol is NULL");
+        return error;
+    }
+
+    const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
+    assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
+    if (!register_to_write_info_p)
+    {
+        error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
+        return error;
+    }
+
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+    if (!process_p->WriteRegisterValue(m_thread.GetID(),
+                                       register_to_write_info_p->byte_offset,
+                                       register_to_write_info_p->name,
+                                       value_to_write))
+        error.SetErrorString ("NativeProcessLinux::WriteRegisterValue() failed");
+
+    return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+    assert (reg_info && "reg_info is null");
+
+    const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
+    if (reg_index == LLDB_INVALID_REGNUM)
+        return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>");
+
+    if (IsGPR(reg_index))
+        return WriteRegister(reg_index, reg_value);
+
+    if (IsFPR(reg_index, GetFPRType()))
+    {
+        if (reg_info->encoding == lldb::eEncodingVector)
+        {
+            if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
+                ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_st].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+            if (reg_index >= m_reg_info.first_mm && reg_index <= m_reg_info.last_mm)
+                ::memcpy (m_fpr.xstate.fxsave.stmm[reg_index - m_reg_info.first_mm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+            if (reg_index >= m_reg_info.first_xmm && reg_index <= m_reg_info.last_xmm)
+                ::memcpy (m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_xmm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+
+            if (reg_index >= m_reg_info.first_ymm && reg_index <= m_reg_info.last_ymm)
+            {
+                if (GetFPRType() != eFPRTypeXSAVE)
+                    return Error ("target processor does not support AVX");
+
+                // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
+                ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+                if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
+                    return Error ("CopyYMMtoXSTATE() failed");
+            }
+        }
+        else
+        {
+            // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
+            assert (reg_info->byte_offset < sizeof(m_fpr));
+            uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
+            switch (reg_info->byte_size)
+            {
+                case 2:
+                    *(uint16_t *)dst = reg_value.GetAsUInt16();
+                    break;
+                case 4:
+                    *(uint32_t *)dst = reg_value.GetAsUInt32();
+                    break;
+                case 8:
+                    *(uint64_t *)dst = reg_value.GetAsUInt64();
+                    break;
+                default:
+                    assert(false && "Unhandled data size.");
+                    return Error ("unhandled register data size %" PRIu32, reg_info->byte_size);
+            }
+        }
+
+        if (WriteFPR())
+        {
+            if (IsAVX(reg_index))
+            {
+                if (!CopyYMMtoXSTATE(reg_index, GetByteOrder()))
+                    return Error ("CopyYMMtoXSTATE() failed");
+            }
+            return Error ();
+        }
+    }
+    return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown");
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+    Error error;
+
+    data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+    if (!data_sp)
+    {
+        error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE);
+        return error;
+    }
+
+    if (!ReadGPR ())
+    {
+        error.SetErrorString ("ReadGPR() failed");
+        return error;
+    }
+
+    if (!ReadFPR ())
+    {
+        error.SetErrorString ("ReadFPR() failed");
+        return error;
+    }
+
+    uint8_t *dst = data_sp->GetBytes ();
+    if (dst == nullptr)
+    {
+        error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE);
+        return error;
+    }
+
+    ::memcpy (dst, &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
+    dst += GetRegisterInfoInterface ().GetGPRSize ();
+    if (GetFPRType () == eFPRTypeFXSAVE)
+        ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+    else if (GetFPRType () == eFPRTypeXSAVE)
+    {
+        lldb::ByteOrder byte_order = GetByteOrder ();
+
+        // Assemble the YMM register content from the register halves.
+        for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
+        {
+            if (!CopyXSTATEtoYMM (reg, byte_order))
+            {
+                error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyXSTATEtoYMM() failed for reg num %" PRIu32, __FUNCTION__, reg);
+                return error;
+            }
+        }
+
+        // Copy the extended register state including the assembled ymm registers.
+        ::memcpy (dst, &m_fpr, sizeof (m_fpr));
+    }
+    else
+    {
+        assert (false && "how do we save the floating point registers?");
+        error.SetErrorString ("unsure how to save the floating point registers");
+    }
+
+    return error;
+}
+
+lldb_private::Error
+NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+    Error error;
+
+    if (!data_sp)
+    {
+        error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__);
+        return error;
+    }
+
+    if (data_sp->GetByteSize () != REG_CONTEXT_SIZE)
+    {
+        error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ());
+        return error;
+    }
+
+    
+    uint8_t *src = data_sp->GetBytes ();
+    if (src == nullptr)
+    {
+        error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__);
+        return error;
+    }
+    ::memcpy (&m_gpr_x86_64, src, GetRegisterInfoInterface ().GetGPRSize ());
+
+    if (!WriteGPR ())
+    {
+        error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__);
+        return error;
+    }
+
+    src += GetRegisterInfoInterface ().GetGPRSize ();
+    if (GetFPRType () == eFPRTypeFXSAVE)
+        ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
+    else if (GetFPRType () == eFPRTypeXSAVE)
+        ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
+
+    if (!WriteFPR ())
+    {
+        error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__);
+        return error;
+    }
+
+    if (GetFPRType() == eFPRTypeXSAVE)
+    {
+        lldb::ByteOrder byte_order = GetByteOrder();
+
+        // Parse the YMM register content from the register halves.
+        for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm; ++reg)
+        {
+            if (!CopyYMMtoXSTATE (reg, byte_order))
+            {
+                error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s CopyYMMtoXSTATE() failed for reg num %" PRIu32, __FUNCTION__, reg);
+                return error;
+            }
+        }
+    }
+
+    return error;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) const
+{
+    // Note: Extended register sets are assumed to be at the end of g_reg_sets.
+    uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+
+    if (GetFPRType () == eFPRTypeXSAVE)
+    {
+        // AVX is the first extended register set.
+        ++num_sets;
+    }
+    return (set_index < num_sets);
+}
+
+lldb::ByteOrder
+NativeRegisterContextLinux_x86_64::GetByteOrder() const
+{
+    // Get the target process whose privileged thread was used for the register read.
+    lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return byte_order;
+
+    if (!process_sp->GetByteOrder (byte_order))
+    {
+        // FIXME log here
+    }
+
+    return byte_order;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const
+{
+    // GPRs come first.
+    return reg_index <= m_reg_info.last_gpr;
+}
+
+NativeRegisterContextLinux_x86_64::FPRType
+NativeRegisterContextLinux_x86_64::GetFPRType () const
+{
+    if (m_fpr_type == eFPRTypeNotValid)
+    {
+        // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx.
+
+        // Try and see if AVX register retrieval works.
+        m_fpr_type = eFPRTypeXSAVE;
+        if (!const_cast<NativeRegisterContextLinux_x86_64*> (this)->ReadFPR ())
+        {
+            // Fall back to general floating point with no AVX support.
+            m_fpr_type = eFPRTypeFXSAVE;
+        }
+    }
+
+    return m_fpr_type;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const
+{
+    return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr);
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) const
+{
+    bool generic_fpr = IsFPR(reg_index);
+
+    if (fpr_type == eFPRTypeXSAVE)
+        return generic_fpr || IsAVX(reg_index);
+    return generic_fpr;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::WriteFPR()
+{
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return false;
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+    if (GetFPRType() == eFPRTypeFXSAVE)
+        return process_p->WriteFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave));
+
+    if (GetFPRType() == eFPRTypeXSAVE)
+        return process_p->WriteRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE);
+    return false;
+}
+
+bool
+NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const
+{
+    return (m_reg_info.first_ymm <= reg_index && reg_index <= m_reg_info.last_ymm);
+}
+
+bool
+NativeRegisterContextLinux_x86_64::CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order)
+{
+    if (!IsAVX (reg_index))
+        return false;
+
+    if (byte_order == lldb::eByteOrderLittle)
+    {
+        ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
+                 m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
+                 sizeof (XMMReg));
+        ::memcpy (m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
+                 m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
+                 sizeof (YMMHReg));
+        return true;
+    }
+
+    if (byte_order == lldb::eByteOrderBig)
+    {
+        ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes + sizeof (XMMReg),
+                 m_fpr.xstate.fxsave.xmm[reg_index - m_reg_info.first_ymm].bytes,
+                 sizeof (XMMReg));
+        ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
+                 m_fpr.xstate.xsave.ymmh[reg_index - m_reg_info.first_ymm].bytes,
+                 sizeof (YMMHReg));
+        return true;
+    }
+    return false; // unsupported or invalid byte order
+
+}
+
+bool
+NativeRegisterContextLinux_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
+{
+    if (!IsAVX(reg))
+        return false;
+
+    if (byte_order == lldb::eByteOrderLittle)
+    {
+        ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+                 m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+                 sizeof(XMMReg));
+        ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+                 m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+                 sizeof(YMMHReg));
+        return true;
+    }
+
+    if (byte_order == lldb::eByteOrderBig)
+    {
+        ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+                 m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+                 sizeof(XMMReg));
+        ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+                 m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+                 sizeof(YMMHReg));
+        return true;
+    }
+    return false; // unsupported or invalid byte order
+}
+
+bool
+NativeRegisterContextLinux_x86_64::ReadFPR ()
+{
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return false;
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+    const FPRType fpr_type = GetFPRType ();
+    switch (fpr_type)
+    {
+    case FPRType::eFPRTypeFXSAVE:
+        return process_p->ReadFPR (m_thread.GetID (), &m_fpr.xstate.fxsave, sizeof (m_fpr.xstate.fxsave));
+
+    case FPRType::eFPRTypeXSAVE:
+        return process_p->ReadRegisterSet (m_thread.GetID (), &m_iovec, sizeof (m_fpr.xstate.xsave), NT_X86_XSTATE);
+
+    default:
+        return false;
+    }
+}
+
+bool
+NativeRegisterContextLinux_x86_64::ReadGPR()
+{
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return false;
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+    return process_p->ReadGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
+}
+
+bool
+NativeRegisterContextLinux_x86_64::WriteGPR()
+{
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+        return false;
+    NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ());
+
+    return process_p->WriteGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ());
+}
+

Added: lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/NativeRegisterContextLinux_x86_64.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,135 @@
+//===-- NativeRegisterContextLinux_x86_64.h ---------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef lldb_NativeRegisterContextLinux_x86_64_h
+#define lldb_NativeRegisterContextLinux_x86_64_h
+
+#include "lldb/Target/NativeRegisterContextRegisterInfo.h"
+#include "RegisterContext_x86.h"
+#include "lldb-x86-register-enums.h"
+
+namespace lldb_private
+{
+    class NativeProcessLinux;
+
+    class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextRegisterInfo
+    {
+    public:
+        NativeRegisterContextLinux_x86_64 (NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p);
+
+        uint32_t
+        GetRegisterSetCount () const override;
+
+        const RegisterSet *
+        GetRegisterSet (uint32_t set_index) const override;
+
+        Error
+        ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) override;
+
+        Error
+        WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
+
+        Error
+        ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
+
+        Error
+        WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+
+    private:
+
+        // Private member types.
+        enum FPRType
+        {
+            eFPRTypeNotValid = 0,
+            eFPRTypeFXSAVE,
+            eFPRTypeXSAVE
+        };
+
+        // Info about register ranges.
+        struct RegInfo
+        {
+            uint32_t num_registers;
+            uint32_t num_gpr_registers;
+            uint32_t num_fpr_registers;
+            uint32_t num_avx_registers;
+
+            uint32_t last_gpr;
+            uint32_t first_fpr;
+            uint32_t last_fpr;
+
+            uint32_t first_st;
+            uint32_t last_st;
+            uint32_t first_mm;
+            uint32_t last_mm;
+            uint32_t first_xmm;
+            uint32_t last_xmm;
+            uint32_t first_ymm;
+            uint32_t last_ymm;
+
+            uint32_t first_dr;
+            uint32_t gpr_flags;
+        };
+
+        // Private member variables.
+        mutable FPRType m_fpr_type;
+        FPR m_fpr;
+        IOVEC m_iovec;
+        YMM m_ymm_set;
+        RegInfo m_reg_info;
+        uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64];
+
+        // Private member methods.
+        lldb_private::Error
+        WriteRegister(const uint32_t reg, const RegisterValue &value);
+
+        bool IsRegisterSetAvailable (uint32_t set_index) const;
+
+        lldb::ByteOrder
+        GetByteOrder() const;
+
+        bool
+        IsGPR(uint32_t reg_index) const;
+
+        FPRType
+        GetFPRType () const;
+
+        bool
+        IsFPR(uint32_t reg_index) const;
+
+        bool
+        WriteFPR();
+
+        bool IsFPR(uint32_t reg_index, FPRType fpr_type) const;
+
+        bool
+        CopyXSTATEtoYMM (uint32_t reg_index, lldb::ByteOrder byte_order);
+
+        bool
+        CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+
+        bool
+        IsAVX (uint32_t reg_index) const;
+
+        bool
+        ReadFPR ();
+
+        lldb_private::Error
+        ReadRegisterRaw (uint32_t reg_index, RegisterValue &reg_value);
+
+        bool
+        ReadGPR();
+
+        bool
+        WriteGPR();
+    };
+}
+
+#endif // #ifndef lldb_NativeRegisterContextLinux_x86_64_h
+

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp Mon Jun 30 16:05:18 2014
@@ -62,18 +62,14 @@ RegisterContextFreeBSD_i386::RegisterCon
 {
 }
 
-RegisterContextFreeBSD_i386::~RegisterContextFreeBSD_i386()
-{
-}
-
 size_t
-RegisterContextFreeBSD_i386::GetGPRSize()
+RegisterContextFreeBSD_i386::GetGPRSize() const
 {
     return sizeof(GPR);
 }
 
 const RegisterInfo *
-RegisterContextFreeBSD_i386::GetRegisterInfo()
+RegisterContextFreeBSD_i386::GetRegisterInfo() const
 {
     switch (m_target_arch.GetMachine())
     {
@@ -84,3 +80,9 @@ RegisterContextFreeBSD_i386::GetRegister
             return NULL;
     }
 }
+
+uint32_t
+RegisterContextFreeBSD_i386::GetRegisterCount () const
+{
+    return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,15 @@ class RegisterContextFreeBSD_i386
 {
 public:
     RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch);
-    virtual ~RegisterContextFreeBSD_i386();
 
     size_t
-    GetGPRSize();
+    GetGPRSize() const override;
 
     const lldb_private::RegisterInfo *
-    GetRegisterInfo();
+    GetRegisterInfo() const override;
+
+    uint32_t
+    GetRegisterCount () const override;
 };
 
 #endif

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp Mon Jun 30 16:05:18 2014
@@ -71,20 +71,23 @@ RegisterContextFreeBSD_mips64::RegisterC
 {
 }
 
-RegisterContextFreeBSD_mips64::~RegisterContextFreeBSD_mips64()
-{
-}
-
 size_t
-RegisterContextFreeBSD_mips64::GetGPRSize()
+RegisterContextFreeBSD_mips64::GetGPRSize() const
 {
     return sizeof(GPR);
 }
 
 const RegisterInfo *
-RegisterContextFreeBSD_mips64::GetRegisterInfo()
+RegisterContextFreeBSD_mips64::GetRegisterInfo() const
 {
     assert (m_target_arch.GetCore() == ArchSpec::eCore_mips64);
     return g_register_infos_mips64;
 }
 
+uint32_t
+RegisterContextFreeBSD_mips64::GetRegisterCount () const
+{
+    return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0]));
+}
+
+

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,15 @@ class RegisterContextFreeBSD_mips64:
 {
 public:
     RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch);
-    virtual ~RegisterContextFreeBSD_mips64();
 
     size_t
-    GetGPRSize();
+    GetGPRSize() const override;
 
     const lldb_private::RegisterInfo *
-    GetRegisterInfo();
+    GetRegisterInfo() const override;
+
+    uint32_t
+    GetRegisterCount () const override;
 };
 
 #endif

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp Mon Jun 30 16:05:18 2014
@@ -67,10 +67,17 @@ struct dbreg {
 #include "RegisterInfos_x86_64.h"
 #undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
 
+static std::vector<lldb_private::RegisterInfo>&
+GetSharedRegisterInfoVector ()
+{
+    static std::vector<lldb_private::RegisterInfo> register_infos;
+    return register_infos;
+}
+
 static const RegisterInfo *
 GetRegisterInfo_i386(const lldb_private::ArchSpec& arch)
 {
-    static std::vector<lldb_private::RegisterInfo> g_register_infos;
+    static std::vector<lldb_private::RegisterInfo> g_register_infos (GetSharedRegisterInfoVector ());
 
     // Allocate RegisterInfo only once
     if (g_register_infos.empty())
@@ -92,33 +99,61 @@ GetRegisterInfo_i386(const lldb_private:
     return &g_register_infos[0];
 }
 
-RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) :
-    lldb_private::RegisterInfoInterface(target_arch)
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr (const lldb_private::ArchSpec& target_arch)
 {
+    switch (target_arch.GetMachine())
+    {
+        case llvm::Triple::x86:
+            return GetRegisterInfo_i386 (target_arch);
+        case llvm::Triple::x86_64:
+            return g_register_infos_x86_64;
+        default:
+            assert(false && "Unhandled target architecture.");
+            return nullptr;
+    }
 }
 
-RegisterContextFreeBSD_x86_64::~RegisterContextFreeBSD_x86_64()
+static uint32_t
+PrivateGetRegisterCount (const lldb_private::ArchSpec& target_arch)
+{
+    switch (target_arch.GetMachine())
+    {
+        case llvm::Triple::x86:
+            // This vector should have already been filled.
+            assert (!GetSharedRegisterInfoVector ().empty () && "i386 register info vector not filled.");
+            return static_cast<uint32_t> (GetSharedRegisterInfoVector().size ());
+        case llvm::Triple::x86_64:
+            return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+        default:
+            assert(false && "Unhandled target architecture.");
+            return 0;
+    }
+}
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) :
+    lldb_private::RegisterInfoInterface(target_arch),
+    m_register_info_p (PrivateGetRegisterInfoPtr (target_arch)),
+    m_register_count (PrivateGetRegisterCount (target_arch))
 {
 }
 
 size_t
-RegisterContextFreeBSD_x86_64::GetGPRSize()
+RegisterContextFreeBSD_x86_64::GetGPRSize() const
 {
     return sizeof(GPR);
 }
 
 const RegisterInfo *
-RegisterContextFreeBSD_x86_64::GetRegisterInfo()
+RegisterContextFreeBSD_x86_64::GetRegisterInfo() const
 {
-    switch (m_target_arch.GetMachine())
-    {
-        case llvm::Triple::x86:
-            return GetRegisterInfo_i386 (m_target_arch);
-        case llvm::Triple::x86_64:
-            return g_register_infos_x86_64;
-        default:
-            assert(false && "Unhandled target architecture.");
-            return NULL;
-    }
+    return m_register_info_p;
 }
 
+uint32_t
+RegisterContextFreeBSD_x86_64::GetRegisterCount () const
+{
+    return m_register_count;
+}
+
+

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,19 @@ class RegisterContextFreeBSD_x86_64:
 {
 public:
     RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch);
-    virtual ~RegisterContextFreeBSD_x86_64();
 
     size_t
-    GetGPRSize();
+    GetGPRSize() const override;
 
     const lldb_private::RegisterInfo *
-    GetRegisterInfo();
+    GetRegisterInfo() const override;
+
+    uint32_t
+    GetRegisterCount () const override;
+
+private:
+    const lldb_private::RegisterInfo *m_register_info_p;
+    const uint32_t m_register_count;
 };
 
 #endif

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp Mon Jun 30 16:05:18 2014
@@ -100,18 +100,14 @@ RegisterContextLinux_i386::RegisterConte
 {
 }
 
-RegisterContextLinux_i386::~RegisterContextLinux_i386()
-{
-}
-
 size_t
-RegisterContextLinux_i386::GetGPRSize()
+RegisterContextLinux_i386::GetGPRSize() const
 {
     return sizeof(GPR);
 }
 
 const RegisterInfo *
-RegisterContextLinux_i386::GetRegisterInfo()
+RegisterContextLinux_i386::GetRegisterInfo() const
 {
     switch (m_target_arch.GetMachine())
     {
@@ -122,3 +118,10 @@ RegisterContextLinux_i386::GetRegisterIn
             return NULL;
     }
 }
+
+uint32_t
+RegisterContextLinux_i386::GetRegisterCount () const
+{
+    return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}
+

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_i386.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,15 @@ class RegisterContextLinux_i386
 {
 public:
     RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch);
-    virtual ~RegisterContextLinux_i386();
 
     size_t
-    GetGPRSize();
+    GetGPRSize() const override;
 
     const lldb_private::RegisterInfo *
-    GetRegisterInfo();
+    GetRegisterInfo() const override;
+
+    uint32_t
+    GetRegisterCount () const override;
 };
 
 #endif

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp Mon Jun 30 16:05:18 2014
@@ -80,10 +80,17 @@ struct UserArea
 #include "RegisterInfos_x86_64.h"
 #undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
 
+static std::vector<lldb_private::RegisterInfo>&
+GetPrivateRegisterInfoVector ()
+{
+    static std::vector<lldb_private::RegisterInfo> g_register_infos;
+    return g_register_infos;
+}
+
 static const RegisterInfo *
 GetRegisterInfo_i386(const lldb_private::ArchSpec &arch)
 {
-    static std::vector<lldb_private::RegisterInfo> g_register_infos;
+    static std::vector<lldb_private::RegisterInfo> g_register_infos (GetPrivateRegisterInfoVector ());
 
     // Allocate RegisterInfo only once
     if (g_register_infos.empty())
@@ -105,33 +112,60 @@ GetRegisterInfo_i386(const lldb_private:
     return &g_register_infos[0];
 }
 
-RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) :
-    lldb_private::RegisterInfoInterface(target_arch)
+static const RegisterInfo *
+GetRegisterInfoPtr (const ArchSpec &target_arch)
 {
+    switch (target_arch.GetMachine())
+    {
+        case llvm::Triple::x86:
+            return GetRegisterInfo_i386 (target_arch);
+        case llvm::Triple::x86_64:
+            return g_register_infos_x86_64;
+        default:
+            assert(false && "Unhandled target architecture.");
+            return nullptr;
+    }
 }
 
-RegisterContextLinux_x86_64::~RegisterContextLinux_x86_64()
+static uint32_t
+GetRegisterInfoCount (const ArchSpec &target_arch)
+{
+    switch (target_arch.GetMachine())
+    {
+        case llvm::Triple::x86:
+            {
+                assert (!GetPrivateRegisterInfoVector ().empty () && "i386 register info not yet filled.");
+                return static_cast<uint32_t> (GetPrivateRegisterInfoVector ().size ());
+            }
+        case llvm::Triple::x86_64:
+            return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+        default:
+            assert(false && "Unhandled target architecture.");
+            return 0;
+    }
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) :
+    lldb_private::RegisterInfoInterface(target_arch),
+    m_register_info_p (GetRegisterInfoPtr (target_arch)),
+    m_register_info_count (GetRegisterInfoCount (target_arch))
 {
 }
 
 size_t
-RegisterContextLinux_x86_64::GetGPRSize()
+RegisterContextLinux_x86_64::GetGPRSize() const
 {
     return sizeof(GPR);
 }
 
 const RegisterInfo *
-RegisterContextLinux_x86_64::GetRegisterInfo()
+RegisterContextLinux_x86_64::GetRegisterInfo() const
 {
-    switch (m_target_arch.GetMachine())
-    {
-        case llvm::Triple::x86:
-            return GetRegisterInfo_i386 (m_target_arch);
-        case llvm::Triple::x86_64:
-            return g_register_infos_x86_64;
-        default:
-            assert(false && "Unhandled target architecture.");
-            return NULL;
-    }
+    return m_register_info_p;
 }
 
+uint32_t
+RegisterContextLinux_x86_64::GetRegisterCount () const
+{
+    return m_register_info_count;
+}

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h Mon Jun 30 16:05:18 2014
@@ -17,13 +17,19 @@ class RegisterContextLinux_x86_64
 {
 public:
     RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch);
-    virtual ~RegisterContextLinux_x86_64();
 
     size_t
-    GetGPRSize();
+    GetGPRSize() const override;
 
     const lldb_private::RegisterInfo *
-    GetRegisterInfo();
+    GetRegisterInfo() const override;
+
+    uint32_t
+    GetRegisterCount () const override;
+
+private:
+    const lldb_private::RegisterInfo *m_register_info_p;
+    uint32_t m_register_info_count;
 };
 
 #endif

Modified: lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterInfoInterface.h Mon Jun 30 16:05:18 2014
@@ -10,6 +10,8 @@
 #ifndef lldb_RegisterInfoInterface_h
 #define lldb_RegisterInfoInterface_h
 
+#include "lldb/Core/ArchSpec.h"
+
 namespace lldb_private
 {
 
@@ -25,12 +27,20 @@ namespace lldb_private
         virtual ~RegisterInfoInterface () {}
 
         virtual size_t
-        GetGPRSize () = 0;
+        GetGPRSize () const = 0;
 
         virtual const lldb_private::RegisterInfo *
-        GetRegisterInfo () = 0;
+        GetRegisterInfo () const = 0;
+
+        virtual uint32_t
+        GetRegisterCount () const = 0;
+
+        const lldb_private::ArchSpec&
+        GetTargetArchitecture() const
+            { return m_target_arch; }
 
     public:
+        // FIXME make private.
         lldb_private::ArchSpec m_target_arch;
     };
 

Added: lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h (added)
+++ lldb/trunk/source/Plugins/Process/Utility/lldb-x86-register-enums.h Mon Jun 30 16:05:18 2014
@@ -0,0 +1,292 @@
+//===-- lldb-x86-register-enums.h -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_x86_register_enums_h
+#define lldb_x86_register_enums_h
+
+namespace lldb_private
+{
+
+    //---------------------------------------------------------------------------
+    // Internal codes for all i386 registers.
+    //---------------------------------------------------------------------------
+    enum
+    {
+        k_first_gpr_i386,
+        gpr_eax_i386 = k_first_gpr_i386,
+        gpr_ebx_i386,
+        gpr_ecx_i386,
+        gpr_edx_i386,
+        gpr_edi_i386,
+        gpr_esi_i386,
+        gpr_ebp_i386,
+        gpr_esp_i386,
+        gpr_eip_i386,
+        gpr_eflags_i386,
+        gpr_cs_i386,
+        gpr_fs_i386,
+        gpr_gs_i386,
+        gpr_ss_i386,
+        gpr_ds_i386,
+        gpr_es_i386,
+
+        k_first_alias_i386,
+        gpr_ax_i386 = k_first_alias_i386,
+        gpr_bx_i386,
+        gpr_cx_i386,
+        gpr_dx_i386,
+        gpr_di_i386,
+        gpr_si_i386,
+        gpr_bp_i386,
+        gpr_sp_i386,
+        gpr_ah_i386,
+        gpr_bh_i386,
+        gpr_ch_i386,
+        gpr_dh_i386,
+        gpr_al_i386,
+        gpr_bl_i386,
+        gpr_cl_i386,
+        gpr_dl_i386,
+        k_last_alias_i386 = gpr_dl_i386,
+
+        k_last_gpr_i386 = k_last_alias_i386,
+
+        k_first_fpr_i386,
+        fpu_fctrl_i386 = k_first_fpr_i386,
+        fpu_fstat_i386,
+        fpu_ftag_i386,
+        fpu_fop_i386,
+        fpu_fiseg_i386,
+        fpu_fioff_i386,
+        fpu_foseg_i386,
+        fpu_fooff_i386,
+        fpu_mxcsr_i386,
+        fpu_mxcsrmask_i386,
+        fpu_st0_i386,
+        fpu_st1_i386,
+        fpu_st2_i386,
+        fpu_st3_i386,
+        fpu_st4_i386,
+        fpu_st5_i386,
+        fpu_st6_i386,
+        fpu_st7_i386,
+        fpu_mm0_i386,
+        fpu_mm1_i386,
+        fpu_mm2_i386,
+        fpu_mm3_i386,
+        fpu_mm4_i386,
+        fpu_mm5_i386,
+        fpu_mm6_i386,
+        fpu_mm7_i386,
+        fpu_xmm0_i386,
+        fpu_xmm1_i386,
+        fpu_xmm2_i386,
+        fpu_xmm3_i386,
+        fpu_xmm4_i386,
+        fpu_xmm5_i386,
+        fpu_xmm6_i386,
+        fpu_xmm7_i386,
+        k_last_fpr_i386 = fpu_xmm7_i386,
+
+        k_first_avx_i386,
+        fpu_ymm0_i386 = k_first_avx_i386,
+        fpu_ymm1_i386,
+        fpu_ymm2_i386,
+        fpu_ymm3_i386,
+        fpu_ymm4_i386,
+        fpu_ymm5_i386,
+        fpu_ymm6_i386,
+        fpu_ymm7_i386,
+        k_last_avx_i386 = fpu_ymm7_i386,
+
+        dr0_i386,
+        dr1_i386,
+        dr2_i386,
+        dr3_i386,
+        dr4_i386,
+        dr5_i386,
+        dr6_i386,
+        dr7_i386,
+
+        k_num_registers_i386,
+        k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1,
+        k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1,
+        k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1
+    };
+
+    //---------------------------------------------------------------------------
+    // Internal codes for all x86_64 registers.
+    //---------------------------------------------------------------------------
+    enum
+    {
+        k_first_gpr_x86_64,
+        gpr_rax_x86_64 = k_first_gpr_x86_64,
+        gpr_rbx_x86_64,
+        gpr_rcx_x86_64,
+        gpr_rdx_x86_64,
+        gpr_rdi_x86_64,
+        gpr_rsi_x86_64,
+        gpr_rbp_x86_64,
+        gpr_rsp_x86_64,
+        gpr_r8_x86_64,
+        gpr_r9_x86_64,
+        gpr_r10_x86_64,
+        gpr_r11_x86_64,
+        gpr_r12_x86_64,
+        gpr_r13_x86_64,
+        gpr_r14_x86_64,
+        gpr_r15_x86_64,
+        gpr_rip_x86_64,
+        gpr_rflags_x86_64,
+        gpr_cs_x86_64,
+        gpr_fs_x86_64,
+        gpr_gs_x86_64,
+        gpr_ss_x86_64,
+        gpr_ds_x86_64,
+        gpr_es_x86_64,
+
+        k_first_alias_x86_64,
+        gpr_eax_x86_64 = k_first_alias_x86_64,
+        gpr_ebx_x86_64,
+        gpr_ecx_x86_64,
+        gpr_edx_x86_64,
+        gpr_edi_x86_64,
+        gpr_esi_x86_64,
+        gpr_ebp_x86_64,
+        gpr_esp_x86_64,
+        gpr_r8d_x86_64,    // Low 32 bits of r8
+        gpr_r9d_x86_64,    // Low 32 bits of r9
+        gpr_r10d_x86_64,   // Low 32 bits of r10
+        gpr_r11d_x86_64,   // Low 32 bits of r11
+        gpr_r12d_x86_64,   // Low 32 bits of r12
+        gpr_r13d_x86_64,   // Low 32 bits of r13
+        gpr_r14d_x86_64,   // Low 32 bits of r14
+        gpr_r15d_x86_64,   // Low 32 bits of r15
+        gpr_ax_x86_64,
+        gpr_bx_x86_64,
+        gpr_cx_x86_64,
+        gpr_dx_x86_64,
+        gpr_di_x86_64,
+        gpr_si_x86_64,
+        gpr_bp_x86_64,
+        gpr_sp_x86_64,
+        gpr_r8w_x86_64,    // Low 16 bits of r8
+        gpr_r9w_x86_64,    // Low 16 bits of r9
+        gpr_r10w_x86_64,   // Low 16 bits of r10
+        gpr_r11w_x86_64,   // Low 16 bits of r11
+        gpr_r12w_x86_64,   // Low 16 bits of r12
+        gpr_r13w_x86_64,   // Low 16 bits of r13
+        gpr_r14w_x86_64,   // Low 16 bits of r14
+        gpr_r15w_x86_64,   // Low 16 bits of r15
+        gpr_ah_x86_64,
+        gpr_bh_x86_64,
+        gpr_ch_x86_64,
+        gpr_dh_x86_64,
+        gpr_al_x86_64,
+        gpr_bl_x86_64,
+        gpr_cl_x86_64,
+        gpr_dl_x86_64,
+        gpr_dil_x86_64,
+        gpr_sil_x86_64,
+        gpr_bpl_x86_64,
+        gpr_spl_x86_64,
+        gpr_r8l_x86_64,    // Low 8 bits of r8
+        gpr_r9l_x86_64,    // Low 8 bits of r9
+        gpr_r10l_x86_64,   // Low 8 bits of r10
+        gpr_r11l_x86_64,   // Low 8 bits of r11
+        gpr_r12l_x86_64,   // Low 8 bits of r12
+        gpr_r13l_x86_64,   // Low 8 bits of r13
+        gpr_r14l_x86_64,   // Low 8 bits of r14
+        gpr_r15l_x86_64,   // Low 8 bits of r15
+        k_last_alias_x86_64 = gpr_r15l_x86_64,
+
+        k_last_gpr_x86_64 = k_last_alias_x86_64,
+
+        k_first_fpr_x86_64,
+        fpu_fctrl_x86_64 = k_first_fpr_x86_64,
+        fpu_fstat_x86_64,
+        fpu_ftag_x86_64,
+        fpu_fop_x86_64,
+        fpu_fiseg_x86_64,
+        fpu_fioff_x86_64,
+        fpu_foseg_x86_64,
+        fpu_fooff_x86_64,
+        fpu_mxcsr_x86_64,
+        fpu_mxcsrmask_x86_64,
+        fpu_st0_x86_64,
+        fpu_st1_x86_64,
+        fpu_st2_x86_64,
+        fpu_st3_x86_64,
+        fpu_st4_x86_64,
+        fpu_st5_x86_64,
+        fpu_st6_x86_64,
+        fpu_st7_x86_64,
+        fpu_mm0_x86_64,
+        fpu_mm1_x86_64,
+        fpu_mm2_x86_64,
+        fpu_mm3_x86_64,
+        fpu_mm4_x86_64,
+        fpu_mm5_x86_64,
+        fpu_mm6_x86_64,
+        fpu_mm7_x86_64,
+        fpu_xmm0_x86_64,
+        fpu_xmm1_x86_64,
+        fpu_xmm2_x86_64,
+        fpu_xmm3_x86_64,
+        fpu_xmm4_x86_64,
+        fpu_xmm5_x86_64,
+        fpu_xmm6_x86_64,
+        fpu_xmm7_x86_64,
+        fpu_xmm8_x86_64,
+        fpu_xmm9_x86_64,
+        fpu_xmm10_x86_64,
+        fpu_xmm11_x86_64,
+        fpu_xmm12_x86_64,
+        fpu_xmm13_x86_64,
+        fpu_xmm14_x86_64,
+        fpu_xmm15_x86_64,
+        k_last_fpr_x86_64 = fpu_xmm15_x86_64,
+
+        k_first_avx_x86_64,
+        fpu_ymm0_x86_64 = k_first_avx_x86_64,
+        fpu_ymm1_x86_64,
+        fpu_ymm2_x86_64,
+        fpu_ymm3_x86_64,
+        fpu_ymm4_x86_64,
+        fpu_ymm5_x86_64,
+        fpu_ymm6_x86_64,
+        fpu_ymm7_x86_64,
+        fpu_ymm8_x86_64,
+        fpu_ymm9_x86_64,
+        fpu_ymm10_x86_64,
+        fpu_ymm11_x86_64,
+        fpu_ymm12_x86_64,
+        fpu_ymm13_x86_64,
+        fpu_ymm14_x86_64,
+        fpu_ymm15_x86_64,
+        k_last_avx_x86_64 = fpu_ymm15_x86_64,
+
+        dr0_x86_64,
+        dr1_x86_64,
+        dr2_x86_64,
+        dr3_x86_64,
+        dr4_x86_64,
+        dr5_x86_64,
+        dr6_x86_64,
+        dr7_x86_64,
+
+        k_num_registers_x86_64,
+        k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1,
+        k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1,
+        k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1
+    };
+
+}
+
+#endif // #ifndef lldb_x86_register_enums_h

Modified: lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h (original)
+++ lldb/trunk/source/Plugins/Process/elf-core/ProcessElfCore.h Mon Jun 30 16:05:18 2014
@@ -132,7 +132,7 @@ public:
 
     // Returns AUXV structure found in the core file
     const lldb::DataBufferSP
-    GetAuxvData();
+    GetAuxvData() override;
 
 protected:
     void

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=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Mon Jun 30 16:05:18 2014
@@ -1586,6 +1586,8 @@ GDBRemoteCommunicationClient::GetGDBServ
 bool
 GDBRemoteCommunicationClient::GetHostInfo (bool force)
 {
+    Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS));
+
     if (force || m_qHostInfo_is_valid == eLazyBoolCalculate)
     {
         m_qHostInfo_is_valid = eLazyBoolNo;
@@ -1819,6 +1821,9 @@ GDBRemoteCommunicationClient::GetHostInf
                     {
                         assert (byte_order == m_host_arch.GetByteOrder());
                     }
+
+                    if (log)
+                        log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ());
                 }
                 if (!distribution_id.empty ())
                     m_host_arch.SetDistributionId (distribution_id.c_str ());

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Mon Jun 30 16:05:18 2014
@@ -14,19 +14,26 @@
 
 // C Includes
 // C++ Includes
+#include <cstring>
+
 // Other libraries and framework includes
 #include "llvm/ADT/Triple.h"
 #include "lldb/Interpreter/Args.h"
 #include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Debugger.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/State.h"
 #include "lldb/Core/StreamString.h"
+#include "lldb/Host/Debug.h"
 #include "lldb/Host/Endian.h"
 #include "lldb/Host/File.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/TimeValue.h"
 #include "lldb/Target/Platform.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Target/NativeRegisterContext.h"
+#include "../../../Host/common/NativeProcessProtocol.h"
+#include "../../../Host/common/NativeThreadProtocol.h"
 
 // Project includes
 #include "Utility/StringExtractorGDBRemote.h"
@@ -37,6 +44,22 @@ using namespace lldb;
 using namespace lldb_private;
 
 //----------------------------------------------------------------------
+// GDBRemote Errors
+//----------------------------------------------------------------------
+
+namespace
+{
+    enum GDBRemoteServerError
+    {
+        // Set to the first unused error number in literal form below
+        eErrorFirst = 29,
+        eErrorNoProcess = eErrorFirst,
+        eErrorResume,
+        eErrorExitStatus
+    };
+}
+
+//----------------------------------------------------------------------
 // GDBRemoteCommunicationServer constructor
 //----------------------------------------------------------------------
 GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
@@ -50,12 +73,28 @@ GDBRemoteCommunicationServer::GDBRemoteC
     m_proc_infos (),
     m_proc_infos_index (0),
     m_port_map (),
-    m_port_offset(0)
+    m_port_offset(0),
+    m_current_tid (LLDB_INVALID_THREAD_ID),
+    m_continue_tid (LLDB_INVALID_THREAD_ID),
+    m_debugged_process_mutex (Mutex::eMutexTypeRecursive),
+    m_debugged_process_sp (),
+    m_debugger_sp (),
+    m_stdio_communication ("process.stdio"),
+    m_exit_now (false),
+    m_inferior_prev_state (StateType::eStateInvalid),
+    m_thread_suffix_supported (false),
+    m_list_threads_in_stop_reply (false),
+    m_active_auxv_buffer_sp (),
+    m_saved_registers_mutex (),
+    m_saved_registers_map (),
+    m_next_saved_registers_id (1)
 {
+    assert(is_platform && "must be lldb-platform if debugger is not specified");
 }
 
 GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform,
-                                                           const lldb::PlatformSP& platform_sp) :
+                                                           const lldb::PlatformSP& platform_sp,
+                                                           lldb::DebuggerSP &debugger_sp) :
     GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
     m_platform_sp (platform_sp),
     m_async_thread (LLDB_INVALID_HOST_THREAD),
@@ -66,9 +105,24 @@ GDBRemoteCommunicationServer::GDBRemoteC
     m_proc_infos (),
     m_proc_infos_index (0),
     m_port_map (),
-    m_port_offset(0)
+    m_port_offset(0),
+    m_current_tid (LLDB_INVALID_THREAD_ID),
+    m_continue_tid (LLDB_INVALID_THREAD_ID),
+    m_debugged_process_mutex (Mutex::eMutexTypeRecursive),
+    m_debugged_process_sp (),
+    m_debugger_sp (debugger_sp),
+    m_stdio_communication ("process.stdio"),
+    m_exit_now (false),
+    m_inferior_prev_state (StateType::eStateInvalid),
+    m_thread_suffix_supported (false),
+    m_list_threads_in_stop_reply (false),
+    m_active_auxv_buffer_sp (),
+    m_saved_registers_mutex (),
+    m_saved_registers_map (),
+    m_next_saved_registers_id (1)
 {
     assert(platform_sp);
+    assert((is_platform || debugger_sp) && "must specify non-NULL debugger_sp when lldb-gdbserver");
 }
 
 //----------------------------------------------------------------------
@@ -78,37 +132,14 @@ GDBRemoteCommunicationServer::~GDBRemote
 {
 }
 
-
-//void *
-//GDBRemoteCommunicationServer::AsyncThread (void *arg)
-//{
-//    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
-//
-//    Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
-//    if (log)
-//        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
-//
-//    StringExtractorGDBRemote packet;
-//
-//    while ()
-//    {
-//        if (packet.
-//    }
-//
-//    if (log)
-//        log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
-//
-//    process->m_async_thread = LLDB_INVALID_HOST_THREAD;
-//    return NULL;
-//}
-//
-bool
+GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
                                                         Error &error,
                                                         bool &interrupt,
                                                         bool &quit)
 {
     StringExtractorGDBRemote packet;
+
     PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
     if (packet_result == PacketResult::Success)
     {
@@ -124,11 +155,6 @@ GDBRemoteCommunicationServer::GetPacketA
             quit = true;
             break;
 
-        case StringExtractorGDBRemote::eServerPacketType_interrupt:
-            error.SetErrorString("interrupt received");
-            interrupt = true;
-            break;
-
         default:
         case StringExtractorGDBRemote::eServerPacketType_unimplemented:
             packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
@@ -164,6 +190,7 @@ GDBRemoteCommunicationServer::GetPacketA
 
         case StringExtractorGDBRemote::eServerPacketType_k:
             packet_result = Handle_k (packet);
+            quit = true;
             break;
 
         case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
@@ -174,6 +201,10 @@ GDBRemoteCommunicationServer::GetPacketA
             packet_result = Handle_qGroupName (packet);
             break;
 
+        case StringExtractorGDBRemote::eServerPacketType_qProcessInfo:
+            packet_result = Handle_qProcessInfo (packet);
+            break;
+                
         case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
             packet_result = Handle_qProcessInfoPID (packet);
             break;
@@ -238,6 +269,26 @@ GDBRemoteCommunicationServer::GetPacketA
             packet_result = Handle_qPlatform_shell (packet);
             break;
 
+        case StringExtractorGDBRemote::eServerPacketType_C:
+            packet_result = Handle_C (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_c:
+            packet_result = Handle_c (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_vCont:
+            packet_result = Handle_vCont (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_vCont_actions:
+            packet_result = Handle_vCont_actions (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_stop_reason: // ?
+            packet_result = Handle_stop_reason (packet);
+            break;
+
         case StringExtractorGDBRemote::eServerPacketType_vFile_open:
             packet_result = Handle_vFile_Open (packet);
             break;
@@ -281,6 +332,92 @@ GDBRemoteCommunicationServer::GetPacketA
         case StringExtractorGDBRemote::eServerPacketType_vFile_unlink:
             packet_result = Handle_vFile_unlink (packet);
             break;
+
+        case StringExtractorGDBRemote::eServerPacketType_qRegisterInfo:
+            packet_result = Handle_qRegisterInfo (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_qfThreadInfo:
+            packet_result = Handle_qfThreadInfo (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_qsThreadInfo:
+            packet_result = Handle_qsThreadInfo (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_p:
+            packet_result = Handle_p (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_P:
+            packet_result = Handle_P (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_H:
+            packet_result = Handle_H (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_m:
+            packet_result = Handle_m (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_M:
+            packet_result = Handle_M (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported:
+            packet_result = Handle_qMemoryRegionInfoSupported (packet);
+            break;
+                
+        case StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo:
+            packet_result = Handle_qMemoryRegionInfo (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_interrupt:
+            if (IsGdbServer ())
+                packet_result = Handle_interrupt (packet);
+            else
+            {
+                error.SetErrorString("interrupt received");
+                interrupt = true;
+            }
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_Z:
+            packet_result = Handle_Z (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_z:
+            packet_result = Handle_z (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_s:
+            packet_result = Handle_s (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_qSupported:
+            packet_result = Handle_qSupported (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported:
+            packet_result = Handle_QThreadSuffixSupported (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply:
+            packet_result = Handle_QListThreadsInStopReply (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read:
+            packet_result = Handle_qXfer_auxv_read (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState:
+            packet_result = Handle_QSaveRegisterState (packet);
+            break;
+
+        case StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState:
+            packet_result = Handle_QRestoreRegisterState (packet);
+            break;
         }
     }
     else
@@ -295,7 +432,12 @@ GDBRemoteCommunicationServer::GetPacketA
             error.SetErrorString("timeout");
         }
     }
-    return packet_result == PacketResult::Success;
+
+    // Check if anything occurred that would force us to want to exit.
+    if (m_exit_now)
+        quit = true;
+
+    return packet_result;
 }
 
 lldb_private::Error
@@ -318,6 +460,96 @@ GDBRemoteCommunicationServer::SetLaunchF
 lldb_private::Error
 GDBRemoteCommunicationServer::LaunchProcess ()
 {
+    // FIXME This looks an awful lot like we could override this in
+    // derived classes, one for lldb-platform, the other for lldb-gdbserver.
+    if (IsGdbServer ())
+        return LaunchDebugServerProcess ();
+    else
+        return LaunchPlatformProcess ();
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::LaunchDebugServerProcess ()
+{
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+    if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
+        return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+    lldb_private::Error error;
+    {
+        Mutex::Locker locker (m_debugged_process_mutex);
+        assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists");
+        error = m_platform_sp->LaunchNativeProcess (
+            m_process_launch_info,
+            *this,
+            m_debugged_process_sp);
+    }
+
+    if (!error.Success ())
+    {
+        fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
+        return error;
+    }
+
+    // Setup stdout/stderr mapping from inferior.
+    auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+    if (terminal_fd >= 0)
+    {
+        if (log)
+            log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+        error = SetSTDIOFileDescriptor (terminal_fd);
+        if (error.Fail ())
+            return error;
+    }
+    else
+    {
+        if (log)
+            log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+    }
+
+    printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ());
+
+    // Add to list of spawned processes.
+    lldb::pid_t pid;
+    if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID)
+    {
+        // add to spawned pids
+        {
+            Mutex::Locker locker (m_spawned_pids_mutex);
+            // On an lldb-gdbserver, we would expect there to be only one.
+            assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+            m_spawned_pids.insert (pid);
+        }
+    }
+
+    if (error.Success ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s beginning check to wait for launched application to hit first stop", __FUNCTION__);
+
+        int iteration = 0;
+        // Wait for the process to hit its first stop state.
+        while (!StateIsStoppedState (m_debugged_process_sp->GetState (), false))
+        {
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s waiting for launched process to hit first stop (%d)...", __FUNCTION__, iteration++);
+
+            // FIXME use a sleep method with finer granularity.
+            sleep (1);
+        }
+
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s launched application has hit first stop", __FUNCTION__);
+
+    }
+
+    return error;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationServer::LaunchPlatformProcess ()
+{
     if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
         return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__);
 
@@ -341,359 +573,1013 @@ GDBRemoteCommunicationServer::LaunchProc
     lldb::pid_t pid;
     if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID )
     {
-        Mutex::Locker locker (m_spawned_pids_mutex);
-        m_spawned_pids.insert(pid);
+        // add to spawned pids
+        {
+            Mutex::Locker locker (m_spawned_pids_mutex);
+            m_spawned_pids.insert(pid);
+        }
     }
 
     return error;
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
+lldb_private::Error
+GDBRemoteCommunicationServer::AttachToProcess (lldb::pid_t pid)
 {
-    // TODO: Log the packet we aren't handling...
-    return SendPacketNoLock ("", 0);
-}
+    Error error;
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
-{
-    char packet[16];
-    int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
-    assert (packet_len < (int)sizeof(packet));
-    return SendPacketNoLock (packet, packet_len);
-}
+    if (!IsGdbServer ())
+    {
+        error.SetErrorString("cannot AttachToProcess () unless process is lldb-gdbserver");
+        return error;
+    }
 
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64, __FUNCTION__, pid);
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::SendOKResponse ()
-{
-    return SendPacketNoLock ("OK", 2);
+    // Scope for mutex locker.
+    {
+        // Before we try to attach, make sure we aren't already monitoring something else.
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (!m_spawned_pids.empty ())
+        {
+            error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin());
+            return error;
+        }
+
+        // Try to attach.
+        error = m_platform_sp->AttachNativeProcess (pid, *this, m_debugged_process_sp);
+        if (!error.Success ())
+        {
+            fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ());
+            return error;
+        }
+
+        // Setup stdout/stderr mapping from inferior.
+        auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+        if (terminal_fd >= 0)
+        {
+            if (log)
+                log->Printf ("ProcessGDBRemoteCommunicationServer::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+            error = SetSTDIOFileDescriptor (terminal_fd);
+            if (error.Fail ())
+                return error;
+        }
+        else
+        {
+            if (log)
+                log->Printf ("ProcessGDBRemoteCommunicationServer::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+        }
+
+        printf ("Attached to process %" PRIu64 "...\n", pid);
+
+        // Add to list of spawned processes.
+        assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+        m_spawned_pids.insert (pid);
+
+        return error;
+    }
 }
 
-bool
-GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
+void
+GDBRemoteCommunicationServer::InitializeDelegate (lldb_private::NativeProcessProtocol *process)
 {
-    return GetAck() == PacketResult::Success;
+    assert (process && "process cannot be NULL");
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+    if (log)
+    {
+        log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s",
+                __FUNCTION__,
+                process->GetID (),
+                StateAsCString (process->GetState ()));
+    }
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::SendWResponse (lldb_private::NativeProcessProtocol *process)
 {
-    StreamString response;
-
-    // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+    assert (process && "process cannot be NULL");
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
 
-    ArchSpec host_arch (Host::GetArchitecture ());
-    const llvm::Triple &host_triple = host_arch.GetTriple();
-    response.PutCString("triple:");
-    response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
-    response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+    // send W notification
+    ExitType exit_type = ExitType::eExitTypeInvalid;
+    int return_code = 0;
+    std::string exit_description;
 
-    const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
-    if (distribution_id)
+    const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description);
+    if (!got_exit_info)
     {
-        response.PutCString("distribution_id:");
-        response.PutCStringAsRawHex8(distribution_id);
-        response.PutCString(";");
-    }
-
-    uint32_t cpu = host_arch.GetMachOCPUType();
-    uint32_t sub = host_arch.GetMachOCPUSubType();
-    if (cpu != LLDB_INVALID_CPUTYPE)
-        response.Printf ("cputype:%u;", cpu);
-    if (sub != LLDB_INVALID_CPUTYPE)
-        response.Printf ("cpusubtype:%u;", sub);
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ());
 
-    if (cpu == ArchSpec::kCore_arm_any)
-        response.Printf("watchpoint_exceptions_received:before;");   // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
+        StreamGDBRemote response;
+        response.PutChar ('E');
+        response.PutHex8 (GDBRemoteServerError::eErrorExitStatus);
+        return SendPacketNoLock(response.GetData(), response.GetSize());
+    }
     else
-        response.Printf("watchpoint_exceptions_received:after;");
-
-    switch (lldb::endian::InlHostByteOrder())
     {
-    case eByteOrderBig:     response.PutCString ("endian:big;"); break;
-    case eByteOrderLittle:  response.PutCString ("endian:little;"); break;
-    case eByteOrderPDP:     response.PutCString ("endian:pdp;"); break;
-    default:                response.PutCString ("endian:unknown;"); break;
-    }
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ());
 
-    uint32_t major = UINT32_MAX;
-    uint32_t minor = UINT32_MAX;
-    uint32_t update = UINT32_MAX;
-    if (Host::GetOSVersion (major, minor, update))
-    {
-        if (major != UINT32_MAX)
+        StreamGDBRemote response;
+
+        char return_type_code;
+        switch (exit_type)
         {
-            response.Printf("os_version:%u", major);
-            if (minor != UINT32_MAX)
-            {
-                response.Printf(".%u", minor);
-                if (update != UINT32_MAX)
-                    response.Printf(".%u", update);
-            }
-            response.PutChar(';');
+            case ExitType::eExitTypeExit:   return_type_code = 'W'; break;
+            case ExitType::eExitTypeSignal: return_type_code = 'X'; break;
+            case ExitType::eExitTypeStop:   return_type_code = 'S'; break;
+
+            case ExitType::eExitTypeInvalid:
+            default:                        return_type_code = 'E'; break;
         }
+        response.PutChar (return_type_code);
+
+        // POSIX exit status limited to unsigned 8 bits.
+        response.PutHex8 (return_code);
+
+        return SendPacketNoLock(response.GetData(), response.GetSize());
     }
+}
 
-    std::string s;
-    if (Host::GetOSBuildString (s))
+static void
+AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap)
+{
+    int64_t i;
+    if (swap)
     {
-        response.PutCString ("os_build:");
-        response.PutCStringAsRawHex8(s.c_str());
-        response.PutChar(';');
+        for (i = buf_size-1; i >= 0; i--)
+            response.PutHex8 (buf[i]);
     }
-    if (Host::GetOSKernelDescription (s))
+    else
     {
-        response.PutCString ("os_kernel:");
-        response.PutCStringAsRawHex8(s.c_str());
-        response.PutChar(';');
+        for (i = 0; i < buf_size; i++)
+            response.PutHex8 (buf[i]);
     }
-#if defined(__APPLE__)
+}
 
-#if defined(__arm__) || defined(__arm64__)
-    // For iOS devices, we are connected through a USB Mux so we never pretend
-    // to actually have a hostname as far as the remote lldb that is connecting
-    // to this lldb-platform is concerned
-    response.PutCString ("hostname:");
-    response.PutCStringAsRawHex8("127.0.0.1");
-    response.PutChar(';');
-#else   // #if defined(__arm__) || defined(__arm64__)
-    if (Host::GetHostname (s))
+static void
+WriteRegisterValueInHexFixedWidth (StreamString &response,
+                                   NativeRegisterContextSP &reg_ctx_sp,
+                                   const RegisterInfo &reg_info,
+                                   const RegisterValue *reg_value_p)
+{
+    RegisterValue reg_value;
+    if (!reg_value_p)
     {
-        response.PutCString ("hostname:");
-        response.PutCStringAsRawHex8(s.c_str());
-        response.PutChar(';');
+        Error error = reg_ctx_sp->ReadRegister (&reg_info, reg_value);
+        if (error.Success ())
+            reg_value_p = &reg_value;
+        // else log.
     }
-#endif  // #if defined(__arm__) || defined(__arm64__)
 
-#else   // #if defined(__APPLE__)
-    if (Host::GetHostname (s))
+    if (reg_value_p)
     {
-        response.PutCString ("hostname:");
-        response.PutCStringAsRawHex8(s.c_str());
-        response.PutChar(';');
+        AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false);
+    }
+    else
+    {
+        // Zero-out any unreadable values.
+        if (reg_info.byte_size > 0)
+        {
+            std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0');
+            AppendHexValue (response, zeros.data(), zeros.size(), false);
+        }
     }
-#endif  // #if defined(__APPLE__)
-
-    return SendPacketNoLock (response.GetData(), response.GetSize());
 }
 
+// WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value);
+
+
 static void
-CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
-{
-    response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
-                     proc_info.GetProcessID(),
-                     proc_info.GetParentProcessID(),
-                     proc_info.GetUserID(),
-                     proc_info.GetGroupID(),
-                     proc_info.GetEffectiveUserID(),
-                     proc_info.GetEffectiveGroupID());
-    response.PutCString ("name:");
-    response.PutCStringAsRawHex8(proc_info.GetName());
-    response.PutChar(';');
-    const ArchSpec &proc_arch = proc_info.GetArchitecture();
-    if (proc_arch.IsValid())
-    {
-        const llvm::Triple &proc_triple = proc_arch.GetTriple();
-        response.PutCString("triple:");
-        response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
-        response.PutChar(';');
-    }
+WriteGdbRegnumWithFixedWidthHexRegisterValue (StreamString &response,
+                                              NativeRegisterContextSP &reg_ctx_sp,
+                                              const RegisterInfo &reg_info,
+                                              const RegisterValue &reg_value)
+{
+    // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX
+    // gdb register number, and VVVVVVVV is the correct number of hex bytes
+    // as ASCII for the register value.
+    if (reg_info.kinds[eRegisterKindGDB] == LLDB_INVALID_REGNUM)
+        return;
+
+    response.Printf ("%.02x:", reg_info.kinds[eRegisterKindGDB]);
+    WriteRegisterValueInHexFixedWidth (response, reg_ctx_sp, reg_info, &reg_value);
+    response.PutChar (';');
 }
 
+
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::SendStopReplyPacketForThread (lldb::tid_t tid)
 {
-    // Packet format: "qProcessInfoPID:%i" where %i is the pid
-    packet.SetFilePos(::strlen ("qProcessInfoPID:"));
-    lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
-    if (pid != LLDB_INVALID_PROCESS_ID)
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+
+    // Ensure we're llgs.
+    if (!IsGdbServer ())
     {
-        ProcessInstanceInfo proc_info;
-        if (Host::GetProcessInfo(pid, proc_info))
+        // Only supported on llgs
+        return SendUnimplementedResponse ("");
+    }
+
+    // Ensure we have a debugged process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+        return SendErrorResponse (50);
+
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s preparing packet for pid %" PRIu64 " tid %" PRIu64,
+                __FUNCTION__, m_debugged_process_sp->GetID (), tid);
+
+    // Ensure we can get info on the given thread.
+    NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+    if (!thread_sp)
+        return SendErrorResponse (51);
+
+    // Grab the reason this thread stopped.
+    struct ThreadStopInfo tid_stop_info;
+    if (!thread_sp->GetStopReason (tid_stop_info))
+        return SendErrorResponse (52);
+
+    const bool did_exec = tid_stop_info.reason == eStopReasonExec;
+    // FIXME implement register handling for exec'd inferiors.
+    // if (did_exec)
+    // {
+    //     const bool force = true;
+    //     InitializeRegisters(force);
+    // }
+
+    StreamString response;
+    // Output the T packet with the thread
+    response.PutChar ('T');
+    int signum = tid_stop_info.details.signal.signo;
+    if (log)
+    {
+        log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, 
+                __FUNCTION__,
+                m_debugged_process_sp->GetID (),
+                tid,
+                signum,
+                tid_stop_info.reason,
+                tid_stop_info.details.exception.type);
+    }
+
+    switch (tid_stop_info.reason)
+    {
+    case eStopReasonSignal:
+    case eStopReasonException:
+        signum = thread_sp->TranslateStopInfoToGdbSignal (tid_stop_info);
+        break;
+    default:
+        signum = 0;
+        if (log)
         {
-            StreamString response;
-            CreateProcessInfoResponse (proc_info, response);
-            return SendPacketNoLock (response.GetData(), response.GetSize());
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " has stop reason %d, using signo = 0 in stop reply response",
+                __FUNCTION__,
+                m_debugged_process_sp->GetID (),
+                tid,
+                tid_stop_info.reason);
         }
+        break;
     }
-    return SendErrorResponse (1);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
-{
-    m_proc_infos_index = 0;
-    m_proc_infos.Clear();
+    // Print the signal number.
+    response.PutHex8 (signum & 0xff);
 
-    ProcessInstanceInfoMatch match_info;
-    packet.SetFilePos(::strlen ("qfProcessInfo"));
-    if (packet.GetChar() == ':')
+    // Include the tid.
+    response.Printf ("thread:%" PRIx64 ";", tid);
+
+    // Include the thread name if there is one.
+    const char *thread_name = thread_sp->GetName ();
+    if (thread_name && thread_name[0])
     {
+        size_t thread_name_len = strlen(thread_name);
 
-        std::string key;
-        std::string value;
-        while (packet.GetNameColonValue(key, value))
+        if (::strcspn (thread_name, "$#+-;:") == thread_name_len)
         {
-            bool success = true;
-            if (key.compare("name") == 0)
-            {
-                StringExtractor extractor;
-                extractor.GetStringRef().swap(value);
-                extractor.GetHexByteString (value);
-                match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
-            }
-            else if (key.compare("name_match") == 0)
+            response.PutCString ("name:");
+            response.PutCString (thread_name);
+        }
+        else
+        {
+            // The thread name contains special chars, send as hex bytes.
+            response.PutCString ("hexname:");
+            response.PutCStringAsRawHex8 (thread_name);
+        }
+        response.PutChar (';');
+    }
+
+    // FIXME look for analog
+    // thread_identifier_info_data_t thread_ident_info;
+    // if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info))
+    // {
+    //     if (thread_ident_info.dispatch_qaddr != 0)
+    //         ostrm << std::hex << "qaddr:" << thread_ident_info.dispatch_qaddr << ';';
+    // }
+
+    // If a 'QListThreadsInStopReply' was sent to enable this feature, we
+    // will send all thread IDs back in the "threads" key whose value is
+    // a listc of hex thread IDs separated by commas:
+    //  "threads:10a,10b,10c;"
+    // This will save the debugger from having to send a pair of qfThreadInfo
+    // and qsThreadInfo packets, but it also might take a lot of room in the
+    // stop reply packet, so it must be enabled only on systems where there
+    // are no limits on packet lengths.
+    if (m_list_threads_in_stop_reply)
+    {
+        response.PutCString ("threads:");
+
+        uint32_t thread_index = 0;
+        NativeThreadProtocolSP listed_thread_sp;
+        for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+        {
+            if (thread_index > 0)
+                response.PutChar (',');
+            response.Printf ("%" PRIx64, listed_thread_sp->GetID ());
+        }
+        response.PutChar (';');
+    }
+
+    //
+    // Expedite registers.
+    //
+
+    // Grab the register context.
+    NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext ();
+    if (reg_ctx_sp)
+    {
+        // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers.
+        const RegisterSet *reg_set_p;
+        if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr))
+        {
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", reg_set_p->num_registers);
+
+            for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p)
             {
-                if (value.compare("equals") == 0)
+                const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p);
+                if (reg_info_p == nullptr)
                 {
-                    match_info.SetNameMatchType (eNameMatchEquals);
-                }
-                else if (value.compare("starts_with") == 0)
-                {
-                    match_info.SetNameMatchType (eNameMatchStartsWith);
-                }
-                else if (value.compare("ends_with") == 0)
-                {
-                    match_info.SetNameMatchType (eNameMatchEndsWith);
-                }
-                else if (value.compare("contains") == 0)
-                {
-                    match_info.SetNameMatchType (eNameMatchContains);
-                }
-                else if (value.compare("regex") == 0)
-                {
-                    match_info.SetNameMatchType (eNameMatchRegularExpression);
+                    if (log)
+                        log->Printf ("GDBRemoteCommunicationServer::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>", *reg_num_p);
                 }
-                else
+                else if (reg_info_p->value_regs == nullptr)
                 {
-                    success = false;
+                    // Only expediate registers that are not contained in other registers.
+                    RegisterValue reg_value;
+                    Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value);
+                    if (error.Success ())
+                        WriteGdbRegnumWithFixedWidthHexRegisterValue (response, reg_ctx_sp, *reg_info_p, reg_value);
+                    else
+                    {
+                        if (log)
+                            log->Printf ("GDBRemoteCommunicationServer::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "<unnamed-register>", *reg_num_p, error.AsCString ());
+
+                    }
                 }
             }
-            else if (key.compare("pid") == 0)
-            {
-                match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
-            }
-            else if (key.compare("parent_pid") == 0)
-            {
-                match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
-            }
-            else if (key.compare("uid") == 0)
-            {
-                match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
-            }
-            else if (key.compare("gid") == 0)
-            {
-                match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
-            }
-            else if (key.compare("euid") == 0)
-            {
-                match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
-            }
-            else if (key.compare("egid") == 0)
-            {
-                match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
-            }
-            else if (key.compare("all_users") == 0)
-            {
-                match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
-            }
-            else if (key.compare("triple") == 0)
-            {
-                match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
-            }
-            else
-            {
-                success = false;
-            }
+        }
+    }
 
-            if (!success)
-                return SendErrorResponse (2);
+    if (did_exec)
+    {
+        response.PutCString ("reason:exec;");
+    }
+    else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type)
+    {
+        response.PutCString ("metype:");
+        response.PutHex64 (tid_stop_info.details.exception.type);
+        response.PutCString (";mecount:");
+        response.PutHex32 (tid_stop_info.details.exception.data_count);
+        response.PutChar (';');
+
+        for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i)
+        {
+            response.PutCString ("medata:");
+            response.PutHex64 (tid_stop_info.details.exception.data[i]);
+            response.PutChar (';');
         }
     }
 
-    if (Host::FindProcesses (match_info, m_proc_infos))
+    return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServer::HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process)
+{
+    assert (process && "process cannot be NULL");
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+    // Send the exit result, and don't flush output.
+    // Note: flushing output here would join the inferior stdio reflection thread, which
+    // would gunk up the waitpid monitor thread that is calling this.
+    PacketResult result = SendStopReasonForState (StateType::eStateExited, false);
+    if (result != PacketResult::Success)
     {
-        // We found something, return the first item by calling the get
-        // subsequent process info packet handler...
-        return Handle_qsProcessInfo (packet);
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
     }
-    return SendErrorResponse (3);
+
+    // Remove the process from the list of spawned pids.
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.erase (process->GetID ()) < 1)
+        {
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ());
+
+        }
+    }
+
+    // FIXME can't do this yet - since process state propagation is currently
+    // synchronous, it is running off the NativeProcessProtocol's innards and
+    // will tear down the NPP while it still has code to execute.
+#if 0
+    // Clear the NativeProcessProtocol pointer.
+    {
+        Mutex::Locker locker (m_debugged_process_mutex);
+        m_debugged_process_sp.reset();
+    }
+#endif
+
+    // Close the pipe to the inferior terminal i/o if we launched it
+    // and set one up.  Otherwise, 'k' and its flush of stdio could
+    // end up waiting on a thread join that will never end.  Consider
+    // adding a timeout to the connection thread join call so we
+    // can avoid that scenario altogether.
+    MaybeCloseInferiorTerminalConnection ();
+
+    // We are ready to exit the debug monitor.
+    m_exit_now = true;
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process)
 {
-    if (m_proc_infos_index < m_proc_infos.GetSize())
+    assert (process && "process cannot be NULL");
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+    // Send the stop reason unless this is the stop after the
+    // launch or attach.
+    switch (m_inferior_prev_state)
     {
-        StreamString response;
-        CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
-        ++m_proc_infos_index;
-        return SendPacketNoLock (response.GetData(), response.GetSize());
+        case eStateLaunching:
+        case eStateAttaching:
+            // Don't send anything per debugserver behavior.
+            break;
+        default:
+            // In all other cases, send the stop reason.
+            PacketResult result = SendStopReasonForState (StateType::eStateStopped, false);
+            if (result != PacketResult::Success)
+            {
+                if (log)
+                    log->Printf ("GDBRemoteCommunicationServer::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
+            }
+            break;
     }
-    return SendErrorResponse (4);
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state)
 {
-    // Packet format: "qUserName:%i" where %i is the uid
-    packet.SetFilePos(::strlen ("qUserName:"));
-    uint32_t uid = packet.GetU32 (UINT32_MAX);
-    if (uid != UINT32_MAX)
+    assert (process && "process cannot be NULL");
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+    if (log)
     {
-        std::string name;
-        if (Host::GetUserName (uid, name))
+        log->Printf ("GDBRemoteCommunicationServer::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s",
+                __FUNCTION__,
+                process->GetID (),
+                StateAsCString (state));
+    }
+
+    switch (state)
+    {
+    case StateType::eStateExited:
+        HandleInferiorState_Exited (process);
+        break;
+
+    case StateType::eStateStopped:
+        HandleInferiorState_Stopped (process);
+        break;
+
+    default:
+        if (log)
         {
-            StreamString response;
-            response.PutCStringAsRawHex8 (name.c_str());
-            return SendPacketNoLock (response.GetData(), response.GetSize());
+            log->Printf ("GDBRemoteCommunicationServer::%s didn't handle state change for pid %" PRIu64 ", new state: %s",
+                    __FUNCTION__,
+                    process->GetID (),
+                    StateAsCString (state));
         }
+        break;
     }
-    return SendErrorResponse (5);
 
+    // Remember the previous state reported to us.
+    m_inferior_prev_state = state;
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::SendONotification (const char *buffer, uint32_t len)
 {
-    // Packet format: "qGroupName:%i" where %i is the gid
-    packet.SetFilePos(::strlen ("qGroupName:"));
-    uint32_t gid = packet.GetU32 (UINT32_MAX);
-    if (gid != UINT32_MAX)
+    if ((buffer == nullptr) || (len == 0))
     {
-        std::string name;
-        if (Host::GetGroupName (gid, name))
-        {
-            StreamString response;
-            response.PutCStringAsRawHex8 (name.c_str());
-            return SendPacketNoLock (response.GetData(), response.GetSize());
-        }
+        // Nothing to send.
+        return PacketResult::Success;
     }
-    return SendErrorResponse (6);
+
+    StreamString response;
+    response.PutChar ('O');
+    response.PutBytesAsRawHex8 (buffer, len);
+
+    return SendPacketNoLock (response.GetData (), response.GetSize ());
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+lldb_private::Error
+GDBRemoteCommunicationServer::SetSTDIOFileDescriptor (int fd)
 {
-    packet.SetFilePos(::strlen ("qSpeedTest:"));
+    Error error;
 
-    std::string key;
-    std::string value;
-    bool success = packet.GetNameColonValue(key, value);
-    if (success && key.compare("response_size") == 0)
+    // Set up the Read Thread for reading/handling process I/O
+    std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true));
+    if (!conn_up)
     {
-        uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
-        if (success)
-        {
-            if (response_size == 0)
-                return SendOKResponse();
-            StreamString response;
-            uint32_t bytes_left = response_size;
-            response.PutCString("data:");
-            while (bytes_left > 0)
-            {
+        error.SetErrorString ("failed to create ConnectionFileDescriptor");
+        return error;
+    }
+
+    m_stdio_communication.SetConnection (conn_up.release());
+    if (!m_stdio_communication.IsConnected ())
+    {
+        error.SetErrorString ("failed to set connection for inferior I/O communication");
+        return error;
+    }
+
+    m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
+    m_stdio_communication.StartReadThread();
+
+    return error;
+}
+
+void
+GDBRemoteCommunicationServer::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+    GDBRemoteCommunicationServer *server = reinterpret_cast<GDBRemoteCommunicationServer*> (baton);
+    static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len));
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
+{
+    // TODO: Log the packet we aren't handling...
+    return SendPacketNoLock ("", 0);
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
+{
+    char packet[16];
+    int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
+    assert (packet_len < (int)sizeof(packet));
+    return SendPacketNoLock (packet, packet_len);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message)
+{
+    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : "");
+    return SendErrorResponse (0x03);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendOKResponse ()
+{
+    return SendPacketNoLock ("OK", 2);
+}
+
+bool
+GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
+{
+    return GetAck() == PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+{
+    StreamString response;
+
+    // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+
+    ArchSpec host_arch (Host::GetArchitecture ());
+    const llvm::Triple &host_triple = host_arch.GetTriple();
+    response.PutCString("triple:");
+    response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
+    response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+
+    const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
+    if (distribution_id)
+    {
+        response.PutCString("distribution_id:");
+        response.PutCStringAsRawHex8(distribution_id);
+        response.PutCString(";");
+    }
+
+    // Only send out MachO info when lldb-platform/llgs is running on a MachO host.
+#if defined(__APPLE__)
+    uint32_t cpu = host_arch.GetMachOCPUType();
+    uint32_t sub = host_arch.GetMachOCPUSubType();
+    if (cpu != LLDB_INVALID_CPUTYPE)
+        response.Printf ("cputype:%u;", cpu);
+    if (sub != LLDB_INVALID_CPUTYPE)
+        response.Printf ("cpusubtype:%u;", sub);
+
+    if (cpu == ArchSpec::kCore_arm_any)
+        response.Printf("watchpoint_exceptions_received:before;");   // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
+    else
+        response.Printf("watchpoint_exceptions_received:after;");
+#else
+    response.Printf("watchpoint_exceptions_received:after;");
+#endif
+
+    switch (lldb::endian::InlHostByteOrder())
+    {
+    case eByteOrderBig:     response.PutCString ("endian:big;"); break;
+    case eByteOrderLittle:  response.PutCString ("endian:little;"); break;
+    case eByteOrderPDP:     response.PutCString ("endian:pdp;"); break;
+    default:                response.PutCString ("endian:unknown;"); break;
+    }
+
+    uint32_t major = UINT32_MAX;
+    uint32_t minor = UINT32_MAX;
+    uint32_t update = UINT32_MAX;
+    if (Host::GetOSVersion (major, minor, update))
+    {
+        if (major != UINT32_MAX)
+        {
+            response.Printf("os_version:%u", major);
+            if (minor != UINT32_MAX)
+            {
+                response.Printf(".%u", minor);
+                if (update != UINT32_MAX)
+                    response.Printf(".%u", update);
+            }
+            response.PutChar(';');
+        }
+    }
+
+    std::string s;
+    if (Host::GetOSBuildString (s))
+    {
+        response.PutCString ("os_build:");
+        response.PutCStringAsRawHex8(s.c_str());
+        response.PutChar(';');
+    }
+    if (Host::GetOSKernelDescription (s))
+    {
+        response.PutCString ("os_kernel:");
+        response.PutCStringAsRawHex8(s.c_str());
+        response.PutChar(';');
+    }
+#if defined(__APPLE__)
+
+#if defined(__arm__) || defined(__arm64__)
+    // For iOS devices, we are connected through a USB Mux so we never pretend
+    // to actually have a hostname as far as the remote lldb that is connecting
+    // to this lldb-platform is concerned
+    response.PutCString ("hostname:");
+    response.PutCStringAsRawHex8("127.0.0.1");
+    response.PutChar(';');
+#else   // #if defined(__arm__) || defined(__arm64__)
+    if (Host::GetHostname (s))
+    {
+        response.PutCString ("hostname:");
+        response.PutCStringAsRawHex8(s.c_str());
+        response.PutChar(';');
+    }
+#endif  // #if defined(__arm__) || defined(__arm64__)
+
+#else   // #if defined(__APPLE__)
+    if (Host::GetHostname (s))
+    {
+        response.PutCString ("hostname:");
+        response.PutCStringAsRawHex8(s.c_str());
+        response.PutChar(';');
+    }
+#endif  // #if defined(__APPLE__)
+
+    return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+static void
+CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+    response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
+                     proc_info.GetProcessID(),
+                     proc_info.GetParentProcessID(),
+                     proc_info.GetUserID(),
+                     proc_info.GetGroupID(),
+                     proc_info.GetEffectiveUserID(),
+                     proc_info.GetEffectiveGroupID());
+    response.PutCString ("name:");
+    response.PutCStringAsRawHex8(proc_info.GetName());
+    response.PutChar(';');
+    const ArchSpec &proc_arch = proc_info.GetArchitecture();
+    if (proc_arch.IsValid())
+    {
+        const llvm::Triple &proc_triple = proc_arch.GetTriple();
+        response.PutCString("triple:");
+        response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+        response.PutChar(';');
+    }
+}
+
+static void
+CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+    response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;",
+                     proc_info.GetProcessID(),
+                     proc_info.GetParentProcessID(),
+                     proc_info.GetUserID(),
+                     proc_info.GetGroupID(),
+                     proc_info.GetEffectiveUserID(),
+                     proc_info.GetEffectiveGroupID());
+
+    const ArchSpec &proc_arch = proc_info.GetArchitecture();
+    if (proc_arch.IsValid())
+    {
+        const uint32_t cpu_type = proc_arch.GetMachOCPUType();
+        if (cpu_type != 0)
+            response.Printf ("cputype:%" PRIx32 ";", cpu_type);
+        
+        const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType();
+        if (cpu_subtype != 0)
+            response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype);
+        
+        const llvm::Triple &proc_triple = proc_arch.GetTriple();
+        const std::string vendor = proc_triple.getVendorName ();
+        if (!vendor.empty ())
+            response.Printf ("vendor:%s;", vendor.c_str ());
+
+        std::string ostype = proc_triple.getOSName ();
+        // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64.
+        if (proc_triple.getVendor () == llvm::Triple::Apple)
+        {
+            switch (proc_triple.getArch ())
+            {
+                case llvm::Triple::arm:
+                case llvm::Triple::arm64:
+                    ostype = "ios";
+                    break;
+                default:
+                    // No change.
+                    break;
+            }
+        }
+        response.Printf ("ostype:%s;", ostype.c_str ());
+
+
+        switch (proc_arch.GetByteOrder ())
+        {
+            case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break;
+            case lldb::eByteOrderBig:    response.PutCString ("endian:big;");    break;
+            case lldb::eByteOrderPDP:    response.PutCString ("endian:pdp;");    break;
+            default:
+                // Nothing.
+                break;
+        }
+
+        if (proc_triple.isArch64Bit ())
+            response.PutCString ("ptrsize:8;");
+        else if (proc_triple.isArch32Bit ())
+            response.PutCString ("ptrsize:4;");
+        else if (proc_triple.isArch16Bit ())
+            response.PutCString ("ptrsize:2;");
+    }
+
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
+{
+    // Only the gdb server handles this.
+    if (!IsGdbServer ())
+        return SendUnimplementedResponse (packet.GetStringRef ().c_str ());
+    
+    // Fail if we don't have a current process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+        return SendErrorResponse (68);
+    
+    ProcessInstanceInfo proc_info;
+    if (Host::GetProcessInfo (m_debugged_process_sp->GetID (), proc_info))
+    {
+        StreamString response;
+        CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+        return SendPacketNoLock (response.GetData (), response.GetSize ());
+    }
+    
+    return SendErrorResponse (1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+{
+    // Packet format: "qProcessInfoPID:%i" where %i is the pid
+    packet.SetFilePos(::strlen ("qProcessInfoPID:"));
+    lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
+    if (pid != LLDB_INVALID_PROCESS_ID)
+    {
+        ProcessInstanceInfo proc_info;
+        if (Host::GetProcessInfo(pid, proc_info))
+        {
+            StreamString response;
+            CreateProcessInfoResponse (proc_info, response);
+            return SendPacketNoLock (response.GetData(), response.GetSize());
+        }
+    }
+    return SendErrorResponse (1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
+{
+    m_proc_infos_index = 0;
+    m_proc_infos.Clear();
+
+    ProcessInstanceInfoMatch match_info;
+    packet.SetFilePos(::strlen ("qfProcessInfo"));
+    if (packet.GetChar() == ':')
+    {
+
+        std::string key;
+        std::string value;
+        while (packet.GetNameColonValue(key, value))
+        {
+            bool success = true;
+            if (key.compare("name") == 0)
+            {
+                StringExtractor extractor;
+                extractor.GetStringRef().swap(value);
+                extractor.GetHexByteString (value);
+                match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
+            }
+            else if (key.compare("name_match") == 0)
+            {
+                if (value.compare("equals") == 0)
+                {
+                    match_info.SetNameMatchType (eNameMatchEquals);
+                }
+                else if (value.compare("starts_with") == 0)
+                {
+                    match_info.SetNameMatchType (eNameMatchStartsWith);
+                }
+                else if (value.compare("ends_with") == 0)
+                {
+                    match_info.SetNameMatchType (eNameMatchEndsWith);
+                }
+                else if (value.compare("contains") == 0)
+                {
+                    match_info.SetNameMatchType (eNameMatchContains);
+                }
+                else if (value.compare("regex") == 0)
+                {
+                    match_info.SetNameMatchType (eNameMatchRegularExpression);
+                }
+                else
+                {
+                    success = false;
+                }
+            }
+            else if (key.compare("pid") == 0)
+            {
+                match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+            }
+            else if (key.compare("parent_pid") == 0)
+            {
+                match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+            }
+            else if (key.compare("uid") == 0)
+            {
+                match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+            }
+            else if (key.compare("gid") == 0)
+            {
+                match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+            }
+            else if (key.compare("euid") == 0)
+            {
+                match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+            }
+            else if (key.compare("egid") == 0)
+            {
+                match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+            }
+            else if (key.compare("all_users") == 0)
+            {
+                match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
+            }
+            else if (key.compare("triple") == 0)
+            {
+                match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
+            }
+            else
+            {
+                success = false;
+            }
+
+            if (!success)
+                return SendErrorResponse (2);
+        }
+    }
+
+    if (Host::FindProcesses (match_info, m_proc_infos))
+    {
+        // We found something, return the first item by calling the get
+        // subsequent process info packet handler...
+        return Handle_qsProcessInfo (packet);
+    }
+    return SendErrorResponse (3);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+{
+    if (m_proc_infos_index < m_proc_infos.GetSize())
+    {
+        StreamString response;
+        CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
+        ++m_proc_infos_index;
+        return SendPacketNoLock (response.GetData(), response.GetSize());
+    }
+    return SendErrorResponse (4);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
+{
+    // Packet format: "qUserName:%i" where %i is the uid
+    packet.SetFilePos(::strlen ("qUserName:"));
+    uint32_t uid = packet.GetU32 (UINT32_MAX);
+    if (uid != UINT32_MAX)
+    {
+        std::string name;
+        if (Host::GetUserName (uid, name))
+        {
+            StreamString response;
+            response.PutCStringAsRawHex8 (name.c_str());
+            return SendPacketNoLock (response.GetData(), response.GetSize());
+        }
+    }
+    return SendErrorResponse (5);
+
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
+{
+    // Packet format: "qGroupName:%i" where %i is the gid
+    packet.SetFilePos(::strlen ("qGroupName:"));
+    uint32_t gid = packet.GetU32 (UINT32_MAX);
+    if (gid != UINT32_MAX)
+    {
+        std::string name;
+        if (Host::GetGroupName (gid, name))
+        {
+            StreamString response;
+            response.PutCStringAsRawHex8 (name.c_str());
+            return SendPacketNoLock (response.GetData(), response.GetSize());
+        }
+    }
+    return SendErrorResponse (6);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("qSpeedTest:"));
+
+    std::string key;
+    std::string value;
+    bool success = packet.GetNameColonValue(key, value);
+    if (success && key.compare("response_size") == 0)
+    {
+        uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
+        if (success)
+        {
+            if (response_size == 0)
+                return SendOKResponse();
+            StreamString response;
+            uint32_t bytes_left = response_size;
+            response.PutCString("data:");
+            while (bytes_left > 0)
+            {
                 if (bytes_left >= 26)
                 {
                     response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -701,906 +1587,2621 @@ GDBRemoteCommunicationServer::Handle_qSp
                 }
                 else
                 {
-                    response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-                    bytes_left = 0;
+                    response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+                    bytes_left = 0;
+                }
+            }
+            return SendPacketNoLock (response.GetData(), response.GetSize());
+        }
+    }
+    return SendErrorResponse (7);
+}
+
+//
+//static bool
+//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
+//{
+//    const int time_delta_usecs = 100000;
+//    const int num_retries = timeout_in_seconds/time_delta_usecs;
+//    for (int i=0; i<num_retries; i++)
+//    {
+//        struct proc_bsdinfo bsd_info;
+//        int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
+//                                    (uint64_t) 0,
+//                                    &bsd_info,
+//                                    PROC_PIDTBSDINFO_SIZE);
+//
+//        switch (error)
+//        {
+//            case EINVAL:
+//            case ENOTSUP:
+//            case ESRCH:
+//            case EPERM:
+//                return false;
+//
+//            default:
+//                break;
+//
+//            case 0:
+//                if (bsd_info.pbi_status == SSTOP)
+//                    return true;
+//        }
+//        ::usleep (time_delta_usecs);
+//    }
+//    return false;
+//}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
+{
+    // The 'A' packet is the most over designed packet ever here with
+    // redundant argument indexes, redundant argument lengths and needed hex
+    // encoded argument string values. Really all that is needed is a comma
+    // separated hex encoded argument value list, but we will stay true to the
+    // documented version of the 'A' packet here...
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+    int actual_arg_index = 0;
+
+    packet.SetFilePos(1); // Skip the 'A'
+    bool success = true;
+    while (success && packet.GetBytesLeft() > 0)
+    {
+        // Decode the decimal argument string length. This length is the
+        // number of hex nibbles in the argument string value.
+        const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+        if (arg_len == UINT32_MAX)
+            success = false;
+        else
+        {
+            // Make sure the argument hex string length is followed by a comma
+            if (packet.GetChar() != ',')
+                success = false;
+            else
+            {
+                // Decode the argument index. We ignore this really becuase
+                // who would really send down the arguments in a random order???
+                const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
+                if (arg_idx == UINT32_MAX)
+                    success = false;
+                else
+                {
+                    // Make sure the argument index is followed by a comma
+                    if (packet.GetChar() != ',')
+                        success = false;
+                    else
+                    {
+                        // Decode the argument string value from hex bytes
+                        // back into a UTF8 string and make sure the length
+                        // matches the one supplied in the packet
+                        std::string arg;
+                        if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2))
+                            success = false;
+                        else
+                        {
+                            // If there are any bytes left
+                            if (packet.GetBytesLeft())
+                            {
+                                if (packet.GetChar() != ',')
+                                    success = false;
+                            }
+
+                            if (success)
+                            {
+                                if (arg_idx == 0)
+                                    m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
+                                m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
+                                if (log)
+                                    log->Printf ("GDBRemoteCommunicationServer::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ());
+                                ++actual_arg_index;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    if (success)
+    {
+        m_process_launch_error = LaunchProcess ();
+        if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+        {
+            return SendOKResponse ();
+        }
+        else
+        {
+            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+            if (log)
+                log->Printf("GDBRemoteCommunicationServer::%s failed to launch exe: %s",
+                        __FUNCTION__,
+                        m_process_launch_error.AsCString());
+
+        }
+    }
+    return SendErrorResponse (8);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
+{
+    StreamString response;
+
+    if (IsGdbServer ())
+    {
+        // Fail if we don't have a current process.
+        if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+            return SendErrorResponse (68);
+
+        // Make sure we set the current thread so g and p packets return
+        // the data the gdb will expect.
+        lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+        SetCurrentThreadID (tid);
+
+        NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread ();
+        if (!thread_sp)
+            return SendErrorResponse (69);
+
+        response.Printf ("QC%" PRIx64, thread_sp->GetID ());
+    }
+    else
+    {
+        // NOTE: lldb should now be using qProcessInfo for process IDs.  This path here
+        // should not be used.  It is reporting process id instead of thread id.  The
+        // correct answer doesn't seem to make much sense for lldb-platform.
+        // CONSIDER: flip to "unsupported".
+        lldb::pid_t pid = m_process_launch_info.GetProcessID();
+        response.Printf("QC%" PRIx64, pid);
+
+        // this should always be platform here
+        assert (m_is_platform && "this code path should only be traversed for lldb-platform");
+
+        if (m_is_platform)
+        {
+            // If we launch a process and this GDB server is acting as a platform,
+            // then we need to clear the process launch state so we can start
+            // launching another process. In order to launch a process a bunch or
+            // packets need to be sent: environment packets, working directory,
+            // disable ASLR, and many more settings. When we launch a process we
+            // then need to know when to clear this information. Currently we are
+            // selecting the 'qC' packet as that packet which seems to make the most
+            // sense.
+            if (pid != LLDB_INVALID_PROCESS_ID)
+            {
+                m_process_launch_info.Clear();
+            }
+        }
+    }
+    return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
+{
+    Mutex::Locker locker (m_spawned_pids_mutex);
+    FreePortForProcess(pid);
+    return m_spawned_pids.erase(pid) > 0;
+}
+bool
+GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
+                                                      lldb::pid_t pid,
+                                                      bool exited,
+                                                      int signal,    // Zero for no signal
+                                                      int status)    // Exit value of process if signal is zero
+{
+    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
+    server->DebugserverProcessReaped (pid);
+    return true;
+}
+
+bool
+GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid)
+{
+    // reap a process that we were debugging (but not debugserver)
+    Mutex::Locker locker (m_spawned_pids_mutex);
+    return m_spawned_pids.erase(pid) > 0;
+}
+
+bool
+GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton,
+                                                   lldb::pid_t pid,
+                                                   bool exited,
+                                                   int signal,    // Zero for no signal
+                                                   int status)    // Exit value of process if signal is zero
+{
+    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
+    server->DebuggedProcessReaped (pid);
+    return true;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+    return SendErrorResponse(9);
+#else
+    // Spawn a local debugserver as a platform so we can then attach or launch
+    // a process...
+
+    if (m_is_platform)
+    {
+        // Sleep and wait a bit for debugserver to start to listen...
+        ConnectionFileDescriptor file_conn;
+        Error error;
+        std::string hostname;
+        // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
+        // with the TMPDIR environnement variable
+        packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
+        std::string name;
+        std::string value;
+        uint16_t port = UINT16_MAX;
+        while (packet.GetNameColonValue(name, value))
+        {
+            if (name.compare ("host") == 0)
+                hostname.swap(value);
+            else if (name.compare ("port") == 0)
+                port = Args::StringToUInt32(value.c_str(), 0, 0);
+        }
+        if (port == UINT16_MAX)
+            port = GetNextAvailablePort();
+
+        // Spawn a new thread to accept the port that gets bound after
+        // binding to port 0 (zero).
+
+        if (error.Success())
+        {
+            // Spawn a debugserver and try to get the port it listens to.
+            ProcessLaunchInfo debugserver_launch_info;
+            if (hostname.empty())
+                hostname = "127.0.0.1";
+            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+            if (log)
+                log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);
+
+            debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
+            
+            error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(),
+                                             port,
+                                             debugserver_launch_info,
+                                             port);
+
+            lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+
+
+            if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+            {
+                Mutex::Locker locker (m_spawned_pids_mutex);
+                m_spawned_pids.insert(debugserver_pid);
+                if (port > 0)
+                    AssociatePortWithProcess(port, debugserver_pid);
+            }
+            else
+            {
+                if (port > 0)
+                    FreePort (port);
+            }
+
+            if (error.Success())
+            {
+                char response[256];
+                const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
+                assert (response_len < (int)sizeof(response));
+                PacketResult packet_result = SendPacketNoLock (response, response_len);
+
+                if (packet_result != PacketResult::Success)
+                {
+                    if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+                        ::kill (debugserver_pid, SIGINT);
                 }
+                return packet_result;
+            }
+        }
+    }
+    return SendErrorResponse (9);
+#endif
+}
+
+bool
+GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)
+{
+    // make sure we know about this process
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            return false;
+    }
+
+    // first try a SIGTERM (standard kill)
+    Host::Kill (pid, SIGTERM);
+
+    // check if that worked
+    for (size_t i=0; i<10; ++i)
+    {
+        {
+            Mutex::Locker locker (m_spawned_pids_mutex);
+            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            {
+                // it is now killed
+                return true;
+            }
+        }
+        usleep (10000);
+    }
+
+    // check one more time after the final usleep
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            return true;
+    }
+
+    // the launched process still lives.  Now try killling it again,
+    // this time with an unblockable signal.
+    Host::Kill (pid, SIGKILL);
+
+    for (size_t i=0; i<10; ++i)
+    {
+        {
+            Mutex::Locker locker (m_spawned_pids_mutex);
+            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            {
+                // it is now killed
+                return true;
+            }
+        }
+        usleep (10000);
+    }
+
+    // check one more time after the final usleep
+    // Scope for locker
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+            return true;
+    }
+
+    // no luck - the process still lives
+    return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+
+    lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+    // verify that we know anything about this pid.
+    // Scope for locker
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+        {
+            // not a pid we know about
+            return SendErrorResponse (10);
+        }
+    }
+
+    // go ahead and attempt to kill the spawned process
+    if (KillSpawnedProcess (pid))
+        return SendOKResponse ();
+    else
+        return SendErrorResponse (11);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet)
+{
+    // ignore for now if we're lldb_platform
+    if (m_is_platform)
+        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+    // shutdown all spawned processes
+    std::set<lldb::pid_t> spawned_pids_copy;
+
+    // copy pids
+    {
+        Mutex::Locker locker (m_spawned_pids_mutex);
+        spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
+    }
+
+    // nuke the spawned processes
+    for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
+    {
+        lldb::pid_t spawned_pid = *it;
+        if (!KillSpawnedProcess (spawned_pid))
+        {
+            fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
+        }
+    }
+
+    FlushInferiorOutput ();
+
+    // No OK response for kill packet.
+    // return SendOKResponse ();
+    return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
+{
+    if (m_process_launch_error.Success())
+        return SendOKResponse();
+    StreamString response;
+    response.PutChar('E');
+    response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+    return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QEnvironment  (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QEnvironment:"));
+    const uint32_t bytes_left = packet.GetBytesLeft();
+    if (bytes_left > 0)
+    {
+        m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
+        return SendOKResponse ();
+    }
+    return SendErrorResponse (12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QLaunchArch:"));
+    const uint32_t bytes_left = packet.GetBytesLeft();
+    if (bytes_left > 0)
+    {
+        const char* arch_triple = packet.Peek();
+        ArchSpec arch_spec(arch_triple,NULL);
+        m_process_launch_info.SetArchitecture(arch_spec);
+        return SendOKResponse();
+    }
+    return SendErrorResponse(13);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+    if (packet.GetU32(0))
+        m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+    else
+        m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+    return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QSetWorkingDir:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (m_is_platform)
+    {
+#ifdef _WIN32
+        // Not implemented on Windows
+        return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented");
+#else
+        // If this packet is sent to a platform, then change the current working directory
+        if (::chdir(path.c_str()) != 0)
+            return SendErrorResponse(errno);
+#endif
+    }
+    else
+    {
+        m_process_launch_info.SwapWorkingDirectory (path);
+    }
+    return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+{
+    StreamString response;
+
+    if (m_is_platform)
+    {
+        // If this packet is sent to a platform, then change the current working directory
+        char cwd[PATH_MAX];
+        if (getcwd(cwd, sizeof(cwd)) == NULL)
+        {
+            return SendErrorResponse(errno);
+        }
+        else
+        {
+            response.PutBytesAsRawHex8(cwd, strlen(cwd));
+            return SendPacketNoLock(response.GetData(), response.GetSize());
+        }
+    }
+    else
+    {
+        const char *working_dir = m_process_launch_info.GetWorkingDirectory();
+        if (working_dir && working_dir[0])
+        {
+            response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+            return SendPacketNoLock(response.GetData(), response.GetSize());
+        }
+        else
+        {
+            return SendErrorResponse(14);
+        }
+    }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QSetSTDIN:"));
+    ProcessLaunchInfo::FileAction file_action;
+    std::string path;
+    packet.GetHexByteString(path);
+    const bool read = false;
+    const bool write = true;
+    if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+    {
+        m_process_launch_info.AppendFileAction(file_action);
+        return SendOKResponse ();
+    }
+    return SendErrorResponse (15);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QSetSTDOUT:"));
+    ProcessLaunchInfo::FileAction file_action;
+    std::string path;
+    packet.GetHexByteString(path);
+    const bool read = true;
+    const bool write = false;
+    if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+    {
+        m_process_launch_info.AppendFileAction(file_action);
+        return SendOKResponse ();
+    }
+    return SendErrorResponse (16);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen ("QSetSTDERR:"));
+    ProcessLaunchInfo::FileAction file_action;
+    std::string path;
+    packet.GetHexByteString(path);
+    const bool read = true;
+    const bool write = false;
+    if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+    {
+        m_process_launch_info.AppendFileAction(file_action);
+        return SendOKResponse ();
+    }
+    return SendErrorResponse (17);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_C (StringExtractorGDBRemote &packet)
+{
+    if (!IsGdbServer ())
+        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+    // Ensure we have a native process.
+    if (!m_debugged_process_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+        return SendErrorResponse (0x36);
+    }
+
+    // Pull out the signal number.
+    packet.SetFilePos (::strlen ("C"));
+    if (packet.GetBytesLeft () < 1)
+    {
+        // Shouldn't be using a C without a signal.
+        return SendIllFormedResponse (packet, "C packet specified without signal.");
+    }
+    const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+    if (signo == std::numeric_limits<uint32_t>::max ())
+        return SendIllFormedResponse (packet, "failed to parse signal number");
+
+    // Handle optional continue address.
+    if (packet.GetBytesLeft () > 0)
+    {
+        // FIXME add continue at address support for $C{signo}[;{continue-address}].
+        if (*packet.Peek () == ';')
+            return SendUnimplementedResponse (packet.GetStringRef().c_str());
+        else
+            return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}");
+    }
+
+    lldb_private::ResumeActionList resume_actions (StateType::eStateRunning, 0);
+    Error error;
+
+    // We have two branches: what to do if a continue thread is specified (in which case we target
+    // sending the signal to that thread), or when we don't have a continue thread set (in which
+    // case we send a signal to the process).
+
+    // TODO discuss with Greg Clayton, make sure this makes sense.
+
+    lldb::tid_t signal_tid = GetContinueThreadID ();
+    if (signal_tid != LLDB_INVALID_THREAD_ID)
+    {
+        // The resume action for the continue thread (or all threads if a continue thread is not set).
+        lldb_private::ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) };
+
+        // Add the action for the continue thread (or all threads when the continue thread isn't present).
+        resume_actions.Append (action);
+    }
+    else
+    {
+        // Send the signal to the process since we weren't targeting a specific continue thread with the signal.
+        error = m_debugged_process_sp->Signal (signo);
+        if (error.Fail ())
+        {
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s failed to send signal for process %" PRIu64 ": %s",
+                             __FUNCTION__,
+                             m_debugged_process_sp->GetID (),
+                             error.AsCString ());
+
+            return SendErrorResponse (0x52);
+        }
+    }
+
+    // Resume the threads.
+    error = m_debugged_process_sp->Resume (resume_actions);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed to resume threads for process %" PRIu64 ": %s",
+                         __FUNCTION__,
+                         m_debugged_process_sp->GetID (),
+                         error.AsCString ());
+
+        return SendErrorResponse (0x38);
+    }
+
+    // Don't send an "OK" packet; response is the stopped/exited message.
+    return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment)
+{
+    if (!IsGdbServer ())
+        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s called", __FUNCTION__);
+
+    // We reuse this method in vCont - don't double adjust the file position.
+    if (!skip_file_pos_adjustment)
+        packet.SetFilePos (::strlen ("c"));
+
+    // For now just support all continue.
+    const bool has_continue_address = (packet.GetBytesLeft () > 0);
+    if (has_continue_address)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ());
+        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+    }
+
+    // Ensure we have a native process.
+    if (!m_debugged_process_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+        return SendErrorResponse (0x36);
+    }
+
+    // Build the ResumeActionList
+    lldb_private::ResumeActionList actions (StateType::eStateRunning, 0);
+
+    Error error = m_debugged_process_sp->Resume (actions);
+    if (error.Fail ())
+    {
+        if (log)
+        {
+            log->Printf ("GDBRemoteCommunicationServer::%s c failed for process %" PRIu64 ": %s",
+                         __FUNCTION__,
+                         m_debugged_process_sp->GetID (),
+                         error.AsCString ());
+        }
+        return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+    }
+
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+    // No response required from continue.
+    return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vCont_actions (StringExtractorGDBRemote &packet)
+{
+    if (!IsGdbServer ())
+    {
+        // only llgs supports $vCont.
+        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+    }
+
+    // We handle $vCont messages for c.
+    // TODO add C, s and S.
+    StreamString response;
+    response.Printf("vCont;c;C;s;S");
+
+    return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vCont (StringExtractorGDBRemote &packet)
+{
+    if (!IsGdbServer ())
+    {
+        // only llgs supports $vCont
+        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+    }
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s handling vCont packet", __FUNCTION__);
+
+    packet.SetFilePos (::strlen ("vCont"));
+
+    // Check if this is all continue (no options or ";c").
+    if (!packet.GetBytesLeft () || (::strcmp (packet.Peek (), ";c") == 0))
+    {
+        // Move the packet past the ";c".
+        if (packet.GetBytesLeft ())
+            packet.SetFilePos (packet.GetFilePos () + ::strlen (";c"));
+
+        const bool skip_file_pos_adjustment = true;
+        return Handle_c (packet, skip_file_pos_adjustment);
+    }
+    else if (::strcmp (packet.Peek (), ";s") == 0)
+    {
+        // Move past the ';', then do a simple 's'.
+        packet.SetFilePos (packet.GetFilePos () + 1);
+        return Handle_s (packet);
+    }
+
+    // Ensure we have a native process.
+    if (!m_debugged_process_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s no debugged process shared pointer", __FUNCTION__);
+        return SendErrorResponse (0x36);
+    }
+
+    ResumeActionList thread_actions;
+
+    while (packet.GetBytesLeft () && *packet.Peek () == ';')
+    {
+        // Skip the semi-colon.
+        packet.GetChar ();
+
+        // Build up the thread action.
+        ResumeAction thread_action;
+        thread_action.tid = LLDB_INVALID_THREAD_ID;
+        thread_action.state = eStateInvalid;
+        thread_action.signal = 0;
+
+        const char action = packet.GetChar ();
+        switch (action)
+        {
+            case 'C':
+                thread_action.signal = packet.GetHexMaxU32 (false, 0);
+                if (thread_action.signal == 0)
+                    return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action");
+                // Fall through to next case...
+
+            case 'c':
+                // Continue
+                thread_action.state = eStateRunning;
+                break;
+
+            case 'S':
+                thread_action.signal = packet.GetHexMaxU32 (false, 0);
+                if (thread_action.signal == 0)
+                    return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action");
+                // Fall through to next case...
+
+            case 's':
+                // Step
+                thread_action.state = eStateStepping;
+                break;
+
+            default:
+                return SendIllFormedResponse (packet, "Unsupported vCont action");
+                break;
+        }
+
+        // Parse out optional :{thread-id} value.
+        if (packet.GetBytesLeft () && (*packet.Peek () == ':'))
+        {
+            // Consume the separator.
+            packet.GetChar ();
+
+            thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID);
+            if (thread_action.tid == LLDB_INVALID_THREAD_ID)
+                return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet");
+        }
+
+        thread_actions.Append (thread_action);
+    }
+
+    // If a default action for all other threads wasn't mentioned
+    // then we should stop the threads.
+    thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0);
+
+    Error error = m_debugged_process_sp->Resume (thread_actions);
+    if (error.Fail ())
+    {
+        if (log)
+        {
+            log->Printf ("GDBRemoteCommunicationServer::%s vCont failed for process %" PRIu64 ": %s",
+                         __FUNCTION__,
+                         m_debugged_process_sp->GetID (),
+                         error.AsCString ());
+        }
+        return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+    }
+
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+    // No response required from vCont.
+    return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
+{
+    // Send response first before changing m_send_acks to we ack this packet
+    PacketResult packet_result = SendOKResponse ();
+    m_send_acks = false;
+    return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("qPlatform_mkdir:"));
+    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+    if (packet.GetChar() == ',')
+    {
+        std::string path;
+        packet.GetHexByteString(path);
+        Error error = Host::MakeDirectory(path.c_str(),mode);
+        if (error.Success())
+            return SendPacketNoLock ("OK", 2);
+        else
+            return SendErrorResponse(error.GetError());
+    }
+    return SendErrorResponse(20);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("qPlatform_chmod:"));
+    
+    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+    if (packet.GetChar() == ',')
+    {
+        std::string path;
+        packet.GetHexByteString(path);
+        Error error = Host::SetFilePermissions (path.c_str(), mode);
+        if (error.Success())
+            return SendPacketNoLock ("OK", 2);
+        else
+            return SendErrorResponse(error.GetError());
+    }
+    return SendErrorResponse(19);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:open:"));
+    std::string path;
+    packet.GetHexByteStringTerminatedBy(path,',');
+    if (!path.empty())
+    {
+        if (packet.GetChar() == ',')
+        {
+            uint32_t flags = packet.GetHexMaxU32(false, 0);
+            if (packet.GetChar() == ',')
+            {
+                mode_t mode = packet.GetHexMaxU32(false, 0600);
+                Error error;
+                int fd = ::open (path.c_str(), flags, mode);
+                const int save_errno = fd == -1 ? errno : 0;
+                StreamString response;
+                response.PutChar('F');
+                response.Printf("%i", fd);
+                if (save_errno)
+                    response.Printf(",%i", save_errno);
+                return SendPacketNoLock(response.GetData(), response.GetSize());
+            }
+        }
+    }
+    return SendErrorResponse(18);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:close:"));
+    int fd = packet.GetS32(-1);
+    Error error;
+    int err = -1;
+    int save_errno = 0;
+    if (fd >= 0)
+    {
+        err = close(fd);
+        save_errno = err == -1 ? errno : 0;
+    }
+    else
+    {
+        save_errno = EINVAL;
+    }
+    StreamString response;
+    response.PutChar('F');
+    response.Printf("%i", err);
+    if (save_errno)
+        response.Printf(",%i", save_errno);
+    return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+    // Not implemented on Windows
+    return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented");
+#else
+    StreamGDBRemote response;
+    packet.SetFilePos(::strlen("vFile:pread:"));
+    int fd = packet.GetS32(-1);
+    if (packet.GetChar() == ',')
+    {
+        uint64_t count = packet.GetU64(UINT64_MAX);
+        if (packet.GetChar() == ',')
+        {
+            uint64_t offset = packet.GetU64(UINT32_MAX);
+            if (count == UINT64_MAX)
+            {
+                response.Printf("F-1:%i", EINVAL);
+                return SendPacketNoLock(response.GetData(), response.GetSize());
+            }
+            
+            std::string buffer(count, 0);
+            const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
+            const int save_errno = bytes_read == -1 ? errno : 0;
+            response.PutChar('F');
+            response.Printf("%zi", bytes_read);
+            if (save_errno)
+                response.Printf(",%i", save_errno);
+            else
+            {
+                response.PutChar(';');
+                response.PutEscapedBytes(&buffer[0], bytes_read);
+            }
+            return SendPacketNoLock(response.GetData(), response.GetSize());
+        }
+    }
+    return SendErrorResponse(21);
+
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+    return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented");
+#else
+    packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+    StreamGDBRemote response;
+    response.PutChar('F');
+
+    int fd = packet.GetU32(UINT32_MAX);
+    if (packet.GetChar() == ',')
+    {
+        off_t offset = packet.GetU64(UINT32_MAX);
+        if (packet.GetChar() == ',')
+        {
+            std::string buffer;
+            if (packet.GetEscapedBinaryData(buffer))
+            {
+                const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
+                const int save_errno = bytes_written == -1 ? errno : 0;
+                response.Printf("%zi", bytes_written);
+                if (save_errno)
+                    response.Printf(",%i", save_errno);
+            }
+            else
+            {
+                response.Printf ("-1,%i", EINVAL);
+            }
+            return SendPacketNoLock(response.GetData(), response.GetSize());
+        }
+    }
+    return SendErrorResponse(27);
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:size:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (!path.empty())
+    {
+        lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
+        StreamString response;
+        response.PutChar('F');
+        response.PutHex64(retcode);
+        if (retcode == UINT64_MAX)
+        {
+            response.PutChar(',');
+            response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+        }
+        return SendPacketNoLock(response.GetData(), response.GetSize());
+    }
+    return SendErrorResponse(22);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:mode:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (!path.empty())
+    {
+        Error error;
+        const uint32_t mode = File::GetPermissions(path.c_str(), error);
+        StreamString response;
+        response.Printf("F%u", mode);
+        if (mode == 0 || error.Fail())
+            response.Printf(",%i", (int)error.GetError());
+        return SendPacketNoLock(response.GetData(), response.GetSize());
+    }
+    return SendErrorResponse(23);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:exists:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (!path.empty())
+    {
+        bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
+        StreamString response;
+        response.PutChar('F');
+        response.PutChar(',');
+        if (retcode)
+            response.PutChar('1');
+        else
+            response.PutChar('0');
+        return SendPacketNoLock(response.GetData(), response.GetSize());
+    }
+    return SendErrorResponse(24);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:symlink:"));
+    std::string dst, src;
+    packet.GetHexByteStringTerminatedBy(dst, ',');
+    packet.GetChar(); // Skip ',' char
+    packet.GetHexByteString(src);
+    Error error = Host::Symlink(src.c_str(), dst.c_str());
+    StreamString response;
+    response.Printf("F%u,%u", error.GetError(), error.GetError());
+    return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:unlink:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    Error error = Host::Unlink(path.c_str());
+    StreamString response;
+    response.Printf("F%u,%u", error.GetError(), error.GetError());
+    return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("qPlatform_shell:"));
+    std::string path;
+    std::string working_dir;
+    packet.GetHexByteStringTerminatedBy(path,',');
+    if (!path.empty())
+    {
+        if (packet.GetChar() == ',')
+        {
+            // FIXME: add timeout to qPlatform_shell packet
+            // uint32_t timeout = packet.GetHexMaxU32(false, 32);
+            uint32_t timeout = 10;
+            if (packet.GetChar() == ',')
+                packet.GetHexByteString(working_dir);
+            int status, signo;
+            std::string output;
+            Error err = Host::RunShellCommand(path.c_str(),
+                                              working_dir.empty() ? NULL : working_dir.c_str(),
+                                              &status, &signo, &output, timeout);
+            StreamGDBRemote response;
+            if (err.Fail())
+            {
+                response.PutCString("F,");
+                response.PutHex32(UINT32_MAX);
+            }
+            else
+            {
+                response.PutCString("F,");
+                response.PutHex32(status);
+                response.PutChar(',');
+                response.PutHex32(signo);
+                response.PutChar(',');
+                response.PutEscapedBytes(output.c_str(), output.size());
             }
-            return SendPacketNoLock (response.GetData(), response.GetSize());
+            return SendPacketNoLock(response.GetData(), response.GetSize());
         }
     }
-    return SendErrorResponse (7);
+    return SendErrorResponse(24);
 }
 
-//
-//static bool
-//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
-//{
-//    const int time_delta_usecs = 100000;
-//    const int num_retries = timeout_in_seconds/time_delta_usecs;
-//    for (int i=0; i<num_retries; i++)
-//    {
-//        struct proc_bsdinfo bsd_info;
-//        int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
-//                                    (uint64_t) 0,
-//                                    &bsd_info,
-//                                    PROC_PIDTBSDINFO_SIZE);
-//
-//        switch (error)
-//        {
-//            case EINVAL:
-//            case ENOTSUP:
-//            case ESRCH:
-//            case EPERM:
-//                return false;
-//
-//            default:
-//                break;
-//
-//            case 0:
-//                if (bsd_info.pbi_status == SSTOP)
-//                    return true;
-//        }
-//        ::usleep (time_delta_usecs);
-//    }
-//    return false;
-//}
+void
+GDBRemoteCommunicationServer::SetCurrentThreadID (lldb::tid_t tid)
+{
+    assert (IsGdbServer () && "SetCurrentThreadID() called when not GdbServer code");
+
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s setting current thread id to %" PRIu64, __FUNCTION__, tid);
+
+    m_current_tid = tid;
+    if (m_debugged_process_sp)
+        m_debugged_process_sp->SetCurrentThreadID (m_current_tid);
+}
+
+void
+GDBRemoteCommunicationServer::SetContinueThreadID (lldb::tid_t tid)
+{
+    assert (IsGdbServer () && "SetContinueThreadID() called when not GdbServer code");
+
+    Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid);
+
+    m_continue_tid = tid;
+}
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_stop_reason (StringExtractorGDBRemote &packet)
 {
-    // The 'A' packet is the most over designed packet ever here with
-    // redundant argument indexes, redundant argument lengths and needed hex
-    // encoded argument string values. Really all that is needed is a comma
-    // separated hex encoded argument value list, but we will stay true to the
-    // documented version of the 'A' packet here...
+    // Handle the $? gdbremote command.
+    if (!IsGdbServer ())
+        return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_stop_reason() unimplemented");
 
-    packet.SetFilePos(1); // Skip the 'A'
-    bool success = true;
-    while (success && packet.GetBytesLeft() > 0)
+    // If no process, indicate error
+    if (!m_debugged_process_sp)
+        return SendErrorResponse (02);
+
+    return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit)
+{
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+    switch (process_state)
     {
-        // Decode the decimal argument string length. This length is the
-        // number of hex nibbles in the argument string value.
-        const uint32_t arg_len = packet.GetU32(UINT32_MAX);
-        if (arg_len == UINT32_MAX)
-            success = false;
-        else
+        case eStateAttaching:
+        case eStateLaunching:
+        case eStateRunning:
+        case eStateStepping:
+        case eStateDetached:
+            // NOTE: gdb protocol doc looks like it should return $OK
+            // when everything is running (i.e. no stopped result).
+            return PacketResult::Success;  // Ignore
+
+        case eStateSuspended:
+        case eStateStopped:
+        case eStateCrashed:
         {
-            // Make sure the argument hex string length is followed by a comma
-            if (packet.GetChar() != ',')
-                success = false;
-            else
-            {
-                // Decode the argument index. We ignore this really becuase
-                // who would really send down the arguments in a random order???
-                const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
-                if (arg_idx == UINT32_MAX)
-                    success = false;
-                else
-                {
-                    // Make sure the argument index is followed by a comma
-                    if (packet.GetChar() != ',')
-                        success = false;
-                    else
-                    {
-                        // Decode the argument string value from hex bytes
-                        // back into a UTF8 string and make sure the length
-                        // matches the one supplied in the packet
-                        std::string arg;
-                        if (packet.GetHexByteString(arg) != (arg_len / 2))
-                            success = false;
-                        else
-                        {
-                            // If there are any bytes lft
-                            if (packet.GetBytesLeft())
-                            {
-                                if (packet.GetChar() != ',')
-                                    success = false;
-                            }
+            lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+            // Make sure we set the current thread so g and p packets return
+            // the data the gdb will expect.
+            SetCurrentThreadID (tid);
+            return SendStopReplyPacketForThread (tid);
+        }
 
-                            if (success)
-                            {
-                                if (arg_idx == 0)
-                                    m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
-                                m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
-                            }
-                        }
-                    }
-                }
+        case eStateInvalid:
+        case eStateUnloaded:
+        case eStateExited:
+            if (flush_on_exit)
+                FlushInferiorOutput ();
+            return SendWResponse(m_debugged_process_sp.get());
+
+        default:
+            if (log)
+            {
+                log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 ", current state reporting not handled: %s",
+                             __FUNCTION__,
+                             m_debugged_process_sp->GetID (),
+                             StateAsCString (process_state));
             }
-        }
+            break;
     }
+    
+    return SendErrorResponse (0);
+}
 
-    if (success)
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
+{
+    return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+{
+    packet.SetFilePos(::strlen("vFile:MD5:"));
+    std::string path;
+    packet.GetHexByteString(path);
+    if (!path.empty())
     {
-        // FIXME: remove linux restriction once eLaunchFlagDebug is supported
-#if !defined (__linux__)
-        m_process_launch_info.GetFlags().Set (eLaunchFlagDebug);
-#endif
-        m_process_launch_error = LaunchProcess ();
-        if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+        uint64_t a,b;
+        StreamGDBRemote response;
+        if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
         {
-            return SendOKResponse ();
+            response.PutCString("F,");
+            response.PutCString("x");
+        }
+        else
+        {
+            response.PutCString("F,");
+            response.PutHex64(a);
+            response.PutHex64(b);
         }
+        return SendPacketNoLock(response.GetData(), response.GetSize());
     }
-    return SendErrorResponse (8);
+    return SendErrorResponse(25);
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_qRegisterInfo (StringExtractorGDBRemote &packet)
 {
-    lldb::pid_t pid = m_process_launch_info.GetProcessID();
-    StreamString response;
-    response.Printf("QC%" PRIx64, pid);
-    if (m_is_platform)
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qRegisterInfo() unimplemented");
+
+    // Fail if we don't have a current process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+        return SendErrorResponse (68);
+
+    // Ensure we have a thread.
+    NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0));
+    if (!thread_sp)
+        return SendErrorResponse (69);
+
+    // Get the register context for the first thread.
+    NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+    if (!reg_context_sp)
+        return SendErrorResponse (69);
+
+    // Parse out the register number from the request.
+    packet.SetFilePos (strlen("qRegisterInfo"));
+    const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+    if (reg_index == std::numeric_limits<uint32_t>::max ())
+        return SendErrorResponse (69);
+
+    // Return the end of registers response if we've iterated one past the end of the register set.
+    if (reg_index >= reg_context_sp->GetRegisterCount ())
+        return SendErrorResponse (69);
+
+    const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+    if (!reg_info)
+        return SendErrorResponse (69);
+
+    // Build the reginfos response.
+    StreamGDBRemote response;
+
+    response.PutCString ("name:");
+    response.PutCString (reg_info->name);
+    response.PutChar (';');
+
+    if (reg_info->alt_name && reg_info->alt_name[0])
+    {
+        response.PutCString ("alt-name:");
+        response.PutCString (reg_info->alt_name);
+        response.PutChar (';');
+    }
+
+    response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset);
+
+    switch (reg_info->encoding)
     {
-        // If we launch a process and this GDB server is acting as a platform,
-        // then we need to clear the process launch state so we can start
-        // launching another process. In order to launch a process a bunch or
-        // packets need to be sent: environment packets, working directory,
-        // disable ASLR, and many more settings. When we launch a process we
-        // then need to know when to clear this information. Currently we are
-        // selecting the 'qC' packet as that packet which seems to make the most
-        // sense.
-        if (pid != LLDB_INVALID_PROCESS_ID)
+        case eEncodingUint:    response.PutCString ("encoding:uint;"); break;
+        case eEncodingSint:    response.PutCString ("encoding:sint;"); break;
+        case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break;
+        case eEncodingVector:  response.PutCString ("encoding:vector;"); break;
+        default: break;
+    }
+
+    switch (reg_info->format)
+    {
+        case eFormatBinary:          response.PutCString ("format:binary;"); break;
+        case eFormatDecimal:         response.PutCString ("format:decimal;"); break;
+        case eFormatHex:             response.PutCString ("format:hex;"); break;
+        case eFormatFloat:           response.PutCString ("format:float;"); break;
+        case eFormatVectorOfSInt8:   response.PutCString ("format:vector-sint8;"); break;
+        case eFormatVectorOfUInt8:   response.PutCString ("format:vector-uint8;"); break;
+        case eFormatVectorOfSInt16:  response.PutCString ("format:vector-sint16;"); break;
+        case eFormatVectorOfUInt16:  response.PutCString ("format:vector-uint16;"); break;
+        case eFormatVectorOfSInt32:  response.PutCString ("format:vector-sint32;"); break;
+        case eFormatVectorOfUInt32:  response.PutCString ("format:vector-uint32;"); break;
+        case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break;
+        case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break;
+        default: break;
+    };
+
+    const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index);
+    if (register_set_name)
+    {
+        response.PutCString ("set:");
+        response.PutCString (register_set_name);
+        response.PutChar (';');
+    }
+
+    if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM)
+        response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]);
+
+    if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
+        response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
+
+    switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric])
+    {
+        case LLDB_REGNUM_GENERIC_PC:     response.PutCString("generic:pc;"); break;
+        case LLDB_REGNUM_GENERIC_SP:     response.PutCString("generic:sp;"); break;
+        case LLDB_REGNUM_GENERIC_FP:     response.PutCString("generic:fp;"); break;
+        case LLDB_REGNUM_GENERIC_RA:     response.PutCString("generic:ra;"); break;
+        case LLDB_REGNUM_GENERIC_FLAGS:  response.PutCString("generic:flags;"); break;
+        case LLDB_REGNUM_GENERIC_ARG1:   response.PutCString("generic:arg1;"); break;
+        case LLDB_REGNUM_GENERIC_ARG2:   response.PutCString("generic:arg2;"); break;
+        case LLDB_REGNUM_GENERIC_ARG3:   response.PutCString("generic:arg3;"); break;
+        case LLDB_REGNUM_GENERIC_ARG4:   response.PutCString("generic:arg4;"); break;
+        case LLDB_REGNUM_GENERIC_ARG5:   response.PutCString("generic:arg5;"); break;
+        case LLDB_REGNUM_GENERIC_ARG6:   response.PutCString("generic:arg6;"); break;
+        case LLDB_REGNUM_GENERIC_ARG7:   response.PutCString("generic:arg7;"); break;
+        case LLDB_REGNUM_GENERIC_ARG8:   response.PutCString("generic:arg8;"); break;
+        default: break;
+    }
+
+    if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+    {
+        response.PutCString ("container-regs:");
+        int i = 0;
+        for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
         {
-            m_process_launch_info.Clear();
+            if (i > 0)
+                response.PutChar (',');
+            response.Printf ("%" PRIx32, *reg_num);
         }
+        response.PutChar (';');
     }
-    return SendPacketNoLock (response.GetData(), response.GetSize());
-}
 
-bool
-GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
-{
-    Mutex::Locker locker (m_spawned_pids_mutex);
-    FreePortForProcess(pid);
-    return m_spawned_pids.erase(pid) > 0;
+    if (reg_info->invalidate_regs && reg_info->invalidate_regs[0])
+    {
+        response.PutCString ("invalidate-regs:");
+        int i = 0;
+        for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
+        {
+            if (i > 0)
+                response.PutChar (',');
+            response.Printf ("%" PRIx32, *reg_num);
+        }
+        response.PutChar (';');
+    }
+
+    return SendPacketNoLock(response.GetData(), response.GetSize());
 }
-bool
-GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
-                                                      lldb::pid_t pid,
-                                                      bool exited,
-                                                      int signal,    // Zero for no signal
-                                                      int status)    // Exit value of process if signal is zero
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qfThreadInfo (StringExtractorGDBRemote &packet)
 {
-    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
-    server->DebugserverProcessReaped (pid);
-    return true;
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_qfThreadInfo() unimplemented");
+
+    // Fail if we don't have a current process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+        return SendErrorResponse (68);
+
+    StreamGDBRemote response;
+    response.PutChar ('m');
+
+    NativeThreadProtocolSP thread_sp;
+    uint32_t thread_index;
+    for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index);
+         thread_sp;
+         ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+    {
+        if (thread_index > 0)
+            response.PutChar(',');
+        response.Printf ("%" PRIx64, thread_sp->GetID ());
+    }
+
+    return SendPacketNoLock(response.GetData(), response.GetSize());
 }
 
-bool
-GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid)
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_qsThreadInfo (StringExtractorGDBRemote &packet)
 {
-    // reap a process that we were debugging (but not debugserver)
-    Mutex::Locker locker (m_spawned_pids_mutex);
-    return m_spawned_pids.erase(pid) > 0;
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_qsThreadInfo() unimplemented");
+
+    // FIXME for now we return the full thread list in the initial packet and always do nothing here.
+    return SendPacketNoLock ("l", 1);
 }
 
-bool
-GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton,
-                                                   lldb::pid_t pid,
-                                                   bool exited,
-                                                   int signal,    // Zero for no signal
-                                                   int status)    // Exit value of process if signal is zero
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::Handle_p (StringExtractorGDBRemote &packet)
 {
-    GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
-    server->DebuggedProcessReaped (pid);
-    return true;
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_p() unimplemented");
+
+    // Parse out the register number from the request.
+    packet.SetFilePos (strlen("p"));
+    const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+    if (reg_index == std::numeric_limits<uint32_t>::max ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+        return SendErrorResponse (0x15);
+    }
+
+    // Get the thread to use.
+    NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+    if (!thread_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available", __FUNCTION__);
+        return SendErrorResponse (0x15);
+    }
+
+    // Get the thread's register context.
+    NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+    if (!reg_context_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+        return SendErrorResponse (0x15);
+    }
+
+    // Return the end of registers response if we've iterated one past the end of the register set.
+    if (reg_index >= reg_context_sp->GetRegisterCount ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ());
+        return SendErrorResponse (0x15);
+    }
+
+    const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+    if (!reg_info)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+        return SendErrorResponse (0x15);
+    }
+
+    // Build the reginfos response.
+    StreamGDBRemote response;
+
+    // Retrieve the value
+    RegisterValue reg_value;
+    Error error = reg_context_sp->ReadRegister (reg_info, reg_value);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+        return SendErrorResponse (0x15);
+    }
+
+    const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ());
+    if (!data)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index);
+        return SendErrorResponse (0x15);
+    }
+
+    // FIXME flip as needed to get data in big/little endian format for this host.
+    for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i)
+        response.PutHex8 (data[i]);
+
+    return SendPacketNoLock (response.GetData (), response.GetSize ());
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_P (StringExtractorGDBRemote &packet)
 {
-#ifdef _WIN32
-    return SendErrorResponse(9);
-#else
-    // Spawn a local debugserver as a platform so we can then attach or launch
-    // a process...
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("GDBRemoteCommunicationServer::Handle_P() unimplemented");
 
-    if (m_is_platform)
+    // Ensure there is more content.
+    if (packet.GetBytesLeft () < 1)
+        return SendIllFormedResponse (packet, "Empty P packet");
+
+    // Parse out the register number from the request.
+    packet.SetFilePos (strlen("P"));
+    const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+    if (reg_index == std::numeric_limits<uint32_t>::max ())
     {
-        // Sleep and wait a bit for debugserver to start to listen...
-        ConnectionFileDescriptor file_conn;
-        Error error;
-        std::string hostname;
-        // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
-        // with the TMPDIR environnement variable
-        packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
-        std::string name;
-        std::string value;
-        uint16_t port = UINT16_MAX;
-        while (packet.GetNameColonValue(name, value))
-        {
-            if (name.compare ("host") == 0)
-                hostname.swap(value);
-            else if (name.compare ("port") == 0)
-                port = Args::StringToUInt32(value.c_str(), 0, 0);
-        }
-        if (port == UINT16_MAX)
-            port = GetNextAvailablePort();
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+        return SendErrorResponse (0x29);
+    }
 
-        // Spawn a new thread to accept the port that gets bound after
-        // binding to port 0 (zero).
+    // Note debugserver would send an E30 here.
+    if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '='))
+        return SendIllFormedResponse (packet, "P packet missing '=' char after register number");
 
-        if (error.Success())
-        {
-            // Spawn a debugserver and try to get the port it listens to.
-            ProcessLaunchInfo debugserver_launch_info;
-            if (hostname.empty())
-                hostname = "127.0.0.1";
-            Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
-            if (log)
-                log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port);
+    // Get process architecture.
+    ArchSpec process_arch;
+    if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch))
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed to retrieve inferior architecture", __FUNCTION__);
+        return SendErrorResponse (0x49);
+    }
 
-            debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
-            
-            error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(),
-                                             port,
-                                             debugserver_launch_info,
-                                             port);
+    // Parse out the value.
+    const uint64_t raw_value = packet.GetHexMaxU64 (process_arch.GetByteOrder () == lldb::eByteOrderLittle, std::numeric_limits<uint64_t>::max ());
 
-            lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+    // Get the thread to use.
+    NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+    if (!thread_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no thread available (thread index 0)", __FUNCTION__);
+        return SendErrorResponse (0x28);
+    }
 
+    // Get the thread's register context.
+    NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+    if (!reg_context_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+        return SendErrorResponse (0x15);
+    }
 
-            if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
-            {
-                Mutex::Locker locker (m_spawned_pids_mutex);
-                m_spawned_pids.insert(debugserver_pid);
-                if (port > 0)
-                    AssociatePortWithProcess(port, debugserver_pid);
-            }
-            else
-            {
-                if (port > 0)
-                    FreePort (port);
-            }
+    const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+    if (!reg_info)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+        return SendErrorResponse (0x48);
+    }
 
-            if (error.Success())
-            {
-                char response[256];
-                const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
-                assert (response_len < (int)sizeof(response));
-                PacketResult packet_result = SendPacketNoLock (response, response_len);
+    // Return the end of registers response if we've iterated one past the end of the register set.
+    if (reg_index >= reg_context_sp->GetRegisterCount ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetRegisterCount ());
+        return SendErrorResponse (0x47);
+    }
 
-                if (packet_result != PacketResult::Success)
-                {
-                    if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
-                        ::kill (debugserver_pid, SIGINT);
-                }
-                return packet_result;
-            }
-        }
+
+    // Build the reginfos response.
+    StreamGDBRemote response;
+
+    // FIXME Could be suffixed with a thread: parameter.
+    // That thread then needs to be fed back into the reg context retrieval above.
+    Error error = reg_context_sp->WriteRegisterFromUnsigned (reg_info, raw_value);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+        return SendErrorResponse (0x32);
     }
-    return SendErrorResponse (9);
-#endif
+
+    return SendOKResponse();
 }
 
-bool
-GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_H (StringExtractorGDBRemote &packet)
 {
-    // make sure we know about this process
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_H() unimplemented");
+
+    // Fail if we don't have a current process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-        Mutex::Locker locker (m_spawned_pids_mutex);
-        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-            return false;
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
     }
 
-    // first try a SIGTERM (standard kill)
-    Host::Kill (pid, SIGTERM);
-
-    // check if that worked
-    for (size_t i=0; i<10; ++i)
+    // Parse out which variant of $H is requested.
+    packet.SetFilePos (strlen("H"));
+    if (packet.GetBytesLeft () < 1)
     {
-        {
-            Mutex::Locker locker (m_spawned_pids_mutex);
-            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-            {
-                // it is now killed
-                return true;
-            }
-        }
-        usleep (10000);
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, H command missing {g,c} variant", __FUNCTION__);
+        return SendIllFormedResponse (packet, "H command missing {g,c} variant");
     }
 
-    // check one more time after the final usleep
+    const char h_variant = packet.GetChar ();
+    switch (h_variant)
     {
-        Mutex::Locker locker (m_spawned_pids_mutex);
-        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-            return true;
+        case 'g':
+            break;
+
+        case 'c':
+            break;
+
+        default:
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s failed, invalid $H variant %c", __FUNCTION__, h_variant);
+            return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
     }
 
-    // the launched process still lives.  Now try killling it again,
-    // this time with an unblockable signal.
-    Host::Kill (pid, SIGKILL);
+    // Parse out the thread number.
+    // FIXME return a parse success/fail value.  All values are valid here.
+    const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ());
 
-    for (size_t i=0; i<10; ++i)
+    // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread).
+    if (tid != LLDB_INVALID_THREAD_ID && tid != 0)
     {
+        NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+        if (!thread_sp)
         {
-            Mutex::Locker locker (m_spawned_pids_mutex);
-            if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-            {
-                // it is now killed
-                return true;
-            }
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid);
+            return SendErrorResponse (0x15);
         }
-        usleep (10000);
     }
 
-    // check one more time after the final usleep
-    // Scope for locker
+    // Now switch the given thread type.
+    switch (h_variant)
     {
-        Mutex::Locker locker (m_spawned_pids_mutex);
-        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
-            return true;
+        case 'g':
+            SetCurrentThreadID (tid);
+            break;
+
+        case 'c':
+            SetContinueThreadID (tid);
+            break;
+
+        default:
+            assert (false && "unsupported $H variant - shouldn't get here");
+            return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
     }
 
-    // no luck - the process still lives
-    return false;
+    return SendOKResponse();
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_interrupt (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
 
-    lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+    {
+        // Only supported on llgs
+        return SendUnimplementedResponse ("");
+    }
 
-    // verify that we know anything about this pid.
-    // Scope for locker
+    // Fail if we don't have a current process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-        Mutex::Locker locker (m_spawned_pids_mutex);
-        if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
+    }
+
+    // Build the ResumeActionList - stop everything.
+    lldb_private::ResumeActionList actions (StateType::eStateStopped, 0);
+
+    Error error = m_debugged_process_sp->Resume (actions);
+    if (error.Fail ())
+    {
+        if (log)
         {
-            // not a pid we know about
-            return SendErrorResponse (10);
+            log->Printf ("GDBRemoteCommunicationServer::%s failed for process %" PRIu64 ": %s",
+                         __FUNCTION__,
+                         m_debugged_process_sp->GetID (),
+                         error.AsCString ());
         }
+        return SendErrorResponse (GDBRemoteServerError::eErrorResume);
     }
 
-    // go ahead and attempt to kill the spawned process
-    if (KillSpawnedProcess (pid))
-        return SendOKResponse ();
-    else
-        return SendErrorResponse (11);
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+    // No response required from stop all.
+    return PacketResult::Success;
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_m (StringExtractorGDBRemote &packet)
 {
-    // ignore for now if we're lldb_platform
-    if (m_is_platform)
-        return SendUnimplementedResponse (packet.GetStringRef().c_str());
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
 
-    // shutdown all spawned processes
-    std::set<lldb::pid_t> spawned_pids_copy;
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+    {
+        // Only supported on llgs
+        return SendUnimplementedResponse ("");
+    }
 
-    // copy pids
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-        Mutex::Locker locker (m_spawned_pids_mutex);
-        spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
     }
 
-    // nuke the spawned processes
-    for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
+    // Parse out the memory address.
+    packet.SetFilePos (strlen("m"));
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Too short m packet");
+
+    // Read the address.  Punting on validation.
+    // FIXME replace with Hex U64 read with no default value that fails on failed read.
+    const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+    // Validate comma.
+    if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+        return SendIllFormedResponse(packet, "Comma sep missing in m packet");
+
+    // Get # bytes to read.
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Length missing in m packet");
+
+    const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+    if (byte_count == 0)
     {
-        lldb::pid_t spawned_pid = *it;
-        if (!KillSpawnedProcess (spawned_pid))
-        {
-            fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
-        }
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s nothing to read: zero-length packet", __FUNCTION__);
+        return PacketResult::Success;
     }
 
-    // TODO figure out how to shut down gracefully at this point
-    return SendOKResponse ();
-}
+    // Allocate the response buffer.
+    std::string buf(byte_count, '\0');
+    if (buf.empty())
+        return SendErrorResponse (0x78);
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
-{
-    if (m_process_launch_error.Success())
-        return SendOKResponse();
-    StreamString response;
-    response.PutChar('E');
-    response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
-    return SendPacketNoLock (response.GetData(), response.GetSize());
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QEnvironment  (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen ("QEnvironment:"));
-    const uint32_t bytes_left = packet.GetBytesLeft();
-    if (bytes_left > 0)
+    // Retrieve the process memory.
+    lldb::addr_t bytes_read = 0;
+    lldb_private::Error error = m_debugged_process_sp->ReadMemory (read_addr, &buf[0], byte_count, bytes_read);
+    if (error.Fail ())
     {
-        m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
-        return SendOKResponse ();
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ());
+        return SendErrorResponse (0x08);
     }
-    return SendErrorResponse (12);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen ("QLaunchArch:"));
-    const uint32_t bytes_left = packet.GetBytesLeft();
-    if (bytes_left > 0)
+    if (bytes_read == 0)
     {
-        const char* arch_triple = packet.Peek();
-        ArchSpec arch_spec(arch_triple,NULL);
-        m_process_launch_info.SetArchitecture(arch_spec);
-        return SendOKResponse();
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, bytes_read, byte_count);
+        return SendErrorResponse (0x08);
     }
-    return SendErrorResponse(13);
+
+    StreamGDBRemote response;
+    for (lldb::addr_t i = 0; i < bytes_read; ++i)
+        response.PutHex8(buf[i]);
+
+    return SendPacketNoLock(response.GetData(), response.GetSize());
 }
 
 GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+    packet.SetFilePos(::strlen ("QSetDetachOnError:"));
     if (packet.GetU32(0))
-        m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+        m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
     else
-        m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+        m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError);
     return SendOKResponse ();
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen ("QSetDetachOnError:"));
-    if (packet.GetU32(0))
-        m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
-    else
-        m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError);
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_M (StringExtractorGDBRemote &packet)
+{
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+    // Ensure we're llgs.
+    if (!IsGdbServer())
+    {
+        // Only supported on llgs
+        return SendUnimplementedResponse ("");
+    }
+
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
+    }
+
+    // Parse out the memory address.
+    packet.SetFilePos (strlen("M"));
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Too short M packet");
+
+    // Read the address.  Punting on validation.
+    // FIXME replace with Hex U64 read with no default value that fails on failed read.
+    const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0);
+
+    // Validate comma.
+    if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+        return SendIllFormedResponse(packet, "Comma sep missing in M packet");
+
+    // Get # bytes to read.
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Length missing in M packet");
+
+    const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+    if (byte_count == 0)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s nothing to write: zero-length packet", __FUNCTION__);
+        return PacketResult::Success;
+    }
+
+    // Validate colon.
+    if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':'))
+        return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length");
+
+    // Allocate the conversion buffer.
+    std::vector<uint8_t> buf(byte_count, 0);
+    if (buf.empty())
+        return SendErrorResponse (0x78);
+
+    // Convert the hex memory write contents to bytes.
+    StreamGDBRemote response;
+    const uint64_t convert_count = static_cast<uint64_t> (packet.GetHexBytes (&buf[0], byte_count, 0));
+    if (convert_count != byte_count)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count);
+        return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length");
+    }
+
+    // Write the process memory.
+    lldb::addr_t bytes_written = 0;
+    lldb_private::Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ());
+        return SendErrorResponse (0x09);
+    }
+
+    if (bytes_written == 0)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote %" PRIu64 " of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, bytes_written, byte_count);
+        return SendErrorResponse (0x09);
+    }
+
     return SendOKResponse ();
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen ("QSetWorkingDir:"));
-    std::string path;
-    packet.GetHexByteString(path);
-    if (m_is_platform)
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("");
+
+    // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported
+    // request, but we're not guaranteed to be attached to a process.  For now we'll assume the
+    // client only asks this when a process is being debugged.
+
+    // Ensure we have a process running; otherwise, we can't figure this out
+    // since we won't have a NativeProcessProtocol.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-#ifdef _WIN32
-        // Not implemented on Windows
-        return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented");
-#else
-        // If this packet is sent to a platform, then change the current working directory
-        if (::chdir(path.c_str()) != 0)
-            return SendErrorResponse(errno);
-#endif
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
     }
-    else
+
+    // Test if we can get any region back when asking for the region around NULL.
+    MemoryRegionInfo region_info;
+    const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info);
+    if (error.Fail ())
     {
-        m_process_launch_info.SwapWorkingDirectory (path);
+        // We don't support memory region info collection for this NativeProcessProtocol.
+        return SendUnimplementedResponse ("");
     }
-    return SendOKResponse ();
+
+    return SendOKResponse();
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet)
 {
-    StreamString response;
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
 
-    if (m_is_platform)
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("");
+
+    // Ensure we have a process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-        // If this packet is sent to a platform, then change the current working directory
-        char cwd[PATH_MAX];
-        if (getcwd(cwd, sizeof(cwd)) == NULL)
-        {
-            return SendErrorResponse(errno);
-        }
-        else
-        {
-            response.PutBytesAsRawHex8(cwd, strlen(cwd));
-            return SendPacketNoLock(response.GetData(), response.GetSize());
-        }
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
+    }
+
+    // Parse out the memory address.
+    packet.SetFilePos (strlen("qMemoryRegionInfo:"));
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet");
+
+    // Read the address.  Punting on validation.
+    const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+    StreamGDBRemote response;
+
+    // Get the memory region info for the target address.
+    MemoryRegionInfo region_info;
+    const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info);
+    if (error.Fail ())
+    {
+        // Return the error message.
+
+        response.PutCString ("error:");
+        response.PutCStringAsRawHex8 (error.AsCString ());
+        response.PutChar (';');
     }
     else
     {
-        const char *working_dir = m_process_launch_info.GetWorkingDirectory();
-        if (working_dir && working_dir[0])
-        {
-            response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
-            return SendPacketNoLock(response.GetData(), response.GetSize());
-        }
-        else
+        // Range start and size.
+        response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ());
+
+        // Permissions.
+        if (region_info.GetReadable () ||
+            region_info.GetWritable () ||
+            region_info.GetExecutable ())
         {
-            return SendErrorResponse(14);
+            // Write permissions info.
+            response.PutCString ("permissions:");
+
+            if (region_info.GetReadable ())
+                response.PutChar ('r');
+            if (region_info.GetWritable ())
+                response.PutChar('w');
+            if (region_info.GetExecutable())
+                response.PutChar ('x');
+
+            response.PutChar (';');
         }
     }
+
+    return SendPacketNoLock(response.GetData(), response.GetSize());
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_Z (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen ("QSetSTDIN:"));
-    ProcessLaunchInfo::FileAction file_action;
-    std::string path;
-    packet.GetHexByteString(path);
-    const bool read = false;
-    const bool write = true;
-    if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("");
+
+    // Ensure we have a process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-        m_process_launch_info.AppendFileAction(file_action);
-        return SendOKResponse ();
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
     }
-    return SendErrorResponse (15);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen ("QSetSTDOUT:"));
-    ProcessLaunchInfo::FileAction file_action;
-    std::string path;
-    packet.GetHexByteString(path);
-    const bool read = true;
-    const bool write = false;
-    if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+    // Parse out software or hardware breakpoint requested.
+    packet.SetFilePos (strlen("Z"));
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier");
+
+    bool want_breakpoint = true;
+    bool want_hardware = false;
+
+    const char breakpoint_type_char = packet.GetChar ();
+    switch (breakpoint_type_char)
     {
-        m_process_launch_info.AppendFileAction(file_action);
-        return SendOKResponse ();
+        case '0': want_hardware = false; want_breakpoint = true;  break;
+        case '1': want_hardware = true;  want_breakpoint = true;  break;
+        case '2': want_breakpoint = false; break;
+        case '3': want_breakpoint = false; break;
+        default:
+            return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier");
+
     }
-    return SendErrorResponse (16);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen ("QSetSTDERR:"));
-    ProcessLaunchInfo::FileAction file_action;
-    std::string path;
-    packet.GetHexByteString(path);
-    const bool read = true;
-    const bool write = false;
-    if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+    if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+        return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after breakpoint type");
+
+    // FIXME implement watchpoint support.
+    if (!want_breakpoint)
+        return SendUnimplementedResponse ("watchpoint support not yet implemented");
+
+    // Parse out the breakpoint address.
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Too short Z packet, missing address");
+    const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+
+    if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+        return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address");
+
+    // Parse out the breakpoint kind (i.e. size hint for opcode size).
+    const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+    if (kind == std::numeric_limits<uint32_t>::max ())
+        return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse kind argument");
+
+    if (want_breakpoint)
     {
-        m_process_launch_info.AppendFileAction(file_action);
-        return SendOKResponse ();
+        // Try to set the breakpoint.
+        const Error error = m_debugged_process_sp->SetBreakpoint (breakpoint_addr, kind, want_hardware);
+        if (error.Success ())
+            return SendOKResponse ();
+        else
+        {
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to set breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+            return SendErrorResponse (0x09);
+        }
     }
-    return SendErrorResponse (17);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
-{
-    // Send response first before changing m_send_acks to we ack this packet
-    PacketResult packet_result = SendOKResponse ();
-    m_send_acks = false;
-    return packet_result;
+    // FIXME fix up after watchpoints are handled.
+    return SendUnimplementedResponse ("");
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_z (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen("qPlatform_mkdir:"));
-    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
-    if (packet.GetChar() == ',')
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("");
+
+    // Ensure we have a process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-        std::string path;
-        packet.GetHexByteString(path);
-        Error error = Host::MakeDirectory(path.c_str(),mode);
-        if (error.Success())
-            return SendPacketNoLock ("OK", 2);
-        else
-            return SendErrorResponse(error.GetError());
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x15);
     }
-    return SendErrorResponse(20);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen("qPlatform_chmod:"));
-    
-    mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
-    if (packet.GetChar() == ',')
+    // Parse out software or hardware breakpoint requested.
+    packet.SetFilePos (strlen("Z"));
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier");
+
+    bool want_breakpoint = true;
+
+    const char breakpoint_type_char = packet.GetChar ();
+    switch (breakpoint_type_char)
     {
-        std::string path;
-        packet.GetHexByteString(path);
-        Error error = Host::SetFilePermissions (path.c_str(), mode);
-        if (error.Success())
-            return SendPacketNoLock ("OK", 2);
-        else
-            return SendErrorResponse(error.GetError());
+        case '0': want_breakpoint = true;  break;
+        case '1': want_breakpoint = true;  break;
+        case '2': want_breakpoint = false; break;
+        case '3': want_breakpoint = false; break;
+        default:
+            return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier");
+
     }
-    return SendErrorResponse(19);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen("vFile:open:"));
-    std::string path;
-    packet.GetHexByteStringTerminatedBy(path,',');
-    if (!path.empty())
+    if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+        return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after breakpoint type");
+
+    // FIXME implement watchpoint support.
+    if (!want_breakpoint)
+        return SendUnimplementedResponse ("watchpoint support not yet implemented");
+
+    // Parse out the breakpoint address.
+    if (packet.GetBytesLeft() < 1)
+        return SendIllFormedResponse(packet, "Too short z packet, missing address");
+    const lldb::addr_t breakpoint_addr = packet.GetHexMaxU64(false, 0);
+
+    if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+        return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address");
+
+    // Parse out the breakpoint kind (i.e. size hint for opcode size).
+    const uint32_t kind = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+    if (kind == std::numeric_limits<uint32_t>::max ())
+        return SendIllFormedResponse(packet, "Malformed z packet, failed to parse kind argument");
+
+    if (want_breakpoint)
     {
-        if (packet.GetChar() == ',')
+        // Try to set the breakpoint.
+        const Error error = m_debugged_process_sp->RemoveBreakpoint (breakpoint_addr);
+        if (error.Success ())
+            return SendOKResponse ();
+        else
         {
-            uint32_t flags = packet.GetHexMaxU32(false, 0);
-            if (packet.GetChar() == ',')
-            {
-                mode_t mode = packet.GetHexMaxU32(false, 0600);
-                Error error;
-                int fd = ::open (path.c_str(), flags, mode);
-                const int save_errno = fd == -1 ? errno : 0;
-                StreamString response;
-                response.PutChar('F');
-                response.Printf("%i", fd);
-                if (save_errno)
-                    response.Printf(",%i", save_errno);
-                return SendPacketNoLock(response.GetData(), response.GetSize());
-            }
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to remove breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+            return SendErrorResponse (0x09);
         }
     }
-    return SendErrorResponse(18);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen("vFile:close:"));
-    int fd = packet.GetS32(-1);
-    Error error;
-    int err = -1;
-    int save_errno = 0;
-    if (fd >= 0)
-    {
-        err = close(fd);
-        save_errno = err == -1 ? errno : 0;
-    }
-    else
-    {
-        save_errno = EINVAL;
-    }
-    StreamString response;
-    response.PutChar('F');
-    response.Printf("%i", err);
-    if (save_errno)
-        response.Printf(",%i", save_errno);
-    return SendPacketNoLock(response.GetData(), response.GetSize());
+    // FIXME fix up after watchpoints are handled.
+    return SendUnimplementedResponse ("");
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_s (StringExtractorGDBRemote &packet)
 {
-#ifdef _WIN32
-    // Not implemented on Windows
-    return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented");
-#else
-    StreamGDBRemote response;
-    packet.SetFilePos(::strlen("vFile:pread:"));
-    int fd = packet.GetS32(-1);
-    if (packet.GetChar() == ',')
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("");
+
+    // Ensure we have a process.
+    if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
     {
-        uint64_t count = packet.GetU64(UINT64_MAX);
-        if (packet.GetChar() == ',')
-        {
-            uint64_t offset = packet.GetU64(UINT32_MAX);
-            if (count == UINT64_MAX)
-            {
-                response.Printf("F-1:%i", EINVAL);
-                return SendPacketNoLock(response.GetData(), response.GetSize());
-            }
-            
-            std::string buffer(count, 0);
-            const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
-            const int save_errno = bytes_read == -1 ? errno : 0;
-            response.PutChar('F');
-            response.Printf("%zi", bytes_read);
-            if (save_errno)
-                response.Printf(",%i", save_errno);
-            else
-            {
-                response.PutChar(';');
-                response.PutEscapedBytes(&buffer[0], bytes_read);
-            }
-            return SendPacketNoLock(response.GetData(), response.GetSize());
-        }
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+        return SendErrorResponse (0x32);
+    }
+
+    // We first try to use a continue thread id.  If any one or any all set, use the current thread.
+    // Bail out if we don't have a thread id.
+    lldb::tid_t tid = GetContinueThreadID ();
+    if (tid == 0 || tid == LLDB_INVALID_THREAD_ID)
+        tid = GetCurrentThreadID ();
+    if (tid == LLDB_INVALID_THREAD_ID)
+        return SendErrorResponse (0x33);
+
+    // Double check that we have such a thread.
+    // TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
+    NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid);
+    if (!thread_sp || thread_sp->GetID () != tid)
+        return SendErrorResponse (0x33);
+
+    // Create the step action for the given thread.
+    lldb_private::ResumeAction action = { tid, eStateStepping, 0 };
+
+    // Setup the actions list.
+    lldb_private::ResumeActionList actions;
+    actions.Append (action);
+
+    // All other threads stop while we're single stepping a thread.
+    actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
+    Error error = m_debugged_process_sp->Resume (actions);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ());
+        return SendErrorResponse(0x49);
     }
-    return SendErrorResponse(21);
 
+    // No response here - the stop or exit will come from the resulting action.
+    return PacketResult::Success;
+}
+
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qSupported (StringExtractorGDBRemote &packet)
+{
+    StreamGDBRemote response;
+
+    // Features common to lldb-platform and llgs.
+    uint32_t max_packet_size = 128 * 1024;  // 128KBytes is a reasonable max packet size--debugger can always use less
+    response.Printf ("PacketSize=%x", max_packet_size);
+
+    response.PutCString (";QStartNoAckMode+");
+    response.PutCString (";QThreadSuffixSupported+");
+    response.PutCString (";QListThreadsInStopReply+");
+#if defined(__linux__)
+    response.PutCString (";qXfer:auxv:read+");
 #endif
+
+    return SendPacketNoLock(response.GetData(), response.GetSize());
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet)
 {
-#ifdef _WIN32
-    return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented");
-#else
-    packet.SetFilePos(::strlen("vFile:pwrite:"));
+    m_thread_suffix_supported = true;
+    return SendOKResponse();
+}
 
-    StreamGDBRemote response;
-    response.PutChar('F');
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet)
+{
+    m_list_threads_in_stop_reply = true;
+    return SendOKResponse();
+}
 
-    int fd = packet.GetU32(UINT32_MAX);
-    if (packet.GetChar() == ',')
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet)
+{
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+    // *BSD impls should be able to do this too.
+#if defined(__linux__)
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+    // Parse out the offset.
+    packet.SetFilePos (strlen("qXfer:auxv:read::"));
+    if (packet.GetBytesLeft () < 1)
+        return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+    const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+    if (auxv_offset == std::numeric_limits<uint64_t>::max ())
+        return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+    // Parse out comma.
+    if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',')
+        return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset");
+
+    // Parse out the length.
+    const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+    if (auxv_length == std::numeric_limits<uint64_t>::max ())
+        return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length");
+
+    // Grab the auxv data if we need it.
+    if (!m_active_auxv_buffer_sp)
     {
-        off_t offset = packet.GetU64(UINT32_MAX);
-        if (packet.GetChar() == ',')
+        // Make sure we have a valid process.
+        if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
         {
-            std::string buffer;
-            if (packet.GetEscapedBinaryData(buffer))
-            {
-                const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
-                const int save_errno = bytes_written == -1 ? errno : 0;
-                response.Printf("%zi", bytes_written);
-                if (save_errno)
-                    response.Printf(",%i", save_errno);
-            }
-            else
-            {
-                response.Printf ("-1,%i", EINVAL);
-            }
-            return SendPacketNoLock(response.GetData(), response.GetSize());
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s failed, no process available", __FUNCTION__);
+            return SendErrorResponse (0x10);
+        }
+
+        // Grab the auxv data.
+        m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ());
+        if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () ==  0)
+        {
+            // Hmm, no auxv data, call that an error.
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s failed, no auxv data retrieved", __FUNCTION__);
+            m_active_auxv_buffer_sp.reset ();
+            return SendErrorResponse (0x11);
         }
     }
-    return SendErrorResponse(27);
-#endif
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen("vFile:size:"));
-    std::string path;
-    packet.GetHexByteString(path);
-    if (!path.empty())
+    // FIXME find out if/how I lock the stream here.
+
+    StreamGDBRemote response;
+    bool done_with_buffer = false;
+
+    if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ())
     {
-        lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
-        StreamString response;
-        response.PutChar('F');
-        response.PutHex64(retcode);
-        if (retcode == UINT64_MAX)
+        // We have nothing left to send.  Mark the buffer as complete.
+        response.PutChar ('l');
+        done_with_buffer = true;
+    }
+    else
+    {
+        // Figure out how many bytes are available starting at the given offset.
+        const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset;
+
+        // Figure out how many bytes we're going to read.
+        const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length;
+
+        // Mark the response type according to whether we're reading the remainder of the auxv data.
+        if (bytes_to_read >= bytes_remaining)
         {
-            response.PutChar(',');
-            response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+            // There will be nothing left to read after this
+            response.PutChar ('l');
+            done_with_buffer = true;
         }
-        return SendPacketNoLock(response.GetData(), response.GetSize());
+        else
+        {
+            // There will still be bytes to read after this request.
+            response.PutChar ('m');
+        }
+
+        // Now write the data in encoded binary form.
+        response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read);
     }
-    return SendErrorResponse(22);
+
+    if (done_with_buffer)
+        m_active_auxv_buffer_sp.reset ();
+
+    return SendPacketNoLock(response.GetData(), response.GetSize());
+#else
+    return SendUnimplementedResponse ("not implemented on this platform");
+#endif
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen("vFile:mode:"));
-    std::string path;
-    packet.GetHexByteString(path);
-    if (!path.empty())
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+    // Move past packet name.
+    packet.SetFilePos (strlen ("QSaveRegisterState"));
+
+    // Get the thread to use.
+    NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+    if (!thread_sp)
     {
-        Error error;
-        const uint32_t mode = File::GetPermissions(path.c_str(), error);
-        StreamString response;
-        response.Printf("F%u", mode);
-        if (mode == 0 || error.Fail())
-            response.Printf(",%i", (int)error.GetError());
-        return SendPacketNoLock(response.GetData(), response.GetSize());
+        if (m_thread_suffix_supported)
+            return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet");
+        else
+            return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
     }
-    return SendErrorResponse(23);
+
+    // Grab the register context for the thread.
+    NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+    if (!reg_context_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+        return SendErrorResponse (0x15);
+    }
+
+    // Save registers to a buffer.
+    DataBufferSP register_data_sp;
+    Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+        return SendErrorResponse (0x75);
+    }
+
+    // Allocate a new save id.
+    const uint32_t save_id = GetNextSavedRegistersID ();
+    assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id");
+
+    // Save the register data buffer under the save id.
+    {
+        Mutex::Locker locker (m_saved_registers_mutex);
+        m_saved_registers_map[save_id] = register_data_sp;
+    }
+
+    // Write the response.
+    StreamGDBRemote response;
+    response.Printf ("%" PRIu32, save_id);
+    return SendPacketNoLock(response.GetData(), response.GetSize());
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::PacketResult
+GDBRemoteCommunicationServer::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen("vFile:exists:"));
-    std::string path;
-    packet.GetHexByteString(path);
-    if (!path.empty())
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+    // We don't support if we're not llgs.
+    if (!IsGdbServer())
+        return SendUnimplementedResponse ("only supported for lldb-gdbserver");
+
+    // Parse out save id.
+    packet.SetFilePos (strlen ("QRestoreRegisterState:"));
+    if (packet.GetBytesLeft () < 1)
+        return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id");
+
+    const uint32_t save_id = packet.GetU32 (0);
+    if (save_id == 0)
     {
-        bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
-        StreamString response;
-        response.PutChar('F');
-        response.PutChar(',');
-        if (retcode)
-            response.PutChar('1');
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__);
+        return SendErrorResponse (0x76);
+    }
+
+    // Get the thread to use.
+    NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+    if (!thread_sp)
+    {
+        if (m_thread_suffix_supported)
+            return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet");
         else
-            response.PutChar('0');
-        return SendPacketNoLock(response.GetData(), response.GetSize());
+            return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
     }
-    return SendErrorResponse(24);
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
-{
-    packet.SetFilePos(::strlen("vFile:symlink:"));
-    std::string dst, src;
-    packet.GetHexByteStringTerminatedBy(dst, ',');
-    packet.GetChar(); // Skip ',' char
-    packet.GetHexByteString(src);
-    Error error = Host::Symlink(src.c_str(), dst.c_str());
-    StreamString response;
-    response.Printf("F%u,%u", error.GetError(), error.GetError());
-    return SendPacketNoLock(response.GetData(), response.GetSize());
+    // Grab the register context for the thread.
+    NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+    if (!reg_context_sp)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+        return SendErrorResponse (0x15);
+    }
+
+    // Retrieve register state buffer, then remove from the list.
+    DataBufferSP register_data_sp;
+    {
+        Mutex::Locker locker (m_saved_registers_mutex);
+
+        // Find the register set buffer for the given save id.
+        auto it = m_saved_registers_map.find (save_id);
+        if (it == m_saved_registers_map.end ())
+        {
+            if (log)
+                log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id);
+            return SendErrorResponse (0x77);
+        }
+        register_data_sp = it->second;
+
+        // Remove it from the map.
+        m_saved_registers_map.erase (it);
+    }
+
+    Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp);
+    if (error.Fail ())
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+        return SendErrorResponse (0x77);
+    }
+
+    return SendOKResponse();
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::FlushInferiorOutput ()
 {
-    packet.SetFilePos(::strlen("vFile:unlink:"));
-    std::string path;
-    packet.GetHexByteString(path);
-    Error error = Host::Unlink(path.c_str());
-    StreamString response;
-    response.Printf("F%u,%u", error.GetError(), error.GetError());
-    return SendPacketNoLock(response.GetData(), response.GetSize());
+    // If we're not monitoring an inferior's terminal, ignore this.
+    if (!m_stdio_communication.IsConnected())
+        return;
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+    if (log)
+        log->Printf ("GDBRemoteCommunicationServer::%s() called", __FUNCTION__);
+
+    // FIXME implement a timeout on the join.
+    m_stdio_communication.JoinReadThread();
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
+void
+GDBRemoteCommunicationServer::MaybeCloseInferiorTerminalConnection ()
 {
-    packet.SetFilePos(::strlen("qPlatform_shell:"));
-    std::string path;
-    std::string working_dir;
-    packet.GetHexByteStringTerminatedBy(path,',');
-    if (!path.empty())
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+    // Tell the stdio connection to shut down.
+    if (m_stdio_communication.IsConnected())
     {
-        if (packet.GetChar() == ',')
+        auto connection = m_stdio_communication.GetConnection();
+        if (connection)
         {
-            // FIXME: add timeout to qPlatform_shell packet
-            // uint32_t timeout = packet.GetHexMaxU32(false, 32);
-            uint32_t timeout = 10;
-            if (packet.GetChar() == ',')
-                packet.GetHexByteString(working_dir);
-            int status, signo;
-            std::string output;
-            Error err = Host::RunShellCommand(path.c_str(),
-                                              working_dir.empty() ? NULL : working_dir.c_str(),
-                                              &status, &signo, &output, timeout);
-            StreamGDBRemote response;
-            if (err.Fail())
+            Error error;
+            connection->Disconnect (&error);
+
+            if (error.Success ())
             {
-                response.PutCString("F,");
-                response.PutHex32(UINT32_MAX);
+                if (log)
+                    log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__);
             }
             else
             {
-                response.PutCString("F,");
-                response.PutHex32(status);
-                response.PutChar(',');
-                response.PutHex32(signo);
-                response.PutChar(',');
-                response.PutEscapedBytes(output.c_str(), output.size());
+                if (log)
+                    log->Printf ("GDBRemoteCommunicationServer::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ());
             }
-            return SendPacketNoLock(response.GetData(), response.GetSize());
         }
     }
-    return SendErrorResponse(24);
 }
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
-{
-    return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");
-}
 
-GDBRemoteCommunication::PacketResult
-GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+lldb_private::NativeThreadProtocolSP
+GDBRemoteCommunicationServer::GetThreadFromSuffix (StringExtractorGDBRemote &packet)
 {
-    packet.SetFilePos(::strlen("vFile:MD5:"));
-    std::string path;
-    packet.GetHexByteString(path);
-    if (!path.empty())
-    {
-        uint64_t a,b;
-        StreamGDBRemote response;
-        if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
+    NativeThreadProtocolSP thread_sp;
+
+    // We have no thread if we don't have a process.
+    if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)
+        return thread_sp;
+
+    // If the client hasn't asked for thread suffix support, there will not be a thread suffix.
+    // Use the current thread in that case.
+    if (!m_thread_suffix_supported)
+    {
+        const lldb::tid_t current_tid = GetCurrentThreadID ();
+        if (current_tid == LLDB_INVALID_THREAD_ID)
+            return thread_sp;
+        else if (current_tid == 0)
         {
-            response.PutCString("F,");
-            response.PutCString("x");
+            // Pick a thread.
+            return m_debugged_process_sp->GetThreadAtIndex (0);
         }
         else
-        {
-            response.PutCString("F,");
-            response.PutHex64(a);
-            response.PutHex64(b);
-        }
-        return SendPacketNoLock(response.GetData(), response.GetSize());
+            return m_debugged_process_sp->GetThreadByID (current_tid);
     }
-    return SendErrorResponse(25);
+
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+    // Parse out the ';'.
+    if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';')
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+        return thread_sp;
+    }
+
+    if (!packet.GetBytesLeft ())
+        return thread_sp;
+
+    // Parse out thread: portion.
+    if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0)
+    {
+        if (log)
+            log->Printf ("GDBRemoteCommunicationServer::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+        return thread_sp;
+    }
+    packet.SetFilePos (packet.GetFilePos () + strlen("thread:"));
+    const lldb::tid_t tid = packet.GetHexMaxU64(false, 0);
+    if (tid != 0)
+        return m_debugged_process_sp->GetThreadByID (tid);
+
+    return thread_sp;
+}
+
+lldb::tid_t
+GDBRemoteCommunicationServer::GetCurrentThreadID () const
+{
+    if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID)
+    {
+        // Use whatever the debug process says is the current thread id
+        // since the protocol either didn't specify or specified we want
+        // any/all threads marked as the current thread.
+        if (!m_debugged_process_sp)
+            return LLDB_INVALID_THREAD_ID;
+        return m_debugged_process_sp->GetCurrentThreadID ();
+    }
+    // Use the specific current thread id set by the gdb remote protocol.
+    return m_current_tid;
+}
+
+uint32_t
+GDBRemoteCommunicationServer::GetNextSavedRegistersID ()
+{
+    Mutex::Locker locker (m_saved_registers_mutex);
+    return m_next_saved_registers_id++;
 }
 

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h Mon Jun 30 16:05:18 2014
@@ -14,16 +14,23 @@
 // C++ Includes
 #include <vector>
 #include <set>
+#include <unordered_map>
 // Other libraries and framework includes
 // Project includes
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Communication.h"
 #include "lldb/Host/Mutex.h"
 #include "lldb/Target/Process.h"
 #include "GDBRemoteCommunication.h"
 
+#include "../../../Host/common/NativeProcessProtocol.h"
+
 class ProcessGDBRemote;
 class StringExtractorGDBRemote;
 
-class GDBRemoteCommunicationServer : public GDBRemoteCommunication
+class GDBRemoteCommunicationServer :
+    public GDBRemoteCommunication,
+    public lldb_private::NativeProcessProtocol::NativeDelegate
 {
 public:
     typedef std::map<uint16_t, lldb::pid_t> PortMap;
@@ -38,12 +45,13 @@ public:
     GDBRemoteCommunicationServer(bool is_platform);
 
     GDBRemoteCommunicationServer(bool is_platform,
-                                 const lldb::PlatformSP& platform_sp); 
+                                 const lldb::PlatformSP& platform_sp,
+                                 lldb::DebuggerSP& debugger_sp);
 
     virtual
     ~GDBRemoteCommunicationServer();
 
-    bool
+    PacketResult
     GetPacketAndSendResponse (uint32_t timeout_usec,
                               lldb_private::Error &error,
                               bool &interrupt, 
@@ -188,6 +196,28 @@ public:
     lldb_private::Error
     LaunchProcess ();
 
+    //------------------------------------------------------------------
+    /// Attach to a process.
+    ///
+    /// This method supports attaching llgs to a process accessible via the
+    /// configured Platform.
+    ///
+    /// @return
+    ///     An Error object indicating the success or failure of the
+    ///     attach operation.
+    //------------------------------------------------------------------
+    lldb_private::Error
+    AttachToProcess (lldb::pid_t pid);
+
+    //------------------------------------------------------------------
+    // NativeProcessProtocol::NativeDelegate overrides
+    //------------------------------------------------------------------
+    void
+    InitializeDelegate (lldb_private::NativeProcessProtocol *process) override;
+
+    void
+    ProcessStateChanged (lldb_private::NativeProcessProtocol *process, lldb::StateType state) override;
+
 protected:
     lldb::PlatformSP m_platform_sp;
     lldb::thread_t m_async_thread;
@@ -199,7 +229,20 @@ protected:
     uint32_t m_proc_infos_index;
     PortMap m_port_map;
     uint16_t m_port_offset;
-
+    lldb::tid_t m_current_tid;
+    lldb::tid_t m_continue_tid;
+    lldb_private::Mutex m_debugged_process_mutex;
+    lldb_private::NativeProcessProtocolSP m_debugged_process_sp;
+    lldb::DebuggerSP m_debugger_sp;
+    Communication m_stdio_communication;
+    bool m_exit_now; // use in asynchronous handling to indicate process should exit.
+    lldb::StateType m_inferior_prev_state;
+    bool m_thread_suffix_supported;
+    bool m_list_threads_in_stop_reply;
+    lldb::DataBufferSP m_active_auxv_buffer_sp;
+    lldb_private::Mutex m_saved_registers_mutex;
+    std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
+    uint32_t m_next_saved_registers_id;
 
     PacketResult
     SendUnimplementedResponse (const char *packet);
@@ -208,9 +251,24 @@ protected:
     SendErrorResponse (uint8_t error);
 
     PacketResult
+    SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message);
+
+    PacketResult
     SendOKResponse ();
 
     PacketResult
+    SendONotification (const char *buffer, uint32_t len);
+
+    PacketResult
+    SendWResponse (lldb_private::NativeProcessProtocol *process);
+
+    PacketResult
+    SendStopReplyPacketForThread (lldb::tid_t tid);
+
+    PacketResult
+    SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit);
+
+    PacketResult
     Handle_A (StringExtractorGDBRemote &packet);
     
     PacketResult
@@ -233,7 +291,10 @@ protected:
     
     PacketResult
     Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
-    
+
+    PacketResult
+    Handle_qProcessInfo (StringExtractorGDBRemote &packet);
+
     PacketResult
     Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
     
@@ -284,7 +345,22 @@ protected:
 
     PacketResult
     Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
-    
+
+    PacketResult
+    Handle_C (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_c (StringExtractorGDBRemote &packet, bool skip_file_pos_adjustment = false);
+
+    PacketResult
+    Handle_vCont (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_vCont_actions (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_stop_reason (StringExtractorGDBRemote &packet);
+
     PacketResult
     Handle_vFile_Open (StringExtractorGDBRemote &packet);
 
@@ -321,6 +397,84 @@ protected:
     PacketResult
     Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
 
+    PacketResult
+    Handle_qRegisterInfo (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_qfThreadInfo (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_qsThreadInfo (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_p (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_P (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_H (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_interrupt (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_m (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_M (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_Z (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_z (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_s (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_qSupported (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_QSaveRegisterState (StringExtractorGDBRemote &packet);
+
+    PacketResult
+    Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet);
+
+    void
+    SetCurrentThreadID (lldb::tid_t tid);
+
+    lldb::tid_t
+    GetCurrentThreadID () const;
+
+    void
+    SetContinueThreadID (lldb::tid_t tid);
+
+    lldb::tid_t
+    GetContinueThreadID () const { return m_continue_tid; }
+
+    lldb_private::Error
+    SetSTDIOFileDescriptor (int fd);
+
+    static void
+    STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
 private:
     bool
     DebugserverProcessReaped (lldb::pid_t pid);
@@ -345,6 +499,38 @@ private:
     bool
     KillSpawnedProcess (lldb::pid_t pid);
 
+    bool
+    IsGdbServer ()
+    {
+        return !m_is_platform;
+    }
+
+    /// Launch a process from lldb-gdbserver
+    lldb_private::Error
+    LaunchDebugServerProcess ();
+
+    /// Launch a process from lldb-platform
+    lldb_private::Error
+    LaunchPlatformProcess ();
+
+    void
+    HandleInferiorState_Exited (lldb_private::NativeProcessProtocol *process);
+
+    void
+    HandleInferiorState_Stopped (lldb_private::NativeProcessProtocol *process);
+
+    void
+    FlushInferiorOutput ();
+
+    lldb_private::NativeThreadProtocolSP
+    GetThreadFromSuffix (StringExtractorGDBRemote &packet);
+
+    uint32_t
+    GetNextSavedRegistersID ();
+
+    void
+    MaybeCloseInferiorTerminalConnection ();
+
     //------------------------------------------------------------------
     // For GDBRemoteCommunicationServer only
     //------------------------------------------------------------------

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Mon Jun 30 16:05:18 2014
@@ -61,7 +61,9 @@
 
 // Project includes
 #include "lldb/Host/Host.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
 #include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/LinuxSignals.h"
 #include "Plugins/Process/Utility/StopInfoMachException.h"
 #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
 #include "Utility/StringExtractorGDBRemote.h"
@@ -285,7 +287,8 @@ ProcessGDBRemote::ProcessGDBRemote(Targe
     m_waiting_for_attach (false),
     m_destroy_tried_resuming (false),
     m_command_sp (),
-    m_breakpoint_pc_offset (0)
+    m_breakpoint_pc_offset (0),
+    m_unix_signals_sp (new UnixSignals ())
 {
     m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit,   "async thread should exit");
     m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue,           "async thread continue");
@@ -628,6 +631,7 @@ ProcessGDBRemote::WillAttachToProcessWit
 Error
 ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
 {
+    Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
     Error error (WillLaunchOrAttach ());
     
     if (error.Fail())
@@ -678,7 +682,11 @@ ProcessGDBRemote::DoConnectRemote (Strea
             error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url);
     }
 
-    if (error.Success() 
+    if (log)
+        log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false");
+
+
+    if (error.Success()
         && !GetTarget().GetArchitecture().IsValid()
         && m_gdb_comm.GetHostArchitecture().IsValid())
     {
@@ -689,6 +697,42 @@ ProcessGDBRemote::DoConnectRemote (Strea
             GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture());
     }
 
+    if (log)
+        log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ());
+
+    // Set the Unix signals properly for the target.
+    // FIXME Add a gdb-remote packet to discover dynamically.
+    if (error.Success ())
+    {
+        const ArchSpec arch_spec = GetTarget ().GetArchitecture ();
+        if (arch_spec.IsValid ())
+        {
+            if (log)
+                log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": determining unix signals type based on architecture %s, triple %s", __FUNCTION__, GetID (), arch_spec.GetArchitectureName () ? arch_spec.GetArchitectureName () : "<null>", arch_spec.GetTriple ().getTriple ().c_str ());
+
+            switch (arch_spec.GetTriple ().getOS ())
+            {
+            case llvm::Triple::Linux:
+                m_unix_signals_sp.reset (new process_linux::LinuxSignals ());
+                if (log)
+                    log->Printf ("ProcessGDBRemote::%s using Linux unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+                break;
+            case llvm::Triple::OpenBSD:
+            case llvm::Triple::FreeBSD:
+            case llvm::Triple::NetBSD:
+                m_unix_signals_sp.reset (new FreeBSDSignals ());
+                if (log)
+                    log->Printf ("ProcessGDBRemote::%s using *BSD unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+                break;
+            default:
+                m_unix_signals_sp.reset (new UnixSignals ());
+                if (log)
+                    log->Printf ("ProcessGDBRemote::%s using generic unix signals type for pid %" PRIu64, __FUNCTION__, GetID ());
+                break;
+            }
+        }
+    }
+
     return error;
 }
 
@@ -1040,6 +1084,13 @@ ProcessGDBRemote::DidLaunch ()
     DidLaunchOrAttach ();
 }
 
+UnixSignals&
+ProcessGDBRemote::GetUnixSignals ()
+{
+    assert (m_unix_signals_sp && "m_unix_signals_sp is null");
+    return *m_unix_signals_sp;
+}
+
 Error
 ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid)
 {
@@ -2231,6 +2282,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t
 lldb::addr_t
 ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
 {
+    lldb_private::Log *log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS));
     addr_t allocated_addr = LLDB_INVALID_ADDRESS;
     
     LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
@@ -2256,7 +2308,11 @@ ProcessGDBRemote::DoAllocateMemory (size
                                  eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0))
                 m_addr_to_mmap_size[allocated_addr] = size;
             else
+            {
                 allocated_addr = LLDB_INVALID_ADDRESS;
+                if (log)
+                    log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__);
+            }
             break;
     }
     

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h Mon Jun 30 16:05:18 2014
@@ -91,6 +91,9 @@ public:
     virtual void
     DidLaunch ();
 
+    lldb_private::UnixSignals&
+    GetUnixSignals () override;
+
     virtual lldb_private::Error
     WillAttachToProcessWithID (lldb::pid_t pid);
 
@@ -305,8 +308,8 @@ protected:
     bool
     ParseRegisters(lldb_private::ScriptInterpreterObject *registers_array);
 
-    virtual const lldb::DataBufferSP
-    GetAuxvData();
+    const lldb::DataBufferSP
+    GetAuxvData() override;
 
     lldb_private::StructuredData::ObjectSP
     GetExtendedInfoForThread (lldb::tid_t tid);
@@ -357,7 +360,9 @@ protected:
     bool m_destroy_tried_resuming;
     lldb::CommandObjectSP m_command_sp;
     int64_t m_breakpoint_pc_offset;
-    
+    std::shared_ptr<lldb_private::UnixSignals> m_unix_signals_sp;
+
+
     bool
     StartAsyncThread ();
 

Modified: lldb/trunk/source/Target/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/CMakeLists.txt?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Target/CMakeLists.txt (original)
+++ lldb/trunk/source/Target/CMakeLists.txt Mon Jun 30 16:05:18 2014
@@ -10,6 +10,8 @@ add_lldb_library(lldbTarget
   JITLoaderList.cpp
   LanguageRuntime.cpp
   Memory.cpp
+  NativeRegisterContext.cpp
+  NativeRegisterContextRegisterInfo.cpp
   ObjCLanguageRuntime.cpp
   OperatingSystem.cpp
   PathMappingList.cpp

Added: lldb/trunk/source/Target/NativeRegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/NativeRegisterContext.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Target/NativeRegisterContext.cpp (added)
+++ lldb/trunk/source/Target/NativeRegisterContext.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,470 @@
+//===-- NativeRegisterContext.cpp -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/NativeRegisterContext.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) :
+    m_thread (thread),
+    m_concrete_frame_idx (concrete_frame_idx)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+NativeRegisterContext::~NativeRegisterContext()
+{
+}
+
+// FIXME revisit invalidation, process stop ids, etc.  Right now we don't
+// support caching in NativeRegisterContext.  We can do this later by
+// utilizing NativeProcessProtocol::GetStopID () and adding a stop id to
+// NativeRegisterContext.
+
+// void
+// NativeRegisterContext::InvalidateIfNeeded (bool force)
+// {
+//     ProcessSP process_sp (m_thread.GetProcess());
+//     bool invalidate = force;
+//     uint32_t process_stop_id = UINT32_MAX;
+
+//     if (process_sp)
+//         process_stop_id = process_sp->GetStopID();
+//     else
+//         invalidate = true;
+
+//     if (!invalidate)
+//         invalidate = process_stop_id != GetStopID();
+
+//     if (invalidate)
+//     {
+//         InvalidateAllRegisters ();
+//         SetStopID (process_stop_id);
+//     }
+// }
+
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx)
+{
+    if (reg_name && reg_name[0])
+    {
+        const uint32_t num_registers = GetRegisterCount();
+        for (uint32_t reg = start_idx; reg < num_registers; ++reg)
+        {
+            const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+
+            if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) ||
+                (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0))
+            {
+                return reg_info;
+            }
+        }
+    }
+    return nullptr;
+}
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num)
+{
+    const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
+    if (reg_num == LLDB_INVALID_REGNUM)
+        return nullptr;
+    return GetRegisterInfoAtIndex (reg_num);
+}
+
+const char *
+NativeRegisterContext::GetRegisterName (uint32_t reg)
+{
+    const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+    if (reg_info)
+        return reg_info->name;
+    return nullptr;
+}
+
+const char*
+NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const
+{
+    const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+    if (!reg_info)
+        return nullptr;
+
+    for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index)
+    {
+        const RegisterSet *const reg_set = GetRegisterSet (set_index);
+        if (!reg_set)
+            continue;
+
+        for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index)
+        {
+            const uint32_t reg_num = reg_set->registers[reg_num_index];
+            // FIXME double check we're checking the right register kind here.
+            if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num)
+            {
+                // The given register is a member of this register set.  Return the register set name.
+                return reg_set->name;
+            }
+        }
+    }
+
+    // Didn't find it.
+    return nullptr;
+}
+
+lldb::addr_t
+NativeRegisterContext::GetPC (lldb::addr_t fail_value)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+    if (log)
+        log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value);
+
+    const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value);
+
+    if (log)
+        log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval);
+
+    return retval;
+}
+
+Error
+NativeRegisterContext::SetPC (lldb::addr_t pc)
+{
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+    return WriteRegisterFromUnsigned (reg, pc);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetSP (lldb::addr_t fail_value)
+{
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+    return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetSP (lldb::addr_t sp)
+{
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+    return WriteRegisterFromUnsigned (reg, sp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFP (lldb::addr_t fail_value)
+{
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+    return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetFP (lldb::addr_t fp)
+{
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+    return WriteRegisterFromUnsigned (reg, fp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value)
+{
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+    return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFlags (lldb::addr_t fail_value)
+{
+    uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+    return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+
+lldb::addr_t
+NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value)
+{
+    if (reg != LLDB_INVALID_REGNUM)
+        return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value);
+    return fail_value;
+}
+
+uint64_t
+NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value)
+{
+    Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+    if (reg_info)
+    {
+        RegisterValue value;
+        Error error = ReadRegister (reg_info, value);
+        if (error.Success ())
+        {
+            if (log)
+                log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64());
+            return value.GetAsUInt64();
+        }
+        else
+        {
+            if (log)
+                log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ());
+        }
+    }
+    else
+    {
+        if (log)
+            log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__);
+    }
+    return fail_value;
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+    if (reg == LLDB_INVALID_REGNUM)
+        return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
+    return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval);
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval)
+{
+    assert (reg_info);
+    if (!reg_info)
+        return Error ("reg_info is nullptr");
+
+    RegisterValue value;
+    if (!value.SetUInt(uval, reg_info->byte_size))
+        return Error ("RegisterValue::SetUInt () failed");
+
+    return WriteRegister (reg_info, value);
+}
+
+lldb::tid_t
+NativeRegisterContext::GetThreadID() const
+{
+    return m_thread.GetID();
+}
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareBreakpoints ()
+{
+    return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+    return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+    return false;
+}
+
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareWatchpoints ()
+{
+    return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+    return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+    return false;
+}
+
+bool
+NativeRegisterContext::HardwareSingleStep (bool enable)
+{
+    return false;
+}
+
+Error
+NativeRegisterContext::ReadRegisterValueFromMemory (
+    const RegisterInfo *reg_info,
+    lldb::addr_t src_addr,
+    lldb::addr_t src_len,
+    RegisterValue &reg_value)
+{
+    Error error;
+    if (reg_info == nullptr)
+    {
+        error.SetErrorString ("invalid register info argument.");
+        return error;
+    }
+
+
+    // Moving from addr into a register
+    //
+    // Case 1: src_len == dst_len
+    //
+    //   |AABBCCDD| Address contents
+    //   |AABBCCDD| Register contents
+    //
+    // Case 2: src_len > dst_len
+    //
+    //   Error!  (The register should always be big enough to hold the data)
+    //
+    // Case 3: src_len < dst_len
+    //
+    //   |AABB| Address contents
+    //   |AABB0000| Register contents [on little-endian hardware]
+    //   |0000AABB| Register contents [on big-endian hardware]
+    if (src_len > RegisterValue::kMaxRegisterByteSize)
+    {
+        error.SetErrorString ("register too small to receive memory data");
+        return error;
+    }
+
+    const lldb::addr_t dst_len = reg_info->byte_size;
+
+    if (src_len > dst_len)
+    {
+        error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)", src_len, reg_info->name, dst_len);
+        return error;
+    }
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (!process_sp)
+    {
+        error.SetErrorString("invalid process");
+        return error;
+    }
+
+    uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+    // Read the memory
+    lldb::addr_t bytes_read;
+    error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read);
+    if (error.Fail ())
+        return error;
+
+    // Make sure the memory read succeeded...
+    if (bytes_read != src_len)
+    {
+        // This might happen if we read _some_ bytes but not all
+        error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes", bytes_read, src_len);
+        return error;
+    }
+
+    // We now have a memory buffer that contains the part or all of the register
+    // value. Set the register value using this memory data.
+    // TODO: we might need to add a parameter to this function in case the byte
+    // order of the memory data doesn't match the process. For now we are assuming
+    // they are the same.
+    lldb::ByteOrder byte_order;
+    if (!process_sp->GetByteOrder (byte_order))
+    {
+        error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed");
+        return error;
+    }
+
+    reg_value.SetFromMemoryData (
+        reg_info,
+        src,
+        src_len,
+        byte_order,
+        error);
+
+    return error;
+}
+
+Error
+NativeRegisterContext::WriteRegisterValueToMemory (
+    const RegisterInfo *reg_info,
+    lldb::addr_t dst_addr,
+    lldb::addr_t dst_len,
+    const RegisterValue &reg_value)
+{
+    
+    uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+    Error error;
+
+    NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+    if (process_sp)
+    {
+
+        // TODO: we might need to add a parameter to this function in case the byte
+        // order of the memory data doesn't match the process. For now we are assuming
+        // they are the same.
+        lldb::ByteOrder byte_order;
+        if (!process_sp->GetByteOrder (byte_order))
+            return Error ("NativeProcessProtocol::GetByteOrder () failed");
+
+        const lldb::addr_t bytes_copied = reg_value.GetAsMemoryData (
+            reg_info,
+            dst,
+            dst_len,
+            byte_order,
+            error);
+
+        if (error.Success())
+        {
+            if (bytes_copied == 0)
+            {
+                error.SetErrorString("byte copy failed.");
+            }
+            else
+            {
+                lldb::addr_t bytes_written;
+                error = process_sp->WriteMemory (dst_addr, dst, bytes_copied, bytes_written);
+                if (error.Fail ())
+                    return error;
+
+                if (bytes_written != bytes_copied)
+                {
+                    // This might happen if we read _some_ bytes but not all
+                    error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes", bytes_written, bytes_copied);
+                }
+            }
+        }
+    }
+    else
+        error.SetErrorString("invalid process");
+
+    return error;
+}
+
+uint32_t
+NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+    const uint32_t num_regs = GetRegisterCount();
+
+    assert (kind < kNumRegisterKinds);
+    for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+    {
+        const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+        if (reg_info->kinds[kind] == num)
+            return reg_idx;
+    }
+
+    return LLDB_INVALID_REGNUM;
+}
+
+

Added: lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp?rev=212069&view=auto
==============================================================================
--- lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp (added)
+++ lldb/trunk/source/Target/NativeRegisterContextRegisterInfo.cpp Mon Jun 30 16:05:18 2014
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContex.cpp --------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Target/NativeRegisterContextRegisterInfo.h"
+
+using namespace lldb_private;
+
+NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+                                                                      uint32_t concrete_frame_idx,
+                                                                      RegisterInfoInterface *register_info_interface) :
+    NativeRegisterContext (thread, concrete_frame_idx),
+    m_register_info_interface_up (register_info_interface)
+{
+    assert (register_info_interface && "null register_info_interface");
+}
+
+uint32_t
+NativeRegisterContextRegisterInfo::GetRegisterCount () const
+{
+    return m_register_info_interface_up->GetRegisterCount ();
+}
+
+const RegisterInfo *
+NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const
+{
+    if (reg_index <= GetRegisterCount ())
+        return m_register_info_interface_up->GetRegisterInfo () + reg_index;
+    else
+        return nullptr;
+}
+
+const RegisterInfoInterface&
+NativeRegisterContextRegisterInfo::GetRegisterInfoInterface () const
+{
+    return *m_register_info_interface_up;
+}

Modified: lldb/trunk/source/Target/Platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Platform.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Target/Platform.cpp (original)
+++ lldb/trunk/source/Target/Platform.cpp Mon Jun 30 16:05:18 2014
@@ -527,12 +527,10 @@ RecurseCopy_Callback (void *baton,
         case FileSpec::eFileTypeInvalid:
         case FileSpec::eFileTypeOther:
         case FileSpec::eFileTypeUnknown:
+        default:
             rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());
             return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
             break;
-        default:
-            return FileSpec::eEnumerateDirectoryResultQuit; // unsupported file type, bail out
-            break;
     }
 }
 
@@ -1189,6 +1187,27 @@ Platform::CalculateMD5 (const FileSpec&
         return false;
 }
 
+Error
+Platform::LaunchNativeProcess (
+    ProcessLaunchInfo &launch_info,
+    lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+    NativeProcessProtocolSP &process_sp)
+{
+    // Platforms should override this implementation if they want to
+    // support lldb-gdbserver.
+    return Error("unimplemented");
+}
+
+Error
+Platform::AttachNativeProcess (lldb::pid_t pid,
+                               lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+                               NativeProcessProtocolSP &process_sp)
+{
+    // Platforms should override this implementation if they want to
+    // support lldb-gdbserver.
+    return Error("unimplemented");
+}
+
 void
 Platform::SetLocalCacheDirectory (const char* local)
 {

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Mon Jun 30 16:05:18 2014
@@ -2529,6 +2529,7 @@ Process::CanJIT ()
 {
     if (m_can_jit == eCanJITDontKnow)
     {
+        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
         Error err;
         
         uint64_t allocated_memory = AllocateMemory(8, 
@@ -2536,9 +2537,17 @@ Process::CanJIT ()
                                                    err);
         
         if (err.Success())
+        {
             m_can_jit = eCanJITYes;
+            if (log)
+                log->Printf ("Process::%s pid %" PRIu64 " allocation test passed, CanJIT () is true", __FUNCTION__, GetID ());
+        }
         else
+        {
             m_can_jit = eCanJITNo;
+            if (log)
+                log->Printf ("Process::%s pid %" PRIu64 " allocation test failed, CanJIT () is false: %s", __FUNCTION__, GetID (), err.AsCString ());
+        }
         
         DeallocateMemory (allocated_memory);
     }
@@ -2788,6 +2797,12 @@ Process::GetDynamicLoader ()
     return m_dyld_ap.get();
 }
 
+const lldb::DataBufferSP
+Process::GetAuxvData()
+{
+    return DataBufferSP ();
+}
+
 JITLoaderList &
 Process::GetJITLoaders ()
 {

Modified: lldb/trunk/source/Utility/StringExtractor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractor.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractor.cpp (original)
+++ lldb/trunk/source/Utility/StringExtractor.cpp Mon Jun 30 16:05:18 2014
@@ -419,6 +419,18 @@ StringExtractor::GetHexByteString (std::
 }
 
 size_t
+StringExtractor::GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length)
+{
+    str.clear();
+
+    uint32_t nibble_count = 0;
+    for (const char *pch = Peek(); (nibble_count < nibble_length) && (pch != nullptr); str.append(1, GetHexU8(0, false)), pch = Peek (), nibble_count += 2)
+    {}
+
+    return str.size();
+}
+
+size_t
 StringExtractor::GetHexByteStringTerminatedBy (std::string &str,
                                                char terminator)
 {
@@ -428,6 +440,7 @@ StringExtractor::GetHexByteStringTermina
         str.append(1, ch);
     if (Peek() && *Peek() == terminator)
         return str.size();
+
     str.clear();
     return str.size();
 }

Modified: lldb/trunk/source/Utility/StringExtractor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractor.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractor.h (original)
+++ lldb/trunk/source/Utility/StringExtractor.h Mon Jun 30 16:05:18 2014
@@ -129,6 +129,9 @@ public:
     GetHexByteString (std::string &str);
 
     size_t
+    GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length);
+
+    size_t
     GetHexByteStringTerminatedBy (std::string &str,
                                   char terminator);
     

Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp Mon Jun 30 16:05:18 2014
@@ -179,6 +179,7 @@ StringExtractorGDBRemote::GetServerPacke
             if (PACKET_STARTS_WITH ("qSpeedTest:"))             return eServerPacketType_qSpeedTest;
             if (PACKET_MATCHES ("qShlibInfoAddr"))              return eServerPacketType_qShlibInfoAddr;
             if (PACKET_MATCHES ("qStepPacketSupported"))        return eServerPacketType_qStepPacketSupported;
+            if (PACKET_STARTS_WITH ("qSupported"))              return eServerPacketType_qSupported;
             if (PACKET_MATCHES ("qSyncThreadStateSupported"))   return eServerPacketType_qSyncThreadStateSupported;
             break;
 
@@ -199,6 +200,10 @@ StringExtractorGDBRemote::GetServerPacke
             if (PACKET_STARTS_WITH ("qWatchpointSupportInfo:")) return eServerPacketType_qWatchpointSupportInfo;
             if (PACKET_MATCHES ("qWatchpointSupportInfo"))      return eServerPacketType_qWatchpointSupportInfoSupported;
             break;
+
+        case 'X':
+            if (PACKET_STARTS_WITH ("qXfer:auxv:read::"))       return eServerPacketType_qXfer_auxv_read;
+            break;
         }
         break;
     case 'v':

Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.h?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.h (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.h Mon Jun 30 16:05:18 2014
@@ -106,12 +106,14 @@ public:
         eServerPacketType_qRegisterInfo,
         eServerPacketType_qShlibInfoAddr,
         eServerPacketType_qStepPacketSupported,
+        eServerPacketType_qSupported,
         eServerPacketType_qSyncThreadStateSupported,
         eServerPacketType_qThreadExtraInfo,
         eServerPacketType_qThreadStopInfo,
         eServerPacketType_qVAttachOrWaitSupported,
         eServerPacketType_qWatchpointSupportInfo,
         eServerPacketType_qWatchpointSupportInfoSupported,
+        eServerPacketType_qXfer_auxv_read,
 
         eServerPacketType_vAttach,
         eServerPacketType_vAttachWait,

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteAuxvSupport.py Mon Jun 30 16:05:18 2014
@@ -86,7 +86,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_supports_auxv_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -111,7 +110,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_auxv_data_is_correct_size_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -152,7 +150,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_auxv_keys_look_valid_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -200,7 +197,6 @@ class TestGdbRemoteAuxvSupport(gdbremote
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_auxv_chunked_reads_work_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteExpeditedRegisters.py Mon Jun 30 16:05:18 2014
@@ -62,7 +62,6 @@ class TestGdbRemoteExpeditedRegisters(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_stop_notification_contains_any_registers_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -87,7 +86,6 @@ class TestGdbRemoteExpeditedRegisters(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_stop_notification_contains_no_duplicate_registers_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -107,7 +105,6 @@ class TestGdbRemoteExpeditedRegisters(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_stop_notification_contains_pc_register_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -127,7 +124,6 @@ class TestGdbRemoteExpeditedRegisters(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_stop_notification_contains_fp_register_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -147,7 +143,6 @@ class TestGdbRemoteExpeditedRegisters(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_stop_notification_contains_sp_register_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteRegisterState.py Mon Jun 30 16:05:18 2014
@@ -100,7 +100,6 @@ class TestGdbRemoteRegisterState(gdbremo
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_grp_register_save_restore_works_with_suffix_llgs_dwarf(self):
         USE_THREAD_SUFFIX = True
         self.init_llgs_test()
@@ -119,7 +118,6 @@ class TestGdbRemoteRegisterState(gdbremo
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_grp_register_save_restore_works_no_suffix_llgs_dwarf(self):
         USE_THREAD_SUFFIX = False
         self.init_llgs_test()

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteSingleStep.py Mon Jun 30 16:05:18 2014
@@ -15,7 +15,6 @@ class TestGdbRemoteSingleStep(gdbremote_
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_single_step_only_steps_one_instruction_with_s_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemoteThreadsInStopReply.py Mon Jun 30 16:05:18 2014
@@ -83,7 +83,6 @@ class TestGdbRemoteThreadsInStopReply(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_QListThreadsInStopReply_supported_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -105,7 +104,6 @@ class TestGdbRemoteThreadsInStopReply(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_stop_reply_reports_multiple_threads_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -127,8 +125,7 @@ class TestGdbRemoteThreadsInStopReply(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
-    def test_no_QThreadsInStopReply_supplies_no_threads_llgs_dwarf(self):
+    def test_no_QListThreadsInStopReply_supplies_no_threads_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
         self.set_inferior_startup_launch()
@@ -164,7 +161,6 @@ class TestGdbRemoteThreadsInStopReply(gd
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_stop_reply_reports_correct_threads_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestGdbRemote_vCont.py Mon Jun 30 16:05:18 2014
@@ -41,8 +41,6 @@ class TestGdbRemote_vCont(gdbremote_test
         self.vCont_supports_c()
 
     @llgs_test
-    @dwarf_test
-    @unittest2.expectedFailure()
     def test_vCont_supports_c_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -57,7 +55,6 @@ class TestGdbRemote_vCont(gdbremote_test
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_vCont_supports_C_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -72,7 +69,6 @@ class TestGdbRemote_vCont(gdbremote_test
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_vCont_supports_s_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -87,7 +83,6 @@ class TestGdbRemote_vCont(gdbremote_test
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_vCont_supports_S_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -103,7 +98,6 @@ class TestGdbRemote_vCont(gdbremote_test
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_single_step_only_steps_one_instruction_with_Hc_vCont_s_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -120,7 +114,6 @@ class TestGdbRemote_vCont(gdbremote_test
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_single_step_only_steps_one_instruction_with_vCont_s_thread_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -128,7 +121,5 @@ class TestGdbRemote_vCont(gdbremote_test
         self.single_step_only_steps_one_instruction(use_Hc_packet=False, step_instruction="vCont;s:{thread}")
 
 
-
-
 if __name__ == '__main__':
     unittest2.main()

Modified: lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Mon Jun 30 16:05:18 2014
@@ -63,7 +63,6 @@ class LldbGdbServerTestCase(gdbremote_te
         self.thread_suffix_supported()
 
     @llgs_test
-    @unittest2.expectedFailure()
     def test_thread_suffix_supported_llgs(self):
         self.init_llgs_test()
         self.thread_suffix_supported()
@@ -85,7 +84,6 @@ class LldbGdbServerTestCase(gdbremote_te
         self.list_threads_in_stop_reply_supported()
 
     @llgs_test
-    @unittest2.expectedFailure()
     def test_list_threads_in_stop_reply_supported_llgs(self):
         self.init_llgs_test()
         self.list_threads_in_stop_reply_supported()
@@ -143,7 +141,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_inferior_exit_0_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -176,7 +173,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_inferior_exit_42_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -207,7 +203,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_c_packet_works_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -240,7 +235,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_inferior_print_exit_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -272,7 +266,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_first_launch_stop_reply_thread_matches_first_qC_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -308,7 +301,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qProcessInfo_returns_running_process_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -343,7 +335,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_attach_commandline_qProcessInfo_reports_correct_pid_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -376,7 +367,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qProcessInfo_reports_valid_endian_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -410,7 +400,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_attach_commandline_continue_app_exits_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -445,7 +434,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_attach_commandline_kill_after_initial_stop_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -484,7 +472,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qRegisterInfo_returns_one_valid_result_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -519,7 +506,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qRegisterInfo_returns_all_valid_results_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -568,7 +554,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qRegisterInfo_contains_required_generics_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -606,7 +591,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qRegisterInfo_contains_at_least_one_register_set_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -635,10 +619,8 @@ class LldbGdbServerTestCase(gdbremote_te
         register_sets = { reg_info['set']:1 for reg_info in reg_infos if 'set' in reg_info }
         self.assertTrue("Advanced Vector Extensions" in register_sets)
 
-
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qRegisterInfo_contains_avx_registers_on_linux_x86_64_llgs_dwarf(self):
         # Skip this test if not Linux x86_64.
         if platform.system() != "Linux" or platform.processor() != "x86_64":
@@ -673,7 +655,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qThreadInfo_contains_thread_launch_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -690,7 +671,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qThreadInfo_contains_thread_attach_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -735,7 +715,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qThreadInfo_matches_qC_launch_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -752,7 +731,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qThreadInfo_matches_qC_attach_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -810,7 +788,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_p_returns_correct_data_size_for_each_qRegisterInfo_launch_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -827,7 +804,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_p_returns_correct_data_size_for_each_qRegisterInfo_attach_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -873,7 +849,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_Hg_switches_to_3_threads_launch_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -890,7 +865,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_Hg_switches_to_3_threads_attach_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1010,7 +984,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_Hc_then_Csignal_signals_correct_thread_launch_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1073,7 +1046,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_m_packet_reads_memory_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1101,7 +1073,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qMemoryRegionInfo_is_supported_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1165,7 +1136,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qMemoryRegionInfo_reports_code_address_as_executable_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1229,7 +1199,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qMemoryRegionInfo_reports_stack_address_as_readable_writeable_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1294,7 +1263,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qMemoryRegionInfo_reports_heap_address_as_readable_writeable_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1411,7 +1379,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_software_breakpoint_set_and_remove_work_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1442,7 +1409,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_qSupported_returns_known_stub_features_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1503,7 +1469,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_written_M_content_reads_back_correctly_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1550,7 +1515,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_P_writes_all_gpr_registers_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()
@@ -1659,7 +1623,6 @@ class LldbGdbServerTestCase(gdbremote_te
 
     @llgs_test
     @dwarf_test
-    @unittest2.expectedFailure()
     def test_P_and_p_thread_suffix_work_llgs_dwarf(self):
         self.init_llgs_test()
         self.buildDwarf()

Modified: lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/gdbremote_testcase.py Mon Jun 30 16:05:18 2014
@@ -1024,3 +1024,4 @@ class GdbRemoteTestCaseBase(TestBase):
         (state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5, use_Hc_packet=use_Hc_packet, step_instruction=step_instruction)
         self.assertTrue(state_reached)
         self.assertEquals(step_count, 1)
+

Modified: lldb/trunk/test/tools/lldb-gdbserver/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/main.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/main.cpp (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/main.cpp Mon Jun 30 16:05:18 2014
@@ -92,9 +92,12 @@ signal_handler (int signo)
 	switch (signo)
 	{
         case SIGSEGV:
-            // Fix up the pointer we're writing to.  This needs to happen if nothing intercepts the SIGSEGV
-            // (i.e. if somebody runs this from the command line).
-            longjmp(g_jump_buffer, 1);
+	        if (g_is_segfaulting)
+	        {
+	            // Fix up the pointer we're writing to.  This needs to happen if nothing intercepts the SIGSEGV
+	            // (i.e. if somebody runs this from the command line).
+	            longjmp(g_jump_buffer, 1);
+			}
             break;
         case SIGUSR1:
             if (g_is_segfaulting)

Modified: lldb/trunk/tools/debugserver/source/RNBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/RNBRemote.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/RNBRemote.cpp (original)
+++ lldb/trunk/tools/debugserver/source/RNBRemote.cpp Mon Jun 30 16:05:18 2014
@@ -2326,6 +2326,7 @@ RNBRemote::SendStopReplyPacketForThread
         {
             size_t thread_name_len = strlen(thread_name);
             
+
             if (::strcspn (thread_name, "$#+-;:") == thread_name_len)
                 ostrm << std::hex << "name:" << thread_name << ';';
             else

Modified: lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp (original)
+++ lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp Mon Jun 30 16:05:18 2014
@@ -52,6 +52,7 @@ static struct option g_long_options[] =
     { "lldb-command",       required_argument,  NULL,               'c' },
     { "log-file",           required_argument,  NULL,               'l' },
     { "log-flags",          required_argument,  NULL,               'f' },
+    { "attach",             required_argument,  NULL,               'a' },
     { NULL,                 0,                  NULL,               0   }
 };
 
@@ -59,21 +60,38 @@ static struct option g_long_options[] =
 //----------------------------------------------------------------------
 // Watch for signals
 //----------------------------------------------------------------------
-int g_sigpipe_received = 0;
+static int g_sigpipe_received = 0;
+static int g_sighup_received_count = 0;
+
 void
 signal_handler(int signo)
 {
+    Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+    fprintf (stderr, "lldb-gdbserver:%s received signal %d\n", __FUNCTION__, signo);
+    if (log)
+        log->Printf ("lldb-gdbserver:%s received signal %d", __FUNCTION__, signo);
+
     switch (signo)
     {
     case SIGPIPE:
         g_sigpipe_received = 1;
         break;
     case SIGHUP:
+#if 1
+        ++g_sighup_received_count;
+
+        // For now, swallow SIGHUP.
+        if (log)
+            log->Printf ("lldb-gdbserver:%s swallowing SIGHUP (receive count=%d)", __FUNCTION__, g_sighup_received_count);
+        signal (SIGHUP, signal_handler);
+#else
         // Use SIGINT first, if that does not work, use SIGHUP as a last resort.
         // And we should not call exit() here because it results in the global destructors
         // to be invoked and wreaking havoc on the threads still running.
         Host::SystemLog(Host::eSystemLogWarning, "SIGHUP received, exiting lldb-gdbserver...\n");
         abort();
+#endif
         break;
     }
 }
@@ -124,21 +142,221 @@ terminate_lldb_gdbserver ()
     PluginManager::Terminate ();
 }
 
+static void
+run_lldb_commands (const lldb::DebuggerSP &debugger_sp, const std::vector<std::string> lldb_commands)
+{
+    for (const auto &lldb_command : lldb_commands)
+    {
+        printf("(lldb) %s\n", lldb_command.c_str ());
+
+        lldb_private::CommandReturnObject result;
+        debugger_sp->GetCommandInterpreter ().HandleCommand (lldb_command.c_str (), eLazyBoolNo, result);
+        const char *output = result.GetOutputData ();
+        if (output && output[0])
+            puts (output);
+    }
+}
+
+static lldb::PlatformSP
+setup_platform (const std::string platform_name)
+{
+    lldb::PlatformSP platform_sp;
+
+    if (platform_name.empty())
+    {
+        printf ("using the default platform: ");
+        platform_sp = Platform::GetDefaultPlatform ();
+        printf ("%s\n", platform_sp->GetPluginName ().AsCString ());
+        return platform_sp;
+    }
+
+    Error error;
+    platform_sp = Platform::Create (platform_name.c_str(), error);
+    if (error.Fail ())
+    {
+        // the host platform isn't registered with that name (at
+        // least, not always.  Check if the given name matches
+        // the default platform name.  If so, use it.
+        if ( Platform::GetDefaultPlatform () && ( Platform::GetDefaultPlatform ()->GetPluginName () == ConstString (platform_name.c_str()) ) )
+        {
+            platform_sp = Platform::GetDefaultPlatform ();
+        }
+        else
+        {
+            fprintf (stderr, "error: failed to create platform with name '%s'\n", platform_name.c_str());
+            dump_available_platforms (stderr);
+            exit (1);
+        }
+    }
+    printf ("using platform: %s\n", platform_name.c_str ());
+
+    return platform_sp;
+}
+
+void
+handle_attach_to_pid (GDBRemoteCommunicationServer &gdb_server, lldb::pid_t pid)
+{
+    Error error = gdb_server.AttachToProcess (pid);
+    if (error.Fail ())
+    {
+        fprintf (stderr, "error: failed to attach to pid %" PRIu64 ": %s\n", pid, error.AsCString());
+        exit(1);
+    }
+}
+
+void
+handle_attach_to_process_name (GDBRemoteCommunicationServer &gdb_server, const std::string &process_name)
+{
+    // FIXME implement.
+}
+
+void
+handle_attach (GDBRemoteCommunicationServer &gdb_server, const std::string &attach_target)
+{
+    assert (!attach_target.empty () && "attach_target cannot be empty");
+
+    // First check if the attach_target is convertable to a long. If so, we'll use it as a pid.
+    char *end_p = nullptr;
+    const long int pid = strtol (attach_target.c_str (), &end_p, 10);
+
+    // We'll call it a match if the entire argument is consumed.
+    if (end_p && static_cast<size_t> (end_p - attach_target.c_str ()) == attach_target.size ())
+        handle_attach_to_pid (gdb_server, static_cast<lldb::pid_t> (pid));
+    else
+        handle_attach_to_process_name (gdb_server, attach_target);
+}
+
+void
+handle_launch (GDBRemoteCommunicationServer &gdb_server, int argc, const char *const argv[])
+{
+    Error error;
+    error = gdb_server.SetLaunchArguments (argv, argc);
+    if (error.Fail ())
+    {
+        fprintf (stderr, "error: failed to set launch args for '%s': %s\n", argv[0], error.AsCString());
+        exit(1);
+    }
+
+    unsigned int launch_flags = eLaunchFlagStopAtEntry | eLaunchFlagDebug;
+
+    error = gdb_server.SetLaunchFlags (launch_flags);
+    if (error.Fail ())
+    {
+        fprintf (stderr, "error: failed to set launch flags for '%s': %s\n", argv[0], error.AsCString());
+        exit(1);
+    }
+
+    error = gdb_server.LaunchProcess ();
+    if (error.Fail ())
+    {
+        fprintf (stderr, "error: failed to launch '%s': %s\n", argv[0], error.AsCString());
+        exit(1);
+    }
+}
+
+void
+start_listener (GDBRemoteCommunicationServer &gdb_server, const char *const host_and_port, const char *const progname)
+{
+    Error error;
+
+    if (host_and_port && host_and_port[0])
+    {
+        std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+        if (conn_ap.get())
+        {
+            std::string final_host_and_port;
+            std::string listening_host;
+            std::string listening_port;
+
+            // If host_and_port starts with ':', default the host to be "localhost" and expect the remainder to be the port.
+            if (host_and_port[0] == ':')
+                final_host_and_port.append ("localhost");
+            final_host_and_port.append (host_and_port);
+
+            const std::string::size_type colon_pos = final_host_and_port.find(':');
+            if (colon_pos != std::string::npos)
+            {
+                listening_host = final_host_and_port.substr(0, colon_pos);
+                listening_port = final_host_and_port.substr(colon_pos + 1);
+            }
+
+            std::string connect_url ("listen://");
+            connect_url.append (final_host_and_port);
+
+            printf ("Listening to port %s for a connection from %s...\n", listening_port.c_str (), listening_host.c_str ());
+            if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+            {
+                printf ("Connection established.\n");
+                gdb_server.SetConnection (conn_ap.release());
+            }
+            else
+            {
+                fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ());
+                display_usage (progname);
+                exit (1);
+            }
+        }
+
+        if (gdb_server.IsConnected())
+        {
+            // After we connected, we need to get an initial ack from...
+            if (gdb_server.HandshakeWithClient(&error))
+            {
+                // We'll use a half a second timeout interval so that an exit conditions can
+                // be checked that often.
+                const uint32_t TIMEOUT_USEC = 500000;
+
+                bool interrupt = false;
+                bool done = false;
+                while (!interrupt && !done && (g_sighup_received_count < 1))
+                {
+                    const GDBRemoteCommunication::PacketResult result = gdb_server.GetPacketAndSendResponse (TIMEOUT_USEC, error, interrupt, done);
+                    if ((result != GDBRemoteCommunication::PacketResult::Success) &&
+                        (result != GDBRemoteCommunication::PacketResult::ErrorReplyTimeout))
+                    {
+                        // We're bailing out - we only support successful handling and timeouts.
+                        fprintf(stderr, "leaving packet loop due to PacketResult %d\n", result);
+                        break;
+                    }
+                }
+
+                if (error.Fail())
+                {
+                    fprintf(stderr, "error: %s\n", error.AsCString());
+                }
+            }
+            else
+            {
+                fprintf(stderr, "error: handshake with client failed\n");
+            }
+        }
+    }
+    else
+    {
+        fprintf (stderr, "no connection information provided, unable to run\n");
+        display_usage (progname);
+        exit (1);
+    }
+}
+
 //----------------------------------------------------------------------
 // main
 //----------------------------------------------------------------------
 int
 main (int argc, char *argv[])
 {
-    const char *progname = argv[0];
+    // Setup signal handlers first thing.
     signal (SIGPIPE, signal_handler);
     signal (SIGHUP, signal_handler);
+
+    const char *progname = argv[0];
     int long_option_index = 0;
     StreamSP log_stream_sp;
     Args log_args;
     Error error;
     int ch;
     std::string platform_name;
+    std::string attach_target;
 
     initialize_lldb_gdbserver ();
 
@@ -215,6 +433,11 @@ main (int argc, char *argv[])
                 platform_name = optarg;
             break;
 
+        case 'a': // attach {pid|process_name}
+            if (optarg && optarg[0])
+                attach_target = optarg;
+                break;
+
         case 'h':   /* fall-through is intentional */
         case '?':
             show_usage = true;
@@ -235,7 +458,7 @@ main (int argc, char *argv[])
         ProcessGDBRemoteLog::EnableLog (log_stream_sp, 0,log_args.GetConstArgumentVector(), log_stream_sp.get());
     }
 
-    // Skip any options we consumed with getopt_long_only
+    // Skip any options we consumed with getopt_long_only.
     argc -= optind;
     argv += optind;
 
@@ -245,155 +468,29 @@ main (int argc, char *argv[])
         exit(255);
     }
 
-    // Run any commands requested
-    for (const auto &lldb_command : lldb_commands)
-    {
-        printf("(lldb) %s\n", lldb_command.c_str ());
-
-        lldb_private::CommandReturnObject result;
-        debugger_sp->GetCommandInterpreter ().HandleCommand (lldb_command.c_str (), eLazyBoolNo, result);
-        const char *output = result.GetOutputData ();
-        if (output && output[0])
-            puts (output);
-    }
+    // Run any commands requested.
+    run_lldb_commands (debugger_sp, lldb_commands);
 
-    // setup the platform that GDBRemoteCommunicationServer will use
-    lldb::PlatformSP platform_sp;
-    if (platform_name.empty())
-    {
-        printf ("using the default platform: ");
-        platform_sp = Platform::GetDefaultPlatform ();
-        printf ("%s\n", platform_sp->GetPluginName ().AsCString ());
-    }
-    else
-    {
-        Error error;
-        platform_sp = Platform::Create (platform_name.c_str(), error);
-        if (error.Fail ())
-        {
-            // the host platform isn't registered with that name (at
-            // least, not always.  Check if the given name matches
-            // the default platform name.  If so, use it.
-            if ( Platform::GetDefaultPlatform () && ( Platform::GetDefaultPlatform ()->GetPluginName () == ConstString (platform_name.c_str()) ) )
-            {
-                platform_sp = Platform::GetDefaultPlatform ();
-            }
-            else
-            {
-                fprintf (stderr, "error: failed to create platform with name '%s'\n", platform_name.c_str());
-                dump_available_platforms (stderr);
-                exit (1);
-            }
-        }
-        printf ("using platform: %s\n", platform_name.c_str ());
-    }
+    // Setup the platform that GDBRemoteCommunicationServer will use.
+    lldb::PlatformSP platform_sp = setup_platform (platform_name);
 
     const bool is_platform = false;
-    GDBRemoteCommunicationServer gdb_server (is_platform, platform_sp);
+    GDBRemoteCommunicationServer gdb_server (is_platform, platform_sp, debugger_sp);
 
-    const char *host_and_port = argv[0];
+    const char *const host_and_port = argv[0];
     argc -= 1;
     argv += 1;
+
     // Any arguments left over are for the the program that we need to launch. If there
     // are no arguments, then the GDB server will start up and wait for an 'A' packet
-    // to launch a program, or a vAttach packet to attach to an existing process.
-    if (argc > 0)
-    {
-        error = gdb_server.SetLaunchArguments (argv, argc);
-        if (error.Fail ())
-        {
-            fprintf (stderr, "error: failed to set launch args for '%s': %s\n", argv[0], error.AsCString());
-            exit(1);
-        }
-
-        unsigned int launch_flags = eLaunchFlagStopAtEntry;
-#if !defined(__linux__)
-        // linux doesn't yet handle eLaunchFlagDebug
-        launch_flags |= eLaunchFlagDebug;
-#endif
-        error = gdb_server.SetLaunchFlags (launch_flags);
-        if (error.Fail ())
-        {
-            fprintf (stderr, "error: failed to set launch flags for '%s': %s\n", argv[0], error.AsCString());
-            exit(1);
-        }
-
-        error = gdb_server.LaunchProcess ();
-        if (error.Fail ())
-        {
-            fprintf (stderr, "error: failed to launch '%s': %s\n", argv[0], error.AsCString());
-            exit(1);
-        }
-    }
-
-    if (host_and_port && host_and_port[0])
-    {
-        std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
-        if (conn_ap.get())
-        {
-            std::string final_host_and_port;
-            std::string listening_host;
-            std::string listening_port;
-
-            // If host_and_port starts with ':', default the host to be "localhost" and expect the remainder to be the port.
-            if (host_and_port[0] == ':')
-                final_host_and_port.append ("localhost");
-            final_host_and_port.append (host_and_port);
-
-            const std::string::size_type colon_pos = final_host_and_port.find(':');
-            if (colon_pos != std::string::npos)
-            {
-                listening_host = final_host_and_port.substr(0, colon_pos);
-                listening_port = final_host_and_port.substr(colon_pos + 1);
-            }
-
-            std::string connect_url ("listen://");
-            connect_url.append (final_host_and_port);
-
-            printf ("Listening to port %s for a connection from %s...\n", listening_port.c_str (), listening_host.c_str ());
-            if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
-            {
-                printf ("Connection established.\n");
-                gdb_server.SetConnection (conn_ap.release());
-            }
-            else
-            {
-                fprintf (stderr, "failed to connect to '%s': %s\n", final_host_and_port.c_str (), error.AsCString ());
-                display_usage (progname);
-                exit (1);
-            }
-        }
-
-        if (gdb_server.IsConnected())
-        {
-            // After we connected, we need to get an initial ack from...
-            if (gdb_server.HandshakeWithClient(&error))
-            {
-                bool interrupt = false;
-                bool done = false;
-                while (!interrupt && !done)
-                {
-                    if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
-                        break;
-                }
+    // to launch a program, or a vAttach packet to attach to an existing process, unless
+    // explicitly asked to attach with the --attach={pid|program_name} form.
+    if (!attach_target.empty ())
+        handle_attach (gdb_server, attach_target);
+    else if (argc > 0)
+        handle_launch (gdb_server, argc, argv);
 
-                if (error.Fail())
-                {
-                    fprintf(stderr, "error: %s\n", error.AsCString());
-                }
-            }
-            else
-            {
-                fprintf(stderr, "error: handshake with client failed\n");
-            }
-        }
-    }
-    else
-    {
-        fprintf (stderr, "no connection information provided, unable to run\n");
-        display_usage (progname);
-        exit (1);
-    }
+    start_listener (gdb_server, host_and_port, progname);
 
     terminate_lldb_gdbserver ();
 

Modified: lldb/trunk/tools/lldb-platform/lldb-platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-platform/lldb-platform.cpp?rev=212069&r1=212068&r2=212069&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-platform/lldb-platform.cpp (original)
+++ lldb/trunk/tools/lldb-platform/lldb-platform.cpp Mon Jun 30 16:05:18 2014
@@ -286,7 +286,7 @@ main (int argc, char *argv[])
                     bool done = false;
                     while (!interrupt && !done)
                     {
-                        if (!gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done))
+                        if (gdb_server.GetPacketAndSendResponse (UINT32_MAX, error, interrupt, done) != GDBRemoteCommunication::PacketResult::Success)
                             break;
                     }
                     





More information about the lldb-commits mailing list