LLDB  mainline
GDBRemoteCommunicationReplayServer.cpp
Go to the documentation of this file.
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 
14 #include "ProcessGDBRemoteLog.h"
15 
16 // C Includes
17 // C++ Includes
18 #include <cstring>
19 
20 // Project includes
23 #include "lldb/Utility/Event.h"
24 #include "lldb/Utility/FileSpec.h"
27 
28 using namespace llvm;
29 using namespace lldb;
30 using namespace lldb_private;
31 using namespace lldb_private::process_gdb_remote;
32 
33 static bool unexpected(llvm::StringRef expected, llvm::StringRef actual) {
34  // The 'expected' string contains the raw data, including the leading $ and
35  // trailing checksum. The 'actual' string contains only the packet's content.
36  if (expected.contains(actual))
37  return false;
38  // Contains a PID which might be different.
39  if (expected.contains("vAttach"))
40  return false;
41  // Contains a ascii-hex-path.
42  if (expected.contains("QSetSTD"))
43  return false;
44  // Contains environment values.
45  if (expected.contains("QEnvironment"))
46  return false;
47 
48  return true;
49 }
50 
51 GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer()
52  : GDBRemoteCommunication("gdb-replay", "gdb-replay.rx_packet"),
53  m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"),
54  m_async_listener_sp(
55  Listener::MakeListener("lldb.gdb-replay.async-listener")),
56  m_async_thread_state_mutex(), m_skip_acks(false) {
58  "async thread continue");
60  "async thread should exit");
61 
62  const uint32_t async_event_mask =
64  m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster,
65  async_event_mask);
66 }
67 
70 }
71 
74  Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
75  std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
76 
78  PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false);
79 
80  if (packet_result != PacketResult::Success) {
81  if (!IsConnected()) {
82  error.SetErrorString("lost connection");
83  quit = true;
84  } else {
85  error.SetErrorString("timeout");
86  }
87  return packet_result;
88  }
89 
91 
92  // If m_send_acks is true, we're before the handshake phase. We've already
93  // acknowledge the '+' packet so we're done here.
94  if (m_send_acks && packet.GetStringRef() == "+")
95  return PacketResult::Success;
96 
97  // This completes the handshake. Since m_send_acks was true, we can unset it
98  // already.
99  if (packet.GetStringRef() == "QStartNoAckMode")
100  m_send_acks = false;
101 
102  // A QEnvironment packet is sent for every environment variable. If the
103  // number of environment variables is different during replay, the replies
104  // become out of sync.
105  if (packet.GetStringRef().find("QEnvironment") == 0) {
106  return SendRawPacketNoLock("$OK#9a");
107  }
108 
110  while (!m_packet_history.empty()) {
111  // Pop last packet from the history.
113  m_packet_history.pop_back();
114 
115  // We're handled the handshake implicitly before. Skip the packet and move
116  // on.
117  if (entry.packet.data == "+")
118  continue;
119 
121  if (unexpected(entry.packet.data, packet.GetStringRef())) {
122  LLDB_LOG(log,
123  "GDBRemoteCommunicationReplayServer expected packet: '{0}'",
124  entry.packet.data);
125  LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'",
126  packet.GetStringRef());
127  }
128 
129  // Ignore QEnvironment packets as they're handled earlier.
130  if (entry.packet.data.find("QEnvironment") == 1) {
131  assert(m_packet_history.back().type ==
133  m_packet_history.pop_back();
134  }
135 
136  continue;
137  }
138 
140  LLDB_LOG(
141  log,
142  "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'",
143  packet.GetStringRef());
144  continue;
145  }
146 
147  LLDB_LOG(log,
148  "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'",
149  packet.GetStringRef(), entry.packet.data);
150  return SendRawPacketNoLock(entry.packet.data);
151  }
152 
153  quit = true;
154 
155  return packet_result;
156 }
157 
159  std::vector<
161 
162 llvm::Error
164  auto error_or_file = MemoryBuffer::getFile(path.GetPath());
165  if (auto err = error_or_file.getError())
166  return errorCodeToError(err);
167 
168  yaml::Input yin((*error_or_file)->getBuffer());
169  yin >> m_packet_history;
170 
171  if (auto err = yin.error())
172  return errorCodeToError(err);
173 
174  // We want to manipulate the vector like a stack so we need to reverse the
175  // order of the packets to have the oldest on at the back.
176  std::reverse(m_packet_history.begin(), m_packet_history.end());
177 
178  return Error::success();
179 }
180 
182  std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
183  if (!m_async_thread.IsJoinable()) {
184  // Create a thread that watches our internal state and controls which
185  // events make it to clients (into the DCProcess event queue).
187  "<lldb.gdb-replay.async>",
189  }
190 
191  // Wait for handshake.
193 
194  return m_async_thread.IsJoinable();
195 }
196 
198  std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
199 
200  if (!m_async_thread.IsJoinable())
201  return;
202 
203  // Request thread to stop.
205 
206  // Disconnect client.
207  Disconnect();
208 
209  // Stop the thread.
210  m_async_thread.Join(nullptr);
212 }
213 
215  GDBRemoteCommunicationReplayServer &server, bool &done) {
216  Status error;
217  bool interrupt;
218  auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1),
219  error, interrupt, done);
220  if (packet_result != GDBRemoteCommunication::PacketResult::Success &&
221  packet_result !=
223  done = true;
224  } else {
226  }
227 }
228 
232 
233  EventSP event_sp;
234  bool done = false;
235 
236  while (true) {
237  if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
238  const uint32_t event_type = event_sp->GetType();
239  if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) {
240  switch (event_type) {
242  ReceivePacket(*server, done);
243  if (done)
244  return {};
245  break;
247  default:
248  return {};
249  }
250  }
251  }
252  }
253 
254  return {};
255 }
static bool unexpected(llvm::StringRef expected, llvm::StringRef actual)
void SetEventName(uint32_t event_mask, const char *name)
Set the name for an event bit.
Definition: Broadcaster.h:361
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
Definition: Debugger.h:71
PacketResult GetPacketAndSendResponse(Timeout< std::micro > timeout, Status &error, bool &interrupt, bool &quit)
lldb::ConnectionStatus Disconnect(Status *error_ptr=nullptr)
Disconnect the communications connection if one is currently connected.
static HostThread LaunchThread(llvm::StringRef name, lldb::thread_func_t thread_function, lldb::thread_arg_t thread_arg, Status *error_ptr, size_t min_stack_byte_size=0)
PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response, Timeout< std::micro > timeout, bool sync_on_timeout)
llvm::Error Error
A file utility class.
Definition: FileSpec.h:55
Dummy GDB server that replays packets from the GDB Remote Communication history.
#define LLDB_LOG(log,...)
Definition: Log.h:209
void BroadcastEvent(lldb::EventSP &event_sp)
Broadcast an event which has no associated data.
Definition: Broadcaster.h:283
Entry in the ring buffer containing the packet data, its type, size and index.
#define GDBR_LOG_PROCESS
std::vector< GDBRemoteCommunicationHistory::Entry > m_packet_history
Replay history with the oldest packet at the end.
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:241
Status Join(lldb::thread_result_t *result)
Definition: HostThread.cpp:20
bool IsConnected() const
Check if the connection is valid.
Definition: SBAddress.h:15
static void ReceivePacket(GDBRemoteCommunicationReplayServer &server, bool &done)
PacketResult SendRawPacketNoLock(llvm::StringRef payload, bool skip_ack=false)
std::string & GetStringRef()
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(std::vector< lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry >) llvm
An error handling class.
Definition: Status.h:44
void * thread_result_t
Definition: lldb-types.h:62