forked from OSchip/llvm-project
Switch local launching of debugserver over to always use a FIFO in order to handshake with the launched debugserver.
This helps ensure that the launched debugserver is ready and listening for a connection. Prior to this we had a race condition. Consolidate the launching of debugserver into a single place: a static function in GDBRemoteCommunication. llvm-svn: 196401
This commit is contained in:
parent
c15bf89122
commit
91a9b247d4
|
@ -142,15 +142,6 @@ public:
|
|||
{
|
||||
return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
// Start a debugserver instance on the current host using the
|
||||
// supplied connection URL.
|
||||
//------------------------------------------------------------------
|
||||
lldb_private::Error
|
||||
StartDebugserverProcess (const char *connect_url,
|
||||
const char *unix_socket_name,
|
||||
lldb_private::ProcessLaunchInfo &launch_info);
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Public Request Packets
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// C Includes
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
|
@ -539,9 +540,11 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
|
|||
|
||||
Error
|
||||
GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
|
||||
const char *unix_socket_name, // For handshaking
|
||||
lldb_private::ProcessLaunchInfo &launch_info)
|
||||
lldb_private::ProcessLaunchInfo &launch_info,
|
||||
uint16_t &port)
|
||||
{
|
||||
port = 0;
|
||||
|
||||
Error error;
|
||||
// If we locate debugserver, keep that located version around
|
||||
static FileSpec g_debugserver_file_spec;
|
||||
|
@ -598,11 +601,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
|
|||
// special terminal key sequences (^C) don't affect debugserver
|
||||
debugserver_args.AppendArgument("--setsid");
|
||||
|
||||
if (unix_socket_name && unix_socket_name[0])
|
||||
char named_pipe_path[PATH_MAX];
|
||||
|
||||
// Create a temporary file to get the stdout/stderr and redirect the
|
||||
// output of the command into this file. We will later read this file
|
||||
// if all goes well and fill the data into "command_output_ptr"
|
||||
FileSpec tmpdir_file_spec;
|
||||
if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
|
||||
{
|
||||
debugserver_args.AppendArgument("--unix-socket");
|
||||
debugserver_args.AppendArgument(unix_socket_name);
|
||||
tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
|
||||
strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
|
||||
}
|
||||
|
||||
if (::mktemp (named_pipe_path))
|
||||
{
|
||||
if (::mkfifo(named_pipe_path, 0600) == 0)
|
||||
{
|
||||
debugserver_args.AppendArgument("--named-pipe");
|
||||
debugserver_args.AppendArgument(named_pipe_path);
|
||||
}
|
||||
else
|
||||
named_pipe_path[0] = '\0';
|
||||
}
|
||||
else
|
||||
named_pipe_path[0] = '\0';
|
||||
|
||||
const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
|
||||
if (env_debugserver_log_file)
|
||||
|
@ -617,46 +643,33 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
|
|||
::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
|
||||
debugserver_args.AppendArgument(arg_cstr);
|
||||
}
|
||||
// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
|
||||
// debugserver_args.AppendArgument("--log-flags=0x802e0e");
|
||||
|
||||
// We currently send down all arguments, attach pids, or attach
|
||||
// process names in dedicated GDB server packets, so we don't need
|
||||
// to pass them as arguments. This is currently because of all the
|
||||
// things we need to setup prior to launching: the environment,
|
||||
// current working dir, file actions, etc.
|
||||
#if 0
|
||||
// Now append the program arguments
|
||||
if (inferior_argv)
|
||||
{
|
||||
// Terminate the debugserver args so we can now append the inferior args
|
||||
debugserver_args.AppendArgument("--");
|
||||
|
||||
for (int i = 0; inferior_argv[i] != NULL; ++i)
|
||||
debugserver_args.AppendArgument (inferior_argv[i]);
|
||||
}
|
||||
else if (attach_pid != LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
|
||||
debugserver_args.AppendArgument (arg_cstr);
|
||||
}
|
||||
else if (attach_name && attach_name[0])
|
||||
{
|
||||
if (wait_for_launch)
|
||||
debugserver_args.AppendArgument ("--waitfor");
|
||||
else
|
||||
debugserver_args.AppendArgument ("--attach");
|
||||
debugserver_args.AppendArgument (attach_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Close STDIN, STDOUT and STDERR. We might need to redirect them
|
||||
// to "/dev/null" if we run into any problems.
|
||||
// launch_info.AppendCloseFileAction (STDIN_FILENO);
|
||||
// launch_info.AppendCloseFileAction (STDOUT_FILENO);
|
||||
// launch_info.AppendCloseFileAction (STDERR_FILENO);
|
||||
launch_info.AppendCloseFileAction (STDIN_FILENO);
|
||||
launch_info.AppendCloseFileAction (STDOUT_FILENO);
|
||||
launch_info.AppendCloseFileAction (STDERR_FILENO);
|
||||
|
||||
error = Host::LaunchProcess(launch_info);
|
||||
|
||||
if (named_pipe_path[0])
|
||||
{
|
||||
File name_pipe_file;
|
||||
error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead);
|
||||
if (error.Success())
|
||||
{
|
||||
char port_cstr[256];
|
||||
port_cstr[0] = '\0';
|
||||
size_t num_bytes = sizeof(port_cstr);
|
||||
error = name_pipe_file.Read(port_cstr, num_bytes);
|
||||
assert (error.Success());
|
||||
assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
|
||||
port = Args::StringToUInt32(port_cstr, 0);
|
||||
name_pipe_file.Close();
|
||||
}
|
||||
Host::Unlink(named_pipe_path);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -108,10 +108,10 @@ public:
|
|||
// Start a debugserver instance on the current host using the
|
||||
// supplied connection URL.
|
||||
//------------------------------------------------------------------
|
||||
lldb_private::Error
|
||||
static lldb_private::Error
|
||||
StartDebugserverProcess (const char *connect_url,
|
||||
const char *unix_socket_name,
|
||||
lldb_private::ProcessLaunchInfo &launch_info);
|
||||
lldb_private::ProcessLaunchInfo &launch_info,
|
||||
uint16_t &port);
|
||||
|
||||
void
|
||||
DumpHistory(lldb_private::Stream &strm);
|
||||
|
|
|
@ -775,7 +775,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
|
|||
{
|
||||
// Sleep and wait a bit for debugserver to start to listen...
|
||||
ConnectionFileDescriptor file_conn;
|
||||
char connect_url[PATH_MAX];
|
||||
Error error;
|
||||
std::string hostname;
|
||||
// TODO: /tmp/ should not be hardcoded. User might want to override /tmp
|
||||
|
@ -796,26 +795,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
|
|||
|
||||
// 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 (::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 (error.Success())
|
||||
{
|
||||
|
@ -832,9 +811,9 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
|
|||
|
||||
debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
|
||||
|
||||
error = StartDebugserverProcess (host_and_port_cstr,
|
||||
unix_socket_name,
|
||||
debugserver_launch_info);
|
||||
error = GDBRemoteCommunication::StartDebugserverProcess (host_and_port_cstr,
|
||||
debugserver_launch_info,
|
||||
port);
|
||||
|
||||
lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
|
||||
|
||||
|
@ -856,32 +835,10 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
|
|||
{
|
||||
bool success = false;
|
||||
|
||||
if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
|
||||
{
|
||||
thread_result_t accept_thread_result = NULL;
|
||||
if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
|
||||
{
|
||||
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 + 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 + m_port_offset);
|
||||
assert (response_len < sizeof(response));
|
||||
//m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
|
||||
success = SendPacketNoLock (response, response_len) > 0;
|
||||
|
||||
}
|
||||
Host::Unlink (unix_socket_name);
|
||||
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));
|
||||
success = SendPacketNoLock (response, response_len) > 0;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
|
@ -890,10 +847,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote
|
|||
}
|
||||
return success;
|
||||
}
|
||||
else if (accept_thread)
|
||||
{
|
||||
Host::Unlink (unix_socket_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SendErrorResponse (9);
|
||||
|
|
|
@ -167,34 +167,6 @@ namespace {
|
|||
|
||||
} // anonymous namespace end
|
||||
|
||||
static bool rand_initialized = false;
|
||||
|
||||
// TODO Randomly assigning a port is unsafe. We should get an unused
|
||||
// ephemeral port from the kernel and make sure we reserve it before passing
|
||||
// it to debugserver.
|
||||
|
||||
#if defined (__APPLE__)
|
||||
#define LOW_PORT (IPPORT_RESERVED)
|
||||
#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
|
||||
#else
|
||||
#define LOW_PORT (1024u)
|
||||
#define HIGH_PORT (49151u)
|
||||
#endif
|
||||
|
||||
static inline uint16_t
|
||||
get_random_port ()
|
||||
{
|
||||
if (!rand_initialized)
|
||||
{
|
||||
time_t seed = time(NULL);
|
||||
|
||||
rand_initialized = true;
|
||||
srand(seed);
|
||||
}
|
||||
return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT;
|
||||
}
|
||||
|
||||
|
||||
lldb_private::ConstString
|
||||
ProcessGDBRemote::GetPluginNameStatic()
|
||||
{
|
||||
|
@ -728,23 +700,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_
|
|||
ObjectFile * object_file = exe_module->GetObjectFile();
|
||||
if (object_file)
|
||||
{
|
||||
char host_port[128];
|
||||
snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
|
||||
char connect_url[128];
|
||||
snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
|
||||
|
||||
// Make sure we aren't already connected?
|
||||
if (!m_gdb_comm.IsConnected())
|
||||
{
|
||||
error = StartDebugserverProcess (host_port, launch_info);
|
||||
if (error.Fail())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("failed to start debugserver process: %s", error.AsCString());
|
||||
return error;
|
||||
}
|
||||
|
||||
error = ConnectToDebugserver (connect_url);
|
||||
error = LaunchAndConnectToDebugserver (launch_info);
|
||||
}
|
||||
|
||||
if (error.Success())
|
||||
|
@ -1040,12 +999,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process
|
|||
// Make sure we aren't already connected?
|
||||
if (!m_gdb_comm.IsConnected())
|
||||
{
|
||||
char host_port[128];
|
||||
snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
|
||||
char connect_url[128];
|
||||
snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
|
||||
|
||||
error = StartDebugserverProcess (host_port, attach_info);
|
||||
error = LaunchAndConnectToDebugserver (attach_info);
|
||||
|
||||
if (error.Fail())
|
||||
{
|
||||
|
@ -1055,10 +1009,6 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process
|
|||
|
||||
SetExitStatus (-1, error_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = ConnectToDebugserver (connect_url);
|
||||
}
|
||||
}
|
||||
|
||||
if (error.Success())
|
||||
|
@ -1105,12 +1055,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait
|
|||
// Make sure we aren't already connected?
|
||||
if (!m_gdb_comm.IsConnected())
|
||||
{
|
||||
char host_port[128];
|
||||
snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
|
||||
char connect_url[128];
|
||||
snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
|
||||
error = LaunchAndConnectToDebugserver (attach_info);
|
||||
|
||||
error = StartDebugserverProcess (host_port, attach_info);
|
||||
if (error.Fail())
|
||||
{
|
||||
const char *error_string = error.AsCString();
|
||||
|
@ -1119,10 +1065,6 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait
|
|||
|
||||
SetExitStatus (-1, error_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = ConnectToDebugserver (connect_url);
|
||||
}
|
||||
}
|
||||
|
||||
if (error.Success())
|
||||
|
@ -2546,157 +2488,45 @@ ProcessGDBRemote::DoSignal (int signo)
|
|||
}
|
||||
|
||||
Error
|
||||
ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url)
|
||||
{
|
||||
ProcessLaunchInfo launch_info;
|
||||
return StartDebugserverProcess(debugserver_url, launch_info);
|
||||
}
|
||||
|
||||
Error
|
||||
ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const ProcessInfo &process_info) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
|
||||
ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info)
|
||||
{
|
||||
Error error;
|
||||
uint16_t port = 0;
|
||||
if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
// If we locate debugserver, keep that located version around
|
||||
static FileSpec g_debugserver_file_spec;
|
||||
|
||||
ProcessLaunchInfo debugserver_launch_info;
|
||||
char debugserver_path[PATH_MAX];
|
||||
FileSpec &debugserver_file_spec = debugserver_launch_info.GetExecutableFile();
|
||||
debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
|
||||
debugserver_launch_info.SetUserID(process_info.GetUserID());
|
||||
|
||||
// Always check to see if we have an environment override for the path
|
||||
// to the debugserver to use and use it if we do.
|
||||
const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
|
||||
if (env_debugserver_path)
|
||||
debugserver_file_spec.SetFile (env_debugserver_path, false);
|
||||
error = GDBRemoteCommunication::StartDebugserverProcess ("localhost:0",
|
||||
debugserver_launch_info,
|
||||
port);
|
||||
|
||||
if (error.Success ())
|
||||
m_debugserver_pid = debugserver_launch_info.GetProcessID();
|
||||
else
|
||||
debugserver_file_spec = g_debugserver_file_spec;
|
||||
bool debugserver_exists = debugserver_file_spec.Exists();
|
||||
if (!debugserver_exists)
|
||||
{
|
||||
// The debugserver binary is in the LLDB.framework/Resources
|
||||
// directory.
|
||||
if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
|
||||
{
|
||||
debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
|
||||
debugserver_exists = debugserver_file_spec.Exists();
|
||||
if (debugserver_exists)
|
||||
{
|
||||
g_debugserver_file_spec = debugserver_file_spec;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debugserver_file_spec.Clear();
|
||||
debugserver_file_spec.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debugserver_exists)
|
||||
{
|
||||
debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
|
||||
|
||||
m_stdio_communication.Clear();
|
||||
|
||||
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
|
||||
|
||||
Args &debugserver_args = debugserver_launch_info.GetArguments();
|
||||
char arg_cstr[PATH_MAX];
|
||||
|
||||
// Start args with "debugserver /file/path -r --"
|
||||
debugserver_args.AppendArgument(debugserver_path);
|
||||
debugserver_args.AppendArgument(debugserver_url);
|
||||
// use native registers, not the GDB registers
|
||||
debugserver_args.AppendArgument("--native-regs");
|
||||
// make debugserver run in its own session so signals generated by
|
||||
// special terminal key sequences (^C) don't affect debugserver
|
||||
debugserver_args.AppendArgument("--setsid");
|
||||
|
||||
const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
|
||||
if (env_debugserver_log_file)
|
||||
{
|
||||
::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
|
||||
debugserver_args.AppendArgument(arg_cstr);
|
||||
}
|
||||
|
||||
const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
|
||||
if (env_debugserver_log_flags)
|
||||
{
|
||||
::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
|
||||
debugserver_args.AppendArgument(arg_cstr);
|
||||
}
|
||||
// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
|
||||
// debugserver_args.AppendArgument("--log-flags=0x802e0e");
|
||||
|
||||
// We currently send down all arguments, attach pids, or attach
|
||||
// process names in dedicated GDB server packets, so we don't need
|
||||
// to pass them as arguments. This is currently because of all the
|
||||
// things we need to setup prior to launching: the environment,
|
||||
// current working dir, file actions, etc.
|
||||
#if 0
|
||||
// Now append the program arguments
|
||||
if (inferior_argv)
|
||||
{
|
||||
// Terminate the debugserver args so we can now append the inferior args
|
||||
debugserver_args.AppendArgument("--");
|
||||
|
||||
for (int i = 0; inferior_argv[i] != NULL; ++i)
|
||||
debugserver_args.AppendArgument (inferior_argv[i]);
|
||||
}
|
||||
else if (attach_pid != LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
|
||||
debugserver_args.AppendArgument (arg_cstr);
|
||||
}
|
||||
else if (attach_name && attach_name[0])
|
||||
{
|
||||
if (wait_for_launch)
|
||||
debugserver_args.AppendArgument ("--waitfor");
|
||||
else
|
||||
debugserver_args.AppendArgument ("--attach");
|
||||
debugserver_args.AppendArgument (attach_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
ProcessLaunchInfo::FileAction file_action;
|
||||
|
||||
// Close STDIN, STDOUT and STDERR. We might need to redirect them
|
||||
// to "/dev/null" if we run into any problems.
|
||||
file_action.Close (STDIN_FILENO);
|
||||
debugserver_launch_info.AppendFileAction (file_action);
|
||||
file_action.Close (STDOUT_FILENO);
|
||||
debugserver_launch_info.AppendFileAction (file_action);
|
||||
file_action.Close (STDERR_FILENO);
|
||||
debugserver_launch_info.AppendFileAction (file_action);
|
||||
|
||||
if (log)
|
||||
{
|
||||
StreamString strm;
|
||||
debugserver_args.Dump (&strm);
|
||||
log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData());
|
||||
}
|
||||
|
||||
debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
|
||||
debugserver_launch_info.SetUserID(process_info.GetUserID());
|
||||
|
||||
error = Host::LaunchProcess(debugserver_launch_info);
|
||||
|
||||
if (error.Success ())
|
||||
m_debugserver_pid = debugserver_launch_info.GetProcessID();
|
||||
else
|
||||
m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
|
||||
|
||||
if (error.Fail() || log)
|
||||
error.PutToLog(log, "Host::LaunchProcess (launch_info) => pid=%" PRIu64 ", path='%s'", m_debugserver_pid, debugserver_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME);
|
||||
}
|
||||
m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
|
||||
|
||||
if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
|
||||
StartAsyncThread ();
|
||||
|
||||
if (error.Fail())
|
||||
{
|
||||
Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
|
||||
|
||||
if (log)
|
||||
log->Printf("failed to start debugserver process: %s", error.AsCString());
|
||||
return error;
|
||||
}
|
||||
|
||||
char connect_url[128];
|
||||
snprintf (connect_url, sizeof(connect_url), "connect://localhost:%u", port);
|
||||
|
||||
error = ConnectToDebugserver (connect_url);
|
||||
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -284,10 +284,7 @@ protected:
|
|||
lldb_private::ThreadList &new_thread_list);
|
||||
|
||||
lldb_private::Error
|
||||
StartDebugserverProcess (const char *debugserver_url);
|
||||
|
||||
lldb_private::Error
|
||||
StartDebugserverProcess (const char *debugserver_url, const lldb_private::ProcessInfo &process_info);
|
||||
LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info);
|
||||
|
||||
void
|
||||
KillDebugserverProcess ();
|
||||
|
|
|
@ -915,7 +915,6 @@ RNBRemote::InitializeRegisters (bool force)
|
|||
|
||||
if (reg_entry.nub_info.value_regs == NULL)
|
||||
{
|
||||
DNBLogThreaded("%s -> %u", reg_entry.nub_info.name, reg_data_offset);
|
||||
reg_data_offset += reg_entry.nub_info.size;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,20 +120,6 @@ RNBSocket::Listen (const char *listen_host, in_port_t port, PortBoundCallback ca
|
|||
return rnb_err;
|
||||
}
|
||||
|
||||
if (callback && port == 0)
|
||||
{
|
||||
// We were asked to listen on port zero which means we
|
||||
// must now read the actual port that was given to us
|
||||
// as port zero is a special code for "find an open port
|
||||
// for me".
|
||||
socklen_t sa_len = sizeof (sa);
|
||||
if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0)
|
||||
{
|
||||
port = ntohs (sa.sin_port);
|
||||
callback (callback_baton, port);
|
||||
}
|
||||
}
|
||||
|
||||
error = ::listen (listen_fd, 5);
|
||||
if (error == -1)
|
||||
err.SetError(errno, DNBError::POSIX);
|
||||
|
@ -146,6 +132,27 @@ RNBSocket::Listen (const char *listen_host, in_port_t port, PortBoundCallback ca
|
|||
ClosePort (listen_fd, false);
|
||||
return rnb_err;
|
||||
}
|
||||
|
||||
if (callback)
|
||||
{
|
||||
// We were asked to listen on port zero which means we
|
||||
// must now read the actual port that was given to us
|
||||
// as port zero is a special code for "find an open port
|
||||
// for me".
|
||||
if (port == 0)
|
||||
{
|
||||
socklen_t sa_len = sizeof (sa);
|
||||
if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0)
|
||||
{
|
||||
port = ntohs (sa.sin_port);
|
||||
callback (callback_baton, port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callback (callback_baton, port);
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in accept_addr;
|
||||
::memset (&accept_addr, 0, sizeof accept_addr);
|
||||
|
|
|
@ -625,73 +625,32 @@ RNBRunLoopPlatform (RNBRemote *remote)
|
|||
return eRNBRunLoopModeExit;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Convenience function to set up the remote listening port
|
||||
// Returns 1 for success 0 for failure.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
PortWasBoundCallback (const void *baton, in_port_t port)
|
||||
PortWasBoundCallbackNamedPipe (const void *baton, in_port_t port)
|
||||
{
|
||||
//::printf ("PortWasBoundCallback (baton = %p, port = %u)\n", baton, port);
|
||||
|
||||
const char *unix_socket_name = (const char *)baton;
|
||||
|
||||
if (unix_socket_name && unix_socket_name[0])
|
||||
const char *named_pipe = (const char *)baton;
|
||||
if (named_pipe && named_pipe[0])
|
||||
{
|
||||
// We were given a unix socket name to use to communicate the port
|
||||
// that we ended up binding to back to our parent process
|
||||
struct sockaddr_un saddr_un;
|
||||
int s = ::socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (s < 0)
|
||||
int fd = ::open(named_pipe, O_WRONLY);
|
||||
if (fd > -1)
|
||||
{
|
||||
perror("error: socket (AF_UNIX, SOCK_STREAM, 0)");
|
||||
exit(1);
|
||||
char port_str[64];
|
||||
const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port);
|
||||
// Write the port number as a C string with the NULL terminator
|
||||
::write (fd, port_str, port_str_len + 1);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
saddr_un.sun_family = AF_UNIX;
|
||||
::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1);
|
||||
saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
|
||||
saddr_un.sun_len = SUN_LEN (&saddr_un);
|
||||
|
||||
if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
|
||||
{
|
||||
perror("error: connect (socket, &saddr_un, saddr_un_len)");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//::printf ("connect () sucess!!\n");
|
||||
|
||||
|
||||
// We were able to connect to the socket, now write our PID so whomever
|
||||
// launched us will know this process's ID
|
||||
RNBLogSTDOUT ("Listening to port %i...\n", port);
|
||||
|
||||
char pid_str[64];
|
||||
const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port);
|
||||
const int bytes_sent = ::send (s, pid_str, pid_str_len, 0);
|
||||
|
||||
if (pid_str_len != bytes_sent)
|
||||
{
|
||||
perror("error: send (s, pid_str, pid_str_len, 0)");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
//::printf ("send () sucess!!\n");
|
||||
|
||||
// We are done with the socket
|
||||
close (s);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
StartListening (RNBRemote *remote, const char *listen_host, int listen_port, const char *unix_socket_name)
|
||||
StartListening (RNBRemote *remote, const char *listen_host, int listen_port, const char *named_pipe_path)
|
||||
{
|
||||
if (!remote->Comm().IsConnected())
|
||||
{
|
||||
if (listen_port != 0)
|
||||
RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", listen_port, listen_host ? listen_host : "localhost");
|
||||
if (remote->Comm().Listen(listen_host, listen_port, PortWasBoundCallback, unix_socket_name) != rnb_success)
|
||||
if (remote->Comm().Listen(listen_host, listen_port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success)
|
||||
{
|
||||
RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
|
||||
return 0;
|
||||
|
@ -786,7 +745,7 @@ static struct option g_long_options[] =
|
|||
{ "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization
|
||||
{ "working-dir", required_argument, NULL, 'W' }, // The working directory that the inferior process should have (only if debugserver launches the process)
|
||||
{ "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode
|
||||
{ "unix-socket", required_argument, NULL, 'u' }, // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use
|
||||
{ "named-pipe", required_argument, NULL, 'P' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
|
@ -838,7 +797,7 @@ main (int argc, char *argv[])
|
|||
std::string attach_pid_name;
|
||||
std::string arch_name;
|
||||
std::string working_dir; // The new working directory to use for the inferior
|
||||
std::string unix_socket_name; // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use
|
||||
std::string named_pipe_path; // If we need to handshake with our parent process, an option will be passed down that specifies a named pipe to use
|
||||
useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
|
||||
useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever.
|
||||
bool no_stdio = false;
|
||||
|
@ -1086,8 +1045,8 @@ main (int argc, char *argv[])
|
|||
start_mode = eRNBRunLoopModePlatformMode;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
unix_socket_name.assign (optarg);
|
||||
case 'P':
|
||||
named_pipe_path.assign (optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1306,7 +1265,7 @@ main (int argc, char *argv[])
|
|||
#endif
|
||||
if (listen_port != INT32_MAX)
|
||||
{
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
|
||||
mode = eRNBRunLoopModeExit;
|
||||
}
|
||||
else if (str[0] == '/')
|
||||
|
@ -1419,7 +1378,7 @@ main (int argc, char *argv[])
|
|||
{
|
||||
if (listen_port != INT32_MAX)
|
||||
{
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
|
||||
mode = eRNBRunLoopModeExit;
|
||||
}
|
||||
else if (str[0] == '/')
|
||||
|
@ -1444,7 +1403,7 @@ main (int argc, char *argv[])
|
|||
{
|
||||
if (listen_port != INT32_MAX)
|
||||
{
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
|
||||
mode = eRNBRunLoopModeExit;
|
||||
}
|
||||
else if (str[0] == '/')
|
||||
|
@ -1471,7 +1430,7 @@ main (int argc, char *argv[])
|
|||
case eRNBRunLoopModePlatformMode:
|
||||
if (listen_port != INT32_MAX)
|
||||
{
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str()))
|
||||
if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
|
||||
mode = eRNBRunLoopModeExit;
|
||||
}
|
||||
else if (str[0] == '/')
|
||||
|
|
Loading…
Reference in New Issue