Added a boolean to the pure virtual lldb_private::Process::CanDebug(...)

method so process plug-ins that are requested by name can answer yes when
asked if they can debug a target that might not have any file in the target.

Modified the ConnectionFileDescriptor to have both a read and a write file
descriptor. This allows us to support UDP, and eventually will allow us to
support pipes. The ConnectionFileDescriptor class also has a file descriptor
type for each of the read and write file decriptors so we can use the correct
read/recv/recvfrom call when reading, or write/send/sendto for writing.

Finished up an initial implementation of UDP where you can use the "udp://"
URL to specify a host and port to connect to:

(lldb) process connect --plugin kdp-remote udp://host:41139

This will cause a ConnectionFileDescriptor to be created that can send UDP
packets to "host:41139", and it will also bind to a localhost port that can
be given out to receive the connectionless UDP reply. 

Added the ability to get to the IPv4/IPv6 socket port number from a 
ConnectionFileDescriptor instance if either file descriptor is a socket.

The ProcessKDP can now successfully connect to a remote kernel and detach
using the above "processs connect" command!!! So far we have the following
packets working:
    KDP_CONNECT
    KDP_DISCONNECT
    KDP_HOSTINFO
    KDP_VERSION
    KDP_REATTACH

Now that the packets are working, adding new packets will go very quickly.

llvm-svn: 135363
This commit is contained in:
Greg Clayton 2011-07-17 20:36:25 +00:00
parent 76d51c6c89
commit 3a29bdbe9b
16 changed files with 444 additions and 237 deletions

View File

@ -167,6 +167,12 @@ public:
bool bool
HasConnection () const; HasConnection () const;
lldb_private::Connection *
GetConnection ()
{
return m_connection_sp.get();
}
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Read bytes from the current connection. /// Read bytes from the current connection.
/// ///

View File

@ -56,6 +56,16 @@ public:
lldb::ConnectionStatus &status, lldb::ConnectionStatus &status,
Error *error_ptr); Error *error_ptr);
// If the read file descriptor is a socket, then return
// the port number that is being used by the socket.
in_port_t
GetReadPort () const;
// If the write file descriptor is a socket, then return
// the port number that is being used by the socket.
in_port_t
GetWritePort () const;
protected: protected:
lldb::ConnectionStatus lldb::ConnectionStatus
@ -68,7 +78,7 @@ protected:
ConnectTCP (const char *host_and_port, Error *error_ptr); ConnectTCP (const char *host_and_port, Error *error_ptr);
lldb::ConnectionStatus lldb::ConnectionStatus
ConnectUDP (const char *host_and_port, Error *error_ptr); ConnectUDP (const char *args, Error *error_ptr);
lldb::ConnectionStatus lldb::ConnectionStatus
NamedSocketAccept (const char *socket_name, Error *error_ptr); NamedSocketAccept (const char *socket_name, Error *error_ptr);
@ -85,13 +95,27 @@ protected:
eFDTypeSocket, // Socket requiring send/recv eFDTypeSocket, // Socket requiring send/recv
eFDTypeSocketUDP // Unconnected UDP socket requiring sendto/recvfrom eFDTypeSocketUDP // Unconnected UDP socket requiring sendto/recvfrom
} FDType; } FDType;
int m_fd; // Socket we use to communicate once conn established
FDType m_fd_type; typedef union sockaddr_tag
struct sockaddr_storage m_udp_sockaddr; {
socklen_t m_udp_sockaddr_len; struct sockaddr sa;
struct sockaddr_in sa_ipv4;
struct sockaddr_in6 sa_ipv6;
struct sockaddr_storage sa_storage;
} sockaddr_t;
int m_fd_send;
int m_fd_recv;
FDType m_fd_send_type;
FDType m_fd_recv_type;
sockaddr_t m_udp_send_sockaddr;
bool m_should_close_fd; // True if this class should close the file descriptor when it goes away. bool m_should_close_fd; // True if this class should close the file descriptor when it goes away.
uint32_t m_socket_timeout_usec; uint32_t m_socket_timeout_usec;
static in_port_t
GetSocketPort (int fd);
static int static int
GetSocketOption(int fd, int level, int option_name, int &option_value); GetSocketOption(int fd, int level, int option_name, int &option_value);

View File

@ -58,7 +58,8 @@ public:
DumpHexBytes (Stream *s, DumpHexBytes (Stream *s,
const void *src, const void *src,
size_t src_len, size_t src_len,
lldb::addr_t base_addr = LLDB_INVALID_ADDRESS); uint32_t bytes_per_line,
lldb::addr_t base_addr); // Pass LLDB_INVALID_ADDRESS to not show address at start of line
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Default constructor. /// Default constructor.
/// ///

View File

@ -1169,7 +1169,8 @@ public:
/// debug the executable, \b false otherwise. /// debug the executable, \b false otherwise.
//------------------------------------------------------------------ //------------------------------------------------------------------
virtual bool virtual bool
CanDebug (Target &target) = 0; CanDebug (Target &target,
bool plugin_specified_by_name) = 0;
//------------------------------------------------------------------ //------------------------------------------------------------------

View File

@ -35,61 +35,88 @@
using namespace lldb; using namespace lldb;
using namespace lldb_private; using namespace lldb_private;
static bool
DecodeHostAndPort (const char *host_and_port,
std::string &host_str,
std::string &port_str,
int32_t& port,
Error *error_ptr)
{
RegularExpression regex ("([^:]+):([0-9]+)");
if (regex.Execute (host_and_port, 2))
{
if (regex.GetMatchAtIndex (host_and_port, 1, host_str) &&
regex.GetMatchAtIndex (host_and_port, 2, port_str))
{
port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
if (port != INT32_MIN)
{
if (error_ptr)
error_ptr->Clear();
return true;
}
}
}
host_str.clear();
port_str.clear();
port = INT32_MIN;
if (error_ptr)
error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port);
return false;
}
ConnectionFileDescriptor::ConnectionFileDescriptor () : ConnectionFileDescriptor::ConnectionFileDescriptor () :
Connection(), Connection(),
m_fd (-1), m_fd_send (-1),
m_fd_type (eFDTypeFile), m_fd_recv (-1),
m_udp_sockaddr (), m_fd_send_type (eFDTypeFile),
m_udp_sockaddr_len (0), m_fd_recv_type (eFDTypeFile),
m_should_close_fd (false), m_should_close_fd (false),
m_socket_timeout_usec(0) m_socket_timeout_usec(0)
{ {
memset (&m_udp_sockaddr, 0, sizeof(m_udp_sockaddr)); memset (&m_udp_send_sockaddr, 0, sizeof(m_udp_send_sockaddr));
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
"%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", if (log)
this); log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", this);
} }
ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) : ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
Connection(), Connection(),
m_fd (fd), m_fd_send (fd),
m_fd_type (eFDTypeFile), m_fd_recv (fd),
m_udp_sockaddr (), m_fd_send_type (eFDTypeFile),
m_udp_sockaddr_len (0), m_fd_recv_type (eFDTypeFile),
m_should_close_fd (owns_fd), m_should_close_fd (owns_fd),
m_socket_timeout_usec(0) m_socket_timeout_usec(0)
{ {
memset (&m_udp_sockaddr, 0, sizeof(m_udp_sockaddr)); memset (&m_udp_send_sockaddr, 0, sizeof(m_udp_send_sockaddr));
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
"%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", if (log)
this, log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", this, fd, owns_fd);
fd,
owns_fd);
} }
ConnectionFileDescriptor::~ConnectionFileDescriptor () ConnectionFileDescriptor::~ConnectionFileDescriptor ()
{ {
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
"%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", if (log)
this); log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", this);
Disconnect (NULL); Disconnect (NULL);
} }
bool bool
ConnectionFileDescriptor::IsConnected () const ConnectionFileDescriptor::IsConnected () const
{ {
return m_fd >= 0; return m_fd_send >= 0 || m_fd_recv >= 0;
} }
ConnectionStatus ConnectionStatus
ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
{ {
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
"%p ConnectionFileDescriptor::Connect (url = '%s')", if (log)
this, log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')", this, s);
s);
if (s && s[0]) if (s && s[0])
{ {
@ -109,9 +136,9 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
{ {
return ConnectTCP (s + strlen("connect://"), error_ptr); return ConnectTCP (s + strlen("connect://"), error_ptr);
} }
else if (strstr(s, "tcp://")) else if (strstr(s, "tcp-connect://"))
{ {
return ConnectTCP (s + strlen("tcp://"), error_ptr); return ConnectTCP (s + strlen("tcp-connect://"), error_ptr);
} }
else if (strstr(s, "udp://")) else if (strstr(s, "udp://"))
{ {
@ -123,7 +150,8 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
// that is already opened (possibly from a service or other source). // that is already opened (possibly from a service or other source).
s += strlen ("fd://"); s += strlen ("fd://");
bool success = false; bool success = false;
m_fd = Args::StringToSInt32 (s, -1, 0, &success); m_fd_send = m_fd_recv = Args::StringToSInt32 (s, -1, 0, &success);
if (success) if (success)
{ {
// We have what looks to be a valid file descriptor, but we // We have what looks to be a valid file descriptor, but we
@ -131,12 +159,12 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
// get the flags from the file descriptor and making sure it // get the flags from the file descriptor and making sure it
// isn't a bad fd. // isn't a bad fd.
errno = 0; errno = 0;
int flags = ::fcntl (m_fd, F_GETFL, 0); int flags = ::fcntl (m_fd_send, F_GETFL, 0);
if (flags == -1 || errno == EBADF) if (flags == -1 || errno == EBADF)
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s); error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s);
m_fd = -1; m_fd_send = m_fd_recv = -1;
return eConnectionStatusError; return eConnectionStatusError;
} }
else else
@ -144,9 +172,9 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
// Try and get a socket option from this file descriptor to // Try and get a socket option from this file descriptor to
// see if this is a socket and set m_is_socket accordingly. // see if this is a socket and set m_is_socket accordingly.
int resuse; int resuse;
bool is_socket = GetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, resuse) == 0; bool is_socket = GetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, resuse) == 0;
if (is_socket) if (is_socket)
m_fd_type = eFDTypeSocket; m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
m_should_close_fd = true; m_should_close_fd = true;
return eConnectionStatusSuccess; return eConnectionStatusSuccess;
} }
@ -154,28 +182,28 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
if (error_ptr) if (error_ptr)
error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s); error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s);
m_fd = -1; m_fd_send = m_fd_recv = -1;
return eConnectionStatusError; return eConnectionStatusError;
} }
else if (strstr(s, "file://")) else if (strstr(s, "file://"))
{ {
// file:///PATH // file:///PATH
const char *path = s + strlen("file://"); const char *path = s + strlen("file://");
m_fd = ::open (path, O_RDWR); m_fd_send = m_fd_recv = ::open (path, O_RDWR);
if (m_fd == -1) if (m_fd_send == -1)
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorToErrno();
return eConnectionStatusError; return eConnectionStatusError;
} }
int flags = ::fcntl (m_fd, F_GETFL, 0); int flags = ::fcntl (m_fd_send, F_GETFL, 0);
if (flags >= 0) if (flags >= 0)
{ {
if ((flags & O_NONBLOCK) == 0) if ((flags & O_NONBLOCK) == 0)
{ {
flags |= O_NONBLOCK; flags |= O_NONBLOCK;
::fcntl (m_fd, F_SETFL, flags); ::fcntl (m_fd_send, F_SETFL, flags);
} }
} }
m_should_close_fd = true; m_should_close_fd = true;
@ -193,15 +221,34 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
ConnectionStatus ConnectionStatus
ConnectionFileDescriptor::Disconnect (Error *error_ptr) ConnectionFileDescriptor::Disconnect (Error *error_ptr)
{ {
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
"%p ConnectionFileDescriptor::Disconnect ()", if (log)
this); log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", this);
if (m_should_close_fd == false) if (m_should_close_fd == false)
{ {
m_fd = -1; m_fd_send = m_fd_recv = -1;
return eConnectionStatusSuccess; return eConnectionStatusSuccess;
} }
return Close (m_fd, error_ptr); ConnectionStatus status = eConnectionStatusSuccess;
if (m_fd_send == m_fd_recv)
{
// Both file descriptors are the same, only close one
status = Close (m_fd_send, error_ptr);
m_fd_recv = -1;
}
else
{
// File descriptors are the different, close both if needed
if (m_fd_send >= 0)
status = Close (m_fd_send, error_ptr);
if (m_fd_recv >= 0)
{
ConnectionStatus recv_status = Close (m_fd_recv, error_ptr);
if (status == eConnectionStatusSuccess)
status = recv_status;
}
}
return status;
} }
size_t size_t
@ -214,25 +261,23 @@ ConnectionFileDescriptor::Read (void *dst,
LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
if (log) if (log)
log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu)...", log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu)...",
this, m_fd, dst, dst_len); this, m_fd_recv, dst, dst_len);
ssize_t bytes_read = 0; ssize_t bytes_read = 0;
struct sockaddr_storage from;
socklen_t from_len = sizeof(from);
switch (m_fd_type) switch (m_fd_recv_type)
{ {
case eFDTypeFile: // Other FD requireing read/write case eFDTypeFile: // Other FD requireing read/write
status = BytesAvailable (timeout_usec, error_ptr); status = BytesAvailable (timeout_usec, error_ptr);
if (status == eConnectionStatusSuccess) if (status == eConnectionStatusSuccess)
bytes_read = ::read (m_fd, dst, dst_len); bytes_read = ::read (m_fd_recv, dst, dst_len);
break; break;
case eFDTypeSocket: // Socket requiring send/recv case eFDTypeSocket: // Socket requiring send/recv
if (SetSocketReceiveTimeout (timeout_usec)) if (SetSocketReceiveTimeout (timeout_usec))
{ {
status = eConnectionStatusSuccess; status = eConnectionStatusSuccess;
bytes_read = ::recv (m_fd, dst, dst_len, 0); bytes_read = ::recv (m_fd_recv, dst, dst_len, 0);
} }
break; break;
@ -240,8 +285,9 @@ ConnectionFileDescriptor::Read (void *dst,
if (SetSocketReceiveTimeout (timeout_usec)) if (SetSocketReceiveTimeout (timeout_usec))
{ {
status = eConnectionStatusSuccess; status = eConnectionStatusSuccess;
::memset (&from, 0, sizeof(from)); sockaddr_t from = m_udp_send_sockaddr;
bytes_read = ::recvfrom (m_fd, dst, dst_len, 0, (struct sockaddr *)&from, &from_len); socklen_t from_len = m_udp_send_sockaddr.sa.sa_len;
bytes_read = ::recvfrom (m_fd_recv, dst, dst_len, 0, (struct sockaddr *)&from, &from_len);
} }
break; break;
} }
@ -267,7 +313,7 @@ ConnectionFileDescriptor::Read (void *dst,
if (log) if (log)
log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu) => %zi, error = %s", log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %zu) => %zi, error = %s",
this, this,
m_fd, m_fd_recv,
dst, dst,
dst_len, dst_len,
bytes_read, bytes_read,
@ -282,7 +328,10 @@ ConnectionFileDescriptor::Read (void *dst,
switch (error_value) switch (error_value)
{ {
case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read. case EAGAIN: // The file was marked for non-blocking I/O, and no data were ready to be read.
status = eConnectionStatusSuccess; if (m_fd_recv_type == eFDTypeSocket || m_fd_recv_type == eFDTypeSocketUDP)
status = eConnectionStatusTimedOut;
else
status = eConnectionStatusSuccess;
return 0; return 0;
case EFAULT: // Buf points outside the allocated address space. case EFAULT: // Buf points outside the allocated address space.
@ -315,9 +364,7 @@ ConnectionFileDescriptor::Read (void *dst,
return 0; return 0;
} }
// if (log) Disconnect (NULL);
// error->Log(log, "::read ( %i, %p, %zu ) => %i", m_fd, dst, dst_len, bytesread);
Close (m_fd, NULL);
return 0; return 0;
} }
return bytes_read; return bytes_read;
@ -343,24 +390,24 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
ssize_t bytes_sent = 0; ssize_t bytes_sent = 0;
switch (m_fd_type) switch (m_fd_send_type)
{ {
case eFDTypeFile: // Other FD requireing read/write case eFDTypeFile: // Other FD requireing read/write
bytes_sent = ::write (m_fd, src, src_len); bytes_sent = ::write (m_fd_send, src, src_len);
break; break;
case eFDTypeSocket: // Socket requiring send/recv case eFDTypeSocket: // Socket requiring send/recv
bytes_sent = ::send (m_fd, src, src_len, 0); bytes_sent = ::send (m_fd_send, src, src_len, 0);
break; break;
case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
assert (m_udp_sockaddr_len != 0); assert (m_udp_send_sockaddr.sa_storage.ss_family != 0);
bytes_sent = ::sendto (m_fd, bytes_sent = ::sendto (m_fd_send,
src, src,
src_len, src_len,
0, 0,
(struct sockaddr *)&m_udp_sockaddr, &m_udp_send_sockaddr.sa,
m_udp_sockaddr_len); m_udp_send_sockaddr.sa.sa_len);
break; break;
} }
@ -371,12 +418,12 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
if (log) if (log)
{ {
switch (m_fd_type) switch (m_fd_send_type)
{ {
case eFDTypeFile: // Other FD requireing read/write case eFDTypeFile: // Other FD requireing read/write
log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)", log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %zu) => %zi (error = %s)",
this, this,
m_fd, m_fd_send,
src, src,
src_len, src_len,
bytes_sent, bytes_sent,
@ -386,7 +433,7 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
case eFDTypeSocket: // Socket requiring send/recv case eFDTypeSocket: // Socket requiring send/recv
log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)", log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)",
this, this,
m_fd, m_fd_send,
src, src,
src_len, src_len,
bytes_sent, bytes_sent,
@ -396,7 +443,7 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom 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)", log->Printf ("%p ConnectionFileDescriptor::Write() ::sendto (socket = %i, src = %p, src_len = %zu, flags = 0) => %zi (error = %s)",
this, this,
m_fd, m_fd_send,
src, src,
src_len, src_len,
bytes_sent, bytes_sent,
@ -427,7 +474,7 @@ ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStat
break; // Break to close.... break; // Break to close....
} }
Close (m_fd, NULL); Disconnect (NULL);
return 0; return 0;
} }
@ -460,16 +507,15 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
{ {
fd_set read_fds; fd_set read_fds;
FD_ZERO (&read_fds); FD_ZERO (&read_fds);
FD_SET (m_fd, &read_fds); FD_SET (m_fd_recv, &read_fds);
int nfds = m_fd + 1; int nfds = m_fd_recv + 1;
Error error; Error error;
log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION);
if (log) if (log)
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...", log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p)...",
this, nfds, m_fd, tv_ptr); this, nfds, m_fd_recv, tv_ptr);
const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr); const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr);
if (num_set_fds < 0) if (num_set_fds < 0)
@ -477,10 +523,9 @@ ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_pt
else else
error.Clear(); error.Clear();
log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION);
if (log) if (log)
log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s", log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds = %i, fd = %i, NULL, NULL, timeout = %p) => %d, error = %s",
this, nfds, m_fd, tv_ptr, num_set_fds, error.AsCString()); this, nfds, m_fd_recv, tv_ptr, num_set_fds, error.AsCString());
if (error_ptr) if (error_ptr)
*error_ptr = error; *error_ptr = error;
@ -528,10 +573,9 @@ ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
bool success = true; bool success = true;
if (fd >= 0) if (fd >= 0)
{ {
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
"%p ConnectionFileDescriptor::Close (fd = %i)", if (log)
this, log->Printf ("%p ConnectionFileDescriptor::Close (fd = %i)", this,fd);
fd);
success = ::close (fd) == 0; success = ::close (fd) == 0;
if (!success && error_ptr) if (!success && error_ptr)
@ -543,7 +587,7 @@ ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
} }
fd = -1; fd = -1;
} }
m_fd_type = eFDTypeFile; m_fd_send_type = m_fd_recv_type = eFDTypeFile;
if (success) if (success)
return eConnectionStatusSuccess; return eConnectionStatusSuccess;
else else
@ -556,7 +600,7 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err
ConnectionStatus result = eConnectionStatusError; ConnectionStatus result = eConnectionStatusError;
struct sockaddr_un saddr_un; struct sockaddr_un saddr_un;
m_fd_type = eFDTypeSocket; m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0); int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0);
if (listen_socket == -1) if (listen_socket == -1)
@ -577,8 +621,8 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err
{ {
if (::listen (listen_socket, 5) == 0) if (::listen (listen_socket, 5) == 0)
{ {
m_fd = ::accept (listen_socket, NULL, 0); m_fd_send = m_fd_recv = ::accept (listen_socket, NULL, 0);
if (m_fd > 0) if (m_fd_send > 0)
{ {
m_should_close_fd = true; m_should_close_fd = true;
@ -602,13 +646,13 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err
ConnectionStatus ConnectionStatus
ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr) ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr)
{ {
Close (m_fd, NULL); Disconnect (NULL);
m_fd_type = eFDTypeSocket; m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
// Open the socket that was passed in as an option // Open the socket that was passed in as an option
struct sockaddr_un saddr_un; struct sockaddr_un saddr_un;
m_fd = ::socket (AF_UNIX, SOCK_STREAM, 0); m_fd_send = m_fd_recv = ::socket (AF_UNIX, SOCK_STREAM, 0);
if (m_fd == -1) if (m_fd_send == -1)
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorToErrno();
@ -622,11 +666,11 @@ ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *er
saddr_un.sun_len = SUN_LEN (&saddr_un); saddr_un.sun_len = SUN_LEN (&saddr_un);
#endif #endif
if (::connect (m_fd, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) if (::connect (m_fd_send, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorToErrno();
Close (m_fd, NULL); Disconnect (NULL);
return eConnectionStatusError; return eConnectionStatusError;
} }
if (error_ptr) if (error_ptr)
@ -637,12 +681,12 @@ ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *er
ConnectionStatus ConnectionStatus
ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr) ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
{ {
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
"%p ConnectionFileDescriptor::SocketListen (port = %i)", if (log)
this, listen_port_num); log->Printf ("%p ConnectionFileDescriptor::SocketListen (port = %i)", this, listen_port_num);
Close (m_fd, NULL); Disconnect (NULL);
m_fd_type = eFDTypeSocket; m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_port == -1) if (listen_port == -1)
{ {
@ -678,8 +722,8 @@ ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_p
return eConnectionStatusError; return eConnectionStatusError;
} }
m_fd = ::accept (listen_port, NULL, 0); m_fd_send = m_fd_recv = ::accept (listen_port, NULL, 0);
if (m_fd == -1) if (m_fd_send == -1)
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorToErrno();
@ -693,7 +737,7 @@ ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_p
m_should_close_fd = true; m_should_close_fd = true;
// Keep our TCP packets coming without any delays. // Keep our TCP packets coming without any delays.
SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
if (error_ptr) if (error_ptr)
error_ptr->Clear(); error_ptr->Clear();
return eConnectionStatusSuccess; return eConnectionStatusSuccess;
@ -702,39 +746,21 @@ ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_p
ConnectionStatus ConnectionStatus
ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_ptr) ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_ptr)
{ {
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
"%p ConnectionFileDescriptor::ConnectTCP (host/port = %s)", if (log)
this, host_and_port); log->Printf ("%p ConnectionFileDescriptor::ConnectTCP (host/port = %s)", this, host_and_port);
Close (m_fd, NULL); Disconnect (NULL);
m_fd_type = eFDTypeSocket;
RegularExpression regex ("([^:]+):([0-9]+)"); m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
if (regex.Execute (host_and_port, 2) == false)
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port);
return eConnectionStatusError;
}
std::string host_str; std::string host_str;
std::string port_str; std::string port_str;
if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false || int32_t port = INT32_MIN;
regex.GetMatchAtIndex (host_and_port, 2, port_str) == false) if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("invalid host:port specification '%s'", host_and_port);
return eConnectionStatusError; return eConnectionStatusError;
}
int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
if (port == INT32_MIN)
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("invalid port '%s'", port_str.c_str());
return eConnectionStatusError;
}
// Create the socket // Create the socket
m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); m_fd_send = m_fd_recv = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_fd == -1) if (m_fd_send == -1)
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorToErrno();
@ -744,7 +770,7 @@ ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_pt
m_should_close_fd = true; m_should_close_fd = true;
// Enable local address reuse // Enable local address reuse
SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1); SetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, 1);
struct sockaddr_in sa; struct sockaddr_in sa;
::memset (&sa, 0, sizeof (sa)); ::memset (&sa, 0, sizeof (sa));
@ -769,21 +795,23 @@ ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_pt
else else
error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str()); error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
} }
Close (m_fd, NULL); Disconnect (NULL);
return eConnectionStatusError; return eConnectionStatusError;
} }
} }
if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa))) if (-1 == ::connect (m_fd_send, (const struct sockaddr *)&sa, sizeof(sa)))
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorToErrno();
Close (m_fd, NULL); Disconnect (NULL);
return eConnectionStatusError; return eConnectionStatusError;
} }
// Keep our TCP packets coming without any delays. // Keep our TCP packets coming without any delays.
SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
if (error_ptr) if (error_ptr)
error_ptr->Clear(); error_ptr->Clear();
return eConnectionStatusSuccess; return eConnectionStatusSuccess;
@ -792,90 +820,104 @@ ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_pt
ConnectionStatus ConnectionStatus
ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_ptr) ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_ptr)
{ {
lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION, LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
"%p ConnectionFileDescriptor::ConnectUDP (host/port = %s)", if (log)
this, host_and_port); log->Printf ("%p ConnectionFileDescriptor::ConnectUDP (host/port = %s)", this, host_and_port);
Close (m_fd, NULL); Disconnect (NULL);
m_fd_type = eFDTypeSocketUDP;
m_fd_send_type = m_fd_recv_type = eFDTypeSocketUDP;
RegularExpression regex ("([^:]+):([0-9]+)");
if (regex.Execute (host_and_port, 2) == false)
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port);
return eConnectionStatusError;
}
std::string host_str; std::string host_str;
std::string port_str; std::string port_str;
if (regex.GetMatchAtIndex (host_and_port, 1, host_str) == false || int32_t port = INT32_MIN;
regex.GetMatchAtIndex (host_and_port, 2, port_str) == false) if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat("invalid host:port specification '%s'", host_and_port);
return eConnectionStatusError; return eConnectionStatusError;
}
// Setup the receiving end of the UDP connection on this localhost
int32_t port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN); // on port zero. After we bind to port zero we can read the port.
if (port == INT32_MIN) m_fd_recv = ::socket (AF_INET, SOCK_DGRAM, 0);
{ if (m_fd_recv == -1)
if (error_ptr)
error_ptr->SetErrorStringWithFormat("invalid port '%s'", port_str.c_str());
return eConnectionStatusError;
}
// Create the socket
m_fd = ::socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (m_fd == -1)
{ {
// Socket creation failed...
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorToErrno();
return eConnectionStatusError;
} }
else
m_should_close_fd = true;
// Enable local address reuse
SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
struct sockaddr_in sa;
::memset (&sa, 0, sizeof (sa));
sa.sin_family = AF_INET;
sa.sin_port = htons (port);
int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
if (inet_pton_result <= 0)
{ {
struct hostent *host_entry = gethostbyname (host_str.c_str()); // Socket was created, now lets bind to the requested port
if (host_entry) struct sockaddr_in sin;
host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list); ::memset (&sin, 0, sizeof(sin));
inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr); sin.sin_len = sizeof(sin);
if (inet_pton_result <= 0) sin.sin_family = AF_INET;
sin.sin_port = 0;
sin.sin_addr.s_addr = htonl (INADDR_ANY);
if (::bind (m_fd_recv, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{ {
// Bind failed...
if (error_ptr) if (error_ptr)
{ error_ptr->SetErrorToErrno();
if (inet_pton_result == -1) Disconnect (NULL);
error_ptr->SetErrorToErrno();
else
error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
}
Close (m_fd, NULL);
return eConnectionStatusError;
} }
} }
if (m_fd_recv == -1)
return eConnectionStatusError;
// At this point we have setup the recieve port, now we need to
// setup the UDP send socket
struct addrinfo hints;
struct addrinfo *service_info_list = NULL;
if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa))) ::memset (&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list);
if (err != 0)
{ {
if (error_ptr) if (error_ptr)
error_ptr->SetErrorToErrno(); error_ptr->SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)",
Close (m_fd, NULL); host_str.c_str(),
return eConnectionStatusError; port_str.c_str(),
err,
gai_strerror(err));
Disconnect (NULL);
return eConnectionStatusError;
} }
// Keep our TCP packets coming without any delays. for (struct addrinfo *service_info_ptr = service_info_list;
SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); service_info_ptr != NULL;
service_info_ptr = service_info_ptr->ai_next)
{
m_fd_send = ::socket (service_info_ptr->ai_family,
service_info_ptr->ai_socktype,
service_info_ptr->ai_protocol);
if (m_fd_send != -1)
{
::memset (&m_udp_send_sockaddr, 0, sizeof(m_udp_send_sockaddr));
::memcpy (&m_udp_send_sockaddr,
service_info_ptr->ai_addr,
service_info_ptr->ai_addrlen);
break;
}
else
continue;
}
:: freeaddrinfo (service_info_list);
if (m_fd_send == -1)
{
Disconnect (NULL);
return eConnectionStatusError;
}
if (error_ptr) if (error_ptr)
error_ptr->Clear(); error_ptr->Clear();
m_should_close_fd = true;
return eConnectionStatusSuccess; return eConnectionStatusSuccess;
} }
@ -905,7 +947,7 @@ ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, in
bool bool
ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec) ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec)
{ {
switch (m_fd_type) switch (m_fd_recv_type)
{ {
case eFDTypeFile: // Other FD requireing read/write case eFDTypeFile: // Other FD requireing read/write
break; break;
@ -921,7 +963,7 @@ ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec)
struct timeval timeout; struct timeval timeout;
timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec; timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec;
timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec; timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec;
if (::setsockopt (m_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0) if (::setsockopt (m_fd_recv, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0)
{ {
m_socket_timeout_usec = timeout_usec; m_socket_timeout_usec = timeout_usec;
return true; return true;
@ -931,4 +973,38 @@ ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec)
return false; return false;
} }
in_port_t
ConnectionFileDescriptor::GetSocketPort (int fd)
{
// We bound to port zero, so we need to figure out which port we actually bound to
sockaddr_t sock_addr;
socklen_t sock_addr_len = sizeof (sock_addr);
if (::getsockname (fd, &sock_addr.sa, &sock_addr_len) == 0)
{
switch (sock_addr.sa.sa_family)
{
case AF_INET: return sock_addr.sa_ipv4.sin_port;
case AF_INET6: return sock_addr.sa_ipv6.sin6_port;
}
}
return 0;
}
// If the read file descriptor is a socket, then return
// the port number that is being used by the socket.
in_port_t
ConnectionFileDescriptor::GetReadPort () const
{
return ConnectionFileDescriptor::GetSocketPort (m_fd_recv);
}
// If the write file descriptor is a socket, then return
// the port number that is being used by the socket.
in_port_t
ConnectionFileDescriptor::GetWritePort () const
{
return ConnectionFileDescriptor::GetSocketPort (m_fd_send);
}

View File

@ -1793,6 +1793,7 @@ void
DataExtractor::DumpHexBytes (Stream *s, DataExtractor::DumpHexBytes (Stream *s,
const void *src, const void *src,
size_t src_len, size_t src_len,
uint32_t bytes_per_line,
addr_t base_addr) addr_t base_addr)
{ {
DataExtractor data (src, src_len, eByteOrderLittle, 4); DataExtractor data (src, src_len, eByteOrderLittle, 4);
@ -1801,7 +1802,7 @@ DataExtractor::DumpHexBytes (Stream *s,
eFormatBytes, // Dump as hex bytes eFormatBytes, // Dump as hex bytes
1, // Size of each item is 1 for single bytes 1, // Size of each item is 1 for single bytes
src_len, // Number of bytes src_len, // Number of bytes
32, // Num bytes per line bytes_per_line, // Num bytes per line
base_addr, // Base address base_addr, // Base address
0, 0); // Bitfield info 0, 0); // Bitfield info
} }

View File

@ -102,7 +102,7 @@ CommunicationKDP::SendRequestAndGetReply (const CommandType command,
Mutex::Locker locker(m_sequence_mutex); Mutex::Locker locker(m_sequence_mutex);
if (SendRequestPacketNoLock(request_packet)) if (SendRequestPacketNoLock(request_packet))
{ {
if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, m_packet_timeout)) if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, GetPacketTimeoutInMicroSeconds ()))
{ {
uint32_t offset = 0; uint32_t offset = 0;
const uint8_t reply_command = reply_packet.GetU8 (&offset); const uint8_t reply_command = reply_packet.GetU8 (&offset);
@ -131,9 +131,11 @@ CommunicationKDP::SendRequestPacketNoLock (const PacketStreamType &request_packe
{ {
PacketStreamType log_strm; PacketStreamType log_strm;
DataExtractor::DumpHexBytes (&log_strm, packet_data, packet_size, 0); DataExtractor::DumpHexBytes (&log_strm, packet_data, packet_size, UINT32_MAX, LLDB_INVALID_ADDRESS);
log->Printf("request packet: <%u>\n%s", packet_size, log_strm.GetData()); log->Printf("send kdp-packet: %.*s",
(uint32_t)log_strm.GetSize(),
log_strm.GetData());
} }
ConnectionStatus status = eConnectionStatusSuccess; ConnectionStatus status = eConnectionStatusSuccess;
@ -239,7 +241,7 @@ CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtrac
if (log && log->GetVerbose()) if (log && log->GetVerbose())
{ {
PacketStreamType log_strm; PacketStreamType log_strm;
DataExtractor::DumpHexBytes (&log_strm, src, src_len, 0); DataExtractor::DumpHexBytes (&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS);
log->Printf ("CommunicationKDP::%s adding %u bytes: %s", log->Printf ("CommunicationKDP::%s adding %u bytes: %s",
__FUNCTION__, __FUNCTION__,
(uint32_t)src_len, (uint32_t)src_len,
@ -292,6 +294,23 @@ CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtrac
// erase the bytes from our communcation buffer "m_bytes" // erase the bytes from our communcation buffer "m_bytes"
packet.SetData (DataBufferSP (new DataBufferHeap (&m_bytes[0], length))); packet.SetData (DataBufferSP (new DataBufferHeap (&m_bytes[0], length)));
m_bytes.erase (0, length); m_bytes.erase (0, length);
if (log)
{
PacketStreamType log_strm;
packet.Dump (&log_strm, // Stream to dump to
0, // Offset into "packet"
eFormatBytes, // Dump as hex bytes
1, // Size of each item is 1 for single bytes
length, // Number of bytes
UINT32_MAX, // Num bytes per line
LLDB_INVALID_ADDRESS, // Base address
0, 0); // Bitfield info set to not do anything bitfield related
log->Printf("recv kdp-packet: %.*s",
(uint32_t)log_strm.GetSize(),
log_strm.GetData());
}
return true; return true;
} }
} }
@ -313,22 +332,25 @@ CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtrac
bool bool
CommunicationKDP::Connect (uint16_t reply_port, CommunicationKDP::SendRequestConnect (uint16_t reply_port,
uint16_t exc_port, uint16_t exc_port,
const char *greeting) const char *greeting)
{ {
PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
if (greeting == NULL) if (greeting == NULL)
greeting = ""; greeting = "";
const CommandType command = eCommandTypeConnect; const CommandType command = eCommandTypeConnect;
// Length is 82 uint16_t and the length of the greeting C string // 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); const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1;
const uint32_t request_sequence_id = m_request_sequence_id; const uint32_t request_sequence_id = m_request_sequence_id;
MakeRequestPacketHeader (command, request_packet, command_length); MakeRequestPacketHeader (command, request_packet, command_length);
request_packet.PutHex16(reply_port); // Always send connect ports as little endian
request_packet.PutHex16(exc_port); request_packet.SetByteOrder (eByteOrderLittle);
request_packet.PutCString(greeting); request_packet.PutHex16 (reply_port);
request_packet.PutHex16 (exc_port);
request_packet.SetByteOrder (m_byte_order);
request_packet.PutCString (greeting);
DataExtractor reply_packet; DataExtractor reply_packet;
return SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet); return SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet);
} }
@ -345,7 +367,7 @@ CommunicationKDP::ClearKDPSettings ()
} }
bool bool
CommunicationKDP::Reattach (uint16_t reply_port) CommunicationKDP::SendRequestReattach (uint16_t reply_port)
{ {
PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
const CommandType command = eCommandTypeReattach; const CommandType command = eCommandTypeReattach;
@ -353,7 +375,10 @@ CommunicationKDP::Reattach (uint16_t reply_port)
const uint32_t command_length = 8 + 2; const uint32_t command_length = 8 + 2;
const uint32_t request_sequence_id = m_request_sequence_id; const uint32_t request_sequence_id = m_request_sequence_id;
MakeRequestPacketHeader (command, request_packet, command_length); MakeRequestPacketHeader (command, request_packet, command_length);
// Always send connect ports as little endian
request_packet.SetByteOrder (eByteOrderLittle);
request_packet.PutHex16(reply_port); request_packet.PutHex16(reply_port);
request_packet.SetByteOrder (m_byte_order);
DataExtractor reply_packet; DataExtractor reply_packet;
if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet)) if (SendRequestAndGetReply (command, request_sequence_id, request_packet, reply_packet))
{ {
@ -448,7 +473,7 @@ CommunicationKDP::SendRequestHostInfo ()
} }
bool bool
CommunicationKDP::Disconnect () CommunicationKDP::SendRequestDisconnect ()
{ {
PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order); PacketStreamType request_packet (Stream::eBinary, 4, m_byte_order);
const CommandType command = eCommandTypeDisconnect; const CommandType command = eCommandTypeDisconnect;

View File

@ -141,15 +141,15 @@ public:
bool bool
Connect (uint16_t reply_port, SendRequestConnect (uint16_t reply_port,
uint16_t exc_port, uint16_t exc_port,
const char *greeting); const char *greeting);
bool bool
Reattach (uint16_t reply_port); SendRequestReattach (uint16_t reply_port);
bool bool
Disconnect (); SendRequestDisconnect ();
uint32_t uint32_t
GetVersion (); GetVersion ();

View File

@ -13,6 +13,7 @@
// C++ Includes // C++ Includes
// Other libraries and framework includes // Other libraries and framework includes
#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/PluginManager.h" #include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h" #include "lldb/Core/State.h"
#include "lldb/Host/Host.h" #include "lldb/Host/Host.h"
@ -53,7 +54,7 @@ ProcessKDP::CreateInstance (Target &target, Listener &listener)
} }
bool bool
ProcessKDP::CanDebug(Target &target) ProcessKDP::CanDebug(Target &target, bool plugin_specified_by_name)
{ {
// For now we are just making sure the file exists for a given module // For now we are just making sure the file exists for a given module
ModuleSP exe_module_sp(target.GetExecutableModule()); ModuleSP exe_module_sp(target.GetExecutableModule());
@ -68,8 +69,10 @@ ProcessKDP::CanDebug(Target &target)
exe_objfile->GetStrata() == ObjectFile::eStrataKernel) exe_objfile->GetStrata() == ObjectFile::eStrataKernel)
return true; return true;
} }
return false;
} }
return false; // No target executable, assume we can debug if our plug-in was specified by name
return plugin_specified_by_name;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -143,7 +146,63 @@ ProcessKDP::DoConnectRemote (const char *remote_url)
{ {
// TODO: fill in the remote connection to the remote KDP here! // TODO: fill in the remote connection to the remote KDP here!
Error error; Error error;
error.SetErrorString ("attaching to a by process name not supported in kdp-remote plug-in");
if (remote_url == NULL || remote_url[0] == '\0')
remote_url = "udp://localhost:41139";
std::auto_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 uint16_t reply_port = conn_ap->GetReadPort ();
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();
uint32_t cpu = m_comm.GetCPUType();
uint32_t sub = m_comm.GetCPUSubtype();
ArchSpec kernel_arch;
kernel_arch.SetArchitecture(eArchTypeMachO, cpu, sub);
m_target.SetArchitecture(kernel_arch);
// TODO: thread registers based off of architecture...
}
}
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; return error;
} }
@ -414,13 +473,19 @@ ProcessKDP::DoDetach()
m_thread_list.DiscardThreadPlans(); m_thread_list.DiscardThreadPlans();
size_t response_size = m_comm.Disconnect (); if (m_comm.IsConnected())
if (log)
{ {
if (response_size)
log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully"); m_comm.SendRequestDisconnect();
else
log->PutCString ("ProcessKDP::DoDetach() detach packet send failed"); size_t response_size = m_comm.Disconnect ();
if (log)
{
if (response_size)
log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully");
else
log->PutCString ("ProcessKDP::DoDetach() detach packet send failed");
}
} }
// Sleep for one second to let the process get all detached... // Sleep for one second to let the process get all detached...
StopAsyncThread (); StopAsyncThread ();
@ -446,6 +511,8 @@ ProcessKDP::DoDestroy ()
// Interrupt if our inferior is running... // Interrupt if our inferior is running...
if (m_comm.IsConnected()) if (m_comm.IsConnected())
{ {
m_comm.SendRequestDisconnect();
if (m_public_state.GetValue() == eStateAttaching) if (m_public_state.GetValue() == eStateAttaching)
{ {
// We are being asked to halt during an attach. We need to just close // We are being asked to halt during an attach. We need to just close

View File

@ -65,7 +65,8 @@ public:
// Check if a given Process // Check if a given Process
//------------------------------------------------------------------ //------------------------------------------------------------------
virtual bool virtual bool
CanDebug (lldb_private::Target &target); CanDebug (lldb_private::Target &target,
bool plugin_specified_by_name);
// virtual uint32_t // virtual uint32_t
// ListProcessesMatchingName (const char *name, lldb_private::StringList &matches, std::vector<lldb::pid_t> &pids); // ListProcessesMatchingName (const char *name, lldb_private::StringList &matches, std::vector<lldb::pid_t> &pids);

View File

@ -208,7 +208,7 @@ ProcessMacOSX::CreateInstance (Target &target, Listener &listener)
} }
bool bool
ProcessMacOSX::CanDebug(Target &target) ProcessMacOSX::CanDebug(Target &target, bool plugin_specified_by_name)
{ {
// For now we are just making sure the file exists for a given module // For now we are just making sure the file exists for a given module
ModuleSP exe_module_sp(target.GetExecutableModule()); ModuleSP exe_module_sp(target.GetExecutableModule());

View File

@ -81,7 +81,8 @@ public:
// Check if a given Process // Check if a given Process
//------------------------------------------------------------------ //------------------------------------------------------------------
virtual bool virtual bool
CanDebug (lldb_private::Target &target); CanDebug (lldb_private::Target &target,
bool plugin_specified_by_name);
//------------------------------------------------------------------ //------------------------------------------------------------------
// Creating a new process, or attaching to an existing one // Creating a new process, or attaching to an existing one

View File

@ -101,7 +101,7 @@ ProcessGDBRemote::CreateInstance (Target &target, Listener &listener)
} }
bool bool
ProcessGDBRemote::CanDebug(Target &target) ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name)
{ {
// For now we are just making sure the file exists for a given module // For now we are just making sure the file exists for a given module
ModuleSP exe_module_sp(target.GetExecutableModule()); ModuleSP exe_module_sp(target.GetExecutableModule());

View File

@ -66,7 +66,8 @@ public:
// Check if a given Process // Check if a given Process
//------------------------------------------------------------------ //------------------------------------------------------------------
virtual bool virtual bool
CanDebug (lldb_private::Target &target); CanDebug (lldb_private::Target &target,
bool plugin_specified_by_name);
// virtual uint32_t // virtual uint32_t
// ListProcessesMatchingName (const char *name, lldb_private::StringList &matches, std::vector<lldb::pid_t> &pids); // ListProcessesMatchingName (const char *name, lldb_private::StringList &matches, std::vector<lldb::pid_t> &pids);

View File

@ -549,7 +549,7 @@ Process::FindPlugin (Target &target, const char *plugin_name, Listener &listener
if (create_callback) if (create_callback)
{ {
std::auto_ptr<Process> debugger_ap(create_callback(target, listener)); std::auto_ptr<Process> debugger_ap(create_callback(target, listener));
if (debugger_ap->CanDebug(target)) if (debugger_ap->CanDebug(target, true))
return debugger_ap.release(); return debugger_ap.release();
} }
} }
@ -558,7 +558,7 @@ Process::FindPlugin (Target &target, const char *plugin_name, Listener &listener
for (uint32_t idx = 0; (create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx)) != NULL; ++idx) for (uint32_t idx = 0; (create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx)) != NULL; ++idx)
{ {
std::auto_ptr<Process> debugger_ap(create_callback(target, listener)); std::auto_ptr<Process> debugger_ap(create_callback(target, listener));
if (debugger_ap->CanDebug(target)) if (debugger_ap->CanDebug(target, false))
return debugger_ap.release(); return debugger_ap.release();
} }
} }

View File

@ -45,6 +45,7 @@
#include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h" #include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h"
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
#include "Plugins/Process/MacOSX-User/source/ProcessMacOSX.h" #include "Plugins/Process/MacOSX-User/source/ProcessMacOSX.h"
#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
#include "Plugins/Platform/MacOSX/PlatformMacOSX.h" #include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
@ -102,6 +103,7 @@ lldb_private::Initialize ()
AppleObjCRuntimeV1::Initialize(); AppleObjCRuntimeV1::Initialize();
ObjectContainerUniversalMachO::Initialize(); ObjectContainerUniversalMachO::Initialize();
ObjectFileMachO::Initialize(); ObjectFileMachO::Initialize();
ProcessKDP::Initialize();
ProcessGDBRemote::Initialize(); ProcessGDBRemote::Initialize();
//ProcessMacOSX::Initialize(); //ProcessMacOSX::Initialize();
SymbolVendorMacOSX::Initialize(); SymbolVendorMacOSX::Initialize();
@ -167,6 +169,7 @@ lldb_private::Terminate ()
AppleObjCRuntimeV1::Terminate(); AppleObjCRuntimeV1::Terminate();
ObjectContainerUniversalMachO::Terminate(); ObjectContainerUniversalMachO::Terminate();
ObjectFileMachO::Terminate(); ObjectFileMachO::Terminate();
ProcessKDP::Terminate();
ProcessGDBRemote::Terminate(); ProcessGDBRemote::Terminate();
//ProcessMacOSX::Terminate(); //ProcessMacOSX::Terminate();
SymbolVendorMacOSX::Terminate(); SymbolVendorMacOSX::Terminate();