brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.5 KiB · b28b801 Raw
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