diff options
-rw-r--r-- | lldb/include/lldb/Core/ConnectionFileDescriptor.h | 14 | ||||
-rw-r--r-- | lldb/include/lldb/Core/DataExtractor.h | 5 | ||||
-rw-r--r-- | lldb/include/lldb/Core/StreamBuffer.h | 83 | ||||
-rw-r--r-- | lldb/include/lldb/Core/StreamString.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/lldb-forward.h | 1 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/project.pbxproj | 2 | ||||
-rw-r--r-- | lldb/source/Core/ConnectionFileDescriptor.cpp | 179 | ||||
-rw-r--r-- | lldb/source/Core/DataExtractor.cpp | 17 | ||||
-rw-r--r-- | lldb/source/Core/StreamString.cpp | 8 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp | 310 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h | 146 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp | 1 |
12 files changed, 607 insertions, 162 deletions
diff --git a/lldb/include/lldb/Core/ConnectionFileDescriptor.h b/lldb/include/lldb/Core/ConnectionFileDescriptor.h index 6413a2bee78..2b5932dff2c 100644 --- a/lldb/include/lldb/Core/ConnectionFileDescriptor.h +++ b/lldb/include/lldb/Core/ConnectionFileDescriptor.h @@ -11,6 +11,10 @@ #define liblldb_ConnectionFileDescriptor_h_ // C Includes +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> + // C++ Includes // Other libraries and framework includes // Project includes @@ -75,8 +79,16 @@ protected: lldb::ConnectionStatus Close (int& fd, Error *error); + typedef enum + { + eFDTypeFile, // Other FD requireing read/write + eFDTypeSocket, // Socket requiring send/recv + eFDTypeSocketUDP // Unconnected UDP socket requiring sendto/recvfrom + } FDType; int m_fd; // Socket we use to communicate once conn established - bool m_is_socket; + FDType m_fd_type; + struct sockaddr_storage m_udp_sockaddr; + socklen_t m_udp_sockaddr_len; bool m_should_close_fd; // True if this class should close the file descriptor when it goes away. uint32_t m_socket_timeout_usec; diff --git a/lldb/include/lldb/Core/DataExtractor.h b/lldb/include/lldb/Core/DataExtractor.h index e4ec102d1e8..c1963c00e1e 100644 --- a/lldb/include/lldb/Core/DataExtractor.h +++ b/lldb/include/lldb/Core/DataExtractor.h @@ -54,6 +54,11 @@ public: TypeSLEB128 ///< Format output as SLEB128 numbers } Type; + static void + DumpHexBytes (Stream *s, + const void *src, + size_t src_len, + lldb::addr_t base_addr = LLDB_INVALID_ADDRESS); //------------------------------------------------------------------ /// Default constructor. /// diff --git a/lldb/include/lldb/Core/StreamBuffer.h b/lldb/include/lldb/Core/StreamBuffer.h new file mode 100644 index 00000000000..e9cd756be2a --- /dev/null +++ b/lldb/include/lldb/Core/StreamBuffer.h @@ -0,0 +1,83 @@ +//===-- StreamBuffer.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_StreamBuffer_h_ +#define liblldb_StreamBuffer_h_ + +#include <stdio.h> +#include <string> +#include "llvm/ADT/SmallVector.h" +#include "lldb/Core/Stream.h" + +namespace lldb_private { + +template <unsigned N> +class StreamBuffer : public Stream +{ +public: + StreamBuffer () : + Stream (0, 4, lldb::eByteOrderBig), + m_packet () + { + } + + + StreamBuffer (uint32_t flags, + uint32_t addr_size, + lldb::ByteOrder byte_order) : + Stream (flags, addr_size, byte_order), + m_packet () + { + } + + virtual + ~StreamBuffer () + { + } + + virtual void + Flush () + { + // Nothing to do when flushing a buffer based stream... + } + + virtual int + Write (const void *s, size_t length) + { + if (s && length) + m_packet.append ((const char *)s, ((const char *)s) + length); + return length; + } + + void + Clear() + { + m_packet.clear(); + } + + const char * + GetData () const + { + return m_packet.data(); + } + + size_t + GetSize() const + { + return m_packet.size(); + } + +protected: + llvm::SmallVector<char, N> m_packet; + +}; + +} // namespace lldb_private + +#endif // #ifndef liblldb_StreamBuffer_h_ diff --git a/lldb/include/lldb/Core/StreamString.h b/lldb/include/lldb/Core/StreamString.h index 699c7493fe9..ccb84b033ce 100644 --- a/lldb/include/lldb/Core/StreamString.h +++ b/lldb/include/lldb/Core/StreamString.h @@ -37,9 +37,6 @@ public: void Clear(); - void - Dump(FILE *f); - const char * GetData () const; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 9d616d19cc6..c476a1d01c8 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -129,6 +129,7 @@ class Stoppoint; class StoppointCallbackContext; class StoppointLocation; class Stream; +template <unsigned N> class StreamBuffer; class StreamFile; class StreamString; class StringList; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index d187845ab4f..354335e4d9f 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -638,6 +638,7 @@ 261B5A5311C3F2AD00AABD0A /* SharingPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingPtr.h; path = include/lldb/Utility/SharingPtr.h; sourceTree = "<group>"; }; 26217930133BC8640083B112 /* lldb-private-types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-private-types.h"; path = "include/lldb/lldb-private-types.h"; sourceTree = "<group>"; }; 26217932133BCB850083B112 /* lldb-private-enumerations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-private-enumerations.h"; path = "include/lldb/lldb-private-enumerations.h"; sourceTree = "<group>"; }; + 2623096E13D0EFFB006381D9 /* StreamBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = StreamBuffer.h; path = include/lldb/Core/StreamBuffer.h; sourceTree = "<group>"; }; 263664921140A4930075843B /* Debugger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Debugger.cpp; path = source/Core/Debugger.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; 263664941140A4C10075843B /* Debugger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Debugger.h; path = include/lldb/Core/Debugger.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 26368A3B126B697600E8659F /* darwin-debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "darwin-debug.cpp"; path = "tools/darwin-debug/darwin-debug.cpp"; sourceTree = "<group>"; }; @@ -2003,6 +2004,7 @@ 26BC7E9110F1B85900F91463 /* Stream.cpp */, 9A4F35111368A54100823F52 /* StreamAsynchronousIO.h */, 9A4F350F1368A51A00823F52 /* StreamAsynchronousIO.cpp */, + 2623096E13D0EFFB006381D9 /* StreamBuffer.h */, 26BC7D7A10F1B77400F91463 /* StreamFile.h */, 26BC7E9210F1B85900F91463 /* StreamFile.cpp */, 26BC7D7B10F1B77400F91463 /* StreamString.h */, diff --git a/lldb/source/Core/ConnectionFileDescriptor.cpp b/lldb/source/Core/ConnectionFileDescriptor.cpp index f5375ca6cdf..f8d44eeb2da 100644 --- a/lldb/source/Core/ConnectionFileDescriptor.cpp +++ b/lldb/source/Core/ConnectionFileDescriptor.cpp @@ -38,33 +38,42 @@ using namespace lldb_private; ConnectionFileDescriptor::ConnectionFileDescriptor () : Connection(), m_fd (-1), - m_is_socket (false), + m_fd_type (eFDTypeFile), + m_udp_sockaddr (), + m_udp_sockaddr_len (0), m_should_close_fd (false), m_socket_timeout_usec(0) { + memset (&m_udp_sockaddr, 0, sizeof(m_udp_sockaddr)); + lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, - "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", - this); + "%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", + this); } ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) : Connection(), m_fd (fd), - m_is_socket (false), + m_fd_type (eFDTypeFile), + m_udp_sockaddr (), + m_udp_sockaddr_len (0), m_should_close_fd (owns_fd), m_socket_timeout_usec(0) { + memset (&m_udp_sockaddr, 0, sizeof(m_udp_sockaddr)); lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, - "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", - this, fd, owns_fd); + "%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", + this, + fd, + owns_fd); } ConnectionFileDescriptor::~ConnectionFileDescriptor () { lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, - "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", - this); + "%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", + this); Disconnect (NULL); } @@ -78,8 +87,9 @@ ConnectionStatus ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) { lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, - "%p ConnectionFileDescriptor::Connect (url = '%s')", - this, s); + "%p ConnectionFileDescriptor::Connect (url = '%s')", + this, + s); if (s && s[0]) { @@ -134,7 +144,9 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) // Try and get a socket option from this file descriptor to // see if this is a socket and set m_is_socket accordingly. int resuse; - m_is_socket = GetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, resuse) == 0; + bool is_socket = GetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, resuse) == 0; + if (is_socket) + m_fd_type = eFDTypeSocket; m_should_close_fd = true; return eConnectionStatusSuccess; } @@ -204,28 +216,40 @@ ConnectionFileDescriptor::Read (void *dst, log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu)...", this, m_fd, dst, dst_len); - if (timeout_usec == UINT32_MAX) + ssize_t bytes_read = 0; + struct sockaddr_storage from; + socklen_t from_len = sizeof(from); + + switch (m_fd_type) { - if (m_is_socket && SetSocketReceiveTimeout (timeout_usec)) + case eFDTypeFile: // Other FD requireing read/write + status = BytesAvailable (timeout_usec, error_ptr); + if (status == eConnectionStatusSuccess) + bytes_read = ::read (m_fd, dst, dst_len); + break; + + case eFDTypeSocket: // Socket requiring send/recv + if (SetSocketReceiveTimeout (timeout_usec)) + { status = eConnectionStatusSuccess; - } - else - { - if (m_is_socket && SetSocketReceiveTimeout (timeout_usec)) + bytes_read = ::recv (m_fd, dst, dst_len, 0); + } + break; + + case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom + if (SetSocketReceiveTimeout (timeout_usec)) + { status = eConnectionStatusSuccess; - else - status = BytesAvailable (timeout_usec, error_ptr); + ::memset (&from, 0, sizeof(from)); + bytes_read = ::recvfrom (m_fd, dst, dst_len, 0, (struct sockaddr *)&from, &from_len); + } + break; } + if (status != eConnectionStatusSuccess) return 0; Error error; - ssize_t bytes_read; - if (m_is_socket) - bytes_read = ::recv (m_fd, dst, dst_len, 0); - else - bytes_read = ::read (m_fd, dst, dst_len); - if (bytes_read == 0) { error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers. @@ -319,10 +343,26 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat ssize_t bytes_sent = 0; - if (m_is_socket) - bytes_sent = ::send (m_fd, src, src_len, 0); - else - bytes_sent = ::write (m_fd, src, src_len); + switch (m_fd_type) + { + case eFDTypeFile: // Other FD requireing read/write + bytes_sent = ::write (m_fd, src, src_len); + break; + + case eFDTypeSocket: // Socket requiring send/recv + bytes_sent = ::send (m_fd, src, src_len, 0); + break; + + case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom + assert (m_udp_sockaddr_len != 0); + bytes_sent = ::sendto (m_fd, + src, + src_len, + 0, + (struct sockaddr *)&m_udp_sockaddr, + m_udp_sockaddr_len); + break; + } if (bytes_sent < 0) error.SetErrorToErrno (); @@ -331,12 +371,38 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat if (log) { - if (m_is_socket) - log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)", - this, m_fd, src, src_len, bytes_sent, error.AsCString()); - else - log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)", - this, m_fd, src, src_len, bytes_sent, error.AsCString()); + switch (m_fd_type) + { + case eFDTypeFile: // Other FD requireing read/write + log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)", + this, + m_fd, + src, + src_len, + bytes_sent, + error.AsCString()); + break; + + case eFDTypeSocket: // Socket requiring send/recv + log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)", + this, + m_fd, + src, + src_len, + bytes_sent, + error.AsCString()); + break; + + case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom + log->Printf ("%p ConnectionFileDescriptor::Write() ::sendto (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)", + this, + m_fd, + src, + src_len, + bytes_sent, + error.AsCString()); + break; + } } if (error_ptr) @@ -477,7 +543,7 @@ ConnectionFileDescriptor::Close (int& fd, Error *error_ptr) } fd = -1; } - m_is_socket = false; + m_fd_type = eFDTypeFile; if (success) return eConnectionStatusSuccess; else @@ -490,7 +556,7 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err ConnectionStatus result = eConnectionStatusError; struct sockaddr_un saddr_un; - m_is_socket = true; + m_fd_type = eFDTypeSocket; int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0); if (listen_socket == -1) @@ -537,7 +603,7 @@ ConnectionStatus ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr) { Close (m_fd, NULL); - m_is_socket = true; + m_fd_type = eFDTypeSocket; // Open the socket that was passed in as an option struct sockaddr_un saddr_un; @@ -576,7 +642,7 @@ ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_p this, listen_port_num); Close (m_fd, NULL); - m_is_socket = true; + m_fd_type = eFDTypeSocket; int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_port == -1) { @@ -640,7 +706,7 @@ ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_pt "%p ConnectionFileDescriptor::ConnectTCP (host/port = %s)", this, host_and_port); Close (m_fd, NULL); - m_is_socket = true; + m_fd_type = eFDTypeSocket; RegularExpression regex ("([^:]+):([0-9]+)"); if (regex.Execute (host_and_port, 2) == false) @@ -730,7 +796,7 @@ ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_pt "%p ConnectionFileDescriptor::ConnectUDP (host/port = %s)", this, host_and_port); Close (m_fd, NULL); - m_is_socket = true; + m_fd_type = eFDTypeSocketUDP; RegularExpression regex ("([^:]+):([0-9]+)"); if (regex.Execute (host_and_port, 2) == false) @@ -839,20 +905,27 @@ ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, in bool ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec) { - if (m_is_socket) + switch (m_fd_type) { - // Check in case timeout for m_fd has already been set to this value - if (timeout_usec == m_socket_timeout_usec) - return true; - //printf ("ConnectionFileDescriptor::SetSocketReceiveTimeout (timeout_usec = %u)\n", timeout_usec); - - struct timeval timeout; - timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec; - timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec; - if (::setsockopt (m_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0) + case eFDTypeFile: // Other FD requireing read/write + break; + + case eFDTypeSocket: // Socket requiring send/recv + case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom { - m_socket_timeout_usec = timeout_usec; - return true; + // Check in case timeout for m_fd has already been set to this value + if (timeout_usec == m_socket_timeout_usec) + return true; + //printf ("ConnectionFileDescriptor::SetSocketReceiveTimeout (timeout_usec = %u)\n", timeout_usec); + + struct timeval timeout; + timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec; + timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec; + if (::setsockopt (m_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0) + { + m_socket_timeout_usec = timeout_usec; + return true; + } } } return false; diff --git a/lldb/source/Core/DataExtractor.cpp b/lldb/source/Core/DataExtractor.cpp index aea0c471fcb..9518b44cffb 100644 --- a/lldb/source/Core/DataExtractor.cpp +++ b/lldb/source/Core/DataExtractor.cpp @@ -1789,4 +1789,19 @@ DataExtractor::DumpUUID (Stream *s, uint32_t offset) const } } - +void +DataExtractor::DumpHexBytes (Stream *s, + const void *src, + size_t src_len, + addr_t base_addr) +{ + DataExtractor data (src, src_len, eByteOrderLittle, 4); + data.Dump (s, + 0, // Offset into "src" + eFormatBytes, // Dump as hex bytes + 1, // Size of each item is 1 for single bytes + src_len, // Number of bytes + 32, // Num bytes per line + base_addr, // Base address + 0, 0); // Bitfield info +} diff --git a/lldb/source/Core/StreamString.cpp b/lldb/source/Core/StreamString.cpp index 44472ade75c..54ca278b8b8 100644 --- a/lldb/source/Core/StreamString.cpp +++ b/lldb/source/Core/StreamString.cpp @@ -47,14 +47,6 @@ StreamString::Clear() m_packet.clear(); } -void -StreamString::Dump(FILE *f) -{ - int size = GetSize(); - if (size > 0) - fprintf(f, "%*.*s", size, size, m_packet.c_str()); -} - const char * StreamString::GetData () const { diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp index 2287e40a867..06096afb046 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp @@ -16,14 +16,13 @@ // 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/StreamString.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" #include "lldb/Target/Process.h" -#include "Utility/StringExtractor.h" // Project includes #include "ProcessKDPLog.h" @@ -38,13 +37,19 @@ using namespace lldb_private; //---------------------------------------------------------------------- CommunicationKDP::CommunicationKDP (const char *comm_name) : Communication(comm_name), + m_byte_order (eByteOrderLittle), m_packet_timeout (1), m_sequence_mutex (Mutex::eMutexTypeRecursive), m_public_is_running (false), m_private_is_running (false), - m_session_key (0), - m_request_sequence_id (0), - m_exception_sequence_id (0) + 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) { } @@ -60,27 +65,61 @@ CommunicationKDP::~CommunicationKDP() } bool -CommunicationKDP::SendRequestPacket (const StreamString &request_packet) +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 (RequestType request_type, - StreamString &request_packet) +CommunicationKDP::MakeRequestPacketHeader (CommandType request_type, + PacketStreamType &request_packet, + uint16_t request_length) { request_packet.Clear(); - request_packet.PutHex32 (request_type); // Set the request type - request_packet.PutHex8 (ePacketTypeRequest); // Set the packet type - request_packet.PutHex8 (++m_request_sequence_id); // Sequence number - request_packet.PutHex16 (0); // Pad1 and Pad2 bytes - request_packet.PutHex32 (m_session_key); // Session key + 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 uint8_t request_sequence_id, + const PacketStreamType &request_packet, + DataExtractor &reply_packet) +{ + + Mutex::Locker locker(m_sequence_mutex); + if (SendRequestPacketNoLock(request_packet)) + { + if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, m_packet_timeout)) + { + uint32_t offset = 0; + const uint8_t reply_command = reply_packet.GetU8 (&offset); + const uint8_t reply_sequence_id = reply_packet.GetU8 (&offset); + if ((reply_command & eCommandTypeMask) == command) + { + if (request_sequence_id == reply_sequence_id) + return true; + } + } + } + reply_packet.Clear(); + return false; +} bool -CommunicationKDP::SendRequestPacketNoLock (const StreamString &request_packet) +CommunicationKDP::SendRequestPacketNoLock (const PacketStreamType &request_packet) { if (IsConnected()) { @@ -90,22 +129,11 @@ CommunicationKDP::SendRequestPacketNoLock (const StreamString &request_packet) LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS)); if (log) { - StreamString log_strm; - DataExtractor data (packet_data, - packet_size, - request_packet.GetByteOrder(), - request_packet.GetAddressByteSize()); - data.Dump (&log_strm, - 0, - eFormatBytes, - 1, - packet_size, - 32, // Num bytes per line - 0, // Base address - 0, - 0); + PacketStreamType log_strm; - log->Printf("request packet: <%u>\n%s", packet_size, log_strm.GetString().c_str()); + DataExtractor::DumpHexBytes (&log_strm, packet_data, packet_size, 0); + + log->Printf("request packet: <%u>\n%s", packet_size, log_strm.GetData()); } ConnectionStatus status = eConnectionStatusSuccess; @@ -137,14 +165,14 @@ CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) } size_t -CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (StringExtractor &packet, uint32_t timeout_usec) +CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (DataExtractor &packet, uint32_t timeout_usec) { Mutex::Locker locker(m_sequence_mutex); return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); } size_t -CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractor &packet, uint32_t timeout_usec) +CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (DataExtractor &packet, uint32_t timeout_usec) { uint8_t buffer[8192]; Error error; @@ -153,7 +181,7 @@ CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractor &p // Check for a packet from our cache first without trying any reading... if (CheckForPacket (NULL, 0, packet)) - return packet.GetStringRef().size(); + return packet.GetByteSize(); bool timed_out = false; while (IsConnected() && !timed_out) @@ -172,7 +200,7 @@ CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractor &p if (bytes_read > 0) { if (CheckForPacket (buffer, bytes_read, packet)) - return packet.GetStringRef().size(); + return packet.GetByteSize(); } else { @@ -199,7 +227,7 @@ CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractor &p } bool -CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractor &packet) +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); @@ -210,43 +238,229 @@ CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, StringExtr { if (log && log->GetVerbose()) { - StreamString s; - log->Printf ("CommunicationKDP::%s adding %u bytes: %.*s", + PacketStreamType log_strm; + DataExtractor::DumpHexBytes (&log_strm, src, src_len, 0); + log->Printf ("CommunicationKDP::%s adding %u bytes: %s", __FUNCTION__, (uint32_t)src_len, - (uint32_t)src_len, - src); + log_strm.GetData()); } m_bytes.append ((const char *)src, src_len); } - // Parse up the packets into gdb remote packets - if (!m_bytes.empty()) + // Make sure we at least have enough bytes for a packet header + const size_t bytes_available = m_bytes.size(); + if (bytes_available >= 8) { - // TODO: Figure out if we have a full packet reply + packet.SetData (&m_bytes[0], bytes_available, m_byte_order); + uint32_t offset = 0; + uint8_t reply_command = packet.GetU8(&offset); + switch (reply_command) + { + case ePacketTypeReply | eCommandTypeConnect: + case ePacketTypeReply | eCommandTypeDisconnect: + case ePacketTypeReply | eCommandTypeHostInfo: + case ePacketTypeReply | eCommandTypeVersion: + case ePacketTypeReply | eCommandTypeMaxBytes: + case ePacketTypeReply | eCommandTypeReadMemory: + case ePacketTypeReply | eCommandTypeWriteMemory: + case ePacketTypeReply | eCommandTypeReadRegisters: + case ePacketTypeReply | eCommandTypeWriteRegisters: + case ePacketTypeReply | eCommandTypeLoad: + case ePacketTypeReply | eCommandTypeImagePath: + case ePacketTypeReply | eCommandTypeSuspend: + case ePacketTypeReply | eCommandTypeResume: + case ePacketTypeReply | eCommandTypeException: + case ePacketTypeReply | eCommandTypeTermination: + case ePacketTypeReply | eCommandTypeBreakpointSet: + case ePacketTypeReply | eCommandTypeBreakpointRemove: + case ePacketTypeReply | eCommandTypeRegions: + case ePacketTypeReply | eCommandTypeReattach: + case ePacketTypeReply | eCommandTypeHostReboot: + case ePacketTypeReply | eCommandTypeReadMemory64: + case ePacketTypeReply | eCommandTypeWriteMemory64: + case ePacketTypeReply | eCommandTypeBreakpointSet64: + case ePacketTypeReply | eCommandTypeBreakpointRemove64: + case ePacketTypeReply | eCommandTypeKernelVersion: + { + 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); + 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; } -CommunicationKDP::ErrorType +bool CommunicationKDP::Connect (uint16_t reply_port, uint16_t exc_port, const char *greeting) { - StreamString request_packet (Stream::eBinary, 4, eByteOrderLittle); - MakeRequestPacketHeader (eRequestTypeConnect, request_packet); + PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + if (greeting == NULL) + greeting = ""; + + const CommandType command = eCommandTypeConnect; + // Length is 82 uint16_t and the length of the greeting C string + const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting); + const uint32_t request_sequence_id = m_request_sequence_id; + MakeRequestPacketHeader (command, request_packet, command_length); request_packet.PutHex16(reply_port); request_packet.PutHex16(exc_port); request_packet.PutCString(greeting); - - return eErrorUnimplemented; + DataExtractor reply_packet; + return SendRequestAndGetReply (command, request_sequence_id, 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::Reattach (uint16_t reply_port) +{ + PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + const CommandType command = eCommandTypeReattach; + // Length is 8 bytes for the header plus 2 bytes for the reply UDP port + const uint32_t command_length = 8 + 2; + const uint32_t request_sequence_id = m_request_sequence_id; + MakeRequestPacketHeader (command, request_packet, command_length); + request_packet.PutHex16(reply_port); + DataExtractor reply_packet; + if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet)) + { + // Reset the sequence ID to zero for reattach + ClearKDPSettings (); + uint32_t offset = 4; + m_session_key = reply_packet.GetU32 (&offset); + return true; + } + return false; } -CommunicationKDP::ErrorType +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, 4, m_byte_order); + const CommandType command = eCommandTypeVersion; + const uint32_t command_length = 8; + const uint32_t request_sequence_id = m_request_sequence_id; + MakeRequestPacketHeader (command, request_packet, command_length); + DataExtractor reply_packet; + if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet)) + { + // Reset the sequence ID to zero for reattach + uint32_t offset = 8; + m_kdp_version_version = reply_packet.GetU32 (&offset); + m_kdp_version_feature = reply_packet.GetU32 (&offset); + return true; + } + return false; +} + +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; +} + +bool +CommunicationKDP::SendRequestHostInfo () +{ + PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + const CommandType command = eCommandTypeHostInfo; + const uint32_t command_length = 8; + const uint32_t request_sequence_id = m_request_sequence_id; + MakeRequestPacketHeader (command, request_packet, command_length); + DataExtractor reply_packet; + if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet)) + { + // Reset the sequence ID to zero for reattach + uint32_t offset = 8; + 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); + return true; + } + return false; +} + +bool CommunicationKDP::Disconnect () { - return eErrorUnimplemented; + PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); + const CommandType command = eCommandTypeDisconnect; + const uint32_t command_length = 8; + const uint32_t request_sequence_id = m_request_sequence_id; + MakeRequestPacketHeader (command, request_packet, command_length); + DataExtractor reply_packet; + if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet)) + { + // Are we supposed to get a reply for disconnect? + } + ClearKDPSettings (); + return true; } diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h index c0c7b08ccf7..44456080e39 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h @@ -20,12 +20,11 @@ #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 StringExtractor; - class CommunicationKDP : public lldb_private::Communication { public: @@ -36,49 +35,50 @@ public: const static uint32_t kMaxPacketSize = 1200; const static uint32_t kMaxDataSize = 1024; - + typedef lldb_private::StreamBuffer<1024> PacketStreamType; typedef enum { - eRequestTypeConnect = 0u, - eRequestTypeDisconnect, - eRequestTypeHostInfo, - eRequestTypeVersion, - eRequestTypeMaxBytes, - eRequestTypeReadMemory, - eRequestTypeWriteMemory, - eRequestTypeReadRegisters, - eRequestTypeWriteRegisters, - eRequestTypeLoad, - eRequestTypeImagePath, - eRequestTypeSuspend, - eRequestTypeResume, - eRequestTypeException, - eRequestTypeTermination, - eRequestTypeBreakpointSet, - eRequestTypeBreakpointRemove, - eRequestTypeRegions, - eRequestTypeReattach, - eRequestTypeHostReboot, - eRequestTypeReadMemory64, - eRequestTypeWriteMemory64, - eRequestTypeBreakpointSet64, - eRequestTypeBreakpointRemove64, - eRequestTypeKernelVersion - } RequestType; + eCommandTypeConnect = 0u, + eCommandTypeDisconnect, + eCommandTypeHostInfo, + eCommandTypeVersion, + eCommandTypeMaxBytes, + eCommandTypeReadMemory, + eCommandTypeWriteMemory, + eCommandTypeReadRegisters, + eCommandTypeWriteRegisters, + eCommandTypeLoad, + eCommandTypeImagePath, + eCommandTypeSuspend, + eCommandTypeResume, + eCommandTypeException, + eCommandTypeTermination, + eCommandTypeBreakpointSet, + eCommandTypeBreakpointRemove, + eCommandTypeRegions, + eCommandTypeReattach, + eCommandTypeHostReboot, + eCommandTypeReadMemory64, + eCommandTypeWriteMemory64, + eCommandTypeBreakpointSet64, + eCommandTypeBreakpointRemove64, + eCommandTypeKernelVersion + } CommandType; - typedef enum + typedef enum { - eErrorSuccess = 0, - eErrorAlreadyConnected, - eErrorPacketToBig, - eErrorInvalidRegisterFlavor, - eErrorUnimplemented - } ErrorType; + KDP_PROTERR_SUCCESS = 0, + KDP_PROTERR_ALREADY_CONNECTED, + KDP_PROTERR_BAD_NBYTES, + KDP_PROTERR_BADFLAVOR + } KDPError; typedef enum { - ePacketTypeRequest = 0u, - ePacketTypeReply = 1u + ePacketTypeRequest = 0x00u, + ePacketTypeReply = 0x80u, + ePacketTypeMask = 0x80u, + eCommandTypeMask = 0x7fu } PacketType; //------------------------------------------------------------------ // Constructors and Destructors @@ -89,11 +89,11 @@ public: ~CommunicationKDP(); bool - SendRequestPacket (const lldb_private::StreamString &request_packet); + SendRequestPacket (const PacketStreamType &request_packet); // Wait for a packet within 'nsec' seconds size_t - WaitForPacketWithTimeoutMicroSeconds (StringExtractor &response, + WaitForPacketWithTimeoutMicroSeconds (lldb_private::DataExtractor &response, uint32_t usec); bool @@ -102,7 +102,7 @@ public: bool CheckForPacket (const uint8_t *src, size_t src_len, - StringExtractor &packet); + lldb_private::DataExtractor &packet); bool IsRunning() const { @@ -140,34 +140,81 @@ public: lldb_private::ProcessLaunchInfo &launch_info); - ErrorType + bool Connect (uint16_t reply_port, uint16_t exc_port, const char *greeting); - ErrorType + bool + Reattach (uint16_t reply_port); + + bool Disconnect (); + + uint32_t + GetVersion (); + + uint32_t + GetFeatureFlags (); + + uint32_t + GetCPUMask (); + + uint32_t + GetCPUType (); + + uint32_t + GetCPUSubtype (); protected: typedef std::list<std::string> packet_collection; bool - SendRequestPacketNoLock (const lldb_private::StreamString &request_packet); + SendRequestPacketNoLock (const PacketStreamType &request_packet); size_t - WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractor &response, + WaitForPacketWithTimeoutMicroSecondsNoLock (lldb_private::DataExtractor &response, uint32_t timeout_usec); bool WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr); void - MakeRequestPacketHeader (RequestType request_type, - lldb_private::StreamString &request_packet); + MakeRequestPacketHeader (CommandType request_type, + PacketStreamType &request_packet, + uint16_t request_length); + bool + SendRequestVersion (); + + + bool + VersionIsValid() const + { + return m_kdp_version_version != 0; + } + + bool + HostInfoIsValid() const + { + return m_kdp_hostinfo_cpu_type != 0; + } + + bool + SendRequestHostInfo (); + + void + ClearKDPSettings (); + + bool + SendRequestAndGetReply (const CommandType command, + const uint8_t request_sequence_id, + const PacketStreamType &request_packet, + lldb_private::DataExtractor &reply_packet); //------------------------------------------------------------------ // Classes that inherit from CommunicationKDP can see and modify these //------------------------------------------------------------------ + 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_public_is_running; @@ -175,6 +222,11 @@ protected: 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; private: //------------------------------------------------------------------ // For CommunicationKDP only diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index 9e199c14334..1e3158d2cad 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -63,7 +63,6 @@ ProcessKDP::CanDebug(Target &target) if (triple_ref.getOS() == llvm::Triple::Darwin && triple_ref.getVendor() == llvm::Triple::Apple) { - ObjectFile *exe_objfile = exe_module_sp->GetObjectFile(); if (exe_objfile->GetType() == ObjectFile::eTypeExecutable && exe_objfile->GetStrata() == ObjectFile::eStrataKernel) |