mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-15 21:01:29 +00:00

Summary: These are general purpose "utility" classes, whose functionality is not debugger-specific in any way. As such, I believe they belong in the Utility module. This doesn't break any particular dependency (yet), but it reduces the number of Core dependencies across the board. Reviewers: zturner, jingham, teemperor, clayborg Subscribers: mgorny, lldb-commits Differential Revision: https://reviews.llvm.org/D55361 llvm-svn: 349157
205 lines
6.4 KiB
C++
205 lines
6.4 KiB
C++
//===-- GDBRemoteCommunicationReplayServer.cpp ------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <errno.h>
|
|
|
|
#include "lldb/Host/Config.h"
|
|
|
|
#include "GDBRemoteCommunicationReplayServer.h"
|
|
#include "ProcessGDBRemoteLog.h"
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
#include <cstring>
|
|
|
|
// Project includes
|
|
#include "lldb/Host/ThreadLauncher.h"
|
|
#include "lldb/Utility/ConstString.h"
|
|
#include "lldb/Utility/Event.h"
|
|
#include "lldb/Utility/FileSpec.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
#include "lldb/Utility/StringExtractorGDBRemote.h"
|
|
|
|
using namespace llvm;
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
using namespace lldb_private::process_gdb_remote;
|
|
|
|
GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer()
|
|
: GDBRemoteCommunication("gdb-remote.server",
|
|
"gdb-remote.server.rx_packet"),
|
|
m_async_broadcaster(nullptr, "lldb.gdb-remote.server.async-broadcaster"),
|
|
m_async_listener_sp(
|
|
Listener::MakeListener("lldb.gdb-remote.server.async-listener")),
|
|
m_async_thread_state_mutex(), m_skip_acks(false) {
|
|
m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue,
|
|
"async thread continue");
|
|
m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit,
|
|
"async thread should exit");
|
|
|
|
const uint32_t async_event_mask =
|
|
eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit;
|
|
m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster,
|
|
async_event_mask);
|
|
}
|
|
|
|
GDBRemoteCommunicationReplayServer::~GDBRemoteCommunicationReplayServer() {
|
|
StopAsyncThread();
|
|
}
|
|
|
|
GDBRemoteCommunication::PacketResult
|
|
GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse(
|
|
Timeout<std::micro> timeout, Status &error, bool &interrupt, bool &quit) {
|
|
StringExtractorGDBRemote packet;
|
|
PacketResult packet_result = WaitForPacketNoLock(packet, timeout, false);
|
|
|
|
if (packet_result != PacketResult::Success) {
|
|
if (!IsConnected()) {
|
|
error.SetErrorString("lost connection");
|
|
quit = true;
|
|
} else {
|
|
error.SetErrorString("timeout");
|
|
}
|
|
return packet_result;
|
|
}
|
|
|
|
m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
|
|
|
|
if (m_skip_acks) {
|
|
const StringExtractorGDBRemote::ServerPacketType packet_type =
|
|
packet.GetServerPacketType();
|
|
switch (packet_type) {
|
|
case StringExtractorGDBRemote::eServerPacketType_nack:
|
|
case StringExtractorGDBRemote::eServerPacketType_ack:
|
|
return PacketResult::Success;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (packet.GetStringRef() == "QStartNoAckMode") {
|
|
m_skip_acks = true;
|
|
m_send_acks = false;
|
|
}
|
|
|
|
while (!m_packet_history.empty()) {
|
|
// Pop last packet from the history.
|
|
GDBRemoteCommunicationHistory::Entry entry = m_packet_history.back();
|
|
m_packet_history.pop_back();
|
|
|
|
// We only care about what we received from the server. Skip everything
|
|
// the client sent.
|
|
if (entry.type != GDBRemoteCommunicationHistory::ePacketTypeRecv)
|
|
continue;
|
|
|
|
return SendRawPacketNoLock(entry.packet.data, true);
|
|
}
|
|
|
|
quit = true;
|
|
|
|
return packet_result;
|
|
}
|
|
|
|
LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(
|
|
std::vector<
|
|
lldb_private::process_gdb_remote::GDBRemoteCommunicationHistory::Entry>)
|
|
|
|
llvm::Error
|
|
GDBRemoteCommunicationReplayServer::LoadReplayHistory(const FileSpec &path) {
|
|
auto error_or_file = MemoryBuffer::getFile(path.GetPath());
|
|
if (auto err = error_or_file.getError())
|
|
return errorCodeToError(err);
|
|
|
|
yaml::Input yin((*error_or_file)->getBuffer());
|
|
yin >> m_packet_history;
|
|
|
|
if (auto err = yin.error())
|
|
return errorCodeToError(err);
|
|
|
|
// We want to manipulate the vector like a stack so we need to reverse the
|
|
// order of the packets to have the oldest on at the back.
|
|
std::reverse(m_packet_history.begin(), m_packet_history.end());
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
bool GDBRemoteCommunicationReplayServer::StartAsyncThread() {
|
|
std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
|
|
if (!m_async_thread.IsJoinable()) {
|
|
// Create a thread that watches our internal state and controls which
|
|
// events make it to clients (into the DCProcess event queue).
|
|
m_async_thread = ThreadLauncher::LaunchThread(
|
|
"<lldb.gdb-remote.server.async>",
|
|
GDBRemoteCommunicationReplayServer::AsyncThread, this, nullptr);
|
|
}
|
|
|
|
// Wait for handshake.
|
|
m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
|
|
|
|
return m_async_thread.IsJoinable();
|
|
}
|
|
|
|
void GDBRemoteCommunicationReplayServer::StopAsyncThread() {
|
|
std::lock_guard<std::recursive_mutex> guard(m_async_thread_state_mutex);
|
|
|
|
if (!m_async_thread.IsJoinable())
|
|
return;
|
|
|
|
// Request thread to stop.
|
|
m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit);
|
|
|
|
// Disconnect client.
|
|
Disconnect();
|
|
|
|
// Stop the thread.
|
|
m_async_thread.Join(nullptr);
|
|
m_async_thread.Reset();
|
|
}
|
|
|
|
void GDBRemoteCommunicationReplayServer::ReceivePacket(
|
|
GDBRemoteCommunicationReplayServer &server, bool &done) {
|
|
Status error;
|
|
bool interrupt;
|
|
auto packet_result = server.GetPacketAndSendResponse(std::chrono::seconds(1),
|
|
error, interrupt, done);
|
|
if (packet_result != GDBRemoteCommunication::PacketResult::Success &&
|
|
packet_result !=
|
|
GDBRemoteCommunication::PacketResult::ErrorReplyTimeout) {
|
|
done = true;
|
|
} else {
|
|
server.m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue);
|
|
}
|
|
}
|
|
|
|
thread_result_t GDBRemoteCommunicationReplayServer::AsyncThread(void *arg) {
|
|
GDBRemoteCommunicationReplayServer *server =
|
|
(GDBRemoteCommunicationReplayServer *)arg;
|
|
|
|
EventSP event_sp;
|
|
bool done = false;
|
|
|
|
while (true) {
|
|
if (server->m_async_listener_sp->GetEvent(event_sp, llvm::None)) {
|
|
const uint32_t event_type = event_sp->GetType();
|
|
if (event_sp->BroadcasterIs(&server->m_async_broadcaster)) {
|
|
switch (event_type) {
|
|
case eBroadcastBitAsyncContinue:
|
|
ReceivePacket(*server, done);
|
|
if (done)
|
|
return {};
|
|
break;
|
|
case eBroadcastBitAsyncThreadShouldExit:
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|