forked from OSchip/llvm-project
Split the GDBRemoteCommunication class into three classes:
GDBRemoteCommunication - The base GDB remote communication class GDBRemoteCommunicationClient - designed to be used for clients the connect to a remote GDB server GDBRemoteCommunicationServer - designed to be used on the server side of a GDB server implementation. llvm-svn: 128070
This commit is contained in:
parent
27cfcbac82
commit
576d8834fe
|
@ -56,6 +56,10 @@
|
|||
26680336116005EF008E1FE4 /* SBBreakpointLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */; };
|
||||
26680337116005F1008E1FE4 /* SBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AF16A9C11402D5B007A7B3F /* SBBreakpoint.cpp */; };
|
||||
2668035C11601108008E1FE4 /* LLDB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26680207115FD0ED008E1FE4 /* LLDB.framework */; };
|
||||
26744EF11338317700EF765A /* GDBRemoteCommunicationClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */; };
|
||||
26744EF21338317700EF765A /* GDBRemoteCommunicationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 26744EEE1338317700EF765A /* GDBRemoteCommunicationClient.h */; };
|
||||
26744EF31338317700EF765A /* GDBRemoteCommunicationServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26744EEF1338317700EF765A /* GDBRemoteCommunicationServer.cpp */; };
|
||||
26744EF41338317700EF765A /* GDBRemoteCommunicationServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 26744EF01338317700EF765A /* GDBRemoteCommunicationServer.h */; };
|
||||
2689000013353DB600698AC0 /* BreakpointResolverAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = 26D0DD5010FE554D00271C65 /* BreakpointResolverAddress.h */; };
|
||||
2689000113353DB600698AC0 /* BreakpointResolverAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26D0DD5310FE555900271C65 /* BreakpointResolverAddress.cpp */; };
|
||||
2689000213353DB600698AC0 /* BreakpointResolverFileLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 26D0DD5110FE554D00271C65 /* BreakpointResolverFileLine.h */; };
|
||||
|
@ -635,6 +639,10 @@
|
|||
266F5CBB12FC846200DFCE33 /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Config.h; path = include/lldb/Host/Config.h; sourceTree = "<group>"; };
|
||||
2672D8461189055500FF4019 /* CommandObjectFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectFrame.cpp; path = source/Commands/CommandObjectFrame.cpp; sourceTree = "<group>"; };
|
||||
2672D8471189055500FF4019 /* CommandObjectFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectFrame.h; path = source/Commands/CommandObjectFrame.h; sourceTree = "<group>"; };
|
||||
26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GDBRemoteCommunicationClient.cpp; sourceTree = "<group>"; };
|
||||
26744EEE1338317700EF765A /* GDBRemoteCommunicationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationClient.h; sourceTree = "<group>"; };
|
||||
26744EEF1338317700EF765A /* GDBRemoteCommunicationServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GDBRemoteCommunicationServer.cpp; sourceTree = "<group>"; };
|
||||
26744EF01338317700EF765A /* GDBRemoteCommunicationServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GDBRemoteCommunicationServer.h; sourceTree = "<group>"; };
|
||||
2675F6FE1332BE690067997B /* PlatformRemoteiOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformRemoteiOS.cpp; sourceTree = "<group>"; };
|
||||
2675F6FF1332BE690067997B /* PlatformRemoteiOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformRemoteiOS.h; sourceTree = "<group>"; };
|
||||
2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringExtractorGDBRemote.cpp; path = source/Utility/StringExtractorGDBRemote.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2380,6 +2388,10 @@
|
|||
children = (
|
||||
2618EE5B1315B29C001D6D71 /* GDBRemoteCommunication.cpp */,
|
||||
2618EE5C1315B29C001D6D71 /* GDBRemoteCommunication.h */,
|
||||
26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */,
|
||||
26744EEE1338317700EF765A /* GDBRemoteCommunicationClient.h */,
|
||||
26744EEF1338317700EF765A /* GDBRemoteCommunicationServer.cpp */,
|
||||
26744EF01338317700EF765A /* GDBRemoteCommunicationServer.h */,
|
||||
2618EE5D1315B29C001D6D71 /* GDBRemoteRegisterContext.cpp */,
|
||||
2618EE5E1315B29C001D6D71 /* GDBRemoteRegisterContext.h */,
|
||||
2618EE5F1315B29C001D6D71 /* ProcessGDBRemote.cpp */,
|
||||
|
@ -2483,6 +2495,8 @@
|
|||
2689000C13353DB600698AC0 /* StoppointCallbackContext.h in Headers */,
|
||||
2689000E13353DB600698AC0 /* StoppointLocation.h in Headers */,
|
||||
2689001013353DB600698AC0 /* WatchpointLocation.h in Headers */,
|
||||
26744EF21338317700EF765A /* GDBRemoteCommunicationClient.h in Headers */,
|
||||
26744EF41338317700EF765A /* GDBRemoteCommunicationServer.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3038,6 +3052,8 @@
|
|||
2689011213353E8200698AC0 /* StringExtractorGDBRemote.cpp in Sources */,
|
||||
2689011313353E8200698AC0 /* PseudoTerminal.cpp in Sources */,
|
||||
26B1FCC21338115F002886E2 /* Host.mm in Sources */,
|
||||
26744EF11338317700EF765A /* GDBRemoteCommunicationClient.cpp in Sources */,
|
||||
26744EF31338317700EF765A /* GDBRemoteCommunicationServer.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,10 +18,7 @@
|
|||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
#include "lldb/Core/Communication.h"
|
||||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/Listener.h"
|
||||
#include "lldb/Host/Mutex.h"
|
||||
#include "lldb/Host/Predicate.h"
|
||||
|
@ -30,8 +27,7 @@
|
|||
|
||||
class ProcessGDBRemote;
|
||||
|
||||
class GDBRemoteCommunication :
|
||||
public lldb_private::Communication
|
||||
class GDBRemoteCommunication : public lldb_private::Communication
|
||||
{
|
||||
public:
|
||||
enum
|
||||
|
@ -41,7 +37,7 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
GDBRemoteCommunication();
|
||||
GDBRemoteCommunication(const char *comm_name, const char *listener_name);
|
||||
|
||||
virtual
|
||||
~GDBRemoteCommunication();
|
||||
|
@ -53,23 +49,6 @@ public:
|
|||
SendPacket (const char *payload,
|
||||
size_t payload_length);
|
||||
|
||||
size_t
|
||||
SendPacketAndWaitForResponse (const char *send_payload,
|
||||
StringExtractorGDBRemote &response,
|
||||
bool send_async);
|
||||
|
||||
size_t
|
||||
SendPacketAndWaitForResponse (const char *send_payload,
|
||||
size_t send_length,
|
||||
StringExtractorGDBRemote &response,
|
||||
bool send_async);
|
||||
|
||||
lldb::StateType
|
||||
SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,
|
||||
const char *packet_payload,
|
||||
size_t packet_length,
|
||||
StringExtractorGDBRemote &response);
|
||||
|
||||
// Wait for a packet within 'nsec' seconds
|
||||
size_t
|
||||
WaitForPacket (StringExtractorGDBRemote &response,
|
||||
|
@ -90,23 +69,10 @@ public:
|
|||
size_t
|
||||
SendNack ();
|
||||
|
||||
|
||||
char
|
||||
CalculcateChecksum (const char *payload,
|
||||
size_t payload_length);
|
||||
|
||||
bool
|
||||
GetThreadSuffixSupported ();
|
||||
|
||||
bool
|
||||
SendAsyncSignal (int signo);
|
||||
|
||||
bool
|
||||
SendInterrupt (lldb_private::Mutex::Locker &locker,
|
||||
uint32_t seconds_to_wait_for_stop,
|
||||
bool &sent_interrupt,
|
||||
bool &timed_out);
|
||||
|
||||
bool
|
||||
GetSequenceMutex(lldb_private::Mutex::Locker& locker);
|
||||
|
||||
|
@ -116,167 +82,29 @@ public:
|
|||
virtual void
|
||||
AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast, lldb::ConnectionStatus status);
|
||||
|
||||
|
||||
lldb::pid_t
|
||||
GetCurrentProcessID ();
|
||||
|
||||
bool
|
||||
GetLaunchSuccess (std::string &error_str);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sends a GDB remote protocol 'A' packet that delivers program
|
||||
/// arguments to the remote server.
|
||||
///
|
||||
/// @param[in] argv
|
||||
/// A NULL terminated array of const C strings to use as the
|
||||
/// arguments.
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the response was "OK", a positive value if the
|
||||
/// the response was "Exx" where xx are two hex digits, or
|
||||
/// -1 if the call is unsupported or any other unexpected
|
||||
/// response was received.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SendArgumentsPacket (char const *argv[]);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
|
||||
/// environment that will get used when launching an application
|
||||
/// in conjunction with the 'A' packet. This function can be called
|
||||
/// multiple times in a row in order to pass on the desired
|
||||
/// environment that the inferior should be launched with.
|
||||
///
|
||||
/// @param[in] name_equal_value
|
||||
/// A NULL terminated C string that contains a single environment
|
||||
/// in the format "NAME=VALUE".
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the response was "OK", a positive value if the
|
||||
/// the response was "Exx" where xx are two hex digits, or
|
||||
/// -1 if the call is unsupported or any other unexpected
|
||||
/// response was received.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SendEnvironmentPacket (char const *name_equal_value);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sends a "vAttach:PID" where PID is in hex.
|
||||
///
|
||||
/// @param[in] pid
|
||||
/// A process ID for the remote gdb server to attach to.
|
||||
///
|
||||
/// @param[out] response
|
||||
/// The response received from the gdb server. If the return
|
||||
/// value is zero, \a response will contain a stop reply
|
||||
/// packet.
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the attach was successful, or an error indicating
|
||||
/// an error code.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SendAttach (lldb::pid_t pid,
|
||||
StringExtractorGDBRemote& response);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets the path to use for stdin/out/err for a process
|
||||
/// that will be launched with the 'A' packet.
|
||||
///
|
||||
/// @param[in] path
|
||||
/// The path to use for stdin/out/err
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the for success, or an error code for failure.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SetSTDIN (char const *path);
|
||||
int
|
||||
SetSTDOUT (char const *path);
|
||||
int
|
||||
SetSTDERR (char const *path);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets the disable ASLR flag to \a enable for a process that will
|
||||
/// be launched with the 'A' packet.
|
||||
///
|
||||
/// @param[in] enable
|
||||
/// A boolean value indicating wether to disable ASLR or not.
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the for success, or an error code for failure.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SetDisableASLR (bool enable);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets the working directory to \a path for a process that will
|
||||
/// be launched with the 'A' packet.
|
||||
///
|
||||
/// @param[in] path
|
||||
/// The path to a directory to use when launching our processs
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the for success, or an error code for failure.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SetWorkingDir (char const *path);
|
||||
|
||||
lldb::addr_t
|
||||
AllocateMemory (size_t size, uint32_t permissions);
|
||||
|
||||
bool
|
||||
DeallocateMemory (lldb::addr_t addr);
|
||||
|
||||
bool
|
||||
IsRunning() const
|
||||
{
|
||||
return m_public_is_running.GetValue();
|
||||
}
|
||||
|
||||
const lldb_private::ArchSpec &
|
||||
GetHostArchitecture ();
|
||||
|
||||
const lldb_private::ConstString &
|
||||
GetOSString ();
|
||||
|
||||
const lldb_private::ConstString &
|
||||
GetVendorString();
|
||||
|
||||
lldb::ByteOrder
|
||||
GetByteOrder ();
|
||||
//------------------------------------------------------------------
|
||||
// Client and server must implement these pure virtual functions
|
||||
//------------------------------------------------------------------
|
||||
virtual bool
|
||||
GetThreadSuffixSupported () = 0;
|
||||
|
||||
uint32_t
|
||||
GetAddressByteSize ();
|
||||
|
||||
bool
|
||||
GetVContSupported (char flavor);
|
||||
|
||||
void
|
||||
ResetDiscoverableSettings();
|
||||
|
||||
bool
|
||||
GetHostInfo ();
|
||||
|
||||
bool
|
||||
GetSendAcks ();
|
||||
|
||||
bool
|
||||
GetSupportsThreadSuffix ();
|
||||
|
||||
bool
|
||||
HasFullVContSupport ()
|
||||
{
|
||||
return GetVContSupported ('A');
|
||||
}
|
||||
|
||||
bool
|
||||
HasAnyVContSupport ()
|
||||
{
|
||||
return GetVContSupported ('a');
|
||||
}
|
||||
virtual bool
|
||||
GetSendAcks () = 0;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Set the global packet timeout.
|
||||
//
|
||||
// For clients, this is the timeout that gets used when sending
|
||||
// packets and waiting for responses. For servers, this might not
|
||||
// get used, and if it doesn't this should be moved to the
|
||||
// GDBRemoteCommunicationClient.
|
||||
//------------------------------------------------------------------
|
||||
uint32_t
|
||||
SetPacketTimeout (uint32_t packet_timeout)
|
||||
{
|
||||
|
@ -299,46 +127,15 @@ protected:
|
|||
bool
|
||||
WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr);
|
||||
|
||||
bool
|
||||
HostInfoIsValid () const
|
||||
{
|
||||
return m_supports_qHostInfo != lldb::eLazyBoolCalculate;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Classes that inherit from GDBRemoteCommunication can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
uint32_t m_packet_timeout;
|
||||
lldb::LazyBool m_supports_not_sending_acks;
|
||||
lldb::LazyBool m_supports_thread_suffix;
|
||||
lldb::LazyBool m_supports_qHostInfo;
|
||||
lldb::LazyBool m_supports_vCont_all;
|
||||
lldb::LazyBool m_supports_vCont_any;
|
||||
lldb::LazyBool m_supports_vCont_c;
|
||||
lldb::LazyBool m_supports_vCont_C;
|
||||
lldb::LazyBool m_supports_vCont_s;
|
||||
lldb::LazyBool m_supports_vCont_S;
|
||||
lldb_private::Listener m_rx_packet_listener;
|
||||
lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
|
||||
lldb_private::Predicate<bool> m_public_is_running;
|
||||
lldb_private::Predicate<bool> m_private_is_running;
|
||||
|
||||
// If we need to send a packet while the target is running, the m_async_XXX
|
||||
// member variables take care of making this happen.
|
||||
lldb_private::Mutex m_async_mutex;
|
||||
lldb_private::Predicate<bool> m_async_packet_predicate;
|
||||
std::string m_async_packet;
|
||||
StringExtractorGDBRemote m_async_response;
|
||||
int m_async_signal; // We were asked to deliver a signal to the inferior process.
|
||||
|
||||
lldb_private::ArchSpec m_arch; // Results from the qHostInfo call
|
||||
uint32_t m_cpusubtype; // Results from the qHostInfo call
|
||||
lldb_private::ConstString m_os; // Results from the qHostInfo call
|
||||
lldb_private::ConstString m_vendor; // Results from the qHostInfo call
|
||||
lldb::ByteOrder m_byte_order; // Results from the qHostInfo call
|
||||
uint32_t m_pointer_byte_size; // Results from the qHostInfo call
|
||||
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// For GDBRemoteCommunication only
|
||||
|
|
|
@ -0,0 +1,934 @@
|
|||
//===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "GDBRemoteCommunicationClient.h"
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "lldb/Interpreter/Args.h"
|
||||
#include "lldb/Core/ConnectionFileDescriptor.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Host/Endian.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Host/TimeValue.h"
|
||||
|
||||
// Project includes
|
||||
#include "Utility/StringExtractorGDBRemote.h"
|
||||
#include "ProcessGDBRemote.h"
|
||||
#include "ProcessGDBRemoteLog.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// GDBRemoteCommunicationClient constructor
|
||||
//----------------------------------------------------------------------
|
||||
GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() :
|
||||
GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"),
|
||||
m_supports_not_sending_acks (eLazyBoolCalculate),
|
||||
m_supports_thread_suffix (eLazyBoolCalculate),
|
||||
m_supports_qHostInfo (eLazyBoolCalculate),
|
||||
m_supports_vCont_all (eLazyBoolCalculate),
|
||||
m_supports_vCont_any (eLazyBoolCalculate),
|
||||
m_supports_vCont_c (eLazyBoolCalculate),
|
||||
m_supports_vCont_C (eLazyBoolCalculate),
|
||||
m_supports_vCont_s (eLazyBoolCalculate),
|
||||
m_supports_vCont_S (eLazyBoolCalculate),
|
||||
m_async_mutex (Mutex::eMutexTypeRecursive),
|
||||
m_async_packet_predicate (false),
|
||||
m_async_packet (),
|
||||
m_async_response (),
|
||||
m_async_signal (-1),
|
||||
m_arch(),
|
||||
m_os(),
|
||||
m_vendor(),
|
||||
m_byte_order(lldb::endian::InlHostByteOrder()),
|
||||
m_pointer_byte_size(0)
|
||||
{
|
||||
m_rx_packet_listener.StartListeningForEvents(this,
|
||||
Communication::eBroadcastBitPacketAvailable |
|
||||
Communication::eBroadcastBitReadThreadDidExit);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Destructor
|
||||
//----------------------------------------------------------------------
|
||||
GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()
|
||||
{
|
||||
m_rx_packet_listener.StopListeningForEvents(this,
|
||||
Communication::eBroadcastBitPacketAvailable |
|
||||
Communication::eBroadcastBitReadThreadDidExit);
|
||||
if (IsConnected())
|
||||
{
|
||||
StopReadThread();
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetSendAcks ()
|
||||
{
|
||||
if (m_supports_not_sending_acks == eLazyBoolCalculate)
|
||||
{
|
||||
StringExtractorGDBRemote response;
|
||||
m_supports_not_sending_acks = eLazyBoolNo;
|
||||
if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
m_supports_not_sending_acks = eLazyBoolYes;
|
||||
}
|
||||
}
|
||||
return m_supports_not_sending_acks != eLazyBoolYes;
|
||||
}
|
||||
|
||||
void
|
||||
GDBRemoteCommunicationClient::ResetDiscoverableSettings()
|
||||
{
|
||||
m_supports_not_sending_acks = eLazyBoolCalculate;
|
||||
m_supports_thread_suffix = eLazyBoolCalculate;
|
||||
m_supports_qHostInfo = eLazyBoolCalculate;
|
||||
m_supports_vCont_c = eLazyBoolCalculate;
|
||||
m_supports_vCont_C = eLazyBoolCalculate;
|
||||
m_supports_vCont_s = eLazyBoolCalculate;
|
||||
m_supports_vCont_S = eLazyBoolCalculate;
|
||||
m_arch.Clear();
|
||||
m_os.Clear();
|
||||
m_vendor.Clear();
|
||||
m_byte_order = lldb::endian::InlHostByteOrder();
|
||||
m_pointer_byte_size = 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetThreadSuffixSupported ()
|
||||
{
|
||||
if (m_supports_thread_suffix == eLazyBoolCalculate)
|
||||
{
|
||||
StringExtractorGDBRemote response;
|
||||
m_supports_thread_suffix = eLazyBoolNo;
|
||||
if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
m_supports_thread_suffix = eLazyBoolYes;
|
||||
}
|
||||
}
|
||||
return m_supports_thread_suffix;
|
||||
}
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetVContSupported (char flavor)
|
||||
{
|
||||
if (m_supports_vCont_c == eLazyBoolCalculate)
|
||||
{
|
||||
StringExtractorGDBRemote response;
|
||||
m_supports_vCont_any = eLazyBoolNo;
|
||||
m_supports_vCont_all = eLazyBoolNo;
|
||||
m_supports_vCont_c = eLazyBoolNo;
|
||||
m_supports_vCont_C = eLazyBoolNo;
|
||||
m_supports_vCont_s = eLazyBoolNo;
|
||||
m_supports_vCont_S = eLazyBoolNo;
|
||||
if (SendPacketAndWaitForResponse("vCont?", response, false))
|
||||
{
|
||||
const char *response_cstr = response.GetStringRef().c_str();
|
||||
if (::strstr (response_cstr, ";c"))
|
||||
m_supports_vCont_c = eLazyBoolYes;
|
||||
|
||||
if (::strstr (response_cstr, ";C"))
|
||||
m_supports_vCont_C = eLazyBoolYes;
|
||||
|
||||
if (::strstr (response_cstr, ";s"))
|
||||
m_supports_vCont_s = eLazyBoolYes;
|
||||
|
||||
if (::strstr (response_cstr, ";S"))
|
||||
m_supports_vCont_S = eLazyBoolYes;
|
||||
|
||||
if (m_supports_vCont_c == eLazyBoolYes &&
|
||||
m_supports_vCont_C == eLazyBoolYes &&
|
||||
m_supports_vCont_s == eLazyBoolYes &&
|
||||
m_supports_vCont_S == eLazyBoolYes)
|
||||
{
|
||||
m_supports_vCont_all = eLazyBoolYes;
|
||||
}
|
||||
|
||||
if (m_supports_vCont_c == eLazyBoolYes ||
|
||||
m_supports_vCont_C == eLazyBoolYes ||
|
||||
m_supports_vCont_s == eLazyBoolYes ||
|
||||
m_supports_vCont_S == eLazyBoolYes)
|
||||
{
|
||||
m_supports_vCont_any = eLazyBoolYes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (flavor)
|
||||
{
|
||||
case 'a': return m_supports_vCont_any;
|
||||
case 'A': return m_supports_vCont_all;
|
||||
case 'c': return m_supports_vCont_c;
|
||||
case 'C': return m_supports_vCont_C;
|
||||
case 's': return m_supports_vCont_s;
|
||||
case 'S': return m_supports_vCont_S;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
|
||||
(
|
||||
const char *payload,
|
||||
StringExtractorGDBRemote &response,
|
||||
bool send_async
|
||||
)
|
||||
{
|
||||
return SendPacketAndWaitForResponse (payload,
|
||||
::strlen (payload),
|
||||
response,
|
||||
send_async);
|
||||
}
|
||||
|
||||
size_t
|
||||
GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
|
||||
(
|
||||
const char *payload,
|
||||
size_t payload_length,
|
||||
StringExtractorGDBRemote &response,
|
||||
bool send_async
|
||||
)
|
||||
{
|
||||
Mutex::Locker locker;
|
||||
TimeValue timeout_time;
|
||||
timeout_time = TimeValue::Now();
|
||||
timeout_time.OffsetWithSeconds (m_packet_timeout);
|
||||
LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
|
||||
|
||||
if (GetSequenceMutex (locker))
|
||||
{
|
||||
if (SendPacketNoLock (payload, strlen(payload)))
|
||||
return WaitForPacketNoLock (response, &timeout_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (send_async)
|
||||
{
|
||||
Mutex::Locker async_locker (m_async_mutex);
|
||||
m_async_packet.assign(payload, payload_length);
|
||||
m_async_packet_predicate.SetValue (true, eBroadcastNever);
|
||||
|
||||
if (log)
|
||||
log->Printf ("async: async packet = %s", m_async_packet.c_str());
|
||||
|
||||
bool timed_out = false;
|
||||
bool sent_interrupt = false;
|
||||
if (SendInterrupt(locker, 2, sent_interrupt, timed_out))
|
||||
{
|
||||
if (sent_interrupt)
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: sent interrupt");
|
||||
if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: got response");
|
||||
response = m_async_response;
|
||||
return response.GetStringRef().size();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: timed out waiting for response");
|
||||
}
|
||||
|
||||
// Make sure we wait until the continue packet has been sent again...
|
||||
if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out))
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: timed out waiting for process to resume");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We had a racy condition where we went to send the interrupt
|
||||
// yet we were able to get the loc
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: failed to interrupt");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("mutex taken and send_async == false, aborting packet");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//template<typename _Tp>
|
||||
//class ScopedValueChanger
|
||||
//{
|
||||
//public:
|
||||
// // Take a value reference and the value to assign it to when this class
|
||||
// // instance goes out of scope.
|
||||
// ScopedValueChanger (_Tp &value_ref, _Tp value) :
|
||||
// m_value_ref (value_ref),
|
||||
// m_value (value)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// // This object is going out of scope, change the value pointed to by
|
||||
// // m_value_ref to the value we got during construction which was stored in
|
||||
// // m_value;
|
||||
// ~ScopedValueChanger ()
|
||||
// {
|
||||
// m_value_ref = m_value;
|
||||
// }
|
||||
//protected:
|
||||
// _Tp &m_value_ref; // A reference to the value we will change when this object destructs
|
||||
// _Tp m_value; // The value to assign to m_value_ref when this goes out of scope.
|
||||
//};
|
||||
|
||||
StateType
|
||||
GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
|
||||
(
|
||||
ProcessGDBRemote *process,
|
||||
const char *payload,
|
||||
size_t packet_length,
|
||||
StringExtractorGDBRemote &response
|
||||
)
|
||||
{
|
||||
LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
|
||||
|
||||
Mutex::Locker locker(m_sequence_mutex);
|
||||
StateType state = eStateRunning;
|
||||
|
||||
BroadcastEvent(eBroadcastBitRunPacketSent, NULL);
|
||||
m_public_is_running.SetValue (true, eBroadcastNever);
|
||||
// Set the starting continue packet into "continue_packet". This packet
|
||||
// make change if we are interrupted and we continue after an async packet...
|
||||
std::string continue_packet(payload, packet_length);
|
||||
|
||||
while (state == eStateRunning)
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str());
|
||||
if (SendPacket(continue_packet.c_str(), continue_packet.size()) == 0)
|
||||
state = eStateInvalid;
|
||||
|
||||
m_private_is_running.SetValue (true, eBroadcastNever);
|
||||
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%.*s)", __FUNCTION__);
|
||||
|
||||
if (WaitForPacket (response, (TimeValue*)NULL))
|
||||
{
|
||||
if (response.Empty())
|
||||
state = eStateInvalid;
|
||||
else
|
||||
{
|
||||
const char stop_type = response.GetChar();
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str());
|
||||
switch (stop_type)
|
||||
{
|
||||
case 'T':
|
||||
case 'S':
|
||||
if (process->GetStopID() == 0)
|
||||
{
|
||||
if (process->GetID() == LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
lldb::pid_t pid = GetCurrentProcessID ();
|
||||
if (pid != LLDB_INVALID_PROCESS_ID)
|
||||
process->SetID (pid);
|
||||
}
|
||||
process->BuildDynamicRegisterInfo (true);
|
||||
}
|
||||
|
||||
// Privately notify any internal threads that we have stopped
|
||||
// in case we wanted to interrupt our process, yet we might
|
||||
// send a packet and continue without returning control to the
|
||||
// user.
|
||||
m_private_is_running.SetValue (false, eBroadcastAlways);
|
||||
if (m_async_signal != -1)
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal));
|
||||
|
||||
// Save off the async signal we are supposed to send
|
||||
const int async_signal = m_async_signal;
|
||||
// Clear the async signal member so we don't end up
|
||||
// sending the signal multiple times...
|
||||
m_async_signal = -1;
|
||||
// Check which signal we stopped with
|
||||
uint8_t signo = response.GetHexU8(255);
|
||||
if (signo == async_signal)
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo));
|
||||
|
||||
// We already stopped with a signal that we wanted
|
||||
// to stop with, so we are done
|
||||
response.SetFilePos (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We stopped with a different signal that the one
|
||||
// we wanted to stop with, so now we must resume
|
||||
// with the signal we want
|
||||
char signal_packet[32];
|
||||
int signal_packet_len = 0;
|
||||
signal_packet_len = ::snprintf (signal_packet,
|
||||
sizeof (signal_packet),
|
||||
"C%2.2x",
|
||||
async_signal);
|
||||
|
||||
if (log)
|
||||
log->Printf ("async: stopped with signal %s, resume with %s",
|
||||
Host::GetSignalAsCString (signo),
|
||||
Host::GetSignalAsCString (async_signal));
|
||||
|
||||
// Set the continue packet to resume...
|
||||
continue_packet.assign(signal_packet, signal_packet_len);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (m_async_packet_predicate.GetValue())
|
||||
{
|
||||
// We are supposed to send an asynchronous packet while
|
||||
// we are running.
|
||||
m_async_response.Clear();
|
||||
if (m_async_packet.empty())
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: error: empty async packet");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("async: sending packet: %s",
|
||||
m_async_packet.c_str());
|
||||
|
||||
SendPacketAndWaitForResponse (&m_async_packet[0],
|
||||
m_async_packet.size(),
|
||||
m_async_response,
|
||||
false);
|
||||
}
|
||||
// Let the other thread that was trying to send the async
|
||||
// packet know that the packet has been sent and response is
|
||||
// ready...
|
||||
m_async_packet_predicate.SetValue(false, eBroadcastAlways);
|
||||
|
||||
// Set the continue packet to resume...
|
||||
continue_packet.assign (1, 'c');
|
||||
continue;
|
||||
}
|
||||
// Stop with signal and thread info
|
||||
state = eStateStopped;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
case 'X':
|
||||
// process exited
|
||||
state = eStateExited;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
// STDOUT
|
||||
{
|
||||
std::string inferior_stdout;
|
||||
inferior_stdout.reserve(response.GetBytesLeft () / 2);
|
||||
char ch;
|
||||
while ((ch = response.GetHexU8()) != '\0')
|
||||
inferior_stdout.append(1, ch);
|
||||
process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size());
|
||||
}
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
// ERROR
|
||||
state = eStateInvalid;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__);
|
||||
state = eStateInvalid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__);
|
||||
state = eStateInvalid;
|
||||
}
|
||||
}
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state));
|
||||
response.SetFilePos(0);
|
||||
m_private_is_running.SetValue (false, eBroadcastAlways);
|
||||
m_public_is_running.SetValue (false, eBroadcastAlways);
|
||||
return state;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::SendAsyncSignal (int signo)
|
||||
{
|
||||
m_async_signal = signo;
|
||||
bool timed_out = false;
|
||||
bool sent_interrupt = false;
|
||||
Mutex::Locker locker;
|
||||
if (SendInterrupt (locker, 1, sent_interrupt, timed_out))
|
||||
return true;
|
||||
m_async_signal = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This function takes a mutex locker as a parameter in case the GetSequenceMutex
|
||||
// actually succeeds. If it doesn't succeed in acquiring the sequence mutex
|
||||
// (the expected result), then it will send the halt packet. If it does succeed
|
||||
// then the caller that requested the interrupt will want to keep the sequence
|
||||
// locked down so that no one else can send packets while the caller has control.
|
||||
// This function usually gets called when we are running and need to stop the
|
||||
// target. It can also be used when we are running and and we need to do something
|
||||
// else (like read/write memory), so we need to interrupt the running process
|
||||
// (gdb remote protocol requires this), and do what we need to do, then resume.
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::SendInterrupt
|
||||
(
|
||||
Mutex::Locker& locker,
|
||||
uint32_t seconds_to_wait_for_stop,
|
||||
bool &sent_interrupt,
|
||||
bool &timed_out
|
||||
)
|
||||
{
|
||||
sent_interrupt = false;
|
||||
timed_out = false;
|
||||
LogSP log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
|
||||
|
||||
if (IsRunning())
|
||||
{
|
||||
// Only send an interrupt if our debugserver is running...
|
||||
if (GetSequenceMutex (locker) == false)
|
||||
{
|
||||
// Someone has the mutex locked waiting for a response or for the
|
||||
// inferior to stop, so send the interrupt on the down low...
|
||||
char ctrl_c = '\x03';
|
||||
ConnectionStatus status = eConnectionStatusSuccess;
|
||||
TimeValue timeout;
|
||||
if (seconds_to_wait_for_stop)
|
||||
{
|
||||
timeout = TimeValue::Now();
|
||||
timeout.OffsetWithSeconds (seconds_to_wait_for_stop);
|
||||
}
|
||||
size_t bytes_written = Write (&ctrl_c, 1, status, NULL);
|
||||
ProcessGDBRemoteLog::LogIf (GDBR_LOG_PACKETS | GDBR_LOG_PROCESS, "send packet: \\x03");
|
||||
if (bytes_written > 0)
|
||||
{
|
||||
sent_interrupt = true;
|
||||
if (seconds_to_wait_for_stop)
|
||||
{
|
||||
if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out))
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, private state stopped", __FUNCTION__);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, timed out wating for async thread resume", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () - sent interrupt, not waiting for stop...", __FUNCTION__);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () - failed to write interrupt", __FUNCTION__);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("GDBRemoteCommunicationClient::%s () - got sequence mutex without having to interrupt", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
lldb::pid_t
|
||||
GDBRemoteCommunicationClient::GetCurrentProcessID ()
|
||||
{
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false))
|
||||
{
|
||||
if (response.GetChar() == 'Q')
|
||||
if (response.GetChar() == 'C')
|
||||
return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
|
||||
}
|
||||
return LLDB_INVALID_PROCESS_ID;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str)
|
||||
{
|
||||
error_str.clear();
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return true;
|
||||
if (response.GetChar() == 'E')
|
||||
{
|
||||
// A string the describes what failed when launching...
|
||||
error_str = response.GetStringRef().substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_str.assign ("unknown error occurred launching process");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error_str.assign ("failed to send the qLaunchSuccess packet");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[])
|
||||
{
|
||||
if (argv && argv[0])
|
||||
{
|
||||
StreamString packet;
|
||||
packet.PutChar('A');
|
||||
const char *arg;
|
||||
for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i)
|
||||
{
|
||||
const int arg_len = strlen(arg);
|
||||
if (i > 0)
|
||||
packet.PutChar(',');
|
||||
packet.Printf("%i,%i,", arg_len * 2, i);
|
||||
packet.PutBytesAsRawHex8 (arg, arg_len);
|
||||
}
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return 0;
|
||||
uint8_t error = response.GetError();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value)
|
||||
{
|
||||
if (name_equal_value && name_equal_value[0])
|
||||
{
|
||||
StreamString packet;
|
||||
packet.Printf("QEnvironment:%s", name_equal_value);
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return 0;
|
||||
uint8_t error = response.GetError();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::GetHostInfo ()
|
||||
{
|
||||
if (m_supports_qHostInfo == eLazyBoolCalculate)
|
||||
{
|
||||
m_supports_qHostInfo = eLazyBoolNo;
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse ("qHostInfo", response, false))
|
||||
{
|
||||
if (response.IsUnsupportedResponse())
|
||||
return false;
|
||||
|
||||
m_supports_qHostInfo = eLazyBoolYes;
|
||||
|
||||
std::string name;
|
||||
std::string value;
|
||||
uint32_t cpu = LLDB_INVALID_CPUTYPE;
|
||||
uint32_t sub = 0;
|
||||
|
||||
while (response.GetNameColonValue(name, value))
|
||||
{
|
||||
if (name.compare("cputype") == 0)
|
||||
{
|
||||
// exception type in big endian hex
|
||||
cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0);
|
||||
}
|
||||
else if (name.compare("cpusubtype") == 0)
|
||||
{
|
||||
// exception count in big endian hex
|
||||
sub = Args::StringToUInt32 (value.c_str(), 0, 0);
|
||||
}
|
||||
else if (name.compare("ostype") == 0)
|
||||
{
|
||||
// exception data in big endian hex
|
||||
m_os.SetCString(value.c_str());
|
||||
}
|
||||
else if (name.compare("vendor") == 0)
|
||||
{
|
||||
m_vendor.SetCString(value.c_str());
|
||||
}
|
||||
else if (name.compare("endian") == 0)
|
||||
{
|
||||
if (value.compare("little") == 0)
|
||||
m_byte_order = eByteOrderLittle;
|
||||
else if (value.compare("big") == 0)
|
||||
m_byte_order = eByteOrderBig;
|
||||
else if (value.compare("pdp") == 0)
|
||||
m_byte_order = eByteOrderPDP;
|
||||
}
|
||||
else if (name.compare("ptrsize") == 0)
|
||||
{
|
||||
m_pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (cpu != LLDB_INVALID_CPUTYPE)
|
||||
m_arch.SetArchitecture (lldb::eArchTypeMachO, cpu, sub);
|
||||
}
|
||||
}
|
||||
return m_supports_qHostInfo == eLazyBoolYes;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SendAttach
|
||||
(
|
||||
lldb::pid_t pid,
|
||||
StringExtractorGDBRemote& response
|
||||
)
|
||||
{
|
||||
if (pid != LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
StreamString packet;
|
||||
packet.Printf("vAttach;%x", pid);
|
||||
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsErrorResponse())
|
||||
return response.GetError();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const lldb_private::ArchSpec &
|
||||
GDBRemoteCommunicationClient::GetHostArchitecture ()
|
||||
{
|
||||
if (!HostInfoIsValid ())
|
||||
GetHostInfo ();
|
||||
return m_arch;
|
||||
}
|
||||
|
||||
const lldb_private::ConstString &
|
||||
GDBRemoteCommunicationClient::GetOSString ()
|
||||
{
|
||||
if (!HostInfoIsValid ())
|
||||
GetHostInfo ();
|
||||
return m_os;
|
||||
}
|
||||
|
||||
const lldb_private::ConstString &
|
||||
GDBRemoteCommunicationClient::GetVendorString()
|
||||
{
|
||||
if (!HostInfoIsValid ())
|
||||
GetHostInfo ();
|
||||
return m_vendor;
|
||||
}
|
||||
|
||||
lldb::ByteOrder
|
||||
GDBRemoteCommunicationClient::GetByteOrder ()
|
||||
{
|
||||
if (!HostInfoIsValid ())
|
||||
GetHostInfo ();
|
||||
return m_byte_order;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GDBRemoteCommunicationClient::GetAddressByteSize ()
|
||||
{
|
||||
if (!HostInfoIsValid ())
|
||||
GetHostInfo ();
|
||||
return m_pointer_byte_size;
|
||||
}
|
||||
|
||||
addr_t
|
||||
GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions)
|
||||
{
|
||||
char packet[64];
|
||||
::snprintf (packet, sizeof(packet), "_M%zx,%s%s%s", size,
|
||||
permissions & lldb::ePermissionsReadable ? "r" : "",
|
||||
permissions & lldb::ePermissionsWritable ? "w" : "",
|
||||
permissions & lldb::ePermissionsExecutable ? "x" : "");
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet, response, false))
|
||||
{
|
||||
if (!response.IsErrorResponse())
|
||||
return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
|
||||
}
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)
|
||||
{
|
||||
char packet[64];
|
||||
snprintf(packet, sizeof(packet), "_m%llx", (uint64_t)addr);
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet, response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SetSTDIN (char const *path)
|
||||
{
|
||||
if (path && path[0])
|
||||
{
|
||||
StreamString packet;
|
||||
packet.PutCString("QSetSTDIN:");
|
||||
packet.PutBytesAsRawHex8(path, strlen(path));
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return 0;
|
||||
uint8_t error = response.GetError();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SetSTDOUT (char const *path)
|
||||
{
|
||||
if (path && path[0])
|
||||
{
|
||||
StreamString packet;
|
||||
packet.PutCString("QSetSTDOUT:");
|
||||
packet.PutBytesAsRawHex8(path, strlen(path));
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return 0;
|
||||
uint8_t error = response.GetError();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SetSTDERR (char const *path)
|
||||
{
|
||||
if (path && path[0])
|
||||
{
|
||||
StreamString packet;
|
||||
packet.PutCString("QSetSTDERR:");
|
||||
packet.PutBytesAsRawHex8(path, strlen(path));
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return 0;
|
||||
uint8_t error = response.GetError();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SetWorkingDir (char const *path)
|
||||
{
|
||||
if (path && path[0])
|
||||
{
|
||||
StreamString packet;
|
||||
packet.PutCString("QSetWorkingDir:");
|
||||
packet.PutBytesAsRawHex8(path, strlen(path));
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return 0;
|
||||
uint8_t error = response.GetError();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
GDBRemoteCommunicationClient::SetDisableASLR (bool enable)
|
||||
{
|
||||
StreamString packet;
|
||||
packet.Printf("QSetDisableASLR:%i", enable ? 1 : 0);
|
||||
|
||||
StringExtractorGDBRemote response;
|
||||
if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
|
||||
{
|
||||
if (response.IsOKResponse())
|
||||
return 0;
|
||||
uint8_t error = response.GetError();
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
//===-- GDBRemoteCommunicationClient.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_GDBRemoteCommunicationClient_h_
|
||||
#define liblldb_GDBRemoteCommunicationClient_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
|
||||
#include "GDBRemoteCommunication.h"
|
||||
|
||||
class GDBRemoteCommunicationClient : public GDBRemoteCommunication
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
GDBRemoteCommunicationClient();
|
||||
|
||||
virtual
|
||||
~GDBRemoteCommunicationClient();
|
||||
|
||||
size_t
|
||||
SendPacketAndWaitForResponse (const char *send_payload,
|
||||
StringExtractorGDBRemote &response,
|
||||
bool send_async);
|
||||
|
||||
size_t
|
||||
SendPacketAndWaitForResponse (const char *send_payload,
|
||||
size_t send_length,
|
||||
StringExtractorGDBRemote &response,
|
||||
bool send_async);
|
||||
|
||||
lldb::StateType
|
||||
SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,
|
||||
const char *packet_payload,
|
||||
size_t packet_length,
|
||||
StringExtractorGDBRemote &response);
|
||||
|
||||
virtual bool
|
||||
GetThreadSuffixSupported ();
|
||||
|
||||
virtual bool
|
||||
GetSendAcks ();
|
||||
|
||||
bool
|
||||
SendAsyncSignal (int signo);
|
||||
|
||||
bool
|
||||
SendInterrupt (lldb_private::Mutex::Locker &locker,
|
||||
uint32_t seconds_to_wait_for_stop,
|
||||
bool &sent_interrupt,
|
||||
bool &timed_out);
|
||||
|
||||
lldb::pid_t
|
||||
GetCurrentProcessID ();
|
||||
|
||||
bool
|
||||
GetLaunchSuccess (std::string &error_str);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sends a GDB remote protocol 'A' packet that delivers program
|
||||
/// arguments to the remote server.
|
||||
///
|
||||
/// @param[in] argv
|
||||
/// A NULL terminated array of const C strings to use as the
|
||||
/// arguments.
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the response was "OK", a positive value if the
|
||||
/// the response was "Exx" where xx are two hex digits, or
|
||||
/// -1 if the call is unsupported or any other unexpected
|
||||
/// response was received.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SendArgumentsPacket (char const *argv[]);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
|
||||
/// environment that will get used when launching an application
|
||||
/// in conjunction with the 'A' packet. This function can be called
|
||||
/// multiple times in a row in order to pass on the desired
|
||||
/// environment that the inferior should be launched with.
|
||||
///
|
||||
/// @param[in] name_equal_value
|
||||
/// A NULL terminated C string that contains a single environment
|
||||
/// in the format "NAME=VALUE".
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the response was "OK", a positive value if the
|
||||
/// the response was "Exx" where xx are two hex digits, or
|
||||
/// -1 if the call is unsupported or any other unexpected
|
||||
/// response was received.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SendEnvironmentPacket (char const *name_equal_value);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sends a "vAttach:PID" where PID is in hex.
|
||||
///
|
||||
/// @param[in] pid
|
||||
/// A process ID for the remote gdb server to attach to.
|
||||
///
|
||||
/// @param[out] response
|
||||
/// The response received from the gdb server. If the return
|
||||
/// value is zero, \a response will contain a stop reply
|
||||
/// packet.
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the attach was successful, or an error indicating
|
||||
/// an error code.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SendAttach (lldb::pid_t pid,
|
||||
StringExtractorGDBRemote& response);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets the path to use for stdin/out/err for a process
|
||||
/// that will be launched with the 'A' packet.
|
||||
///
|
||||
/// @param[in] path
|
||||
/// The path to use for stdin/out/err
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the for success, or an error code for failure.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SetSTDIN (char const *path);
|
||||
int
|
||||
SetSTDOUT (char const *path);
|
||||
int
|
||||
SetSTDERR (char const *path);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets the disable ASLR flag to \a enable for a process that will
|
||||
/// be launched with the 'A' packet.
|
||||
///
|
||||
/// @param[in] enable
|
||||
/// A boolean value indicating wether to disable ASLR or not.
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the for success, or an error code for failure.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SetDisableASLR (bool enable);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Sets the working directory to \a path for a process that will
|
||||
/// be launched with the 'A' packet.
|
||||
///
|
||||
/// @param[in] path
|
||||
/// The path to a directory to use when launching our processs
|
||||
///
|
||||
/// @return
|
||||
/// Zero if the for success, or an error code for failure.
|
||||
//------------------------------------------------------------------
|
||||
int
|
||||
SetWorkingDir (char const *path);
|
||||
|
||||
lldb::addr_t
|
||||
AllocateMemory (size_t size, uint32_t permissions);
|
||||
|
||||
bool
|
||||
DeallocateMemory (lldb::addr_t addr);
|
||||
|
||||
const lldb_private::ArchSpec &
|
||||
GetHostArchitecture ();
|
||||
|
||||
const lldb_private::ConstString &
|
||||
GetOSString ();
|
||||
|
||||
const lldb_private::ConstString &
|
||||
GetVendorString();
|
||||
|
||||
lldb::ByteOrder
|
||||
GetByteOrder ();
|
||||
|
||||
uint32_t
|
||||
GetAddressByteSize ();
|
||||
|
||||
bool
|
||||
GetVContSupported (char flavor);
|
||||
|
||||
void
|
||||
ResetDiscoverableSettings();
|
||||
|
||||
bool
|
||||
GetHostInfo ();
|
||||
|
||||
bool
|
||||
GetSupportsThreadSuffix ();
|
||||
|
||||
bool
|
||||
HasFullVContSupport ()
|
||||
{
|
||||
return GetVContSupported ('A');
|
||||
}
|
||||
|
||||
bool
|
||||
HasAnyVContSupport ()
|
||||
{
|
||||
return GetVContSupported ('a');
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SetPacketTimeout (uint32_t packet_timeout)
|
||||
{
|
||||
const uint32_t old_packet_timeout = m_packet_timeout;
|
||||
m_packet_timeout = packet_timeout;
|
||||
return old_packet_timeout;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool
|
||||
HostInfoIsValid () const
|
||||
{
|
||||
return m_supports_qHostInfo != lldb::eLazyBoolCalculate;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Classes that inherit from GDBRemoteCommunicationClient can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
lldb::LazyBool m_supports_not_sending_acks;
|
||||
lldb::LazyBool m_supports_thread_suffix;
|
||||
lldb::LazyBool m_supports_qHostInfo;
|
||||
lldb::LazyBool m_supports_vCont_all;
|
||||
lldb::LazyBool m_supports_vCont_any;
|
||||
lldb::LazyBool m_supports_vCont_c;
|
||||
lldb::LazyBool m_supports_vCont_C;
|
||||
lldb::LazyBool m_supports_vCont_s;
|
||||
lldb::LazyBool m_supports_vCont_S;
|
||||
|
||||
// If we need to send a packet while the target is running, the m_async_XXX
|
||||
// member variables take care of making this happen.
|
||||
lldb_private::Mutex m_async_mutex;
|
||||
lldb_private::Predicate<bool> m_async_packet_predicate;
|
||||
std::string m_async_packet;
|
||||
StringExtractorGDBRemote m_async_response;
|
||||
int m_async_signal; // We were asked to deliver a signal to the inferior process.
|
||||
|
||||
lldb_private::ArchSpec m_arch;
|
||||
uint32_t m_cpusubtype;
|
||||
lldb_private::ConstString m_os;
|
||||
lldb_private::ConstString m_vendor;
|
||||
lldb::ByteOrder m_byte_order;
|
||||
uint32_t m_pointer_byte_size;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// For GDBRemoteCommunicationClient only
|
||||
//------------------------------------------------------------------
|
||||
DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient);
|
||||
};
|
||||
|
||||
#endif // liblldb_GDBRemoteCommunicationClient_h_
|
|
@ -0,0 +1,134 @@
|
|||
//===-- 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 "GDBRemoteCommunicationServer.h"
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "lldb/Interpreter/Args.h"
|
||||
#include "lldb/Core/ConnectionFileDescriptor.h"
|
||||
#include "lldb/Core/Log.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Host/TimeValue.h"
|
||||
|
||||
// Project includes
|
||||
#include "Utility/StringExtractorGDBRemote.h"
|
||||
#include "ProcessGDBRemote.h"
|
||||
#include "ProcessGDBRemoteLog.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// GDBRemoteCommunicationServer constructor
|
||||
//----------------------------------------------------------------------
|
||||
GDBRemoteCommunicationServer::GDBRemoteCommunicationServer() :
|
||||
GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet"),
|
||||
m_async_thread (LLDB_INVALID_HOST_THREAD),
|
||||
m_send_acks (true)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Destructor
|
||||
//----------------------------------------------------------------------
|
||||
GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//void *
|
||||
//GDBRemoteCommunicationServer::AsyncThread (void *arg)
|
||||
//{
|
||||
// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
|
||||
//
|
||||
// LogSP log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
|
||||
// if (log)
|
||||
// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
|
||||
//
|
||||
// StringExtractorGDBRemote packet;
|
||||
//
|
||||
// while ()
|
||||
// {
|
||||
// if (packet.
|
||||
// }
|
||||
//
|
||||
// if (log)
|
||||
// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
|
||||
//
|
||||
// process->m_async_thread = LLDB_INVALID_HOST_THREAD;
|
||||
// return NULL;
|
||||
//}
|
||||
//
|
||||
bool
|
||||
GDBRemoteCommunicationServer::GetPacketAndSendResponse (const TimeValue* timeout_time_ptr)
|
||||
{
|
||||
StringExtractorGDBRemote packet;
|
||||
if (WaitForPacketNoLock (packet, timeout_time_ptr))
|
||||
{
|
||||
const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
|
||||
switch (packet_type)
|
||||
{
|
||||
case StringExtractorGDBRemote::eServerPacketType_nack:
|
||||
case StringExtractorGDBRemote::eServerPacketType_ack:
|
||||
break;
|
||||
|
||||
case StringExtractorGDBRemote::eServerPacketType_invalid:
|
||||
case StringExtractorGDBRemote::eServerPacketType_unimplemented:
|
||||
return SendUnimplementedResponse () > 0;
|
||||
|
||||
case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
|
||||
return Handle_qHostInfo ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t
|
||||
GDBRemoteCommunicationServer::SendUnimplementedResponse ()
|
||||
{
|
||||
return SendPacket ("");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GDBRemoteCommunicationServer::Handle_qHostInfo ()
|
||||
{
|
||||
StreamString response;
|
||||
|
||||
// $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
|
||||
|
||||
ArchSpec host_arch (Host::GetArchitecture ());
|
||||
|
||||
const llvm::Triple &host_triple = host_arch.GetTriple();
|
||||
const llvm::StringRef arch_name (host_triple.getArchName());
|
||||
const llvm::StringRef vendor_name (host_triple.getOSName());
|
||||
const llvm::StringRef os_name (host_triple.getVendorName());
|
||||
response.Printf ("arch:%.*s;ostype:%.*s;vendor:%.*s;ptrsize:%u",
|
||||
(int)arch_name.size(), arch_name.data(),
|
||||
(int)os_name.size(), os_name.data(),
|
||||
(int)vendor_name.size(), vendor_name.data(),
|
||||
host_arch.GetAddressByteSize());
|
||||
|
||||
switch (lldb::endian::InlHostByteOrder())
|
||||
{
|
||||
case eByteOrderBig: response.PutCString ("endian:big;"); break;
|
||||
case eByteOrderLittle: response.PutCString ("endian:little;"); break;
|
||||
case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
|
||||
default: response.PutCString ("endian:unknown;"); break;
|
||||
}
|
||||
|
||||
return SendPacket (response.GetString().c_str(),response.GetString().size()) > 0;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
//===-- 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
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "GDBRemoteCommunication.h"
|
||||
|
||||
class ProcessGDBRemote;
|
||||
|
||||
class GDBRemoteCommunicationServer : public GDBRemoteCommunication
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
eBroadcastBitRunPacketSent = kLoUserBroadcastBit
|
||||
};
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
GDBRemoteCommunicationServer();
|
||||
|
||||
virtual
|
||||
~GDBRemoteCommunicationServer();
|
||||
|
||||
bool
|
||||
GetPacketAndSendResponse (const lldb_private::TimeValue* timeout_time_ptr);
|
||||
|
||||
virtual bool
|
||||
GetThreadSuffixSupported ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
GetSendAcks ()
|
||||
{
|
||||
return m_send_acks;
|
||||
}
|
||||
|
||||
protected:
|
||||
lldb::thread_t m_async_thread;
|
||||
bool m_send_acks;
|
||||
|
||||
size_t
|
||||
SendUnimplementedResponse ();
|
||||
|
||||
|
||||
bool
|
||||
Handle_qHostInfo ();
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// For GDBRemoteCommunicationServer only
|
||||
//------------------------------------------------------------------
|
||||
DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer);
|
||||
};
|
||||
|
||||
#endif // liblldb_GDBRemoteCommunicationServer_h_
|
|
@ -208,7 +208,7 @@ GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor
|
|||
bool
|
||||
GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
|
||||
{
|
||||
GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
|
||||
GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote());
|
||||
|
||||
InvalidateIfNeeded(false);
|
||||
|
||||
|
@ -235,7 +235,7 @@ GDBRemoteRegisterContext::ReadRegisterBytes (uint32_t reg, DataExtractor &data)
|
|||
assert (packet_len < (sizeof(packet) - 1));
|
||||
if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
|
||||
{
|
||||
if (response.IsNormalPacket())
|
||||
if (response.IsNormalResponse())
|
||||
if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
|
||||
SetAllRegisterValid (true);
|
||||
}
|
||||
|
@ -290,7 +290,7 @@ GDBRemoteRegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
|
|||
bool
|
||||
GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data, uint32_t data_offset)
|
||||
{
|
||||
GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
|
||||
GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote());
|
||||
// FIXME: This check isn't right because IsRunning checks the Public state, but this
|
||||
// is work you need to do - for instance in ShouldStop & friends - before the public
|
||||
// state has been changed.
|
||||
|
@ -358,7 +358,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data,
|
|||
false))
|
||||
{
|
||||
SetAllRegisterValid (false);
|
||||
if (response.IsOKPacket())
|
||||
if (response.IsOKResponse())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data,
|
|||
response,
|
||||
false))
|
||||
{
|
||||
if (response.IsOKPacket())
|
||||
if (response.IsOKResponse())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -399,7 +399,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (uint32_t reg, DataExtractor &data,
|
|||
bool
|
||||
GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
|
||||
{
|
||||
GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
|
||||
GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote());
|
||||
StringExtractorGDBRemote response;
|
||||
|
||||
Mutex::Locker locker;
|
||||
|
@ -418,7 +418,7 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
|
|||
|
||||
if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
|
||||
{
|
||||
if (response.IsErrorPacket())
|
||||
if (response.IsErrorResponse())
|
||||
return false;
|
||||
|
||||
response.GetStringRef().insert(0, 1, 'G');
|
||||
|
@ -443,7 +443,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
|
|||
if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0)
|
||||
return false;
|
||||
|
||||
GDBRemoteCommunication &gdb_comm = GetGDBProcess().GetGDBRemote();
|
||||
GDBRemoteCommunicationClient &gdb_comm (GetGDBProcess().GetGDBRemote());
|
||||
StringExtractorGDBRemote response;
|
||||
Mutex::Locker locker;
|
||||
if (gdb_comm.GetSequenceMutex (locker))
|
||||
|
@ -456,7 +456,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data
|
|||
response,
|
||||
false))
|
||||
{
|
||||
if (response.IsOKPacket())
|
||||
if (response.IsOKResponse())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,18 +170,20 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
|
|||
|
||||
char packet[128];
|
||||
m_register_info.Clear();
|
||||
StringExtractorGDBRemote::Type packet_type = StringExtractorGDBRemote::eResponse;
|
||||
uint32_t reg_offset = 0;
|
||||
uint32_t reg_num = 0;
|
||||
for (; packet_type == StringExtractorGDBRemote::eResponse; ++reg_num)
|
||||
StringExtractorGDBRemote::ResponseType response_type;
|
||||
for (response_type = StringExtractorGDBRemote::eResponse;
|
||||
response_type == StringExtractorGDBRemote::eResponse;
|
||||
++reg_num)
|
||||
{
|
||||
const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num);
|
||||
assert (packet_len < sizeof(packet));
|
||||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
|
||||
{
|
||||
packet_type = response.GetType();
|
||||
if (packet_type == StringExtractorGDBRemote::eResponse)
|
||||
response_type = response.GetResponseType();
|
||||
if (response_type == StringExtractorGDBRemote::eResponse)
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
@ -298,7 +300,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
|
|||
}
|
||||
else
|
||||
{
|
||||
packet_type = StringExtractorGDBRemote::eError;
|
||||
response_type = StringExtractorGDBRemote::eError;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1046,7 @@ ProcessGDBRemote::UpdateThreadListIfNeeded ()
|
|||
Error err;
|
||||
StringExtractorGDBRemote response;
|
||||
for (m_gdb_comm.SendPacketAndWaitForResponse("qfThreadInfo", response, false);
|
||||
response.IsNormalPacket();
|
||||
response.IsNormalResponse();
|
||||
m_gdb_comm.SendPacketAndWaitForResponse("qsThreadInfo", response, false))
|
||||
{
|
||||
char ch = response.GetChar();
|
||||
|
@ -1460,7 +1462,7 @@ ProcessGDBRemote::GetImageInfoAddress()
|
|||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false))
|
||||
{
|
||||
if (response.IsNormalPacket())
|
||||
if (response.IsNormalResponse())
|
||||
return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
|
||||
}
|
||||
}
|
||||
|
@ -1487,14 +1489,14 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro
|
|||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true))
|
||||
{
|
||||
if (response.IsNormalPacket())
|
||||
if (response.IsNormalResponse())
|
||||
{
|
||||
error.Clear();
|
||||
return response.GetHexBytes(buf, size, '\xdd');
|
||||
}
|
||||
else if (response.IsErrorPacket())
|
||||
else if (response.IsErrorResponse())
|
||||
error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str());
|
||||
else if (response.IsUnsupportedPacket())
|
||||
else if (response.IsUnsupportedResponse())
|
||||
error.SetErrorStringWithFormat("'%s' packet unsupported", packet);
|
||||
else
|
||||
error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet, response.GetStringRef().c_str());
|
||||
|
@ -1515,14 +1517,14 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro
|
|||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true))
|
||||
{
|
||||
if (response.IsOKPacket())
|
||||
if (response.IsOKResponse())
|
||||
{
|
||||
error.Clear();
|
||||
return size;
|
||||
}
|
||||
else if (response.IsErrorPacket())
|
||||
else if (response.IsErrorResponse())
|
||||
error.SetErrorStringWithFormat("gdb remote returned an error: %s", response.GetStringRef().c_str());
|
||||
else if (response.IsUnsupportedPacket())
|
||||
else if (response.IsUnsupportedResponse())
|
||||
error.SetErrorStringWithFormat("'%s' packet unsupported", packet.GetString().c_str());
|
||||
else
|
||||
error.SetErrorStringWithFormat("unexpected response to '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str());
|
||||
|
@ -1640,13 +1642,13 @@ ProcessGDBRemote::EnableBreakpoint (BreakpointSite *bp_site)
|
|||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true))
|
||||
{
|
||||
if (response.IsUnsupportedPacket())
|
||||
if (response.IsUnsupportedResponse())
|
||||
{
|
||||
// Disable z packet support and try again
|
||||
m_z0_supported = 0;
|
||||
return EnableBreakpoint (bp_site);
|
||||
}
|
||||
else if (response.IsOKPacket())
|
||||
else if (response.IsOKResponse())
|
||||
{
|
||||
bp_site->SetEnabled(true);
|
||||
bp_site->SetType (BreakpointSite::eExternal);
|
||||
|
@ -1708,11 +1710,11 @@ ProcessGDBRemote::DisableBreakpoint (BreakpointSite *bp_site)
|
|||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true))
|
||||
{
|
||||
if (response.IsUnsupportedPacket())
|
||||
if (response.IsUnsupportedResponse())
|
||||
{
|
||||
error.SetErrorString("Breakpoint site was set with Z packet, yet remote debugserver states z packets are not supported.");
|
||||
}
|
||||
else if (response.IsOKPacket())
|
||||
else if (response.IsOKResponse())
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("ProcessGDBRemote::DisableBreakpoint (site_id = %d) addr = 0x%8.8llx -- SUCCESS", site_id, (uint64_t)addr);
|
||||
|
@ -2121,7 +2123,7 @@ ProcessGDBRemote::SetCurrentGDBRemoteThread (int tid)
|
|||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
|
||||
{
|
||||
if (response.IsOKPacket())
|
||||
if (response.IsOKResponse())
|
||||
{
|
||||
m_curr_tid = tid;
|
||||
return true;
|
||||
|
@ -2147,7 +2149,7 @@ ProcessGDBRemote::SetCurrentGDBRemoteThreadForRun (int tid)
|
|||
StringExtractorGDBRemote response;
|
||||
if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
|
||||
{
|
||||
if (response.IsOKPacket())
|
||||
if (response.IsOKResponse())
|
||||
{
|
||||
m_curr_tid_run = tid;
|
||||
return true;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
|
||||
#include "GDBRemoteCommunication.h"
|
||||
#include "GDBRemoteCommunicationClient.h"
|
||||
#include "Utility/StringExtractor.h"
|
||||
#include "GDBRemoteRegisterContext.h"
|
||||
|
||||
|
@ -212,7 +212,7 @@ public:
|
|||
|
||||
protected:
|
||||
friend class ThreadGDBRemote;
|
||||
friend class GDBRemoteCommunication;
|
||||
friend class GDBRemoteCommunicationClient;
|
||||
friend class GDBRemoteRegisterContext;
|
||||
|
||||
bool
|
||||
|
@ -289,7 +289,7 @@ protected:
|
|||
void
|
||||
BuildDynamicRegisterInfo (bool force);
|
||||
|
||||
GDBRemoteCommunication &
|
||||
GDBRemoteCommunicationClient &
|
||||
GetGDBRemote()
|
||||
{
|
||||
return m_gdb_comm;
|
||||
|
@ -306,7 +306,7 @@ protected:
|
|||
|
||||
lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
|
||||
lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio
|
||||
GDBRemoteCommunication m_gdb_comm;
|
||||
GDBRemoteCommunicationClient m_gdb_comm;
|
||||
lldb::pid_t m_debugserver_pid;
|
||||
lldb::thread_t m_debugserver_thread;
|
||||
StringExtractor m_last_stop_packet;
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
|
||||
|
||||
StringExtractorGDBRemote::Type
|
||||
StringExtractorGDBRemote::GetType () const
|
||||
StringExtractorGDBRemote::ResponseType
|
||||
StringExtractorGDBRemote::GetResponseType () const
|
||||
{
|
||||
if (m_packet.empty())
|
||||
return eUnsupported;
|
||||
|
@ -49,29 +49,57 @@ StringExtractorGDBRemote::GetType () const
|
|||
return eResponse;
|
||||
}
|
||||
|
||||
bool
|
||||
StringExtractorGDBRemote::IsOKPacket() const
|
||||
StringExtractorGDBRemote::ServerPacketType
|
||||
StringExtractorGDBRemote::GetServerPacketType () const
|
||||
{
|
||||
return GetType () == eOK;
|
||||
// Empty is not a supported packet...
|
||||
if (m_packet.empty())
|
||||
return eServerPacketType_invalid;
|
||||
|
||||
const char *packet_cstr = m_packet.c_str();
|
||||
switch (m_packet[0])
|
||||
{
|
||||
case '-':
|
||||
if (m_packet.size() == 1)
|
||||
return eServerPacketType_nack;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (m_packet.size() == 1)
|
||||
return eServerPacketType_ack;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
if (strcmp (packet_cstr, "qHostInfo") == 0)
|
||||
return eServerPacketType_qHostInfo;
|
||||
break;
|
||||
}
|
||||
return eServerPacketType_unimplemented;
|
||||
}
|
||||
|
||||
bool
|
||||
StringExtractorGDBRemote::IsOKResponse() const
|
||||
{
|
||||
return GetResponseType () == eOK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StringExtractorGDBRemote::IsUnsupportedPacket() const
|
||||
StringExtractorGDBRemote::IsUnsupportedResponse() const
|
||||
{
|
||||
return GetType () == eUnsupported;
|
||||
return GetResponseType () == eUnsupported;
|
||||
}
|
||||
|
||||
bool
|
||||
StringExtractorGDBRemote::IsNormalPacket() const
|
||||
StringExtractorGDBRemote::IsNormalResponse() const
|
||||
{
|
||||
return GetType () == eResponse;
|
||||
return GetResponseType () == eResponse;
|
||||
}
|
||||
|
||||
bool
|
||||
StringExtractorGDBRemote::IsErrorPacket() const
|
||||
StringExtractorGDBRemote::IsErrorResponse() const
|
||||
{
|
||||
return GetType () == eError &&
|
||||
return GetResponseType () == eError &&
|
||||
m_packet.size() == 3 &&
|
||||
isxdigit(m_packet[1]) &&
|
||||
isxdigit(m_packet[2]);
|
||||
|
@ -80,7 +108,7 @@ StringExtractorGDBRemote::IsErrorPacket() const
|
|||
uint8_t
|
||||
StringExtractorGDBRemote::GetError ()
|
||||
{
|
||||
if (GetType() == eError)
|
||||
if (GetResponseType() == eError)
|
||||
{
|
||||
SetFilePos(1);
|
||||
return GetHexU8(255);
|
||||
|
|
|
@ -39,30 +39,42 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
enum Type
|
||||
enum ServerPacketType
|
||||
{
|
||||
eServerPacketType_nack = 0,
|
||||
eServerPacketType_ack,
|
||||
eServerPacketType_invalid,
|
||||
eServerPacketType_unimplemented,
|
||||
eServerPacketType_qHostInfo
|
||||
};
|
||||
|
||||
ServerPacketType
|
||||
GetServerPacketType () const;
|
||||
|
||||
enum ResponseType
|
||||
{
|
||||
eUnsupported = 0,
|
||||
eAck,
|
||||
eNack,
|
||||
eError,
|
||||
eOK,
|
||||
eResponse
|
||||
eResponse,
|
||||
};
|
||||
|
||||
StringExtractorGDBRemote::Type
|
||||
GetType () const;
|
||||
ResponseType
|
||||
GetResponseType () const;
|
||||
|
||||
bool
|
||||
IsOKPacket() const;
|
||||
IsOKResponse() const;
|
||||
|
||||
bool
|
||||
IsUnsupportedPacket() const;
|
||||
IsUnsupportedResponse() const;
|
||||
|
||||
bool
|
||||
IsNormalPacket () const;
|
||||
IsNormalResponse () const;
|
||||
|
||||
bool
|
||||
IsErrorPacket() const;
|
||||
IsErrorResponse() const;
|
||||
|
||||
// Returns zero if the packet isn't a EXX packet where XX are two hex
|
||||
// digits. Otherwise the error encoded in XX is returned.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "GDBRemoteCommunication.h"
|
||||
#include "GDBRemoteCommunicationServer.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// option descriptors for getopt_long()
|
||||
|
@ -106,7 +106,7 @@ main (int argc, char *argv[])
|
|||
argv += optind;
|
||||
|
||||
|
||||
GDBRemoteCommunication gdb_comm;
|
||||
GDBRemoteCommunicationServer gdb_comm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue