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
91 lines
2.9 KiB
C++
91 lines
2.9 KiB
C++
//===-- GDBRemoteTestUtils.h ------------------------------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef LLDB_UNITTESTS_PROCESS_GDB_REMOTE_GDBREMOTETESTUTILS_H
|
|
#define LLDB_UNITTESTS_PROCESS_GDB_REMOTE_GDBREMOTETESTUTILS_H
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
|
|
#include "lldb/Utility/Connection.h"
|
|
|
|
namespace lldb_private {
|
|
namespace process_gdb_remote {
|
|
|
|
class GDBRemoteTest : public testing::Test {
|
|
public:
|
|
static void SetUpTestCase();
|
|
static void TearDownTestCase();
|
|
};
|
|
|
|
class MockConnection : public lldb_private::Connection {
|
|
public:
|
|
MockConnection(std::vector<std::string> &packets) { m_packets = &packets; };
|
|
|
|
MOCK_METHOD2(Connect,
|
|
lldb::ConnectionStatus(llvm::StringRef url, Status *error_ptr));
|
|
MOCK_METHOD5(Read, size_t(void *dst, size_t dst_len,
|
|
const Timeout<std::micro> &timeout,
|
|
lldb::ConnectionStatus &status, Status *error_ptr));
|
|
MOCK_METHOD0(GetURI, std::string());
|
|
MOCK_METHOD0(InterruptRead, bool());
|
|
|
|
lldb::ConnectionStatus Disconnect(Status *error_ptr) {
|
|
return lldb::eConnectionStatusSuccess;
|
|
};
|
|
|
|
bool IsConnected() const { return true; };
|
|
size_t Write(const void *dst, size_t dst_len, lldb::ConnectionStatus &status,
|
|
Status *error_ptr) {
|
|
m_packets->emplace_back(static_cast<const char *>(dst), dst_len);
|
|
return dst_len;
|
|
};
|
|
|
|
lldb::IOObjectSP GetReadObject() { return lldb::IOObjectSP(); }
|
|
|
|
std::vector<std::string> *m_packets;
|
|
};
|
|
|
|
class MockServer : public GDBRemoteCommunicationServer {
|
|
public:
|
|
MockServer()
|
|
: GDBRemoteCommunicationServer("mock-server", "mock-server.listener") {
|
|
m_send_acks = false;
|
|
m_send_error_strings = true;
|
|
}
|
|
|
|
PacketResult SendPacket(llvm::StringRef payload) {
|
|
return GDBRemoteCommunicationServer::SendPacketNoLock(payload);
|
|
}
|
|
|
|
PacketResult GetPacket(StringExtractorGDBRemote &response) {
|
|
const bool sync_on_timeout = false;
|
|
return ReadPacket(response, std::chrono::seconds(1), sync_on_timeout);
|
|
}
|
|
|
|
using GDBRemoteCommunicationServer::SendErrorResponse;
|
|
using GDBRemoteCommunicationServer::SendOKResponse;
|
|
using GDBRemoteCommunicationServer::SendUnimplementedResponse;
|
|
};
|
|
|
|
class MockServerWithMockConnection : public MockServer {
|
|
public:
|
|
MockServerWithMockConnection() : MockServer() {
|
|
SetConnection(std::make_unique<MockConnection>(m_packets));
|
|
}
|
|
|
|
llvm::ArrayRef<std::string> GetPackets() { return m_packets; };
|
|
|
|
std::vector<std::string> m_packets;
|
|
};
|
|
|
|
} // namespace process_gdb_remote
|
|
} // namespace lldb_private
|
|
|
|
#endif // LLDB_UNITTESTS_PROCESS_GDB_REMOTE_GDBREMOTETESTUTILS_H
|