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