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