GDBRemoteCommunicationReplayServer.cpp revision 353358
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"
12343181Sdim
13343181Sdim#include "GDBRemoteCommunicationReplayServer.h"
14343181Sdim#include "ProcessGDBRemoteLog.h"
15343181Sdim
16343181Sdim// C Includes
17343181Sdim// C++ Includes
18343181Sdim#include <cstring>
19343181Sdim
20343181Sdim// Project includes
21343181Sdim#include "lldb/Host/ThreadLauncher.h"
22343181Sdim#include "lldb/Utility/ConstString.h"
23343181Sdim#include "lldb/Utility/Event.h"
24343181Sdim#include "lldb/Utility/FileSpec.h"
25343181Sdim#include "lldb/Utility/StreamString.h"
26343181Sdim#include "lldb/Utility/StringExtractorGDBRemote.h"
27343181Sdim
28343181Sdimusing namespace llvm;
29343181Sdimusing namespace lldb;
30343181Sdimusing namespace lldb_private;
31343181Sdimusing namespace lldb_private::process_gdb_remote;
32343181Sdim
33353358Sdim/// Check if the given expected packet matches the actual packet.
34353358Sdimstatic bool unexpected(llvm::StringRef expected, llvm::StringRef actual) {
35353358Sdim  // The 'expected' string contains the raw data, including the leading $ and
36353358Sdim  // trailing checksum. The 'actual' string contains only the packet's content.
37353358Sdim  if (expected.contains(actual))
38353358Sdim    return false;
39353358Sdim  // Contains a PID which might be different.
40353358Sdim  if (expected.contains("vAttach"))
41353358Sdim    return false;
42353358Sdim  // Contains a ascii-hex-path.
43353358Sdim  if (expected.contains("QSetSTD"))
44353358Sdim    return false;
45353358Sdim  // Contains environment values.
46353358Sdim  if (expected.contains("QEnvironment"))
47353358Sdim    return false;
48353358Sdim
49353358Sdim  return true;
50353358Sdim}
51353358Sdim
52353358Sdim/// Check if we should reply to the given packet.
53353358Sdimstatic bool skip(llvm::StringRef data) {
54353358Sdim  assert(!data.empty() && "Empty packet?");
55353358Sdim
56353358Sdim  // We've already acknowledge the '+' packet so we're done here.
57353358Sdim  if (data == "+")
58353358Sdim    return true;
59353358Sdim
60353358Sdim  /// Don't 't reply to ^C. We need this because of stop reply packets, which
61353358Sdim  /// are only returned when the target halts. Reproducers synchronize these
62353358Sdim  /// 'asynchronous' replies, by recording them as a regular replies to the
63353358Sdim  /// previous packet (e.g. vCont). As a result, we should ignore real
64353358Sdim  /// asynchronous requests.
65353358Sdim  if (data.data()[0] == 0x03)
66353358Sdim    return true;
67353358Sdim
68353358Sdim  return false;
69353358Sdim}
70353358Sdim
71343181SdimGDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer()
72353358Sdim    : GDBRemoteCommunication("gdb-replay", "gdb-replay.rx_packet"),
73353358Sdim      m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"),
74343181Sdim      m_async_listener_sp(
75353358Sdim          Listener::MakeListener("lldb.gdb-replay.async-listener")),
76343181Sdim      m_async_thread_state_mutex(), m_skip_acks(false) {
77343181Sdim  m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
78343181Sdim                                   "async thread continue");
79343181Sdim  m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
80343181Sdim                                   "async thread should exit");
81343181Sdim
82343181Sdim  const uint32_t async_event_mask =
83343181Sdim      eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit;
84343181Sdim  m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster,
85343181Sdim                                               async_event_mask);
86343181Sdim}
87343181Sdim
88343181SdimGDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() {
89343181Sdim  StopAsyncThread();
90343181Sdim}
91343181Sdim
92343181SdimGDBRemoteCommunication::PacketResult
93343181SdimGDBRemoteCommunicationReplayServer::GetPacketAndSendResponse(
94343181Sdim    Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
95353358Sdim  std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
96353358Sdim
97343181Sdim  StringExtractorGDBRemote packet;
98343181Sdim  PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false);
99343181Sdim
100343181Sdim  if (packet_result != PacketResult::Success) {
101343181Sdim    if (!IsConnected()) {
102343181Sdim      error.SetErrorString("lost connection");
103343181Sdim      quit = true;
104343181Sdim    } else {
105343181Sdim      error.SetErrorString("timeout");
106343181Sdim    }
107343181Sdim    return packet_result;
108343181Sdim  }
109343181Sdim
110343181Sdim  m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
111343181Sdim
112353358Sdim  // Check if we should reply to this packet.
113353358Sdim  if (skip(packet.GetStringRef()))
114353358Sdim    return PacketResult::Success;
115353358Sdim
116353358Sdim  // This completes the handshake. Since m_send_acks was true, we can unset it
117353358Sdim  // already.
118353358Sdim  if (packet.GetStringRef() == "QStartNoAckMode")
119343181Sdim    m_send_acks = false;
120343181Sdim
121353358Sdim  // A QEnvironment packet is sent for every environment variable. If the
122353358Sdim  // number of environment variables is different during replay, the replies
123353358Sdim  // become out of sync.
124353358Sdim  if (packet.GetStringRef().find("QEnvironment") == 0)
125353358Sdim    return SendRawPacketNoLock("$OK#9a");
126353358Sdim
127353358Sdim  Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
128343181Sdim  while (!m_packet_history.empty()) {
129343181Sdim    // Pop last packet from the history.
130343181Sdim    GDBRemoteCommunicationHistory::Entry entry = m_packet_history.back();
131343181Sdim    m_packet_history.pop_back();
132343181Sdim
133353358Sdim    // We've handled the handshake implicitly before. Skip the packet and move
134353358Sdim    // on.
135353358Sdim    if (entry.packet.data == "+")
136343181Sdim      continue;
137343181Sdim
138353358Sdim    if (entry.type == GDBRemoteCommunicationHistory::ePacketTypeSend) {
139353358Sdim      if (unexpected(entry.packet.data, packet.GetStringRef())) {
140353358Sdim        LLDB_LOG(log,
141353358Sdim                 "GDBRemoteCommunicationReplayServer expected packet: '{0}'",
142353358Sdim                 entry.packet.data);
143353358Sdim        LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'",
144353358Sdim                 packet.GetStringRef());
145353358Sdim        assert(false && "Encountered unexpected packet during replay");
146353358Sdim        return PacketResult::ErrorSendFailed;
147353358Sdim      }
148353358Sdim
149353358Sdim      // Ignore QEnvironment packets as they're handled earlier.
150353358Sdim      if (entry.packet.data.find("QEnvironment") == 1) {
151353358Sdim        assert(m_packet_history.back().type ==
152353358Sdim               GDBRemoteCommunicationHistory::ePacketTypeRecv);
153353358Sdim        m_packet_history.pop_back();
154353358Sdim      }
155353358Sdim
156353358Sdim      continue;
157353358Sdim    }
158353358Sdim
159353358Sdim    if (entry.type == GDBRemoteCommunicationHistory::ePacketTypeInvalid) {
160353358Sdim      LLDB_LOG(
161353358Sdim          log,
162353358Sdim          "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'",
163353358Sdim          packet.GetStringRef());
164353358Sdim      continue;
165353358Sdim    }
166353358Sdim
167353358Sdim    LLDB_LOG(log,
168353358Sdim             "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'",
169353358Sdim             packet.GetStringRef(), entry.packet.data);
170353358Sdim    return SendRawPacketNoLock(entry.packet.data);
171343181Sdim  }
172343181Sdim
173343181Sdim  quit = true;
174343181Sdim
175343181Sdim  return packet_result;
176343181Sdim}
177343181Sdim
178343181SdimLLVM_YAML_IS_DOCUMENT_LIST_VECTOR(
179343181Sdim    std::vector<
180343181Sdim        lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry>)
181343181Sdim
182343181Sdimllvm::Error
183343181SdimGDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) {
184343181Sdim  auto error_or_file = MemoryBuffer::getFile(path.GetPath());
185343181Sdim  if (auto err = error_or_file.getError())
186343181Sdim    return errorCodeToError(err);
187343181Sdim
188343181Sdim  yaml::Input yin((*error_or_file)->getBuffer());
189343181Sdim  yin >> m_packet_history;
190343181Sdim
191343181Sdim  if (auto err = yin.error())
192343181Sdim    return errorCodeToError(err);
193343181Sdim
194343181Sdim  // We want to manipulate the vector like a stack so we need to reverse the
195343181Sdim  // order of the packets to have the oldest on at the back.
196343181Sdim  std::reverse(m_packet_history.begin(), m_packet_history.end());
197343181Sdim
198343181Sdim  return Error::success();
199343181Sdim}
200343181Sdim
201343181Sdimbool GDBRemoteCommunicationReplayServer::StartAsyncThread() {
202343181Sdim  std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
203343181Sdim  if (!m_async_thread.IsJoinable()) {
204343181Sdim    // Create a thread that watches our internal state and controls which
205343181Sdim    // events make it to clients (into the DCProcess event queue).
206353358Sdim    llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread(
207353358Sdim        "<lldb.gdb-replay.async>",
208353358Sdim        GDBRemoteCommunicationReplayServer::AsyncThread, this);
209353358Sdim    if (!async_thread) {
210353358Sdim      LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
211353358Sdim               "failed to launch host thread: {}",
212353358Sdim               llvm::toString(async_thread.takeError()));
213353358Sdim      return false;
214353358Sdim    }
215353358Sdim    m_async_thread = *async_thread;
216343181Sdim  }
217343181Sdim
218343181Sdim  // Wait for handshake.
219343181Sdim  m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
220343181Sdim
221343181Sdim  return m_async_thread.IsJoinable();
222343181Sdim}
223343181Sdim
224343181Sdimvoid GDBRemoteCommunicationReplayServer::StopAsyncThread() {
225343181Sdim  std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
226343181Sdim
227343181Sdim  if (!m_async_thread.IsJoinable())
228343181Sdim    return;
229343181Sdim
230343181Sdim  // Request thread to stop.
231343181Sdim  m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit);
232343181Sdim
233343181Sdim  // Disconnect client.
234343181Sdim  Disconnect();
235343181Sdim
236343181Sdim  // Stop the thread.
237343181Sdim  m_async_thread.Join(nullptr);
238343181Sdim  m_async_thread.Reset();
239343181Sdim}
240343181Sdim
241343181Sdimvoid GDBRemoteCommunicationReplayServer::ReceivePacket(
242343181Sdim    GDBRemoteCommunicationReplayServer &server, bool &done) {
243343181Sdim  Status error;
244343181Sdim  bool interrupt;
245343181Sdim  auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1),
246343181Sdim                                                       error, interrupt, done);
247343181Sdim  if (packet_result != GDBRemoteCommunication::PacketResult::Success &&
248343181Sdim      packet_result !=
249343181Sdim          GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) {
250343181Sdim    done = true;
251343181Sdim  } else {
252343181Sdim    server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
253343181Sdim  }
254343181Sdim}
255343181Sdim
256343181Sdimthread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) {
257343181Sdim  GDBRemoteCommunicationReplayServer *server =
258343181Sdim      (GDBRemoteCommunicationReplayServer *)arg;
259343181Sdim
260343181Sdim  EventSP event_sp;
261343181Sdim  bool done = false;
262343181Sdim
263343181Sdim  while (true) {
264343181Sdim    if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
265343181Sdim      const uint32_t event_type = event_sp->GetType();
266343181Sdim      if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) {
267343181Sdim        switch (event_type) {
268343181Sdim        case eBroadcastBitAsyncContinue:
269343181Sdim          ReceivePacket(*server, done);
270343181Sdim          if (done)
271343181Sdim            return {};
272343181Sdim          break;
273343181Sdim        case eBroadcastBitAsyncThreadShouldExit:
274343181Sdim        default:
275343181Sdim          return {};
276343181Sdim        }
277343181Sdim      }
278343181Sdim    }
279343181Sdim  }
280343181Sdim
281343181Sdim  return {};
282343181Sdim}
283