llvm-capstone/lldb/source/Core/ConnectionMachPort.cpp
Greg Clayton 73bf5dbd16 Improved the packet throughput when debugging with GDB remote by over 3x on
darwin (not sure about other platforms).

Modified the communication and connection classes to not require the
BytesAvailable function. Now the "Read(...)" function has a timeout in
microseconds.

Fixed a lot of assertions that were firing off in certain cases and replaced
them with error output and code that can deal with the assertion case.

llvm-svn: 133224
2011-06-17 01:22:15 +00:00

324 lines
8.5 KiB
C++

//===-- ConnectionMachPort.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#if defined(__APPLE__)
#include "lldb/Core/ConnectionMachPort.h"
// C Includes
#include <servers/bootstrap.h>
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/Log.h"
using namespace lldb;
using namespace lldb_private;
struct MessageType
{
mach_msg_header_t head;
ConnectionMachPort::PayloadType payload;
};
ConnectionMachPort::ConnectionMachPort () :
Connection(),
m_task(mach_task_self()),
m_port(MACH_PORT_TYPE_NONE)
{
}
ConnectionMachPort::~ConnectionMachPort ()
{
Disconnect (NULL);
}
bool
ConnectionMachPort::IsConnected () const
{
return m_port != MACH_PORT_TYPE_NONE;
}
ConnectionStatus
ConnectionMachPort::Connect (const char *s, Error *error_ptr)
{
if (IsConnected())
{
if (error_ptr)
error_ptr->SetErrorString ("already connected");
return eConnectionStatusError;
}
if (s == NULL || s[0] == '\0')
{
if (error_ptr)
error_ptr->SetErrorString ("empty connect URL");
return eConnectionStatusError;
}
ConnectionStatus status = eConnectionStatusError;
if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
{
s += strlen("bootstrap-checkin://");
if (*s)
{
status = BootstrapCheckIn (s, error_ptr);
}
else
{
if (error_ptr)
error_ptr->SetErrorString ("bootstrap port name is empty");
}
}
else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
{
s += strlen("bootstrap-lookup://");
if (*s)
{
status = BootstrapLookup (s, error_ptr);
}
else
{
if (error_ptr)
error_ptr->SetErrorString ("bootstrap port name is empty");
}
}
else
{
if (error_ptr)
error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
}
if (status == eConnectionStatusSuccess)
{
if (error_ptr)
error_ptr->Clear();
}
else
{
Disconnect(NULL);
}
return status;
}
ConnectionStatus
ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr)
{
mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
/* Getting bootstrap server port */
kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
if (kret == KERN_SUCCESS)
{
name_t port_name;
int len = snprintf(port_name, sizeof(port_name), "%s", port);
if (len < sizeof(port_name))
{
kret = ::bootstrap_check_in (bootstrap_port,
port_name,
&m_port);
}
else
{
Disconnect(NULL);
if (error_ptr)
error_ptr->SetErrorString ("bootstrap is too long");
return eConnectionStatusError;
}
}
if (kret != KERN_SUCCESS)
{
Disconnect(NULL);
if (error_ptr)
error_ptr->SetError (kret, eErrorTypeMachKernel);
return eConnectionStatusError;
}
return eConnectionStatusSuccess;
}
lldb::ConnectionStatus
ConnectionMachPort::BootstrapLookup (const char *port,
Error *error_ptr)
{
name_t port_name;
if (port && port[0])
{
if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name))
{
if (error_ptr)
error_ptr->SetErrorString ("port netname is too long");
return eConnectionStatusError;
}
}
else
{
if (error_ptr)
error_ptr->SetErrorString ("empty port netname");
return eConnectionStatusError;
}
mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
/* Getting bootstrap server port */
kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
if (kret == KERN_SUCCESS)
{
kret = ::bootstrap_look_up (bootstrap_port,
port_name,
&m_port);
}
if (kret != KERN_SUCCESS)
{
if (error_ptr)
error_ptr->SetError (kret, eErrorTypeMachKernel);
return eConnectionStatusError;
}
return eConnectionStatusSuccess;
}
ConnectionStatus
ConnectionMachPort::Disconnect (Error *error_ptr)
{
kern_return_t kret;
// TODO: verify if we need to netname_check_out for
// either or both
if (m_port != MACH_PORT_TYPE_NONE)
{
kret = ::mach_port_deallocate (m_task, m_port);
if (error_ptr)
error_ptr->SetError (kret, eErrorTypeMachKernel);
m_port = MACH_PORT_TYPE_NONE;
}
return eConnectionStatusSuccess;
}
size_t
ConnectionMachPort::Read (void *dst,
size_t dst_len,
uint32_t timeout_usec,
ConnectionStatus &status,
Error *error_ptr)
{
PayloadType payload;
kern_return_t kret = Receive (payload);
if (kret == KERN_SUCCESS)
{
memcpy (dst, payload.data, payload.data_length);
status = eConnectionStatusSuccess;
return payload.data_length;
}
if (error_ptr)
error_ptr->SetError (kret, eErrorTypeMachKernel);
status = eConnectionStatusError;
return 0;
}
size_t
ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
{
PayloadType payload;
payload.command = 0;
payload.data_length = src_len;
const size_t max_payload_size = sizeof(payload.data);
if (src_len > max_payload_size)
payload.data_length = max_payload_size;
memcpy (payload.data, src, payload.data_length);
if (Send (payload) == KERN_SUCCESS)
{
status = eConnectionStatusSuccess;
return payload.data_length;
}
status = eConnectionStatusError;
return 0;
}
ConnectionStatus
ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
{
return eConnectionStatusLostConnection;
}
kern_return_t
ConnectionMachPort::Send (const PayloadType &payload)
{
struct MessageType message;
/* (i) Form the message : */
/* (i.a) Fill the header fields : */
message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) |
MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX);
message.head.msgh_size = sizeof(MessageType);
message.head.msgh_local_port = MACH_PORT_NULL;
message.head.msgh_remote_port = m_port;
/* (i.b) Explain the message type ( an integer ) */
// message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
// message.type.msgt_size = 32;
// message.type.msgt_number = 1;
// message.type.msgt_inline = TRUE;
// message.type.msgt_longform = FALSE;
// message.type.msgt_deallocate = FALSE;
/* message.type.msgt_unused = 0; */ /* not needed, I think */
/* (i.c) Fill the message with the given integer : */
message.payload = payload;
/* (ii) Send the message : */
kern_return_t kret = ::mach_msg (&message.head,
MACH_SEND_MSG,
message.head.msgh_size,
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
return kret;
}
kern_return_t
ConnectionMachPort::Receive (PayloadType &payload)
{
MessageType message;
message.head.msgh_size = sizeof(MessageType);
kern_return_t kret = ::mach_msg (&message.head,
MACH_RCV_MSG,
0,
sizeof(MessageType),
m_port,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
if (kret == KERN_SUCCESS)
payload = message.payload;
return kret;
}
#endif // #if defined(__APPLE__)