diff --git a/i/lldb/tools/darwin-debug/CMakeLists.txt b/lldb/tools/darwin-debug/CMakeLists.txt --- a/i/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/i/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm --- a/i/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -730,6 +730,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; @@ -751,6 +753,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/i/lldb/tools/debugserver/source/MacOSX/MachTask.h b/lldb/tools/debugserver/source/MacOSX/MachTask.h --- a/i/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/i/lldb/tools/debugserver/source/MacOSX/MachTask.mm b/lldb/tools/debugserver/source/MacOSX/MachTask.mm --- a/i/lldb/tools/debugserver/source/MacOSX/MachTask.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm @@ -73,7 +73,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)); } @@ -107,6 +108,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 @@ -139,6 +148,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; } //---------------------------------------------------------------------- @@ -665,6 +676,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(); } @@ -974,4 +988,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; }