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/Core/ArchSpec.h"
12 #include "lldb/Host/HostInfo.h"
13 #include "lldb/Host/common/TCPSocket.h"
14 #include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
15 #include "lldb/Interpreter/Args.h"
16 #include "lldb/Target/ProcessLaunchInfo.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Support/Path.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 
29 namespace llgs_tests {
30 void TestClient::Initialize() { HostInfo::Initialize(); }
31 
32 bool TestClient::IsDebugServer() {
33   return sys::path::filename(LLDB_SERVER).contains("debugserver");
34 }
35 
36 bool TestClient::IsLldbServer() { return !IsDebugServer(); }
37 
38 TestClient::TestClient(const std::string &test_name,
39                        const std::string &test_case_name)
40     : m_test_name(test_name), m_test_case_name(test_case_name),
41       m_pc_register(UINT_MAX) {}
42 
43 TestClient::~TestClient() {}
44 
45 bool TestClient::StartDebugger() {
46   const ArchSpec &arch_spec = HostInfo::GetArchitecture();
47   Args args;
48   args.AppendArgument(LLDB_SERVER);
49   if (IsLldbServer()) {
50     args.AppendArgument("gdbserver");
51     args.AppendArgument("--log-channels=gdb-remote packets");
52   } else {
53     args.AppendArgument("--log-flags=0x800000");
54   }
55   args.AppendArgument("--reverse-connect");
56   std::string log_file_name = GenerateLogFileName(arch_spec);
57   if (log_file_name.size())
58     args.AppendArgument("--log-file=" + log_file_name);
59 
60   Status error;
61   TCPSocket listen_socket(true, false);
62   error = listen_socket.Listen("127.0.0.1:0", 5);
63   if (error.Fail()) {
64     GTEST_LOG_(ERROR) << "Unable to open listen socket.";
65     return false;
66   }
67 
68   char connect_remote_address[64];
69   snprintf(connect_remote_address, sizeof(connect_remote_address),
70            "localhost:%u", listen_socket.GetLocalPortNumber());
71 
72   args.AppendArgument(connect_remote_address);
73 
74   m_server_process_info.SetArchitecture(arch_spec);
75   m_server_process_info.SetArguments(args, true);
76   Status status = Host::LaunchProcess(m_server_process_info);
77   if (status.Fail()) {
78     GTEST_LOG_(ERROR)
79         << formatv("Failure to launch lldb server: {0}.", status).str();
80     return false;
81   }
82 
83   char connect_remote_uri[64];
84   snprintf(connect_remote_uri, sizeof(connect_remote_uri), "connect://%s",
85            connect_remote_address);
86   Socket *accept_socket;
87   listen_socket.Accept(accept_socket);
88   SetConnection(new ConnectionFileDescriptor(accept_socket));
89 
90   SendAck(); // Send this as a handshake.
91   return true;
92 }
93 
94 bool TestClient::StopDebugger() {
95   std::string response;
96   // Debugserver (non-conformingly?) sends a reply to the k packet instead of
97   // simply closing the connection.
98   PacketResult result =
99       IsDebugServer() ? PacketResult::Success : PacketResult::ErrorDisconnected;
100   return SendMessage("k", response, result);
101 }
102 
103 bool TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
104   StringList env;
105   Host::GetEnvironment(env);
106   for (size_t i = 0; i < env.GetSize(); ++i) {
107     if (SendEnvironmentPacket(env[i].c_str()) != 0) {
108       GTEST_LOG_(ERROR) << "failed to set environment variable `" << env[i] << "`";
109       return false;
110     }
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 (!SendMessage(command.str()))
122     return false;
123   if (!SendMessage("qLaunchSuccess"))
124     return false;
125   std::string response;
126   if (!SendMessage("qProcessInfo", response))
127     return false;
128   auto create_or_error = ProcessInfo::Create(response);
129   if (auto create_error = create_or_error.takeError()) {
130     GTEST_LOG_(ERROR) << toString(std::move(create_error));
131     return false;
132   }
133 
134   m_process_info = *create_or_error;
135   return true;
136 }
137 
138 bool TestClient::ListThreadsInStopReply() {
139   return SendMessage("QListThreadsInStopReply");
140 }
141 
142 bool TestClient::SetBreakpoint(unsigned long address) {
143   std::stringstream command;
144   command << "Z0," << std::hex << address << ",1";
145   return SendMessage(command.str());
146 }
147 
148 bool TestClient::ContinueAll() { return Continue("vCont;c"); }
149 
150 bool TestClient::ContinueThread(unsigned long thread_id) {
151   return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
152 }
153 
154 const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; }
155 
156 Optional<JThreadsInfo> TestClient::GetJThreadsInfo() {
157   std::string response;
158   if (!SendMessage("jThreadsInfo", response))
159     return llvm::None;
160   auto creation = JThreadsInfo::Create(response, m_process_info->GetEndian());
161   if (auto create_error = creation.takeError()) {
162     GTEST_LOG_(ERROR) << toString(std::move(create_error));
163     return llvm::None;
164   }
165 
166   return std::move(*creation);
167 }
168 
169 const StopReply &TestClient::GetLatestStopReply() {
170   return m_stop_reply.getValue();
171 }
172 
173 bool TestClient::SendMessage(StringRef message) {
174   std::string dummy_string;
175   return SendMessage(message, dummy_string);
176 }
177 
178 bool TestClient::SendMessage(StringRef message, std::string &response_string) {
179   if (!SendMessage(message, response_string, PacketResult::Success))
180     return false;
181   else if (response_string[0] == 'E') {
182     GTEST_LOG_(ERROR) << "Error " << response_string
183                       << " while sending message: " << message.str();
184     return false;
185   }
186 
187   return true;
188 }
189 
190 bool 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     GTEST_LOG_(ERROR) << FormatFailedResult(message, result);
199     return false;
200   }
201 
202   return true;
203 }
204 
205 unsigned int TestClient::GetPcRegisterId() {
206   if (m_pc_register != UINT_MAX)
207     return m_pc_register;
208 
209   for (unsigned int register_id = 0;; register_id++) {
210     std::string message = formatv("qRegisterInfo{0:x-}", register_id).str();
211     std::string response;
212     if (!SendMessage(message, response)) {
213       GTEST_LOG_(ERROR) << "Unable to query register ID for PC register.";
214       return UINT_MAX;
215     }
216 
217     auto elements_or_error = SplitUniquePairList("GetPcRegisterId", response);
218     if (auto split_error = elements_or_error.takeError()) {
219       GTEST_LOG_(ERROR) << "GetPcRegisterId: Error splitting response: "
220                         << response;
221       return UINT_MAX;
222     }
223 
224     auto elements = *elements_or_error;
225     if (elements["alt-name"] == "pc" || elements["generic"] == "pc") {
226       m_pc_register = register_id;
227       break;
228     }
229   }
230 
231   return m_pc_register;
232 }
233 
234 bool TestClient::Continue(StringRef message) {
235   if (!m_process_info.hasValue()) {
236     GTEST_LOG_(ERROR) << "Continue() called before m_process_info initialized.";
237     return false;
238   }
239 
240   std::string response;
241   if (!SendMessage(message, response))
242     return false;
243   auto creation = StopReply::Create(response, m_process_info->GetEndian());
244   if (auto create_error = creation.takeError()) {
245     GTEST_LOG_(ERROR) << toString(std::move(create_error));
246     return false;
247   }
248 
249   m_stop_reply = std::move(*creation);
250   return true;
251 }
252 
253 std::string TestClient::GenerateLogFileName(const ArchSpec &arch) const {
254   char *log_directory = getenv("LOG_FILE_DIRECTORY");
255   if (!log_directory)
256     return "";
257 
258   if (!llvm::sys::fs::is_directory(log_directory)) {
259     GTEST_LOG_(WARNING) << "Cannot access log directory: " << log_directory;
260     return "";
261   }
262 
263   std::string log_file_name;
264   raw_string_ostream log_file(log_file_name);
265   log_file << log_directory << "/lldb-" << m_test_case_name << '-'
266            << m_test_name << '-' << arch.GetArchitectureName() << ".log";
267   return log_file.str();
268 }
269 
270 std::string TestClient::FormatFailedResult(const std::string &message,
271                                            PacketResult result) {
272   std::string formatted_error;
273   raw_string_ostream error_stream(formatted_error);
274   error_stream << "Failure sending message: " << message << " Result: ";
275 
276   switch (result) {
277   case PacketResult::ErrorSendFailed:
278     error_stream << "ErrorSendFailed";
279     break;
280   case PacketResult::ErrorSendAck:
281     error_stream << "ErrorSendAck";
282     break;
283   case PacketResult::ErrorReplyFailed:
284     error_stream << "ErrorReplyFailed";
285     break;
286   case PacketResult::ErrorReplyTimeout:
287     error_stream << "ErrorReplyTimeout";
288     break;
289   case PacketResult::ErrorReplyInvalid:
290     error_stream << "ErrorReplyInvalid";
291     break;
292   case PacketResult::ErrorReplyAck:
293     error_stream << "ErrorReplyAck";
294     break;
295   case PacketResult::ErrorDisconnected:
296     error_stream << "ErrorDisconnected";
297     break;
298   case PacketResult::ErrorNoSequenceLock:
299     error_stream << "ErrorNoSequenceLock";
300     break;
301   default:
302     error_stream << "Unknown Error";
303   }
304 
305   error_stream.str();
306   return formatted_error;
307 }
308 } // namespace llgs_tests
309