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 
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.
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.
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 
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 
89 GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() {
90   StopAsyncThread();
91 }
92 
93 GDBRemoteCommunication::PacketResult
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     // 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 
186 llvm::Error
187 GDBRemoteCommunicationReplayServer::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 
205 bool 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 
228 void 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 
245 void 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 
260 thread_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