//------------------------------------------------------------------------------ /// 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; } }
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); }
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; }