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 "gtest/gtest.h"
19 #include <cstdlib>
20 #include <future>
21 #include <sstream>
22 #include <string>
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 using namespace llvm;
27 
28 namespace llgs_tests {
29 void TestClient::Initialize() { HostInfo::Initialize(); }
30 
31 bool TestClient::IsDebugServer() {
32   return sys::path::filename(LLDB_SERVER).contains("debugserver");
33 }
34 
35 bool TestClient::IsLldbServer() { return !IsDebugServer(); }
36 
37 TestClient::TestClient(const std::string &test_name,
38                        const std::string &test_case_name)
39     : m_test_name(test_name), m_test_case_name(test_case_name),
40       m_pc_register(UINT_MAX) {}
41 
42 TestClient::~TestClient() {}
43 
44 llvm::Error TestClient::StartDebugger() {
45   const ArchSpec &arch_spec = HostInfo::GetArchitecture();
46   Args args;
47   args.AppendArgument(LLDB_SERVER);
48   if (IsLldbServer()) {
49     args.AppendArgument("gdbserver");
50     args.AppendArgument("--log-channels=gdb-remote packets");
51   } else {
52     args.AppendArgument("--log-flags=0x800000");
53   }
54   args.AppendArgument("--reverse-connect");
55   std::string log_file_name = GenerateLogFileName(arch_spec);
56   if (log_file_name.size())
57     args.AppendArgument("--log-file=" + log_file_name);
58 
59   Status status;
60   TCPSocket listen_socket(true, false);
61   status = listen_socket.Listen("127.0.0.1:0", 5);
62   if (status.Fail())
63     return status.ToError();
64 
65   char connect_remote_address[64];
66   snprintf(connect_remote_address, sizeof(connect_remote_address),
67            "localhost:%u", listen_socket.GetLocalPortNumber());
68 
69   args.AppendArgument(connect_remote_address);
70 
71   m_server_process_info.SetArchitecture(arch_spec);
72   m_server_process_info.SetArguments(args, true);
73   status = Host::LaunchProcess(m_server_process_info);
74   if (status.Fail())
75     return status.ToError();
76 
77   char connect_remote_uri[64];
78   snprintf(connect_remote_uri, sizeof(connect_remote_uri), "connect://%s",
79            connect_remote_address);
80   Socket *accept_socket;
81   listen_socket.Accept(accept_socket);
82   SetConnection(new ConnectionFileDescriptor(accept_socket));
83 
84   SendAck(); // Send this as a handshake.
85   return llvm::Error::success();
86 }
87 
88 llvm::Error TestClient::StopDebugger() {
89   std::string response;
90   // Debugserver (non-conformingly?) sends a reply to the k packet instead of
91   // simply closing the connection.
92   PacketResult result =
93       IsDebugServer() ? PacketResult::Success : PacketResult::ErrorDisconnected;
94   return SendMessage("k", response, result);
95 }
96 
97 Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
98   StringList env;
99   Host::GetEnvironment(env);
100   for (size_t i = 0; i < env.GetSize(); ++i) {
101     if (SendEnvironmentPacket(env[i].c_str()) != 0) {
102       return make_error<StringError>(
103           formatv("Failed to set environment variable: {0}", env[i]).str(),
104           inconvertibleErrorCode());
105     }
106   }
107   std::stringstream command;
108   command << "A";
109   for (size_t i = 0; i < inferior_args.size(); i++) {
110     if (i > 0)
111       command << ',';
112     std::string hex_encoded = toHex(inferior_args[i]);
113     command << hex_encoded.size() << ',' << i << ',' << hex_encoded;
114   }
115 
116   if (Error E = SendMessage(command.str()))
117     return E;
118   if (Error E = SendMessage("qLaunchSuccess"))
119     return E;
120   std::string response;
121   if (Error E = SendMessage("qProcessInfo", response))
122     return E;
123   auto create_or_error = ProcessInfo::Create(response);
124   if (auto create_error = create_or_error.takeError())
125     return create_error;
126 
127   m_process_info = *create_or_error;
128   return Error::success();
129 }
130 
131 Error TestClient::ListThreadsInStopReply() {
132   return SendMessage("QListThreadsInStopReply");
133 }
134 
135 Error TestClient::SetBreakpoint(unsigned long address) {
136   return SendMessage(formatv("Z0,{0:x-},1", address).str());
137 }
138 
139 Error TestClient::ContinueAll() { return Continue("vCont;c"); }
140 
141 Error TestClient::ContinueThread(unsigned long thread_id) {
142   return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
143 }
144 
145 const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; }
146 
147 Optional<JThreadsInfo> TestClient::GetJThreadsInfo() {
148   std::string response;
149   if (SendMessage("jThreadsInfo", response))
150     return llvm::None;
151   auto creation = JThreadsInfo::Create(response, m_process_info->GetEndian());
152   if (auto create_error = creation.takeError()) {
153     GTEST_LOG_(ERROR) << toString(std::move(create_error));
154     return llvm::None;
155   }
156 
157   return std::move(*creation);
158 }
159 
160 const StopReply &TestClient::GetLatestStopReply() {
161   return m_stop_reply.getValue();
162 }
163 
164 Error TestClient::SendMessage(StringRef message) {
165   std::string dummy_string;
166   return SendMessage(message, dummy_string);
167 }
168 
169 Error TestClient::SendMessage(StringRef message, std::string &response_string) {
170   if (Error E = SendMessage(message, response_string, PacketResult::Success))
171     return E;
172   if (response_string[0] == 'E') {
173     return make_error<StringError>(
174         formatv("Error `{0}` while sending message: {1}", response_string,
175                 message)
176             .str(),
177         inconvertibleErrorCode());
178   }
179   return Error::success();
180 }
181 
182 Error TestClient::SendMessage(StringRef message, std::string &response_string,
183                               PacketResult expected_result) {
184   StringExtractorGDBRemote response;
185   GTEST_LOG_(INFO) << "Send Packet: " << message.str();
186   PacketResult result = SendPacketAndWaitForResponse(message, response, false);
187   response.GetEscapedBinaryData(response_string);
188   GTEST_LOG_(INFO) << "Read Packet: " << response_string;
189   if (result != expected_result)
190     return make_error<StringError>(
191         formatv("Error sending message `{0}`: {1}", message, result).str(),
192         inconvertibleErrorCode());
193 
194   return Error::success();
195 }
196 
197 unsigned int TestClient::GetPcRegisterId() {
198   if (m_pc_register != UINT_MAX)
199     return m_pc_register;
200 
201   for (unsigned int register_id = 0;; register_id++) {
202     std::string message = formatv("qRegisterInfo{0:x-}", register_id).str();
203     std::string response;
204     if (SendMessage(message, response)) {
205       GTEST_LOG_(ERROR) << "Unable to query register ID for PC register.";
206       return UINT_MAX;
207     }
208 
209     auto elements_or_error = SplitUniquePairList("GetPcRegisterId", response);
210     if (auto split_error = elements_or_error.takeError()) {
211       GTEST_LOG_(ERROR) << "GetPcRegisterId: Error splitting response: "
212                         << response;
213       return UINT_MAX;
214     }
215 
216     auto elements = *elements_or_error;
217     if (elements["alt-name"] == "pc" || elements["generic"] == "pc") {
218       m_pc_register = register_id;
219       break;
220     }
221   }
222 
223   return m_pc_register;
224 }
225 
226 Error TestClient::Continue(StringRef message) {
227   assert(m_process_info.hasValue());
228 
229   std::string response;
230   if (Error E = SendMessage(message, response))
231     return E;
232   auto creation = StopReply::Create(response, m_process_info->GetEndian());
233   if (Error E = creation.takeError())
234     return E;
235 
236   m_stop_reply = std::move(*creation);
237   return Error::success();
238 }
239 
240 std::string TestClient::GenerateLogFileName(const ArchSpec &arch) const {
241   char *log_directory = getenv("LOG_FILE_DIRECTORY");
242   if (!log_directory)
243     return "";
244 
245   if (!llvm::sys::fs::is_directory(log_directory)) {
246     GTEST_LOG_(WARNING) << "Cannot access log directory: " << log_directory;
247     return "";
248   }
249 
250   std::string log_file_name;
251   raw_string_ostream log_file(log_file_name);
252   log_file << log_directory << "/lldb-" << m_test_case_name << '-'
253            << m_test_name << '-' << arch.GetArchitectureName() << ".log";
254   return log_file.str();
255 }
256 
257 } // namespace llgs_tests
258