aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Process/MacOSX-Kernel
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/MacOSX-Kernel')
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt10
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp1445
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h347
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/Makefile14
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp1211
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h274
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp186
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h54
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp161
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h61
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp161
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h61
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp129
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h53
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp127
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h54
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp211
-rw-r--r--source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h98
18 files changed, 4657 insertions, 0 deletions
diff --git a/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt b/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt
new file mode 100644
index 000000000000..681b7405e2b8
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginProcessMacOSXKernel
+ CommunicationKDP.cpp
+ ProcessKDP.cpp
+ ProcessKDPLog.cpp
+ RegisterContextKDP_arm.cpp
+ RegisterContextKDP_arm64.cpp
+ RegisterContextKDP_i386.cpp
+ RegisterContextKDP_x86_64.cpp
+ ThreadKDP.cpp
+ )
diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp
new file mode 100644
index 000000000000..5c1c3284a35c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp
@@ -0,0 +1,1445 @@
+//===-- CommunicationKDP.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "CommunicationKDP.h"
+
+// C Includes
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+
+// C++ Includes
+
+// 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/Core/UUID.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "ProcessKDPLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// CommunicationKDP constructor
+//----------------------------------------------------------------------
+CommunicationKDP::CommunicationKDP (const char *comm_name) :
+ Communication(comm_name),
+ m_addr_byte_size (4),
+ m_byte_order (eByteOrderLittle),
+ m_packet_timeout (5),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_is_running (false),
+ m_session_key (0u),
+ m_request_sequence_id (0u),
+ m_exception_sequence_id (0u),
+ m_kdp_version_version (0u),
+ m_kdp_version_feature (0u),
+ m_kdp_hostinfo_cpu_mask (0u),
+ m_kdp_hostinfo_cpu_type (0u),
+ m_kdp_hostinfo_cpu_subtype (0u)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommunicationKDP::~CommunicationKDP()
+{
+ if (IsConnected())
+ {
+ Disconnect();
+ }
+}
+
+bool
+CommunicationKDP::SendRequestPacket (const PacketStreamType &request_packet)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendRequestPacketNoLock (request_packet);
+}
+
+#if 0
+typedef struct {
+ uint8_t request; // Either: CommandType | ePacketTypeRequest, or CommandType | ePacketTypeReply
+ uint8_t sequence;
+ uint16_t length; // Length of entire packet including this header
+ uint32_t key; // Session key
+} kdp_hdr_t;
+#endif
+
+void
+CommunicationKDP::MakeRequestPacketHeader (CommandType request_type,
+ PacketStreamType &request_packet,
+ uint16_t request_length)
+{
+ request_packet.Clear();
+ request_packet.PutHex8 (request_type | ePacketTypeRequest); // Set the request type
+ request_packet.PutHex8 (m_request_sequence_id++); // Sequence number
+ request_packet.PutHex16 (request_length); // Length of the packet including this header
+ request_packet.PutHex32 (m_session_key); // Session key
+}
+
+bool
+CommunicationKDP::SendRequestAndGetReply (const CommandType command,
+ const PacketStreamType &request_packet,
+ DataExtractor &reply_packet)
+{
+ if (IsRunning())
+ {
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
+ if (log)
+ {
+ PacketStreamType log_strm;
+ DumpPacket (log_strm, request_packet.GetData(), request_packet.GetSize());
+ log->Printf("error: kdp running, not sending packet: %.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
+ }
+ return false;
+ }
+
+ Mutex::Locker locker(m_sequence_mutex);
+#ifdef LLDB_CONFIGURATION_DEBUG
+ // NOTE: this only works for packets that are in native endian byte order
+ assert (request_packet.GetSize() == *((uint16_t *)(request_packet.GetData() + 2)));
+#endif
+ lldb::offset_t offset = 1;
+ const uint32_t num_retries = 3;
+ for (uint32_t i=0; i<num_retries; ++i)
+ {
+ if (SendRequestPacketNoLock(request_packet))
+ {
+ const uint8_t request_sequence_id = (uint8_t)request_packet.GetData()[1];
+ while (1)
+ {
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, GetPacketTimeoutInMicroSeconds ()))
+ {
+ offset = 0;
+ const uint8_t reply_command = reply_packet.GetU8 (&offset);
+ const uint8_t reply_sequence_id = reply_packet.GetU8 (&offset);
+ if (request_sequence_id == reply_sequence_id)
+ {
+ // The sequent ID was correct, now verify we got the response we were looking for
+ if ((reply_command & eCommandTypeMask) == command)
+ {
+ // Success
+ if (command == KDP_RESUMECPUS)
+ m_is_running.SetValue(true, eBroadcastAlways);
+ return true;
+ }
+ else
+ {
+ // Failed to get the correct response, bail
+ reply_packet.Clear();
+ return false;
+ }
+ }
+ else if (reply_sequence_id > request_sequence_id)
+ {
+ // Sequence ID was greater than the sequence ID of the packet we sent, something
+ // is really wrong...
+ reply_packet.Clear();
+ return false;
+ }
+ else
+ {
+ // The reply sequence ID was less than our current packet's sequence ID
+ // so we should keep trying to get a response because this was a response
+ // for a previous packet that we must have retried.
+ }
+ }
+ else
+ {
+ // Break and retry sending the packet as we didn't get a response due to timeout
+ break;
+ }
+ }
+ }
+ }
+ reply_packet.Clear();
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestPacketNoLock (const PacketStreamType &request_packet)
+{
+ if (IsConnected())
+ {
+ const char *packet_data = request_packet.GetData();
+ const size_t packet_size = request_packet.GetSize();
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
+ if (log)
+ {
+ PacketStreamType log_strm;
+ DumpPacket (log_strm, packet_data, packet_size);
+ log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
+ }
+ ConnectionStatus status = eConnectionStatusSuccess;
+
+ size_t bytes_written = Write (packet_data,
+ packet_size,
+ status,
+ NULL);
+
+ if (bytes_written == packet_size)
+ return true;
+
+ if (log)
+ log->Printf ("error: failed to send packet entire packet %" PRIu64 " of %" PRIu64 " bytes sent", (uint64_t)bytes_written, (uint64_t)packet_size);
+ }
+ return false;
+}
+
+bool
+CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker)
+{
+ return locker.TryLock (m_sequence_mutex);
+}
+
+
+bool
+CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
+{
+ return m_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
+}
+
+size_t
+CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (DataExtractor &packet, uint32_t timeout_usec)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec);
+}
+
+size_t
+CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (DataExtractor &packet, uint32_t timeout_usec)
+{
+ uint8_t buffer[8192];
+ Error error;
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS | KDP_LOG_VERBOSE));
+
+ // Check for a packet from our cache first without trying any reading...
+ if (CheckForPacket (NULL, 0, packet))
+ return packet.GetByteSize();
+
+ bool timed_out = false;
+ while (IsConnected() && !timed_out)
+ {
+ lldb::ConnectionStatus status = eConnectionStatusNoConnection;
+ size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
+
+ if (log)
+ log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64,
+ __PRETTY_FUNCTION__,
+ timeout_usec,
+ Communication::ConnectionStatusAsCString (status),
+ error.AsCString(),
+ (uint64_t)bytes_read);
+
+ if (bytes_read > 0)
+ {
+ if (CheckForPacket (buffer, bytes_read, packet))
+ return packet.GetByteSize();
+ }
+ else
+ {
+ switch (status)
+ {
+ case eConnectionStatusInterrupted:
+ case eConnectionStatusTimedOut:
+ timed_out = true;
+ break;
+ case eConnectionStatusSuccess:
+ //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
+ break;
+
+ case eConnectionStatusEndOfFile:
+ case eConnectionStatusNoConnection:
+ case eConnectionStatusLostConnection:
+ case eConnectionStatusError:
+ Disconnect();
+ break;
+ }
+ }
+ }
+ packet.Clear ();
+ return 0;
+}
+
+bool
+CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtractor &packet)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
+
+ if (src && src_len > 0)
+ {
+ if (log && log->GetVerbose())
+ {
+ PacketStreamType log_strm;
+ DataExtractor::DumpHexBytes (&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS);
+ log->Printf ("CommunicationKDP::%s adding %u bytes: %s",
+ __FUNCTION__,
+ (uint32_t)src_len,
+ log_strm.GetData());
+ }
+ m_bytes.append ((const char *)src, src_len);
+ }
+
+ // Make sure we at least have enough bytes for a packet header
+ const size_t bytes_available = m_bytes.size();
+ if (bytes_available >= 8)
+ {
+ packet.SetData (&m_bytes[0], bytes_available, m_byte_order);
+ lldb::offset_t offset = 0;
+ uint8_t reply_command = packet.GetU8(&offset);
+ switch (reply_command)
+ {
+ case ePacketTypeRequest | KDP_EXCEPTION:
+ case ePacketTypeRequest | KDP_TERMINATION:
+ // We got an exception request, so be sure to send an ACK
+ {
+ PacketStreamType request_ack_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ // Set the reply but and make the ACK packet
+ request_ack_packet.PutHex8 (reply_command | ePacketTypeReply);
+ request_ack_packet.PutHex8 (packet.GetU8(&offset));
+ request_ack_packet.PutHex16 (packet.GetU16(&offset));
+ request_ack_packet.PutHex32 (packet.GetU32(&offset));
+ m_is_running.SetValue(false, eBroadcastAlways);
+ // Ack to the exception or termination
+ SendRequestPacketNoLock (request_ack_packet);
+ }
+ // Fall through to case below to get packet contents
+ case ePacketTypeReply | KDP_CONNECT:
+ case ePacketTypeReply | KDP_DISCONNECT:
+ case ePacketTypeReply | KDP_HOSTINFO:
+ case ePacketTypeReply | KDP_VERSION:
+ case ePacketTypeReply | KDP_MAXBYTES:
+ case ePacketTypeReply | KDP_READMEM:
+ case ePacketTypeReply | KDP_WRITEMEM:
+ case ePacketTypeReply | KDP_READREGS:
+ case ePacketTypeReply | KDP_WRITEREGS:
+ case ePacketTypeReply | KDP_LOAD:
+ case ePacketTypeReply | KDP_IMAGEPATH:
+ case ePacketTypeReply | KDP_SUSPEND:
+ case ePacketTypeReply | KDP_RESUMECPUS:
+ case ePacketTypeReply | KDP_BREAKPOINT_SET:
+ case ePacketTypeReply | KDP_BREAKPOINT_REMOVE:
+ case ePacketTypeReply | KDP_REGIONS:
+ case ePacketTypeReply | KDP_REATTACH:
+ case ePacketTypeReply | KDP_HOSTREBOOT:
+ case ePacketTypeReply | KDP_READMEM64:
+ case ePacketTypeReply | KDP_WRITEMEM64:
+ case ePacketTypeReply | KDP_BREAKPOINT_SET64:
+ case ePacketTypeReply | KDP_BREAKPOINT_REMOVE64:
+ case ePacketTypeReply | KDP_KERNELVERSION:
+ case ePacketTypeReply | KDP_READPHYSMEM64:
+ case ePacketTypeReply | KDP_WRITEPHYSMEM64:
+ case ePacketTypeReply | KDP_READIOPORT:
+ case ePacketTypeReply | KDP_WRITEIOPORT:
+ case ePacketTypeReply | KDP_READMSR64:
+ case ePacketTypeReply | KDP_WRITEMSR64:
+ case ePacketTypeReply | KDP_DUMPINFO:
+ {
+ offset = 2;
+ const uint16_t length = packet.GetU16 (&offset);
+ if (length <= bytes_available)
+ {
+ // We have an entire packet ready, we need to copy the data
+ // bytes into a buffer that will be owned by the packet and
+ // erase the bytes from our communcation buffer "m_bytes"
+ packet.SetData (DataBufferSP (new DataBufferHeap (&m_bytes[0], length)));
+ m_bytes.erase (0, length);
+
+ if (log)
+ {
+ PacketStreamType log_strm;
+ DumpPacket (log_strm, packet);
+
+ log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData());
+ }
+ return true;
+ }
+ }
+ break;
+
+ default:
+ // Unrecognized reply command byte, erase this byte and try to get back on track
+ if (log)
+ log->Printf ("CommunicationKDP::%s: tossing junk byte: 0x%2.2x",
+ __FUNCTION__,
+ (uint8_t)m_bytes[0]);
+ m_bytes.erase(0, 1);
+ break;
+ }
+ }
+ packet.Clear();
+ return false;
+}
+
+
+bool
+CommunicationKDP::SendRequestConnect (uint16_t reply_port,
+ uint16_t exc_port,
+ const char *greeting)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ if (greeting == NULL)
+ greeting = "";
+
+ const CommandType command = KDP_CONNECT;
+ // Length is 82 uint16_t and the length of the greeting C string with the terminating NULL
+ const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ // Always send connect ports as little endian
+ request_packet.SetByteOrder (eByteOrderLittle);
+ request_packet.PutHex16 (htons(reply_port));
+ request_packet.PutHex16 (htons(exc_port));
+ request_packet.SetByteOrder (m_byte_order);
+ request_packet.PutCString (greeting);
+ DataExtractor reply_packet;
+ return SendRequestAndGetReply (command, request_packet, reply_packet);
+}
+
+void
+CommunicationKDP::ClearKDPSettings ()
+{
+ m_request_sequence_id = 0;
+ m_kdp_version_version = 0;
+ m_kdp_version_feature = 0;
+ m_kdp_hostinfo_cpu_mask = 0;
+ m_kdp_hostinfo_cpu_type = 0;
+ m_kdp_hostinfo_cpu_subtype = 0;
+}
+
+bool
+CommunicationKDP::SendRequestReattach (uint16_t reply_port)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_REATTACH;
+ // Length is 8 bytes for the header plus 2 bytes for the reply UDP port
+ const uint32_t command_length = 8 + 2;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ // Always send connect ports as little endian
+ request_packet.SetByteOrder (eByteOrderLittle);
+ request_packet.PutHex16(htons(reply_port));
+ request_packet.SetByteOrder (m_byte_order);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ // Reset the sequence ID to zero for reattach
+ ClearKDPSettings ();
+ lldb::offset_t offset = 4;
+ m_session_key = reply_packet.GetU32 (&offset);
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+CommunicationKDP::GetVersion ()
+{
+ if (!VersionIsValid())
+ SendRequestVersion();
+ return m_kdp_version_version;
+}
+
+uint32_t
+CommunicationKDP::GetFeatureFlags ()
+{
+ if (!VersionIsValid())
+ SendRequestVersion();
+ return m_kdp_version_feature;
+}
+
+bool
+CommunicationKDP::SendRequestVersion ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_VERSION;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ m_kdp_version_version = reply_packet.GetU32 (&offset);
+ m_kdp_version_feature = reply_packet.GetU32 (&offset);
+ return true;
+ }
+ return false;
+}
+
+#if 0 // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+const char *
+CommunicationKDP::GetImagePath ()
+{
+ if (m_image_path.empty())
+ SendRequestImagePath();
+ return m_image_path.c_str();
+}
+
+bool
+CommunicationKDP::SendRequestImagePath ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_IMAGEPATH;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ const char *path = reply_packet.PeekCStr(8);
+ if (path && path[0])
+ m_kernel_version.assign (path);
+ return true;
+ }
+ return false;
+}
+#endif
+
+uint32_t
+CommunicationKDP::GetCPUMask ()
+{
+ if (!HostInfoIsValid())
+ SendRequestHostInfo();
+ return m_kdp_hostinfo_cpu_mask;
+}
+
+uint32_t
+CommunicationKDP::GetCPUType ()
+{
+ if (!HostInfoIsValid())
+ SendRequestHostInfo();
+ return m_kdp_hostinfo_cpu_type;
+}
+
+uint32_t
+CommunicationKDP::GetCPUSubtype ()
+{
+ if (!HostInfoIsValid())
+ SendRequestHostInfo();
+ return m_kdp_hostinfo_cpu_subtype;
+}
+
+lldb_private::UUID
+CommunicationKDP::GetUUID ()
+{
+ UUID uuid;
+ if (GetKernelVersion() == NULL)
+ return uuid;
+
+ if (m_kernel_version.find("UUID=") == std::string::npos)
+ return uuid;
+
+ size_t p = m_kernel_version.find("UUID=") + strlen ("UUID=");
+ std::string uuid_str = m_kernel_version.substr(p, 36);
+ if (uuid_str.size() < 32)
+ return uuid;
+
+ if (uuid.SetFromCString (uuid_str.c_str()) == 0)
+ {
+ UUID invalid_uuid;
+ return invalid_uuid;
+ }
+
+ return uuid;
+}
+
+bool
+CommunicationKDP::RemoteIsEFI ()
+{
+ if (GetKernelVersion() == NULL)
+ return false;
+ if (strncmp (m_kernel_version.c_str(), "EFI", 3) == 0)
+ return true;
+ else
+ return false;
+}
+
+bool
+CommunicationKDP::RemoteIsDarwinKernel ()
+{
+ if (GetKernelVersion() == NULL)
+ return false;
+ if (m_kernel_version.find("Darwin Kernel") != std::string::npos)
+ return true;
+ else
+ return false;
+}
+
+lldb::addr_t
+CommunicationKDP::GetLoadAddress ()
+{
+ if (GetKernelVersion() == NULL)
+ return LLDB_INVALID_ADDRESS;
+
+ if (m_kernel_version.find("stext=") == std::string::npos)
+ return LLDB_INVALID_ADDRESS;
+ size_t p = m_kernel_version.find("stext=") + strlen ("stext=");
+ if (m_kernel_version[p] != '0' || m_kernel_version[p + 1] != 'x')
+ return LLDB_INVALID_ADDRESS;
+
+ addr_t kernel_load_address;
+ errno = 0;
+ kernel_load_address = ::strtoul (m_kernel_version.c_str() + p, NULL, 16);
+ if (errno != 0 || kernel_load_address == 0)
+ return LLDB_INVALID_ADDRESS;
+
+ return kernel_load_address;
+}
+
+bool
+CommunicationKDP::SendRequestHostInfo ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_HOSTINFO;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_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);
+
+ 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;
+}
+
+const char *
+CommunicationKDP::GetKernelVersion ()
+{
+ if (m_kernel_version.empty())
+ SendRequestKernelVersion ();
+ return m_kernel_version.c_str();
+}
+
+bool
+CommunicationKDP::SendRequestKernelVersion ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_KERNELVERSION;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ const char *kernel_version_cstr = reply_packet.PeekCStr(8);
+ if (kernel_version_cstr && kernel_version_cstr[0])
+ m_kernel_version.assign (kernel_version_cstr);
+ return true;
+ }
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestDisconnect ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_DISCONNECT;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ // Are we supposed to get a reply for disconnect?
+ }
+ ClearKDPSettings ();
+ 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 ? KDP_READMEM64 : KDP_READMEM;
+ // Size is header + address size + uint32_t length
+ const uint32_t command_length = 8 + command_addr_byte_size + 4;
+ 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_packet, reply_packet))
+ {
+ lldb::offset_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");
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+
+uint32_t
+CommunicationKDP::SendRequestWriteMemory (lldb::addr_t addr,
+ const void *src,
+ uint32_t src_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 ? KDP_WRITEMEM64 : KDP_WRITEMEM;
+ // Size is header + address size + uint32_t length
+ const uint32_t command_length = 8 + command_addr_byte_size + 4 + src_len;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutMaxHex64 (addr, command_addr_byte_size);
+ request_packet.PutHex32 (src_len);
+ request_packet.PutRawBytes(src, src_len);
+
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error)
+ error.SetErrorStringWithFormat ("kdp write memory failed (error %u)", kdp_error);
+ else
+ {
+ error.Clear();
+ return src_len;
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+bool
+CommunicationKDP::SendRawRequest (uint8_t command_byte,
+ const void *src, // Raw packet payload bytes
+ uint32_t src_len, // Raw packet payload length
+ DataExtractor &reply_packet,
+ Error &error)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ // Size is header + address size + uint32_t length
+ const uint32_t command_length = 8 + src_len;
+ const CommandType command = (CommandType)command_byte;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutRawBytes(src, src_len);
+
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error && (command_byte != KDP_DUMPINFO))
+ error.SetErrorStringWithFormat ("request packet 0x%8.8x failed (error %u)", command_byte, kdp_error);
+ else
+ {
+ error.Clear();
+ return true;
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return false;
+}
+
+
+const char *
+CommunicationKDP::GetCommandAsCString (uint8_t command)
+{
+ switch (command)
+ {
+ case KDP_CONNECT: return "KDP_CONNECT";
+ case KDP_DISCONNECT: return "KDP_DISCONNECT";
+ case KDP_HOSTINFO: return "KDP_HOSTINFO";
+ case KDP_VERSION: return "KDP_VERSION";
+ case KDP_MAXBYTES: return "KDP_MAXBYTES";
+ case KDP_READMEM: return "KDP_READMEM";
+ case KDP_WRITEMEM: return "KDP_WRITEMEM";
+ case KDP_READREGS: return "KDP_READREGS";
+ case KDP_WRITEREGS: return "KDP_WRITEREGS";
+ case KDP_LOAD: return "KDP_LOAD";
+ case KDP_IMAGEPATH: return "KDP_IMAGEPATH";
+ case KDP_SUSPEND: return "KDP_SUSPEND";
+ case KDP_RESUMECPUS: return "KDP_RESUMECPUS";
+ case KDP_EXCEPTION: return "KDP_EXCEPTION";
+ case KDP_TERMINATION: return "KDP_TERMINATION";
+ case KDP_BREAKPOINT_SET: return "KDP_BREAKPOINT_SET";
+ case KDP_BREAKPOINT_REMOVE: return "KDP_BREAKPOINT_REMOVE";
+ case KDP_REGIONS: return "KDP_REGIONS";
+ case KDP_REATTACH: return "KDP_REATTACH";
+ case KDP_HOSTREBOOT: return "KDP_HOSTREBOOT";
+ case KDP_READMEM64: return "KDP_READMEM64";
+ case KDP_WRITEMEM64: return "KDP_WRITEMEM64";
+ case KDP_BREAKPOINT_SET64: return "KDP_BREAKPOINT64_SET";
+ case KDP_BREAKPOINT_REMOVE64: return "KDP_BREAKPOINT64_REMOVE";
+ case KDP_KERNELVERSION: return "KDP_KERNELVERSION";
+ case KDP_READPHYSMEM64: return "KDP_READPHYSMEM64";
+ case KDP_WRITEPHYSMEM64: return "KDP_WRITEPHYSMEM64";
+ case KDP_READIOPORT: return "KDP_READIOPORT";
+ case KDP_WRITEIOPORT: return "KDP_WRITEIOPORT";
+ case KDP_READMSR64: return "KDP_READMSR64";
+ case KDP_WRITEMSR64: return "KDP_WRITEMSR64";
+ case KDP_DUMPINFO: return "KDP_DUMPINFO";
+ }
+ 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
+ {
+ lldb::offset_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 ("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ",
+ IsRunning(),
+ is_reply ? "<--" : "-->",
+ command_name,
+ first_packet_byte,
+ sequence_id,
+ length,
+ key);
+
+ if (is_reply)
+ {
+ // Dump request reply packets
+ switch (command)
+ {
+ // Commands that return a single 32 bit error
+ case KDP_CONNECT:
+ case KDP_WRITEMEM:
+ case KDP_WRITEMEM64:
+ case KDP_BREAKPOINT_SET:
+ case KDP_BREAKPOINT_REMOVE:
+ case KDP_BREAKPOINT_SET64:
+ case KDP_BREAKPOINT_REMOVE64:
+ case KDP_WRITEREGS:
+ case KDP_LOAD:
+ case KDP_WRITEIOPORT:
+ case KDP_WRITEMSR64:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ s.Printf(" (error=0x%8.8x)", error);
+ }
+ break;
+
+ case KDP_DISCONNECT:
+ case KDP_REATTACH:
+ case KDP_HOSTREBOOT:
+ case KDP_SUSPEND:
+ case KDP_RESUMECPUS:
+ case KDP_EXCEPTION:
+ case KDP_TERMINATION:
+ // No return value for the reply, just the header to ack
+ s.PutCString(" ()");
+ break;
+
+ case KDP_HOSTINFO:
+ {
+ 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 KDP_VERSION:
+ {
+ 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 KDP_REGIONS:
+ {
+ 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[%" PRIu64 "] = { range = [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), size = 0x%8.8x, prot = %s }", region_addr, region_addr, region_addr + region_size, region_size, GetPermissionsAsCString (region_prot));
+ }
+ }
+ break;
+
+ case KDP_READMEM:
+ case KDP_READMEM64:
+ case KDP_READPHYSMEM64:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (error = 0x%8.8x:\n", error);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatBytesWithASCII, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ m_last_read_memory_addr, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_READREGS:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (error = 0x%8.8x regs:\n", error);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ m_addr_byte_size, // Size of each item in bytes
+ count / m_addr_byte_size, // Number of items
+ 16 / m_addr_byte_size, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_KERNELVERSION:
+ {
+ const char *kernel_version = packet.PeekCStr(8);
+ s.Printf(" (version = \"%s\")", kernel_version);
+ }
+ break;
+
+ case KDP_MAXBYTES:
+ {
+ const uint32_t max_bytes = packet.GetU32 (&offset);
+ s.Printf(" (max_bytes = 0x%8.8x (%u))", max_bytes, max_bytes);
+ }
+ break;
+ case KDP_IMAGEPATH:
+ {
+ const char *path = packet.GetCStr(&offset);
+ s.Printf(" (path = \"%s\")", path);
+ }
+ break;
+
+ case KDP_READIOPORT:
+ case KDP_READMSR64:
+ {
+ const uint32_t error = packet.GetU32 (&offset);
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (error = 0x%8.8x io:\n", error);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+ case KDP_DUMPINFO:
+ {
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (count = %u, bytes = \n", count);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+
+ }
+ break;
+
+ default:
+ s.Printf(" (add support for dumping this packet reply!!!");
+ break;
+
+ }
+ }
+ else
+ {
+ // Dump request packets
+ switch (command)
+ {
+ case KDP_CONNECT:
+ {
+ const uint16_t reply_port = ntohs(packet.GetU16 (&offset));
+ const uint16_t exc_port = ntohs(packet.GetU16 (&offset));
+ s.Printf(" (reply_port = %u, exc_port = %u, greeting = \"%s\")", reply_port, exc_port, packet.GetCStr(&offset));
+ }
+ break;
+
+ case KDP_DISCONNECT:
+ case KDP_HOSTREBOOT:
+ case KDP_HOSTINFO:
+ case KDP_VERSION:
+ case KDP_REGIONS:
+ case KDP_KERNELVERSION:
+ case KDP_MAXBYTES:
+ case KDP_IMAGEPATH:
+ case KDP_SUSPEND:
+ // No args, just the header in the request...
+ s.PutCString(" ()");
+ break;
+
+ case KDP_RESUMECPUS:
+ {
+ const uint32_t cpu_mask = packet.GetU32 (&offset);
+ s.Printf(" (cpu_mask = 0x%8.8x)", cpu_mask);
+ }
+ break;
+
+ case KDP_READMEM:
+ {
+ const uint32_t addr = packet.GetU32 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%8.8x, size = %u)", addr, size);
+ m_last_read_memory_addr = addr;
+ }
+ break;
+
+ case KDP_WRITEMEM:
+ {
+ const uint32_t addr = packet.GetU32 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%8.8x, size = %u, bytes = \n", addr, size);
+ if (size > 0)
+ DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
+ }
+ break;
+
+ case KDP_READMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u)", addr, size);
+ m_last_read_memory_addr = addr;
+ }
+ break;
+
+ case KDP_READPHYSMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ const uint32_t lcpu = packet.GetU16 (&offset);
+ s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u)", addr, size, lcpu);
+ m_last_read_memory_addr = addr;
+ }
+ break;
+
+ case KDP_WRITEMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u, bytes = \n", addr, size);
+ if (size > 0)
+ DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
+ }
+ break;
+
+ case KDP_WRITEPHYSMEM64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ const uint32_t size = packet.GetU32 (&offset);
+ const uint32_t lcpu = packet.GetU16 (&offset);
+ s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u, bytes = \n", addr, size, lcpu);
+ if (size > 0)
+ DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr);
+ }
+ break;
+
+ case KDP_READREGS:
+ {
+ const uint32_t cpu = packet.GetU32 (&offset);
+ const uint32_t flavor = packet.GetU32 (&offset);
+ s.Printf(" (cpu = %u, flavor = %u)", cpu, flavor);
+ }
+ break;
+
+ case KDP_WRITEREGS:
+ {
+ const uint32_t cpu = packet.GetU32 (&offset);
+ const uint32_t flavor = packet.GetU32 (&offset);
+ const uint32_t nbytes = packet.GetByteSize() - offset;
+ s.Printf(" (cpu = %u, flavor = %u, regs = \n", cpu, flavor);
+ if (nbytes > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ m_addr_byte_size, // Size of each item in bytes
+ nbytes / m_addr_byte_size, // Number of items
+ 16 / m_addr_byte_size, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+
+ case KDP_BREAKPOINT_SET:
+ case KDP_BREAKPOINT_REMOVE:
+ {
+ const uint32_t addr = packet.GetU32 (&offset);
+ s.Printf(" (addr = 0x%8.8x)", addr);
+ }
+ break;
+
+ case KDP_BREAKPOINT_SET64:
+ case KDP_BREAKPOINT_REMOVE64:
+ {
+ const uint64_t addr = packet.GetU64 (&offset);
+ s.Printf(" (addr = 0x%16.16" PRIx64 ")", addr);
+ }
+ break;
+
+
+ case KDP_LOAD:
+ {
+ const char *path = packet.GetCStr(&offset);
+ s.Printf(" (path = \"%s\")", path);
+ }
+ break;
+
+ case KDP_EXCEPTION:
+ {
+ const uint32_t count = packet.GetU32 (&offset);
+
+ for (uint32_t i=0; i<count; ++i)
+ {
+ const uint32_t cpu = packet.GetU32 (&offset);
+ const uint32_t exc = packet.GetU32 (&offset);
+ const uint32_t code = packet.GetU32 (&offset);
+ const uint32_t subcode = packet.GetU32 (&offset);
+ const char *exc_cstr = NULL;
+ switch (exc)
+ {
+ case 1: exc_cstr = "EXC_BAD_ACCESS"; break;
+ case 2: exc_cstr = "EXC_BAD_INSTRUCTION"; break;
+ case 3: exc_cstr = "EXC_ARITHMETIC"; break;
+ case 4: exc_cstr = "EXC_EMULATION"; break;
+ case 5: exc_cstr = "EXC_SOFTWARE"; break;
+ case 6: exc_cstr = "EXC_BREAKPOINT"; break;
+ case 7: exc_cstr = "EXC_SYSCALL"; break;
+ case 8: exc_cstr = "EXC_MACH_SYSCALL"; break;
+ case 9: exc_cstr = "EXC_RPC_ALERT"; break;
+ case 10: exc_cstr = "EXC_CRASH"; break;
+ default:
+ break;
+ }
+
+ s.Printf ("{ cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), subcode = %u (0x%8.8x)} ",
+ cpu, exc_cstr, exc, code, code, subcode, subcode);
+ }
+ }
+ break;
+
+ case KDP_TERMINATION:
+ {
+ const uint32_t term_code = packet.GetU32 (&offset);
+ const uint32_t exit_code = packet.GetU32 (&offset);
+ s.Printf(" (term_code = 0x%8.8x (%u), exit_code = 0x%8.8x (%u))", term_code, term_code, exit_code, exit_code);
+ }
+ break;
+
+ case KDP_REATTACH:
+ {
+ const uint16_t reply_port = ntohs(packet.GetU16 (&offset));
+ s.Printf(" (reply_port = %u)", reply_port);
+ }
+ break;
+
+ case KDP_READMSR64:
+ {
+ const uint32_t address = packet.GetU32 (&offset);
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x)", address, lcpu);
+ }
+ break;
+
+ case KDP_WRITEMSR64:
+ {
+ const uint32_t address = packet.GetU32 (&offset);
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ const uint32_t nbytes = packet.GetByteSize() - offset;
+ s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x, nbytes=0x%8.8x)", lcpu, address, nbytes);
+ if (nbytes > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ nbytes, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_READIOPORT:
+ {
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ const uint16_t address = packet.GetU16 (&offset);
+ const uint16_t nbytes = packet.GetU16 (&offset);
+ s.Printf(" (lcpu=0x%4.4x, address=0x%4.4x, nbytes=%u)", lcpu, address, nbytes);
+ }
+ break;
+
+ case KDP_WRITEIOPORT:
+ {
+ const uint16_t lcpu = packet.GetU16 (&offset);
+ const uint16_t address = packet.GetU16 (&offset);
+ const uint16_t nbytes = packet.GetU16 (&offset);
+ s.Printf(" (lcpu = %u, addr = 0x%4.4x, nbytes = %u, bytes = \n", lcpu, address, nbytes);
+ if (nbytes > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ nbytes, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+ }
+ break;
+
+ case KDP_DUMPINFO:
+ {
+ const uint32_t count = packet.GetByteSize() - offset;
+ s.Printf(" (count = %u, bytes = \n", count);
+ if (count > 0)
+ packet.Dump (&s, // Stream to dump to
+ offset, // Offset within "packet"
+ eFormatHex, // Format to use
+ 1, // Size of each item in bytes
+ count, // Number of items
+ 16, // Number per line
+ LLDB_INVALID_ADDRESS, // Don't show addresses before each line
+ 0, 0); // No bitfields
+
+ }
+ 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 = KDP_READREGS;
+ // Size is header + 4 byte cpu and 4 byte flavor
+ const uint32_t command_length = 8 + 4 + 4;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutHex32 (cpu);
+ request_packet.PutHex32 (flavor);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_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);
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+uint32_t
+CommunicationKDP::SendRequestWriteRegisters (uint32_t cpu,
+ uint32_t flavor,
+ const void *src,
+ uint32_t src_len,
+ Error &error)
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_WRITEREGS;
+ // Size is header + 4 byte cpu and 4 byte flavor
+ const uint32_t command_length = 8 + 4 + 4 + src_len;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutHex32 (cpu);
+ request_packet.PutHex32 (flavor);
+ request_packet.Write(src, src_len);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error == 0)
+ return src_len;
+ error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, flavor, kdp_error);
+ }
+ else
+ {
+ error.SetErrorString ("failed to send packet");
+ }
+ return 0;
+}
+
+
+bool
+CommunicationKDP::SendRequestResume ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_RESUMECPUS;
+ const uint32_t command_length = 12;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutHex32(GetCPUMask());
+
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ return true;
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestBreakpoint (bool set, addr_t addr)
+{
+ 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 = set ? (use_64 ? KDP_BREAKPOINT_SET64 : KDP_BREAKPOINT_SET ):
+ (use_64 ? KDP_BREAKPOINT_REMOVE64 : KDP_BREAKPOINT_REMOVE);
+
+ const uint32_t command_length = 8 + command_addr_byte_size;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ request_packet.PutMaxHex64 (addr, command_addr_byte_size);
+
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ {
+ lldb::offset_t offset = 8;
+ uint32_t kdp_error = reply_packet.GetU32 (&offset);
+ if (kdp_error == 0)
+ return true;
+ }
+ return false;
+}
+
+bool
+CommunicationKDP::SendRequestSuspend ()
+{
+ PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order);
+ const CommandType command = KDP_SUSPEND;
+ const uint32_t command_length = 8;
+ MakeRequestPacketHeader (command, request_packet, command_length);
+ DataExtractor reply_packet;
+ if (SendRequestAndGetReply (command, request_packet, reply_packet))
+ return true;
+ return false;
+}
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h
new file mode 100644
index 000000000000..98a146d5a06d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h
@@ -0,0 +1,347 @@
+//===-- CommunicationKDP.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_CommunicationKDP_h_
+#define liblldb_CommunicationKDP_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Core/StreamBuffer.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/TimeValue.h"
+
+class CommunicationKDP : public lldb_private::Communication
+{
+public:
+ enum
+ {
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit
+ };
+
+ const static uint32_t kMaxPacketSize = 1200;
+ const static uint32_t kMaxDataSize = 1024;
+ typedef lldb_private::StreamBuffer<1024> PacketStreamType;
+ typedef enum
+ {
+ KDP_CONNECT = 0u,
+ KDP_DISCONNECT,
+ KDP_HOSTINFO,
+ KDP_VERSION,
+ KDP_MAXBYTES,
+ KDP_READMEM,
+ KDP_WRITEMEM,
+ KDP_READREGS,
+ KDP_WRITEREGS,
+ KDP_LOAD,
+ KDP_IMAGEPATH,
+ KDP_SUSPEND,
+ KDP_RESUMECPUS,
+ KDP_EXCEPTION,
+ KDP_TERMINATION,
+ KDP_BREAKPOINT_SET,
+ KDP_BREAKPOINT_REMOVE,
+ KDP_REGIONS,
+ KDP_REATTACH,
+ KDP_HOSTREBOOT,
+ KDP_READMEM64,
+ KDP_WRITEMEM64,
+ KDP_BREAKPOINT_SET64,
+ KDP_BREAKPOINT_REMOVE64,
+ KDP_KERNELVERSION,
+ KDP_READPHYSMEM64,
+ KDP_WRITEPHYSMEM64,
+ KDP_READIOPORT,
+ KDP_WRITEIOPORT,
+ KDP_READMSR64,
+ KDP_WRITEMSR64,
+ KDP_DUMPINFO
+ } CommandType;
+
+ enum
+ {
+ KDP_FEATURE_BP = (1u << 0)
+ };
+
+ typedef enum
+ {
+ KDP_PROTERR_SUCCESS = 0,
+ KDP_PROTERR_ALREADY_CONNECTED,
+ KDP_PROTERR_BAD_NBYTES,
+ KDP_PROTERR_BADFLAVOR
+ } KDPError;
+
+ typedef enum
+ {
+ ePacketTypeRequest = 0x00u,
+ ePacketTypeReply = 0x80u,
+ ePacketTypeMask = 0x80u,
+ eCommandTypeMask = 0x7fu
+ } PacketType;
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommunicationKDP (const char *comm_name);
+
+ virtual
+ ~CommunicationKDP();
+
+ bool
+ SendRequestPacket (const PacketStreamType &request_packet);
+
+ // Wait for a packet within 'nsec' seconds
+ size_t
+ WaitForPacketWithTimeoutMicroSeconds (lldb_private::DataExtractor &response,
+ uint32_t usec);
+
+ bool
+ GetSequenceMutex(lldb_private::Mutex::Locker& locker);
+
+ bool
+ CheckForPacket (const uint8_t *src,
+ size_t src_len,
+ lldb_private::DataExtractor &packet);
+ bool
+ IsRunning() const
+ {
+ return m_is_running.GetValue();
+ }
+
+ //------------------------------------------------------------------
+ // Set the global packet timeout.
+ //
+ // For clients, this is the timeout that gets used when sending
+ // packets and waiting for responses. For servers, this might not
+ // get used, and if it doesn't this should be moved to the
+ // CommunicationKDPClient.
+ //------------------------------------------------------------------
+ uint32_t
+ SetPacketTimeout (uint32_t packet_timeout)
+ {
+ const uint32_t old_packet_timeout = m_packet_timeout;
+ m_packet_timeout = packet_timeout;
+ return old_packet_timeout;
+ }
+
+ uint32_t
+ GetPacketTimeoutInMicroSeconds () const
+ {
+ return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec;
+ }
+
+ //------------------------------------------------------------------
+ // Public Request Packets
+ //------------------------------------------------------------------
+ bool
+ SendRequestConnect (uint16_t reply_port,
+ uint16_t exc_port,
+ const char *greeting);
+
+ bool
+ SendRequestReattach (uint16_t reply_port);
+
+ bool
+ SendRequestDisconnect ();
+
+ uint32_t
+ SendRequestReadMemory (lldb::addr_t addr,
+ void *dst,
+ uint32_t dst_size,
+ lldb_private::Error &error);
+
+ uint32_t
+ SendRequestWriteMemory (lldb::addr_t addr,
+ const void *src,
+ uint32_t src_len,
+ lldb_private::Error &error);
+
+ bool
+ SendRawRequest (uint8_t command_byte,
+ const void *src,
+ uint32_t src_len,
+ lldb_private::DataExtractor &reply,
+ lldb_private::Error &error);
+
+ uint32_t
+ SendRequestReadRegisters (uint32_t cpu,
+ uint32_t flavor,
+ void *dst,
+ uint32_t dst_size,
+ lldb_private::Error &error);
+
+ uint32_t
+ SendRequestWriteRegisters (uint32_t cpu,
+ uint32_t flavor,
+ const void *src,
+ uint32_t src_size,
+ lldb_private::Error &error);
+
+ const char *
+ GetKernelVersion ();
+
+ // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+ // const char *
+ // GetImagePath ();
+
+ uint32_t
+ GetVersion ();
+
+ uint32_t
+ GetFeatureFlags ();
+
+ bool
+ LocalBreakpointsAreSupported ()
+ {
+ return (GetFeatureFlags() & KDP_FEATURE_BP) != 0;
+ }
+
+ uint32_t
+ GetCPUMask ();
+
+ uint32_t
+ GetCPUType ();
+
+ uint32_t
+ GetCPUSubtype ();
+
+ lldb_private::UUID
+ GetUUID ();
+
+ bool
+ RemoteIsEFI ();
+
+ bool
+ RemoteIsDarwinKernel ();
+
+ lldb::addr_t
+ GetLoadAddress ();
+
+ bool
+ SendRequestResume ();
+
+ bool
+ SendRequestSuspend ();
+
+ bool
+ SendRequestBreakpoint (bool set, lldb::addr_t addr);
+
+protected:
+
+ bool
+ SendRequestPacketNoLock (const PacketStreamType &request_packet);
+
+ size_t
+ WaitForPacketWithTimeoutMicroSecondsNoLock (lldb_private::DataExtractor &response,
+ uint32_t timeout_usec);
+
+ bool
+ WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr);
+
+ void
+ MakeRequestPacketHeader (CommandType request_type,
+ PacketStreamType &request_packet,
+ uint16_t request_length);
+
+ //------------------------------------------------------------------
+ // Protected Request Packets (use public accessors which will cache
+ // results.
+ //------------------------------------------------------------------
+ bool
+ SendRequestVersion ();
+
+ bool
+ SendRequestHostInfo ();
+
+ bool
+ SendRequestKernelVersion ();
+
+ // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+ //bool
+ //SendRequestImagePath ();
+
+ 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
+ {
+ return m_kdp_version_version != 0;
+ }
+
+ bool
+ HostInfoIsValid() const
+ {
+ return m_kdp_hostinfo_cpu_type != 0;
+ }
+
+ bool
+ 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 ();
+
+ bool
+ SendRequestAndGetReply (const CommandType command,
+ const PacketStreamType &request_packet,
+ lldb_private::DataExtractor &reply_packet);
+ //------------------------------------------------------------------
+ // 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
+ lldb_private::Predicate<bool> m_is_running;
+ uint32_t m_session_key;
+ uint8_t m_request_sequence_id;
+ uint8_t m_exception_sequence_id;
+ uint32_t m_kdp_version_version;
+ uint32_t m_kdp_version_feature;
+ uint32_t m_kdp_hostinfo_cpu_mask;
+ uint32_t m_kdp_hostinfo_cpu_type;
+ uint32_t m_kdp_hostinfo_cpu_subtype;
+ std::string m_kernel_version;
+ //std::string m_image_path; // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection...
+ lldb::addr_t m_last_read_memory_addr; // Last memory read address for logging
+private:
+ //------------------------------------------------------------------
+ // For CommunicationKDP only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommunicationKDP);
+};
+
+#endif // liblldb_CommunicationKDP_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/Makefile b/source/Plugins/Process/MacOSX-Kernel/Makefile
new file mode 100644
index 000000000000..e42f390ffe0d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Process/MacOSX-Darwin/Makefile -------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginProcessDarwin
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
new file mode 100644
index 000000000000..628f76d104fe
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -0,0 +1,1211 @@
+//===-- ProcessKDP.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 <errno.h>
+#include <stdlib.h>
+
+// C++ Includes
+#include <mutex>
+
+// Other libraries and framework includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupString.h"
+#include "lldb/Interpreter/OptionGroupUInt64.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/StringExtractor.h"
+
+#define USEC_PER_SEC 1000000
+
+// Project includes
+#include "ProcessKDP.h"
+#include "ProcessKDPLog.h"
+#include "ThreadKDP.h"
+#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+ static PropertyDefinition
+ g_properties[] =
+ {
+ { "packet-timeout" , OptionValue::eTypeUInt64 , true , 5, NULL, NULL, "Specify the default packet timeout in seconds." },
+ { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
+ };
+
+ enum
+ {
+ ePropertyPacketTimeout
+ };
+
+ class PluginProperties : public Properties
+ {
+ public:
+
+ static ConstString
+ GetSettingName ()
+ {
+ return ProcessKDP::GetPluginNameStatic();
+ }
+
+ PluginProperties() :
+ Properties ()
+ {
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
+ m_collection_sp->Initialize(g_properties);
+ }
+
+ virtual
+ ~PluginProperties()
+ {
+ }
+
+ uint64_t
+ GetPacketTimeout()
+ {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value);
+ }
+ };
+
+ typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
+
+ static const ProcessKDPPropertiesSP &
+ GetGlobalPluginProperties()
+ {
+ static ProcessKDPPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new PluginProperties ());
+ return g_settings_sp;
+ }
+
+} // anonymous namespace end
+
+static const lldb::tid_t g_kernel_tid = 1;
+
+ConstString
+ProcessKDP::GetPluginNameStatic()
+{
+ static ConstString g_name("kdp-remote");
+ return g_name;
+}
+
+const char *
+ProcessKDP::GetPluginDescriptionStatic()
+{
+ return "KDP Remote protocol based debugging plug-in for darwin kernel debugging.";
+}
+
+void
+ProcessKDP::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessKDP::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessKDP::CreateInstance (TargetSP target_sp,
+ Listener &listener,
+ const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset(new ProcessKDP (target_sp, listener));
+ return process_sp;
+}
+
+bool
+ProcessKDP::CanDebug(TargetSP target_sp, bool plugin_specified_by_name)
+{
+ if (plugin_specified_by_name)
+ return true;
+
+ // For now we are just making sure the file exists for a given module
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module)
+ {
+ const llvm::Triple &triple_ref = target_sp->GetArchitecture().GetTriple();
+ switch (triple_ref.getOS())
+ {
+ case llvm::Triple::Darwin: // Should use "macosx" for desktop and "ios" for iOS, but accept darwin just in case
+ case llvm::Triple::MacOSX: // For desktop targets
+ case llvm::Triple::IOS: // For arm targets
+ case llvm::Triple::TvOS:
+ case llvm::Triple::WatchOS:
+ if (triple_ref.getVendor() == llvm::Triple::Apple)
+ {
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ if (exe_objfile->GetType() == ObjectFile::eTypeExecutable &&
+ exe_objfile->GetStrata() == ObjectFile::eStrataKernel)
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessKDP constructor
+//----------------------------------------------------------------------
+ProcessKDP::ProcessKDP(TargetSP target_sp, Listener &listener) :
+ Process (target_sp, listener),
+ m_comm("lldb.process.kdp-remote.communication"),
+ m_async_broadcaster (NULL, "lldb.process.kdp-remote.async-broadcaster"),
+ m_dyld_plugin_name (),
+ m_kernel_load_addr (LLDB_INVALID_ADDRESS),
+ m_command_sp(),
+ m_kernel_thread_wp()
+{
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
+ const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout();
+ if (timeout_seconds > 0)
+ m_comm.SetPacketTimeout(timeout_seconds);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessKDP::~ProcessKDP()
+{
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+lldb_private::ConstString
+ProcessKDP::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessKDP::GetPluginVersion()
+{
+ return 1;
+}
+
+Error
+ProcessKDP::WillLaunch (Module* module)
+{
+ Error error;
+ error.SetErrorString ("launching not supported in kdp-remote plug-in");
+ return error;
+}
+
+Error
+ProcessKDP::WillAttachToProcessWithID (lldb::pid_t pid)
+{
+ Error error;
+ error.SetErrorString ("attaching to a by process ID not supported in kdp-remote plug-in");
+ return error;
+}
+
+Error
+ProcessKDP::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch)
+{
+ Error error;
+ error.SetErrorString ("attaching to a by process name not supported in kdp-remote plug-in");
+ return error;
+}
+
+bool
+ProcessKDP::GetHostArchitecture(ArchSpec &arch)
+{
+ uint32_t cpu = m_comm.GetCPUType();
+ if (cpu)
+ {
+ uint32_t sub = m_comm.GetCPUSubtype();
+ arch.SetArchitecture(eArchTypeMachO, cpu, sub);
+ // Leave architecture vendor as unspecified unknown
+ arch.GetTriple().setVendor(llvm::Triple::UnknownVendor);
+ arch.GetTriple().setVendorName(llvm::StringRef());
+ return true;
+ }
+ arch.Clear();
+ return false;
+}
+
+Error
+ProcessKDP::DoConnectRemote (Stream *strm, const char *remote_url)
+{
+ Error error;
+
+ // Don't let any JIT happen when doing KDP as we can't allocate
+ // memory and we don't want to be mucking with threads that might
+ // already be handling exceptions
+ SetCanJIT(false);
+
+ if (remote_url == NULL || remote_url[0] == '\0')
+ {
+ error.SetErrorStringWithFormat ("invalid connection URL '%s'", remote_url);
+ return error;
+ }
+
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ // Only try once for now.
+ // TODO: check if we should be retrying?
+ const uint32_t max_retry_count = 1;
+ for (uint32_t retry_count = 0; retry_count < max_retry_count; ++retry_count)
+ {
+ if (conn_ap->Connect(remote_url, &error) == eConnectionStatusSuccess)
+ break;
+ usleep (100000);
+ }
+ }
+
+ if (conn_ap->IsConnected())
+ {
+ const TCPSocket& socket = static_cast<const TCPSocket&>(*conn_ap->GetReadObject());
+ const uint16_t reply_port = socket.GetLocalPortNumber();
+
+ if (reply_port != 0)
+ {
+ m_comm.SetConnection(conn_ap.release());
+
+ if (m_comm.SendRequestReattach(reply_port))
+ {
+ if (m_comm.SendRequestConnect(reply_port, reply_port, "Greetings from LLDB..."))
+ {
+ m_comm.GetVersion();
+
+ Target &target = GetTarget();
+ ArchSpec kernel_arch;
+ // The host architecture
+ GetHostArchitecture(kernel_arch);
+ ArchSpec target_arch = target.GetArchitecture();
+ // Merge in any unspecified stuff into the target architecture in
+ // case the target arch isn't set at all or incompletely.
+ target_arch.MergeFrom(kernel_arch);
+ target.SetArchitecture(target_arch);
+
+ /* Get the kernel's UUID and load address via KDP_KERNELVERSION packet. */
+ /* An EFI kdp session has neither UUID nor load address. */
+
+ UUID kernel_uuid = m_comm.GetUUID ();
+ addr_t kernel_load_addr = m_comm.GetLoadAddress ();
+
+ if (m_comm.RemoteIsEFI ())
+ {
+ // Select an invalid plugin name for the dynamic loader so one doesn't get used
+ // since EFI does its own manual loading via python scripting
+ static ConstString g_none_dynamic_loader("none");
+ m_dyld_plugin_name = g_none_dynamic_loader;
+
+ if (kernel_uuid.IsValid()) {
+ // If EFI passed in a UUID= try to lookup UUID
+ // The slide will not be provided. But the UUID
+ // lookup will be used to launch EFI debug scripts
+ // from the dSYM, that can load all of the symbols.
+ ModuleSpec module_spec;
+ module_spec.GetUUID() = kernel_uuid;
+ module_spec.GetArchitecture() = target.GetArchitecture();
+
+ // Lookup UUID locally, before attempting dsymForUUID like action
+ module_spec.GetSymbolFileSpec() = Symbols::LocateExecutableSymbolFile(module_spec);
+ if (module_spec.GetSymbolFileSpec())
+ {
+ ModuleSpec executable_module_spec = Symbols::LocateExecutableObjectFile (module_spec);
+ if (executable_module_spec.GetFileSpec().Exists())
+ {
+ module_spec.GetFileSpec() = executable_module_spec.GetFileSpec();
+ }
+ }
+ if (!module_spec.GetSymbolFileSpec() || !module_spec.GetSymbolFileSpec())
+ Symbols::DownloadObjectAndSymbolFile (module_spec, true);
+
+ if (module_spec.GetFileSpec().Exists())
+ {
+ ModuleSP module_sp(new Module (module_spec));
+ if (module_sp.get() && module_sp->GetObjectFile())
+ {
+ // Get the current target executable
+ ModuleSP exe_module_sp (target.GetExecutableModule ());
+
+ // Make sure you don't already have the right module loaded and they will be uniqued
+ if (exe_module_sp.get() != module_sp.get())
+ target.SetExecutableModule (module_sp, false);
+ }
+ }
+ }
+ }
+ else if (m_comm.RemoteIsDarwinKernel ())
+ {
+ m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
+ if (kernel_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_kernel_load_addr = kernel_load_addr;
+ }
+ }
+
+ // Set the thread ID
+ UpdateThreadListIfNeeded ();
+ SetID (1);
+ GetThreadList ();
+ SetPrivateState (eStateStopped);
+ StreamSP async_strm_sp(target.GetDebugger().GetAsyncOutputStream());
+ if (async_strm_sp)
+ {
+ const char *cstr;
+ if ((cstr = m_comm.GetKernelVersion ()) != NULL)
+ {
+ async_strm_sp->Printf ("Version: %s\n", cstr);
+ async_strm_sp->Flush();
+ }
+// if ((cstr = m_comm.GetImagePath ()) != NULL)
+// {
+// async_strm_sp->Printf ("Image Path: %s\n", cstr);
+// async_strm_sp->Flush();
+// }
+ }
+ }
+ else
+ {
+ error.SetErrorString("KDP_REATTACH failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString("KDP_REATTACH failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid reply port from UDP connection");
+ }
+ }
+ else
+ {
+ if (error.Success())
+ error.SetErrorStringWithFormat ("failed to connect to '%s'", remote_url);
+ }
+ if (error.Fail())
+ m_comm.Disconnect();
+
+ return error;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessKDP::DoLaunch (Module *exe_module,
+ ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ error.SetErrorString ("launching not supported in kdp-remote plug-in");
+ return error;
+}
+
+Error
+ProcessKDP::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ error.SetErrorString ("attach to process by ID is not suppported in kdp remote debugging");
+ return error;
+}
+
+Error
+ProcessKDP::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ error.SetErrorString ("attach to process by name is not suppported in kdp remote debugging");
+ return error;
+}
+
+
+void
+ProcessKDP::DidAttach (ArchSpec &process_arch)
+{
+ Process::DidAttach(process_arch);
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessKDP::DidAttach()");
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ GetHostArchitecture(process_arch);
+ }
+}
+
+addr_t
+ProcessKDP::GetImageInfoAddress()
+{
+ return m_kernel_load_addr;
+}
+
+lldb_private::DynamicLoader *
+ProcessKDP::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString()));
+ return m_dyld_ap.get();
+}
+
+Error
+ProcessKDP::WillResume ()
+{
+ return Error();
+}
+
+Error
+ProcessKDP::DoResume ()
+{
+ Error error;
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS));
+ // Only start the async thread if we try to do any process control
+ if (!m_async_thread.IsJoinable())
+ StartAsyncThread();
+
+ bool resume = false;
+
+ // With KDP there is only one thread we can tell what to do
+ ThreadSP kernel_thread_sp (m_thread_list.FindThreadByProtocolID(g_kernel_tid));
+
+ if (kernel_thread_sp)
+ {
+ const StateType thread_resume_state = kernel_thread_sp->GetTemporaryResumeState();
+
+ if (log)
+ log->Printf ("ProcessKDP::DoResume() thread_resume_state = %s", StateAsCString(thread_resume_state));
+ switch (thread_resume_state)
+ {
+ case eStateSuspended:
+ // Nothing to do here when a thread will stay suspended
+ // we just leave the CPU mask bit set to zero for the thread
+ if (log)
+ log->Printf ("ProcessKDP::DoResume() = suspended???");
+ break;
+
+ case eStateStepping:
+ {
+ lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext());
+
+ if (reg_ctx_sp)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (true);");
+ reg_ctx_sp->HardwareSingleStep (true);
+ resume = true;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID());
+ }
+ }
+ break;
+
+ case eStateRunning:
+ {
+ lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext());
+
+ if (reg_ctx_sp)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (false);");
+ reg_ctx_sp->HardwareSingleStep (false);
+ resume = true;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID());
+ }
+ }
+ break;
+
+ default:
+ // The only valid thread resume states are listed above
+ assert (!"invalid thread resume state");
+ break;
+ }
+ }
+
+ if (resume)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::DoResume () sending resume");
+
+ if (m_comm.SendRequestResume ())
+ {
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue);
+ SetPrivateState(eStateRunning);
+ }
+ else
+ error.SetErrorString ("KDP resume failed");
+ }
+ else
+ {
+ error.SetErrorString ("kernel thread is suspended");
+ }
+
+ return error;
+}
+
+lldb::ThreadSP
+ProcessKDP::GetKernelThread()
+{
+ // KDP only tells us about one thread/core. Any other threads will usually
+ // be the ones that are read from memory by the OS plug-ins.
+
+ ThreadSP thread_sp (m_kernel_thread_wp.lock());
+ if (!thread_sp)
+ {
+ thread_sp.reset(new ThreadKDP (*this, g_kernel_tid));
+ m_kernel_thread_wp = thread_sp;
+ }
+ return thread_sp;
+}
+
+
+
+
+bool
+ProcessKDP::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_THREAD));
+ if (log && log->GetMask().Test(KDP_LOG_VERBOSE))
+ log->Printf ("ProcessKDP::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
+
+ // Even though there is a CPU mask, it doesn't mean we can see each CPU
+ // individually, there is really only one. Lets call this thread 1.
+ ThreadSP thread_sp (old_thread_list.FindThreadByProtocolID(g_kernel_tid, false));
+ if (!thread_sp)
+ thread_sp = GetKernelThread ();
+ new_thread_list.AddThread(thread_sp);
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessKDP::RefreshStateAfterStop ()
+{
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list.RefreshStateAfterStop();
+}
+
+Error
+ProcessKDP::DoHalt (bool &caused_stop)
+{
+ Error error;
+
+ if (m_comm.IsRunning())
+ {
+ if (m_destroy_in_process)
+ {
+ // If we are attemping to destroy, we need to not return an error to
+ // Halt or DoDestroy won't get called.
+ // We are also currently running, so send a process stopped event
+ SetPrivateState (eStateStopped);
+ }
+ else
+ {
+ error.SetErrorString ("KDP cannot interrupt a running kernel");
+ }
+ }
+ return error;
+}
+
+Error
+ProcessKDP::DoDetach(bool keep_stopped)
+{
+ Error error;
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped);
+
+ if (m_comm.IsRunning())
+ {
+ // We are running and we can't interrupt a running kernel, so we need
+ // to just close the connection to the kernel and hope for the best
+ }
+ else
+ {
+ // If we are going to keep the target stopped, then don't send the disconnect message.
+ if (!keep_stopped && m_comm.IsConnected())
+ {
+ const bool success = m_comm.SendRequestDisconnect();
+ if (log)
+ {
+ if (success)
+ log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully");
+ else
+ log->PutCString ("ProcessKDP::DoDetach() connection channel shutdown failed");
+ }
+ m_comm.Disconnect ();
+ }
+ }
+ StopAsyncThread ();
+ m_comm.Clear();
+
+ SetPrivateState (eStateDetached);
+ ResumePrivateStateThread();
+
+ //KillDebugserverProcess ();
+ return error;
+}
+
+Error
+ProcessKDP::DoDestroy ()
+{
+ // For KDP there really is no difference between destroy and detach
+ bool keep_stopped = false;
+ return DoDetach(keep_stopped);
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessKDP::IsAlive ()
+{
+ return m_comm.IsConnected() && Process::IsAlive();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessKDP::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ uint8_t *data_buffer = (uint8_t *) buf;
+ if (m_comm.IsConnected())
+ {
+ const size_t max_read_size = 512;
+ size_t total_bytes_read = 0;
+
+ // Read the requested amount of memory in 512 byte chunks
+ while (total_bytes_read < size)
+ {
+ size_t bytes_to_read_this_request = size - total_bytes_read;
+ if (bytes_to_read_this_request > max_read_size)
+ {
+ bytes_to_read_this_request = max_read_size;
+ }
+ size_t bytes_read = m_comm.SendRequestReadMemory (addr + total_bytes_read,
+ data_buffer + total_bytes_read,
+ bytes_to_read_this_request, error);
+ total_bytes_read += bytes_read;
+ if (error.Fail() || bytes_read == 0)
+ {
+ return total_bytes_read;
+ }
+ }
+
+ return total_bytes_read;
+ }
+ error.SetErrorString ("not connected");
+ return 0;
+}
+
+size_t
+ProcessKDP::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ if (m_comm.IsConnected())
+ return m_comm.SendRequestWriteMemory (addr, buf, size, error);
+ error.SetErrorString ("not connected");
+ return 0;
+}
+
+lldb::addr_t
+ProcessKDP::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
+{
+ error.SetErrorString ("memory allocation not suppported in kdp remote debugging");
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+ProcessKDP::DoDeallocateMemory (lldb::addr_t addr)
+{
+ Error error;
+ error.SetErrorString ("memory deallocation not suppported in kdp remote debugging");
+ return error;
+}
+
+Error
+ProcessKDP::EnableBreakpointSite (BreakpointSite *bp_site)
+{
+ if (m_comm.LocalBreakpointsAreSupported ())
+ {
+ Error error;
+ if (!bp_site->IsEnabled())
+ {
+ if (m_comm.SendRequestBreakpoint(true, bp_site->GetLoadAddress()))
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eExternal);
+ }
+ else
+ {
+ error.SetErrorString ("KDP set breakpoint failed");
+ }
+ }
+ return error;
+ }
+ return EnableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessKDP::DisableBreakpointSite (BreakpointSite *bp_site)
+{
+ if (m_comm.LocalBreakpointsAreSupported ())
+ {
+ Error error;
+ if (bp_site->IsEnabled())
+ {
+ BreakpointSite::Type bp_type = bp_site->GetType();
+ if (bp_type == BreakpointSite::eExternal)
+ {
+ if (m_destroy_in_process && m_comm.IsRunning())
+ {
+ // We are trying to destroy our connection and we are running
+ bp_site->SetEnabled(false);
+ }
+ else
+ {
+ if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress()))
+ bp_site->SetEnabled(false);
+ else
+ error.SetErrorString ("KDP remove breakpoint failed");
+ }
+ }
+ else
+ {
+ error = DisableSoftwareBreakpoint (bp_site);
+ }
+ }
+ return error;
+ }
+ return DisableSoftwareBreakpoint (bp_site);
+}
+
+Error
+ProcessKDP::EnableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ error.SetErrorString ("watchpoints are not suppported in kdp remote debugging");
+ return error;
+}
+
+Error
+ProcessKDP::DisableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ error.SetErrorString ("watchpoints are not suppported in kdp remote debugging");
+ return error;
+}
+
+void
+ProcessKDP::Clear()
+{
+ m_thread_list.Clear();
+}
+
+Error
+ProcessKDP::DoSignal (int signo)
+{
+ Error error;
+ error.SetErrorString ("sending signals is not suppported in kdp remote debugging");
+ return error;
+}
+
+void
+ProcessKDP::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []()
+ {
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ DebuggerInitialize);
+
+ Log::Callbacks log_callbacks = {
+ ProcessKDPLog::DisableLog,
+ ProcessKDPLog::EnableLog,
+ ProcessKDPLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessKDP::GetPluginNameStatic(), log_callbacks);
+ });
+}
+
+void
+ProcessKDP::DebuggerInitialize (lldb_private::Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForProcessPlugin (debugger,
+ GetGlobalPluginProperties()->GetValueProperties(),
+ ConstString ("Properties for the kdp-remote process plug-in."),
+ is_global_setting);
+ }
+}
+
+bool
+ProcessKDP::StartAsyncThread ()
+{
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessKDP::StartAsyncThread ()");
+
+ if (m_async_thread.IsJoinable())
+ return true;
+
+ m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.kdp-remote.async>", ProcessKDP::AsyncThread, this, NULL);
+ return m_async_thread.IsJoinable();
+}
+
+void
+ProcessKDP::StopAsyncThread ()
+{
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessKDP::StopAsyncThread ()");
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
+
+ // Stop the stdio thread
+ if (m_async_thread.IsJoinable())
+ m_async_thread.Join(nullptr);
+}
+
+
+void *
+ProcessKDP::AsyncThread (void *arg)
+{
+ ProcessKDP *process = (ProcessKDP*) arg;
+
+ const lldb::pid_t pid = process->GetID();
+
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread starting...", arg, pid);
+
+ Listener listener ("ProcessKDP::AsyncThread");
+ EventSP event_sp;
+ const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
+ eBroadcastBitAsyncThreadShouldExit;
+
+
+ if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask)
+ {
+ bool done = false;
+ while (!done)
+ {
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...",
+ pid);
+ if (listener.WaitForEvent (NULL, event_sp))
+ {
+ uint32_t event_type = event_sp->GetType();
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") Got an event of type: %d...",
+ pid,
+ event_type);
+
+ // When we are running, poll for 1 second to try and get an exception
+ // to indicate the process has stopped. If we don't get one, check to
+ // make sure no one asked us to exit
+ bool is_running = false;
+ DataExtractor exc_reply_packet;
+ do
+ {
+ switch (event_type)
+ {
+ case eBroadcastBitAsyncContinue:
+ {
+ is_running = true;
+ if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds (exc_reply_packet, 1 * USEC_PER_SEC))
+ {
+ ThreadSP thread_sp (process->GetKernelThread());
+ if (thread_sp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext());
+ if (reg_ctx_sp)
+ reg_ctx_sp->InvalidateAllRegisters();
+ static_cast<ThreadKDP *>(thread_sp.get())->SetStopInfoFrom_KDP_EXCEPTION (exc_reply_packet);
+ }
+
+ // TODO: parse the stop reply packet
+ is_running = false;
+ process->SetPrivateState(eStateStopped);
+ }
+ else
+ {
+ // Check to see if we are supposed to exit. There is no way to
+ // interrupt a running kernel, so all we can do is wait for an
+ // exception or detach...
+ if (listener.GetNextEvent(event_sp))
+ {
+ // We got an event, go through the loop again
+ event_type = event_sp->GetType();
+ }
+ }
+ }
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...",
+ pid);
+ done = true;
+ is_running = false;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got unknown event 0x%8.8x",
+ pid,
+ event_type);
+ done = true;
+ is_running = false;
+ break;
+ }
+ } while (is_running);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false",
+ pid);
+ done = true;
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread exiting...",
+ arg,
+ pid);
+
+ process->m_async_thread.Reset();
+ return NULL;
+}
+
+
+class CommandObjectProcessKDPPacketSend : public CommandObjectParsed
+{
+private:
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUInt64 m_command_byte;
+ OptionGroupString m_packet_data;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+
+public:
+ CommandObjectProcessKDPPacketSend(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet send",
+ "Send a custom packet through the KDP protocol by specifying the command byte and the packet payload data. A packet will be sent with a correct header and payload, and the raw result bytes will be displayed as a string value. ",
+ NULL),
+ m_option_group (interpreter),
+ m_command_byte(LLDB_OPT_SET_1, true , "command", 'c', 0, eArgTypeNone, "Specify the command byte to use when sending the KDP request packet.", 0),
+ m_packet_data (LLDB_OPT_SET_1, false, "payload", 'p', 0, eArgTypeNone, "Specify packet payload bytes as a hex ASCII string with no spaces or hex prefixes.", NULL)
+ {
+ m_option_group.Append (&m_command_byte, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_packet_data , LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessKDPPacketSend ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (!m_command_byte.GetOptionValue().OptionWasSet())
+ {
+ result.AppendError ("the --command option must be set to a valid command byte");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ const uint64_t command_byte = m_command_byte.GetOptionValue().GetUInt64Value(0);
+ if (command_byte > 0 && command_byte <= UINT8_MAX)
+ {
+ ProcessKDP *process = (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ const StateType state = process->GetState();
+
+ if (StateIsStoppedState (state, true))
+ {
+ std::vector<uint8_t> payload_bytes;
+ const char *ascii_hex_bytes_cstr = m_packet_data.GetOptionValue().GetCurrentValue();
+ if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0])
+ {
+ StringExtractor extractor(ascii_hex_bytes_cstr);
+ const size_t ascii_hex_bytes_cstr_len = extractor.GetStringRef().size();
+ if (ascii_hex_bytes_cstr_len & 1)
+ {
+ result.AppendErrorWithFormat ("payload data must contain an even number of ASCII hex characters: '%s'", ascii_hex_bytes_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ payload_bytes.resize(ascii_hex_bytes_cstr_len/2);
+ if (extractor.GetHexBytes(&payload_bytes[0], payload_bytes.size(), '\xdd') != payload_bytes.size())
+ {
+ result.AppendErrorWithFormat ("payload data must only contain ASCII hex characters (no spaces or hex prefixes): '%s'", ascii_hex_bytes_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ Error error;
+ DataExtractor reply;
+ process->GetCommunication().SendRawRequest (command_byte,
+ payload_bytes.empty() ? NULL : payload_bytes.data(),
+ payload_bytes.size(),
+ reply,
+ error);
+
+ if (error.Success())
+ {
+ // Copy the binary bytes into a hex ASCII string for the result
+ StreamString packet;
+ packet.PutBytesAsRawHex8(reply.GetDataStart(),
+ reply.GetByteSize(),
+ endian::InlHostByteOrder(),
+ endian::InlHostByteOrder());
+ result.AppendMessage(packet.GetString().c_str());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ else
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr && error_cstr[0])
+ result.AppendError (error_cstr);
+ else
+ result.AppendErrorWithFormat ("unknown error 0x%8.8x", error.GetError());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process must be stopped in order to send KDP packets, state is %s", StateAsCString (state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid process");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid command byte 0x%" PRIx64 ", valid values are 1 - 255", command_byte);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes no arguments, only options.", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return false;
+ }
+};
+
+class CommandObjectProcessKDPPacket : public CommandObjectMultiword
+{
+private:
+
+public:
+ CommandObjectProcessKDPPacket(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin packet",
+ "Commands that deal with KDP remote packets.",
+ NULL)
+ {
+ LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessKDPPacketSend (interpreter)));
+ }
+
+ ~CommandObjectProcessKDPPacket ()
+ {
+ }
+};
+
+class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordProcessKDP (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin",
+ "A set of commands for operating on a ProcessKDP process.",
+ "process plugin <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessKDPPacket (interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessKDP ()
+ {
+ }
+};
+
+CommandObject *
+ProcessKDP::GetPluginCommandObject()
+{
+ if (!m_command_sp)
+ m_command_sp.reset (new CommandObjectMultiwordProcessKDP (GetTarget().GetDebugger().GetCommandInterpreter()));
+ return m_command_sp.get();
+}
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
new file mode 100644
index 000000000000..fe9a4e2844bf
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
@@ -0,0 +1,274 @@
+//===-- ProcessKDP.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_ProcessKDP_h_
+#define liblldb_ProcessKDP_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "CommunicationKDP.h"
+
+class ThreadKDP;
+
+class ProcessKDP : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (lldb::TargetSP target_sp,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ DebuggerInitialize (lldb_private::Debugger &debugger);
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessKDP(lldb::TargetSP target_sp, lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessKDP();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb::TargetSP target_sp,
+ bool plugin_specified_by_name);
+
+ virtual lldb_private::CommandObject *
+ GetPluginCommandObject();
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillLaunch (lldb_private::Module* module);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithID (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
+
+ virtual lldb_private::Error
+ DoConnectRemote (lldb_private::Stream *strm, const char *remote_url);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithName (const char *process_name, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual void
+ DidAttach (lldb_private::ArchSpec &process_arch);
+
+ lldb::addr_t
+ GetImageInfoAddress();
+
+ lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillResume ();
+
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt (bool &caused_stop);
+
+ virtual lldb_private::Error
+ DoDetach (bool keep_stopped);
+
+ virtual lldb_private::Error
+ DoSignal (int signal);
+
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ CommunicationKDP &
+ GetCommunication()
+ {
+ return m_comm;
+ }
+
+protected:
+ friend class ThreadKDP;
+ friend class CommunicationKDP;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ IsRunning ( lldb::StateType state )
+ {
+ return state == lldb::eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( lldb::StateType state)
+ {
+ return state == lldb::eStateStepping;
+ }
+
+ bool
+ CanResume ( lldb::StateType state)
+ {
+ return state == lldb::eStateStopped;
+ }
+
+ bool
+ HasExited (lldb::StateType state)
+ {
+ return state == lldb::eStateExited;
+ }
+
+ bool
+ GetHostArchitecture (lldb_private::ArchSpec &arch);
+
+ bool
+ ProcessIDIsValid ( ) const;
+
+ void
+ Clear ( );
+
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+ enum
+ {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ eBroadcastBitAsyncThreadShouldExit = (1 << 1)
+ };
+
+ lldb::ThreadSP
+ GetKernelThread ();
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ CommunicationKDP m_comm;
+ lldb_private::Broadcaster m_async_broadcaster;
+ lldb_private::HostThread m_async_thread;
+ lldb_private::ConstString m_dyld_plugin_name;
+ lldb::addr_t m_kernel_load_addr;
+ lldb::CommandObjectSP m_command_sp;
+ lldb::ThreadWP m_kernel_thread_wp;
+
+
+ bool
+ StartAsyncThread ();
+
+ void
+ StopAsyncThread ();
+
+ static void *
+ AsyncThread (void *arg);
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessKDP only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (ProcessKDP);
+
+};
+
+#endif // liblldb_ProcessKDP_h_
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp
new file mode 100644
index 000000000000..79cb62aa0066
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp
@@ -0,0 +1,186 @@
+//===-- ProcessKDPLog.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessKDPLog.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_log_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+Log *
+ProcessKDPLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+ProcessKDPLog::DisableLog (const char **categories, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ if (categories[0] != NULL)
+ {
+ flag_bits = log->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~KDP_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits &= ~KDP_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~KDP_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits &= ~KDP_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~KDP_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits &= ~KDP_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~KDP_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~KDP_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~KDP_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~KDP_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~KDP_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~KDP_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~KDP_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~KDP_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+
+ }
+ }
+
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ }
+
+ return;
+}
+
+Log *
+ProcessKDPLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (size_t i=0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= KDP_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits |= KDP_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= KDP_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits |= KDP_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= KDP_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= KDP_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= KDP_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= KDP_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= KDP_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= KDP_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= KDP_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= KDP_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= KDP_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= KDP_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = KDP_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ }
+ g_log_enabled = true;
+ return g_log;
+}
+
+void
+ProcessKDPLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n",
+ ProcessKDP::GetPluginNameStatic().GetCString());
+}
+
+
+void
+ProcessKDPLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h
new file mode 100644
index 000000000000..0cb32d9b2dcf
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h
@@ -0,0 +1,54 @@
+//===-- ProcessKDPLog.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_ProcessKDPLog_h_
+#define liblldb_ProcessKDPLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define KDP_LOG_VERBOSE (1u << 0)
+#define KDP_LOG_PROCESS (1u << 1)
+#define KDP_LOG_THREAD (1u << 2)
+#define KDP_LOG_PACKETS (1u << 3)
+#define KDP_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define KDP_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define KDP_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define KDP_LOG_BREAKPOINTS (1u << 7)
+#define KDP_LOG_WATCHPOINTS (1u << 8)
+#define KDP_LOG_STEP (1u << 9)
+#define KDP_LOG_COMM (1u << 10)
+#define KDP_LOG_ASYNC (1u << 11)
+#define KDP_LOG_ALL (UINT32_MAX)
+#define KDP_LOG_DEFAULT KDP_LOG_PACKETS
+
+class ProcessKDPLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog (const char **categories, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_ProcessKDPLog_h_
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 000000000000..449ac646ab3c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp
@@ -0,0 +1,161 @@
+//===-- 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)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->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)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ 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 000000000000..1e547289d9ce
--- /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_arm64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp
new file mode 100644
index 000000000000..ed62f1982d3c
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp
@@ -0,0 +1,161 @@
+//===-- RegisterContextKDP_arm64.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_arm64.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_arm64::RegisterContextKDP_arm64 (ThreadKDP &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm64 (thread, concrete_frame_idx),
+ m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_arm64::~RegisterContextKDP_arm64()
+{
+}
+
+int
+RegisterContextKDP_arm64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_arm64::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h
new file mode 100644
index 000000000000..8780b7be4a9a
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h
@@ -0,0 +1,61 @@
+//===-- RegisterContextKDP_arm64.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_arm64_h_
+#define liblldb_RegisterContextKDP_arm64_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
+
+class ThreadKDP;
+
+class RegisterContextKDP_arm64 : public RegisterContextDarwin_arm64
+{
+public:
+
+ RegisterContextKDP_arm64 (ThreadKDP &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextKDP_arm64();
+
+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_arm64_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 000000000000..882b0c2e931d
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp
@@ -0,0 +1,129 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextKDP_i386.h"
+#include "ProcessKDP.h"
+#include "ThreadKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_i386::RegisterContextKDP_i386 (ThreadKDP &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_i386 (thread, concrete_frame_idx),
+ m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_i386::~RegisterContextKDP_i386()
+{
+}
+
+int
+RegisterContextKDP_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
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 000000000000..4b6bc5b262f7
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h
@@ -0,0 +1,53 @@
+//===-- 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 ThreadKDP;
+
+class RegisterContextKDP_i386 : public RegisterContextDarwin_i386
+{
+public:
+ RegisterContextKDP_i386 (ThreadKDP &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);
+
+ ThreadKDP &m_kdp_thread;
+};
+
+#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 000000000000..f4247a5da272
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp
@@ -0,0 +1,127 @@
+//===-- 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
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextKDP_x86_64.h"
+#include "ProcessKDP.h"
+#include "ThreadKDP.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextKDP_x86_64::RegisterContextKDP_x86_64 (ThreadKDP &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_x86_64 (thread, concrete_frame_idx),
+ m_kdp_thread (thread)
+{
+}
+
+RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64()
+{
+}
+
+int
+RegisterContextKDP_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+RegisterContextKDP_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error))
+ {
+ if (error.Success())
+ return 0;
+ }
+ }
+ 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 000000000000..a426349198ff
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h
@@ -0,0 +1,54 @@
+//===-- 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 ThreadKDP;
+
+class RegisterContextKDP_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+
+ RegisterContextKDP_x86_64 (ThreadKDP &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);
+
+ ThreadKDP &m_kdp_thread;
+};
+
+#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 000000000000..3b8bed101a8a
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp
@@ -0,0 +1,211 @@
+//===-- 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 "lldb/Utility/SafeMachO.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/Watchpoint.h"
+
+#include "ProcessKDP.h"
+#include "ProcessKDPLog.h"
+#include "RegisterContextKDP_arm.h"
+#include "RegisterContextKDP_arm64.h"
+#include "RegisterContextKDP_i386.h"
+#include "RegisterContextKDP_x86_64.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadKDP::ThreadKDP (Process &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 (tid = 0x%4.4x)", this, GetID());
+}
+
+ThreadKDP::~ThreadKDP ()
+{
+ ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::~ThreadKDP (tid = 0x%4.4x)", this, GetID());
+ DestroyThread();
+}
+
+const char *
+ThreadKDP::GetName ()
+{
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+const char *
+ThreadKDP::GetQueueName ()
+{
+ return NULL;
+}
+
+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;
+ lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext());
+ if (reg_ctx_sp)
+ reg_ctx_sp->InvalidateIfNeeded (force);
+}
+
+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)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ switch (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().GetCPUType())
+ {
+ case llvm::MachO::CPU_TYPE_ARM:
+ reg_ctx_sp.reset (new RegisterContextKDP_arm (*this, concrete_frame_idx));
+ break;
+ case llvm::MachO::CPU_TYPE_ARM64:
+ reg_ctx_sp.reset (new RegisterContextKDP_arm64 (*this, concrete_frame_idx));
+ break;
+ case llvm::MachO::CPU_TYPE_I386:
+ reg_ctx_sp.reset (new RegisterContextKDP_i386 (*this, concrete_frame_idx));
+ break;
+ case llvm::MachO::CPU_TYPE_X86_64:
+ reg_ctx_sp.reset (new RegisterContextKDP_x86_64 (*this, concrete_frame_idx));
+ break;
+ default:
+ assert (!"Add CPU type support in KDP");
+ break;
+ }
+ }
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadKDP::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ if (m_cached_stop_info_sp)
+ {
+ SetStopInfo (m_cached_stop_info_sp);
+ }
+ else
+ {
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP));
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+ThreadKDP::SetStopInfoFrom_KDP_EXCEPTION (const DataExtractor &exc_reply_packet)
+{
+ lldb::offset_t offset = 0;
+ uint8_t reply_command = exc_reply_packet.GetU8(&offset);
+ if (reply_command == CommunicationKDP::KDP_EXCEPTION)
+ {
+ offset = 8;
+ const uint32_t count = exc_reply_packet.GetU32 (&offset);
+ if (count >= 1)
+ {
+ //const uint32_t cpu = exc_reply_packet.GetU32 (&offset);
+ offset += 4; // Skip the useless CPU field
+ const uint32_t exc_type = exc_reply_packet.GetU32 (&offset);
+ const uint32_t exc_code = exc_reply_packet.GetU32 (&offset);
+ const uint32_t exc_subcode = exc_reply_packet.GetU32 (&offset);
+ // We have to make a copy of the stop info because the thread list
+ // will iterate through the threads and clear all stop infos..
+
+ // Let the StopInfoMachException::CreateStopReasonWithMachException()
+ // function update the PC if needed as we might hit a software breakpoint
+ // and need to decrement the PC (i386 and x86_64 need this) and KDP
+ // doesn't do this for us.
+ const bool pc_already_adjusted = false;
+ const bool adjust_pc_if_needed = true;
+
+ m_cached_stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException (*this,
+ exc_type,
+ 2,
+ exc_code,
+ exc_subcode,
+ 0,
+ pc_already_adjusted,
+ adjust_pc_if_needed);
+ }
+ }
+}
+
diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h
new file mode 100644
index 000000000000..7dc373f03550
--- /dev/null
+++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h
@@ -0,0 +1,98 @@
+//===-- 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 (lldb_private::Process &process,
+ lldb::tid_t tid);
+
+ virtual
+ ~ThreadKDP ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetName ();
+
+ virtual const char *
+ GetQueueName ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ 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;
+ }
+
+ void
+ SetStopInfoFrom_KDP_EXCEPTION (const lldb_private::DataExtractor &exc_reply_packet);
+
+protected:
+
+ friend class ProcessKDP;
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ lldb::StopInfoSP m_cached_stop_info_sp;
+ //------------------------------------------------------------------
+ // Protected member functions.
+ //------------------------------------------------------------------
+ virtual bool
+ CalculateStopInfo ();
+};
+
+#endif // liblldb_ThreadKDP_h_