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