summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2014-12-03 22:04:18 +0000
committerZachary Turner <zturner@google.com>2014-12-03 22:04:18 +0000
commitc6a6653ebb59a40f1701bd757540cdaf1108c969 (patch)
treefba6553f28bbb3e1fb79ea0297e6029051f775bb /lldb/source/Plugins/Process/Windows/DebuggerThread.cpp
parentbbc017851815da300ce9d6315204a73d68754a1c (diff)
downloadbcm5719-llvm-c6a6653ebb59a40f1701bd757540cdaf1108c969.tar.gz
bcm5719-llvm-c6a6653ebb59a40f1701bd757540cdaf1108c969.zip
Correctly shutdown when DoDestroy is called with an active exception.
Previously if we got a DoDestroy while stopped at a breakpoint, we would detach and then say the process had exited. This is completely wrong, as it resulted in the python script incorrectly assuming that the process had actually exited and trying to delete the image, when in fact it had done no such thing. The fix employed here is that when we get a DoDestroy, we do 3 steps: 1) initiate a termination sequence on the process 2) If we were stopped handling an exception of any kind, mask it and let the program resume, causing the program to see the termination request and exit on its own. 3) Let the program exit normally, and close all of our handles before returning control back to DoDestroy. This fixes Bug 21722 and Bug 21723. llvm-svn: 223272
Diffstat (limited to 'lldb/source/Plugins/Process/Windows/DebuggerThread.cpp')
-rw-r--r--lldb/source/Plugins/Process/Windows/DebuggerThread.cpp85
1 files changed, 72 insertions, 13 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;
}
OpenPOWER on IntegriCloud