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