Error GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, uint16_t in_port, lldb_private::ProcessLaunchInfo &launch_info, uint16_t &out_port) { out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // 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); 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)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); // If a host and port is supplied then use it char host_and_port[128]; if (hostname) { snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); debugserver_args.AppendArgument(host_and_port); } else { host_and_port[0] = '\0'; } // 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"); char named_pipe_path[PATH_MAX]; named_pipe_path[0] = '\0'; bool listen = false; if (host_and_port[0]) { // 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" if (in_port == 0) { // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... FileSpec tmpdir_file_spec; if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { 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 { listen = true; } } else { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. error = StartListenThread ("localhost", 0); if (error.Fail()) return error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); out_port = connection->GetBoundPort(3); assert (out_port != 0); char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); // Send the host and port down that debugserver and specify an option // so that it connects back to the port we are listening to in this process debugserver_args.AppendArgument("--reverse-connect"); debugserver_args.AppendArgument(port_cstr); } 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); } // 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); 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'); out_port = Args::StringToUInt32(port_cstr, 0); name_pipe_file.Close(); } Host::Unlink(named_pipe_path); } else if (listen) { } else { // Make sure we actually connect with the debugserver... JoinListenThread(); } } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, const char *unix_socket_name, // For handshaking lldb_private::ProcessLaunchInfo &launch_info) { Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; // This function will fill in the launch information for the debugserver // instance that gets launched. launch_info.Clear(); char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // 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); 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)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); 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"); if (unix_socket_name && unix_socket_name[0]) { debugserver_args.AppendArgument("--unix-socket"); debugserver_args.AppendArgument(unix_socket_name); } 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 // 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); error = Host::LaunchProcess(launch_info); } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }