| 1 | //===-- TestClient.h --------------------------------------------*- C++ -*-===// |
| 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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H |
| 10 | #define LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H |
| 11 | |
| 12 | #include "MessageObjects.h" |
| 13 | #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h" |
| 14 | #include "lldb/Host/ProcessLaunchInfo.h" |
| 15 | #include "lldb/Utility/ArchSpec.h" |
| 16 | #include "lldb/Utility/Connection.h" |
| 17 | #include "llvm/Support/Casting.h" |
| 18 | #include "llvm/Support/FormatVariadic.h" |
| 19 | #include <memory> |
| 20 | #include <optional> |
| 21 | #include <string> |
| 22 | |
| 23 | #ifdef SendMessage |
| 24 | #undef SendMessage |
| 25 | #endif |
| 26 | |
| 27 | #if LLDB_SERVER_IS_DEBUGSERVER |
| 28 | #define LLGS_TEST(x) DISABLED_ ## x |
| 29 | #define DS_TEST(x) x |
| 30 | #else |
| 31 | #define LLGS_TEST(x) x |
| 32 | #define DS_TEST(x) DISABLED_ ## x |
| 33 | #endif |
| 34 | |
| 35 | namespace llgs_tests { |
| 36 | class TestClient |
| 37 | : public lldb_private::process_gdb_remote::GDBRemoteCommunicationClient { |
| 38 | public: |
| 39 | static bool IsDebugServer() { return LLDB_SERVER_IS_DEBUGSERVER; } |
| 40 | static bool IsLldbServer() { return !IsDebugServer(); } |
| 41 | |
| 42 | /// Launches the server, connects it to the client and returns the client. If |
| 43 | /// Log is non-empty, the server will write it's log to this file. |
| 44 | static llvm::Expected<std::unique_ptr<TestClient>> launch(llvm::StringRef Log); |
| 45 | |
| 46 | /// Launches the server, while specifying the inferior on its command line. |
| 47 | /// When the client connects, it already has a process ready. |
| 48 | static llvm::Expected<std::unique_ptr<TestClient>> |
| 49 | launch(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> InferiorArgs); |
| 50 | |
| 51 | /// Allows user to pass additional arguments to the server. Be careful when |
| 52 | /// using this for generic tests, as the two stubs have different |
| 53 | /// command-line interfaces. |
| 54 | static llvm::Expected<std::unique_ptr<TestClient>> |
| 55 | launchCustom(llvm::StringRef Log, bool disable_stdio, |
| 56 | llvm::ArrayRef<llvm::StringRef> ServerArgs, |
| 57 | llvm::ArrayRef<llvm::StringRef> InferiorArgs); |
| 58 | |
| 59 | ~TestClient() override; |
| 60 | llvm::Error SetInferior(llvm::ArrayRef<std::string> inferior_args); |
| 61 | llvm::Error ListThreadsInStopReply(); |
| 62 | llvm::Error SetBreakpoint(unsigned long address); |
| 63 | llvm::Error ContinueAll(); |
| 64 | llvm::Error ContinueThread(unsigned long thread_id); |
| 65 | const ProcessInfo &GetProcessInfo(); |
| 66 | llvm::Expected<JThreadsInfo> GetJThreadsInfo(); |
| 67 | const StopReply &GetLatestStopReply(); |
| 68 | template <typename T> llvm::Expected<const T &> GetLatestStopReplyAs() { |
| 69 | assert(m_stop_reply); |
| 70 | if (const auto *Reply = llvm::dyn_cast<T>(m_stop_reply.get())) |
| 71 | return *Reply; |
| 72 | return llvm::make_error<llvm::StringError>( |
| 73 | Args: llvm::formatv(Fmt: "Unexpected Stop Reply {0}" , Vals: m_stop_reply->getKind()), |
| 74 | Args: llvm::inconvertibleErrorCode()); |
| 75 | } |
| 76 | llvm::Error SendMessage(llvm::StringRef message); |
| 77 | llvm::Error SendMessage(llvm::StringRef message, |
| 78 | std::string &response_string); |
| 79 | llvm::Error SendMessage(llvm::StringRef message, std::string &response_string, |
| 80 | PacketResult expected_result); |
| 81 | |
| 82 | template <typename P, typename... CreateArgs> |
| 83 | llvm::Expected<typename P::result_type> SendMessage(llvm::StringRef Message, |
| 84 | CreateArgs &&... Args); |
| 85 | unsigned int GetPcRegisterId(); |
| 86 | |
| 87 | private: |
| 88 | TestClient(std::unique_ptr<lldb_private::Connection> Conn); |
| 89 | |
| 90 | llvm::Error initializeConnection(); |
| 91 | llvm::Error qProcessInfo(); |
| 92 | llvm::Error qRegisterInfos(); |
| 93 | llvm::Error queryProcess(); |
| 94 | llvm::Error Continue(llvm::StringRef message); |
| 95 | std::string FormatFailedResult( |
| 96 | const std::string &message, |
| 97 | lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult |
| 98 | result); |
| 99 | |
| 100 | std::optional<ProcessInfo> m_process_info; |
| 101 | std::unique_ptr<StopReply> m_stop_reply; |
| 102 | std::vector<lldb_private::RegisterInfo> m_register_infos; |
| 103 | unsigned int m_pc_register = LLDB_INVALID_REGNUM; |
| 104 | }; |
| 105 | |
| 106 | template <typename P, typename... CreateArgs> |
| 107 | llvm::Expected<typename P::result_type> |
| 108 | TestClient::SendMessage(llvm::StringRef Message, CreateArgs &&... Args) { |
| 109 | std::string ResponseText; |
| 110 | if (llvm::Error E = SendMessage(message: Message, response_string&: ResponseText)) |
| 111 | return std::move(E); |
| 112 | return P::create(ResponseText, std::forward<CreateArgs>(Args)...); |
| 113 | } |
| 114 | |
| 115 | } // namespace llgs_tests |
| 116 | |
| 117 | #endif // LLDB_UNITTESTS_TOOLS_LLDB_SERVER_TESTS_TESTCLIENT_H |
| 118 | |