diff options
4 files changed, 109 insertions, 42 deletions
diff --git a/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp index c10fb79984d..d037273fc49 100644 --- a/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp +++ b/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp @@ -97,18 +97,74 @@ DebuggerThread::DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info) return 0; } +Error +DebuggerThread::StopDebugging(bool terminate) +{ + Error error; + + if (terminate) + { + // Make a copy of the process, since the termination sequence will reset DebuggerThread's + // internal copy and it needs to remain open for us to perform the Wait operation. + HostProcess process_copy = m_process; + lldb::process_t handle = process_copy.GetNativeProcess().GetSystemHandle(); + + // Initiate the termination before continuing the exception, so that the next debug event + // we get is the exit process event, and not some other event. + BOOL terminate_suceeded = TerminateProcess(handle, 0); + + // If we're stuck waiting for an exception to continue, continue it now. But only + // AFTER setting the termination event, to make sure that we don't race and enter + // another wait for another debug event. + if (m_active_exception.get()) + ContinueAsyncException(ExceptionResult::MaskException); + + // Don't return until the process has exited. + if (terminate_suceeded) + { + DWORD wait_result = ::WaitForSingleObject(handle, 5000); + if (wait_result != WAIT_OBJECT_0) + terminate_suceeded = false; + } + + if (!terminate_suceeded) + error.SetError(GetLastError(), eErrorTypeWin32); + } + else + { + error.SetErrorString("Detach not yet supported on Windows."); + // TODO: Implement detach. + } + return error; +} + void DebuggerThread::ContinueAsyncException(ExceptionResult result) { - m_exception.SetValue(result, eBroadcastAlways); + if (!m_active_exception.get()) + return; + + m_active_exception.reset(); + m_exception_pred.SetValue(result, eBroadcastAlways); +} + +void +DebuggerThread::FreeProcessHandles() +{ + m_process = HostProcess(); + m_main_thread = HostThread(); + if (m_image_file) + { + ::CloseHandle(m_image_file); + m_image_file = nullptr; + } } void DebuggerThread::DebugLoop() { DEBUG_EVENT dbe = {0}; - bool exit = false; - while (!exit && WaitForDebugEvent(&dbe, INFINITE)) + while (WaitForDebugEvent(&dbe, INFINITE)) { DWORD continue_status = DBG_CONTINUE; switch (dbe.dwDebugEventCode) @@ -116,8 +172,6 @@ DebuggerThread::DebugLoop() case EXCEPTION_DEBUG_EVENT: { ExceptionResult status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId); - m_exception.SetValue(status, eBroadcastNever); - m_exception.WaitForValueNotEqualTo(ExceptionResult::BreakInDebugger, status); if (status == ExceptionResult::MaskException) continue_status = DBG_CONTINUE; @@ -136,7 +190,7 @@ DebuggerThread::DebugLoop() break; case EXIT_PROCESS_DEBUG_EVENT: continue_status = HandleExitProcessEvent(dbe.u.ExitProcess, dbe.dwThreadId); - exit = true; + should_debug = false; break; case LOAD_DLL_DEBUG_EVENT: continue_status = HandleLoadDllEvent(dbe.u.LoadDll, dbe.dwThreadId); @@ -150,19 +204,27 @@ DebuggerThread::DebugLoop() case RIP_EVENT: continue_status = HandleRipEvent(dbe.u.RipInfo, dbe.dwThreadId); if (dbe.u.RipInfo.dwType == SLE_ERROR) - exit = true; + should_debug = false; break; } ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status); } + FreeProcessHandles(); } ExceptionResult DebuggerThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id) { bool first_chance = (info.dwFirstChance != 0); - return m_debug_delegate->OnDebugException(first_chance, ExceptionRecord(info.ExceptionRecord)); + + m_active_exception.reset(new ExceptionRecord(info.ExceptionRecord)); + + ExceptionResult result = m_debug_delegate->OnDebugException(first_chance, *m_active_exception); + m_exception_pred.SetValue(result, eBroadcastNever); + m_exception_pred.WaitForValueNotEqualTo(ExceptionResult::BreakInDebugger, result); + + return result; } DWORD @@ -203,12 +265,9 @@ DebuggerThread::HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD DWORD DebuggerThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id) { - m_debug_delegate->OnExitProcess(info.dwExitCode); + FreeProcessHandles(); - m_process = HostProcess(); - m_main_thread = HostThread(); - ::CloseHandle(m_image_file); - m_image_file = nullptr; + m_debug_delegate->OnExitProcess(info.dwExitCode); return DBG_CONTINUE; } diff --git a/lldb/source/Plugins/Process/Windows/DebuggerThread.h b/lldb/source/Plugins/Process/Windows/DebuggerThread.h index 389a1d3c88c..586a1a76856 100644 --- a/lldb/source/Plugins/Process/Windows/DebuggerThread.h +++ b/lldb/source/Plugins/Process/Windows/DebuggerThread.h @@ -45,10 +45,18 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> { return m_main_thread; } + ExceptionRecord * + GetActiveException() + { + return m_active_exception.get(); + } + + Error StopDebugging(bool terminate); void ContinueAsyncException(ExceptionResult result); private: + void FreeProcessHandles(); void DebugLoop(); ExceptionResult HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id); DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id); @@ -66,9 +74,11 @@ class DebuggerThread : public std::enable_shared_from_this<DebuggerThread> HostThread m_main_thread; // The main thread of the inferior. HANDLE m_image_file; // The image file of the process being debugged. - Predicate<ExceptionResult> m_exception; // A predicate which gets signalled when an exception - // is finished processing and the debug loop can be - // continued. + ExceptionRecordUP m_active_exception; // The current exception waiting to be handled + + Predicate<ExceptionResult> m_exception_pred; // A predicate which gets signalled when an exception + // is finished processing and the debug loop can be + // continued. static lldb::thread_result_t DebuggerThreadRoutine(void *data); lldb::thread_result_t DebuggerThreadRoutine(const ProcessLaunchInfo &launch_info); diff --git a/lldb/source/Plugins/Process/Windows/ForwardDecl.h b/lldb/source/Plugins/Process/Windows/ForwardDecl.h index 249dfe88e29..afc7e6a0aec 100644 --- a/lldb/source/Plugins/Process/Windows/ForwardDecl.h +++ b/lldb/source/Plugins/Process/Windows/ForwardDecl.h @@ -34,6 +34,7 @@ class ExceptionRecord; typedef std::shared_ptr<IDebugDelegate> DebugDelegateSP; typedef std::shared_ptr<DebuggerThread> DebuggerThreadSP; +typedef std::unique_ptr<ExceptionRecord> ExceptionRecordUP; } #endif
\ No newline at end of file diff --git a/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp index a577d202111..b19bfbd0077 100644 --- a/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp @@ -61,7 +61,6 @@ class ProcessWindowsData ~ProcessWindowsData() { ::CloseHandle(m_initial_stop_event); } ProcessLaunchInfo m_launch_info; - std::shared_ptr<lldb_private::ExceptionRecord> m_active_exception; lldb_private::Error m_launch_error; lldb_private::DebuggerThreadSP m_debugger; StopInfoSP m_pending_stop_info; @@ -237,11 +236,10 @@ ProcessWindows::DoResume() Error error; if (GetPrivateState() == eStateStopped) { - if (m_session_data->m_active_exception) + if (m_session_data->m_debugger->GetActiveException()) { // Resume the process and continue processing debug events. Mask the exception so that // from the process's view, there is no indication that anything happened. - m_session_data->m_active_exception.reset(); m_session_data->m_debugger->ContinueAsyncException(ExceptionResult::MaskException); } @@ -279,10 +277,10 @@ ProcessWindows::DoDestroy() Error error; if (GetPrivateState() != eStateExited && GetPrivateState() != eStateDetached && m_session_data) { - // Ends the debugging session and terminates the inferior process. - DebugActiveProcessStop(m_session_data->m_debugger->GetProcess().GetProcessId()); - SetPrivateState(eStateExited); + DebuggerThread &debugger = *m_session_data->m_debugger; + error = debugger.StopDebugging(true); } + m_session_data.reset(); return error; } @@ -291,28 +289,28 @@ ProcessWindows::RefreshStateAfterStop() { m_thread_list.RefreshStateAfterStop(); - if (m_session_data->m_active_exception) - { - StopInfoSP stop_info; - ThreadSP stop_thread = m_thread_list.GetSelectedThread(); - RegisterContextSP register_context = stop_thread->GetRegisterContext(); + ExceptionRecord *active_exception = m_session_data->m_debugger->GetActiveException(); + if (!active_exception) + return; - ExceptionRecord &exception = *m_session_data->m_active_exception; - if (exception.GetExceptionCode() == EXCEPTION_BREAKPOINT) - { - uint64_t pc = register_context->GetPC(); - BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); - lldb::break_id_t break_id = LLDB_INVALID_BREAK_ID; - bool should_stop = true; - if (site) - { - should_stop = site->ValidForThisThread(stop_thread.get()); - break_id = site->GetID(); - } + StopInfoSP stop_info; + ThreadSP stop_thread = m_thread_list.GetSelectedThread(); + RegisterContextSP register_context = stop_thread->GetRegisterContext(); - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread, break_id, should_stop); - stop_thread->SetStopInfo(stop_info); + if (active_exception->GetExceptionCode() == EXCEPTION_BREAKPOINT) + { + uint64_t pc = register_context->GetPC(); + BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); + lldb::break_id_t break_id = LLDB_INVALID_BREAK_ID; + bool should_stop = true; + if (site) + { + should_stop = site->ValidForThisThread(stop_thread.get()); + break_id = site->GetID(); } + + stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID(*stop_thread, break_id, should_stop); + stop_thread->SetStopInfo(stop_info); } } @@ -442,7 +440,6 @@ ExceptionResult ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &record) { ExceptionResult result = ExceptionResult::SendToApplication; - m_session_data->m_active_exception.reset(new ExceptionRecord(record)); switch (record.GetExceptionCode()) { case EXCEPTION_BREAKPOINT: |