Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,40 @@
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
include_directories(${LIBXML2_INCLUDE_DIR})
endif()
set(LLDB_PLUGINS
lldbPluginProcessUtility
lldbPluginPlatformMacOSX
)
if(HAVE_LIBCOMPRESSION)
set(LIBCOMPRESSION compression)
endif()
add_lldb_library(lldbPluginProcessGDBRemote PLUGIN
GDBRemoteClientBase.cpp
GDBRemoteCommunication.cpp
GDBRemoteCommunicationClient.cpp
GDBRemoteCommunicationServer.cpp
GDBRemoteCommunicationServerCommon.cpp
GDBRemoteCommunicationServerLLGS.cpp
GDBRemoteCommunicationServerPlatform.cpp
GDBRemoteRegisterContext.cpp
ProcessGDBRemote.cpp
ProcessGDBRemoteLog.cpp
ThreadGDBRemote.cpp
LINK_LIBS
lldbBreakpoint
lldbCore
lldbDataFormatters
lldbHost
lldbInterpreter
lldbSymbol
lldbTarget
lldbUtility
${LLDB_PLUGINS}
${LIBCOMPRESSION}
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1,377 @@
//===-- GDBRemoteClientBase.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "GDBRemoteClientBase.h"
#include "llvm/ADT/StringExtras.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/LLDBAssert.h"
#include "ProcessGDBRemoteLog.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
using namespace std::chrono;
static const seconds kInterruptTimeout(5);
/////////////////////////
// GDBRemoteClientBase //
/////////////////////////
GDBRemoteClientBase::ContinueDelegate::~ContinueDelegate() = default;
GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name,
const char *listener_name)
: GDBRemoteCommunication(comm_name, listener_name), m_async_count(0),
m_is_running(false), m_should_stop(false) {}
StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse(
ContinueDelegate &delegate, const UnixSignals &signals,
llvm::StringRef payload, StringExtractorGDBRemote &response) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
response.Clear();
{
std::lock_guard<std::mutex> lock(m_mutex);
m_continue_packet = payload;
m_should_stop = false;
}
ContinueLock cont_lock(*this);
if (!cont_lock)
return eStateInvalid;
OnRunPacketSent(true);
for (;;) {
PacketResult read_result = ReadPacket(response, kInterruptTimeout, false);
switch (read_result) {
case PacketResult::ErrorReplyTimeout: {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_async_count == 0)
continue;
if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout)
return eStateInvalid;
break;
}
case PacketResult::Success:
break;
default:
if (log)
log->Printf("GDBRemoteClientBase::%s () ReadPacket(...) => false",
__FUNCTION__);
return eStateInvalid;
}
if (response.Empty())
return eStateInvalid;
const char stop_type = response.GetChar();
if (log)
log->Printf("GDBRemoteClientBase::%s () got packet: %s", __FUNCTION__,
response.GetStringRef().c_str());
switch (stop_type) {
case 'W':
case 'X':
return eStateExited;
case 'E':
// ERROR
return eStateInvalid;
default:
if (log)
log->Printf("GDBRemoteClientBase::%s () unrecognized async packet",
__FUNCTION__);
return eStateInvalid;
case 'O': {
std::string inferior_stdout;
response.GetHexByteString(inferior_stdout);
delegate.HandleAsyncStdout(inferior_stdout);
break;
}
case 'A':
delegate.HandleAsyncMisc(
llvm::StringRef(response.GetStringRef()).substr(1));
break;
case 'J':
delegate.HandleAsyncStructuredDataPacket(response.GetStringRef());
break;
case 'T':
case 'S':
// Do this with the continue lock held.
const bool should_stop = ShouldStop(signals, response);
response.SetFilePos(0);
// The packet we should resume with. In the future
// we should check our thread list and "do the right thing"
// for new threads that show up while we stop and run async
// packets. Setting the packet to 'c' to continue all threads
// is the right thing to do 99.99% of the time because if a
// thread was single stepping, and we sent an interrupt, we
// will notice above that we didn't stop due to an interrupt
// but stopped due to stepping and we would _not_ continue.
// This packet may get modified by the async actions (e.g. to send a
// signal).
m_continue_packet = 'c';
cont_lock.unlock();
delegate.HandleStopReply();
if (should_stop)
return eStateStopped;
switch (cont_lock.lock()) {
case ContinueLock::LockResult::Success:
break;
case ContinueLock::LockResult::Failed:
return eStateInvalid;
case ContinueLock::LockResult::Cancelled:
return eStateStopped;
}
OnRunPacketSent(false);
break;
}
}
}
bool GDBRemoteClientBase::SendAsyncSignal(int signo) {
Lock lock(*this, true);
if (!lock || !lock.DidInterrupt())
return false;
m_continue_packet = 'C';
m_continue_packet += llvm::hexdigit((signo / 16) % 16);
m_continue_packet += llvm::hexdigit(signo % 16);
return true;
}
bool GDBRemoteClientBase::Interrupt() {
Lock lock(*this, true);
if (!lock.DidInterrupt())
return false;
m_should_stop = true;
return true;
}
GDBRemoteCommunication::PacketResult
GDBRemoteClientBase::SendPacketAndWaitForResponse(
llvm::StringRef payload, StringExtractorGDBRemote &response,
bool send_async) {
Lock lock(*this, send_async);
if (!lock) {
if (Log *log =
ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS))
log->Printf("GDBRemoteClientBase::%s failed to get mutex, not sending "
"packet '%.*s' (send_async=%d)",
__FUNCTION__, int(payload.size()), payload.data(),
send_async);
return PacketResult::ErrorSendFailed;
}
return SendPacketAndWaitForResponseNoLock(payload, response);
}
GDBRemoteCommunication::PacketResult
GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock(
llvm::StringRef payload, StringExtractorGDBRemote &response) {
PacketResult packet_result = SendPacketNoLock(payload);
if (packet_result != PacketResult::Success)
return packet_result;
const size_t max_response_retries = 3;
for (size_t i = 0; i < max_response_retries; ++i) {
packet_result = ReadPacket(response, GetPacketTimeout(), true);
// Make sure we received a response
if (packet_result != PacketResult::Success)
return packet_result;
// Make sure our response is valid for the payload that was sent
if (response.ValidateResponse())
return packet_result;
// Response says it wasn't valid
Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS);
if (log)
log->Printf(
"error: packet with payload \"%.*s\" got invalid response \"%s\": %s",
int(payload.size()), payload.data(), response.GetStringRef().c_str(),
(i == (max_response_retries - 1))
? "using invalid response and giving up"
: "ignoring response and waiting for another");
}
return packet_result;
}
bool GDBRemoteClientBase::SendvContPacket(llvm::StringRef payload,
StringExtractorGDBRemote &response) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
if (log)
log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
// we want to lock down packet sending while we continue
Lock lock(*this, true);
if (log)
log->Printf(
"GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s",
__FUNCTION__, int(payload.size()), payload.data());
if (SendPacketNoLock(payload) != PacketResult::Success)
return false;
OnRunPacketSent(true);
// wait for the response to the vCont
if (ReadPacket(response, llvm::None, false) == PacketResult::Success) {
if (response.IsOKResponse())
return true;
}
return false;
}
bool GDBRemoteClientBase::ShouldStop(const UnixSignals &signals,
StringExtractorGDBRemote &response) {
std::lock_guard<std::mutex> lock(m_mutex);
if (m_async_count == 0)
return true; // We were not interrupted. The process stopped on its own.
// Older debugserver stubs (before April 2016) can return two
// stop-reply packets in response to a ^C packet.
// Additionally, all debugservers still return two stop replies if
// the inferior stops due to some other reason before the remote
// stub manages to interrupt it. We need to wait for this
// additional packet to make sure the packet sequence does not get
// skewed.
StringExtractorGDBRemote extra_stop_reply_packet;
ReadPacket(extra_stop_reply_packet, milliseconds(100), false);
// Interrupting is typically done using SIGSTOP or SIGINT, so if
// the process stops with some other signal, we definitely want to
// stop.
const uint8_t signo = response.GetHexU8(UINT8_MAX);
if (signo != signals.GetSignalNumberFromName("SIGSTOP") &&
signo != signals.GetSignalNumberFromName("SIGINT"))
return true;
// We probably only stopped to perform some async processing, so continue
// after that is done.
// TODO: This is not 100% correct, as the process may have been stopped with
// SIGINT or SIGSTOP that was not caused by us (e.g. raise(SIGINT)). This will
// normally cause a stop, but if it's done concurrently with a async
// interrupt, that stop will get eaten (llvm.org/pr20231).
return false;
}
void GDBRemoteClientBase::OnRunPacketSent(bool first) {
if (first)
BroadcastEvent(eBroadcastBitRunPacketSent, NULL);
}
///////////////////////////////////////
// GDBRemoteClientBase::ContinueLock //
///////////////////////////////////////
GDBRemoteClientBase::ContinueLock::ContinueLock(GDBRemoteClientBase &comm)
: m_comm(comm), m_acquired(false) {
lock();
}
GDBRemoteClientBase::ContinueLock::~ContinueLock() {
if (m_acquired)
unlock();
}
void GDBRemoteClientBase::ContinueLock::unlock() {
lldbassert(m_acquired);
{
std::unique_lock<std::mutex> lock(m_comm.m_mutex);
m_comm.m_is_running = false;
}
m_comm.m_cv.notify_all();
m_acquired = false;
}
GDBRemoteClientBase::ContinueLock::LockResult
GDBRemoteClientBase::ContinueLock::lock() {
Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS);
if (log)
log->Printf("GDBRemoteClientBase::ContinueLock::%s() resuming with %s",
__FUNCTION__, m_comm.m_continue_packet.c_str());
lldbassert(!m_acquired);
std::unique_lock<std::mutex> lock(m_comm.m_mutex);
m_comm.m_cv.wait(lock, [this] { return m_comm.m_async_count == 0; });
if (m_comm.m_should_stop) {
m_comm.m_should_stop = false;
if (log)
log->Printf("GDBRemoteClientBase::ContinueLock::%s() cancelled",
__FUNCTION__);
return LockResult::Cancelled;
}
if (m_comm.SendPacketNoLock(m_comm.m_continue_packet) !=
PacketResult::Success)
return LockResult::Failed;
lldbassert(!m_comm.m_is_running);
m_comm.m_is_running = true;
m_acquired = true;
return LockResult::Success;
}
///////////////////////////////
// GDBRemoteClientBase::Lock //
///////////////////////////////
GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt)
: m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm),
m_acquired(false), m_did_interrupt(false) {
SyncWithContinueThread(interrupt);
if (m_acquired)
m_async_lock.lock();
}
void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
std::unique_lock<std::mutex> lock(m_comm.m_mutex);
if (m_comm.m_is_running && !interrupt)
return; // We were asked to avoid interrupting the sender. Lock is not
// acquired.
++m_comm.m_async_count;
if (m_comm.m_is_running) {
if (m_comm.m_async_count == 1) {
// The sender has sent the continue packet and we are the first async
// packet. Let's interrupt it.
const char ctrl_c = '\x03';
ConnectionStatus status = eConnectionStatusSuccess;
size_t bytes_written = m_comm.Write(&ctrl_c, 1, status, NULL);
if (bytes_written == 0) {
--m_comm.m_async_count;
if (log)
log->Printf("GDBRemoteClientBase::Lock::Lock failed to send "
"interrupt packet");
return;
}
if (log)
log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03");
m_comm.m_interrupt_time = steady_clock::now();
}
m_comm.m_cv.wait(lock, [this] { return m_comm.m_is_running == false; });
m_did_interrupt = true;
}
m_acquired = true;
}
GDBRemoteClientBase::Lock::~Lock() {
if (!m_acquired)
return;
{
std::unique_lock<std::mutex> lock(m_comm.m_mutex);
--m_comm.m_async_count;
}
m_comm.m_cv.notify_one();
}

View File

@@ -0,0 +1,144 @@
//===-- GDBRemoteClientBase.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GDBRemoteClientBase_h_
#define liblldb_GDBRemoteClientBase_h_
#include "GDBRemoteCommunication.h"
#include <condition_variable>
namespace lldb_private {
namespace process_gdb_remote {
class GDBRemoteClientBase : public GDBRemoteCommunication {
public:
struct ContinueDelegate {
virtual ~ContinueDelegate();
virtual void HandleAsyncStdout(llvm::StringRef out) = 0;
virtual void HandleAsyncMisc(llvm::StringRef data) = 0;
virtual void HandleStopReply() = 0;
// =========================================================================
/// Process asynchronously-received structured data.
///
/// @param[in] data
/// The complete data packet, expected to start with JSON-async.
// =========================================================================
virtual void HandleAsyncStructuredDataPacket(llvm::StringRef data) = 0;
};
GDBRemoteClientBase(const char *comm_name, const char *listener_name);
bool SendAsyncSignal(int signo);
bool Interrupt();
lldb::StateType SendContinuePacketAndWaitForResponse(
ContinueDelegate &delegate, const UnixSignals &signals,
llvm::StringRef payload, StringExtractorGDBRemote &response);
PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload,
StringExtractorGDBRemote &response,
bool send_async);
bool SendvContPacket(llvm::StringRef payload,
StringExtractorGDBRemote &response);
class Lock {
public:
Lock(GDBRemoteClientBase &comm, bool interrupt);
~Lock();
explicit operator bool() { return m_acquired; }
// Whether we had to interrupt the continue thread to acquire the
// connection.
bool DidInterrupt() const { return m_did_interrupt; }
private:
std::unique_lock<std::recursive_mutex> m_async_lock;
GDBRemoteClientBase &m_comm;
bool m_acquired;
bool m_did_interrupt;
void SyncWithContinueThread(bool interrupt);
};
protected:
PacketResult
SendPacketAndWaitForResponseNoLock(llvm::StringRef payload,
StringExtractorGDBRemote &response);
virtual void OnRunPacketSent(bool first);
private:
// Variables handling synchronization between the Continue thread and any
// other threads
// wishing to send packets over the connection. Either the continue thread has
// control over
// the connection (m_is_running == true) or the connection is free for an
// arbitrary number of
// other senders to take which indicate their interest by incrementing
// m_async_count.
// Semantics of individual states:
// - m_continue_packet == false, m_async_count == 0: connection is free
// - m_continue_packet == true, m_async_count == 0: only continue thread is
// present
// - m_continue_packet == true, m_async_count > 0: continue thread has
// control, async threads
// should interrupt it and wait for it to set m_continue_packet to false
// - m_continue_packet == false, m_async_count > 0: async threads have
// control, continue
// thread needs to wait for them to finish (m_async_count goes down to 0).
std::mutex m_mutex;
std::condition_variable m_cv;
// Packet with which to resume after an async interrupt. Can be changed by an
// async thread
// e.g. to inject a signal.
std::string m_continue_packet;
// When was the interrupt packet sent. Used to make sure we time out if the
// stub does not
// respond to interrupt requests.
std::chrono::time_point<std::chrono::steady_clock> m_interrupt_time;
uint32_t m_async_count;
bool m_is_running;
bool m_should_stop; // Whether we should resume after a stop.
// end of continue thread synchronization block
// This handles the synchronization between individual async threads. For now
// they just use a
// simple mutex.
std::recursive_mutex m_async_mutex;
bool ShouldStop(const UnixSignals &signals,
StringExtractorGDBRemote &response);
class ContinueLock {
public:
enum class LockResult { Success, Cancelled, Failed };
explicit ContinueLock(GDBRemoteClientBase &comm);
~ContinueLock();
explicit operator bool() { return m_acquired; }
LockResult lock();
void unlock();
private:
GDBRemoteClientBase &m_comm;
bool m_acquired;
};
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // liblldb_GDBRemoteCommunicationClient_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,303 @@
//===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GDBRemoteCommunication_h_
#define liblldb_GDBRemoteCommunication_h_
// C Includes
// C++ Includes
#include <condition_variable>
#include <mutex>
#include <queue>
#include <string>
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Communication.h"
#include "lldb/Core/Listener.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/Predicate.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/lldb-public.h"
#include "Utility/StringExtractorGDBRemote.h"
namespace lldb_private {
namespace process_gdb_remote {
typedef enum {
eStoppointInvalid = -1,
eBreakpointSoftware = 0,
eBreakpointHardware,
eWatchpointWrite,
eWatchpointRead,
eWatchpointReadWrite
} GDBStoppointType;
enum class CompressionType {
None = 0, // no compression
ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's
// libcompression
LZFSE, // an Apple compression scheme, requires Apple's libcompression
LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with
// https://code.google.com/p/lz4/
LZMA, // Lempel–Ziv–Markov chain algorithm
};
class ProcessGDBRemote;
class GDBRemoteCommunication : public Communication {
public:
enum {
eBroadcastBitRunPacketSent = kLoUserBroadcastBit,
eBroadcastBitGdbReadThreadGotNotify =
kLoUserBroadcastBit << 1 // Sent when we received a notify packet.
};
enum class PacketType { Invalid = 0, Standard, Notify };
enum class PacketResult {
Success = 0, // Success
ErrorSendFailed, // Status sending the packet
ErrorSendAck, // Didn't get an ack back after sending a packet
ErrorReplyFailed, // Status getting the reply
ErrorReplyTimeout, // Timed out waiting for reply
ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that
// was sent
ErrorReplyAck, // Sending reply ack failed
ErrorDisconnected, // We were disconnected
ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet
// request
};
// Class to change the timeout for a given scope and restore it to the
// original value when the
// created ScopedTimeout object got out of scope
class ScopedTimeout {
public:
ScopedTimeout(GDBRemoteCommunication &gdb_comm,
std::chrono::seconds timeout);
~ScopedTimeout();
private:
GDBRemoteCommunication &m_gdb_comm;
std::chrono::seconds m_saved_timeout;
// Don't ever reduce the timeout for a packet, only increase it. If the
// requested timeout if less than the current timeout, we don't set it
// and won't need to restore it.
bool m_timeout_modified;
};
GDBRemoteCommunication(const char *comm_name, const char *listener_name);
~GDBRemoteCommunication() override;
PacketResult GetAck();
size_t SendAck();
size_t SendNack();
char CalculcateChecksum(llvm::StringRef payload);
PacketType CheckForPacket(const uint8_t *src, size_t src_len,
StringExtractorGDBRemote &packet);
bool GetSendAcks() { return m_send_acks; }
//------------------------------------------------------------------
// Set the global packet timeout.
//
// For clients, this is the timeout that gets used when sending
// packets and waiting for responses. For servers, this is used when waiting
// for ACKs.
//------------------------------------------------------------------
std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) {
const auto old_packet_timeout = m_packet_timeout;
m_packet_timeout = packet_timeout;
return old_packet_timeout;
}
std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; }
//------------------------------------------------------------------
// Start a debugserver instance on the current host using the
// supplied connection URL.
//------------------------------------------------------------------
Status StartDebugserverProcess(
const char *url,
Platform *platform, // If non nullptr, then check with the platform for
// the GDB server binary if it can't be located
ProcessLaunchInfo &launch_info, uint16_t *port, const Args *inferior_args,
int pass_comm_fd); // Communication file descriptor to pass during
// fork/exec to avoid having to connect/accept
void DumpHistory(Stream &strm);
protected:
class History {
public:
enum PacketType {
ePacketTypeInvalid = 0,
ePacketTypeSend,
ePacketTypeRecv
};
struct Entry {
Entry()
: packet(), type(ePacketTypeInvalid), bytes_transmitted(0),
packet_idx(0), tid(LLDB_INVALID_THREAD_ID) {}
void Clear() {
packet.clear();
type = ePacketTypeInvalid;
bytes_transmitted = 0;
packet_idx = 0;
tid = LLDB_INVALID_THREAD_ID;
}
std::string packet;
PacketType type;
uint32_t bytes_transmitted;
uint32_t packet_idx;
lldb::tid_t tid;
};
History(uint32_t size);
~History();
// For single char packets for ack, nack and /x03
void AddPacket(char packet_char, PacketType type,
uint32_t bytes_transmitted);
void AddPacket(const std::string &src, uint32_t src_len, PacketType type,
uint32_t bytes_transmitted);
void Dump(Stream &strm) const;
void Dump(Log *log) const;
bool DidDumpToLog() const { return m_dumped_to_log; }
protected:
uint32_t GetFirstSavedPacketIndex() const {
if (m_total_packet_count < m_packets.size())
return 0;
else
return m_curr_idx + 1;
}
uint32_t GetNumPacketsInHistory() const {
if (m_total_packet_count < m_packets.size())
return m_total_packet_count;
else
return (uint32_t)m_packets.size();
}
uint32_t GetNextIndex() {
++m_total_packet_count;
const uint32_t idx = m_curr_idx;
m_curr_idx = NormalizeIndex(idx + 1);
return idx;
}
uint32_t NormalizeIndex(uint32_t i) const { return i % m_packets.size(); }
std::vector<Entry> m_packets;
uint32_t m_curr_idx;
uint32_t m_total_packet_count;
mutable bool m_dumped_to_log;
};
std::chrono::seconds m_packet_timeout;
uint32_t m_echo_number;
LazyBool m_supports_qEcho;
History m_history;
bool m_send_acks;
bool m_is_platform; // Set to true if this class represents a platform,
// false if this class represents a debug session for
// a single process
CompressionType m_compression_type;
PacketResult SendPacketNoLock(llvm::StringRef payload);
PacketResult ReadPacket(StringExtractorGDBRemote &response,
Timeout<std::micro> timeout, bool sync_on_timeout);
// Pop a packet from the queue in a thread safe manner
PacketResult PopPacketFromQueue(StringExtractorGDBRemote &response,
Timeout<std::micro> timeout);
PacketResult WaitForPacketNoLock(StringExtractorGDBRemote &response,
Timeout<std::micro> timeout,
bool sync_on_timeout);
bool CompressionIsEnabled() {
return m_compression_type != CompressionType::None;
}
// If compression is enabled, decompress the packet in m_bytes and update
// m_bytes with the uncompressed version.
// Returns 'true' packet was decompressed and m_bytes is the now-decompressed
// text.
// Returns 'false' if unable to decompress or if the checksum was invalid.
//
// NB: Once the packet has been decompressed, checksum cannot be computed
// based
// on m_bytes. The checksum was for the compressed packet.
bool DecompressPacket();
Status StartListenThread(const char *hostname = "127.0.0.1",
uint16_t port = 0);
bool JoinListenThread();
static lldb::thread_result_t ListenThread(lldb::thread_arg_t arg);
// GDB-Remote read thread
// . this thread constantly tries to read from the communication
// class and stores all packets received in a queue. The usual
// threads read requests simply pop packets off the queue in the
// usual order.
// This setup allows us to intercept and handle async packets, such
// as the notify packet.
// This method is defined as part of communication.h
// when the read thread gets any bytes it will pass them on to this function
void AppendBytesToCache(const uint8_t *bytes, size_t len, bool broadcast,
lldb::ConnectionStatus status) override;
private:
std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue
std::mutex m_packet_queue_mutex; // Mutex for accessing queue
std::condition_variable
m_condition_queue_not_empty; // Condition variable to wait for packets
HostThread m_listen_thread;
std::string m_listen_url;
DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunication);
};
} // namespace process_gdb_remote
} // namespace lldb_private
namespace llvm {
template <>
struct format_provider<
lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult> {
static void format(const lldb_private::process_gdb_remote::
GDBRemoteCommunication::PacketResult &state,
raw_ostream &Stream, StringRef Style);
};
} // namespace llvm
#endif // liblldb_GDBRemoteCommunication_h_

View File

@@ -0,0 +1 @@
867f57c475cec7efd8023f5a78a9cb77783a5a15

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,144 @@
//===-- GDBRemoteCommunicationServer.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 "GDBRemoteCommunicationServer.h"
// C Includes
// C++ Includes
#include <cstring>
// Project includes
#include "ProcessGDBRemoteLog.h"
#include "Utility/StringExtractorGDBRemote.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(
const char *comm_name, const char *listener_name)
: GDBRemoteCommunication(comm_name, listener_name), m_exit_now(false) {
RegisterPacketHandler(
StringExtractorGDBRemote::eServerPacketType_QEnableErrorStrings,
[this](StringExtractorGDBRemote packet, Status &error, bool &interrupt,
bool &quit) { return this->Handle_QErrorStringEnable(packet); });
}
GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() {}
void GDBRemoteCommunicationServer::RegisterPacketHandler(
StringExtractorGDBRemote::ServerPacketType packet_type,
PacketHandler handler) {
m_packet_handlers[packet_type] = std::move(handler);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::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) {
const StringExtractorGDBRemote::ServerPacketType packet_type =
packet.GetServerPacketType();
switch (packet_type) {
case StringExtractorGDBRemote::eServerPacketType_nack:
case StringExtractorGDBRemote::eServerPacketType_ack:
break;
case StringExtractorGDBRemote::eServerPacketType_invalid:
error.SetErrorString("invalid packet");
quit = true;
break;
case StringExtractorGDBRemote::eServerPacketType_unimplemented:
packet_result = SendUnimplementedResponse(packet.GetStringRef().c_str());
break;
default:
auto handler_it = m_packet_handlers.find(packet_type);
if (handler_it == m_packet_handlers.end())
packet_result =
SendUnimplementedResponse(packet.GetStringRef().c_str());
else
packet_result = handler_it->second(packet, error, interrupt, quit);
break;
}
} else {
if (!IsConnected()) {
error.SetErrorString("lost connection");
quit = true;
} else {
error.SetErrorString("timeout");
}
}
// Check if anything occurred that would force us to want to exit.
if (m_exit_now)
quit = true;
return packet_result;
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendUnimplementedResponse(const char *) {
// TODO: Log the packet we aren't handling...
return SendPacketNoLock("");
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendErrorResponse(uint8_t err) {
char packet[16];
int packet_len = ::snprintf(packet, sizeof(packet), "E%2.2x", err);
assert(packet_len < (int)sizeof(packet));
return SendPacketNoLock(llvm::StringRef(packet, packet_len));
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) {
if (m_send_error_strings) {
lldb_private::StreamString packet;
packet.Printf("E%2.2x;", static_cast<uint8_t>(error.GetError()));
packet.PutCStringAsRawHex8(error.AsCString());
return SendPacketNoLock(packet.GetString());
} else
return SendErrorResponse(error.GetError());
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::Handle_QErrorStringEnable(
StringExtractorGDBRemote &packet) {
m_send_error_strings = true;
return SendOKResponse();
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendIllFormedResponse(
const StringExtractorGDBRemote &failed_packet, const char *message) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
if (log)
log->Printf("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)",
__FUNCTION__, failed_packet.GetStringRef().c_str(),
message ? message : "");
return SendErrorResponse(0x03);
}
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendOKResponse() {
return SendPacketNoLock("OK");
}
bool GDBRemoteCommunicationServer::HandshakeWithClient() {
return GetAck() == PacketResult::Success;
}

View File

@@ -0,0 +1,83 @@
//===-- GDBRemoteCommunicationServer.h --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GDBRemoteCommunicationServer_h_
#define liblldb_GDBRemoteCommunicationServer_h_
// C Includes
// C++ Includes
#include <functional>
#include <map>
// Other libraries and framework includes
// Project includes
#include "GDBRemoteCommunication.h"
#include "lldb/lldb-private-forward.h"
class StringExtractorGDBRemote;
namespace lldb_private {
namespace process_gdb_remote {
class ProcessGDBRemote;
class GDBRemoteCommunicationServer : public GDBRemoteCommunication {
public:
using PortMap = std::map<uint16_t, lldb::pid_t>;
using PacketHandler =
std::function<PacketResult(StringExtractorGDBRemote &packet,
Status &error, bool &interrupt, bool &quit)>;
GDBRemoteCommunicationServer(const char *comm_name,
const char *listener_name);
~GDBRemoteCommunicationServer() override;
void
RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type,
PacketHandler handler);
PacketResult GetPacketAndSendResponse(Timeout<std::micro> timeout,
Status &error, bool &interrupt,
bool &quit);
// After connecting, do a little handshake with the client to make sure
// we are at least communicating
bool HandshakeWithClient();
protected:
std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler>
m_packet_handlers;
bool m_exit_now; // use in asynchronous handling to indicate process should
// exit.
bool m_send_error_strings; // If the client enables this then
// we will send error strings as well.
PacketResult Handle_QErrorStringEnable(StringExtractorGDBRemote &packet);
PacketResult SendErrorResponse(const Status &error);
PacketResult SendUnimplementedResponse(const char *packet);
PacketResult SendErrorResponse(uint8_t error);
PacketResult SendIllFormedResponse(const StringExtractorGDBRemote &packet,
const char *error_message);
PacketResult SendOKResponse();
private:
DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServer);
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // liblldb_GDBRemoteCommunicationServer_h_

View File

@@ -0,0 +1,162 @@
//===-- GDBRemoteCommunicationServerCommon.h --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GDBRemoteCommunicationServerCommon_h_
#define liblldb_GDBRemoteCommunicationServerCommon_h_
// C Includes
// C++ Includes
#include <string>
// Other libraries and framework includes
// Project includes
#include "lldb/Target/Process.h"
#include "lldb/lldb-private-forward.h"
#include "GDBRemoteCommunicationServer.h"
#include "GDBRemoteCommunicationServerCommon.h"
class StringExtractorGDBRemote;
namespace lldb_private {
namespace process_gdb_remote {
class ProcessGDBRemote;
class GDBRemoteCommunicationServerCommon : public GDBRemoteCommunicationServer {
public:
GDBRemoteCommunicationServerCommon(const char *comm_name,
const char *listener_name);
~GDBRemoteCommunicationServerCommon() override;
protected:
ProcessLaunchInfo m_process_launch_info;
Status m_process_launch_error;
ProcessInstanceInfoList m_proc_infos;
uint32_t m_proc_infos_index;
bool m_thread_suffix_supported;
bool m_list_threads_in_stop_reply;
PacketResult Handle_A(StringExtractorGDBRemote &packet);
PacketResult Handle_qHostInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qProcessInfoPID(StringExtractorGDBRemote &packet);
PacketResult Handle_qfProcessInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qsProcessInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qUserName(StringExtractorGDBRemote &packet);
PacketResult Handle_qGroupName(StringExtractorGDBRemote &packet);
PacketResult Handle_qSpeedTest(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_Open(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_Close(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_pRead(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_pWrite(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_Size(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_Mode(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_Exists(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_symlink(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_unlink(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_Stat(StringExtractorGDBRemote &packet);
PacketResult Handle_vFile_MD5(StringExtractorGDBRemote &packet);
PacketResult Handle_qEcho(StringExtractorGDBRemote &packet);
PacketResult Handle_qModuleInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_jModulesInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qPlatform_shell(StringExtractorGDBRemote &packet);
PacketResult Handle_qPlatform_mkdir(StringExtractorGDBRemote &packet);
PacketResult Handle_qPlatform_chmod(StringExtractorGDBRemote &packet);
PacketResult Handle_qSupported(StringExtractorGDBRemote &packet);
PacketResult Handle_QThreadSuffixSupported(StringExtractorGDBRemote &packet);
PacketResult Handle_QListThreadsInStopReply(StringExtractorGDBRemote &packet);
PacketResult Handle_QSetDetachOnError(StringExtractorGDBRemote &packet);
PacketResult Handle_QStartNoAckMode(StringExtractorGDBRemote &packet);
PacketResult Handle_QSetSTDIN(StringExtractorGDBRemote &packet);
PacketResult Handle_QSetSTDOUT(StringExtractorGDBRemote &packet);
PacketResult Handle_QSetSTDERR(StringExtractorGDBRemote &packet);
PacketResult Handle_qLaunchSuccess(StringExtractorGDBRemote &packet);
PacketResult Handle_QEnvironment(StringExtractorGDBRemote &packet);
PacketResult Handle_QEnvironmentHexEncoded(StringExtractorGDBRemote &packet);
PacketResult Handle_QLaunchArch(StringExtractorGDBRemote &packet);
static void CreateProcessInfoResponse(const ProcessInstanceInfo &proc_info,
StreamString &response);
static void CreateProcessInfoResponse_DebugServerStyle(
const ProcessInstanceInfo &proc_info, StreamString &response);
template <typename T>
void RegisterMemberFunctionHandler(
StringExtractorGDBRemote::ServerPacketType packet_type,
PacketResult (T::*handler)(StringExtractorGDBRemote &packet)) {
RegisterPacketHandler(packet_type,
[this, handler](StringExtractorGDBRemote packet,
Status &error, bool &interrupt,
bool &quit) {
return (static_cast<T *>(this)->*handler)(packet);
});
}
//------------------------------------------------------------------
/// Launch a process with the current launch settings.
///
/// This method supports running an lldb-gdbserver or similar
/// server in a situation where the startup code has been provided
/// with all the information for a child process to be launched.
///
/// @return
/// An Status object indicating the success or failure of the
/// launch.
//------------------------------------------------------------------
virtual Status LaunchProcess() = 0;
virtual FileSpec FindModuleFile(const std::string &module_path,
const ArchSpec &arch);
private:
ModuleSpec GetModuleInfo(llvm::StringRef module_path, llvm::StringRef triple);
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // liblldb_GDBRemoteCommunicationServerCommon_h_

View File

@@ -0,0 +1 @@
32741c2404e22ba899095a1b103ce7ed3c5576e7

View File

@@ -0,0 +1,239 @@
//===-- GDBRemoteCommunicationServerLLGS.h ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GDBRemoteCommunicationServerLLGS_h_
#define liblldb_GDBRemoteCommunicationServerLLGS_h_
// C Includes
// C++ Includes
#include <mutex>
#include <unordered_map>
// Other libraries and framework includes
#include "lldb/Core/Communication.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/lldb-private-forward.h"
// Project includes
#include "GDBRemoteCommunicationServerCommon.h"
class StringExtractorGDBRemote;
namespace lldb_private {
namespace process_gdb_remote {
class ProcessGDBRemote;
class GDBRemoteCommunicationServerLLGS
: public GDBRemoteCommunicationServerCommon,
public NativeProcessProtocol::NativeDelegate {
public:
//------------------------------------------------------------------
// Constructors and Destructors
//------------------------------------------------------------------
GDBRemoteCommunicationServerLLGS(
MainLoop &mainloop,
const NativeProcessProtocol::Factory &process_factory);
void SetLaunchInfo(const ProcessLaunchInfo &info);
//------------------------------------------------------------------
/// Launch a process with the current launch settings.
///
/// This method supports running an lldb-gdbserver or similar
/// server in a situation where the startup code has been provided
/// with all the information for a child process to be launched.
///
/// @return
/// An Status object indicating the success or failure of the
/// launch.
//------------------------------------------------------------------
Status LaunchProcess() override;
//------------------------------------------------------------------
/// Attach to a process.
///
/// This method supports attaching llgs to a process accessible via the
/// configured Platform.
///
/// @return
/// An Status object indicating the success or failure of the
/// attach operation.
//------------------------------------------------------------------
Status AttachToProcess(lldb::pid_t pid);
//------------------------------------------------------------------
// NativeProcessProtocol::NativeDelegate overrides
//------------------------------------------------------------------
void InitializeDelegate(NativeProcessProtocol *process) override;
void ProcessStateChanged(NativeProcessProtocol *process,
lldb::StateType state) override;
void DidExec(NativeProcessProtocol *process) override;
Status InitializeConnection(std::unique_ptr<Connection> &&connection);
protected:
MainLoop &m_mainloop;
MainLoop::ReadHandleUP m_network_handle_up;
const NativeProcessProtocol::Factory &m_process_factory;
lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID;
lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID;
std::recursive_mutex m_debugged_process_mutex;
std::unique_ptr<NativeProcessProtocol> m_debugged_process_up;
Communication m_stdio_communication;
MainLoop::ReadHandleUP m_stdio_handle_up;
lldb::StateType m_inferior_prev_state = lldb::StateType::eStateInvalid;
std::unique_ptr<llvm::MemoryBuffer> m_active_auxv_buffer_up;
std::mutex m_saved_registers_mutex;
std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
uint32_t m_next_saved_registers_id = 1;
bool m_handshake_completed = false;
PacketResult SendONotification(const char *buffer, uint32_t len);
PacketResult SendWResponse(NativeProcessProtocol *process);
PacketResult SendStopReplyPacketForThread(lldb::tid_t tid);
PacketResult SendStopReasonForState(lldb::StateType process_state);
PacketResult Handle_k(StringExtractorGDBRemote &packet);
PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qC(StringExtractorGDBRemote &packet);
PacketResult Handle_QSetDisableASLR(StringExtractorGDBRemote &packet);
PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet);
PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
PacketResult Handle_C(StringExtractorGDBRemote &packet);
PacketResult Handle_c(StringExtractorGDBRemote &packet);
PacketResult Handle_vCont(StringExtractorGDBRemote &packet);
PacketResult Handle_vCont_actions(StringExtractorGDBRemote &packet);
PacketResult Handle_stop_reason(StringExtractorGDBRemote &packet);
PacketResult Handle_qRegisterInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qfThreadInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qsThreadInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_p(StringExtractorGDBRemote &packet);
PacketResult Handle_P(StringExtractorGDBRemote &packet);
PacketResult Handle_H(StringExtractorGDBRemote &packet);
PacketResult Handle_I(StringExtractorGDBRemote &packet);
PacketResult Handle_interrupt(StringExtractorGDBRemote &packet);
// Handles $m and $x packets.
PacketResult Handle_memory_read(StringExtractorGDBRemote &packet);
PacketResult Handle_M(StringExtractorGDBRemote &packet);
PacketResult
Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet);
PacketResult Handle_qMemoryRegionInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_Z(StringExtractorGDBRemote &packet);
PacketResult Handle_z(StringExtractorGDBRemote &packet);
PacketResult Handle_s(StringExtractorGDBRemote &packet);
PacketResult Handle_qXfer_auxv_read(StringExtractorGDBRemote &packet);
PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_jTraceStart(StringExtractorGDBRemote &packet);
PacketResult Handle_jTraceRead(StringExtractorGDBRemote &packet);
PacketResult Handle_jTraceStop(StringExtractorGDBRemote &packet);
PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
PacketResult Handle_D(StringExtractorGDBRemote &packet);
PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_jThreadsInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qWatchpointSupportInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qFileLoadAddress(StringExtractorGDBRemote &packet);
PacketResult Handle_QPassSignals(StringExtractorGDBRemote &packet);
void SetCurrentThreadID(lldb::tid_t tid);
lldb::tid_t GetCurrentThreadID() const;
void SetContinueThreadID(lldb::tid_t tid);
lldb::tid_t GetContinueThreadID() const { return m_continue_tid; }
Status SetSTDIOFileDescriptor(int fd);
FileSpec FindModuleFile(const std::string &module_path,
const ArchSpec &arch) override;
private:
void HandleInferiorState_Exited(NativeProcessProtocol *process);
void HandleInferiorState_Stopped(NativeProcessProtocol *process);
NativeThreadProtocol *GetThreadFromSuffix(StringExtractorGDBRemote &packet);
uint32_t GetNextSavedRegistersID();
void MaybeCloseInferiorTerminalConnection();
void ClearProcessSpecificData();
void RegisterPacketHandlers();
void DataAvailableCallback();
void SendProcessOutput();
void StartSTDIOForwarding();
void StopSTDIOForwarding();
//------------------------------------------------------------------
// For GDBRemoteCommunicationServerLLGS only
//------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerLLGS);
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_

View File

@@ -0,0 +1,116 @@
//===-- GDBRemoteCommunicationServerPlatform.h ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GDBRemoteCommunicationServerPlatform_h_
#define liblldb_GDBRemoteCommunicationServerPlatform_h_
// C Includes
// C++ Includes
#include <map>
#include <mutex>
#include <set>
// Other libraries and framework includes
// Project includes
#include "GDBRemoteCommunicationServerCommon.h"
#include "lldb/Host/Socket.h"
namespace lldb_private {
namespace process_gdb_remote {
class GDBRemoteCommunicationServerPlatform
: public GDBRemoteCommunicationServerCommon {
public:
typedef std::map<uint16_t, lldb::pid_t> PortMap;
GDBRemoteCommunicationServerPlatform(
const Socket::SocketProtocol socket_protocol, const char *socket_scheme);
~GDBRemoteCommunicationServerPlatform() override;
Status LaunchProcess() override;
// Set both ports to zero to let the platform automatically bind to
// a port chosen by the OS.
void SetPortMap(PortMap &&port_map);
//----------------------------------------------------------------------
// If we are using a port map where we can only use certain ports,
// get the next available port.
//
// If we are using a port map and we are out of ports, return UINT16_MAX
//
// If we aren't using a port map, return 0 to indicate we should bind to
// port 0 and then figure out which port we used.
//----------------------------------------------------------------------
uint16_t GetNextAvailablePort();
bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid);
bool FreePort(uint16_t port);
bool FreePortForProcess(lldb::pid_t pid);
void SetPortOffset(uint16_t port_offset);
void SetInferiorArguments(const lldb_private::Args &args);
Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname,
lldb::pid_t &pid, uint16_t &port,
std::string &socket_name);
void SetPendingGdbServer(lldb::pid_t pid, uint16_t port,
const std::string &socket_name);
protected:
const Socket::SocketProtocol m_socket_protocol;
const std::string m_socket_scheme;
std::recursive_mutex m_spawned_pids_mutex;
std::set<lldb::pid_t> m_spawned_pids;
PortMap m_port_map;
uint16_t m_port_offset;
struct {
lldb::pid_t pid;
uint16_t port;
std::string socket_name;
} m_pending_gdb_server;
PacketResult Handle_qLaunchGDBServer(StringExtractorGDBRemote &packet);
PacketResult Handle_qQueryGDBServer(StringExtractorGDBRemote &packet);
PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet);
PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
PacketResult Handle_QSetWorkingDir(StringExtractorGDBRemote &packet);
PacketResult Handle_qC(StringExtractorGDBRemote &packet);
PacketResult Handle_jSignalsInfo(StringExtractorGDBRemote &packet);
private:
bool KillSpawnedProcess(lldb::pid_t pid);
bool DebugserverProcessReaped(lldb::pid_t pid);
static const FileSpec &GetDomainSocketDir();
static FileSpec GetDomainSocketPath(const char *prefix);
DISALLOW_COPY_AND_ASSIGN(GDBRemoteCommunicationServerPlatform);
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // liblldb_GDBRemoteCommunicationServerPlatform_h_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
//===-- GDBRemoteRegisterContext.h ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef lldb_GDBRemoteRegisterContext_h_
#define lldb_GDBRemoteRegisterContext_h_
// C Includes
// C++ Includes
#include <vector>
// Other libraries and framework includes
// Project includes
#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-private.h"
#include "GDBRemoteCommunicationClient.h"
class StringExtractor;
namespace lldb_private {
namespace process_gdb_remote {
class ThreadGDBRemote;
class ProcessGDBRemote;
class GDBRemoteDynamicRegisterInfo : public DynamicRegisterInfo {
public:
GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {}
~GDBRemoteDynamicRegisterInfo() override = default;
void HardcodeARMRegisters(bool from_scratch);
};
class GDBRemoteRegisterContext : public RegisterContext {
public:
GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
GDBRemoteDynamicRegisterInfo &reg_info,
bool read_all_at_once);
~GDBRemoteRegisterContext() override;
void InvalidateAllRegisters() override;
size_t GetRegisterCount() override;
const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
size_t GetRegisterSetCount() override;
const RegisterSet *GetRegisterSet(size_t reg_set) override;
bool ReadRegister(const RegisterInfo *reg_info,
RegisterValue &value) override;
bool WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &value) override;
bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
bool ReadAllRegisterValues(RegisterCheckpoint &reg_checkpoint) override;
bool
WriteAllRegisterValues(const RegisterCheckpoint &reg_checkpoint) override;
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
uint32_t num) override;
protected:
friend class ThreadGDBRemote;
bool ReadRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data);
bool WriteRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data,
uint32_t data_offset);
bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data);
bool PrivateSetRegisterValue(uint32_t reg, uint64_t val);
void SetAllRegisterValid(bool b);
bool GetRegisterIsValid(uint32_t reg) const {
#if defined(LLDB_CONFIGURATION_DEBUG)
assert(reg < m_reg_valid.size());
#endif
if (reg < m_reg_valid.size())
return m_reg_valid[reg];
return false;
}
void SetRegisterIsValid(const RegisterInfo *reg_info, bool valid) {
if (reg_info)
return SetRegisterIsValid(reg_info->kinds[lldb::eRegisterKindLLDB],
valid);
}
void SetRegisterIsValid(uint32_t reg, bool valid) {
#if defined(LLDB_CONFIGURATION_DEBUG)
assert(reg < m_reg_valid.size());
#endif
if (reg < m_reg_valid.size())
m_reg_valid[reg] = valid;
}
GDBRemoteDynamicRegisterInfo &m_reg_info;
std::vector<bool> m_reg_valid;
DataExtractor m_reg_data;
bool m_read_all_at_once;
private:
// Helper function for ReadRegisterBytes().
bool GetPrimordialRegister(const RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm);
// Helper function for WriteRegisterBytes().
bool SetPrimordialRegister(const RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm);
DISALLOW_COPY_AND_ASSIGN(GDBRemoteRegisterContext);
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // lldb_GDBRemoteRegisterContext_h_

View File

@@ -0,0 +1 @@
35d02c15ab85b6af5563930e9e336135d8aaa579

View File

@@ -0,0 +1,464 @@
//===-- ProcessGDBRemote.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ProcessGDBRemote_h_
#define liblldb_ProcessGDBRemote_h_
// C Includes
// C++ Includes
#include <atomic>
#include <map>
#include <mutex>
#include <string>
#include <vector>
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/LoadedModuleInfoList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/ThreadSafeValue.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamGDBRemote.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringExtractor.h"
#include "lldb/Utility/StringList.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private-forward.h"
#include "GDBRemoteCommunicationClient.h"
#include "GDBRemoteRegisterContext.h"
#include "llvm/ADT/DenseMap.h"
namespace lldb_private {
namespace process_gdb_remote {
class ThreadGDBRemote;
class ProcessGDBRemote : public Process,
private GDBRemoteClientBase::ContinueDelegate {
public:
ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
~ProcessGDBRemote() override;
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec *crash_file_path);
static void Initialize();
static void DebuggerInitialize(Debugger &debugger);
static void Terminate();
static ConstString GetPluginNameStatic();
static const char *GetPluginDescriptionStatic();
//------------------------------------------------------------------
// Check if a given Process
//------------------------------------------------------------------
bool CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) override;
CommandObject *GetPluginCommandObject() override;
//------------------------------------------------------------------
// Creating a new process, or attaching to an existing one
//------------------------------------------------------------------
Status WillLaunch(Module *module) override;
Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override;
void DidLaunch() override;
Status WillAttachToProcessWithID(lldb::pid_t pid) override;
Status WillAttachToProcessWithName(const char *process_name,
bool wait_for_launch) override;
Status DoConnectRemote(Stream *strm, llvm::StringRef remote_url) override;
Status WillLaunchOrAttach();
Status DoAttachToProcessWithID(lldb::pid_t pid,
const ProcessAttachInfo &attach_info) override;
Status
DoAttachToProcessWithName(const char *process_name,
const ProcessAttachInfo &attach_info) override;
void DidAttach(ArchSpec &process_arch) override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
//------------------------------------------------------------------
// Process Control
//------------------------------------------------------------------
Status WillResume() override;
Status DoResume() override;
Status DoHalt(bool &caused_stop) override;
Status DoDetach(bool keep_stopped) override;
bool DetachRequiresHalt() override { return true; }
Status DoSignal(int signal) override;
Status DoDestroy() override;
void RefreshStateAfterStop() override;
void SetUnixSignals(const lldb::UnixSignalsSP &signals_sp);
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
bool IsAlive() override;
lldb::addr_t GetImageInfoAddress() override;
void WillPublicStop() override;
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
Status &error) override;
size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size,
Status &error) override;
lldb::addr_t DoAllocateMemory(size_t size, uint32_t permissions,
Status &error) override;
Status GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &region_info) override;
Status DoDeallocateMemory(lldb::addr_t ptr) override;
//------------------------------------------------------------------
// Process STDIO
//------------------------------------------------------------------
size_t PutSTDIN(const char *buf, size_t buf_size, Status &error) override;
//----------------------------------------------------------------------
// Process Breakpoints
//----------------------------------------------------------------------
Status EnableBreakpointSite(BreakpointSite *bp_site) override;
Status DisableBreakpointSite(BreakpointSite *bp_site) override;
//----------------------------------------------------------------------
// Process Watchpoints
//----------------------------------------------------------------------
Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override;
Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
Status GetWatchpointSupportInfo(uint32_t &num) override;
lldb::user_id_t StartTrace(const TraceOptions &options,
Status &error) override;
Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override;
Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id,
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) override;
Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id,
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) override;
Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
bool StartNoticingNewThreads() override;
bool StopNoticingNewThreads() override;
GDBRemoteCommunicationClient &GetGDBRemote() { return m_gdb_comm; }
Status SendEventData(const char *data) override;
//----------------------------------------------------------------------
// Override DidExit so we can disconnect from the remote GDB server
//----------------------------------------------------------------------
void DidExit() override;
void SetUserSpecifiedMaxMemoryTransferSize(uint64_t user_specified_max);
bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch,
ModuleSpec &module_spec) override;
void PrefetchModuleSpecs(llvm::ArrayRef<FileSpec> module_file_specs,
const llvm::Triple &triple) override;
bool GetHostOSVersion(uint32_t &major, uint32_t &minor,
uint32_t &update) override;
size_t LoadModules(LoadedModuleInfoList &module_list) override;
size_t LoadModules() override;
Status GetFileLoadAddress(const FileSpec &file, bool &is_loaded,
lldb::addr_t &load_addr) override;
void ModulesDidLoad(ModuleList &module_list) override;
StructuredData::ObjectSP
GetLoadedDynamicLibrariesInfos(lldb::addr_t image_list_address,
lldb::addr_t image_count) override;
Status
ConfigureStructuredData(const ConstString &type_name,
const StructuredData::ObjectSP &config_sp) override;
StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos() override;
StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos(
const std::vector<lldb::addr_t> &load_addresses) override;
StructuredData::ObjectSP
GetLoadedDynamicLibrariesInfos_sender(StructuredData::ObjectSP args);
StructuredData::ObjectSP GetSharedCacheInfo() override;
std::string HarmonizeThreadIdsForProfileData(
StringExtractorGDBRemote &inputStringExtractor);
protected:
friend class ThreadGDBRemote;
friend class GDBRemoteCommunicationClient;
friend class GDBRemoteRegisterContext;
//------------------------------------------------------------------
/// Broadcaster event bits definitions.
//------------------------------------------------------------------
enum {
eBroadcastBitAsyncContinue = (1 << 0),
eBroadcastBitAsyncThreadShouldExit = (1 << 1),
eBroadcastBitAsyncThreadDidExit = (1 << 2)
};
GDBRemoteCommunicationClient m_gdb_comm;
std::atomic<lldb::pid_t> m_debugserver_pid;
std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet
// stack replaces
// the last stop
// packet variable
std::recursive_mutex m_last_stop_packet_mutex;
GDBRemoteDynamicRegisterInfo m_register_info;
Broadcaster m_async_broadcaster;
lldb::ListenerSP m_async_listener_sp;
HostThread m_async_thread;
std::recursive_mutex m_async_thread_state_mutex;
typedef std::vector<lldb::tid_t> tid_collection;
typedef std::vector<std::pair<lldb::tid_t, int>> tid_sig_collection;
typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
typedef std::map<uint32_t, std::string> ExpeditedRegisterMap;
tid_collection m_thread_ids; // Thread IDs for all threads. This list gets
// updated after stopping
std::vector<lldb::addr_t> m_thread_pcs; // PC values for all the threads.
StructuredData::ObjectSP m_jstopinfo_sp; // Stop info only for any threads
// that have valid stop infos
StructuredData::ObjectSP m_jthreadsinfo_sp; // Full stop info, expedited
// registers and memory for all
// threads if "jThreadsInfo"
// packet is supported
tid_collection m_continue_c_tids; // 'c' for continue
tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
tid_collection m_continue_s_tids; // 's' for step
tid_sig_collection m_continue_S_tids; // 'S' for step with signal
uint64_t m_max_memory_size; // The maximum number of bytes to read/write when
// reading and writing memory
uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote
// gdb stub can handle
MMapMap m_addr_to_mmap_size;
lldb::BreakpointSP m_thread_create_bp_sp;
bool m_waiting_for_attach;
bool m_destroy_tried_resuming;
lldb::CommandObjectSP m_command_sp;
int64_t m_breakpoint_pc_offset;
lldb::tid_t m_initial_tid; // The initial thread ID, given by stub on attach
//----------------------------------------------------------------------
// Accessors
//----------------------------------------------------------------------
bool IsRunning(lldb::StateType state) {
return state == lldb::eStateRunning || IsStepping(state);
}
bool IsStepping(lldb::StateType state) {
return state == lldb::eStateStepping;
}
bool CanResume(lldb::StateType state) { return state == lldb::eStateStopped; }
bool HasExited(lldb::StateType state) { return state == lldb::eStateExited; }
bool ProcessIDIsValid() const;
void Clear();
bool UpdateThreadList(ThreadList &old_thread_list,
ThreadList &new_thread_list) override;
Status EstablishConnectionIfNeeded(const ProcessInfo &process_info);
Status LaunchAndConnectToDebugserver(const ProcessInfo &process_info);
void KillDebugserverProcess();
void BuildDynamicRegisterInfo(bool force);
void SetLastStopPacket(const StringExtractorGDBRemote &response);
bool ParsePythonTargetDefinition(const FileSpec &target_definition_fspec);
const lldb::DataBufferSP GetAuxvData() override;
StructuredData::ObjectSP GetExtendedInfoForThread(lldb::tid_t tid);
void GetMaxMemorySize();
bool CalculateThreadStopInfo(ThreadGDBRemote *thread);
size_t UpdateThreadPCsFromStopReplyThreadsValue(std::string &value);
size_t UpdateThreadIDsFromStopReplyThreadsValue(std::string &value);
bool HandleNotifyPacket(StringExtractorGDBRemote &packet);
bool StartAsyncThread();
void StopAsyncThread();
static lldb::thread_result_t AsyncThread(void *arg);
static bool
MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp,
lldb::pid_t pid, bool exited, int signo,
int exit_status);
lldb::StateType SetThreadStopInfo(StringExtractor &stop_packet);
bool
GetThreadStopInfoFromJSON(ThreadGDBRemote *thread,
const StructuredData::ObjectSP &thread_infos_sp);
lldb::ThreadSP SetThreadStopInfo(StructuredData::Dictionary *thread_dict);
lldb::ThreadSP
SetThreadStopInfo(lldb::tid_t tid,
ExpeditedRegisterMap &expedited_register_map, uint8_t signo,
const std::string &thread_name, const std::string &reason,
const std::string &description, uint32_t exc_type,
const std::vector<lldb::addr_t> &exc_data,
lldb::addr_t thread_dispatch_qaddr, bool queue_vars_valid,
lldb_private::LazyBool associated_with_libdispatch_queue,
lldb::addr_t dispatch_queue_t, std::string &queue_name,
lldb::QueueKind queue_kind, uint64_t queue_serial);
void HandleStopReplySequence();
void ClearThreadIDList();
bool UpdateThreadIDList();
void DidLaunchOrAttach(ArchSpec &process_arch);
Status ConnectToDebugserver(llvm::StringRef host_port);
const char *GetDispatchQueueNameForThread(lldb::addr_t thread_dispatch_qaddr,
std::string &dispatch_queue_name);
DynamicLoader *GetDynamicLoader() override;
// Query remote GDBServer for register information
bool GetGDBServerRegisterInfo(ArchSpec &arch);
// Query remote GDBServer for a detailed loaded library list
Status GetLoadedModuleList(LoadedModuleInfoList &);
lldb::ModuleSP LoadModuleAtAddress(const FileSpec &file,
lldb::addr_t link_map,
lldb::addr_t base_addr,
bool value_is_offset);
Status UpdateAutomaticSignalFiltering() override;
private:
//------------------------------------------------------------------
// For ProcessGDBRemote only
//------------------------------------------------------------------
std::string m_partial_profile_data;
std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
uint64_t m_last_signals_version = 0;
static bool NewThreadNotifyBreakpointHit(void *baton,
StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
//------------------------------------------------------------------
// ContinueDelegate interface
//------------------------------------------------------------------
void HandleAsyncStdout(llvm::StringRef out) override;
void HandleAsyncMisc(llvm::StringRef data) override;
void HandleStopReply() override;
void HandleAsyncStructuredDataPacket(llvm::StringRef data) override;
void SetThreadPc(const lldb::ThreadSP &thread_sp, uint64_t index);
using ModuleCacheKey = std::pair<std::string, std::string>;
// KeyInfo for the cached module spec DenseMap.
// The invariant is that all real keys will have the file and architecture
// set.
// The empty key has an empty file and an empty arch.
// The tombstone key has an invalid arch and an empty file.
// The comparison and hash functions take the file name and architecture
// triple into account.
struct ModuleCacheInfo {
static ModuleCacheKey getEmptyKey() { return ModuleCacheKey(); }
static ModuleCacheKey getTombstoneKey() { return ModuleCacheKey("", "T"); }
static unsigned getHashValue(const ModuleCacheKey &key) {
return llvm::hash_combine(key.first, key.second);
}
static bool isEqual(const ModuleCacheKey &LHS, const ModuleCacheKey &RHS) {
return LHS == RHS;
}
};
llvm::DenseMap<ModuleCacheKey, ModuleSpec, ModuleCacheInfo>
m_cached_module_specs;
DISALLOW_COPY_AND_ASSIGN(ProcessGDBRemote);
};
} // namespace process_gdb_remote
} // namespace lldb_private
#endif // liblldb_ProcessGDBRemote_h_

View File

@@ -0,0 +1,44 @@
//===-- ProcessGDBRemoteLog.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ProcessGDBRemoteLog.h"
#include "ProcessGDBRemote.h"
#include "llvm/Support/Threading.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::process_gdb_remote;
static constexpr Log::Category g_categories[] = {
{{"async"}, {"log asynchronous activity"}, GDBR_LOG_ASYNC},
{{"break"}, {"log breakpoints"}, GDBR_LOG_BREAKPOINTS},
{{"comm"}, {"log communication activity"}, GDBR_LOG_COMM},
{{"packets"}, {"log gdb remote packets"}, GDBR_LOG_PACKETS},
{{"memory"}, {"log memory reads and writes"}, GDBR_LOG_MEMORY},
{{"data-short"},
{"log memory bytes for memory reads and writes for short transactions "
"only"},
GDBR_LOG_MEMORY_DATA_SHORT},
{{"data-long"},
{"log memory bytes for memory reads and writes for all transactions"},
GDBR_LOG_MEMORY_DATA_LONG},
{{"process"}, {"log process events and activities"}, GDBR_LOG_PROCESS},
{{"step"}, {"log step related activities"}, GDBR_LOG_STEP},
{{"thread"}, {"log thread events and activities"}, GDBR_LOG_THREAD},
{{"watch"}, {"log watchpoint related activities"}, GDBR_LOG_WATCHPOINTS},
};
Log::Channel ProcessGDBRemoteLog::g_channel(g_categories, GDBR_LOG_DEFAULT);
void ProcessGDBRemoteLog::Initialize() {
static llvm::once_flag g_once_flag;
llvm::call_once(g_once_flag, []() {
Log::Register("gdb-remote", g_channel);
});
}

Some files were not shown because too many files have changed in this diff Show More