summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp369
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h58
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp503
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h75
5 files changed, 977 insertions, 32 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index d7efdf2302d..46bd9ca8069 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -133,7 +133,11 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,
const char *listener_name,
bool is_platform) :
Communication(comm_name),
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_packet_timeout (1000),
+#else
m_packet_timeout (1),
+#endif
m_sequence_mutex (Mutex::eMutexTypeRecursive),
m_public_is_running (false),
m_private_is_running (false),
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 6a6e063e35b..e3183fca1db 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -20,6 +20,7 @@
#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/State.h"
+#include "lldb/Core/StreamGDBRemote.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Endian.h"
#include "lldb/Host/Host.h"
@@ -2137,21 +2138,37 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t
}
uint16_t
-GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort ()
+GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
{
+ pid = LLDB_INVALID_PROCESS_ID;
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false))
+ StreamString stream;
+ stream.PutCString("qLaunchGDBServer:port:0;");
+ std::string hostname;
+ if (Host::GetHostname (hostname))
+ {
+ // Make the GDB server we launch only accept connections from this host
+ stream.Printf("host:%s;", hostname.c_str());
+ }
+ else
+ {
+ // Make the GDB server we launch accept connections from any host since we can't figure out the hostname
+ stream.Printf("host:*;");
+ }
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
{
std::string name;
std::string value;
uint16_t port = 0;
- //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
while (response.GetNameColonValue(name, value))
{
- if (name.size() == 4 && name.compare("port") == 0)
+ if (name.compare("port") == 0)
port = Args::StringToUInt32(value.c_str(), 0, 0);
-// if (name.size() == 3 && name.compare("pid") == 0)
-// pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
+ else if (name.compare("pid") == 0)
+ pid = Args::StringToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
}
return port;
}
@@ -2159,6 +2176,23 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort ()
}
bool
+GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid)
+{
+ StreamString stream;
+ stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid);
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ pid = LLDB_INVALID_PROCESS_ID;
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ return false;
+}
+
+bool
GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid)
{
if (m_curr_tid == tid)
@@ -2351,3 +2385,326 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr()
return LLDB_INVALID_ADDRESS;
}
+lldb_private::Error
+GDBRemoteCommunicationClient::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
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ 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
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_RunCommand:");
+ stream.PutBytesAsRawHex8(command, strlen(command));
+ stream.PutChar(',');
+ stream.PutHex32(timeout_sec);
+ if (working_dir && *working_dir)
+ {
+ stream.PutChar(',');
+ stream.PutBytesAsRawHex8(working_dir, strlen(working_dir));
+ }
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return Error("malformed reply");
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX);
+ if (exitcode == UINT32_MAX)
+ return Error("unable to run remote process");
+ else if (status_ptr)
+ *status_ptr = exitcode;
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX);
+ if (signo_ptr)
+ *signo_ptr = signo;
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ std::string output;
+ response.GetEscapedBinaryData(output);
+ if (command_output)
+ command_output->assign(output);
+ return Error();
+ }
+ return Error("unable to send packet");
+}
+
+uint32_t
+GDBRemoteCommunicationClient::MakeDirectory (const std::string &path,
+ mode_t mode)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_IO_MkDir:");
+ stream.PutHex32(mode);
+ stream.PutChar(',');
+ stream.PutBytesAsRawHex8(path.c_str(), path.size());
+ 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 UINT32_MAX;
+
+}
+
+static uint64_t
+ParseHostIOPacketResponse (StringExtractorGDBRemote &response,
+ uint64_t fail_result,
+ Error &error)
+{
+ response.SetFilePos(0);
+ if (response.GetChar() != 'F')
+ return fail_result;
+ int32_t result = response.GetS32 (-2);
+ if (result == -2)
+ return fail_result;
+ if (response.GetChar() == ',')
+ {
+ int result_errno = response.GetS32 (-2);
+ if (result_errno != -2)
+ error.SetError(result_errno, eErrorTypePOSIX);
+ else
+ error.SetError(-1, eErrorTypeGeneric);
+ }
+ else
+ error.Clear();
+ return result;
+}
+lldb::user_id_t
+GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:open:");
+ std::string path (file_spec.GetPath());
+ if (path.empty())
+ return UINT64_MAX;
+ stream.PutCStringAsRawHex8(path.c_str());
+ stream.PutChar(',');
+ const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags);
+ stream.PutHex32(posix_open_flags);
+ stream.PutChar(',');
+ stream.PutHex32(mode);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ return ParseHostIOPacketResponse (response, UINT64_MAX, error);
+ }
+ return UINT64_MAX;
+}
+
+bool
+GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:close:%i", (int)fd);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ return ParseHostIOPacketResponse (response, -1, error) == 0;
+ }
+ return UINT64_MAX;
+}
+
+// Extension of host I/O packets to get the file size.
+lldb::user_id_t
+GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:size:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return UINT64_MAX;
+ uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
+ return retcode;
+ }
+ return UINT64_MAX;
+}
+
+uint32_t
+GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:mode:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ {
+ error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet);
+ return 0;
+ }
+ const uint32_t mode = response.GetS32(-1);
+ if (mode == -1)
+ {
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ else
+ error.SetErrorToGenericError();
+ }
+ }
+ else
+ error.Clear();
+ return mode & (S_IRWXU|S_IRWXG|S_IRWXO);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("failed to send '%s' packet", packet);
+ }
+ return 0;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return 0;
+ uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX);
+ if (retcode == UINT32_MAX)
+ return retcode;
+ const char next = (response.Peek() ? *response.Peek() : 0);
+ if (next == ',')
+ return 0;
+ if (next == ';')
+ {
+ response.GetChar(); // skip the semicolon
+ std::string buffer;
+ if (response.GetEscapedBinaryData(buffer))
+ {
+ const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size());
+ if (data_to_write > 0)
+ memcpy(dst, &buffer[0], data_to_write);
+ return data_to_write;
+ }
+ }
+ }
+ return 0;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error)
+{
+ lldb_private::StreamGDBRemote stream;
+ stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset);
+ stream.PutEscapedBytes(src, src_len);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ {
+ error.SetErrorStringWithFormat("write file failed");
+ return 0;
+ }
+ uint64_t bytes_written = response.GetU64(UINT64_MAX);
+ if (bytes_written == UINT64_MAX)
+ {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ return 0;
+ }
+ return bytes_written;
+ }
+ else
+ {
+ error.SetErrorString ("failed to send vFile:pwrite packet");
+ }
+ return 0;
+}
+
+// Extension of host I/O packets to get whether a file exists.
+bool
+GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:exists:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ bool retcode = (response.GetChar() != '0');
+ return retcode;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec,
+ uint64_t &high,
+ uint64_t &low)
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:MD5:");
+ std::string path (file_spec.GetPath());
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ if (response.Peek() && *response.Peek() == 'x')
+ return false;
+ low = response.GetHexMaxU64(false, UINT64_MAX);
+ high = response.GetHexMaxU64(false, UINT64_MAX);
+ return true;
+ }
+ return false;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 5bb8387b909..c8809cbf445 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -89,7 +89,10 @@ public:
GetLaunchSuccess (std::string &error_str);
uint16_t
- LaunchGDBserverAndGetPort ();
+ LaunchGDBserverAndGetPort (lldb::pid_t &pid);
+
+ bool
+ KillSpawnedProcess (lldb::pid_t pid);
//------------------------------------------------------------------
/// Sends a GDB remote protocol 'A' packet that delivers program
@@ -347,10 +350,61 @@ public:
return m_interrupt_sent;
}
+ virtual lldb::user_id_t
+ OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ lldb_private::Error &error);
+
+ virtual bool
+ CloseFile (lldb::user_id_t fd,
+ lldb_private::Error &error);
+
+ virtual 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);
+
+ virtual uint64_t
+ ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ lldb_private::Error &error);
+
+ virtual 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);
+
+ virtual bool
+ GetFileExists (const lldb_private::FileSpec& file_spec);
+
+ virtual 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
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ 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
+ CalculateMD5 (const lldb_private::FileSpec& file_spec,
+ uint64_t &high,
+ uint64_t &low);
+
std::string
HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
StringExtractorGDBRemote &inputStringExtractor);
-
+
protected:
bool
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index 050ed00ff6d..f6fdf1513eb 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -9,6 +9,7 @@
#include "GDBRemoteCommunicationServer.h"
+#include "lldb/Core/StreamGDBRemote.h"
// C Includes
// C++ Includes
@@ -20,6 +21,7 @@
#include "lldb/Core/State.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Endian.h"
+#include "lldb/Host/File.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/TimeValue.h"
#include "lldb/Target/Process.h"
@@ -40,11 +42,31 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
m_async_thread (LLDB_INVALID_HOST_THREAD),
m_process_launch_info (),
m_process_launch_error (),
+ m_spawned_pids (),
+ 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_hi_port_num (0),
+ m_next_port (0),
+ m_use_port_range (false)
{
+ // 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);
+ }
}
//----------------------------------------------------------------------
@@ -125,6 +147,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
return Handle_qLaunchGDBServer (packet);
+ case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess:
+ return Handle_qKillSpawnedProcess (packet);
+
case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
return Handle_qLaunchSuccess (packet);
@@ -142,6 +167,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
return Handle_QEnvironment (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QLaunchArch:
+ return Handle_QLaunchArch (packet);
case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
return Handle_QSetDisableASLR (packet);
@@ -160,6 +188,39 @@ 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_RunCommand:
+ return Handle_qPlatform_RunCommand (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Open:
+ return Handle_vFile_Open (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Close:
+ return Handle_vFile_Close (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_pRead:
+ return Handle_vFile_pRead (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite:
+ return Handle_vFile_pWrite (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Size:
+ return Handle_vFile_Size (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Mode:
+ return Handle_vFile_Mode (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Exists:
+ return Handle_vFile_Exists (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_Stat:
+ return Handle_vFile_Stat (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_vFile_MD5:
+ return Handle_vFile_MD5 (packet);
}
return true;
}
@@ -666,6 +727,24 @@ GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
}
bool
+GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid)
+{
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ return m_spawned_pids.erase(pid) > 0;
+}
+bool
+GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton;
+ server->DebugserverProcessReaped (pid);
+ return true;
+}
+
+bool
GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
{
#ifdef _WIN32
@@ -681,47 +760,97 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
ConnectionFileDescriptor file_conn;
char connect_url[PATH_MAX];
Error error;
- char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
+ std::string hostname;
+ char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
if (::mktemp (unix_socket_name) == NULL)
{
error.SetErrorString ("failed to make temporary path for a unix socket");
}
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();
+
::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 = Host::ThreadCreate (unix_socket_name,
- AcceptPortFromInferior,
- connect_url,
- &error);
+ lldb::thread_t accept_thread = NULL;
+
+ if (port == 0)
+ {
+ accept_thread = Host::ThreadCreate (unix_socket_name,
+ AcceptPortFromInferior,
+ connect_url,
+ &error);
+ }
if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
{
- // Spawn a debugserver and try to get
+ // Spawn a debugserver and try to get the port it listens to.
ProcessLaunchInfo debugserver_launch_info;
- error = StartDebugserverProcess ("localhost:0",
+ 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);
+ }
+
if (error.Success())
{
bool success = false;
- thread_result_t accept_thread_result = NULL;
- if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
+ if (accept_thread)
{
- if (accept_thread_result)
+ thread_result_t accept_thread_result = NULL;
+ if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
{
- uint16_t 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 < (int)sizeof(response));
- //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
- success = SendPacketNoLock (response, response_len) > 0;
+ 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;
+ }
}
}
+ 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;
+
+ }
::unlink (unix_socket_name);
if (!success)
@@ -734,11 +863,64 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
}
}
}
- return SendErrorResponse (13);
+ return SendErrorResponse (9);
#endif
}
bool
+GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ if (m_is_platform)
+ {
+ packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+
+ lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return SendErrorResponse (10);
+ }
+ kill (pid, SIGTERM);
+
+ for (size_t i=0; i<10; ++i)
+ {
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+ usleep (10000);
+ }
+
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+ kill (pid, SIGKILL);
+
+ for (size_t i=0; i<10; ++i)
+ {
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+ usleep (10000);
+ }
+ }
+ return SendErrorResponse (10);
+}
+
+bool
GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
{
if (m_process_launch_error.Success())
@@ -759,7 +941,22 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa
m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
return SendOKResponse ();
}
- return SendErrorResponse (9);
+ return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QLaunchArch:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ const char* arch_triple = packet.Peek();
+ ArchSpec arch_spec(arch_triple,NULL);
+ m_process_launch_info.SetArchitecture(arch_spec);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(12);
}
bool
@@ -797,7 +994,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (10);
+ return SendErrorResponse (13);
}
bool
@@ -814,7 +1011,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (11);
+ return SendErrorResponse (14);
}
bool
@@ -831,7 +1028,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe
m_process_launch_info.AppendFileAction(file_action);
return SendOKResponse ();
}
- return SendErrorResponse (12);
+ return SendErrorResponse (15);
}
bool
@@ -842,3 +1039,265 @@ GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &
m_send_acks = false;
return true;
}
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_IO_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;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet)
+{
+ 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;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:close:"));
+ int fd = packet.GetS32(-1);
+ Error error;
+ int err = -1;
+ int save_errno = 0;
+ if (fd >= 0)
+ {
+ err = close(fd);
+ save_errno = err == -1 ? errno : 0;
+ }
+ else
+ {
+ save_errno = EINVAL;
+ }
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", err);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+{
+ 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
+ {
+ response.PutChar(';');
+ response.PutEscapedBytes(&buffer[0], bytes_read);
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+ StreamGDBRemote response;
+ 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
+ {
+ response.Printf ("-1,%i", EINVAL);
+ }
+
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet)
+{
+ 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)
+ {
+ response.PutChar(',');
+ response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+{
+ 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;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+{
+ 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));
+ StreamString response;
+ response.PutChar('F');
+ response.PutChar(',');
+ if (retcode)
+ response.PutChar('1');
+ else
+ response.PutChar('0');
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_RunCommand:"));
+ std::string path;
+ std::string working_dir;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (path.size() == 0)
+ return false;
+ if (packet.GetChar() != ',')
+ return false;
+ uint32_t timeout = packet.GetHexMaxU32(false, 32);
+ 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());
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
+{
+ return false;
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:exists:"));
+ 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)
+ {
+ response.PutCString("F,");
+ response.PutCString("x");
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex64(a);
+ response.PutHex64(b);
+ }
+ SendPacketNoLock(response.GetData(), response.GetSize());
+ return true;
+}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index cce0e4e64c1..64f6f8de1a2 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -12,10 +12,12 @@
// C Includes
// C++ Includes
+#include <vector>
+#include <set>
// Other libraries and framework includes
// Project includes
+#include "lldb/Host/Mutex.h"
#include "lldb/Target/Process.h"
-
#include "GDBRemoteCommunication.h"
class ProcessGDBRemote;
@@ -60,6 +62,21 @@ public:
{
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;
+ }
+
+ // If we are using a port range, get and update the next port to be used variable.
+ // Otherwise, just return 0.
+ uint16_t
+ GetAndUpdateNextPort ()
+ {
+ 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;
}
protected:
@@ -68,11 +85,16 @@ protected:
lldb::thread_t m_async_thread;
lldb_private::ProcessLaunchInfo m_process_launch_info;
lldb_private::Error m_process_launch_error;
+ std::set<lldb::pid_t> m_spawned_pids;
+ 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;
+
size_t
SendUnimplementedResponse (const char *packet);
@@ -85,7 +107,7 @@ protected:
bool
Handle_A (StringExtractorGDBRemote &packet);
-
+
bool
Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
@@ -94,8 +116,14 @@ protected:
bool
Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
bool
+ Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet);
+
+ bool
Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
bool
@@ -120,6 +148,9 @@ protected:
Handle_QEnvironment (StringExtractorGDBRemote &packet);
bool
+ Handle_QLaunchArch (StringExtractorGDBRemote &packet);
+
+ bool
Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
bool
@@ -137,7 +168,47 @@ protected:
bool
Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
+ bool
+ Handle_vFile_Open (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Close (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_pRead (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_pWrite (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Size (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Mode (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Exists (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_Stat (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet);
+
private:
+ bool
+ DebugserverProcessReaped (lldb::pid_t pid);
+
+ static bool
+ ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status);
+
//------------------------------------------------------------------
// For GDBRemoteCommunicationServer only
//------------------------------------------------------------------
OpenPOWER on IntegriCloud