1 //===-- TestClient.cpp ------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "TestClient.h"
11 #include "lldb/Host/HostInfo.h"
12 #include "lldb/Host/common/TCPSocket.h"
13 #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
14 #include "lldb/Target/ProcessLaunchInfo.h"
15 #include "lldb/Utility/Args.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/Support/Path.h"
18 #include "llvm/Testing/Support/Error.h"
19 #include "gtest/gtest.h"
26 using namespace lldb_private;
28 using namespace llgs_tests;
30 TestClient::TestClient(std::unique_ptr<Connection> Conn) {
31 SetConnection(Conn.release());
32 SetPacketTimeout(std::chrono::seconds(10));
35 TestClient::~TestClient() {
39 EXPECT_THAT_ERROR(SendMessage("k"), Succeeded());
42 Error TestClient::initializeConnection() {
44 return make_error<StringError>("Sending initial ACK failed.",
45 inconvertibleErrorCode());
47 if (Error E = SendMessage("QStartNoAckMode"))
51 return Error::success();
54 Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log) {
55 return launch(Log, {});
58 Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log, ArrayRef<StringRef> InferiorArgs) {
59 return launchCustom(Log, {}, InferiorArgs);
62 Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, ArrayRef<StringRef> ServerArgs, ArrayRef<StringRef> InferiorArgs) {
63 const ArchSpec &arch_spec = HostInfo::GetArchitecture();
65 args.AppendArgument(LLDB_SERVER);
67 args.AppendArgument("gdbserver");
68 args.AppendArgument("--reverse-connect");
71 args.AppendArgument(("--log-file=" + Log).str());
73 args.AppendArgument("--log-channels=gdb-remote packets");
75 args.AppendArgument("--log-flags=0x800000");
79 TCPSocket listen_socket(true, false);
80 status = listen_socket.Listen("127.0.0.1:0", 5);
82 return status.ToError();
85 ("localhost:" + Twine(listen_socket.GetLocalPortNumber())).str());
87 for (StringRef arg : ServerArgs)
88 args.AppendArgument(arg);
90 if (!InferiorArgs.empty()) {
91 args.AppendArgument("--");
92 for (StringRef arg : InferiorArgs)
93 args.AppendArgument(arg);
96 ProcessLaunchInfo Info;
97 Info.SetArchitecture(arch_spec);
98 Info.SetArguments(args, true);
99 Info.GetEnvironment() = Host::GetEnvironment();
100 // TODO: Use this callback to detect botched launches. If lldb-server does not
101 // start, we can print a nice error message here instead of hanging in
103 Info.SetMonitorProcessCallback(&ProcessLaunchInfo::NoOpMonitorCallback,
106 status = Host::LaunchProcess(Info);
108 return status.ToError();
110 Socket *accept_socket;
111 listen_socket.Accept(accept_socket);
112 auto Conn = llvm::make_unique<ConnectionFileDescriptor>(accept_socket);
113 auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn)));
115 if (Error E = Client->initializeConnection())
118 if (!InferiorArgs.empty()) {
119 if (Error E = Client->queryProcess())
123 return std::move(Client);
126 Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
127 if (SendEnvironment(Host::GetEnvironment()) != 0) {
128 return make_error<StringError>("Failed to set launch environment",
129 inconvertibleErrorCode());
131 std::stringstream command;
133 for (size_t i = 0; i < inferior_args.size(); i++) {
136 std::string hex_encoded = toHex(inferior_args[i]);
137 command << hex_encoded.size() << ',' << i << ',' << hex_encoded;
140 if (Error E = SendMessage(command.str()))
142 if (Error E = SendMessage("qLaunchSuccess"))
144 if (Error E = queryProcess())
146 return Error::success();
149 Error TestClient::ListThreadsInStopReply() {
150 return SendMessage("QListThreadsInStopReply");
153 Error TestClient::SetBreakpoint(unsigned long address) {
154 return SendMessage(formatv("Z0,{0:x-},1", address).str());
157 Error TestClient::ContinueAll() { return Continue("vCont;c"); }
159 Error TestClient::ContinueThread(unsigned long thread_id) {
160 return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
163 const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() {
164 return *m_process_info;
167 Expected<JThreadsInfo> TestClient::GetJThreadsInfo() {
168 return SendMessage<JThreadsInfo>("jThreadsInfo", m_register_infos);
171 const StopReply &TestClient::GetLatestStopReply() {
172 assert(m_stop_reply);
173 return *m_stop_reply;
176 Error TestClient::SendMessage(StringRef message) {
177 std::string dummy_string;
178 return SendMessage(message, dummy_string);
181 Error TestClient::SendMessage(StringRef message, std::string &response_string) {
182 if (Error E = SendMessage(message, response_string, PacketResult::Success))
184 StringExtractorGDBRemote Extractor(response_string);
185 if (Extractor.IsErrorResponse())
186 return Extractor.GetStatus().ToError();
187 return Error::success();
190 Error TestClient::SendMessage(StringRef message, std::string &response_string,
191 PacketResult expected_result) {
192 StringExtractorGDBRemote response;
193 GTEST_LOG_(INFO) << "Send Packet: " << message.str();
194 PacketResult result = SendPacketAndWaitForResponse(message, response, false);
195 response.GetEscapedBinaryData(response_string);
196 GTEST_LOG_(INFO) << "Read Packet: " << response_string;
197 if (result != expected_result)
198 return make_error<StringError>(
199 formatv("Error sending message `{0}`: {1}", message, result).str(),
200 inconvertibleErrorCode());
202 return Error::success();
205 unsigned int TestClient::GetPcRegisterId() {
206 assert(m_pc_register != LLDB_INVALID_REGNUM);
207 return m_pc_register;
210 Error TestClient::qProcessInfo() {
211 m_process_info = None;
212 auto InfoOr = SendMessage<ProcessInfo>("qProcessInfo");
214 return InfoOr.takeError();
215 m_process_info = std::move(*InfoOr);
216 return Error::success();
219 Error TestClient::qRegisterInfos() {
220 for (unsigned int Reg = 0;; ++Reg) {
221 std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str();
222 Expected<RegisterInfo> InfoOr = SendMessage<RegisterInfoParser>(Message);
224 consumeError(InfoOr.takeError());
227 m_register_infos.emplace_back(std::move(*InfoOr));
228 if (m_register_infos[Reg].kinds[eRegisterKindGeneric] ==
229 LLDB_REGNUM_GENERIC_PC)
232 if (m_pc_register == LLDB_INVALID_REGNUM)
233 return make_parsing_error("qRegisterInfo: generic");
234 return Error::success();
237 Error TestClient::queryProcess() {
238 if (Error E = qProcessInfo())
240 if (Error E = qRegisterInfos())
242 return Error::success();
245 Error TestClient::Continue(StringRef message) {
246 assert(m_process_info.hasValue());
248 auto StopReplyOr = SendMessage<StopReply>(
249 message, m_process_info->GetEndian(), m_register_infos);
251 return StopReplyOr.takeError();
253 m_stop_reply = std::move(*StopReplyOr);
254 if (!isa<StopReplyStop>(m_stop_reply)) {
255 StringExtractorGDBRemote R;
256 PacketResult result = ReadPacket(R, GetPacketTimeout(), false);
257 if (result != PacketResult::ErrorDisconnected) {
258 return make_error<StringError>(
259 formatv("Expected connection close after sending {0}. Got {1}/{2} "
261 message, result, R.GetStringRef())
263 inconvertibleErrorCode());
266 return Error::success();