mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-13 03:41:11 +00:00

Summary: This is the first part of our effort to make llgs single threaded. Currently, llgs consists of about three threads and the synchronisation between them is a major source of latency when debugging linux and android applications. In order to be able to go single threaded, we must have the ability to listen for events from multiple sources (primarily, client commands coming over the network and debug events from the inferior) and perform necessary actions. For this reason I introduce the concept of a MainLoop. A main loop has the ability to register callback's which will be invoked upon receipt of certain events. MainLoopPosix has the ability to listen for file descriptors and signals. For the moment, I have merely made the GDBRemoteCommunicationServerLLGS class use MainLoop instead of waiting on the network socket directly, but the other threads still remain. In the followup patches I indend to migrate NativeProcessLinux to this class and remove the remaining threads. Reviewers: ovyalov, clayborg, amccarth, zturner, emaste Subscribers: tberghammer, lldb-commits Differential Revision: http://reviews.llvm.org/D11066 llvm-svn: 242018
139 lines
4.2 KiB
C++
139 lines
4.2 KiB
C++
//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <errno.h>
|
|
|
|
#include "lldb/Host/Config.h"
|
|
|
|
#include "GDBRemoteCommunicationServer.h"
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
#include <cstring>
|
|
|
|
// Project includes
|
|
#include "ProcessGDBRemoteLog.h"
|
|
#include "Utility/StringExtractorGDBRemote.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::process_gdb_remote;
|
|
|
|
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(const char *comm_name,
|
|
const char *listener_name) :
|
|
GDBRemoteCommunication (comm_name, listener_name),
|
|
m_exit_now (false)
|
|
{
|
|
}
|
|
|
|
GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
|
|
{
|
|
}
|
|
|
|
void GDBRemoteCommunicationServer::RegisterPacketHandler(
|
|
StringExtractorGDBRemote::ServerPacketType packet_type,
|
|
PacketHandler handler)
|
|
{
|
|
m_packet_handlers[packet_type] = std::move(handler);
|
|
}
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
|
|
Error &error,
|
|
bool &interrupt,
|
|
bool &quit)
|
|
{
|
|
StringExtractorGDBRemote packet;
|
|
|
|
PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec, false);
|
|
if (packet_result == PacketResult::Success)
|
|
{
|
|
const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
|
|
switch (packet_type)
|
|
{
|
|
case StringExtractorGDBRemote::eServerPacketType_nack:
|
|
case StringExtractorGDBRemote::eServerPacketType_ack:
|
|
break;
|
|
|
|
case StringExtractorGDBRemote::eServerPacketType_invalid:
|
|
error.SetErrorString("invalid packet");
|
|
quit = true;
|
|
break;
|
|
|
|
case StringExtractorGDBRemote::eServerPacketType_unimplemented:
|
|
packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
|
|
break;
|
|
|
|
default:
|
|
auto handler_it = m_packet_handlers.find(packet_type);
|
|
if (handler_it == m_packet_handlers.end())
|
|
packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
|
|
else
|
|
packet_result = handler_it->second (packet, error, interrupt, quit);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsConnected())
|
|
{
|
|
error.SetErrorString("lost connection");
|
|
quit = true;
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString("timeout");
|
|
}
|
|
}
|
|
|
|
// Check if anything occurred that would force us to want to exit.
|
|
if (m_exit_now)
|
|
quit = true;
|
|
|
|
return packet_result;
|
|
}
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
|
|
{
|
|
// TODO: Log the packet we aren't handling...
|
|
return SendPacketNoLock ("", 0);
|
|
}
|
|
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
|
|
{
|
|
char packet[16];
|
|
int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
|
|
assert (packet_len < (int)sizeof(packet));
|
|
return SendPacketNoLock (packet, packet_len);
|
|
}
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message)
|
|
{
|
|
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
|
|
if (log)
|
|
log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : "");
|
|
return SendErrorResponse (0x03);
|
|
}
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
GDBRemoteCommunicationServer::SendOKResponse ()
|
|
{
|
|
return SendPacketNoLock ("OK", 2);
|
|
}
|
|
|
|
bool
|
|
GDBRemoteCommunicationServer::HandshakeWithClient()
|
|
{
|
|
return GetAck() == PacketResult::Success;
|
|
}
|