1 //===-- TestClient.cpp ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
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/Interpreter/Args.h"
15 #include "lldb/Target/ProcessLaunchInfo.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"
20 #include <cstdlib>
21 #include <future>
22 #include <sstream>
23 #include <string>
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 using namespace llvm;
28 
29 namespace llgs_tests {
30 
31 TestClient::TestClient(std::unique_ptr<Connection> Conn) {
32   SetConnection(Conn.release());
33 
34   SendAck(); // Send this as a handshake.
35 }
36 
37 TestClient::~TestClient() {
38   if (!IsConnected())
39     return;
40 
41   std::string response;
42   // Debugserver (non-conformingly?) sends a reply to the k packet instead of
43   // simply closing the connection.
44   PacketResult result =
45       IsDebugServer() ? PacketResult::Success : PacketResult::ErrorDisconnected;
46   EXPECT_THAT_ERROR(SendMessage("k", response, result), Succeeded());
47 }
48 
49 Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log) {
50   return launch(Log, {});
51 }
52 
53 Expected<std::unique_ptr<TestClient>> TestClient::launch(StringRef Log, ArrayRef<StringRef> InferiorArgs) {
54   return launchCustom(Log, {}, InferiorArgs);
55 }
56 
57 Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, ArrayRef<StringRef> ServerArgs, ArrayRef<StringRef> InferiorArgs) {
58   const ArchSpec &arch_spec = HostInfo::GetArchitecture();
59   Args args;
60   args.AppendArgument(LLDB_SERVER);
61   if (IsLldbServer())
62     args.AppendArgument("gdbserver");
63   args.AppendArgument("--reverse-connect");
64 
65   if (!Log.empty()) {
66     args.AppendArgument(("--log-file=" + Log).str());
67     if (IsLldbServer())
68       args.AppendArgument("--log-channels=gdb-remote packets");
69     else
70       args.AppendArgument("--log-flags=0x800000");
71   }
72 
73   Status status;
74   TCPSocket listen_socket(true, false);
75   status = listen_socket.Listen("127.0.0.1:0", 5);
76   if (status.Fail())
77     return status.ToError();
78 
79   args.AppendArgument(
80       ("localhost:" + Twine(listen_socket.GetLocalPortNumber())).str());
81 
82   for (StringRef arg : ServerArgs)
83     args.AppendArgument(arg);
84 
85   if (!InferiorArgs.empty()) {
86     args.AppendArgument("--");
87     for (StringRef arg : InferiorArgs)
88       args.AppendArgument(arg);
89   }
90 
91   ProcessLaunchInfo Info;
92   Info.SetArchitecture(arch_spec);
93   Info.SetArguments(args, true);
94   Info.GetEnvironment() = Host::GetEnvironment();
95 
96   status = Host::LaunchProcess(Info);
97   if (status.Fail())
98     return status.ToError();
99 
100   Socket *accept_socket;
101   listen_socket.Accept(accept_socket);
102   auto Conn = llvm::make_unique<ConnectionFileDescriptor>(accept_socket);
103   auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn)));
104 
105   if (!InferiorArgs.empty()) {
106     if (Error E = Client->QueryProcessInfo())
107       return std::move(E);
108   }
109 
110   return std::move(Client);
111 }
112 
113 Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
114   if (SendEnvironment(Host::GetEnvironment()) != 0) {
115     return make_error<StringError>("Failed to set launch environment",
116                                    inconvertibleErrorCode());
117   }
118   std::stringstream command;
119   command << "A";
120   for (size_t i = 0; i < inferior_args.size(); i++) {
121     if (i > 0)
122       command << ',';
123     std::string hex_encoded = toHex(inferior_args[i]);
124     command << hex_encoded.size() << ',' << i << ',' << hex_encoded;
125   }
126 
127   if (Error E = SendMessage(command.str()))
128     return E;
129   if (Error E = SendMessage("qLaunchSuccess"))
130     return E;
131   if (Error E = QueryProcessInfo())
132     return E;
133   return Error::success();
134 }
135 
136 Error TestClient::ListThreadsInStopReply() {
137   return SendMessage("QListThreadsInStopReply");
138 }
139 
140 Error TestClient::SetBreakpoint(unsigned long address) {
141   return SendMessage(formatv("Z0,{0:x-},1", address).str());
142 }
143 
144 Error TestClient::ContinueAll() { return Continue("vCont;c"); }
145 
146 Error TestClient::ContinueThread(unsigned long thread_id) {
147   return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
148 }
149 
150 const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; }
151 
152 Optional<JThreadsInfo> TestClient::GetJThreadsInfo() {
153   std::string response;
154   if (SendMessage("jThreadsInfo", response))
155     return llvm::None;
156   auto creation = JThreadsInfo::Create(response, m_process_info->GetEndian());
157   if (auto create_error = creation.takeError()) {
158     GTEST_LOG_(ERROR) << toString(std::move(create_error));
159     return llvm::None;
160   }
161 
162   return std::move(*creation);
163 }
164 
165 const StopReply &TestClient::GetLatestStopReply() {
166   assert(m_stop_reply);
167   return *m_stop_reply;
168 }
169 
170 Error TestClient::SendMessage(StringRef message) {
171   std::string dummy_string;
172   return SendMessage(message, dummy_string);
173 }
174 
175 Error TestClient::SendMessage(StringRef message, std::string &response_string) {
176   if (Error E = SendMessage(message, response_string, PacketResult::Success))
177     return E;
178   if (response_string[0] == 'E') {
179     return make_error<StringError>(
180         formatv("Error `{0}` while sending message: {1}", response_string,
181                 message)
182             .str(),
183         inconvertibleErrorCode());
184   }
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   if (m_pc_register != UINT_MAX)
205     return m_pc_register;
206 
207   for (unsigned int register_id = 0;; register_id++) {
208     std::string message = formatv("qRegisterInfo{0:x-}", register_id).str();
209     std::string response;
210     if (SendMessage(message, response)) {
211       GTEST_LOG_(ERROR) << "Unable to query register ID for PC register.";
212       return UINT_MAX;
213     }
214 
215     auto elements_or_error = SplitUniquePairList("GetPcRegisterId", response);
216     if (auto split_error = elements_or_error.takeError()) {
217       GTEST_LOG_(ERROR) << "GetPcRegisterId: Error splitting response: "
218                         << response;
219       return UINT_MAX;
220     }
221 
222     auto elements = *elements_or_error;
223     if (elements["alt-name"] == "pc" || elements["generic"] == "pc") {
224       m_pc_register = register_id;
225       break;
226     }
227   }
228 
229   return m_pc_register;
230 }
231 
232 llvm::Error TestClient::QueryProcessInfo() {
233   std::string response;
234   if (Error E = SendMessage("qProcessInfo", response))
235     return E;
236   auto create_or_error = ProcessInfo::Create(response);
237   if (!create_or_error)
238     return create_or_error.takeError();
239   m_process_info = *create_or_error;
240   return Error::success();
241 }
242 
243 Error TestClient::Continue(StringRef message) {
244   assert(m_process_info.hasValue());
245 
246   std::string response;
247   if (Error E = SendMessage(message, response))
248     return E;
249   auto creation = StopReply::create(response, m_process_info->GetEndian());
250   if (Error E = creation.takeError())
251     return E;
252 
253   m_stop_reply = std::move(*creation);
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 receiving {0}. Got {1}/{2} "
260                   "instead.",
261                   response, result, R.GetStringRef())
262               .str(),
263           inconvertibleErrorCode());
264     }
265   }
266   return Error::success();
267 }
268 
269 } // namespace llgs_tests
270