diff options
Diffstat (limited to 'gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp')
-rw-r--r-- | gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp new file mode 100644 index 00000000000..ac6ecffcf85 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -0,0 +1,156 @@ +//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <errno.h> + +#include "lldb/Host/Config.h" + +#include "GDBRemoteCommunicationServer.h" + +#include <cstring> + +#include "ProcessGDBRemoteLog.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/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) { + RegisterPacketHandler( + StringExtractorGDBRemote::eServerPacketType_QEnableErrorStrings, + [this](StringExtractorGDBRemote packet, Status &error, bool &interrupt, + bool &quit) { return this->Handle_QErrorStringEnable(packet); }); +} + +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, Status &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().data()); + break; + + default: + auto handler_it = m_packet_handlers.find(packet_type); + if (handler_it == m_packet_handlers.end()) + packet_result = SendUnimplementedResponse(packet.GetStringRef().data()); + 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::SendErrorResponse(const Status &error) { + if (m_send_error_strings) { + lldb_private::StreamString packet; + packet.Printf("E%2.2x;", static_cast<uint8_t>(error.GetError())); + packet.PutStringAsRawHex8(error.AsCString()); + return SendPacketNoLock(packet.GetString()); + } else + return SendErrorResponse(error.GetError()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendErrorResponse(llvm::Error error) { + std::unique_ptr<llvm::ErrorInfoBase> EIB; + std::unique_ptr<PacketUnimplementedError> PUE; + llvm::handleAllErrors( + std::move(error), + [&](std::unique_ptr<PacketUnimplementedError> E) { PUE = std::move(E); }, + [&](std::unique_ptr<llvm::ErrorInfoBase> E) { EIB = std::move(E); }); + + if (EIB) + return SendErrorResponse(Status(llvm::Error(std::move(EIB)))); + if (PUE) + return SendUnimplementedResponse(PUE->message().c_str()); + return SendErrorResponse(Status("Unknown Error")); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_QErrorStringEnable( + StringExtractorGDBRemote &packet) { + m_send_error_strings = true; + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendIllFormedResponse( + const StringExtractorGDBRemote &failed_packet, const char *message) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS)); + LLDB_LOGF(log, "GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", + __FUNCTION__, failed_packet.GetStringRef().data(), + message ? message : ""); + return SendErrorResponse(0x03); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendOKResponse() { + return SendPacketNoLock("OK"); +} + +bool GDBRemoteCommunicationServer::HandshakeWithClient() { + return GetAck() == PacketResult::Success; +} + +char PacketUnimplementedError::ID; |