1 //===-- GDBRemoteCommunicationReplayServer.cpp ----------------------------===//
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
29 using namespace llvm;
30 using namespace lldb;
31 using namespace lldb_private;
32 using namespace lldb_private::process_gdb_remote;
33
34 /// Check if the given expected packet matches the actual packet.
unexpected(llvm::StringRef expected,llvm::StringRef actual)35 static 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.
skip(llvm::StringRef data)54 static 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
GDBRemoteCommunicationReplayServer()72 GDBRemoteCommunicationReplayServer::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
~GDBRemoteCommunicationReplayServer()89 GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() {
90 StopAsyncThread();
91 }
92
93 GDBRemoteCommunication::PacketResult
GetPacketAndSendResponse(Timeout<std::micro> timeout,Status & error,bool & interrupt,bool & quit)94 GDBRemoteCommunicationReplayServer::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 // Decode run-length encoding.
135 const std::string expanded_data =
136 GDBRemoteCommunication::ExpandRLE(entry.packet.data);
137
138 // We've handled the handshake implicitly before. Skip the packet and move
139 // on.
140 if (entry.packet.data == "+")
141 continue;
142
143 if (entry.type == GDBRemotePacket::ePacketTypeSend) {
144 if (unexpected(expanded_data, packet.GetStringRef())) {
145 LLDB_LOG(log,
146 "GDBRemoteCommunicationReplayServer expected packet: '{0}'",
147 expanded_data);
148 LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'",
149 packet.GetStringRef());
150 #ifndef NDEBUG
151 // This behaves like a regular assert, but prints the expected and
152 // received packet before aborting.
153 printf("Reproducer expected packet: '%s'\n", expanded_data.c_str());
154 printf("Reproducer received packet: '%s'\n",
155 packet.GetStringRef().data());
156 llvm::report_fatal_error("Encountered unexpected packet during replay");
157 #endif
158 return PacketResult::ErrorSendFailed;
159 }
160
161 // Ignore QEnvironment packets as they're handled earlier.
162 if (expanded_data.find("QEnvironment") == 1) {
163 assert(m_packet_history.back().type ==
164 GDBRemotePacket::ePacketTypeRecv);
165 m_packet_history.pop_back();
166 }
167
168 continue;
169 }
170
171 if (entry.type == GDBRemotePacket::ePacketTypeInvalid) {
172 LLDB_LOG(
173 log,
174 "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'",
175 packet.GetStringRef());
176 continue;
177 }
178
179 LLDB_LOG(log,
180 "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'",
181 packet.GetStringRef(), entry.packet.data);
182 return SendRawPacketNoLock(entry.packet.data);
183 }
184
185 quit = true;
186
187 return packet_result;
188 }
189
190 llvm::Error
LoadReplayHistory(const FileSpec & path)191 GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) {
192 auto error_or_file = MemoryBuffer::getFile(path.GetPath());
193 if (auto err = error_or_file.getError())
194 return errorCodeToError(err);
195
196 yaml::Input yin((*error_or_file)->getBuffer());
197 yin >> m_packet_history;
198
199 if (auto err = yin.error())
200 return errorCodeToError(err);
201
202 // We want to manipulate the vector like a stack so we need to reverse the
203 // order of the packets to have the oldest on at the back.
204 std::reverse(m_packet_history.begin(), m_packet_history.end());
205
206 return Error::success();
207 }
208
StartAsyncThread()209 bool GDBRemoteCommunicationReplayServer::StartAsyncThread() {
210 std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
211 if (!m_async_thread.IsJoinable()) {
212 // Create a thread that watches our internal state and controls which
213 // events make it to clients (into the DCProcess event queue).
214 llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread(
215 "<lldb.gdb-replay.async>",
216 GDBRemoteCommunicationReplayServer::AsyncThread, this);
217 if (!async_thread) {
218 LLDB_LOG_ERROR(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
219 async_thread.takeError(),
220 "failed to launch host thread: {}");
221 return false;
222 }
223 m_async_thread = *async_thread;
224 }
225
226 // Wait for handshake.
227 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
228
229 return m_async_thread.IsJoinable();
230 }
231
StopAsyncThread()232 void GDBRemoteCommunicationReplayServer::StopAsyncThread() {
233 std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
234
235 if (!m_async_thread.IsJoinable())
236 return;
237
238 // Request thread to stop.
239 m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit);
240
241 // Disconnect client.
242 Disconnect();
243
244 // Stop the thread.
245 m_async_thread.Join(nullptr);
246 m_async_thread.Reset();
247 }
248
ReceivePacket(GDBRemoteCommunicationReplayServer & server,bool & done)249 void GDBRemoteCommunicationReplayServer::ReceivePacket(
250 GDBRemoteCommunicationReplayServer &server, bool &done) {
251 Status error;
252 bool interrupt;
253 auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1),
254 error, interrupt, done);
255 if (packet_result != GDBRemoteCommunication::PacketResult::Success &&
256 packet_result !=
257 GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) {
258 done = true;
259 } else {
260 server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
261 }
262 }
263
AsyncThread(void * arg)264 thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) {
265 GDBRemoteCommunicationReplayServer *server =
266 (GDBRemoteCommunicationReplayServer *)arg;
267 auto D = make_scope_exit([&]() { server->Disconnect(); });
268 EventSP event_sp;
269 bool done = false;
270 while (!done) {
271 if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
272 const uint32_t event_type = event_sp->GetType();
273 if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) {
274 switch (event_type) {
275 case eBroadcastBitAsyncContinue:
276 ReceivePacket(*server, done);
277 if (done)
278 return {};
279 break;
280 case eBroadcastBitAsyncThreadShouldExit:
281 default:
282 return {};
283 }
284 }
285 }
286 }
287
288 return {};
289 }
290
Connect(process_gdb_remote::GDBRemoteCommunicationClient & client)291 Status GDBRemoteCommunicationReplayServer::Connect(
292 process_gdb_remote::GDBRemoteCommunicationClient &client) {
293 repro::Loader *loader = repro::Reproducer::Instance().GetLoader();
294 if (!loader)
295 return Status("No loader provided.");
296
297 static std::unique_ptr<repro::MultiLoader<repro::GDBRemoteProvider>>
298 multi_loader = repro::MultiLoader<repro::GDBRemoteProvider>::Create(
299 repro::Reproducer::Instance().GetLoader());
300 if (!multi_loader)
301 return Status("No gdb remote provider found.");
302
303 llvm::Optional<std::string> history_file = multi_loader->GetNextFile();
304 if (!history_file)
305 return Status("No gdb remote packet log found.");
306
307 if (auto error = LoadReplayHistory(FileSpec(*history_file)))
308 return Status("Unable to load replay history");
309
310 if (auto error = GDBRemoteCommunication::ConnectLocally(client, *this))
311 return Status("Unable to connect to replay server");
312
313 return {};
314 }
315