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