Files
clang-p2996/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
Pavel Labath 165545c7a4 [lldb/gdb-remote] Ignore spurious ACK packets
Although I cannot find any mention of this in the specification, both
gdb and lldb agree on sending an initial + packet after establishing the
connection.

OTOH, gdbserver and lldb-server behavior is subtly different. While
lldb-server *expects* the initial ack, and drops the connection if it is
not received, gdbserver will just ignore a spurious ack at _any_ point
in the connection.

This patch changes lldb's behavior to match that of gdb. An ACK packet
is ignored at any point in the connection (except when expecting an ACK
packet, of course). This is inline with the "be strict in what you
generate, and lenient in what you accept" philosophy, and also enables
us to remove some special cases from the server code. I've extended the
same handling to NAK (-) packets, mainly because I don't see a reason to
treat them differently here.

(The background here is that we had a stub which was sending spurious
+ packets. This bug has since been fixed, but I think this change makes
sense nonetheless.)

Differential Revision: https://reviews.llvm.org/D114520
2021-11-25 12:34:08 +01:00

170 lines
5.7 KiB
C++

//===-- GDBRemoteCommunicationServer.cpp ----------------------------------===//
//
// 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 <cerrno>
#include "lldb/Host/Config.h"
#include "GDBRemoteCommunicationServer.h"
#include "ProcessGDBRemoteLog.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
#include "lldb/Utility/UnimplementedError.h"
#include "llvm/Support/JSON.h"
#include <cstring>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
using namespace llvm;
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() = default;
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 = ReadPacket(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) {
assert(error);
std::unique_ptr<llvm::ErrorInfoBase> EIB;
std::unique_ptr<UnimplementedError> UE;
llvm::handleAllErrors(
std::move(error),
[&](std::unique_ptr<UnimplementedError> E) { UE = std::move(E); },
[&](std::unique_ptr<llvm::ErrorInfoBase> E) { EIB = std::move(E); });
if (EIB)
return SendErrorResponse(Status(llvm::Error(std::move(EIB))));
return SendUnimplementedResponse("");
}
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");
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendJSONResponse(const json::Value &value) {
std::string json_string;
raw_string_ostream os(json_string);
os << value;
os.flush();
StreamGDBRemote escaped_response;
escaped_response.PutEscapedBytes(json_string.c_str(), json_string.size());
return SendPacketNoLock(escaped_response.GetString());
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendJSONResponse(Expected<json::Value> value) {
if (!value)
return SendErrorResponse(value.takeError());
return SendJSONResponse(*value);
}