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