374 lines · cpp
1//===-- GDBRemoteClientBaseTest.cpp ---------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"10#include "GDBRemoteTestUtils.h"11#include "Plugins/Process/Utility/LinuxSignals.h"12#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"13#include "lldb/Host/ConnectionFileDescriptor.h"14#include "lldb/Utility/GDBRemote.h"15#include "lldb/Utility/Listener.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/Testing/Support/Error.h"18#include "gtest/gtest.h"19#include <chrono>20#include <future>21#include <string>22#include <vector>23 24using namespace lldb_private::process_gdb_remote;25using namespace lldb_private;26using namespace lldb;27typedef GDBRemoteCommunication::PacketResult PacketResult;28 29namespace {30 31struct MockDelegate : public GDBRemoteClientBase::ContinueDelegate {32 std::string output;33 std::string misc_data;34 unsigned stop_reply_called = 0;35 std::vector<std::string> structured_data_packets;36 37 void HandleAsyncStdout(llvm::StringRef out) override { output += out; }38 void HandleAsyncMisc(llvm::StringRef data) override { misc_data += data; }39 void HandleStopReply() override { ++stop_reply_called; }40 41 void HandleAsyncStructuredDataPacket(llvm::StringRef data) override {42 structured_data_packets.push_back(std::string(data));43 }44};45 46struct TestClient : public GDBRemoteClientBase {47 TestClient() : GDBRemoteClientBase("test.client") {48 m_send_acks = false;49 }50};51 52class GDBRemoteClientBaseTest : public GDBRemoteTest {53public:54 void SetUp() override {55 llvm::Expected<Socket::Pair> pair = Socket::CreatePair();56 ASSERT_THAT_EXPECTED(pair, llvm::Succeeded());57 client.SetConnection(58 std::make_unique<ConnectionFileDescriptor>(std::move(pair->first)));59 server.SetConnection(60 std::make_unique<ConnectionFileDescriptor>(std::move(pair->second)));61 ASSERT_EQ(TestClient::eBroadcastBitRunPacketSent,62 listener_sp->StartListeningForEvents(63 &client, TestClient::eBroadcastBitRunPacketSent));64 }65 66protected:67 // We don't have a process to get the interrupt timeout from, so make one up.68 static std::chrono::seconds g_timeout;69 TestClient client;70 MockServer server;71 MockDelegate delegate;72 ListenerSP listener_sp = Listener::MakeListener("listener");73 74 StateType SendCPacket(StringExtractorGDBRemote &response) {75 return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(),76 "c", g_timeout, 77 response);78 }79 80 void WaitForRunEvent() {81 EventSP event_sp;82 listener_sp->GetEventForBroadcasterWithType(83 &client, TestClient::eBroadcastBitRunPacketSent, event_sp,84 std::nullopt);85 }86};87 88std::chrono::seconds GDBRemoteClientBaseTest::g_timeout(10);89 90} // end anonymous namespace91 92TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {93 StringExtractorGDBRemote response;94 95 // Continue. The inferior will stop with a signal.96 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));97 ASSERT_EQ(eStateStopped, SendCPacket(response));98 ASSERT_EQ("T01", response.GetStringRef());99 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));100 ASSERT_EQ("c", response.GetStringRef());101 102 // Continue. The inferior will exit.103 ASSERT_EQ(PacketResult::Success, server.SendPacket("W01"));104 ASSERT_EQ(eStateExited, SendCPacket(response));105 ASSERT_EQ("W01", response.GetStringRef());106 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));107 ASSERT_EQ("c", response.GetStringRef());108 109 // Continue. The inferior will get killed.110 ASSERT_EQ(PacketResult::Success, server.SendPacket("X01"));111 ASSERT_EQ(eStateExited, SendCPacket(response));112 ASSERT_EQ("X01", response.GetStringRef());113 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));114 ASSERT_EQ("c", response.GetStringRef());115}116 117TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {118 StringExtractorGDBRemote continue_response, response;119 120 // SendAsyncSignal should do nothing when we are not running.121 ASSERT_FALSE(client.SendAsyncSignal(0x47, g_timeout));122 123 // Continue. After the run packet is sent, send an async signal.124 std::future<StateType> continue_state = std::async(125 std::launch::async, [&] { return SendCPacket(continue_response); });126 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));127 ASSERT_EQ("c", response.GetStringRef());128 WaitForRunEvent();129 130 std::future<bool> async_result = std::async(std::launch::async, [&] {131 return client.SendAsyncSignal(0x47, g_timeout);132 });133 134 // First we'll get interrupted.135 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));136 ASSERT_EQ("\x03", response.GetStringRef());137 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));138 139 // Then we get the signal packet.140 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));141 ASSERT_EQ("C47", response.GetStringRef());142 ASSERT_TRUE(async_result.get());143 144 // And we report back a signal stop.145 ASSERT_EQ(PacketResult::Success, server.SendPacket("T47"));146 ASSERT_EQ(eStateStopped, continue_state.get());147 ASSERT_EQ("T47", continue_response.GetStringRef());148}149 150TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) {151 StringExtractorGDBRemote continue_response, async_response, response;152 153 // Continue. After the run packet is sent, send an async packet.154 std::future<StateType> continue_state = std::async(155 std::launch::async, [&] { return SendCPacket(continue_response); });156 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));157 ASSERT_EQ("c", response.GetStringRef());158 WaitForRunEvent();159 160 // Sending without async enabled should fail.161 ASSERT_EQ(PacketResult::ErrorSendFailed,162 client.SendPacketAndWaitForResponse("qTest1", response));163 164 std::future<PacketResult> async_result = std::async(std::launch::async, [&] {165 return client.SendPacketAndWaitForResponse("qTest2", async_response,166 g_timeout);167 });168 169 // First we'll get interrupted.170 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));171 ASSERT_EQ("\x03", response.GetStringRef());172 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));173 174 // Then we get the async packet.175 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));176 ASSERT_EQ("qTest2", response.GetStringRef());177 178 // Send the response and receive it.179 ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest2"));180 ASSERT_EQ(PacketResult::Success, async_result.get());181 ASSERT_EQ("QTest2", async_response.GetStringRef());182 183 // And we get resumed again.184 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));185 ASSERT_EQ("c", response.GetStringRef());186 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));187 ASSERT_EQ(eStateStopped, continue_state.get());188 ASSERT_EQ("T01", continue_response.GetStringRef());189}190 191TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {192 StringExtractorGDBRemote continue_response, response;193 194 // Interrupt should do nothing when we're not running.195 ASSERT_FALSE(client.Interrupt(g_timeout));196 197 // Continue. After the run packet is sent, send an interrupt.198 std::future<StateType> continue_state = std::async(199 std::launch::async, [&] { return SendCPacket(continue_response); });200 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));201 ASSERT_EQ("c", response.GetStringRef());202 WaitForRunEvent();203 204 std::future<bool> async_result = std::async(205 std::launch::async, [&] { return client.Interrupt(g_timeout); });206 207 // We get interrupted.208 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));209 ASSERT_EQ("\x03", response.GetStringRef());210 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));211 212 // And that's it.213 ASSERT_EQ(eStateStopped, continue_state.get());214 ASSERT_EQ("T13", continue_response.GetStringRef());215 ASSERT_TRUE(async_result.get());216}217 218TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) {219 StringExtractorGDBRemote continue_response, response;220 221 // Continue. After the run packet is sent, send an interrupt.222 std::future<StateType> continue_state = std::async(223 std::launch::async, [&] { return SendCPacket(continue_response); });224 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));225 ASSERT_EQ("c", response.GetStringRef());226 WaitForRunEvent();227 228 std::future<bool> async_result = std::async(229 std::launch::async, [&] { return client.Interrupt(g_timeout); });230 231 // However, the target stops due to a different reason than the original232 // interrupt.233 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));234 ASSERT_EQ("\x03", response.GetStringRef());235 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));236 ASSERT_EQ(eStateStopped, continue_state.get());237 ASSERT_EQ("T01", continue_response.GetStringRef());238 ASSERT_TRUE(async_result.get());239 240 // The subsequent continue packet should work normally.241 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));242 ASSERT_EQ(eStateStopped, SendCPacket(response));243 ASSERT_EQ("T01", response.GetStringRef());244 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));245 ASSERT_EQ("c", response.GetStringRef());246}247 248TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {249 StringExtractorGDBRemote continue_response, async_response, response;250 251 // Interrupt should do nothing when we're not running.252 ASSERT_FALSE(client.Interrupt(g_timeout));253 254 // Continue. After the run packet is sent, send an async signal.255 std::future<StateType> continue_state = std::async(256 std::launch::async, [&] { return SendCPacket(continue_response); });257 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));258 ASSERT_EQ("c", response.GetStringRef());259 WaitForRunEvent();260 261 std::future<bool> interrupt_result = std::async(262 std::launch::async, [&] { return client.Interrupt(g_timeout); });263 264 // We get interrupted. We'll send two packets to simulate a buggy stub.265 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));266 ASSERT_EQ("\x03", response.GetStringRef());267 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));268 ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));269 270 // We should stop.271 ASSERT_EQ(eStateStopped, continue_state.get());272 ASSERT_EQ("T13", continue_response.GetStringRef());273 ASSERT_TRUE(interrupt_result.get());274 275 // Packet stream should remain synchronized.276 std::future<PacketResult> send_result = std::async(std::launch::async, [&] {277 return client.SendPacketAndWaitForResponse("qTest", async_response);278 });279 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));280 ASSERT_EQ("qTest", response.GetStringRef());281 ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest"));282 ASSERT_EQ(PacketResult::Success, send_result.get());283 ASSERT_EQ("QTest", async_response.GetStringRef());284}285 286TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {287 StringExtractorGDBRemote response;288 289 // Continue. We'll have the server send a bunch of async packets before it290 // stops.291 ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142"));292 ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro"));293 ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344"));294 ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile"));295 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));296 ASSERT_EQ(eStateStopped, SendCPacket(response));297 ASSERT_EQ("T01", response.GetStringRef());298 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));299 ASSERT_EQ("c", response.GetStringRef());300 301 EXPECT_EQ("ABCD", delegate.output);302 EXPECT_EQ("profile", delegate.misc_data);303 EXPECT_EQ(1u, delegate.stop_reply_called);304}305 306TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {307 // Build the plain-text version of the JSON data we will have the308 // server send.309 const std::string json_payload =310 "{ \"type\": \"MyFeatureType\", "311 " \"elements\": [ \"entry1\", \"entry2\" ] }";312 const std::string json_packet = "JSON-async:" + json_payload;313 314 // Escape it properly for transit.315 StreamGDBRemote stream;316 stream.PutEscapedBytes(json_packet.c_str(), json_packet.length());317 stream.Flush();318 319 StringExtractorGDBRemote response;320 321 // Send async structured data packet, then stop.322 ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData()));323 ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));324 ASSERT_EQ(eStateStopped, SendCPacket(response));325 ASSERT_EQ("T01", response.GetStringRef());326 ASSERT_EQ(1ul, delegate.structured_data_packets.size());327 328 // Verify the packet contents. It should have been unescaped upon packet329 // reception.330 ASSERT_EQ(json_packet, delegate.structured_data_packets[0]);331}332 333TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) {334 StringExtractorGDBRemote continue_response, response;335 336 // Continue. After the run packet is sent, send an interrupt.337 std::future<StateType> continue_state = std::async(338 std::launch::async, [&] { return SendCPacket(continue_response); });339 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));340 ASSERT_EQ("c", response.GetStringRef());341 WaitForRunEvent();342 343 std::future<bool> async_result = std::async(344 std::launch::async, [&] { return client.Interrupt(g_timeout); });345 346 // We get interrupted, but we don't send a stop packet.347 ASSERT_EQ(PacketResult::Success, server.GetPacket(response));348 ASSERT_EQ("\x03", response.GetStringRef());349 350 // The functions should still terminate (after a timeout).351 ASSERT_TRUE(async_result.get());352 ASSERT_EQ(eStateInvalid, continue_state.get());353}354 355TEST_F(GDBRemoteClientBaseTest, SendPacketAndReceiveResponseWithOutputSupport) {356 StringExtractorGDBRemote response;357 StreamString command_output;358 359 ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));360 ASSERT_EQ(PacketResult::Success, server.SendPacket("O48656c6c6f2c"));361 ASSERT_EQ(PacketResult::Success, server.SendPacket("O20"));362 ASSERT_EQ(PacketResult::Success, server.SendPacket("O"));363 ASSERT_EQ(PacketResult::Success, server.SendPacket("O776f726c64"));364 ASSERT_EQ(PacketResult::Success, server.SendPacket("OK"));365 366 PacketResult result = client.SendPacketAndReceiveResponseWithOutputSupport(367 "qRcmd,test", response, g_timeout,368 [&command_output](llvm::StringRef output) { command_output << output; });369 370 ASSERT_EQ(PacketResult::Success, result);371 ASSERT_EQ("OK", response.GetStringRef());372 ASSERT_EQ("Hello, world", command_output.GetString().str());373}374