1343181Sdim//===-- GDBRemoteCommunicationReplayServer.cpp ------------------*- C++ -*-===// 2343181Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343181Sdim// 7343181Sdim//===----------------------------------------------------------------------===// 8343181Sdim 9343181Sdim#include <errno.h> 10343181Sdim 11343181Sdim#include "lldb/Host/Config.h" 12360784Sdim#include "llvm/ADT/ScopeExit.h" 13343181Sdim 14343181Sdim#include "GDBRemoteCommunicationReplayServer.h" 15343181Sdim#include "ProcessGDBRemoteLog.h" 16343181Sdim 17343181Sdim// C Includes 18343181Sdim// C++ Includes 19343181Sdim#include <cstring> 20343181Sdim 21343181Sdim// Project includes 22343181Sdim#include "lldb/Host/ThreadLauncher.h" 23343181Sdim#include "lldb/Utility/ConstString.h" 24343181Sdim#include "lldb/Utility/Event.h" 25343181Sdim#include "lldb/Utility/FileSpec.h" 26343181Sdim#include "lldb/Utility/StreamString.h" 27343181Sdim#include "lldb/Utility/StringExtractorGDBRemote.h" 28343181Sdim 29343181Sdimusing namespace llvm; 30343181Sdimusing namespace lldb; 31343181Sdimusing namespace lldb_private; 32343181Sdimusing namespace lldb_private::process_gdb_remote; 33343181Sdim 34353358Sdim/// Check if the given expected packet matches the actual packet. 35353358Sdimstatic bool unexpected(llvm::StringRef expected, llvm::StringRef actual) { 36353358Sdim // The 'expected' string contains the raw data, including the leading $ and 37353358Sdim // trailing checksum. The 'actual' string contains only the packet's content. 38353358Sdim if (expected.contains(actual)) 39353358Sdim return false; 40353358Sdim // Contains a PID which might be different. 41353358Sdim if (expected.contains("vAttach")) 42353358Sdim return false; 43353358Sdim // Contains a ascii-hex-path. 44353358Sdim if (expected.contains("QSetSTD")) 45353358Sdim return false; 46353358Sdim // Contains environment values. 47353358Sdim if (expected.contains("QEnvironment")) 48353358Sdim return false; 49353358Sdim 50353358Sdim return true; 51353358Sdim} 52353358Sdim 53353358Sdim/// Check if we should reply to the given packet. 54353358Sdimstatic bool skip(llvm::StringRef data) { 55353358Sdim assert(!data.empty() && "Empty packet?"); 56353358Sdim 57353358Sdim // We've already acknowledge the '+' packet so we're done here. 58353358Sdim if (data == "+") 59353358Sdim return true; 60353358Sdim 61353358Sdim /// Don't 't reply to ^C. We need this because of stop reply packets, which 62353358Sdim /// are only returned when the target halts. Reproducers synchronize these 63353358Sdim /// 'asynchronous' replies, by recording them as a regular replies to the 64353358Sdim /// previous packet (e.g. vCont). As a result, we should ignore real 65353358Sdim /// asynchronous requests. 66353358Sdim if (data.data()[0] == 0x03) 67353358Sdim return true; 68353358Sdim 69353358Sdim return false; 70353358Sdim} 71353358Sdim 72343181SdimGDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer() 73353358Sdim : GDBRemoteCommunication("gdb-replay", "gdb-replay.rx_packet"), 74353358Sdim m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"), 75343181Sdim m_async_listener_sp( 76353358Sdim Listener::MakeListener("lldb.gdb-replay.async-listener")), 77343181Sdim m_async_thread_state_mutex(), m_skip_acks(false) { 78343181Sdim m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, 79343181Sdim "async thread continue"); 80343181Sdim m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, 81343181Sdim "async thread should exit"); 82343181Sdim 83343181Sdim const uint32_t async_event_mask = 84343181Sdim eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; 85343181Sdim m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, 86343181Sdim async_event_mask); 87343181Sdim} 88343181Sdim 89343181SdimGDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() { 90343181Sdim StopAsyncThread(); 91343181Sdim} 92343181Sdim 93343181SdimGDBRemoteCommunication::PacketResult 94343181SdimGDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( 95343181Sdim Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) { 96353358Sdim std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 97353358Sdim 98343181Sdim StringExtractorGDBRemote packet; 99343181Sdim PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); 100343181Sdim 101343181Sdim if (packet_result != PacketResult::Success) { 102343181Sdim if (!IsConnected()) { 103343181Sdim error.SetErrorString("lost connection"); 104343181Sdim quit = true; 105343181Sdim } else { 106343181Sdim error.SetErrorString("timeout"); 107343181Sdim } 108343181Sdim return packet_result; 109343181Sdim } 110343181Sdim 111343181Sdim m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 112343181Sdim 113353358Sdim // Check if we should reply to this packet. 114353358Sdim if (skip(packet.GetStringRef())) 115353358Sdim return PacketResult::Success; 116353358Sdim 117353358Sdim // This completes the handshake. Since m_send_acks was true, we can unset it 118353358Sdim // already. 119353358Sdim if (packet.GetStringRef() == "QStartNoAckMode") 120343181Sdim m_send_acks = false; 121343181Sdim 122353358Sdim // A QEnvironment packet is sent for every environment variable. If the 123353358Sdim // number of environment variables is different during replay, the replies 124353358Sdim // become out of sync. 125353358Sdim if (packet.GetStringRef().find("QEnvironment") == 0) 126353358Sdim return SendRawPacketNoLock("$OK#9a"); 127353358Sdim 128353358Sdim Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); 129343181Sdim while (!m_packet_history.empty()) { 130343181Sdim // Pop last packet from the history. 131360784Sdim GDBRemotePacket entry = m_packet_history.back(); 132343181Sdim m_packet_history.pop_back(); 133343181Sdim 134353358Sdim // We've handled the handshake implicitly before. Skip the packet and move 135353358Sdim // on. 136353358Sdim if (entry.packet.data == "+") 137343181Sdim continue; 138343181Sdim 139360784Sdim if (entry.type == GDBRemotePacket::ePacketTypeSend) { 140353358Sdim if (unexpected(entry.packet.data, packet.GetStringRef())) { 141353358Sdim LLDB_LOG(log, 142353358Sdim "GDBRemoteCommunicationReplayServer expected packet: '{0}'", 143353358Sdim entry.packet.data); 144353358Sdim LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", 145353358Sdim packet.GetStringRef()); 146360784Sdim#ifndef NDEBUG 147360784Sdim // This behaves like a regular assert, but prints the expected and 148360784Sdim // received packet before aborting. 149360784Sdim printf("Reproducer expected packet: '%s'\n", entry.packet.data.c_str()); 150360784Sdim printf("Reproducer received packet: '%s'\n", 151360784Sdim packet.GetStringRef().data()); 152360784Sdim llvm::report_fatal_error("Encountered unexpected packet during replay"); 153360784Sdim#endif 154353358Sdim return PacketResult::ErrorSendFailed; 155353358Sdim } 156353358Sdim 157353358Sdim // Ignore QEnvironment packets as they're handled earlier. 158353358Sdim if (entry.packet.data.find("QEnvironment") == 1) { 159353358Sdim assert(m_packet_history.back().type == 160360784Sdim GDBRemotePacket::ePacketTypeRecv); 161353358Sdim m_packet_history.pop_back(); 162353358Sdim } 163353358Sdim 164353358Sdim continue; 165353358Sdim } 166353358Sdim 167360784Sdim if (entry.type == GDBRemotePacket::ePacketTypeInvalid) { 168353358Sdim LLDB_LOG( 169353358Sdim log, 170353358Sdim "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'", 171353358Sdim packet.GetStringRef()); 172353358Sdim continue; 173353358Sdim } 174353358Sdim 175353358Sdim LLDB_LOG(log, 176353358Sdim "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'", 177353358Sdim packet.GetStringRef(), entry.packet.data); 178353358Sdim return SendRawPacketNoLock(entry.packet.data); 179343181Sdim } 180343181Sdim 181343181Sdim quit = true; 182343181Sdim 183343181Sdim return packet_result; 184343181Sdim} 185343181Sdim 186343181Sdimllvm::Error 187343181SdimGDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) { 188343181Sdim auto error_or_file = MemoryBuffer::getFile(path.GetPath()); 189343181Sdim if (auto err = error_or_file.getError()) 190343181Sdim return errorCodeToError(err); 191343181Sdim 192343181Sdim yaml::Input yin((*error_or_file)->getBuffer()); 193343181Sdim yin >> m_packet_history; 194343181Sdim 195343181Sdim if (auto err = yin.error()) 196343181Sdim return errorCodeToError(err); 197343181Sdim 198343181Sdim // We want to manipulate the vector like a stack so we need to reverse the 199343181Sdim // order of the packets to have the oldest on at the back. 200343181Sdim std::reverse(m_packet_history.begin(), m_packet_history.end()); 201343181Sdim 202343181Sdim return Error::success(); 203343181Sdim} 204343181Sdim 205343181Sdimbool GDBRemoteCommunicationReplayServer::StartAsyncThread() { 206343181Sdim std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 207343181Sdim if (!m_async_thread.IsJoinable()) { 208343181Sdim // Create a thread that watches our internal state and controls which 209343181Sdim // events make it to clients (into the DCProcess event queue). 210353358Sdim llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread( 211353358Sdim "<lldb.gdb-replay.async>", 212353358Sdim GDBRemoteCommunicationReplayServer::AsyncThread, this); 213353358Sdim if (!async_thread) { 214360784Sdim LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), 215360784Sdim async_thread.takeError(), 216360784Sdim "failed to launch host thread: {}"); 217353358Sdim return false; 218353358Sdim } 219353358Sdim m_async_thread = *async_thread; 220343181Sdim } 221343181Sdim 222343181Sdim // Wait for handshake. 223343181Sdim m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 224343181Sdim 225343181Sdim return m_async_thread.IsJoinable(); 226343181Sdim} 227343181Sdim 228343181Sdimvoid GDBRemoteCommunicationReplayServer::StopAsyncThread() { 229343181Sdim std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 230343181Sdim 231343181Sdim if (!m_async_thread.IsJoinable()) 232343181Sdim return; 233343181Sdim 234343181Sdim // Request thread to stop. 235343181Sdim m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); 236343181Sdim 237343181Sdim // Disconnect client. 238343181Sdim Disconnect(); 239343181Sdim 240343181Sdim // Stop the thread. 241343181Sdim m_async_thread.Join(nullptr); 242343181Sdim m_async_thread.Reset(); 243343181Sdim} 244343181Sdim 245343181Sdimvoid GDBRemoteCommunicationReplayServer::ReceivePacket( 246343181Sdim GDBRemoteCommunicationReplayServer &server, bool &done) { 247343181Sdim Status error; 248343181Sdim bool interrupt; 249343181Sdim auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1), 250343181Sdim error, interrupt, done); 251343181Sdim if (packet_result != GDBRemoteCommunication::PacketResult::Success && 252343181Sdim packet_result != 253343181Sdim GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) { 254343181Sdim done = true; 255343181Sdim } else { 256343181Sdim server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 257343181Sdim } 258343181Sdim} 259343181Sdim 260343181Sdimthread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) { 261343181Sdim GDBRemoteCommunicationReplayServer *server = 262343181Sdim (GDBRemoteCommunicationReplayServer *)arg; 263360784Sdim auto D = make_scope_exit([&]() { server->Disconnect(); }); 264343181Sdim EventSP event_sp; 265343181Sdim bool done = false; 266360784Sdim while (!done) { 267343181Sdim if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { 268343181Sdim const uint32_t event_type = event_sp->GetType(); 269343181Sdim if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) { 270343181Sdim switch (event_type) { 271343181Sdim case eBroadcastBitAsyncContinue: 272343181Sdim ReceivePacket(*server, done); 273343181Sdim if (done) 274343181Sdim return {}; 275343181Sdim break; 276343181Sdim case eBroadcastBitAsyncThreadShouldExit: 277343181Sdim default: 278343181Sdim return {}; 279343181Sdim } 280343181Sdim } 281343181Sdim } 282343181Sdim } 283343181Sdim 284343181Sdim return {}; 285343181Sdim} 286