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