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