summaryrefslogtreecommitdiffstats
path: root/source/Plugins/Process/gdb-remote
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/gdb-remote')
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp374
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h84
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp696
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h112
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp175
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h6
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp14
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h7
8 files changed, 1020 insertions, 448 deletions
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 2ac7d20..2690992 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -65,6 +65,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
m_attach_or_wait_reply(eLazyBoolCalculate),
m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
m_supports_p (eLazyBoolCalculate),
+ m_supports_QSaveRegisterState (eLazyBoolCalculate),
m_supports_qProcessInfoPID (true),
m_supports_qfProcessInfo (true),
m_supports_qUserName (true),
@@ -110,17 +111,35 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()
bool
GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
{
+ ResetDiscoverableSettings();
+
// Start the read thread after we send the handshake ack since if we
// fail to send the handshake ack, there is no reason to continue...
if (SendAck())
- return true;
-
- if (error_ptr)
- error_ptr->SetErrorString("failed to send the handshake ack");
+ {
+ // The return value from QueryNoAckModeSupported() is true if the packet
+ // was sent and _any_ response (including UNIMPLEMENTED) was received),
+ // or false if no response was received. This quickly tells us if we have
+ // a live connection to a remote GDB server...
+ if (QueryNoAckModeSupported())
+ {
+ return true;
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to get reply to handshake packet");
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to send the handshake ack");
+ }
return false;
}
-void
+bool
GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
{
if (m_supports_not_sending_acks == eLazyBoolCalculate)
@@ -136,8 +155,10 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
m_send_acks = false;
m_supports_not_sending_acks = eLazyBoolYes;
}
+ return true;
}
}
+ return false;
}
void
@@ -208,6 +229,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings()
m_supports_vCont_s = eLazyBoolCalculate;
m_supports_vCont_S = eLazyBoolCalculate;
m_supports_p = eLazyBoolCalculate;
+ m_supports_QSaveRegisterState = eLazyBoolCalculate;
m_qHostInfo_is_valid = eLazyBoolCalculate;
m_qProcessInfo_is_valid = eLazyBoolCalculate;
m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
@@ -987,19 +1009,43 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str)
}
int
-GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[])
-{
- if (argv && argv[0])
+GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info)
+{
+ // Since we don't get the send argv0 separate from the executable path, we need to
+ // make sure to use the actual exectuable path found in the launch_info...
+ std::vector<const char *> argv;
+ FileSpec exe_file = launch_info.GetExecutableFile();
+ std::string exe_path;
+ const char *arg = NULL;
+ const Args &launch_args = launch_info.GetArguments();
+ if (exe_file)
+ exe_path = exe_file.GetPath();
+ else
+ {
+ arg = launch_args.GetArgumentAtIndex(0);
+ if (arg)
+ exe_path = arg;
+ }
+ if (!exe_path.empty())
+ {
+ argv.push_back(exe_path.c_str());
+ for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i)
+ {
+ if (arg)
+ argv.push_back(arg);
+ }
+ }
+ if (!argv.empty())
{
StreamString packet;
packet.PutChar('A');
- const char *arg;
- for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i)
+ for (size_t i = 0, n = argv.size(); i < n; ++i)
{
+ arg = argv[i];
const int arg_len = strlen(arg);
if (i > 0)
packet.PutChar(',');
- packet.Printf("%i,%i,", arg_len * 2, i);
+ packet.Printf("%i,%i,", arg_len * 2, (int)i);
packet.PutBytesAsRawHex8 (arg, arg_len);
}
@@ -1783,6 +1829,22 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path)
return -1;
}
+bool
+GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd)
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false))
+ {
+ if (response.IsUnsupportedResponse())
+ return false;
+ if (response.IsErrorResponse())
+ return false;
+ response.GetHexByteString (cwd);
+ return !cwd.empty();
+ }
+ return false;
+}
+
int
GDBRemoteCommunicationClient::SetWorkingDir (char const *path)
{
@@ -2244,7 +2306,7 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
pid = LLDB_INVALID_PROCESS_ID;
StringExtractorGDBRemote response;
StreamString stream;
- stream.PutCString("qLaunchGDBServer:port:0;");
+ stream.PutCString("qLaunchGDBServer;");
std::string hostname;
if (Host::GetHostname (hostname))
{
@@ -2495,7 +2557,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, //
uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
{
lldb_private::StreamString stream;
- stream.PutCString("qPlatform_RunCommand:");
+ stream.PutCString("qPlatform_shell:");
stream.PutBytesAsRawHex8(command, strlen(command));
stream.PutChar(',');
stream.PutHex32(timeout_sec);
@@ -2534,24 +2596,44 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, //
return Error("unable to send packet");
}
-uint32_t
-GDBRemoteCommunicationClient::MakeDirectory (const std::string &path,
- mode_t mode)
+Error
+GDBRemoteCommunicationClient::MakeDirectory (const char *path,
+ uint32_t file_permissions)
{
lldb_private::StreamString stream;
- stream.PutCString("qPlatform_IO_MkDir:");
- stream.PutHex32(mode);
+ stream.PutCString("qPlatform_mkdir:");
+ stream.PutHex32(file_permissions);
stream.PutChar(',');
- stream.PutBytesAsRawHex8(path.c_str(), path.size());
+ stream.PutBytesAsRawHex8(path, strlen(path));
const char *packet = stream.GetData();
int packet_len = stream.GetSize();
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
{
- return response.GetHexMaxU32(false, UINT32_MAX);
+ return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
}
- return UINT32_MAX;
+ return Error();
+
+}
+Error
+GDBRemoteCommunicationClient::SetFilePermissions (const char *path,
+ uint32_t file_permissions)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_chmod:");
+ stream.PutHex32(file_permissions);
+ stream.PutChar(',');
+ stream.PutBytesAsRawHex8(path, strlen(path));
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
+ }
+ return Error();
+
}
static uint64_t
@@ -2641,13 +2723,13 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp
return UINT64_MAX;
}
-uint32_t
-GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error)
+Error
+GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions)
{
+ Error error;
lldb_private::StreamString stream;
stream.PutCString("vFile:mode:");
- std::string path (file_spec.GetPath());
- stream.PutCStringAsRawHex8(path.c_str());
+ stream.PutCStringAsRawHex8(path);
const char* packet = stream.GetData();
int packet_len = stream.GetSize();
StringExtractorGDBRemote response;
@@ -2656,29 +2738,34 @@ GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& f
if (response.GetChar() != 'F')
{
error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet);
- return 0;
}
- const uint32_t mode = response.GetS32(-1);
- if (mode == -1)
+ else
{
- if (response.GetChar() == ',')
+ const uint32_t mode = response.GetS32(-1);
+ if (mode == -1)
{
- int response_errno = response.GetS32(-1);
- if (response_errno > 0)
- error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ else
+ error.SetErrorToGenericError();
+ }
else
error.SetErrorToGenericError();
}
+ else
+ {
+ file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO);
+ }
}
- else
- error.Clear();
- return mode & (S_IRWXU|S_IRWXG|S_IRWXO);
}
else
{
error.SetErrorStringWithFormat ("failed to send '%s' packet", packet);
}
- return 0;
+ return error;
}
uint64_t
@@ -2760,6 +2847,90 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,
return 0;
}
+Error
+GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst)
+{
+ Error error;
+ lldb_private::StreamGDBRemote stream;
+ stream.PutCString("vFile:symlink:");
+ // the unix symlink() command reverses its parameters where the dst if first,
+ // so we follow suit here
+ stream.PutCStringAsRawHex8(dst);
+ stream.PutChar(',');
+ stream.PutCStringAsRawHex8(src);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() == 'F')
+ {
+ uint32_t result = response.GetU32(UINT32_MAX);
+ if (result != 0)
+ {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ }
+ }
+ else
+ {
+ // Should have returned with 'F<result>[,<errno>]'
+ error.SetErrorStringWithFormat("symlink failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send vFile:symlink packet");
+ }
+ return error;
+}
+
+Error
+GDBRemoteCommunicationClient::Unlink (const char *path)
+{
+ Error error;
+ lldb_private::StreamGDBRemote stream;
+ stream.PutCString("vFile:unlink:");
+ // the unix symlink() command reverses its parameters where the dst if first,
+ // so we follow suit here
+ stream.PutCStringAsRawHex8(path);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() == 'F')
+ {
+ uint32_t result = response.GetU32(UINT32_MAX);
+ if (result != 0)
+ {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ }
+ }
+ else
+ {
+ // Should have returned with 'F<result>[,<errno>]'
+ error.SetErrorStringWithFormat("unlink failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send vFile:unlink packet");
+ }
+ return error;
+}
+
// Extension of host I/O packets to get whether a file exists.
bool
GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)
@@ -2809,3 +2980,134 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s
}
return false;
}
+
+bool
+GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
+{
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[64];
+ int packet_len = 0;
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid);
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ return SendPacketAndWaitForResponse(packet, response, false);
+ }
+ }
+ return false;
+
+}
+
+
+bool
+GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response)
+{
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[64];
+ int packet_len = 0;
+ // Get all registers in one packet
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid);
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ return SendPacketAndWaitForResponse(packet, response, false);
+ }
+ }
+ return false;
+}
+bool
+GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id)
+{
+ save_id = 0; // Set to invalid save ID
+ if (m_supports_QSaveRegisterState == eLazyBoolNo)
+ return false;
+
+ m_supports_QSaveRegisterState = eLazyBoolYes;
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[256];
+ if (thread_suffix_supported)
+ ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid);
+ else
+ ::strncpy (packet, "QSaveRegisterState", sizeof(packet));
+
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, response, false))
+ {
+ if (response.IsUnsupportedResponse())
+ {
+ // This packet isn't supported, don't try calling it again
+ m_supports_QSaveRegisterState = eLazyBoolNo;
+ }
+
+ const uint32_t response_save_id = response.GetU32(0);
+ if (response_save_id != 0)
+ {
+ save_id = response_save_id;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id)
+{
+ // We use the "m_supports_QSaveRegisterState" variable here becuase the
+ // QSaveRegisterState and QRestoreRegisterState packets must both be supported in
+ // order to be useful
+ if (m_supports_QSaveRegisterState == eLazyBoolNo)
+ return false;
+
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[256];
+ if (thread_suffix_supported)
+ ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid);
+ else
+ ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id);
+
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, response, false))
+ {
+ if (response.IsOKResponse())
+ {
+ return true;
+ }
+ else if (response.IsUnsupportedResponse())
+ {
+ // This packet isn't supported, don't try calling this packet or
+ // QSaveRegisterState again...
+ m_supports_QSaveRegisterState = eLazyBoolNo;
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index d5535bb..564afbb 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -38,7 +38,6 @@ public:
//------------------------------------------------------------------
GDBRemoteCommunicationClient(bool is_platform);
- virtual
~GDBRemoteCommunicationClient();
//------------------------------------------------------------------
@@ -65,10 +64,16 @@ public:
size_t packet_length,
StringExtractorGDBRemote &response);
- virtual bool
+ bool
GetThreadSuffixSupported ();
- void
+ // This packet is usually sent first and the boolean return value
+ // indicates if the packet was send and any response was received
+ // even in the response is UNIMPLEMENTED. If the packet failed to
+ // get a response, then false is returned. This quickly tells us
+ // if we were able to connect and communicte with the remote GDB
+ // server
+ bool
QueryNoAckModeSupported ();
void
@@ -109,7 +114,7 @@ public:
/// response was received.
//------------------------------------------------------------------
int
- SendArgumentsPacket (char const *argv[]);
+ SendArgumentsPacket (const lldb_private::ProcessLaunchInfo &launch_info);
//------------------------------------------------------------------
/// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
@@ -185,7 +190,10 @@ public:
//------------------------------------------------------------------
/// Sets the working directory to \a path for a process that will
- /// be launched with the 'A' packet.
+ /// be launched with the 'A' packet for non platform based
+ /// connections. If this packet is sent to a GDB server that
+ /// implements the platform, it will change the current working
+ /// directory for the platform process.
///
/// @param[in] path
/// The path to a directory to use when launching our processs
@@ -196,6 +204,19 @@ public:
int
SetWorkingDir (char const *path);
+ //------------------------------------------------------------------
+ /// Gets the current working directory of a remote platform GDB
+ /// server.
+ ///
+ /// @param[out] cwd
+ /// The current working directory on the remote platform.
+ ///
+ /// @return
+ /// Boolean for success
+ //------------------------------------------------------------------
+ bool
+ GetWorkingDir (std::string &cwd);
+
lldb::addr_t
AllocateMemory (size_t size, uint32_t permissions);
@@ -356,45 +377,54 @@ public:
return m_interrupt_sent;
}
- virtual lldb::user_id_t
+ lldb::user_id_t
OpenFile (const lldb_private::FileSpec& file_spec,
uint32_t flags,
mode_t mode,
lldb_private::Error &error);
- virtual bool
+ bool
CloseFile (lldb::user_id_t fd,
lldb_private::Error &error);
- virtual lldb::user_id_t
+ lldb::user_id_t
GetFileSize (const lldb_private::FileSpec& file_spec);
- virtual uint32_t
- GetFilePermissions(const lldb_private::FileSpec& file_spec,
- lldb_private::Error &error);
+ lldb_private::Error
+ GetFilePermissions(const char *path, uint32_t &file_permissions);
+
+ lldb_private::Error
+ SetFilePermissions(const char *path, uint32_t file_permissions);
- virtual uint64_t
+ uint64_t
ReadFile (lldb::user_id_t fd,
uint64_t offset,
void *dst,
uint64_t dst_len,
lldb_private::Error &error);
- virtual uint64_t
+ uint64_t
WriteFile (lldb::user_id_t fd,
uint64_t offset,
const void* src,
uint64_t src_len,
lldb_private::Error &error);
- virtual uint32_t
- MakeDirectory (const std::string &path,
- mode_t mode);
+ lldb_private::Error
+ CreateSymlink (const char *src,
+ const char *dst);
- virtual bool
+ lldb_private::Error
+ Unlink (const char *path);
+
+ lldb_private::Error
+ MakeDirectory (const char *path,
+ uint32_t mode);
+
+ bool
GetFileExists (const lldb_private::FileSpec& file_spec);
- virtual lldb_private::Error
+ lldb_private::Error
RunShellCommand (const char *command, // Shouldn't be NULL
const char *working_dir, // Pass NULL to use the current working directory
int *status_ptr, // Pass NULL if you don't want the process exit status
@@ -402,7 +432,7 @@ public:
std::string *command_output, // Pass NULL if you don't want the command output
uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
- virtual bool
+ bool
CalculateMD5 (const lldb_private::FileSpec& file_spec,
uint64_t &high,
uint64_t &low);
@@ -411,6 +441,21 @@ public:
HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
StringExtractorGDBRemote &inputStringExtractor);
+ bool
+ ReadRegister(lldb::tid_t tid,
+ uint32_t reg_num,
+ StringExtractorGDBRemote &response);
+
+ bool
+ ReadAllRegisters (lldb::tid_t tid,
+ StringExtractorGDBRemote &response);
+
+ bool
+ SaveRegisterState (lldb::tid_t tid, uint32_t &save_id);
+
+ bool
+ RestoreRegisterState (lldb::tid_t tid, uint32_t save_id);
+
protected:
bool
@@ -438,6 +483,7 @@ protected:
lldb_private::LazyBool m_attach_or_wait_reply;
lldb_private::LazyBool m_prepare_for_reg_writing_reply;
lldb_private::LazyBool m_supports_p;
+ lldb_private::LazyBool m_supports_QSaveRegisterState;
bool
m_supports_qProcessInfoPID:1,
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index df036cd..7cc3a05 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -47,27 +47,9 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
m_proc_infos (),
m_proc_infos_index (0),
- m_lo_port_num (0),
- m_hi_port_num (0),
- m_next_port (0),
- m_use_port_range (false)
+ m_port_map (),
+ m_port_offset(0)
{
- // We seldom need to override the port number that the debugserver process
- // starts with. We just pass in 0 to let the system choose a random port.
- // In rare situation where the need arises, use two environment variables
- // to override.
- uint16_t lo_port_num = 0;
- uint16_t hi_port_num = 0;
- const char *lo_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_LO_PORT");
- if (lo_port_c_str)
- lo_port_num = ::atoi(lo_port_c_str);
- const char *hi_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_HI_PORT");
- if (hi_port_c_str)
- hi_port_num = ::atoi(hi_port_c_str);
- if (lo_port_num && hi_port_num && lo_port_num < hi_port_num)
- {
- SetPortRange(lo_port_num, hi_port_num);
- }
}
//----------------------------------------------------------------------
@@ -166,6 +148,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_qUserName:
return Handle_qUserName (packet);
+ case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir:
+ return Handle_qGetWorkingDir(packet);
+
case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
return Handle_QEnvironment (packet);
@@ -190,38 +175,47 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
return Handle_QStartNoAckMode (packet);
- case StringExtractorGDBRemote::eServerPacketType_qPlatform_IO_MkDir:
- return Handle_qPlatform_IO_MkDir (packet);
+ case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir:
+ return Handle_qPlatform_mkdir (packet);
- case StringExtractorGDBRemote::eServerPacketType_qPlatform_RunCommand:
- return Handle_qPlatform_RunCommand (packet);
+ case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod:
+ return Handle_qPlatform_chmod (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_Open:
+ case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell:
+ return Handle_qPlatform_shell (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_open:
return Handle_vFile_Open (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_Close:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_close:
return Handle_vFile_Close (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_pRead:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_pread:
return Handle_vFile_pRead (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite:
return Handle_vFile_pWrite (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_Size:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_size:
return Handle_vFile_Size (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_Mode:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_mode:
return Handle_vFile_Mode (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_Exists:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_exists:
return Handle_vFile_Exists (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_Stat:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_stat:
return Handle_vFile_Stat (packet);
- case StringExtractorGDBRemote::eServerPacketType_vFile_MD5:
+ case StringExtractorGDBRemote::eServerPacketType_vFile_md5:
return Handle_vFile_MD5 (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_symlink:
+ return Handle_vFile_symlink (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_unlink:
+ return Handle_vFile_unlink (packet);
}
return true;
}
@@ -329,12 +323,33 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
response.PutCStringAsRawHex8(s.c_str());
response.PutChar(';');
}
+#if defined(__APPLE__)
+
+#if defined(__arm__)
+ // For iOS devices, we are connected through a USB Mux so we never pretend
+ // to actually have a hostname as far as the remote lldb that is connecting
+ // to this lldb-platform is concerned
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8("localhost");
+ response.PutChar(';');
+#else // #if defined(__arm__)
+ if (Host::GetHostname (s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+
+#endif // #if defined(__arm__)
+
+#else // #if defined(__APPLE__)
if (Host::GetHostname (s))
{
response.PutCString ("hostname:");
response.PutCStringAsRawHex8(s.c_str());
response.PutChar(';');
}
+#endif // #if defined(__APPLE__)
return SendPacketNoLock (response.GetData(), response.GetSize()) > 0;
}
@@ -731,6 +746,7 @@ bool
GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
{
Mutex::Locker locker (m_spawned_pids_mutex);
+ FreePortForProcess(pid);
return m_spawned_pids.erase(pid) > 0;
}
bool
@@ -764,105 +780,119 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
std::string hostname;
// TODO: /tmp/ should not be hardcoded. User might want to override /tmp
// with the TMPDIR environnement variable
- char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
- if (::mkstemp (unix_socket_name) == -1)
+ packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
+ std::string name;
+ std::string value;
+ uint16_t port = UINT16_MAX;
+ while (packet.GetNameColonValue(name, value))
{
- error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno));
+ if (name.compare ("host") == 0)
+ hostname.swap(value);
+ else if (name.compare ("port") == 0)
+ port = Args::StringToUInt32(value.c_str(), 0, 0);
}
- else
- {
- packet.SetFilePos(::strlen ("qLaunchGDBServer:"));
- std::string name;
- std::string value;
- uint16_t port = UINT16_MAX;
- while (packet.GetNameColonValue(name, value))
- {
- if (name.compare ("host") == 0)
- hostname.swap(value);
- else if (name.compare ("port") == 0)
- port = Args::StringToUInt32(value.c_str(), 0, 0);
- }
- if (port == UINT16_MAX)
- port = GetAndUpdateNextPort();
+ if (port == UINT16_MAX)
+ port = GetNextAvailablePort();
- ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
- // Spawn a new thread to accept the port that gets bound after
- // binding to port 0 (zero).
- lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD;
+ // Spawn a new thread to accept the port that gets bound after
+ // binding to port 0 (zero).
+ lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD;
+ const char *unix_socket_name = NULL;
+ char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX";
- if (port == 0)
+ if (port == 0)
+ {
+ if (::mkstemp (unix_socket_name_buf) == 0)
{
+ unix_socket_name = unix_socket_name_buf;
+ ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
accept_thread = Host::ThreadCreate (unix_socket_name,
AcceptPortFromInferior,
connect_url,
&error);
}
+ else
+ {
+ error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno));
+ }
+ }
- if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
+ if (error.Success())
+ {
+ // Spawn a debugserver and try to get the port it listens to.
+ ProcessLaunchInfo debugserver_launch_info;
+ StreamString host_and_port;
+ if (hostname.empty())
+ hostname = "localhost";
+ host_and_port.Printf("%s:%u", hostname.c_str(), port);
+ const char *host_and_port_cstr = host_and_port.GetString().c_str();
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr);
+
+ debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
+
+ error = StartDebugserverProcess (host_and_port_cstr,
+ unix_socket_name,
+ debugserver_launch_info);
+
+ lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+
+
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
{
- // Spawn a debugserver and try to get the port it listens to.
- ProcessLaunchInfo debugserver_launch_info;
- StreamString host_and_port;
- if (hostname.empty())
- hostname = "localhost";
- host_and_port.Printf("%s:%u", hostname.c_str(), port);
- const char *host_and_port_cstr = host_and_port.GetString().c_str();
- Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
- if (log)
- log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr);
- error = StartDebugserverProcess (host_and_port_cstr,
- unix_socket_name,
- debugserver_launch_info);
-
- lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
-
- if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
- {
- {
- Mutex::Locker locker (m_spawned_pids_mutex);
- m_spawned_pids.insert(debugserver_pid);
- }
- Host::StartMonitoringChildProcess (ReapDebugserverProcess, this, debugserver_pid, false);
- }
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(debugserver_pid);
+ if (port > 0)
+ AssociatePortWithProcess(port, debugserver_pid);
+ }
+ else
+ {
+ if (port > 0)
+ FreePort (port);
+ }
- if (error.Success())
- {
- bool success = false;
+ if (error.Success())
+ {
+ bool success = false;
- if (accept_thread)
+ if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
+ {
+ thread_result_t accept_thread_result = NULL;
+ if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
{
- thread_result_t accept_thread_result = NULL;
- if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
+ if (accept_thread_result)
{
- if (accept_thread_result)
- {
- port = (intptr_t)accept_thread_result;
- char response[256];
- const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
- assert (response_len < sizeof(response));
- //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
- success = SendPacketNoLock (response, response_len) > 0;
- }
+ port = (intptr_t)accept_thread_result;
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
+ assert (response_len < sizeof(response));
+ //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+ success = SendPacketNoLock (response, response_len) > 0;
}
}
- else
- {
- char response[256];
- const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
- assert (response_len < sizeof(response));
- //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
- success = SendPacketNoLock (response, response_len) > 0;
+ }
+ else
+ {
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
+ assert (response_len < sizeof(response));
+ //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+ success = SendPacketNoLock (response, response_len) > 0;
- }
- ::unlink (unix_socket_name);
+ }
+ Host::Unlink (unix_socket_name);
- if (!success)
- {
- if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
- ::kill (debugserver_pid, SIGINT);
- }
- return success;
+ if (!success)
+ {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ ::kill (debugserver_pid, SIGINT);
}
+ return success;
+ }
+ else if (accept_thread)
+ {
+ Host::Unlink (unix_socket_name);
}
}
}
@@ -896,7 +926,7 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo
{
Mutex::Locker locker (m_spawned_pids_mutex);
if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return true;
+ return SendOKResponse();
}
usleep (10000);
}
@@ -905,7 +935,7 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo
{
Mutex::Locker locker (m_spawned_pids_mutex);
if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return true;
+ return SendOKResponse();
}
Host::Kill (pid, SIGKILL);
@@ -915,12 +945,12 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo
{
Mutex::Locker locker (m_spawned_pids_mutex);
if (m_spawned_pids.find(pid) == m_spawned_pids.end())
- return true;
+ return SendOKResponse();
}
usleep (10000);
}
}
- return SendErrorResponse (10);
+ return SendErrorResponse (11);
}
bool
@@ -944,7 +974,7 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa
m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
return SendOKResponse ();
}
- return SendErrorResponse (11);
+ return SendErrorResponse (12);
}
bool
@@ -959,7 +989,7 @@ GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &pack
m_process_launch_info.SetArchitecture(arch_spec);
return SendOKResponse();
}
- return SendErrorResponse(12);
+ return SendErrorResponse(13);
}
bool
@@ -979,11 +1009,61 @@ GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &p
packet.SetFilePos(::strlen ("QSetWorkingDir:"));
std::string path;
packet.GetHexByteString(path);
- m_process_launch_info.SwapWorkingDirectory (path);
+ if (m_is_platform)
+ {
+#ifdef _WIN32
+ // Not implemented on Windows
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented");
+#else
+ // If this packet is sent to a platform, then change the current working directory
+ if (::chdir(path.c_str()) != 0)
+ return SendErrorResponse(errno);
+#endif
+ }
+ else
+ {
+ m_process_launch_info.SwapWorkingDirectory (path);
+ }
return SendOKResponse ();
}
bool
+GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ if (m_is_platform)
+ {
+ // If this packet is sent to a platform, then change the current working directory
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, sizeof(cwd)) == NULL)
+ {
+ return SendErrorResponse(errno);
+ }
+ else
+ {
+ response.PutBytesAsRawHex8(cwd, strlen(cwd));
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+ }
+ }
+ else
+ {
+ const char *working_dir = m_process_launch_info.GetWorkingDirectory();
+ if (working_dir && working_dir[0])
+ {
+ response.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+ }
+ else
+ {
+ return SendErrorResponse(14);
+ }
+ }
+}
+
+bool
GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
{
packet.SetFilePos(::strlen ("QSetSTDIN:"));
@@ -997,7 +1077,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (13);
+ return SendErrorResponse (15);
}
bool
@@ -1014,7 +1094,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (14);
+ return SendErrorResponse (16);
}
bool
@@ -1031,7 +1111,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (15);
+ return SendErrorResponse (17);
}
bool
@@ -1044,19 +1124,40 @@ GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &
}
bool
-GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen("qPlatform_IO_MkDir:"));
+ packet.SetFilePos(::strlen("qPlatform_mkdir:"));
mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
- if (packet.GetChar() != ',')
- return false;
- std::string path;
- packet.GetHexByteString(path);
- uint32_t retcode = Host::MakeDirectory(path.c_str(),mode);
- StreamString response;
- response.PutHex32(retcode);
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = Host::MakeDirectory(path.c_str(),mode);
+ if (error.Success())
+ return SendPacketNoLock ("OK", 2);
+ else
+ return SendErrorResponse(error.GetError());
+ }
+ return SendErrorResponse(20);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_chmod:"));
+
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = Host::SetFilePermissions (path.c_str(), mode);
+ if (error.Success())
+ return SendPacketNoLock ("OK", 2);
+ else
+ return SendErrorResponse(error.GetError());
+ }
+ return SendErrorResponse(19);
}
bool
@@ -1065,24 +1166,28 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe
packet.SetFilePos(::strlen("vFile:open:"));
std::string path;
packet.GetHexByteStringTerminatedBy(path,',');
- if (path.size() == 0)
- return false;
- if (packet.GetChar() != ',')
- return false;
- uint32_t flags = packet.GetHexMaxU32(false, UINT32_MAX);
- if (packet.GetChar() != ',')
- return false;
- mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
- Error error;
- int fd = ::open (path.c_str(), flags, mode);
- const int save_errno = fd == -1 ? errno : 0;
- StreamString response;
- response.PutChar('F');
- response.Printf("%i", fd);
- if (save_errno)
- response.Printf(",%i", save_errno);
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ if (!path.empty())
+ {
+ if (packet.GetChar() == ',')
+ {
+ uint32_t flags = packet.GetHexMaxU32(false, 0);
+ if (packet.GetChar() == ',')
+ {
+ mode_t mode = packet.GetHexMaxU32(false, 0600);
+ Error error;
+ int fd = ::open (path.c_str(), flags, mode);
+ printf ("open('%s', flags=0x%x, mode=%o) fd = %i (%s)\n", path.c_str(), flags, mode, fd, fd == -1 ? strerror(errno) : "<success>");
+ const int save_errno = fd == -1 ? errno : 0;
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", fd);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ }
+ return SendErrorResponse(18);
}
bool
@@ -1107,8 +1212,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &pack
response.Printf("%i", err);
if (save_errno)
response.Printf(",%i", save_errno);
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
bool
@@ -1116,37 +1220,40 @@ GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &pack
{
#ifdef _WIN32
// Not implemented on Windows
- return false;
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented");
#else
StreamGDBRemote response;
packet.SetFilePos(::strlen("vFile:pread:"));
int fd = packet.GetS32(-1);
- if (packet.GetChar() != ',')
- return false;
- uint64_t count = packet.GetU64(UINT64_MAX);
- if (packet.GetChar() != ',')
- return false;
- uint64_t offset = packet.GetU64(UINT32_MAX);
- if (count == UINT64_MAX)
- {
- response.Printf("F-1:%i", EINVAL);
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
- }
- std::string buffer(count, 0);
- const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
- const int save_errno = bytes_read == -1 ? errno : 0;
- response.PutChar('F');
- response.Printf("%zi", bytes_read);
- if (save_errno)
- response.Printf(",%i", save_errno);
- else
+ if (packet.GetChar() == ',')
{
- response.PutChar(';');
- response.PutEscapedBytes(&buffer[0], bytes_read);
+ uint64_t count = packet.GetU64(UINT64_MAX);
+ if (packet.GetChar() == ',')
+ {
+ uint64_t offset = packet.GetU64(UINT32_MAX);
+ if (count == UINT64_MAX)
+ {
+ response.Printf("F-1:%i", EINVAL);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+
+ std::string buffer(count, 0);
+ const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
+ const int save_errno = bytes_read == -1 ? errno : 0;
+ response.PutChar('F');
+ response.Printf("%zi", bytes_read);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ else
+ {
+ response.PutChar(';');
+ response.PutEscapedBytes(&buffer[0], bytes_read);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
}
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ return SendErrorResponse(21);
+
#endif
}
@@ -1154,8 +1261,7 @@ bool
GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
{
#ifdef _WIN32
- // Not implemented on Windows
- return false;
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented");
#else
packet.SetFilePos(::strlen("vFile:pwrite:"));
@@ -1163,27 +1269,28 @@ GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &pac
response.PutChar('F');
int fd = packet.GetU32(UINT32_MAX);
- if (packet.GetChar() != ',')
- return false;
- off_t offset = packet.GetU64(UINT32_MAX);
- if (packet.GetChar() != ',')
- return false;
- std::string buffer;
- if (packet.GetEscapedBinaryData(buffer))
- {
- const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
- const int save_errno = bytes_written == -1 ? errno : 0;
- response.Printf("%zi", bytes_written);
- if (save_errno)
- response.Printf(",%i", save_errno);
- }
- else
+ if (packet.GetChar() == ',')
{
- response.Printf ("-1,%i", EINVAL);
+ off_t offset = packet.GetU64(UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string buffer;
+ if (packet.GetEscapedBinaryData(buffer))
+ {
+ const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
+ const int save_errno = bytes_written == -1 ? errno : 0;
+ response.Printf("%zi", bytes_written);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ }
+ else
+ {
+ response.Printf ("-1,%i", EINVAL);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
}
-
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ return SendErrorResponse(27);
#endif
}
@@ -1193,19 +1300,20 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe
packet.SetFilePos(::strlen("vFile:size:"));
std::string path;
packet.GetHexByteString(path);
- if (path.empty())
- return false;
- lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
- StreamString response;
- response.PutChar('F');
- response.PutHex64(retcode);
- if (retcode == UINT64_MAX)
+ if (!path.empty())
{
- response.PutChar(',');
- response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutHex64(retcode);
+ if (retcode == UINT64_MAX)
+ {
+ response.PutChar(',');
+ response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ return SendErrorResponse(22);
}
bool
@@ -1214,16 +1322,17 @@ GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packe
packet.SetFilePos(::strlen("vFile:mode:"));
std::string path;
packet.GetHexByteString(path);
- if (path.empty())
- return false;
- Error error;
- const uint32_t mode = File::GetPermissions(path.c_str(), error);
- StreamString response;
- response.Printf("F%u", mode);
- if (mode == 0 || error.Fail())
- response.Printf(",%i", (int)error.GetError());
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ if (!path.empty())
+ {
+ Error error;
+ const uint32_t mode = File::GetPermissions(path.c_str(), error);
+ StreamString response;
+ response.Printf("F%u", mode);
+ if (mode == 0 || error.Fail())
+ response.Printf(",%i", (int)error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(23);
}
bool
@@ -1232,87 +1341,118 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac
packet.SetFilePos(::strlen("vFile:exists:"));
std::string path;
packet.GetHexByteString(path);
- if (path.empty())
- return false;
- bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
+ if (!path.empty())
+ {
+ bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutChar(',');
+ if (retcode)
+ response.PutChar('1');
+ else
+ response.PutChar('0');
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(24);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:symlink:"));
+ std::string dst, src;
+ packet.GetHexByteStringTerminatedBy(dst, ',');
+ packet.GetChar(); // Skip ',' char
+ packet.GetHexByteString(src);
+ Error error = Host::Symlink(src.c_str(), dst.c_str());
StreamString response;
- response.PutChar('F');
- response.PutChar(',');
- if (retcode)
- response.PutChar('1');
- else
- response.PutChar('0');
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
bool
-GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet)
+GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen("qPlatform_RunCommand:"));
+ packet.SetFilePos(::strlen("vFile:unlink:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = Host::Unlink(path.c_str());
+ StreamString response;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_shell:"));
std::string path;
std::string working_dir;
packet.GetHexByteStringTerminatedBy(path,',');
- if (path.size() == 0)
- return false;
- if (packet.GetChar() != ',')
- return false;
- // FIXME: add timeout to qPlatform_RunCommand packet
- // uint32_t timeout = packet.GetHexMaxU32(false, 32);
- uint32_t timeout = 10;
- if (packet.GetChar() == ',')
- packet.GetHexByteString(working_dir);
- int status, signo;
- std::string output;
- Error err = Host::RunShellCommand(path.c_str(),
- working_dir.empty() ? NULL : working_dir.c_str(),
- &status, &signo, &output, timeout);
- StreamGDBRemote response;
- if (err.Fail())
+ if (!path.empty())
{
- response.PutCString("F,");
- response.PutHex32(UINT32_MAX);
- }
- else
- {
- response.PutCString("F,");
- response.PutHex32(status);
- response.PutChar(',');
- response.PutHex32(signo);
- response.PutChar(',');
- response.PutEscapedBytes(output.c_str(), output.size());
+ if (packet.GetChar() == ',')
+ {
+ // FIXME: add timeout to qPlatform_shell packet
+ // uint32_t timeout = packet.GetHexMaxU32(false, 32);
+ uint32_t timeout = 10;
+ if (packet.GetChar() == ',')
+ packet.GetHexByteString(working_dir);
+ int status, signo;
+ std::string output;
+ Error err = Host::RunShellCommand(path.c_str(),
+ working_dir.empty() ? NULL : working_dir.c_str(),
+ &status, &signo, &output, timeout);
+ StreamGDBRemote response;
+ if (err.Fail())
+ {
+ response.PutCString("F,");
+ response.PutHex32(UINT32_MAX);
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex32(status);
+ response.PutChar(',');
+ response.PutHex32(signo);
+ response.PutChar(',');
+ response.PutEscapedBytes(output.c_str(), output.size());
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
}
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ return SendErrorResponse(24);
}
bool
GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
{
- return false;
+ return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented");
}
bool
GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(::strlen("vFile:exists:"));
+ packet.SetFilePos(::strlen("vFile:MD5:"));
std::string path;
packet.GetHexByteString(path);
- if (path.size() == 0)
- return false;
- uint64_t a,b;
- StreamGDBRemote response;
- if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
+ if (!path.empty())
{
- response.PutCString("F,");
- response.PutCString("x");
- }
- else
- {
- response.PutCString("F,");
- response.PutHex64(a);
- response.PutHex64(b);
+ uint64_t a,b;
+ StreamGDBRemote response;
+ if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false)
+ {
+ response.PutCString("F,");
+ response.PutCString("x");
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex64(a);
+ response.PutHex64(b);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
}
- SendPacketNoLock(response.GetData(), response.GetSize());
- return true;
+ return SendErrorResponse(25);
}
+
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index 64f6f8d..721ea50 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -26,6 +26,8 @@ class StringExtractorGDBRemote;
class GDBRemoteCommunicationServer : public GDBRemoteCommunication
{
public:
+ typedef std::map<uint16_t, lldb::pid_t> PortMap;
+
enum
{
eBroadcastBitRunPacketSent = kLoUserBroadcastBit
@@ -58,30 +60,85 @@ public:
// Set both ports to zero to let the platform automatically bind to
// a port chosen by the OS.
void
- SetPortRange (uint16_t lo_port_num, uint16_t hi_port_num)
+ SetPortMap (PortMap &&port_map)
{
- m_lo_port_num = lo_port_num;
- m_hi_port_num = hi_port_num;
- m_next_port = m_lo_port_num;
- m_use_port_range = true;
+ m_port_map = port_map;
}
- // If we are using a port range, get and update the next port to be used variable.
- // Otherwise, just return 0.
+ //----------------------------------------------------------------------
+ // 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
- GetAndUpdateNextPort ()
+ GetNextAvailablePort ()
{
- if (!m_use_port_range)
- return 0;
- uint16_t val = m_next_port;
- if (++m_next_port > m_hi_port_num)
- m_next_port = m_lo_port_num;
- return val;
+ if (m_port_map.empty())
+ return 0; // Bind to port zero and get a port, we didn't have any limitations
+
+ for (auto &pair : m_port_map)
+ {
+ if (pair.second == LLDB_INVALID_PROCESS_ID)
+ {
+ pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
+ return pair.first;
+ }
+ }
+ return UINT16_MAX;
}
-protected:
- //typedef std::map<uint16_t, lldb::pid_t> PortToPIDMap;
+ bool
+ AssociatePortWithProcess (uint16_t port, lldb::pid_t pid)
+ {
+ PortMap::iterator pos = m_port_map.find(port);
+ if (pos != m_port_map.end())
+ {
+ pos->second = pid;
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ FreePort (uint16_t port)
+ {
+ PortMap::iterator pos = m_port_map.find(port);
+ if (pos != m_port_map.end())
+ {
+ pos->second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ FreePortForProcess (lldb::pid_t pid)
+ {
+ if (!m_port_map.empty())
+ {
+ for (auto &pair : m_port_map)
+ {
+ if (pair.second == pid)
+ {
+ pair.second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ void
+ SetPortOffset (uint16_t port_offset)
+ {
+ m_port_offset = port_offset;
+ }
+
+protected:
lldb::thread_t m_async_thread;
lldb_private::ProcessLaunchInfo m_process_launch_info;
lldb_private::Error m_process_launch_error;
@@ -89,11 +146,8 @@ protected:
lldb_private::Mutex m_spawned_pids_mutex;
lldb_private::ProcessInstanceInfoList m_proc_infos;
uint32_t m_proc_infos_index;
- uint16_t m_lo_port_num;
- uint16_t m_hi_port_num;
- //PortToPIDMap m_port_to_pid_map;
- uint16_t m_next_port;
- bool m_use_port_range;
+ PortMap m_port_map;
+ uint16_t m_port_offset;
size_t
@@ -121,7 +175,10 @@ protected:
Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
bool
- Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet);
+ Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
bool
Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
@@ -155,6 +212,9 @@ protected:
bool
Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qGetWorkingDir (StringExtractorGDBRemote &packet);
bool
Handle_QStartNoAckMode (StringExtractorGDBRemote &packet);
@@ -188,6 +248,12 @@ protected:
bool
Handle_vFile_Exists (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_symlink (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_unlink (StringExtractorGDBRemote &packet);
bool
Handle_vFile_Stat (StringExtractorGDBRemote &packet);
@@ -196,7 +262,7 @@ protected:
Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
bool
- Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet);
+ Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
private:
bool
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index c4e468f..c291df7 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -153,20 +153,13 @@ bool
GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
GDBRemoteCommunicationClient &gdb_comm)
{
- char packet[64];
- StringExtractorGDBRemote response;
- int packet_len = 0;
const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
- if (gdb_comm.GetThreadSuffixSupported())
- packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetProtocolID());
- else
- packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
- assert (packet_len < ((int)sizeof(packet) - 1));
- if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
+ StringExtractorGDBRemote response;
+ if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), reg, response))
return PrivateSetRegisterValue (reg, response);
-
return false;
}
+
bool
GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data)
{
@@ -185,93 +178,51 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE
if (!GetRegisterIsValid(reg))
{
- Mutex::Locker locker;
- if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register."))
+ if (m_read_all_at_once)
{
- const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
- ProcessSP process_sp (m_thread.GetProcess());
- if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ StringExtractorGDBRemote response;
+ if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response))
+ return false;
+ if (response.IsNormalResponse())
+ if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
+ SetAllRegisterValid (true);
+ }
+ else if (reg_info->value_regs)
+ {
+ // Process this composite register request by delegating to the constituent
+ // primordial registers.
+
+ // Index of the primordial register.
+ bool success = true;
+ for (uint32_t idx = 0; success; ++idx)
{
- char packet[64];
- StringExtractorGDBRemote response;
- int packet_len = 0;
- if (m_read_all_at_once)
- {
- // Get all registers in one packet
- if (thread_suffix_supported)
- packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
- else
- packet_len = ::snprintf (packet, sizeof(packet), "g");
- assert (packet_len < ((int)sizeof(packet) - 1));
- if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
- {
- if (response.IsNormalResponse())
- if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
- SetAllRegisterValid (true);
- }
- }
- else if (reg_info->value_regs)
- {
- // Process this composite register request by delegating to the constituent
- // primordial registers.
-
- // Index of the primordial register.
- bool success = true;
- for (uint32_t idx = 0; success; ++idx)
- {
- const uint32_t prim_reg = reg_info->value_regs[idx];
- if (prim_reg == LLDB_INVALID_REGNUM)
- break;
- // We have a valid primordial regsiter as our constituent.
- // Grab the corresponding register info.
- const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
- if (prim_reg_info == NULL)
- success = false;
- else
- {
- // Read the containing register if it hasn't already been read
- if (!GetRegisterIsValid(prim_reg))
- success = GetPrimordialRegister(prim_reg_info, gdb_comm);
- }
- }
-
- if (success)
- {
- // If we reach this point, all primordial register requests have succeeded.
- // Validate this composite register.
- SetRegisterIsValid (reg_info, true);
- }
- }
+ const uint32_t prim_reg = reg_info->value_regs[idx];
+ if (prim_reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial regsiter as our constituent.
+ // Grab the corresponding register info.
+ const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
+ if (prim_reg_info == NULL)
+ success = false;
else
{
- // Get each register individually
- GetPrimordialRegister(reg_info, gdb_comm);
+ // Read the containing register if it hasn't already been read
+ if (!GetRegisterIsValid(prim_reg))
+ success = GetPrimordialRegister(prim_reg_info, gdb_comm);
}
}
+
+ if (success)
+ {
+ // If we reach this point, all primordial register requests have succeeded.
+ // Validate this composite register.
+ SetRegisterIsValid (reg_info, true);
+ }
}
else
{
-#if LLDB_CONFIGURATION_DEBUG
- StreamString strm;
- gdb_comm.DumpHistory(strm);
- Host::SetCrashDescription (strm.GetData());
- assert (!"Didn't get sequence mutex for read register.");
-#else
- Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
- if (log)
- {
- if (log->GetVerbose())
- {
- StreamString strm;
- gdb_comm.DumpHistory(strm);
- log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData());
- }
- else
- {
- log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name);
- }
- }
-#endif
+ // Get each register individually
+ GetPrimordialRegister(reg_info, gdb_comm);
}
// Make sure we got a valid register value after reading it
@@ -488,6 +439,54 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *
return false;
}
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ uint32_t save_id = 0;
+ if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id))
+ {
+ reg_checkpoint.SetID(save_id);
+ reg_checkpoint.GetData().reset();
+ return true;
+ }
+ else
+ {
+ reg_checkpoint.SetID(0); // Invalid save ID is zero
+ return ReadAllRegisterValues(reg_checkpoint.GetData());
+ }
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint)
+{
+ uint32_t save_id = reg_checkpoint.GetID();
+ if (save_id != 0)
+ {
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id);
+ }
+ else
+ {
+ return WriteAllRegisterValues(reg_checkpoint.GetData());
+ }
+}
bool
GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index 7a49d69..38f29bb 100644
--- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -91,6 +91,12 @@ public:
virtual bool
WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+ virtual bool
+ ReadAllRegisterValues (lldb_private::RegisterCheckpoint &reg_checkpoint);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb_private::RegisterCheckpoint &reg_checkpoint);
+
virtual uint32_t
ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index aff9c7b..7f1fbef 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -820,7 +820,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_
}
const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (10);
- int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info.GetArguments().GetConstArgumentVector());
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info);
if (arg_packet_err == 0)
{
std::string error_str;
@@ -926,15 +926,13 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
// then we aren't actually connected to anything, so try and do the
// handshake with the remote GDB server and make sure that goes
// alright.
- if (!m_gdb_comm.HandshakeWithServer (NULL))
+ if (!m_gdb_comm.HandshakeWithServer (&error))
{
m_gdb_comm.Disconnect();
if (error.Success())
error.SetErrorString("not connected to remote gdb server");
return error;
}
- m_gdb_comm.ResetDiscoverableSettings();
- m_gdb_comm.QueryNoAckModeSupported ();
m_gdb_comm.GetThreadSuffixSupported ();
m_gdb_comm.GetListThreadsInStopReplySupported ();
m_gdb_comm.GetHostInfo ();
@@ -1158,6 +1156,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait
}
+bool
+ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr)
+{
+ m_gdb_comm.Disconnect();
+ return Process::SetExitStatus (exit_status, cstr);
+}
+
void
ProcessGDBRemote::DidAttach ()
{
@@ -2787,6 +2792,7 @@ ProcessGDBRemote::MonitorDebugserverProcess
void
ProcessGDBRemote::KillDebugserverProcess ()
{
+ m_gdb_comm.Disconnect();
if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
{
Host::Kill (m_debugserver_pid, SIGINT);
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index b18ac5b..3524407 100644
--- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -222,6 +222,13 @@ public:
{
return m_gdb_comm;
}
+
+ //----------------------------------------------------------------------
+ // Override SetExitStatus so we can disconnect from the remote GDB server
+ //----------------------------------------------------------------------
+ virtual bool
+ SetExitStatus (int exit_status, const char *cstr);
+
protected:
friend class ThreadGDBRemote;
OpenPOWER on IntegriCloud