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