//===-- GDBRemoteClientBaseTest.cpp -----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #if defined(_MSC_VER) && (_HAS_EXCEPTIONS == 0) // Workaround for MSVC standard library bug, which fails to include // when // exceptions are disabled. #include #endif #include #include "GDBRemoteTestUtils.h" #include "gtest/gtest.h" #include "Plugins/Process/Utility/LinuxSignals.h" #include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h" #include "llvm/ADT/STLExtras.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; void HandleAsyncStdout(llvm::StringRef out) { output += out; } void HandleAsyncMisc(llvm::StringRef data) { misc_data += data; } void HandleStopReply() { ++stop_reply_called; } bool HandleAsyncStructuredData(const StructuredData::ObjectSP &object_sp) { // TODO work in a test here after I fix the gtest breakage. return true; } }; struct TestClient : public GDBRemoteClientBase { TestClient() : GDBRemoteClientBase("test.client", "test.client.listener") { m_send_acks = false; } }; struct ContinueFixture { MockDelegate delegate; TestClient client; MockServer server; ListenerSP listener_sp; ContinueFixture(); StateType SendCPacket(StringExtractorGDBRemote &response) { return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(), "c", response); } void WaitForRunEvent() { EventSP event_sp; listener_sp->WaitForEventForBroadcasterWithType( std::chrono::microseconds(0), &client, TestClient::eBroadcastBitRunPacketSent, event_sp); } }; ContinueFixture::ContinueFixture() : listener_sp(Listener::MakeListener("listener")) { Connect(client, server); listener_sp->StartListeningForEvents(&client, TestClient::eBroadcastBitRunPacketSent); } } // end anonymous namespace class GDBRemoteClientBaseTest : public GDBRemoteTest {}; TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) { StringExtractorGDBRemote response; ContinueFixture fix; if (HasFailure()) return; // Continue. The inferior will stop with a signal. ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01")); ASSERT_EQ(eStateStopped, fix.SendCPacket(response)); ASSERT_EQ("T01", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); // Continue. The inferior will exit. ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("W01")); ASSERT_EQ(eStateExited, fix.SendCPacket(response)); ASSERT_EQ("W01", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); // Continue. The inferior will get killed. ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("X01")); ASSERT_EQ(eStateExited, fix.SendCPacket(response)); ASSERT_EQ("X01", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); } TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) { StringExtractorGDBRemote continue_response, response; ContinueFixture fix; if (HasFailure()) return; // SendAsyncSignal should do nothing when we are not running. ASSERT_FALSE(fix.client.SendAsyncSignal(0x47)); // Continue. After the run packet is sent, send an async signal. std::future continue_state = std::async( std::launch::async, [&] { return fix.SendCPacket(continue_response); }); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); fix.WaitForRunEvent(); std::future async_result = std::async( std::launch::async, [&] { return fix.client.SendAsyncSignal(0x47); }); // First we'll get interrupted. ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("\x03", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13")); // Then we get the signal packet. ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("C47", response.GetStringRef()); ASSERT_TRUE(async_result.get()); // And we report back a signal stop. ASSERT_EQ(PacketResult::Success, fix.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; ContinueFixture fix; if (HasFailure()) return; // Continue. After the run packet is sent, send an async packet. std::future continue_state = std::async( std::launch::async, [&] { return fix.SendCPacket(continue_response); }); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); fix.WaitForRunEvent(); // Sending without async enabled should fail. ASSERT_EQ( PacketResult::ErrorSendFailed, fix.client.SendPacketAndWaitForResponse("qTest1", response, !send_async)); std::future async_result = std::async(std::launch::async, [&] { return fix.client.SendPacketAndWaitForResponse("qTest2", async_response, send_async); }); // First we'll get interrupted. ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("\x03", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13")); // Then we get the async packet. ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("qTest2", response.GetStringRef()); // Send the response and receive it. ASSERT_EQ(PacketResult::Success, fix.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, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01")); ASSERT_EQ(eStateStopped, continue_state.get()); ASSERT_EQ("T01", continue_response.GetStringRef()); } TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) { StringExtractorGDBRemote continue_response, response; ContinueFixture fix; if (HasFailure()) return; // Interrupt should do nothing when we're not running. ASSERT_FALSE(fix.client.Interrupt()); // Continue. After the run packet is sent, send an interrupt. std::future continue_state = std::async( std::launch::async, [&] { return fix.SendCPacket(continue_response); }); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); fix.WaitForRunEvent(); std::future async_result = std::async(std::launch::async, [&] { return fix.client.Interrupt(); }); // We get interrupted. ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("\x03", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.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; ContinueFixture fix; if (HasFailure()) return; // Continue. After the run packet is sent, send an interrupt. std::future continue_state = std::async( std::launch::async, [&] { return fix.SendCPacket(continue_response); }); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); fix.WaitForRunEvent(); std::future async_result = std::async(std::launch::async, [&] { return fix.client.Interrupt(); }); // However, the target stops due to a different reason than the original // interrupt. ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("\x03", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.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, fix.server.SendPacket("T01")); ASSERT_EQ(eStateStopped, fix.SendCPacket(response)); ASSERT_EQ("T01", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); } TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) { StringExtractorGDBRemote continue_response, async_response, response; const bool send_async = true; ContinueFixture fix; if (HasFailure()) return; // Interrupt should do nothing when we're not running. ASSERT_FALSE(fix.client.Interrupt()); // Continue. After the run packet is sent, send an async signal. std::future continue_state = std::async( std::launch::async, [&] { return fix.SendCPacket(continue_response); }); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); fix.WaitForRunEvent(); std::future interrupt_result = std::async(std::launch::async, [&] { return fix.client.Interrupt(); }); // We get interrupted. We'll send two packets to simulate a buggy stub. ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("\x03", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13")); ASSERT_EQ(PacketResult::Success, fix.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 send_result = std::async(std::launch::async, [&] { return fix.client.SendPacketAndWaitForResponse("qTest", async_response, !send_async); }); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("qTest", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("QTest")); ASSERT_EQ(PacketResult::Success, send_result.get()); ASSERT_EQ("QTest", async_response.GetStringRef()); } TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) { StringExtractorGDBRemote response; ContinueFixture fix; if (HasFailure()) return; // Continue. We'll have the server send a bunch of async packets before it // stops. ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4142")); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Apro")); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4344")); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Afile")); ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01")); ASSERT_EQ(eStateStopped, fix.SendCPacket(response)); ASSERT_EQ("T01", response.GetStringRef()); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); EXPECT_EQ("ABCD", fix.delegate.output); EXPECT_EQ("profile", fix.delegate.misc_data); EXPECT_EQ(1u, fix.delegate.stop_reply_called); } TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) { StringExtractorGDBRemote continue_response, response; ContinueFixture fix; if (HasFailure()) return; // Continue. After the run packet is sent, send an interrupt. std::future continue_state = std::async( std::launch::async, [&] { return fix.SendCPacket(continue_response); }); ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response)); ASSERT_EQ("c", response.GetStringRef()); fix.WaitForRunEvent(); std::future async_result = std::async(std::launch::async, [&] { return fix.client.Interrupt(); }); // We get interrupted, but we don't send a stop packet. ASSERT_EQ(PacketResult::Success, fix.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()); }