diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -153,33 +153,6 @@ return NULL; } -static bool WaitForProcessToSIGSTOP(const lldb::pid_t pid, - const int timeout_in_seconds) { - const int time_delta_usecs = 100000; - const int num_retries = timeout_in_seconds / time_delta_usecs; - for (int i = 0; i < num_retries; i++) { - struct proc_bsdinfo bsd_info; - int error = ::proc_pidinfo(pid, PROC_PIDTBSDINFO, (uint64_t)0, &bsd_info, - PROC_PIDTBSDINFO_SIZE); - - switch (error) { - case EINVAL: - case ENOTSUP: - case ESRCH: - case EPERM: - return false; - - default: - break; - - case 0: - if (bsd_info.pbi_status == SSTOP) - return true; - } - ::usleep(time_delta_usecs); - } - return false; -} #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) const char *applscript_in_new_tty = "tell application \"Terminal\"\n" @@ -325,11 +298,6 @@ lldb_error = accept_thread->Join(&accept_thread_result); if (lldb_error.Success() && accept_thread_result) { pid = (intptr_t)accept_thread_result; - - // Wait for process to be stopped at the entry point by watching - // for the process status to be set to SSTOP which indicates it it - // SIGSTOP'ed at the entry point - WaitForProcessToSIGSTOP(pid, 5); } llvm::sys::fs::remove(unix_socket_name); diff --git a/lldb/tools/darwin-debug/CMakeLists.txt b/lldb/tools/darwin-debug/CMakeLists.txt --- a/lldb/tools/darwin-debug/CMakeLists.txt +++ b/lldb/tools/darwin-debug/CMakeLists.txt @@ -1,3 +1,11 @@ + +# Create an LC_SEGMENT with the special name ExecExtraSuspend which +# debugserver can detect - it tells debugserver that it will exec a +# process and that process will start suspended, so debugserver will +# need to double-resume it to make it run. A random file is copied +# into the segment. +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,ExecExtraSuspend,ExecExtraSuspend,${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt") + add_lldb_tool(darwin-debug ADD_TO_FRAMEWORK darwin-debug.cpp ) diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -734,6 +734,8 @@ this_seg.nsects = seg.nsects; this_seg.flags = seg.flags; inf.segments.push_back(this_seg); + if (this_seg.name == "ExecExtraSuspend") + m_task.TaskWillExecProcessesSuspended(); } if (lc.cmd == LC_SEGMENT_64) { struct segment_command_64 seg; @@ -755,6 +757,8 @@ this_seg.nsects = seg.nsects; this_seg.flags = seg.flags; inf.segments.push_back(this_seg); + if (this_seg.name == "ExecExtraSuspend") + m_task.TaskWillExecProcessesSuspended(); } if (lc.cmd == LC_UUID) { struct uuid_command uuidcmd; diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.h b/lldb/tools/debugserver/source/MacOSX/MachTask.h --- a/lldb/tools/debugserver/source/MacOSX/MachTask.h +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.h @@ -85,6 +85,7 @@ const MachProcess *Process() const { return m_process; } nub_size_t PageSize(); + void TaskWillExecProcessesSuspended() { m_exec_will_be_suspended = true; } protected: MachProcess *m_process; // The mach process that owns this MachTask @@ -97,6 +98,12 @@ // need it mach_port_t m_exception_port; // Exception port on which we will receive child // exceptions + bool m_exec_will_be_suspended; // If this task exec's another process, that + // process will be launched suspended and we will + // need to execute one extra Resume to get it + // to progress from dyld_start. + bool m_do_double_resume; // next time we task_resume(), do it twice to + // fix a too-high suspend count. typedef std::map allocation_collection; allocation_collection m_allocations; diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.mm b/lldb/tools/debugserver/source/MacOSX/MachTask.mm --- a/lldb/tools/debugserver/source/MacOSX/MachTask.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm @@ -69,7 +69,8 @@ //---------------------------------------------------------------------- MachTask::MachTask(MachProcess *process) : m_process(process), m_task(TASK_NULL), m_vm_memory(), - m_exception_thread(0), m_exception_port(MACH_PORT_NULL) { + m_exception_thread(0), m_exception_port(MACH_PORT_NULL), + m_exec_will_be_suspended(false), m_do_double_resume(false) { memset(&m_exc_port_info, 0, sizeof(m_exc_port_info)); } @@ -103,6 +104,14 @@ err = BasicInfo(task, &task_info); if (err.Success()) { + if (m_do_double_resume && task_info.suspend_count == 2) { + err = ::task_resume(task); + if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) + err.LogThreaded("::task_resume double-resume after exec-start-stopped " + "( target_task = 0x%4.4x )", task); + } + m_do_double_resume = false; + // task_resume isn't counted like task_suspend calls are, are, so if the // task is not suspended, don't try and resume it since it is already // running @@ -135,6 +144,8 @@ m_task = TASK_NULL; m_exception_thread = 0; m_exception_port = MACH_PORT_NULL; + m_exec_will_be_suspended = false; + m_do_double_resume = false; } //---------------------------------------------------------------------- @@ -651,6 +662,9 @@ err.LogThreaded("::mach_port_deallocate ( task = 0x%4.4x, name = 0x%4.4x )", task_self, exception_port); + m_exec_will_be_suspended = false; + m_do_double_resume = false; + return err.Status(); } @@ -960,4 +974,14 @@ void MachTask::TaskPortChanged(task_t task) { m_task = task; + + // If we've just exec'd to a new process, and it + // is started suspended, we'll need to do two + // task_resume's to get the inferior process to + // continue. + if (m_exec_will_be_suspended) + m_do_double_resume = true; + else + m_do_double_resume = false; + m_exec_will_be_suspended = false; }