blob: 6a78eb20992e0edee757efb6c361175198b79b84 [file] [log] [blame]
Jonas Devlieghere9e046f02018-11-13 19:18:16 +00001//===-- 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
Jonas Devlieghere9e046f02018-11-13 19:18:16 +000022#include "lldb/Host/ThreadLauncher.h"
23#include "lldb/Utility/ConstString.h"
Pavel Labath181b8232018-12-14 15:59:49 +000024#include "lldb/Utility/Event.h"
Jonas Devlieghere9e046f02018-11-13 19:18:16 +000025#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)
Zachary Turnerfca18e92018-11-14 17:22:09 +0000193 return {};
Jonas Devlieghere9e046f02018-11-13 19:18:16 +0000194 break;
195 case eBroadcastBitAsyncThreadShouldExit:
196 default:
Zachary Turnerfca18e92018-11-14 17:22:09 +0000197 return {};
Jonas Devlieghere9e046f02018-11-13 19:18:16 +0000198 }
199 }
200 }
201 }
202
Zachary Turnerfca18e92018-11-14 17:22:09 +0000203 return {};
Jonas Devlieghere9e046f02018-11-13 19:18:16 +0000204}