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