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;
}
Esempio n. 2
0
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;
}