summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2014-11-17 21:31:30 +0000
committerZachary Turner <zturner@google.com>2014-11-17 21:31:30 +0000
commit1019695b38bf65ad7d54faa62466cc7b67267aea (patch)
tree176643285bd21a2334eb25e2b31f9f76c333c7f8 /lldb/source/Plugins/Process
parentd553d00c79eb250a10cd3ad8b45103ff0be0c9ee (diff)
downloadbcm5719-llvm-1019695b38bf65ad7d54faa62466cc7b67267aea.tar.gz
bcm5719-llvm-1019695b38bf65ad7d54faa62466cc7b67267aea.zip
Move the thread logic around to fit better into LLDB's process model.
Previously we were directly updating the thread list and stopping and restarting the process every time threads were created. With this patch, we queue up thread launches and thread exits, resolve these all internally, and only update the threads when we get an UpdateThreadList call. We now only update the private state on an actual stop (i.e. breakpoint). llvm-svn: 222178
Diffstat (limited to 'lldb/source/Plugins/Process')
-rw-r--r--lldb/source/Plugins/Process/Windows/DebuggerThread.cpp6
-rw-r--r--lldb/source/Plugins/Process/Windows/ForwardDecl.h10
-rw-r--r--lldb/source/Plugins/Process/Windows/ProcessWindows.cpp83
3 files changed, 72 insertions, 27 deletions
diff --git a/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp b/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp
index ac191c40e06..2c3ca6f0bf6 100644
--- a/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp
+++ b/lldb/source/Plugins/Process/Windows/DebuggerThread.cpp
@@ -117,11 +117,11 @@ DebuggerThread::DebugLoop()
{
ExceptionResult status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId);
m_exception.SetValue(status, eBroadcastNever);
- m_exception.WaitForValueNotEqualTo(ExceptionResult::WillHandle, status);
+ m_exception.WaitForValueNotEqualTo(ExceptionResult::BreakInDebugger, status);
- if (status == ExceptionResult::Handled)
+ if (status == ExceptionResult::MaskException)
continue_status = DBG_CONTINUE;
- else if (status == ExceptionResult::NotHandled)
+ else if (status == ExceptionResult::SendToApplication)
continue_status = DBG_EXCEPTION_NOT_HANDLED;
break;
}
diff --git a/lldb/source/Plugins/Process/Windows/ForwardDecl.h b/lldb/source/Plugins/Process/Windows/ForwardDecl.h
index 2fa9b9e5d31..249dfe88e29 100644
--- a/lldb/source/Plugins/Process/Windows/ForwardDecl.h
+++ b/lldb/source/Plugins/Process/Windows/ForwardDecl.h
@@ -18,11 +18,11 @@ class ProcessWindows;
// the exception.
enum class ExceptionResult
{
- Handled, // The delegate handled the exception. Continue.
- NotHandled, // The delegate did not handle the exception. Keep
- // searching.
- WillHandle // The delegate will handle the exception. Do not
- // process further debug events until it finishes.
+ BreakInDebugger, // Break in the debugger and give the user a chance to interact with
+ // the program before continuing.
+ MaskException, // Eat the exception and don't let the application know it occurred.
+ SendToApplication // Send the exception to the application to be handled as if there were
+ // no debugger attached.
};
namespace lldb_private
diff --git a/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp
index 5ad671e1541..17083ace04a 100644
--- a/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/ProcessWindows.cpp
@@ -11,6 +11,7 @@
#include "lldb/Host/windows/windows.h"
// C++ Includes
+#include <list>
#include <vector>
// Other libraries and framework includes
@@ -23,6 +24,7 @@
#include "lldb/Host/HostNativeThreadBase.h"
#include "lldb/Host/MonitoringProcessLauncher.h"
#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/windows/HostThreadWindows.h"
#include "lldb/Host/windows/ProcessLauncherWindows.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/DynamicLoader.h"
@@ -40,6 +42,7 @@ using namespace lldb_private;
namespace lldb_private
{
+
// We store a pointer to this class in the ProcessWindows, so that we don't expose Windows
// OS specific types and implementation details from a public header file.
class ProcessWindowsData
@@ -61,6 +64,8 @@ class ProcessWindowsData
lldb_private::DebuggerThreadSP m_debugger;
HANDLE m_initial_stop_event;
bool m_initial_stop_received;
+ std::map<lldb::tid_t, HostThread> m_new_threads;
+ std::map<lldb::tid_t, HostThread> m_exited_threads;
};
}
//------------------------------------------------------------------------------
@@ -120,8 +125,33 @@ ProcessWindows::GetPluginDescriptionStatic()
bool
ProcessWindows::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
{
- new_thread_list = old_thread_list;
- return new_thread_list.GetSize(false) > 0;
+ // Add all the threads that were previously running and for which we did not detect a thread
+ // exited event.
+ int new_size = 0;
+ for (ThreadSP old_thread : old_thread_list.Threads())
+ {
+ lldb::tid_t old_thread_id = old_thread->GetID();
+ auto exited_thread_iter = m_session_data->m_exited_threads.find(old_thread_id);
+ if (exited_thread_iter == m_session_data->m_exited_threads.end())
+ {
+ new_thread_list.AddThread(old_thread);
+ ++new_size;
+ }
+ }
+
+ // Also add all the threads that are new since the last time we broke into the debugger.
+ for (auto iter = m_session_data->m_new_threads.begin(); iter != m_session_data->m_new_threads.end(); ++iter)
+ {
+ ThreadSP thread(new TargetThreadWindows(*this, iter->second));
+ thread->SetID(iter->first);
+ new_thread_list.AddThread(thread);
+ ++new_size;
+ }
+
+ m_session_data->m_new_threads.clear();
+ m_session_data->m_exited_threads.clear();
+
+ return new_size > 0;
}
Error
@@ -148,6 +178,7 @@ ProcessWindows::DoLaunch(Module *exe_module,
HostProcess process;
if (result.Success())
{
+ // Block this function until we receive the initial stop from the process.
if (::WaitForSingleObject(m_session_data->m_initial_stop_event, INFINITE) == WAIT_OBJECT_0)
process = debugger->GetProcess();
else
@@ -158,7 +189,7 @@ ProcessWindows::DoLaunch(Module *exe_module,
return result;
// We've hit the initial stop. The private state should already be set to stopped as a result
- // of encountering the breakpoint exception.
+ // of encountering the breakpoint exception in ProcessWindows::OnDebugException.
launch_info.SetProcessID(process.GetProcessId());
SetID(process.GetProcessId());
@@ -173,9 +204,10 @@ ProcessWindows::DoResume()
{
if (m_session_data->m_active_exception)
{
- // Resume the process and continue processing debug events.
+ // 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::Handled);
+ m_session_data->m_debugger->ContinueAsyncException(ExceptionResult::MaskException);
}
SetPrivateState(eStateRunning);
@@ -212,6 +244,7 @@ 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);
}
@@ -325,25 +358,27 @@ ProcessWindows::OnExitProcess(uint32_t exit_code)
void
ProcessWindows::OnDebuggerConnected(lldb::addr_t image_base)
{
+ // Either we successfully attached to an existing process, or we successfully launched a new
+ // process under the debugger.
ModuleSP module = GetTarget().GetExecutableModule();
bool load_addr_changed;
module->SetLoadAddress(GetTarget(), image_base, false, load_addr_changed);
DebuggerThreadSP debugger = m_session_data->m_debugger;
- ThreadSP main_thread(new TargetThreadWindows(*this, debugger->GetMainThread()));
- m_thread_list.AddThread(main_thread);
+ const HostThreadWindows &wmain_thread = static_cast<const HostThreadWindows &>(debugger->GetMainThread().GetNativeThread());
+ m_session_data->m_new_threads[wmain_thread.GetThreadId()] = debugger->GetMainThread();
}
ExceptionResult
ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &record)
{
- ExceptionResult result = ExceptionResult::NotHandled;
+ ExceptionResult result = ExceptionResult::SendToApplication;
m_session_data->m_active_exception.reset(new ExceptionRecord(record));
switch (record.GetExceptionCode())
{
case EXCEPTION_BREAKPOINT:
// Handle breakpoints at the first chance.
- result = ExceptionResult::WillHandle;
+ result = ExceptionResult::BreakInDebugger;
if (!m_session_data->m_initial_stop_received)
{
@@ -354,9 +389,9 @@ ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &recor
default:
// For non-breakpoints, give the application a chance to handle the exception first.
if (first_chance)
- result = ExceptionResult::NotHandled;
+ result = ExceptionResult::SendToApplication;
else
- result = ExceptionResult::WillHandle;
+ result = ExceptionResult::BreakInDebugger;
}
if (!first_chance)
@@ -364,10 +399,10 @@ ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &recor
// Any second chance exception is an application crash by definition.
SetPrivateState(eStateCrashed);
}
- else if (result == ExceptionResult::WillHandle)
+ else if (result == ExceptionResult::BreakInDebugger)
{
// For first chance exceptions that we can handle, the process is stopped so the user
- // can inspect / manipulate the state of the process in the debugger.
+ // can interact with the debugger.
SetPrivateState(eStateStopped);
}
else
@@ -380,14 +415,23 @@ ProcessWindows::OnDebugException(bool first_chance, const ExceptionRecord &recor
}
void
-ProcessWindows::OnCreateThread(const HostThread &thread)
+ProcessWindows::OnCreateThread(const HostThread &new_thread)
{
- SuspendThread(thread.GetNativeThread().GetSystemHandle());
+ const HostThreadWindows &wnew_thread = static_cast<const HostThreadWindows &>(new_thread.GetNativeThread());
+ m_session_data->m_new_threads[wnew_thread.GetThreadId()] = new_thread;
}
void
-ProcessWindows::OnExitThread(const HostThread &thread)
-{
+ProcessWindows::OnExitThread(const HostThread &exited_thread)
+{
+ // A thread may have started and exited before the debugger stopped allowing a refresh.
+ // Just remove it from the new threads list in that case.
+ const HostThreadWindows &wexited_thread = static_cast<const HostThreadWindows &>(exited_thread.GetNativeThread());
+ auto iter = m_session_data->m_new_threads.find(wexited_thread.GetThreadId());
+ if (iter != m_session_data->m_new_threads.end())
+ m_session_data->m_new_threads.erase(iter);
+ else
+ m_session_data->m_exited_threads[wexited_thread.GetThreadId()] = exited_thread;
}
void
@@ -418,8 +462,9 @@ ProcessWindows::OnDebuggerError(const Error &error, uint32_t type)
{
if (!m_session_data->m_initial_stop_received)
{
- // If we haven't actually launched the process yet, this was an error
- // launching the process. Set the internal error and signal.
+ // If we haven't actually launched the process yet, this was an error launching the
+ // process. Set the internal error and signal the initial stop event so that the DoLaunch
+ // method wakes up and returns a failure.
m_session_data->m_launch_error = error;
::SetEvent(m_session_data->m_initial_stop_event);
return;
OpenPOWER on IntegriCloud