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