1 //===-- TestClient.cpp ------------------------------------------*- 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 #include "TestClient.h"
10 #include "lldb/Host/HostInfo.h"
11 #include "lldb/Host/common/TCPSocket.h"
12 #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
13 #include "lldb/Utility/Args.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/Support/Path.h"
16 #include "llvm/Testing/Support/Error.h"
17 #include "gtest/gtest.h"
18 #include <cstdlib>
19 #include <future>
20 #include <sstream>
21 #include <string>
22 
23 using namespace lldb;
24 using namespace lldb_private;
25 using namespace llvm;
26 using namespace llgs_tests;
27 
28 TestClient::TestClient(std::unique_ptr<Connection> Conn) {
29   SetConnection(Conn.release());
30   SetPacketTimeout(std::chrono::seconds(10));
31 }
32 
33 TestClient::~TestClient() {
34   if (!IsConnected())
35     return;
36 
37   EXPECT_THAT_ERROR(SendMessage("k"), Succeeded());
38 }
39 
40 Error TestClient::initializeConnection() {
41   if (SendAck() == 0)
42     return make_error<StringError>("Sending initial ACK failed.",
43                                    inconvertibleErrorCode());
44 
45   if (Error E = SendMessage("QStartNoAckMode"))
46     return E;
47 
48   m_send_acks = false;
49   return Error::success();
50 }
51 
52 Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log) {
53   return launch(Log, {});
54 }
55 
56 Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log, ArrayRef<StringRef> InferiorArgs) {
57   return launchCustom(Log, {}, InferiorArgs);
58 }
59 
60 Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, ArrayRef<StringRef> ServerArgs, ArrayRef<StringRef> InferiorArgs) {
61   const ArchSpec &arch_spec = HostInfo::GetArchitecture();
62   Args args;
63   args.AppendArgument(LLDB_SERVER);
64   if (IsLldbServer())
65     args.AppendArgument("gdbserver");
66   args.AppendArgument("--reverse-connect");
67 
68   if (!Log.empty()) {
69     args.AppendArgument(("--log-file=" + Log).str());
70     if (IsLldbServer())
71       args.AppendArgument("--log-channels=gdb-remote packets");
72     else
73       args.AppendArgument("--log-flags=0x800000");
74   }
75 
76   Status status;
77   TCPSocket listen_socket(true, false);
78   status = listen_socket.Listen("127.0.0.1:0", 5);
79   if (status.Fail())
80     return status.ToError();
81 
82   args.AppendArgument(
83       ("127.0.0.1:" + Twine(listen_socket.GetLocalPortNumber())).str());
84 
85   for (StringRef arg : ServerArgs)
86     args.AppendArgument(arg);
87 
88   if (!InferiorArgs.empty()) {
89     args.AppendArgument("--");
90     for (StringRef arg : InferiorArgs)
91       args.AppendArgument(arg);
92   }
93 
94   ProcessLaunchInfo Info;
95   Info.SetArchitecture(arch_spec);
96   Info.SetArguments(args, true);
97   Info.GetEnvironment() = Host::GetEnvironment();
98   // TODO: Use this callback to detect botched launches. If lldb-server does not
99   // start, we can print a nice error message here instead of hanging in
100   // Accept().
101   Info.SetMonitorProcessCallback(&ProcessLaunchInfo::NoOpMonitorCallback,
102                                  false);
103 
104   status = Host::LaunchProcess(Info);
105   if (status.Fail())
106     return status.ToError();
107 
108   Socket *accept_socket;
109   listen_socket.Accept(accept_socket);
110   auto Conn = llvm::make_unique<ConnectionFileDescriptor>(accept_socket);
111   auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn)));
112 
113   if (Error E = Client->initializeConnection())
114     return std::move(E);
115 
116   if (!InferiorArgs.empty()) {
117     if (Error E = Client->queryProcess())
118       return std::move(E);
119   }
120 
121   return std::move(Client);
122 }
123 
124 Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
125   if (SendEnvironment(Host::GetEnvironment()) != 0) {
126     return make_error<StringError>("Failed to set launch environment",
127                                    inconvertibleErrorCode());
128   }
129   std::stringstream command;
130   command << "A";
131   for (size_t i = 0; i < inferior_args.size(); i++) {
132     if (i > 0)
133       command << ',';
134     std::string hex_encoded = toHex(inferior_args[i]);
135     command << hex_encoded.size() << ',' << i << ',' << hex_encoded;
136   }
137 
138   if (Error E = SendMessage(command.str()))
139     return E;
140   if (Error E = SendMessage("qLaunchSuccess"))
141     return E;
142   if (Error E = queryProcess())
143     return E;
144   return Error::success();
145 }
146 
147 Error TestClient::ListThreadsInStopReply() {
148   return SendMessage("QListThreadsInStopReply");
149 }
150 
151 Error TestClient::SetBreakpoint(unsigned long address) {
152   return SendMessage(formatv("Z0,{0:x-},1", address).str());
153 }
154 
155 Error TestClient::ContinueAll() { return Continue("vCont;c"); }
156 
157 Error TestClient::ContinueThread(unsigned long thread_id) {
158   return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
159 }
160 
161 const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() {
162   return *m_process_info;
163 }
164 
165 Expected<JThreadsInfo> TestClient::GetJThreadsInfo() {
166   return SendMessage<JThreadsInfo>("jThreadsInfo", m_register_infos);
167 }
168 
169 const StopReply &TestClient::GetLatestStopReply() {
170   assert(m_stop_reply);
171   return *m_stop_reply;
172 }
173 
174 Error TestClient::SendMessage(StringRef message) {
175   std::string dummy_string;
176   return SendMessage(message, dummy_string);
177 }
178 
179 Error TestClient::SendMessage(StringRef message, std::string &response_string) {
180   if (Error E = SendMessage(message, response_string, PacketResult::Success))
181     return E;
182   StringExtractorGDBRemote Extractor(response_string);
183   if (Extractor.IsErrorResponse())
184     return Extractor.GetStatus().ToError();
185   return Error::success();
186 }
187 
188 Error TestClient::SendMessage(StringRef message, std::string &response_string,
189                               PacketResult expected_result) {
190   StringExtractorGDBRemote response;
191   GTEST_LOG_(INFO) << "Send Packet: " << message.str();
192   PacketResult result = SendPacketAndWaitForResponse(message, response, false);
193   response.GetEscapedBinaryData(response_string);
194   GTEST_LOG_(INFO) << "Read Packet: " << response_string;
195   if (result != expected_result)
196     return make_error<StringError>(
197         formatv("Error sending message `{0}`: {1}", message, result).str(),
198         inconvertibleErrorCode());
199 
200   return Error::success();
201 }
202 
203 unsigned int TestClient::GetPcRegisterId() {
204   assert(m_pc_register != LLDB_INVALID_REGNUM);
205   return m_pc_register;
206 }
207 
208 Error TestClient::qProcessInfo() {
209   m_process_info = None;
210   auto InfoOr = SendMessage<ProcessInfo>("qProcessInfo");
211   if (!InfoOr)
212     return InfoOr.takeError();
213   m_process_info = std::move(*InfoOr);
214   return Error::success();
215 }
216 
217 Error TestClient::qRegisterInfos() {
218   for (unsigned int Reg = 0;; ++Reg) {
219     std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str();
220     Expected<RegisterInfo> InfoOr = SendMessage<RegisterInfoParser>(Message);
221     if (!InfoOr) {
222       consumeError(InfoOr.takeError());
223       break;
224     }
225     m_register_infos.emplace_back(std::move(*InfoOr));
226     if (m_register_infos[Reg].kinds[eRegisterKindGeneric] ==
227         LLDB_REGNUM_GENERIC_PC)
228       m_pc_register = Reg;
229   }
230   if (m_pc_register == LLDB_INVALID_REGNUM)
231     return make_parsing_error("qRegisterInfo: generic");
232   return Error::success();
233 }
234 
235 Error TestClient::queryProcess() {
236   if (Error E = qProcessInfo())
237     return E;
238   if (Error E = qRegisterInfos())
239     return E;
240   return Error::success();
241 }
242 
243 Error TestClient::Continue(StringRef message) {
244   assert(m_process_info.hasValue());
245 
246   auto StopReplyOr = SendMessage<StopReply>(
247       message, m_process_info->GetEndian(), m_register_infos);
248   if (!StopReplyOr)
249     return StopReplyOr.takeError();
250 
251   m_stop_reply = std::move(*StopReplyOr);
252   if (!isa<StopReplyStop>(m_stop_reply)) {
253     StringExtractorGDBRemote R;
254     PacketResult result = ReadPacket(R, GetPacketTimeout(), false);
255     if (result != PacketResult::ErrorDisconnected) {
256       return make_error<StringError>(
257           formatv("Expected connection close after sending {0}. Got {1}/{2} "
258                   "instead.",
259                   message, result, R.GetStringRef())
260               .str(),
261           inconvertibleErrorCode());
262     }
263   }
264   return Error::success();
265 }
266