]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / Process / gdb-remote / GDBRemoteCommunicationReplayServer.cpp
1 //===-- GDBRemoteCommunicationReplayServer.cpp ------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include <errno.h>
11
12 #include "lldb/Host/Config.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 GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer()
35     : GDBRemoteCommunication("gdb-remote.server",
36                              "gdb-remote.server.rx_packet"),
37       m_async_broadcaster(nullptr, "lldb.gdb-remote.server.async-broadcaster"),
38       m_async_listener_sp(
39           Listener::MakeListener("lldb.gdb-remote.server.async-listener")),
40       m_async_thread_state_mutex(), m_skip_acks(false) {
41   m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
42                                    "async thread continue");
43   m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
44                                    "async thread should exit");
45
46   const uint32_t async_event_mask =
47       eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit;
48   m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster,
49                                                async_event_mask);
50 }
51
52 GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() {
53   StopAsyncThread();
54 }
55
56 GDBRemoteCommunication::PacketResult
57 GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse(
58     Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
59   StringExtractorGDBRemote packet;
60   PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false);
61
62   if (packet_result != PacketResult::Success) {
63     if (!IsConnected()) {
64       error.SetErrorString("lost connection");
65       quit = true;
66     } else {
67       error.SetErrorString("timeout");
68     }
69     return packet_result;
70   }
71
72   m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
73
74   if (m_skip_acks) {
75     const StringExtractorGDBRemote::ServerPacketType packet_type =
76         packet.GetServerPacketType();
77     switch (packet_type) {
78     case StringExtractorGDBRemote::eServerPacketType_nack:
79     case StringExtractorGDBRemote::eServerPacketType_ack:
80       return PacketResult::Success;
81     default:
82       break;
83     }
84   } else if (packet.GetStringRef() == "QStartNoAckMode") {
85     m_skip_acks = true;
86     m_send_acks = false;
87   }
88
89   while (!m_packet_history.empty()) {
90     // Pop last packet from the history.
91     GDBRemoteCommunicationHistory::Entry entry = m_packet_history.back();
92     m_packet_history.pop_back();
93
94     // We only care about what we received from the server. Skip everything
95     // the client sent.
96     if (entry.type != GDBRemoteCommunicationHistory::ePacketTypeRecv)
97       continue;
98
99     return SendRawPacketNoLock(entry.packet.data, true);
100   }
101
102   quit = true;
103
104   return packet_result;
105 }
106
107 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(
108     std::vector<
109         lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry>)
110
111 llvm::Error
112 GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) {
113   auto error_or_file = MemoryBuffer::getFile(path.GetPath());
114   if (auto err = error_or_file.getError())
115     return errorCodeToError(err);
116
117   yaml::Input yin((*error_or_file)->getBuffer());
118   yin >> m_packet_history;
119
120   if (auto err = yin.error())
121     return errorCodeToError(err);
122
123   // We want to manipulate the vector like a stack so we need to reverse the
124   // order of the packets to have the oldest on at the back.
125   std::reverse(m_packet_history.begin(), m_packet_history.end());
126
127   return Error::success();
128 }
129
130 bool GDBRemoteCommunicationReplayServer::StartAsyncThread() {
131   std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
132   if (!m_async_thread.IsJoinable()) {
133     // Create a thread that watches our internal state and controls which
134     // events make it to clients (into the DCProcess event queue).
135     m_async_thread = ThreadLauncher::LaunchThread(
136         "<lldb.gdb-remote.server.async>",
137         GDBRemoteCommunicationReplayServer::AsyncThread, this, nullptr);
138   }
139
140   // Wait for handshake.
141   m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
142
143   return m_async_thread.IsJoinable();
144 }
145
146 void GDBRemoteCommunicationReplayServer::StopAsyncThread() {
147   std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
148
149   if (!m_async_thread.IsJoinable())
150     return;
151
152   // Request thread to stop.
153   m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit);
154
155   // Disconnect client.
156   Disconnect();
157
158   // Stop the thread.
159   m_async_thread.Join(nullptr);
160   m_async_thread.Reset();
161 }
162
163 void GDBRemoteCommunicationReplayServer::ReceivePacket(
164     GDBRemoteCommunicationReplayServer &server, bool &done) {
165   Status error;
166   bool interrupt;
167   auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1),
168                                                        error, interrupt, done);
169   if (packet_result != GDBRemoteCommunication::PacketResult::Success &&
170       packet_result !=
171           GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) {
172     done = true;
173   } else {
174     server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
175   }
176 }
177
178 thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) {
179   GDBRemoteCommunicationReplayServer *server =
180       (GDBRemoteCommunicationReplayServer *)arg;
181
182   EventSP event_sp;
183   bool done = false;
184
185   while (true) {
186     if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
187       const uint32_t event_type = event_sp->GetType();
188       if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) {
189         switch (event_type) {
190         case eBroadcastBitAsyncContinue:
191           ReceivePacket(*server, done);
192           if (done)
193             return {};
194           break;
195         case eBroadcastBitAsyncThreadShouldExit:
196         default:
197           return {};
198         }
199       }
200     }
201   }
202
203   return {};
204 }