//------------------------------------------------------------------------------
/// The basic design of the ProcessMonitor is built around two threads.
///
/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
/// for changes in the debugee state.  When a change is detected a
/// ProcessMessage is sent to the associated ProcessFreeBSD instance.  This thread
/// "drives" state changes in the debugger.
///
/// The second thread (@see OperationThread) is responsible for two things 1)
/// launching or attaching to the inferior process, and then 2) servicing
/// operations such as register reads/writes, stepping, etc.  See the comments
/// on the Operation class for more info as to why this is needed.
ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
                               Module *module,
                               const char *argv[],
                               const char *envp[],
                               const FileSpec &stdin_file_spec,
                               const FileSpec &stdout_file_spec,
                               const FileSpec &stderr_file_spec,
                               const FileSpec &working_dir,
                               const lldb_private::ProcessLaunchInfo & /* launch_info */,
                               lldb_private::Error &error)
    : m_process(static_cast<ProcessFreeBSD *>(process)),
      m_pid(LLDB_INVALID_PROCESS_ID),
      m_terminal_fd(-1),
      m_operation(0)
{
    std::unique_ptr<LaunchArgs> args(new LaunchArgs(this, module, argv, envp,
                                                    stdin_file_spec,
                                                    stdout_file_spec,
                                                    stderr_file_spec,
                                                    working_dir));
    

    sem_init(&m_operation_pending, 0, 0);
    sem_init(&m_operation_done, 0, 0);

    StartLaunchOpThread(args.get(), error);
    if (!error.Success())
        return;

WAIT_AGAIN:
    // Wait for the operation thread to initialize.
    if (sem_wait(&args->m_semaphore))
    {
        if (errno == EINTR)
            goto WAIT_AGAIN;
        else
        {
            error.SetErrorToErrno();
            return;
        }
    }

    // Check that the launch was a success.
    if (!args->m_error.Success())
    {
        StopOpThread();
        error = args->m_error;
        return;
    }

    // Finally, start monitoring the child process for change in state.
    m_monitor_thread = Host::StartMonitoringChildProcess(
        ProcessMonitor::MonitorCallback, this, GetPID(), true);
    if (!m_monitor_thread.IsJoinable())
    {
        error.SetErrorToGenericError();
        error.SetErrorString("Process launch failed.");
        return;
    }
}
Example #2
0
ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
                               lldb::pid_t pid,
                               lldb_private::Error &error)
    : m_process(static_cast<ProcessFreeBSD *>(process)),
      m_operation_thread(LLDB_INVALID_HOST_THREAD),
      m_monitor_thread(LLDB_INVALID_HOST_THREAD),
      m_pid(pid),
      m_terminal_fd(-1),
      m_operation(0)
{
    sem_init(&m_operation_pending, 0, 0);
    sem_init(&m_operation_done, 0, 0);


    std::unique_ptr<AttachArgs> args(new AttachArgs(this, pid));

    StartAttachOpThread(args.get(), error);
    if (!error.Success())
        return;

WAIT_AGAIN:
    // Wait for the operation thread to initialize.
    if (sem_wait(&args->m_semaphore))
    {
        if (errno == EINTR)
            goto WAIT_AGAIN;
        else
        {
            error.SetErrorToErrno();
            return;
        }
    }

    // Check that the attach was a success.
    if (!args->m_error.Success())
    {
        StopOpThread();
        error = args->m_error;
        return;
    }

    // Finally, start monitoring the child process for change in state.
    m_monitor_thread = Host::StartMonitoringChildProcess(
        ProcessMonitor::MonitorCallback, this, GetPID(), true);
    if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
    {
        error.SetErrorToGenericError();
        error.SetErrorString("Process attach failed.");
        return;
    }
}
lldb::ProcessSP PlatformRemoteGDBServer::ConnectProcess(
    const char *connect_url, const char *plugin_name,
    lldb_private::Debugger &debugger, lldb_private::Target *target,
    lldb_private::Error &error) {
  if (!IsRemote() || !IsConnected()) {
    error.SetErrorString("Not connected to remote gdb server");
    return nullptr;
  }
  return Platform::ConnectProcess(connect_url, plugin_name, debugger, target,
                                  error);
}
Example #4
0
ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
                               lldb::pid_t pid,
                               lldb_private::Error &error)
    : m_process(static_cast<ProcessFreeBSD *>(process)),
      m_operation_thread(LLDB_INVALID_HOST_THREAD),
      m_monitor_thread(LLDB_INVALID_HOST_THREAD),
      m_pid(pid),
      m_server_mutex(Mutex::eMutexTypeRecursive),
      m_terminal_fd(-1),
      m_client_fd(-1),
      m_server_fd(-1)
{
    std::auto_ptr<AttachArgs> args;

    args.reset(new AttachArgs(this, pid));

    // Server/client descriptors.
    if (!EnableIPC())
    {
        error.SetErrorToGenericError();
        error.SetErrorString("Monitor failed to initialize.");
    }

    StartAttachOpThread(args.get(), error);
    if (!error.Success())
        return;

WAIT_AGAIN:
    // Wait for the operation thread to initialize.
    if (sem_wait(&args->m_semaphore))
    {
        if (errno == EINTR)
            goto WAIT_AGAIN;
        else
        {
            error.SetErrorToErrno();
            return;
        }
    }

    // Check that the launch was a success.
    if (!args->m_error.Success())
    {
        StopAttachOpThread();
        error = args->m_error;
        return;
    }

    // Finally, start monitoring the child process for change in state.
    m_monitor_thread = Host::StartMonitoringChildProcess(
        ProcessMonitor::MonitorCallback, this, GetPID(), true);
    if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
    {
        error.SetErrorToGenericError();
        error.SetErrorString("Process attach failed.");
        return;
    }
}
lldb::ProcessSP
PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_info,
                                       lldb_private::Debugger &debugger,
                                       lldb_private::Target *target,       // Can be NULL, if NULL create a new target, else use existing one
                                       lldb_private::Listener &listener,
                                       lldb_private::Error &error)
{
    lldb::ProcessSP process_sp;
    if (IsRemote())
    {
        if (IsConnected())
        {
            lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
            ArchSpec remote_arch = GetRemoteSystemArchitecture();
            llvm::Triple &remote_triple = remote_arch.GetTriple();
            uint16_t port = 0;
            if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS)
            {
                // When remote debugging to iOS, we use a USB mux that always talks
                // to localhost, so we will need the remote debugserver to accept connections
                // only from localhost, no matter what our current hostname is
                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1");
            }
            else
            {
                // All other hosts should use their actual hostname
                port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL);
            }
            
            if (port == 0)
            {
                error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
            }
            else
            {
                if (target == NULL)
                {
                    TargetSP new_target_sp;
                    
                    error = debugger.GetTargetList().CreateTarget (debugger,
                                                                   NULL,
                                                                   NULL,
                                                                   false,
                                                                   NULL,
                                                                   new_target_sp);
                    target = new_target_sp.get();
                }
                else
                    error.Clear();
                
                if (target && error.Success())
                {
                    debugger.GetTargetList().SetSelectedTarget(target);
                    
                    // The darwin always currently uses the GDB remote debugger plug-in
                    // so even when debugging locally we are debugging remotely!
                    process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
                    
                    if (process_sp)
                    {
                        char connect_url[256];
                        const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME");
                        const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET");
                        int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0;
                        const int connect_url_len = ::snprintf (connect_url,
                                                                sizeof(connect_url),
                                                                "connect://%s:%u",
                                                                override_hostname ? override_hostname : GetHostname (),
                                                                port + port_offset);
                        assert (connect_url_len < (int)sizeof(connect_url));
                        error = process_sp->ConnectRemote (NULL, connect_url);
                        if (error.Success())
                            error = process_sp->Launch(launch_info);
                        else if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
                            m_gdb_client.KillSpawnedProcess(debugserver_pid);
                    }
                }
            }
        }
        else
        {
            error.SetErrorString("not connected to remote gdb server");
        }
    }
    return process_sp;
    
}