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