1 //===-- GDBRemoteCommunicationReplayServer.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 <cerrno> 10 11 #include "lldb/Host/Config.h" 12 #include "llvm/ADT/ScopeExit.h" 13 14 #include "GDBRemoteCommunicationReplayServer.h" 15 #include "ProcessGDBRemoteLog.h" 16 17 // C Includes 18 // C++ Includes 19 #include <cstring> 20 21 // Project includes 22 #include "lldb/Host/ThreadLauncher.h" 23 #include "lldb/Utility/ConstString.h" 24 #include "lldb/Utility/Event.h" 25 #include "lldb/Utility/FileSpec.h" 26 #include "lldb/Utility/StreamString.h" 27 #include "lldb/Utility/StringExtractorGDBRemote.h" 28 29 using namespace llvm; 30 using namespace lldb; 31 using namespace lldb_private; 32 using namespace lldb_private::process_gdb_remote; 33 34 /// Check if the given expected packet matches the actual packet. 35 static bool unexpected(llvm::StringRef expected, llvm::StringRef actual) { 36 // The 'expected' string contains the raw data, including the leading $ and 37 // trailing checksum. The 'actual' string contains only the packet's content. 38 if (expected.contains(actual)) 39 return false; 40 // Contains a PID which might be different. 41 if (expected.contains("vAttach")) 42 return false; 43 // Contains a ascii-hex-path. 44 if (expected.contains("QSetSTD")) 45 return false; 46 // Contains environment values. 47 if (expected.contains("QEnvironment")) 48 return false; 49 50 return true; 51 } 52 53 /// Check if we should reply to the given packet. 54 static bool skip(llvm::StringRef data) { 55 assert(!data.empty() && "Empty packet?"); 56 57 // We've already acknowledge the '+' packet so we're done here. 58 if (data == "+") 59 return true; 60 61 /// Don't 't reply to ^C. We need this because of stop reply packets, which 62 /// are only returned when the target halts. Reproducers synchronize these 63 /// 'asynchronous' replies, by recording them as a regular replies to the 64 /// previous packet (e.g. vCont). As a result, we should ignore real 65 /// asynchronous requests. 66 if (data.data()[0] == 0x03) 67 return true; 68 69 return false; 70 } 71 72 GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer() 73 : GDBRemoteCommunication("gdb-replay", "gdb-replay.rx_packet"), 74 m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"), 75 m_async_listener_sp( 76 Listener::MakeListener("lldb.gdb-replay.async-listener")), 77 m_async_thread_state_mutex() { 78 m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, 79 "async thread continue"); 80 m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, 81 "async thread should exit"); 82 83 const uint32_t async_event_mask = 84 eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; 85 m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, 86 async_event_mask); 87 } 88 89 GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() { 90 StopAsyncThread(); 91 } 92 93 GDBRemoteCommunication::PacketResult 94 GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( 95 Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) { 96 std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 97 98 StringExtractorGDBRemote packet; 99 PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); 100 101 if (packet_result != PacketResult::Success) { 102 if (!IsConnected()) { 103 error.SetErrorString("lost connection"); 104 quit = true; 105 } else { 106 error.SetErrorString("timeout"); 107 } 108 return packet_result; 109 } 110 111 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 112 113 // Check if we should reply to this packet. 114 if (skip(packet.GetStringRef())) 115 return PacketResult::Success; 116 117 // This completes the handshake. Since m_send_acks was true, we can unset it 118 // already. 119 if (packet.GetStringRef() == "QStartNoAckMode") 120 m_send_acks = false; 121 122 // A QEnvironment packet is sent for every environment variable. If the 123 // number of environment variables is different during replay, the replies 124 // become out of sync. 125 if (packet.GetStringRef().find("QEnvironment") == 0) 126 return SendRawPacketNoLock("$OK#9a"); 127 128 Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); 129 while (!m_packet_history.empty()) { 130 // Pop last packet from the history. 131 GDBRemotePacket entry = m_packet_history.back(); 132 m_packet_history.pop_back(); 133 134 // Decode run-length encoding. 135 const std::string expanded_data = 136 GDBRemoteCommunication::ExpandRLE(entry.packet.data); 137 138 // We've handled the handshake implicitly before. Skip the packet and move 139 // on. 140 if (entry.packet.data == "+") 141 continue; 142 143 if (entry.type == GDBRemotePacket::ePacketTypeSend) { 144 if (unexpected(expanded_data, packet.GetStringRef())) { 145 LLDB_LOG(log, 146 "GDBRemoteCommunicationReplayServer expected packet: '{0}'", 147 expanded_data); 148 LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", 149 packet.GetStringRef()); 150 #ifndef NDEBUG 151 // This behaves like a regular assert, but prints the expected and 152 // received packet before aborting. 153 printf("Reproducer expected packet: '%s'\n", expanded_data.c_str()); 154 printf("Reproducer received packet: '%s'\n", 155 packet.GetStringRef().data()); 156 llvm::report_fatal_error("Encountered unexpected packet during replay"); 157 #endif 158 return PacketResult::ErrorSendFailed; 159 } 160 161 // Ignore QEnvironment packets as they're handled earlier. 162 if (expanded_data.find("QEnvironment") == 1) { 163 assert(m_packet_history.back().type == 164 GDBRemotePacket::ePacketTypeRecv); 165 m_packet_history.pop_back(); 166 } 167 168 continue; 169 } 170 171 if (entry.type == GDBRemotePacket::ePacketTypeInvalid) { 172 LLDB_LOG( 173 log, 174 "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'", 175 packet.GetStringRef()); 176 continue; 177 } 178 179 LLDB_LOG(log, 180 "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'", 181 packet.GetStringRef(), entry.packet.data); 182 return SendRawPacketNoLock(entry.packet.data); 183 } 184 185 quit = true; 186 187 return packet_result; 188 } 189 190 llvm::Error 191 GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) { 192 auto error_or_file = MemoryBuffer::getFile(path.GetPath()); 193 if (auto err = error_or_file.getError()) 194 return errorCodeToError(err); 195 196 yaml::Input yin((*error_or_file)->getBuffer()); 197 yin >> m_packet_history; 198 199 if (auto err = yin.error()) 200 return errorCodeToError(err); 201 202 // We want to manipulate the vector like a stack so we need to reverse the 203 // order of the packets to have the oldest on at the back. 204 std::reverse(m_packet_history.begin(), m_packet_history.end()); 205 206 return Error::success(); 207 } 208 209 bool GDBRemoteCommunicationReplayServer::StartAsyncThread() { 210 std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 211 if (!m_async_thread.IsJoinable()) { 212 // Create a thread that watches our internal state and controls which 213 // events make it to clients (into the DCProcess event queue). 214 llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread( 215 "<lldb.gdb-replay.async>", 216 GDBRemoteCommunicationReplayServer::AsyncThread, this); 217 if (!async_thread) { 218 LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), 219 async_thread.takeError(), 220 "failed to launch host thread: {}"); 221 return false; 222 } 223 m_async_thread = *async_thread; 224 } 225 226 // Wait for handshake. 227 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 228 229 return m_async_thread.IsJoinable(); 230 } 231 232 void GDBRemoteCommunicationReplayServer::StopAsyncThread() { 233 std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 234 235 if (!m_async_thread.IsJoinable()) 236 return; 237 238 // Request thread to stop. 239 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); 240 241 // Disconnect client. 242 Disconnect(); 243 244 // Stop the thread. 245 m_async_thread.Join(nullptr); 246 m_async_thread.Reset(); 247 } 248 249 void GDBRemoteCommunicationReplayServer::ReceivePacket( 250 GDBRemoteCommunicationReplayServer &server, bool &done) { 251 Status error; 252 bool interrupt; 253 auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1), 254 error, interrupt, done); 255 if (packet_result != GDBRemoteCommunication::PacketResult::Success && 256 packet_result != 257 GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) { 258 done = true; 259 } else { 260 server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 261 } 262 } 263 264 thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) { 265 GDBRemoteCommunicationReplayServer *server = 266 (GDBRemoteCommunicationReplayServer *)arg; 267 auto D = make_scope_exit([&]() { server->Disconnect(); }); 268 EventSP event_sp; 269 bool done = false; 270 while (!done) { 271 if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { 272 const uint32_t event_type = event_sp->GetType(); 273 if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) { 274 switch (event_type) { 275 case eBroadcastBitAsyncContinue: 276 ReceivePacket(*server, done); 277 if (done) 278 return {}; 279 break; 280 case eBroadcastBitAsyncThreadShouldExit: 281 default: 282 return {}; 283 } 284 } 285 } 286 } 287 288 return {}; 289 } 290 291 Status GDBRemoteCommunicationReplayServer::Connect( 292 process_gdb_remote::GDBRemoteCommunicationClient &client) { 293 repro::Loader *loader = repro::Reproducer::Instance().GetLoader(); 294 if (!loader) 295 return Status("No loader provided."); 296 297 static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>> 298 multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create( 299 repro::Reproducer::Instance().GetLoader()); 300 if (!multi_loader) 301 return Status("No gdb remote provider found."); 302 303 llvm::Optional<std::string> history_file = multi_loader->GetNextFile(); 304 if (!history_file) 305 return Status("No gdb remote packet log found."); 306 307 if (auto error = LoadReplayHistory(FileSpec(*history_file))) 308 return Status("Unable to load replay history"); 309 310 if (auto error = GDBRemoteCommunication::ConnectLocally(client, *this)) 311 return Status("Unable to connect to replay server"); 312 313 return {}; 314 } 315