//===-- TestClient.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_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H #define LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H #include "MessageObjects.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" #include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Connection.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Casting.h" #include "llvm/Support/FormatVariadic.h" #include #include #if LLDB_SERVER_IS_DEBUGSERVER #define LLGS_TEST(x) DISABLED_ ## x #define DS_TEST(x) x #else #define LLGS_TEST(x) x #define DS_TEST(x) DISABLED_ ## x #endif namespace llgs_tests { class TestClient : public lldb_private::process_gdb_remote::GDBRemoteCommunicationClient { public: static bool IsDebugServer() { return LLDB_SERVER_IS_DEBUGSERVER; } static bool IsLldbServer() { return !IsDebugServer(); } /// Launches the server, connects it to the client and returns the client. If /// Log is non-empty, the server will write it's log to this file. static llvm::Expected> launch(llvm::StringRef Log); /// Launches the server, while specifying the inferior on its command line. /// When the client connects, it already has a process ready. static llvm::Expected> launch(llvm::StringRef Log, llvm::ArrayRef InferiorArgs); /// Allows user to pass additional arguments to the server. Be careful when /// using this for generic tests, as the two stubs have different /// command-line interfaces. static llvm::Expected> launchCustom(llvm::StringRef Log, llvm::ArrayRef ServerArgs, llvm::ArrayRef InferiorArgs); ~TestClient() override; llvm::Error SetInferior(llvm::ArrayRef inferior_args); llvm::Error ListThreadsInStopReply(); llvm::Error SetBreakpoint(unsigned long address); llvm::Error ContinueAll(); llvm::Error ContinueThread(unsigned long thread_id); const ProcessInfo &GetProcessInfo(); llvm::Expected GetJThreadsInfo(); const StopReply &GetLatestStopReply(); template llvm::Expected GetLatestStopReplyAs() { assert(m_stop_reply); if (const auto *Reply = llvm::dyn_cast(m_stop_reply.get())) return *Reply; return llvm::make_error( llvm::formatv("Unexpected Stop Reply {0}", m_stop_reply->getKind()), llvm::inconvertibleErrorCode()); } llvm::Error SendMessage(llvm::StringRef message); llvm::Error SendMessage(llvm::StringRef message, std::string &response_string); llvm::Error SendMessage(llvm::StringRef message, std::string &response_string, PacketResult expected_result); template llvm::Expected SendMessage(llvm::StringRef Message, CreateArgs &&... Args); unsigned int GetPcRegisterId(); private: TestClient(std::unique_ptr Conn); llvm::Error initializeConnection(); llvm::Error qProcessInfo(); llvm::Error qRegisterInfos(); llvm::Error queryProcess(); llvm::Error Continue(llvm::StringRef message); std::string FormatFailedResult( const std::string &message, lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult result); llvm::Optional m_process_info; std::unique_ptr m_stop_reply; std::vector m_register_infos; unsigned int m_pc_register = LLDB_INVALID_REGNUM; }; template llvm::Expected TestClient::SendMessage(llvm::StringRef Message, CreateArgs &&... Args) { std::string ResponseText; if (llvm::Error E = SendMessage(Message, ResponseText)) return std::move(E); return P::create(ResponseText, std::forward(Args)...); } } // namespace llgs_tests #endif // LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H