diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp')
-rw-r--r-- | gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp new file mode 100644 index 00000000000..d56e9cf81bc --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp @@ -0,0 +1,361 @@ +//===-- GDBRemoteClientBaseTest.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 <future> + +#include "GDBRemoteTestUtils.h" + +#include "Plugins/Process/Utility/LinuxSignals.h" +#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h" +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h" +#include "lldb/Utility/GDBRemote.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Testing/Support/Error.h" + +using namespace lldb_private::process_gdb_remote; +using namespace lldb_private; +using namespace lldb; +typedef GDBRemoteCommunication::PacketResult PacketResult; + +namespace { + +struct MockDelegate : public GDBRemoteClientBase::ContinueDelegate { + std::string output; + std::string misc_data; + unsigned stop_reply_called = 0; + std::vector<std::string> structured_data_packets; + + void HandleAsyncStdout(llvm::StringRef out) override { output += out; } + void HandleAsyncMisc(llvm::StringRef data) override { misc_data += data; } + void HandleStopReply() override { ++stop_reply_called; } + + void HandleAsyncStructuredDataPacket(llvm::StringRef data) override { + structured_data_packets.push_back(data); + } +}; + +struct TestClient : public GDBRemoteClientBase { + TestClient() : GDBRemoteClientBase("test.client", "test.client.listener") { + m_send_acks = false; + } +}; + +class GDBRemoteClientBaseTest : public GDBRemoteTest { +public: + void SetUp() override { + ASSERT_THAT_ERROR(GDBRemoteCommunication::ConnectLocally(client, server), + llvm::Succeeded()); + ASSERT_EQ(TestClient::eBroadcastBitRunPacketSent, + listener_sp->StartListeningForEvents( + &client, TestClient::eBroadcastBitRunPacketSent)); + } + +protected: + TestClient client; + MockServer server; + MockDelegate delegate; + ListenerSP listener_sp = Listener::MakeListener("listener"); + + StateType SendCPacket(StringExtractorGDBRemote &response) { + return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(), + "c", response); + } + + void WaitForRunEvent() { + EventSP event_sp; + listener_sp->GetEventForBroadcasterWithType( + &client, TestClient::eBroadcastBitRunPacketSent, event_sp, llvm::None); + } +}; + +} // end anonymous namespace + +TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) { + StringExtractorGDBRemote response; + + // Continue. The inferior will stop with a signal. + ASSERT_EQ(PacketResult::Success, server.SendPacket("T01")); + ASSERT_EQ(eStateStopped, SendCPacket(response)); + ASSERT_EQ("T01", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + + // Continue. The inferior will exit. + ASSERT_EQ(PacketResult::Success, server.SendPacket("W01")); + ASSERT_EQ(eStateExited, SendCPacket(response)); + ASSERT_EQ("W01", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + + // Continue. The inferior will get killed. + ASSERT_EQ(PacketResult::Success, server.SendPacket("X01")); + ASSERT_EQ(eStateExited, SendCPacket(response)); + ASSERT_EQ("X01", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); +} + +TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) { + StringExtractorGDBRemote continue_response, response; + + // SendAsyncSignal should do nothing when we are not running. + ASSERT_FALSE(client.SendAsyncSignal(0x47)); + + // Continue. After the run packet is sent, send an async signal. + std::future<StateType> continue_state = std::async( + std::launch::async, [&] { return SendCPacket(continue_response); }); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + WaitForRunEvent(); + + std::future<bool> async_result = std::async( + std::launch::async, [&] { return client.SendAsyncSignal(0x47); }); + + // First we'll get interrupted. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("\x03", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T13")); + + // Then we get the signal packet. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("C47", response.GetStringRef()); + ASSERT_TRUE(async_result.get()); + + // And we report back a signal stop. + ASSERT_EQ(PacketResult::Success, server.SendPacket("T47")); + ASSERT_EQ(eStateStopped, continue_state.get()); + ASSERT_EQ("T47", continue_response.GetStringRef()); +} + +TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) { + StringExtractorGDBRemote continue_response, async_response, response; + const bool send_async = true; + + // Continue. After the run packet is sent, send an async packet. + std::future<StateType> continue_state = std::async( + std::launch::async, [&] { return SendCPacket(continue_response); }); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + WaitForRunEvent(); + + // Sending without async enabled should fail. + ASSERT_EQ( + PacketResult::ErrorSendFailed, + client.SendPacketAndWaitForResponse("qTest1", response, !send_async)); + + std::future<PacketResult> async_result = std::async(std::launch::async, [&] { + return client.SendPacketAndWaitForResponse("qTest2", async_response, + send_async); + }); + + // First we'll get interrupted. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("\x03", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T13")); + + // Then we get the async packet. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("qTest2", response.GetStringRef()); + + // Send the response and receive it. + ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest2")); + ASSERT_EQ(PacketResult::Success, async_result.get()); + ASSERT_EQ("QTest2", async_response.GetStringRef()); + + // And we get resumed again. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T01")); + ASSERT_EQ(eStateStopped, continue_state.get()); + ASSERT_EQ("T01", continue_response.GetStringRef()); +} + +TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) { + StringExtractorGDBRemote continue_response, response; + + // Interrupt should do nothing when we're not running. + ASSERT_FALSE(client.Interrupt()); + + // Continue. After the run packet is sent, send an interrupt. + std::future<StateType> continue_state = std::async( + std::launch::async, [&] { return SendCPacket(continue_response); }); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + WaitForRunEvent(); + + std::future<bool> async_result = + std::async(std::launch::async, [&] { return client.Interrupt(); }); + + // We get interrupted. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("\x03", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T13")); + + // And that's it. + ASSERT_EQ(eStateStopped, continue_state.get()); + ASSERT_EQ("T13", continue_response.GetStringRef()); + ASSERT_TRUE(async_result.get()); +} + +TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) { + StringExtractorGDBRemote continue_response, response; + + // Continue. After the run packet is sent, send an interrupt. + std::future<StateType> continue_state = std::async( + std::launch::async, [&] { return SendCPacket(continue_response); }); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + WaitForRunEvent(); + + std::future<bool> async_result = + std::async(std::launch::async, [&] { return client.Interrupt(); }); + + // However, the target stops due to a different reason than the original + // interrupt. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("\x03", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T01")); + ASSERT_EQ(eStateStopped, continue_state.get()); + ASSERT_EQ("T01", continue_response.GetStringRef()); + ASSERT_TRUE(async_result.get()); + + // The subsequent continue packet should work normally. + ASSERT_EQ(PacketResult::Success, server.SendPacket("T01")); + ASSERT_EQ(eStateStopped, SendCPacket(response)); + ASSERT_EQ("T01", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); +} + +TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) { + StringExtractorGDBRemote continue_response, async_response, response; + const bool send_async = true; + + // Interrupt should do nothing when we're not running. + ASSERT_FALSE(client.Interrupt()); + + // Continue. After the run packet is sent, send an async signal. + std::future<StateType> continue_state = std::async( + std::launch::async, [&] { return SendCPacket(continue_response); }); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + WaitForRunEvent(); + + std::future<bool> interrupt_result = + std::async(std::launch::async, [&] { return client.Interrupt(); }); + + // We get interrupted. We'll send two packets to simulate a buggy stub. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("\x03", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T13")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T13")); + + // We should stop. + ASSERT_EQ(eStateStopped, continue_state.get()); + ASSERT_EQ("T13", continue_response.GetStringRef()); + ASSERT_TRUE(interrupt_result.get()); + + // Packet stream should remain synchronized. + std::future<PacketResult> send_result = std::async(std::launch::async, [&] { + return client.SendPacketAndWaitForResponse("qTest", async_response, + !send_async); + }); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("qTest", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest")); + ASSERT_EQ(PacketResult::Success, send_result.get()); + ASSERT_EQ("QTest", async_response.GetStringRef()); +} + +TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) { + StringExtractorGDBRemote response; + + // Continue. We'll have the server send a bunch of async packets before it + // stops. + ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T01")); + ASSERT_EQ(eStateStopped, SendCPacket(response)); + ASSERT_EQ("T01", response.GetStringRef()); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + + EXPECT_EQ("ABCD", delegate.output); + EXPECT_EQ("profile", delegate.misc_data); + EXPECT_EQ(1u, delegate.stop_reply_called); +} + +TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) { + // Build the plain-text version of the JSON data we will have the + // server send. + const std::string json_payload = + "{ \"type\": \"MyFeatureType\", " + " \"elements\": [ \"entry1\", \"entry2\" ] }"; + const std::string json_packet = "JSON-async:" + json_payload; + + // Escape it properly for transit. + StreamGDBRemote stream; + stream.PutEscapedBytes(json_packet.c_str(), json_packet.length()); + stream.Flush(); + + StringExtractorGDBRemote response; + + // Send async structured data packet, then stop. + ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData())); + ASSERT_EQ(PacketResult::Success, server.SendPacket("T01")); + ASSERT_EQ(eStateStopped, SendCPacket(response)); + ASSERT_EQ("T01", response.GetStringRef()); + ASSERT_EQ(1ul, delegate.structured_data_packets.size()); + + // Verify the packet contents. It should have been unescaped upon packet + // reception. + ASSERT_EQ(json_packet, delegate.structured_data_packets[0]); +} + +TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) { + StringExtractorGDBRemote continue_response, response; + + // Continue. After the run packet is sent, send an interrupt. + std::future<StateType> continue_state = std::async( + std::launch::async, [&] { return SendCPacket(continue_response); }); + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("c", response.GetStringRef()); + WaitForRunEvent(); + + std::future<bool> async_result = + std::async(std::launch::async, [&] { return client.Interrupt(); }); + + // We get interrupted, but we don't send a stop packet. + ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); + ASSERT_EQ("\x03", response.GetStringRef()); + + // The functions should still terminate (after a timeout). + ASSERT_TRUE(async_result.get()); + ASSERT_EQ(eStateInvalid, continue_state.get()); +} + +TEST_F(GDBRemoteClientBaseTest, SendPacketAndReceiveResponseWithOutputSupport) { + StringExtractorGDBRemote response; + StreamString command_output; + + ASSERT_EQ(PacketResult::Success, server.SendPacket("O")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("O48656c6c6f2c")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("O20")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("O")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("O776f726c64")); + ASSERT_EQ(PacketResult::Success, server.SendPacket("OK")); + + PacketResult result = client.SendPacketAndReceiveResponseWithOutputSupport( + "qRcmd,test", response, true, + [&command_output](llvm::StringRef output) { command_output << output; }); + + ASSERT_EQ(PacketResult::Success, result); + ASSERT_EQ("OK", response.GetStringRef()); + ASSERT_EQ("Hello, world", command_output.GetString().str()); +} |