GDBRemoteCommunicationReplayServer.cpp revision 343181
1//===-- GDBRemoteCommunicationReplayServer.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 <errno.h> 11 12#include "lldb/Host/Config.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 29using namespace llvm; 30using namespace lldb; 31using namespace lldb_private; 32using namespace lldb_private::process_gdb_remote; 33 34GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer() 35 : GDBRemoteCommunication("gdb-remote.server", 36 "gdb-remote.server.rx_packet"), 37 m_async_broadcaster(nullptr, "lldb.gdb-remote.server.async-broadcaster"), 38 m_async_listener_sp( 39 Listener::MakeListener("lldb.gdb-remote.server.async-listener")), 40 m_async_thread_state_mutex(), m_skip_acks(false) { 41 m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, 42 "async thread continue"); 43 m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, 44 "async thread should exit"); 45 46 const uint32_t async_event_mask = 47 eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; 48 m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, 49 async_event_mask); 50} 51 52GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() { 53 StopAsyncThread(); 54} 55 56GDBRemoteCommunication::PacketResult 57GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( 58 Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) { 59 StringExtractorGDBRemote packet; 60 PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false); 61 62 if (packet_result != PacketResult::Success) { 63 if (!IsConnected()) { 64 error.SetErrorString("lost connection"); 65 quit = true; 66 } else { 67 error.SetErrorString("timeout"); 68 } 69 return packet_result; 70 } 71 72 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 73 74 if (m_skip_acks) { 75 const StringExtractorGDBRemote::ServerPacketType packet_type = 76 packet.GetServerPacketType(); 77 switch (packet_type) { 78 case StringExtractorGDBRemote::eServerPacketType_nack: 79 case StringExtractorGDBRemote::eServerPacketType_ack: 80 return PacketResult::Success; 81 default: 82 break; 83 } 84 } else if (packet.GetStringRef() == "QStartNoAckMode") { 85 m_skip_acks = true; 86 m_send_acks = false; 87 } 88 89 while (!m_packet_history.empty()) { 90 // Pop last packet from the history. 91 GDBRemoteCommunicationHistory::Entry entry = m_packet_history.back(); 92 m_packet_history.pop_back(); 93 94 // We only care about what we received from the server. Skip everything 95 // the client sent. 96 if (entry.type != GDBRemoteCommunicationHistory::ePacketTypeRecv) 97 continue; 98 99 return SendRawPacketNoLock(entry.packet.data, true); 100 } 101 102 quit = true; 103 104 return packet_result; 105} 106 107LLVM_YAML_IS_DOCUMENT_LIST_VECTOR( 108 std::vector< 109 lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry>) 110 111llvm::Error 112GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) { 113 auto error_or_file = MemoryBuffer::getFile(path.GetPath()); 114 if (auto err = error_or_file.getError()) 115 return errorCodeToError(err); 116 117 yaml::Input yin((*error_or_file)->getBuffer()); 118 yin >> m_packet_history; 119 120 if (auto err = yin.error()) 121 return errorCodeToError(err); 122 123 // We want to manipulate the vector like a stack so we need to reverse the 124 // order of the packets to have the oldest on at the back. 125 std::reverse(m_packet_history.begin(), m_packet_history.end()); 126 127 return Error::success(); 128} 129 130bool GDBRemoteCommunicationReplayServer::StartAsyncThread() { 131 std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 132 if (!m_async_thread.IsJoinable()) { 133 // Create a thread that watches our internal state and controls which 134 // events make it to clients (into the DCProcess event queue). 135 m_async_thread = ThreadLauncher::LaunchThread( 136 "<lldb.gdb-remote.server.async>", 137 GDBRemoteCommunicationReplayServer::AsyncThread, this, nullptr); 138 } 139 140 // Wait for handshake. 141 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 142 143 return m_async_thread.IsJoinable(); 144} 145 146void GDBRemoteCommunicationReplayServer::StopAsyncThread() { 147 std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex); 148 149 if (!m_async_thread.IsJoinable()) 150 return; 151 152 // Request thread to stop. 153 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); 154 155 // Disconnect client. 156 Disconnect(); 157 158 // Stop the thread. 159 m_async_thread.Join(nullptr); 160 m_async_thread.Reset(); 161} 162 163void GDBRemoteCommunicationReplayServer::ReceivePacket( 164 GDBRemoteCommunicationReplayServer &server, bool &done) { 165 Status error; 166 bool interrupt; 167 auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1), 168 error, interrupt, done); 169 if (packet_result != GDBRemoteCommunication::PacketResult::Success && 170 packet_result != 171 GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) { 172 done = true; 173 } else { 174 server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); 175 } 176} 177 178thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) { 179 GDBRemoteCommunicationReplayServer *server = 180 (GDBRemoteCommunicationReplayServer *)arg; 181 182 EventSP event_sp; 183 bool done = false; 184 185 while (true) { 186 if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { 187 const uint32_t event_type = event_sp->GetType(); 188 if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) { 189 switch (event_type) { 190 case eBroadcastBitAsyncContinue: 191 ReceivePacket(*server, done); 192 if (done) 193 return {}; 194 break; 195 case eBroadcastBitAsyncThreadShouldExit: 196 default: 197 return {}; 198 } 199 } 200 } 201 } 202 203 return {}; 204} 205