]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp
Move all sources from the llvm project into contrib/llvm-project.
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / source / Plugins / Process / gdb-remote / GDBRemoteCommunicationReplayServer.cpp
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
13 #include "GDBRemoteCommunicationReplayServer.h"
14 #include "ProcessGDBRemoteLog.h"
15
16 // C Includes
17 // C++ Includes
18 #include <cstring>
19
20 // Project includes
21 #include "lldb/Host/ThreadLauncher.h"
22 #include "lldb/Utility/ConstString.h"
23 #include "lldb/Utility/Event.h"
24 #include "lldb/Utility/FileSpec.h"
25 #include "lldb/Utility/StreamString.h"
26 #include "lldb/Utility/StringExtractorGDBRemote.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 /// Check if the given expected packet matches the actual packet.
34 static bool unexpected(llvm::StringRef expected, llvm::StringRef actual) {
35   // The 'expected' string contains the raw data, including the leading $ and
36   // trailing checksum. The 'actual' string contains only the packet's content.
37   if (expected.contains(actual))
38     return false;
39   // Contains a PID which might be different.
40   if (expected.contains("vAttach"))
41     return false;
42   // Contains a ascii-hex-path.
43   if (expected.contains("QSetSTD"))
44     return false;
45   // Contains environment values.
46   if (expected.contains("QEnvironment"))
47     return false;
48
49   return true;
50 }
51
52 /// Check if we should reply to the given packet.
53 static bool skip(llvm::StringRef data) {
54   assert(!data.empty() && "Empty packet?");
55
56   // We've already acknowledge the '+' packet so we're done here.
57   if (data == "+")
58     return true;
59
60   /// Don't 't reply to ^C. We need this because of stop reply packets, which
61   /// are only returned when the target halts. Reproducers synchronize these
62   /// 'asynchronous' replies, by recording them as a regular replies to the
63   /// previous packet (e.g. vCont). As a result, we should ignore real
64   /// asynchronous requests.
65   if (data.data()[0] == 0x03)
66     return true;
67
68   return false;
69 }
70
71 GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer()
72     : GDBRemoteCommunication("gdb-replay", "gdb-replay.rx_packet"),
73       m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"),
74       m_async_listener_sp(
75           Listener::MakeListener("lldb.gdb-replay.async-listener")),
76       m_async_thread_state_mutex(), m_skip_acks(false) {
77   m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
78                                    "async thread continue");
79   m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
80                                    "async thread should exit");
81
82   const uint32_t async_event_mask =
83       eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit;
84   m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster,
85                                                async_event_mask);
86 }
87
88 GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() {
89   StopAsyncThread();
90 }
91
92 GDBRemoteCommunication::PacketResult
93 GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse(
94     Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
95   std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
96
97   StringExtractorGDBRemote packet;
98   PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false);
99
100   if (packet_result != PacketResult::Success) {
101     if (!IsConnected()) {
102       error.SetErrorString("lost connection");
103       quit = true;
104     } else {
105       error.SetErrorString("timeout");
106     }
107     return packet_result;
108   }
109
110   m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
111
112   // Check if we should reply to this packet.
113   if (skip(packet.GetStringRef()))
114     return PacketResult::Success;
115
116   // This completes the handshake. Since m_send_acks was true, we can unset it
117   // already.
118   if (packet.GetStringRef() == "QStartNoAckMode")
119     m_send_acks = false;
120
121   // A QEnvironment packet is sent for every environment variable. If the
122   // number of environment variables is different during replay, the replies
123   // become out of sync.
124   if (packet.GetStringRef().find("QEnvironment") == 0)
125     return SendRawPacketNoLock("$OK#9a");
126
127   Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
128   while (!m_packet_history.empty()) {
129     // Pop last packet from the history.
130     GDBRemoteCommunicationHistory::Entry entry = m_packet_history.back();
131     m_packet_history.pop_back();
132
133     // We've handled the handshake implicitly before. Skip the packet and move
134     // on.
135     if (entry.packet.data == "+")
136       continue;
137
138     if (entry.type == GDBRemoteCommunicationHistory::ePacketTypeSend) {
139       if (unexpected(entry.packet.data, packet.GetStringRef())) {
140         LLDB_LOG(log,
141                  "GDBRemoteCommunicationReplayServer expected packet: '{0}'",
142                  entry.packet.data);
143         LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'",
144                  packet.GetStringRef());
145         assert(false && "Encountered unexpected packet during replay");
146         return PacketResult::ErrorSendFailed;
147       }
148
149       // Ignore QEnvironment packets as they're handled earlier.
150       if (entry.packet.data.find("QEnvironment") == 1) {
151         assert(m_packet_history.back().type ==
152                GDBRemoteCommunicationHistory::ePacketTypeRecv);
153         m_packet_history.pop_back();
154       }
155
156       continue;
157     }
158
159     if (entry.type == GDBRemoteCommunicationHistory::ePacketTypeInvalid) {
160       LLDB_LOG(
161           log,
162           "GDBRemoteCommunicationReplayServer skipped invalid packet: '{0}'",
163           packet.GetStringRef());
164       continue;
165     }
166
167     LLDB_LOG(log,
168              "GDBRemoteCommunicationReplayServer replied to '{0}' with '{1}'",
169              packet.GetStringRef(), entry.packet.data);
170     return SendRawPacketNoLock(entry.packet.data);
171   }
172
173   quit = true;
174
175   return packet_result;
176 }
177
178 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(
179     std::vector<
180         lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry>)
181
182 llvm::Error
183 GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) {
184   auto error_or_file = MemoryBuffer::getFile(path.GetPath());
185   if (auto err = error_or_file.getError())
186     return errorCodeToError(err);
187
188   yaml::Input yin((*error_or_file)->getBuffer());
189   yin >> m_packet_history;
190
191   if (auto err = yin.error())
192     return errorCodeToError(err);
193
194   // We want to manipulate the vector like a stack so we need to reverse the
195   // order of the packets to have the oldest on at the back.
196   std::reverse(m_packet_history.begin(), m_packet_history.end());
197
198   return Error::success();
199 }
200
201 bool GDBRemoteCommunicationReplayServer::StartAsyncThread() {
202   std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
203   if (!m_async_thread.IsJoinable()) {
204     // Create a thread that watches our internal state and controls which
205     // events make it to clients (into the DCProcess event queue).
206     llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread(
207         "<lldb.gdb-replay.async>",
208         GDBRemoteCommunicationReplayServer::AsyncThread, this);
209     if (!async_thread) {
210       LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST),
211                "failed to launch host thread: {}",
212                llvm::toString(async_thread.takeError()));
213       return false;
214     }
215     m_async_thread = *async_thread;
216   }
217
218   // Wait for handshake.
219   m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
220
221   return m_async_thread.IsJoinable();
222 }
223
224 void GDBRemoteCommunicationReplayServer::StopAsyncThread() {
225   std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
226
227   if (!m_async_thread.IsJoinable())
228     return;
229
230   // Request thread to stop.
231   m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit);
232
233   // Disconnect client.
234   Disconnect();
235
236   // Stop the thread.
237   m_async_thread.Join(nullptr);
238   m_async_thread.Reset();
239 }
240
241 void GDBRemoteCommunicationReplayServer::ReceivePacket(
242     GDBRemoteCommunicationReplayServer &server, bool &done) {
243   Status error;
244   bool interrupt;
245   auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1),
246                                                        error, interrupt, done);
247   if (packet_result != GDBRemoteCommunication::PacketResult::Success &&
248       packet_result !=
249           GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) {
250     done = true;
251   } else {
252     server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
253   }
254 }
255
256 thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) {
257   GDBRemoteCommunicationReplayServer *server =
258       (GDBRemoteCommunicationReplayServer *)arg;
259
260   EventSP event_sp;
261   bool done = false;
262
263   while (true) {
264     if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
265       const uint32_t event_type = event_sp->GetType();
266       if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) {
267         switch (event_type) {
268         case eBroadcastBitAsyncContinue:
269           ReceivePacket(*server, done);
270           if (done)
271             return {};
272           break;
273         case eBroadcastBitAsyncThreadShouldExit:
274         default:
275           return {};
276         }
277       }
278     }
279   }
280
281   return {};
282 }