Modified the LocateMacOSXFilesUsingDebugSymbols(...) function to locate
an executable file if it is right next to a dSYM file that is found using
DebugSymbols. The code also looks into a bundle if the dSYM file is right
next to a bundle.

Modified the MacOSX kernel dynamic loader plug-in to correctly set the load
address for kext sections. This is a tad tricky because of how LLDB chooses
to treat mach-o segments with no name. Also modified the loader to properly
handle the older version 1 kext summary info.

Fixed a crasher in the Mach-o object file parser when it is trying to set
the section size correctly for dSYM sections.

Added packet dumpers to the CommunicationKDP class. We now also properly 
detect address byte sizes based on the cpu type and subtype that is provided.
Added a read memory and read register support to CommunicationKDP. Added a
ThreadKDP class that now uses subclasses of the RegisterContextDarwin_XXX for
arm, i386 and x86_64. 

Fixed some register numbering issues in the RegisterContextDarwin_arm class
and added ARM GDB numbers to the ARM_GCC_Registers.h file.

Change the RegisterContextMach_XXX classes over to subclassing their
RegisterContextDarwin_XXX counterparts so we can share the mach register 
contexts between the user and kernel plug-ins.




git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@135466 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp
index 2d9522b..f84eec3 100644
--- a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp
+++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp
@@ -15,10 +15,13 @@
 #include <string.h>
 
 // C++ Includes
+#include "llvm/Support/MachO.h"
+
 // Other libraries and framework includes
 #include "lldb/Core/DataBufferHeap.h"
 #include "lldb/Core/DataExtractor.h"
 #include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
 #include "lldb/Host/FileSpec.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/TimeValue.h"
@@ -37,6 +40,7 @@
 //----------------------------------------------------------------------
 CommunicationKDP::CommunicationKDP (const char *comm_name) :
     Communication(comm_name),
+    m_addr_byte_size (4),
     m_byte_order (eByteOrderLittle),
     m_packet_timeout (1),
     m_sequence_mutex (Mutex::eMutexTypeRecursive),
@@ -129,13 +133,9 @@
         LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
         if (log)
         {
-            PacketStreamType log_strm;
-            
-            DataExtractor::DumpHexBytes (&log_strm, packet_data, packet_size, UINT32_MAX, LLDB_INVALID_ADDRESS);
-            
-            log->Printf("send kdp-packet: %.*s", 
-                        (uint32_t)log_strm.GetSize(), 
-                        log_strm.GetData());
+            PacketStreamType log_strm;            
+            DumpPacket (log_strm, packet_data, packet_size);
+            log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
         }
         ConnectionStatus status = eConnectionStatusSuccess;
 
@@ -298,18 +298,9 @@
                     if (log)
                     {
                         PacketStreamType log_strm;
-                        packet.Dump (&log_strm,             // Stream to dump to
-                                     0,                     // Offset into "packet"
-                                     eFormatBytes,          // Dump as hex bytes
-                                     1,                     // Size of each item is 1 for single bytes
-                                     length,                // Number of bytes
-                                     UINT32_MAX,            // Num bytes per line
-                                     LLDB_INVALID_ADDRESS,  // Base address
-                                     0, 0);                 // Bitfield info set to not do anything bitfield related
+                        DumpPacket (log_strm, packet);
                         
-                        log->Printf("recv kdp-packet: %.*s", 
-                                    (uint32_t)log_strm.GetSize(), 
-                                    log_strm.GetData());
+                        log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
                     }
                     return true;
                 }
@@ -336,7 +327,7 @@
                                       uint16_t exc_port, 
                                       const char *greeting)
 {
-    PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
+    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
     if (greeting == NULL)
         greeting = "";
 
@@ -369,7 +360,7 @@
 bool
 CommunicationKDP::SendRequestReattach (uint16_t reply_port)
 {
-    PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
+    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
     const CommandType command = eCommandTypeReattach;
     // Length is 8 bytes for the header plus 2 bytes for the reply UDP port
     const uint32_t command_length = 8 + 2;
@@ -410,7 +401,7 @@
 bool
 CommunicationKDP::SendRequestVersion ()
 {
-    PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
+    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
     const CommandType command = eCommandTypeVersion;
     const uint32_t command_length = 8;
     const uint32_t request_sequence_id = m_request_sequence_id;
@@ -454,7 +445,7 @@
 bool
 CommunicationKDP::SendRequestHostInfo ()
 {
-    PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
+    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
     const CommandType command = eCommandTypeHostInfo;
     const uint32_t command_length = 8;
     const uint32_t request_sequence_id = m_request_sequence_id;
@@ -464,9 +455,17 @@
     {
         // Reset the sequence ID to zero for reattach
         uint32_t offset = 8;
-        m_kdp_hostinfo_cpu_mask = reply_packet.GetU32 (&offset);
-        m_kdp_hostinfo_cpu_type = reply_packet.GetU32 (&offset);
-        m_kdp_hostinfo_cpu_subtype = reply_packet.GetU32 (&offset);
+        m_kdp_hostinfo_cpu_mask     = reply_packet.GetU32 (&offset);
+        m_kdp_hostinfo_cpu_type     = reply_packet.GetU32 (&offset);
+        m_kdp_hostinfo_cpu_subtype  = reply_packet.GetU32 (&offset);
+        
+        ArchSpec kernel_arch;
+        kernel_arch.SetArchitecture (eArchTypeMachO, 
+                                     m_kdp_hostinfo_cpu_type, 
+                                     m_kdp_hostinfo_cpu_subtype);
+    
+        m_addr_byte_size = kernel_arch.GetAddressByteSize();
+        m_byte_order = kernel_arch.GetByteOrder();
         return true;
     }
     return false;
@@ -475,7 +474,7 @@
 bool
 CommunicationKDP::SendRequestDisconnect ()
 {
-    PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
+    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
     const CommandType command = eCommandTypeDisconnect;
     const uint32_t command_length = 8;
     const uint32_t request_sequence_id = m_request_sequence_id;
@@ -489,3 +488,331 @@
     return true;
 }
 
+uint32_t
+CommunicationKDP::SendRequestReadMemory (lldb::addr_t addr, 
+                                         void *dst, 
+                                         uint32_t dst_len,
+                                         Error &error)
+{
+    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+    bool use_64 = (GetVersion() >= 11);
+    uint32_t command_addr_byte_size = use_64 ? 8 : 4;
+    const CommandType command = use_64 ? eCommandTypeReadMemory64 : eCommandTypeReadMemory;
+    // Size is header + address size + uint32_t length
+    const uint32_t command_length = 8 + command_addr_byte_size + 4;
+    const uint32_t request_sequence_id = m_request_sequence_id;
+    MakeRequestPacketHeader (command, request_packet, command_length);
+    request_packet.PutMaxHex64 (addr, command_addr_byte_size);
+    request_packet.PutHex32 (dst_len);
+    DataExtractor reply_packet;
+    if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
+    {
+        // Reset the sequence ID to zero for reattach
+        uint32_t offset = 8;
+        uint32_t kdp_error = reply_packet.GetU32 (&offset);
+        uint32_t src_len = reply_packet.GetByteSize() - 12;
+        
+        if (src_len > 0)
+        {
+            const void *src = reply_packet.GetData(&offset, src_len);
+            if (src)
+            {
+                ::memcpy (dst, src, src_len);
+                error.Clear();
+                return src_len;
+            }
+        }
+        if (kdp_error)
+            error.SetErrorStringWithFormat ("kdp read memory failed (error %u)", kdp_error);
+        else
+            error.SetErrorString ("kdp read memory failed");
+    }
+    return 0;
+}
+
+const char *
+CommunicationKDP::GetCommandAsCString (uint8_t command)
+{
+    switch (command)
+    {
+    case eCommandTypeConnect:               return "KDP_CONNECT";
+    case eCommandTypeDisconnect:            return "KDP_DISCONNECT";
+    case eCommandTypeHostInfo:              return "KDP_HOSTINFO";
+    case eCommandTypeVersion:               return "KDP_VERSION";
+    case eCommandTypeMaxBytes:              return "KDP_MAXBYTES";
+    case eCommandTypeReadMemory:            return "KDP_READMEM";
+    case eCommandTypeWriteMemory:           return "KDP_WRITEMEM";
+    case eCommandTypeReadRegisters:         return "KDP_READREGS";
+    case eCommandTypeWriteRegisters:        return "KDP_WRITEREGS";
+    case eCommandTypeLoad:                  return "KDP_LOAD";
+    case eCommandTypeImagePath:             return "KDP_IMAGEPATH";
+    case eCommandTypeSuspend:               return "KDP_SUSPEND";
+    case eCommandTypeResume:                return "KDP_RESUMECPUS";
+    case eCommandTypeException:             return "KDP_EXCEPTION";
+    case eCommandTypeTermination:           return "KDP_TERMINATION";
+    case eCommandTypeBreakpointSet:         return "KDP_BREAKPOINT_SET";
+    case eCommandTypeBreakpointRemove:      return "KDP_BREAKPOINT_REMOVE";
+    case eCommandTypeRegions:               return "KDP_REGIONS";
+    case eCommandTypeReattach:              return "KDP_REATTACH";
+    case eCommandTypeHostReboot:            return "KDP_HOSTREBOOT";
+    case eCommandTypeReadMemory64:          return "KDP_READMEM64";
+    case eCommandTypeWriteMemory64:         return "KDP_WRITEMEM64";
+    case eCommandTypeBreakpointSet64:       return "KDP_BREAKPOINT64_SET";
+    case eCommandTypeBreakpointRemove64:    return "KDP_BREAKPOINT64_REMOVE";
+    case eCommandTypeKernelVersion:         return "KDP_KERNELVERSION";
+    }
+    return NULL;
+}
+
+void
+CommunicationKDP::DumpPacket (Stream &s, const void *data, uint32_t data_len)
+{
+    DataExtractor extractor (data, data_len, m_byte_order, m_addr_byte_size);
+    DumpPacket (s, extractor);
+}
+
+void
+CommunicationKDP::DumpPacket (Stream &s, const DataExtractor& packet)
+{
+    const char *error_desc = NULL;
+    if (packet.GetByteSize() < 8)
+    {
+        error_desc = "error: invalid packet (too short): ";
+    }
+    else
+    {
+        uint32_t offset = 0;
+        const uint8_t first_packet_byte = packet.GetU8 (&offset);
+        const uint8_t sequence_id = packet.GetU8 (&offset);
+        const uint16_t length = packet.GetU16 (&offset);
+        const uint32_t key = packet.GetU32 (&offset);
+        const CommandType command = ExtractCommand (first_packet_byte);
+        const char *command_name = GetCommandAsCString (command);
+        if (command_name)
+        {
+            const bool is_reply = ExtractIsReply(first_packet_byte);
+            s.Printf ("%s {%u:%u} <0x%4.4x> %s", 
+                      is_reply ? "<--" : "-->", 
+                      key,
+                      sequence_id,
+                      length,
+                      command_name);
+            
+            if (is_reply)
+            {
+                // Dump request reply packets
+                switch (command)
+                {
+                    case eCommandTypeConnect:
+                        {
+                            const uint32_t error = packet.GetU32 (&offset);
+                            s.Printf(" (error=0x%8.8x)", error);
+                        }
+                        break;
+                    
+                    case eCommandTypeDisconnect:
+                    case eCommandTypeReattach:
+                    case eCommandTypeHostReboot:
+                        // No return value for the reply, just the header to ack
+                        break;
+
+                    case eCommandTypeHostInfo:
+                        {
+                            const uint32_t cpu_mask = packet.GetU32 (&offset);
+                            const uint32_t cpu_type = packet.GetU32 (&offset);
+                            const uint32_t cpu_subtype = packet.GetU32 (&offset);
+                            s.Printf(" (cpu_mask=0x%8.8x, cpu_type=0x%8.8x, cpu_subtype=0x%8.8x)", cpu_mask, cpu_type, cpu_subtype);
+                        }
+                        break;
+                        
+                    case eCommandTypeVersion:
+                        {
+                            const uint32_t version = packet.GetU32 (&offset);
+                            const uint32_t feature = packet.GetU32 (&offset);
+                            s.Printf(" (version=0x%8.8x, feature=0x%8.8x)", version, feature);
+                        }
+                        break;
+                        
+                    case eCommandTypeRegions:
+                        {
+                            const uint32_t region_count = packet.GetU32 (&offset);
+                            s.Printf(" (count = %u", region_count); 
+                            for (uint32_t i=0; i<region_count; ++i)
+                            {
+                                const addr_t region_addr = packet.GetPointer (&offset);
+                                const uint32_t region_size = packet.GetU32 (&offset);
+                                const uint32_t region_prot = packet.GetU32 (&offset);
+                                s.Printf("\n\tregion[%i] = { range = [0x%16.16llx - 0x%16.16llx), size = 0x%8.8x, prot = %s }", region_addr, region_addr + region_size, region_size, GetPermissionsAsCString (region_prot)); 
+                            }
+                        }
+                        break;
+
+                    case eCommandTypeReadMemory:
+                    case eCommandTypeReadMemory64:
+                    case eCommandTypeReadRegisters:
+                        {
+                            const uint32_t error = packet.GetU32 (&offset);
+                            const uint32_t count = packet.GetByteSize() - 12;
+                            s.Printf(" (error = 0x%8.8x <0x%x>:\n", error, count); 
+                            if (count > 0)
+                                DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, count), count, 32, LLDB_INVALID_ADDRESS);
+                        }
+                        break;
+
+                    case eCommandTypeMaxBytes:
+                    case eCommandTypeWriteMemory:
+                    case eCommandTypeWriteRegisters:
+                    case eCommandTypeLoad:
+                    case eCommandTypeImagePath:
+                    case eCommandTypeSuspend:
+                    case eCommandTypeResume:
+                    case eCommandTypeException:
+                    case eCommandTypeTermination:
+                    case eCommandTypeBreakpointSet:
+                    case eCommandTypeBreakpointRemove:
+                    case eCommandTypeWriteMemory64:
+                    case eCommandTypeBreakpointSet64:
+                    case eCommandTypeBreakpointRemove64:
+                    case eCommandTypeKernelVersion:
+                        break;
+                    
+                } 
+            }
+            else
+            {
+                // Dump request packets
+                switch (command)
+                {
+                    case eCommandTypeConnect:               
+                        {
+                            const uint16_t reply_port = packet.GetU16 (&offset);
+                            const uint16_t exc_port = packet.GetU16 (&offset);
+                            s.Printf(" (reply_port=%u, exc_port=%u, greeting=\"%s\")", reply_port, exc_port, packet.GetCStr(&offset));
+                        }
+                        break;
+                                 
+                    case eCommandTypeDisconnect:
+                    case eCommandTypeHostReboot:
+                    case eCommandTypeHostInfo:
+                    case eCommandTypeVersion:
+                    case eCommandTypeRegions:
+                        // No args, just the header in the request...
+                        break;
+
+                    case eCommandTypeReadMemory:
+                        {
+                            const uint32_t addr = packet.GetU32 (&offset);
+                            const uint32_t size = packet.GetU32 (&offset);
+                            s.Printf(" (addr = 0x%8.8x, size=%u)", addr, size);
+                        }
+                        break;
+
+                    case eCommandTypeReadMemory64:
+                        {
+                            const uint64_t addr = packet.GetU64 (&offset);
+                            const uint32_t size = packet.GetU32 (&offset);
+                            s.Printf(" (addr = 0x%16.16llx, size=%u)", addr, size);
+                        }
+                        break;
+
+                    case eCommandTypeReadRegisters:
+                        {
+                            const uint32_t cpu = packet.GetU32 (&offset);
+                            const uint32_t flavor = packet.GetU32 (&offset);
+                            s.Printf(" (cpu = %u, flavor=%u)", cpu, flavor);
+                        }
+                        break;
+
+                    case eCommandTypeMaxBytes:
+                    case eCommandTypeWriteMemory:
+                    case eCommandTypeWriteRegisters:
+                    case eCommandTypeLoad:
+                    case eCommandTypeImagePath:
+                    case eCommandTypeSuspend:
+                    case eCommandTypeResume:
+                    case eCommandTypeException:
+                    case eCommandTypeTermination:
+                    case eCommandTypeBreakpointSet:
+                    case eCommandTypeBreakpointRemove:
+                        break;
+
+                    case eCommandTypeReattach:
+                        {
+                            const uint16_t reply_port = packet.GetU16 (&offset);
+                            s.Printf(" (reply_port=%u)", reply_port);
+                        }
+                        break;
+
+                    case eCommandTypeWriteMemory64:
+                    case eCommandTypeBreakpointSet64:
+                    case eCommandTypeBreakpointRemove64:
+                    case eCommandTypeKernelVersion:
+                        break;
+                }
+            }
+        }
+        else
+        {
+            error_desc = "error: invalid packet command: ";
+        }
+    }
+
+    if (error_desc)
+    {
+        s.PutCString (error_desc);
+
+        packet.Dump (&s,                    // Stream to dump to
+                     0,                     // Offset into "packet"
+                     eFormatBytes,          // Dump as hex bytes
+                     1,                     // Size of each item is 1 for single bytes
+                     packet.GetByteSize(),  // Number of bytes
+                     UINT32_MAX,            // Num bytes per line
+                     LLDB_INVALID_ADDRESS,  // Base address
+                     0, 0);                 // Bitfield info set to not do anything bitfield related
+    }
+}
+
+uint32_t
+CommunicationKDP::SendRequestReadRegisters (uint32_t cpu,
+                                            uint32_t flavor,
+                                            void *dst, 
+                                            uint32_t dst_len,
+                                            Error &error)
+{
+    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+    const CommandType command = eCommandTypeReadRegisters;
+    // Size is header + 4 byte cpu and 4 byte flavor
+    const uint32_t command_length = 8 + 4 + 4;
+    const uint32_t request_sequence_id = m_request_sequence_id;
+    MakeRequestPacketHeader (command, request_packet, command_length);
+    request_packet.PutHex32 (cpu);
+    request_packet.PutHex32 (flavor);
+    DataExtractor reply_packet;
+    if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
+    {
+        // Reset the sequence ID to zero for reattach
+        uint32_t offset = 8;
+        uint32_t kdp_error = reply_packet.GetU32 (&offset);
+        uint32_t src_len = reply_packet.GetByteSize() - 12;
+        
+        if (src_len > 0)
+        {
+            const uint32_t bytes_to_copy = std::min<uint32_t>(src_len, dst_len);
+            const void *src = reply_packet.GetData(&offset, bytes_to_copy);
+            if (src)
+            {
+                ::memcpy (dst, src, bytes_to_copy);
+                error.Clear();
+                // Return the number of bytes we could have returned regardless if
+                // we copied them or not, just so we know when things don't match up
+                return src_len; 
+            }
+        }
+        if (kdp_error)
+            error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, flavor, kdp_error);
+        else
+            error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u", cpu, flavor);
+    }
+    return 0;
+}
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h
index 83c8790..8e9d8b2 100644
--- a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h
+++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h
@@ -140,6 +140,9 @@
                              lldb_private::ProcessLaunchInfo &launch_info); 
 
     
+    //------------------------------------------------------------------
+    // Public Request Packets
+    //------------------------------------------------------------------
     bool
     SendRequestConnect (uint16_t reply_port, 
                         uint16_t exc_port, 
@@ -152,6 +155,24 @@
     SendRequestDisconnect ();
     
     uint32_t
+    SendRequestReadMemory (lldb::addr_t addr, 
+                           void *buf, 
+                           uint32_t size,
+                           lldb_private::Error &error);
+
+    uint32_t
+    SendRequestReadRegisters (uint32_t cpu,
+                              uint32_t flavor,
+                              void *dst, 
+                              uint32_t dst_size,
+                              lldb_private::Error &error);
+//    size_t
+//    SendRequestWriteMemory (lldb::addr_t addr, 
+//                            const void *buf, 
+//                            size_t size,
+//                            lldb_private::Error &error);
+    
+    uint32_t
     GetVersion ();
 
     uint32_t
@@ -184,9 +205,25 @@
                              PacketStreamType &request_packet,
                              uint16_t request_length);
 
+    //------------------------------------------------------------------
+    // Protected Request Packets (use public accessors which will cache
+    // results.
+    //------------------------------------------------------------------
     bool
     SendRequestVersion ();
     
+    bool
+    SendRequestHostInfo ();
+
+    
+    void
+    DumpPacket (lldb_private::Stream &s, 
+                const void *data, 
+                uint32_t data_len);
+
+    void
+    DumpPacket (lldb_private::Stream &s, 
+                const lldb_private::DataExtractor& extractor);
 
     bool
     VersionIsValid() const
@@ -201,7 +238,21 @@
     }
 
     bool
-    SendRequestHostInfo ();
+    ExtractIsReply (uint8_t first_packet_byte) const
+    {
+        // TODO: handle big endian...
+        return (first_packet_byte & ePacketTypeMask) != 0;
+    }
+
+    CommandType
+    ExtractCommand (uint8_t first_packet_byte) const
+    {
+        // TODO: handle big endian...
+        return (CommandType)(first_packet_byte & eCommandTypeMask);
+    }
+    
+    static const char *
+    GetCommandAsCString (uint8_t command);
 
     void
     ClearKDPSettings ();
@@ -214,6 +265,7 @@
     //------------------------------------------------------------------
     // Classes that inherit from CommunicationKDP can see and modify these
     //------------------------------------------------------------------
+    uint32_t m_addr_byte_size;
     lldb::ByteOrder m_byte_order;
     uint32_t m_packet_timeout;
     lldb_private::Mutex m_sequence_mutex;    // Restrict access to sending/receiving packets to a single thread at a time
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
index 77d3d1c..6d33ea2 100644
--- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -18,11 +18,12 @@
 #include "lldb/Core/State.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
 
 // Project includes
 #include "ProcessKDP.h"
 #include "ProcessKDPLog.h"
-//#include "ThreadKDP.h"
+#include "ThreadKDP.h"
 #include "StopInfoMachException.h"
 
 using namespace lldb;
@@ -182,7 +183,10 @@
                     ArchSpec kernel_arch;
                     kernel_arch.SetArchitecture(eArchTypeMachO, cpu, sub);
                     m_target.SetArchitecture(kernel_arch);
-                    // TODO: thread registers based off of architecture...
+                    
+                    SetID (1);
+                    UpdateThreadListIfNeeded ();
+                    SetPrivateState (eStateStopped);
                 }
             }
             else
@@ -295,34 +299,24 @@
         log->Printf ("ProcessKDP::%s (pid = %i)", __FUNCTION__, GetID());
     
     Mutex::Locker locker (m_thread_list.GetMutex ());
-    // TODO: get the thread list here!
     const uint32_t stop_id = GetStopID();
-    if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID())
+    if (m_thread_list.GetSize(false) == 0)
     {
-        // Update the thread list's stop id immediately so we don't recurse into this function.
-//        ThreadList curr_thread_list (this);
-//        curr_thread_list.SetStopID(stop_id);
-//        
-//        std::vector<lldb::tid_t> thread_ids;
-//        bool sequence_mutex_unavailable = false;
-//        const size_t num_thread_ids = m_comm.GetCurrentThreadIDs (thread_ids, sequence_mutex_unavailable);
-//        if (num_thread_ids > 0)
-//        {
-//            for (size_t i=0; i<num_thread_ids; ++i)
-//            {
-//                tid_t tid = thread_ids[i];
-//                ThreadSP thread_sp (GetThreadList().FindThreadByID (tid, false));
-//                if (!thread_sp)
-//                    thread_sp.reset (new ThreadGDBRemote (*this, tid));
-//                curr_thread_list.AddThread(thread_sp);
-//            }
-//        }
-//        
-//        if (sequence_mutex_unavailable == false)
-//        {
-//            m_thread_list = curr_thread_list;
-//            SetThreadStopInfo (m_last_stop_packet);
-//        }
+        // We currently are making only one thread per core and we
+        // actually don't know about actual threads. Eventually we
+        // want to get the thread list from memory and note which
+        // threads are on CPU as those are the only ones that we 
+        // will be able to resume.
+        ThreadList curr_thread_list (this);
+        curr_thread_list.SetStopID(stop_id);
+        const uint32_t cpu_mask = m_comm.GetCPUMask();
+        for (uint32_t cpu_mask_bit = 1; cpu_mask_bit & cpu_mask; cpu_mask_bit <<= 1)
+        {
+            // The thread ID is currently the CPU mask bit
+            ThreadSP thread_sp (new ThreadKDP (*this, cpu_mask_bit));
+                curr_thread_list.AddThread(thread_sp);
+        }
+        m_thread_list = curr_thread_list;
     }
     return GetThreadList().GetSize(false);
 }
@@ -549,7 +543,9 @@
 size_t
 ProcessKDP::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
 {
-    error.SetErrorString ("ProcessKDP::DoReadMemory not implemented");
+    if (m_comm.IsConnected())
+        return m_comm.SendRequestReadMemory (addr, buf, size, error);
+    error.SetErrorString ("not connected");
     return 0;
 }
 
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
index c967e2f..3649713 100644
--- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
@@ -183,6 +183,12 @@
     virtual lldb_private::Error
     DisableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
     
+    CommunicationKDP &
+    GetCommunication()
+    {
+        return m_comm;
+    }
+
 protected:
     friend class ThreadKDP;
     friend class CommunicationKDP;
@@ -229,12 +235,6 @@
     uint32_t
     UpdateThreadListIfNeeded ();
     
-    CommunicationKDP &
-    GetCommunication()
-    {
-        return m_comm;
-    }
-    
     enum
     {
         eBroadcastBitAsyncContinue                  = (1 << 0),
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp
new file mode 100644
index 0000000..fcc6865
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp
@@ -0,0 +1,90 @@
+//===-- RegisterContextKDP_arm.cpp ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextKDP_arm.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "ProcessKDP.h"
+#include "ThreadKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_arm::RegisterContextKDP_arm(ThreadKDP &thread, uint32_t concrete_frame_idx) :
+    RegisterContextDarwin_arm (thread, concrete_frame_idx),
+    m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_arm::~RegisterContextKDP_arm()
+{
+}
+
+int
+RegisterContextKDP_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+    Error error;
+    if (m_kdp_thread.GetKDPProcess().GetCommunication().SendRequestReadRegisters (tid, 
+                                                                                  GPRRegSet, 
+                                                                                  &gpr, sizeof(gpr), 
+                                                                                  error))
+    {
+        if (error.Success())
+            return 0;
+    }
+    return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+    return -1;
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h
new file mode 100644
index 0000000..1e54728
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h
@@ -0,0 +1,61 @@
+//===-- RegisterContextKDP_arm.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_RegisterContextKDP_arm_h_
+#define liblldb_RegisterContextKDP_arm_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
+
+class ThreadKDP;
+
+class RegisterContextKDP_arm : public RegisterContextDarwin_arm
+{
+public:
+
+    RegisterContextKDP_arm (ThreadKDP &thread, 
+                            uint32_t concrete_frame_idx);
+
+    virtual
+    ~RegisterContextKDP_arm();
+
+protected:
+
+    virtual int
+    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+    
+    int
+    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+    
+    int
+    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+    
+    int
+    DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
+    
+    int
+    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+    
+    int
+    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+    
+    int
+    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+    
+    int
+    DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
+    
+    ThreadKDP &m_kdp_thread;
+};
+
+#endif  // liblldb_RegisterContextKDP_arm_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp
new file mode 100644
index 0000000..7b7fc0f
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp
@@ -0,0 +1,71 @@
+//===-- RegisterContextKDP_i386.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 <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextKDP_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_i386::RegisterContextKDP_i386(Thread &thread, uint32_t concrete_frame_idx) :
+    RegisterContextDarwin_i386 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextKDP_i386::~RegisterContextKDP_i386()
+{
+}
+
+int
+RegisterContextKDP_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+    mach_msg_type_number_t count = GPRWordCount;
+    return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextKDP_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+    mach_msg_type_number_t count = FPUWordCount;
+    return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextKDP_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+    mach_msg_type_number_t count = EXCWordCount;
+    return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextKDP_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+    return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextKDP_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+    return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextKDP_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+    return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h
new file mode 100644
index 0000000..641e49d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextKDP_i386.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_RegisterContextKDP_i386_h_
+#define liblldb_RegisterContextKDP_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
+
+class RegisterContextKDP_i386 : public RegisterContextDarwin_i386
+{
+public:
+    RegisterContextKDP_i386 (lldb_private::Thread &thread, 
+                             uint32_t concrete_frame_idx);
+    
+    virtual
+    ~RegisterContextKDP_i386();
+    
+protected:
+    
+    virtual int
+    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+    
+    int
+    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+    
+    int
+    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+    
+    int
+    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+    
+    int
+    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+    
+    int
+    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif  // liblldb_RegisterContextKDP_i386_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp
new file mode 100644
index 0000000..dc5a47c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp
@@ -0,0 +1,66 @@
+//===-- RegisterContextKDP_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.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextKDP_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_x86_64::RegisterContextKDP_x86_64(Thread &thread, uint32_t concrete_frame_idx) :
+    RegisterContextDarwin_x86_64 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64()
+{
+}
+
+int
+RegisterContextKDP_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+    return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+    return -1;
+}
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h
new file mode 100644
index 0000000..f1d41cb
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h
@@ -0,0 +1,50 @@
+//===-- RegisterContextKDP_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 liblldb_RegisterContextKDP_x86_64_h_
+#define liblldb_RegisterContextKDP_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
+
+class RegisterContextKDP_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+    
+    RegisterContextKDP_x86_64 (lldb_private::Thread &thread, 
+                               uint32_t concrete_frame_idx);
+    
+    virtual
+    ~RegisterContextKDP_x86_64();
+    
+protected:
+    
+    virtual int
+    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+    
+    int
+    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+    
+    int
+    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+    
+    int
+    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+    
+    int
+    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+    
+    int
+    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif  // liblldb_RegisterContextKDP_x86_64_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp
new file mode 100644
index 0000000..dac5517
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp
@@ -0,0 +1,247 @@
+//===-- ThreadKDP.cpp -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadKDP.h"
+
+#include "llvm/Support/MachO.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Breakpoint/WatchpointLocation.h"
+
+#include "ProcessKDP.h"
+#include "ProcessKDPLog.h"
+#include "RegisterContextKDP_arm.h"
+#include "RegisterContextKDP_i386.h"
+#include "RegisterContextKDP_x86_64.h"
+#include "Plugins/Process/Utility/UnwindLLDB.h"
+
+#if defined(__APPLE__)
+#include "UnwindMacOSXFrameBackchain.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadKDP::ThreadKDP (ProcessKDP &process, lldb::tid_t tid) :
+    Thread(process, tid),
+    m_thread_name (),
+    m_dispatch_queue_name (),
+    m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS)
+{
+    ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::ThreadKDP (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID());
+}
+
+ThreadKDP::~ThreadKDP ()
+{
+    ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::~ThreadKDP (pid = %i, tid = 0x%4.4x)", this, m_process.GetID(), GetID());
+    DestroyThread();
+}
+
+
+const char *
+ThreadKDP::GetInfo ()
+{
+    return NULL;
+}
+
+
+const char *
+ThreadKDP::GetName ()
+{
+    if (m_thread_name.empty())
+        return NULL;
+    return m_thread_name.c_str();
+}
+
+const char *
+ThreadKDP::GetQueueName ()
+{
+    return NULL;
+}
+
+bool
+ThreadKDP::WillResume (StateType resume_state)
+{
+    ClearStackFrames();
+    // Call the Thread::WillResume first. If we stop at a signal, the stop info
+    // class for signal will set the resume signal that we need below. The signal
+    // stuff obeys the Process::UnixSignal defaults. 
+    Thread::WillResume(resume_state);
+
+    lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
+    if (log)
+        log->Printf ("Resuming thread: %4.4x with state: %s.", GetID(), StateAsCString(resume_state));
+
+//    ProcessKDP &process = GetKDPProcess();
+//    switch (resume_state)
+//    {
+//    case eStateSuspended:
+//    case eStateStopped:
+//        // Don't append anything for threads that should stay stopped.
+//        break;
+//
+//    case eStateRunning:
+//    case eStateStepping:
+//        break;
+//
+//    default:
+//        break;
+//    }
+    return true;
+}
+
+void
+ThreadKDP::RefreshStateAfterStop()
+{
+    // Invalidate all registers in our register context. We don't set "force" to
+    // true because the stop reply packet might have had some register values
+    // that were expedited and these will already be copied into the register
+    // context by the time this function gets called. The KDPRegisterContext
+    // class has been made smart enough to detect when it needs to invalidate
+    // which registers are valid by putting hooks in the register read and 
+    // register supply functions where they check the process stop ID and do
+    // the right thing.
+    const bool force = false;
+    GetRegisterContext()->InvalidateIfNeeded (force);
+}
+
+Unwind *
+ThreadKDP::GetUnwinder ()
+{
+    if (m_unwinder_ap.get() == NULL)
+    {
+        const ArchSpec target_arch (GetProcess().GetTarget().GetArchitecture ());
+        const llvm::Triple::ArchType machine = target_arch.GetMachine();
+        switch (machine)
+        {
+            case llvm::Triple::x86_64:
+            case llvm::Triple::x86:
+            case llvm::Triple::arm:
+            case llvm::Triple::thumb:
+                m_unwinder_ap.reset (new UnwindLLDB (*this));
+                break;
+
+            default:
+#if defined(__APPLE__)
+                m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this));
+#endif
+                break;
+        }
+    }
+    return m_unwinder_ap.get();
+}
+
+void
+ThreadKDP::ClearStackFrames ()
+{
+    Unwind *unwinder = GetUnwinder ();
+    if (unwinder)
+        unwinder->Clear();
+    Thread::ClearStackFrames();
+}
+
+
+bool
+ThreadKDP::ThreadIDIsValid (lldb::tid_t thread)
+{
+    return thread != 0;
+}
+
+void
+ThreadKDP::Dump(Log *log, uint32_t index)
+{
+}
+
+
+bool
+ThreadKDP::ShouldStop (bool &step_more)
+{
+    return true;
+}
+lldb::RegisterContextSP
+ThreadKDP::GetRegisterContext ()
+{
+    if (m_reg_context_sp.get() == NULL)
+        m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+    return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadKDP::CreateRegisterContextForFrame (StackFrame *frame)
+{
+    lldb::RegisterContextSP reg_ctx_sp;
+    uint32_t concrete_frame_idx = 0;
+    
+    if (frame)
+        concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+    if (concrete_frame_idx == 0)
+    {
+        switch (GetKDPProcess().GetCommunication().GetCPUType())
+        {
+            case llvm::MachO::CPUTypeARM:
+                reg_ctx_sp.reset (new RegisterContextKDP_arm (*this, concrete_frame_idx));
+                break;
+            case llvm::MachO::CPUTypeI386:
+                reg_ctx_sp.reset (new RegisterContextKDP_i386 (*this, concrete_frame_idx));
+                break;
+            case llvm::MachO::CPUTypeX86_64:
+                reg_ctx_sp.reset (new RegisterContextKDP_x86_64 (*this, concrete_frame_idx));
+                break;
+            default:
+                assert (!"Add CPU type support in KDP");
+                break;
+        }
+    }
+    else if (m_unwinder_ap.get())
+        reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame (frame);
+    return reg_ctx_sp;
+}
+
+lldb::StopInfoSP
+ThreadKDP::GetPrivateStopReason ()
+{
+    const uint32_t process_stop_id = GetProcess().GetStopID();
+    if (m_thread_stop_reason_stop_id != process_stop_id ||
+        (m_actual_stop_info_sp && !m_actual_stop_info_sp->IsValid()))
+    {
+        // TODO: can we query the initial state of the thread here?
+        // For now I am just going to pretend that a SIGSTOP happened.
+
+        SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP));
+
+        // If GetKDPProcess().SetThreadStopInfo() doesn't find a stop reason
+        // for this thread, then m_actual_stop_info_sp will not ever contain
+        // a valid stop reason and the "m_actual_stop_info_sp->IsValid() == false"
+        // check will never be able to tell us if we have the correct stop info
+        // for this thread and we will continually send qThreadStopInfo packets
+        // down to the remote KDP server, so we need to keep our own notion
+        // of the stop ID that m_actual_stop_info_sp is valid for (even if it
+        // contains nothing). We use m_thread_stop_reason_stop_id for this below.
+//        m_thread_stop_reason_stop_id = process_stop_id;
+//        m_actual_stop_info_sp.reset();
+
+    }
+    return m_actual_stop_info_sp;
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h
new file mode 100644
index 0000000..95c2f05
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h
@@ -0,0 +1,115 @@
+//===-- ThreadKDP.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_ThreadKDP_h_
+#define liblldb_ThreadKDP_h_
+
+#include <string>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+class ProcessKDP;
+
+class ThreadKDP : public lldb_private::Thread
+{
+public:
+    ThreadKDP (ProcessKDP &process, 
+               lldb::tid_t tid);
+
+    virtual
+    ~ThreadKDP ();
+
+    virtual bool
+    WillResume (lldb::StateType resume_state);
+
+    virtual void
+    RefreshStateAfterStop();
+
+    virtual const char *
+    GetInfo ();
+
+    virtual const char *
+    GetName ();
+
+    virtual const char *
+    GetQueueName ();
+
+    virtual lldb::RegisterContextSP
+    GetRegisterContext ();
+
+    virtual lldb::RegisterContextSP
+    CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+    virtual void
+    ClearStackFrames ();
+
+    ProcessKDP &
+    GetKDPProcess ()
+    {
+        return (ProcessKDP &)m_process;
+    }
+
+    void
+    Dump (lldb_private::Log *log, uint32_t index);
+
+    static bool
+    ThreadIDIsValid (lldb::tid_t thread);
+
+    bool
+    ShouldStop (bool &step_more);
+
+    const char *
+    GetBasicInfoAsString ();
+
+    void
+    SetName (const char *name)
+    {
+        if (name && name[0])
+            m_thread_name.assign (name);
+        else
+            m_thread_name.clear();
+    }
+
+    lldb::addr_t
+    GetThreadDispatchQAddr ()
+    {
+        return m_thread_dispatch_qaddr;
+    }
+
+    void
+    SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr)
+    {
+        m_thread_dispatch_qaddr = thread_dispatch_qaddr;
+    }
+
+protected:
+    
+    friend class ProcessKDP;
+
+    //------------------------------------------------------------------
+    // Member variables.
+    //------------------------------------------------------------------
+    std::string m_thread_name;
+    std::string m_dispatch_queue_name;
+    lldb::addr_t m_thread_dispatch_qaddr;
+    //------------------------------------------------------------------
+    // Member variables.
+    //------------------------------------------------------------------
+
+    virtual lldb_private::Unwind *
+    GetUnwinder ();
+
+    virtual lldb::StopInfoSP
+    GetPrivateStopReason ();
+
+
+};
+
+#endif  // liblldb_ThreadKDP_h_