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
107 status = Host::LaunchProcess(Info);
108 if (status.Fail())
109 return status.ToError();
110
111 Socket *accept_socket;
112 listen_socket.Accept(accept_socket);
113 auto Conn = std::make_unique<ConnectionFileDescriptor>(accept_socket);
114 auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn)));
115
116 if (Error E = Client->initializeConnection())
117 return std::move(E);
118
119 if (!InferiorArgs.empty()) {
120 if (Error E = Client->queryProcess())
121 return std::move(E);
122 }
123
124 return std::move(Client);
125 }
126
SetInferior(llvm::ArrayRef<std::string> inferior_args)127 Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
128 if (SendEnvironment(Host::GetEnvironment()) != 0) {
129 return make_error<StringError>("Failed to set launch environment",
130 inconvertibleErrorCode());
131 }
132 std::stringstream command;
133 command << "A";
134 for (size_t i = 0; i < inferior_args.size(); i++) {
135 if (i > 0)
136 command << ',';
137 std::string hex_encoded = toHex(inferior_args[i]);
138 command << hex_encoded.size() << ',' << i << ',' << hex_encoded;
139 }
140
141 if (Error E = SendMessage(command.str()))
142 return E;
143 if (Error E = SendMessage("qLaunchSuccess"))
144 return E;
145 if (Error E = queryProcess())
146 return E;
147 return Error::success();
148 }
149
ListThreadsInStopReply()150 Error TestClient::ListThreadsInStopReply() {
151 return SendMessage("QListThreadsInStopReply");
152 }
153
SetBreakpoint(unsigned long address)154 Error TestClient::SetBreakpoint(unsigned long address) {
155 return SendMessage(formatv("Z0,{0:x-},1", address).str());
156 }
157
ContinueAll()158 Error TestClient::ContinueAll() { return Continue("vCont;c"); }
159
ContinueThread(unsigned long thread_id)160 Error TestClient::ContinueThread(unsigned long thread_id) {
161 return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
162 }
163
GetProcessInfo()164 const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() {
165 return *m_process_info;
166 }
167
GetJThreadsInfo()168 Expected<JThreadsInfo> TestClient::GetJThreadsInfo() {
169 return SendMessage<JThreadsInfo>("jThreadsInfo", m_register_infos);
170 }
171
GetLatestStopReply()172 const StopReply &TestClient::GetLatestStopReply() {
173 assert(m_stop_reply);
174 return *m_stop_reply;
175 }
176
SendMessage(StringRef message)177 Error TestClient::SendMessage(StringRef message) {
178 std::string dummy_string;
179 return SendMessage(message, dummy_string);
180 }
181
SendMessage(StringRef message,std::string & response_string)182 Error TestClient::SendMessage(StringRef message, std::string &response_string) {
183 if (Error E = SendMessage(message, response_string, PacketResult::Success))
184 return E;
185 StringExtractorGDBRemote Extractor(response_string);
186 if (Extractor.IsErrorResponse())
187 return Extractor.GetStatus().ToError();
188 return Error::success();
189 }
190
SendMessage(StringRef message,std::string & response_string,PacketResult expected_result)191 Error TestClient::SendMessage(StringRef message, std::string &response_string,
192 PacketResult expected_result) {
193 StringExtractorGDBRemote response;
194 GTEST_LOG_(INFO) << "Send Packet: " << message.str();
195 PacketResult result = SendPacketAndWaitForResponse(message, response);
196 response.GetEscapedBinaryData(response_string);
197 GTEST_LOG_(INFO) << "Read Packet: " << response_string;
198 if (result != expected_result)
199 return make_error<StringError>(
200 formatv("Error sending message `{0}`: {1}", message, result).str(),
201 inconvertibleErrorCode());
202
203 return Error::success();
204 }
205
GetPcRegisterId()206 unsigned int TestClient::GetPcRegisterId() {
207 assert(m_pc_register != LLDB_INVALID_REGNUM);
208 return m_pc_register;
209 }
210
qProcessInfo()211 Error TestClient::qProcessInfo() {
212 m_process_info = None;
213 auto InfoOr = SendMessage<ProcessInfo>("qProcessInfo");
214 if (!InfoOr)
215 return InfoOr.takeError();
216 m_process_info = std::move(*InfoOr);
217 return Error::success();
218 }
219
qRegisterInfos()220 Error TestClient::qRegisterInfos() {
221 uint32_t reg_offset = 0;
222 for (unsigned int Reg = 0;; ++Reg) {
223 std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str();
224 Expected<RegisterInfo> InfoOr = SendMessage<RegisterInfoParser>(Message);
225 if (!InfoOr) {
226 consumeError(InfoOr.takeError());
227 break;
228 }
229 m_register_infos.emplace_back(std::move(*InfoOr));
230
231 if (m_register_infos[Reg].byte_offset == LLDB_INVALID_INDEX32)
232 m_register_infos[Reg].byte_offset = reg_offset;
233
234 reg_offset =
235 m_register_infos[Reg].byte_offset + m_register_infos[Reg].byte_size;
236 if (m_register_infos[Reg].kinds[eRegisterKindGeneric] ==
237 LLDB_REGNUM_GENERIC_PC)
238 m_pc_register = Reg;
239 }
240 if (m_pc_register == LLDB_INVALID_REGNUM)
241 return make_parsing_error("qRegisterInfo: generic");
242 return Error::success();
243 }
244
queryProcess()245 Error TestClient::queryProcess() {
246 if (Error E = qProcessInfo())
247 return E;
248 if (Error E = qRegisterInfos())
249 return E;
250 return Error::success();
251 }
252
Continue(StringRef message)253 Error TestClient::Continue(StringRef message) {
254 assert(m_process_info);
255
256 auto StopReplyOr = SendMessage<StopReply>(
257 message, m_process_info->GetEndian(), m_register_infos);
258 if (!StopReplyOr)
259 return StopReplyOr.takeError();
260
261 m_stop_reply = std::move(*StopReplyOr);
262 if (!isa<StopReplyStop>(m_stop_reply)) {
263 StringExtractorGDBRemote R;
264 PacketResult result = ReadPacket(R, GetPacketTimeout(), false);
265 if (result != PacketResult::ErrorDisconnected) {
266 return make_error<StringError>(
267 formatv("Expected connection close after sending {0}. Got {1}/{2} "
268 "instead.",
269 message, result, R.GetStringRef())
270 .str(),
271 inconvertibleErrorCode());
272 }
273 }
274 return Error::success();
275 }
276