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