mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-16 05:10:32 +00:00

Summary: This replaces the usage of raw integers with duration classes in the gdb-remote packet management functions. The values are still converted back to integers once they go into the generic Communication class -- that I am leaving to a separate change. The changes are mostly straight-forward (*), the only tricky part was representation of infinite timeouts. Currently, we use UINT32_MAX to denote infinite timeout. This is not well suited for duration classes, as they tend to do arithmetic on the values, and the identity of the MAX value can easily get lost (e.g. microseconds(seconds(UINT32_MAX)).count() != UINT32_MAX). We cannot use zero to represent infinity (as Listener classes do) because we already use it to do non-blocking polling reads. For this reason, I chose to have an explicit value for infinity. The way I achieved that is via llvm::Optional, and I think it reads quite natural. Passing llvm::None as "timeout" means "no timeout", while passing zero means "poll". The only tricky part is this breaks implicit conversions (seconds are implicitly convertible to microseconds, but Optional<seconds> cannot be easily converted into Optional<microseconds>). For this reason I added a special class Timeout, inheriting from Optional, and enabling the necessary conversions one would normally expect. (*) The other tricky part was GDBRemoteCommunication::PopPacketFromQueue, which was needlessly complicated. I've simplified it, but that one is only used in non-stop mode, and so is untested. Reviewers: clayborg, zturner, jingham Subscribers: lldb-commits Differential Revision: https://reviews.llvm.org/D26971 llvm-svn: 287864
121 lines
3.8 KiB
C++
121 lines
3.8 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(
|
|
Timeout<std::micro> timeout, Error &error, bool &interrupt, bool &quit) {
|
|
StringExtractorGDBRemote packet;
|
|
|
|
PacketResult packet_result = WaitForPacketNoLock(packet, timeout, 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("");
|
|
}
|
|
|
|
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(llvm::StringRef(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");
|
|
}
|
|
|
|
bool GDBRemoteCommunicationServer::HandshakeWithClient() {
|
|
return GetAck() == PacketResult::Success;
|
|
}
|