253 lines
7.6 KiB
C++
253 lines
7.6 KiB
C++
//===-- CommunicationKDP.cpp ------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
#include "CommunicationKDP.h"
|
|
|
|
// C Includes
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
|
|
// C++ Includes
|
|
// Other libraries and framework includes
|
|
#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"
|
|
|
|
#define DEBUGSERVER_BASENAME "debugserver"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
//----------------------------------------------------------------------
|
|
// CommunicationKDP constructor
|
|
//----------------------------------------------------------------------
|
|
CommunicationKDP::CommunicationKDP (const char *comm_name) :
|
|
Communication(comm_name),
|
|
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)
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
// Destructor
|
|
//----------------------------------------------------------------------
|
|
CommunicationKDP::~CommunicationKDP()
|
|
{
|
|
if (IsConnected())
|
|
{
|
|
Disconnect();
|
|
}
|
|
}
|
|
|
|
bool
|
|
CommunicationKDP::SendRequestPacket (const StreamString &request_packet)
|
|
{
|
|
Mutex::Locker locker(m_sequence_mutex);
|
|
return SendRequestPacketNoLock (request_packet);
|
|
}
|
|
|
|
void
|
|
CommunicationKDP::MakeRequestPacketHeader (RequestType request_type,
|
|
StreamString &request_packet)
|
|
{
|
|
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
|
|
}
|
|
|
|
|
|
bool
|
|
CommunicationKDP::SendRequestPacketNoLock (const StreamString &request_packet)
|
|
{
|
|
if (IsConnected())
|
|
{
|
|
const char *packet_data = request_packet.GetData();
|
|
const size_t packet_size = request_packet.GetSize();
|
|
|
|
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);
|
|
|
|
log->Printf("request packet: <%u>\n%s", packet_size, log_strm.GetString().c_str());
|
|
}
|
|
ConnectionStatus status = eConnectionStatusSuccess;
|
|
|
|
size_t bytes_written = Write (packet_data,
|
|
packet_size,
|
|
status,
|
|
NULL);
|
|
|
|
if (bytes_written == packet_size)
|
|
return true;
|
|
|
|
if (log)
|
|
log->Printf ("error: failed to send packet entire packet %zu of %zu bytes sent", bytes_written, packet_size);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker)
|
|
{
|
|
return locker.TryLock (m_sequence_mutex.GetMutex());
|
|
}
|
|
|
|
|
|
bool
|
|
CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
|
|
{
|
|
return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
|
|
}
|
|
|
|
size_t
|
|
CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (StringExtractor &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)
|
|
{
|
|
uint8_t buffer[8192];
|
|
Error error;
|
|
|
|
LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS | KDP_LOG_VERBOSE));
|
|
|
|
// Check for a packet from our cache first without trying any reading...
|
|
if (CheckForPacket (NULL, 0, packet))
|
|
return packet.GetStringRef().size();
|
|
|
|
bool timed_out = false;
|
|
while (IsConnected() && !timed_out)
|
|
{
|
|
lldb::ConnectionStatus status;
|
|
size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
|
|
|
|
if (log)
|
|
log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %zu",
|
|
__PRETTY_FUNCTION__,
|
|
timeout_usec,
|
|
Communication::ConnectionStatusAsCString (status),
|
|
error.AsCString(),
|
|
bytes_read);
|
|
|
|
if (bytes_read > 0)
|
|
{
|
|
if (CheckForPacket (buffer, bytes_read, packet))
|
|
return packet.GetStringRef().size();
|
|
}
|
|
else
|
|
{
|
|
switch (status)
|
|
{
|
|
case eConnectionStatusTimedOut:
|
|
timed_out = true;
|
|
break;
|
|
case eConnectionStatusSuccess:
|
|
//printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
|
|
break;
|
|
|
|
case eConnectionStatusEndOfFile:
|
|
case eConnectionStatusNoConnection:
|
|
case eConnectionStatusLostConnection:
|
|
case eConnectionStatusError:
|
|
Disconnect();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
packet.Clear ();
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractor &packet)
|
|
{
|
|
// Put the packet data into the buffer in a thread safe fashion
|
|
Mutex::Locker locker(m_bytes_mutex);
|
|
|
|
LogSP log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS));
|
|
|
|
if (src && src_len > 0)
|
|
{
|
|
if (log && log->GetVerbose())
|
|
{
|
|
StreamString s;
|
|
log->Printf ("CommunicationKDP::%s adding %u bytes: %.*s",
|
|
__FUNCTION__,
|
|
(uint32_t)src_len,
|
|
(uint32_t)src_len,
|
|
src);
|
|
}
|
|
m_bytes.append ((const char *)src, src_len);
|
|
}
|
|
|
|
// Parse up the packets into gdb remote packets
|
|
if (!m_bytes.empty())
|
|
{
|
|
// TODO: Figure out if we have a full packet reply
|
|
}
|
|
packet.Clear();
|
|
return false;
|
|
}
|
|
|
|
|
|
CommunicationKDP::ErrorType
|
|
CommunicationKDP::Connect (uint16_t reply_port,
|
|
uint16_t exc_port,
|
|
const char *greeting)
|
|
{
|
|
StreamString request_packet (Stream::eBinary, 4, eByteOrderLittle);
|
|
MakeRequestPacketHeader (eRequestTypeConnect, request_packet);
|
|
request_packet.PutHex16(reply_port);
|
|
request_packet.PutHex16(exc_port);
|
|
request_packet.PutCString(greeting);
|
|
|
|
return eErrorUnimplemented;
|
|
}
|
|
|
|
CommunicationKDP::ErrorType
|
|
CommunicationKDP::Disconnect ()
|
|
{
|
|
return eErrorUnimplemented;
|
|
}
|
|
|