Index: lldb/trunk/include/lldb/Host/Predicate.h =================================================================== --- lldb/trunk/include/lldb/Host/Predicate.h +++ lldb/trunk/include/lldb/Host/Predicate.h @@ -11,6 +11,7 @@ #define liblldb_Predicate_h_ #if defined(__cplusplus) +#include "lldb/lldb-defines.h" #include "lldb/Host/Mutex.h" #include "lldb/Host/Condition.h" #include Index: lldb/trunk/include/lldb/Host/windows/HostThreadWindows.h =================================================================== --- lldb/trunk/include/lldb/Host/windows/HostThreadWindows.h +++ lldb/trunk/include/lldb/Host/windows/HostThreadWindows.h @@ -31,9 +31,6 @@ virtual void Reset(); lldb::tid_t GetThreadId() const; - - protected: - llvm::SmallString<32> m_thread_name; }; } Index: lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt +++ lldb/trunk/source/Plugins/Process/Windows/CMakeLists.txt @@ -4,6 +4,11 @@ include_directories(../Utility) add_lldb_library(lldbPluginProcessWindows + DebugMonitorMessages.cpp + DebugMonitorMessageResults.cpp + DebugOneProcessThread.cpp + DebugProcessLauncher.cpp + DebugDriverThread.cpp ProcessWindows.cpp ) Index: lldb/trunk/source/Plugins/Process/Windows/DebugDriverThread.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugDriverThread.h +++ lldb/trunk/source/Plugins/Process/Windows/DebugDriverThread.h @@ -0,0 +1,79 @@ +//===-- DebugDriverThread.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_DebugDriverThread_H_ +#define liblldb_Plugins_Process_Windows_DebugDriverThread_H_ + +#include "lldb/Host/HostThread.h" +#include "lldb/Host/windows/windows.h" +#include "lldb/lldb-types.h" + +#include + +class ProcessWindows; + +namespace lldb_private +{ +class DebugMonitorMessage; +class DebugMonitorMessageResult; +class DebugOneProcessThread; +class LaunchProcessMessage; +class LaunchProcessMessageResult; + +class SlaveMessageProcessExited; +class SlaveMessageRipEvent; + +//---------------------------------------------------------------------- +// DebugDriverThread +// +// Runs a background thread that pumps a queue from the application to tell the +// debugger to do different things like launching processes, attaching to +// processes, etc. +//---------------------------------------------------------------------- +class DebugDriverThread +{ + friend class DebugOneProcessThread; + + public: + virtual ~DebugDriverThread(); + + static void Initialize(); + static void Teardown(); + static DebugDriverThread &GetInstance(); + + void PostDebugMessage(const DebugMonitorMessage *message); + + private: + DebugDriverThread(); + + void Shutdown(); + + bool ProcessMonitorMessages(); + const DebugMonitorMessageResult *HandleMonitorMessage(const DebugMonitorMessage *message); + const LaunchProcessMessageResult *HandleMonitorMessage(const LaunchProcessMessage *launch_message); + + // Slave message handlers. These are invoked by the + void HandleSlaveEvent(const SlaveMessageProcessExited &message); + void HandleSlaveEvent(const SlaveMessageRipEvent &message); + + static DebugDriverThread *m_instance; + + std::map> m_debugged_processes; + + HANDLE m_monitor_event; + HANDLE m_shutdown_event; + HANDLE m_monitor_pipe_read; + HANDLE m_monitor_pipe_write; + lldb_private::HostThread m_monitor_thread; + + static lldb::thread_result_t MonitorThread(void *data); +}; +} + +#endif Index: lldb/trunk/source/Plugins/Process/Windows/DebugDriverThread.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugDriverThread.cpp +++ lldb/trunk/source/Plugins/Process/Windows/DebugDriverThread.cpp @@ -0,0 +1,247 @@ +//===-- DebugDriverThread.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DebugDriverThread.h" +#include "DebugMonitorMessages.h" +#include "DebugMonitorMessageResults.h" +#include "DebugOneProcessThread.h" +#include "SlaveMessages.h" + +#include "lldb/Core/Log.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Target/Process.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +DebugDriverThread *DebugDriverThread::m_instance = NULL; + +DebugDriverThread::DebugDriverThread() +{ + m_monitor_thread = ThreadLauncher::LaunchThread("lldb.plugin.process-windows.monitor-thread", MonitorThread, this, nullptr); + m_shutdown_event = ::CreateEvent(NULL, TRUE, FALSE, NULL); + m_monitor_event = ::CreateEvent(NULL, FALSE, FALSE, NULL); + ::CreatePipe(&m_monitor_pipe_read, &m_monitor_pipe_write, NULL, 1024); +} + +DebugDriverThread::~DebugDriverThread() +{ +} + +void +DebugDriverThread::Initialize() +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); + if (log) + log->Printf("DebugDriverThread::Initialize"); + + m_instance = new DebugDriverThread(); +} + +void +DebugDriverThread::Teardown() +{ + m_instance->Shutdown(); + + delete m_instance; + m_instance = nullptr; +} + +void +DebugDriverThread::Shutdown() +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); + if (log) + log->Printf("DebugDriverThread::Shutdown"); + + if (!m_shutdown_event) + return; + ::SetEvent(m_shutdown_event); + m_monitor_thread.Join(nullptr); + + ::CloseHandle(m_shutdown_event); + ::CloseHandle(m_monitor_event); + ::CloseHandle(m_monitor_pipe_read); + ::CloseHandle(m_monitor_pipe_write); + + m_shutdown_event = nullptr; + m_monitor_event = nullptr; + m_monitor_pipe_read = nullptr; + m_monitor_pipe_write = nullptr; +} + +DebugDriverThread & +DebugDriverThread::GetInstance() +{ + return *m_instance; +} + +void +DebugDriverThread::PostDebugMessage(const DebugMonitorMessage *message) +{ + message->Retain(); + if (!::WriteFile(m_monitor_pipe_write, &message, sizeof(message), NULL, NULL)) + { + message->Release(); + return; + } + + ::SetEvent(m_monitor_event); +} + +const DebugMonitorMessageResult * +DebugDriverThread::HandleMonitorMessage(const DebugMonitorMessage *message) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + switch (message->GetMessageType()) + { + case MonitorMessageType::eLaunchProcess: + { + const auto *launch_message = static_cast(message); + return HandleMonitorMessage(launch_message); + } + default: + if (log) + log->Printf("DebugDriverThread received unknown message type %d.", message->GetMessageType()); + return nullptr; + } +} + +const LaunchProcessMessageResult * +DebugDriverThread::HandleMonitorMessage(const LaunchProcessMessage *launch_message) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + const char *exe = launch_message->GetLaunchInfo().GetExecutableFile().GetPath().c_str(); + if (log) + log->Printf("DebugDriverThread launching process '%s'.", exe); + + // Create a DebugOneProcessThread which will do the actual creation and enter a debug loop on + // a background thread, only returning after the process has been created on the background + // thread. + std::shared_ptr slave(new DebugOneProcessThread(m_monitor_thread)); + const LaunchProcessMessageResult *result = slave->DebugLaunch(launch_message); + if (result && result->GetError().Success()) + { + if (log) + log->Printf("DebugDriverThread launched process '%s' with PID %d.", exe, result->GetProcess().GetProcessId()); + m_debugged_processes.insert(std::make_pair(result->GetProcess().GetProcessId(), slave)); + } + else + { + if (log) + log->Printf("An error occured launching process '%s' -- %s.", exe, result->GetError().AsCString()); + } + return result; +} + +void +DebugDriverThread::HandleSlaveEvent(const SlaveMessageProcessExited &message) +{ + lldb::pid_t pid = message.GetProcess().GetProcessId(); + + m_debugged_processes.erase(pid); + + Process::SetProcessExitStatus(nullptr, pid, true, 0, message.GetExitCode()); +} + +void +DebugDriverThread::HandleSlaveEvent(const SlaveMessageRipEvent &message) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + lldb::pid_t pid = message.GetProcess().GetProcessId(); + m_debugged_processes.erase(pid); + + if (log) + { + log->Printf("An error was encountered while debugging process %d. Debugging has been terminated. Error = s.", pid, + message.GetError().AsCString()); + } +} + +bool +DebugDriverThread::ProcessMonitorMessages() +{ + DWORD bytes_available = 0; + if (!PeekNamedPipe(m_monitor_pipe_read, NULL, 0, NULL, &bytes_available, NULL)) + { + // There's some kind of error with the named pipe. Fail out and stop monitoring. + return false; + } + + if (bytes_available <= 0) + { + // There's no data available, but the operation succeeded. + return true; + } + + int count = bytes_available / sizeof(DebugMonitorMessage *); + std::vector messages(count); + if (!::ReadFile(m_monitor_pipe_read, &messages[0], bytes_available, NULL, NULL)) + return false; + + for (DebugMonitorMessage *message : messages) + { + const DebugMonitorMessageResult *result = HandleMonitorMessage(message); + message->CompleteMessage(result); + message->Release(); + } + return true; +} + +lldb::thread_result_t +DebugDriverThread::MonitorThread(void *data) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("ProcessWindows DebugDriverThread starting up."); + + DebugDriverThread *monitor_thread = static_cast(data); + const int kMonitorEventIndex = 0; + const int kShutdownEventIndex = 1; + + Error error; + HANDLE events[kShutdownEventIndex + 1]; + events[kMonitorEventIndex] = monitor_thread->m_monitor_event; + events[kShutdownEventIndex] = monitor_thread->m_shutdown_event; + + while (true) + { + bool exit = false; + // See if any new processes are ready for debug monitoring. + DWORD result = WaitForMultipleObjectsEx(llvm::array_lengthof(events), events, FALSE, 1000, TRUE); + switch (result) + { + case WAIT_OBJECT_0 + kMonitorEventIndex: + // LLDB is telling us to do something. Process pending messages in our queue. + monitor_thread->ProcessMonitorMessages(); + break; + case WAIT_OBJECT_0 + kShutdownEventIndex: + error.SetErrorString("Shutdown event received."); + exit = true; + break; + case WAIT_TIMEOUT: + case WAIT_IO_COMPLETION: + break; + default: + error.SetError(GetLastError(), eErrorTypeWin32); + exit = true; + break; + } + if (exit) + break; + } + + if (log) + log->Printf("ProcessWindows Debug monitor thread exiting. %s", error.AsCString()); + return 0; +} Index: lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessageResults.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessageResults.h +++ lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessageResults.h @@ -0,0 +1,70 @@ +//===-- DebugMonitorMessages.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_DebugMonitorMessageResults_H_ +#define liblldb_Plugins_Process_Windows_DebugMonitorMessageResults_H_ + +#include "lldb/Core/Error.h" +#include "lldb/Host/HostProcess.h" + +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +namespace lldb_private +{ + +class DebugMonitorMessage; +class DebugMonitorMessageResult; +class LaunchProcessMessage; + +class DebugMonitorMessageResult : public llvm::ThreadSafeRefCountedBase +{ + public: + virtual ~DebugMonitorMessageResult(); + + const Error & + GetError() const + { + return m_error; + } + const DebugMonitorMessage * + GetOriginalMessage() const + { + return m_message; + } + + void SetError(const Error &error); + + protected: + explicit DebugMonitorMessageResult(const DebugMonitorMessage *message); + + private: + Error m_error; + const DebugMonitorMessage *m_message; +}; + +class LaunchProcessMessageResult : public DebugMonitorMessageResult +{ + public: + static LaunchProcessMessageResult *Create(const LaunchProcessMessage *message); + + void SetProcess(const HostProcess &process); + const HostProcess & + GetProcess() const + { + return m_process; + } + + private: + LaunchProcessMessageResult(const LaunchProcessMessage *message); + + HostProcess m_process; +}; +} + +#endif Index: lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessageResults.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessageResults.cpp +++ lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessageResults.cpp @@ -0,0 +1,55 @@ +//===-- DebugMonitorMessageResults.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DebugMonitorMessageResults.h" +#include "DebugMonitorMessages.h" + +#include "lldb/Core/Error.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Target/ProcessLaunchInfo.h" + +using namespace lldb; +using namespace lldb_private; + +DebugMonitorMessageResult::DebugMonitorMessageResult(const DebugMonitorMessage *message) + : m_message(message) +{ + Retain(); + if (m_message) + m_message->Retain(); +} + +DebugMonitorMessageResult::~DebugMonitorMessageResult() +{ + if (m_message) + m_message->Release(); +} + +void +DebugMonitorMessageResult::SetError(const Error &error) +{ + m_error = error; +} + +LaunchProcessMessageResult::LaunchProcessMessageResult(const LaunchProcessMessage *message) + : DebugMonitorMessageResult(message) +{ +} + +LaunchProcessMessageResult * +LaunchProcessMessageResult::Create(const LaunchProcessMessage *message) +{ + return new LaunchProcessMessageResult(message); +} + +void +LaunchProcessMessageResult::SetProcess(const HostProcess &process) +{ + m_process = process; +} Index: lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessages.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessages.h +++ lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessages.h @@ -0,0 +1,86 @@ +//===-- DebugMonitorMessages.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_DebugMonitorMessages_H_ +#define liblldb_Plugins_Process_Windows_DebugMonitorMessages_H_ + +#include "lldb/Host/Predicate.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Host/windows/windows.h" +#include "lldb/lldb-types.h" + +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +#include +#include + +class ProcessWindows; + +namespace lldb_private +{ +class DebugMonitorMessage; +class DebugMonitorMessageResult; +class ProcessLaunchInfo; + +enum class MonitorMessageType +{ + eLaunchProcess, // Launch a process under the control of the debugger. + eAttachProcess, // Attach to an existing process, and give control to the debugger. + eDetachProcess, // Detach from a process that the debugger currently controls. + eSuspendProcess, // Suspend a process. + eResumeProcess, // Resume a suspended process. +}; + +class DebugMonitorMessage : public llvm::ThreadSafeRefCountedBase +{ + public: + virtual ~DebugMonitorMessage(); + + const DebugMonitorMessageResult *WaitForCompletion(); + void CompleteMessage(const DebugMonitorMessageResult *result); + + MonitorMessageType + GetMessageType() const + { + return m_message_type; + } + + protected: + explicit DebugMonitorMessage(MonitorMessageType message_type); + + private: + Predicate m_completion_predicate; + MonitorMessageType m_message_type; +}; + +class LaunchProcessMessage : public DebugMonitorMessage +{ + public: + static LaunchProcessMessage *Create(const ProcessLaunchInfo &launch_info, lldb::ProcessSP m_process_plugin); + const ProcessLaunchInfo & + GetLaunchInfo() const + { + return m_launch_info; + } + + lldb::ProcessSP + GetProcessPlugin() const + { + return m_process_plugin; + } + + private: + LaunchProcessMessage(const ProcessLaunchInfo &launch_info, lldb::ProcessSP m_process_plugin); + + const ProcessLaunchInfo &m_launch_info; + lldb::ProcessSP m_process_plugin; +}; +} + +#endif Index: lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessages.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessages.cpp +++ lldb/trunk/source/Plugins/Process/Windows/DebugMonitorMessages.cpp @@ -0,0 +1,62 @@ +//===-- DebugMonitorMessages.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DebugMonitorMessages.h" +#include "DebugMonitorMessageResults.h" + +#include "lldb/Core/Error.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Target/ProcessLaunchInfo.h" + +using namespace lldb; +using namespace lldb_private; + +DebugMonitorMessage::DebugMonitorMessage(MonitorMessageType message_type) + : m_message_type(message_type) +{ + Retain(); + m_completion_predicate.SetValue(nullptr, eBroadcastNever); +} + +DebugMonitorMessage::~DebugMonitorMessage() +{ + const DebugMonitorMessageResult *result = m_completion_predicate.GetValue(); + if (result) + result->Release(); + m_completion_predicate.SetValue(nullptr, eBroadcastNever); +} + +const DebugMonitorMessageResult * +DebugMonitorMessage::WaitForCompletion() +{ + const DebugMonitorMessageResult *result = nullptr; + m_completion_predicate.WaitForValueNotEqualTo(nullptr, result); + return result; +} + +void +DebugMonitorMessage::CompleteMessage(const DebugMonitorMessageResult *result) +{ + if (result) + result->Retain(); + m_completion_predicate.SetValue(result, eBroadcastAlways); +} + +LaunchProcessMessage::LaunchProcessMessage(const ProcessLaunchInfo &launch_info, lldb::ProcessSP process_plugin) + : DebugMonitorMessage(MonitorMessageType::eLaunchProcess) + , m_launch_info(launch_info) + , m_process_plugin(process_plugin) +{ +} + +LaunchProcessMessage * +LaunchProcessMessage::Create(const ProcessLaunchInfo &launch_info, lldb::ProcessSP process_plugin) +{ + return new LaunchProcessMessage(launch_info, process_plugin); +} Index: lldb/trunk/source/Plugins/Process/Windows/DebugOneProcessThread.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugOneProcessThread.h +++ lldb/trunk/source/Plugins/Process/Windows/DebugOneProcessThread.h @@ -0,0 +1,63 @@ +//===-- DebugOneProcessThread.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_DebugOneProcessThread_H_ +#define liblldb_Plugins_Process_Windows_DebugOneProcessThread_H_ + +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Host/Predicate.h" +#include "lldb/Host/windows/windows.h" + +namespace lldb_private +{ +class LaunchProcessMessage; +class LaunchProcessMessageResult; + +//---------------------------------------------------------------------- +// DebugOneProcessThread +// +// Debugs a single process, notifying the process plugin and/or the debugger +// driver thread as appropriate when interesting things occur. +//---------------------------------------------------------------------- +class DebugOneProcessThread : public std::enable_shared_from_this +{ + public: + DebugOneProcessThread(HostThread driver_thread); + virtual ~DebugOneProcessThread(); + + const LaunchProcessMessageResult *DebugLaunch(const LaunchProcessMessage *message); + + private: + void DebugLoop(); + DWORD HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id); + DWORD HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id); + DWORD HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id); + DWORD HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id); + DWORD HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id); + DWORD HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id); + DWORD HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id); + DWORD HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id); + DWORD HandleRipEvent(const RIP_INFO &info, DWORD thread_id); + + static void __stdcall NotifySlaveProcessExited(ULONG_PTR message); + static void __stdcall NotifySlaveRipEvent(ULONG_PTR message); + + // The main debug driver thread which is controlling this slave. + lldb_private::HostThread m_driver_thread; + Predicate m_launch_predicate; + lldb::ProcessSP m_process_plugin; + HostProcess m_process; + + static lldb::thread_result_t DebugLaunchThread(void *data); + lldb::thread_result_t DebugLaunchThread(const LaunchProcessMessage *message); +}; +} + +#endif Index: lldb/trunk/source/Plugins/Process/Windows/DebugOneProcessThread.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugOneProcessThread.cpp +++ lldb/trunk/source/Plugins/Process/Windows/DebugOneProcessThread.cpp @@ -0,0 +1,227 @@ +//===-- DebugDriverThread.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DebugDriverThread.h" +#include "DebugOneProcessThread.h" +#include "DebugMonitorMessages.h" +#include "DebugMonitorMessageResults.h" +#include "SlaveMessages.h" + +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Host/Predicate.h" +#include "lldb/Host/ThisThread.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/windows/HostThreadWindows.h" +#include "lldb/Host/windows/ProcessLauncherWindows.h" + +#include "llvm/Support/raw_ostream.h" + +using namespace lldb; +using namespace lldb_private; + +namespace +{ +struct DebugLaunchContext +{ + DebugOneProcessThread *instance; + const LaunchProcessMessage *launch; +}; +} + +DebugOneProcessThread::DebugOneProcessThread(HostThread driver_thread) + : m_driver_thread(driver_thread) +{ + m_launch_predicate.SetValue(nullptr, eBroadcastNever); +} + +DebugOneProcessThread::~DebugOneProcessThread() +{ +} + +const LaunchProcessMessageResult * +DebugOneProcessThread::DebugLaunch(const LaunchProcessMessage *message) +{ + Error error; + const LaunchProcessMessageResult *result = nullptr; + DebugLaunchContext context; + context.instance = this; + context.launch = message; + + HostThread slave_thread(ThreadLauncher::LaunchThread("lldb.plugin.process-windows.slave[?]", DebugLaunchThread, &context, &error)); + if (error.Success()) + m_launch_predicate.WaitForValueNotEqualTo(nullptr, result); + + return result; +} + +lldb::thread_result_t +DebugOneProcessThread::DebugLaunchThread(void *data) +{ + DebugLaunchContext *context = static_cast(data); + DebugOneProcessThread *thread = context->instance; + return thread->DebugLaunchThread(context->launch); +} + +lldb::thread_result_t +DebugOneProcessThread::DebugLaunchThread(const LaunchProcessMessage *message) +{ + // Grab a shared_ptr reference to this so that we know it won't get deleted until after the + // thread routine has exited. + std::shared_ptr this_ref(shared_from_this()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + Error error; + ProcessLauncherWindows launcher; + + m_process_plugin = message->GetProcessPlugin(); + m_process = launcher.LaunchProcess(message->GetLaunchInfo(), error); + + std::string thread_name; + llvm::raw_string_ostream name_stream(thread_name); + name_stream << "lldb.plugin.process-windows.slave[" << m_process.GetProcessId() << "]"; + name_stream.flush(); + ThisThread::SetName(thread_name.c_str()); + + LaunchProcessMessageResult *result = LaunchProcessMessageResult::Create(message); + result->SetError(error); + result->SetProcess(m_process); + m_launch_predicate.SetValue(result, eBroadcastAlways); + + DebugLoop(); + if (log) + log->Printf("Debug monitor thread '%s' exiting.", thread_name.c_str()); + + return 0; +} + +void +DebugOneProcessThread::DebugLoop() +{ + DEBUG_EVENT dbe = {0}; + bool exit = false; + while (!exit && WaitForDebugEvent(&dbe, INFINITE)) + { + DWORD continue_status = DBG_CONTINUE; + switch (dbe.dwDebugEventCode) + { + case EXCEPTION_DEBUG_EVENT: + continue_status = HandleExceptionEvent(dbe.u.Exception, dbe.dwThreadId); + break; + case CREATE_THREAD_DEBUG_EVENT: + continue_status = HandleCreateThreadEvent(dbe.u.CreateThread, dbe.dwThreadId); + break; + case CREATE_PROCESS_DEBUG_EVENT: + continue_status = HandleCreateProcessEvent(dbe.u.CreateProcessInfo, dbe.dwThreadId); + break; + case EXIT_THREAD_DEBUG_EVENT: + continue_status = HandleExitThreadEvent(dbe.u.ExitThread, dbe.dwThreadId); + break; + case EXIT_PROCESS_DEBUG_EVENT: + continue_status = HandleExitProcessEvent(dbe.u.ExitProcess, dbe.dwThreadId); + exit = true; + break; + case LOAD_DLL_DEBUG_EVENT: + continue_status = HandleLoadDllEvent(dbe.u.LoadDll, dbe.dwThreadId); + break; + case UNLOAD_DLL_DEBUG_EVENT: + continue_status = HandleUnloadDllEvent(dbe.u.UnloadDll, dbe.dwThreadId); + break; + case OUTPUT_DEBUG_STRING_EVENT: + continue_status = HandleODSEvent(dbe.u.DebugString, dbe.dwThreadId); + break; + case RIP_EVENT: + continue_status = HandleRipEvent(dbe.u.RipInfo, dbe.dwThreadId); + if (dbe.u.RipInfo.dwType == SLE_ERROR) + exit = true; + break; + } + + ::ContinueDebugEvent(dbe.dwProcessId, dbe.dwThreadId, continue_status); + } +} + +DWORD +DebugOneProcessThread::HandleExceptionEvent(const EXCEPTION_DEBUG_INFO &info, DWORD thread_id) +{ + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleCreateThreadEvent(const CREATE_THREAD_DEBUG_INFO &info, DWORD thread_id) +{ + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleCreateProcessEvent(const CREATE_PROCESS_DEBUG_INFO &info, DWORD thread_id) +{ + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleExitThreadEvent(const EXIT_THREAD_DEBUG_INFO &info, DWORD thread_id) +{ + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleExitProcessEvent(const EXIT_PROCESS_DEBUG_INFO &info, DWORD thread_id) +{ + HANDLE driver = m_driver_thread.GetNativeThread().GetSystemHandle(); + SlaveMessageProcessExited *message = new SlaveMessageProcessExited(m_process, info.dwExitCode); + + QueueUserAPC(NotifySlaveProcessExited, driver, reinterpret_cast(message)); + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleLoadDllEvent(const LOAD_DLL_DEBUG_INFO &info, DWORD thread_id) +{ + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleUnloadDllEvent(const UNLOAD_DLL_DEBUG_INFO &info, DWORD thread_id) +{ + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleODSEvent(const OUTPUT_DEBUG_STRING_INFO &info, DWORD thread_id) +{ + return DBG_CONTINUE; +} + +DWORD +DebugOneProcessThread::HandleRipEvent(const RIP_INFO &info, DWORD thread_id) +{ + HANDLE driver = m_driver_thread.GetNativeThread().GetSystemHandle(); + Error error(info.dwError, eErrorTypeWin32); + SlaveMessageRipEvent *message = new SlaveMessageRipEvent(m_process, error, info.dwType); + + QueueUserAPC(NotifySlaveRipEvent, driver, reinterpret_cast(message)); + return DBG_CONTINUE; +} + +void +DebugOneProcessThread::NotifySlaveProcessExited(ULONG_PTR message) +{ + SlaveMessageProcessExited *slave_message = reinterpret_cast(message); + DebugDriverThread::GetInstance().HandleSlaveEvent(*slave_message); + delete slave_message; +} + +void +DebugOneProcessThread::NotifySlaveRipEvent(ULONG_PTR message) +{ + SlaveMessageRipEvent *slave_message = reinterpret_cast(message); + DebugDriverThread::GetInstance().HandleSlaveEvent(*slave_message); + delete slave_message; +} Index: lldb/trunk/source/Plugins/Process/Windows/DebugProcessLauncher.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugProcessLauncher.h +++ lldb/trunk/source/Plugins/Process/Windows/DebugProcessLauncher.h @@ -0,0 +1,40 @@ +//===-- DebugProcessLauncher.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_DebugProcessLauncher_H_ +#define liblldb_Plugins_Process_Windows_DebugProcessLauncher_H_ + +#include "lldb/Host/ProcessLauncher.h" +#include "lldb/lldb-forward.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +// DebugProcessLauncher +// +// DebugProcessLauncher launches a process for debugging on Windows. On +// Windows, the debug loop that detects events and status changes in a debugged +// process must run on the same thread that calls CreateProcess. So +// DebugProcessLauncher is built with this in mind. It queues a request to the +// DebugDriverThread to launch a new process, then waits for a notification from +// that thread that the launch is complete. +//---------------------------------------------------------------------- +class DebugProcessLauncher : public ProcessLauncher +{ + public: + explicit DebugProcessLauncher(lldb::ProcessSP process_plugin); + virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error); + + private: + lldb::ProcessSP m_process_plugin; +}; +} + +#endif Index: lldb/trunk/source/Plugins/Process/Windows/DebugProcessLauncher.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/DebugProcessLauncher.cpp +++ lldb/trunk/source/Plugins/Process/Windows/DebugProcessLauncher.cpp @@ -0,0 +1,38 @@ +//===-- DebugProcessLauncher.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DebugDriverThread.h" +#include "DebugMonitorMessages.h" +#include "DebugMonitorMessageResults.h" +#include "DebugProcessLauncher.h" + +#include "lldb/Core/Error.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Target/ProcessLaunchInfo.h" + +using namespace lldb; +using namespace lldb_private; + +DebugProcessLauncher::DebugProcessLauncher(lldb::ProcessSP process_plugin) + : m_process_plugin(process_plugin) +{ +} + +HostProcess +DebugProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) +{ + LaunchProcessMessage *message = LaunchProcessMessage::Create(launch_info, m_process_plugin); + DebugDriverThread::GetInstance().PostDebugMessage(message); + const LaunchProcessMessageResult *result = static_cast(message->WaitForCompletion()); + error = result->GetError(); + HostProcess process = result->GetProcess(); + + message->Release(); + return process; +} Index: lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.h +++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.h @@ -13,13 +13,20 @@ // C Includes // C++ Includes +#include #include // Other libraries and framework includes +#include "lldb/Host/HostThread.h" #include "lldb/Target/Process.h" class ProcessMonitor; +namespace lldb_private +{ +class HostProcess; +} + class ProcessWindows : public lldb_private::Process { @@ -50,6 +57,8 @@ ProcessWindows(lldb_private::Target& target, lldb_private::Listener &listener); + ~ProcessWindows(); + virtual lldb_private::Error DoDetach(bool keep_stopped); @@ -99,11 +108,7 @@ virtual bool IsAlive (); - virtual size_t - DoReadMemory (lldb::addr_t vm_addr, - void *buf, - size_t size, - lldb_private::Error &error); + virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, lldb_private::Error &error); }; #endif // liblldb_Plugins_Process_Windows_ProcessWindows_H_ Index: lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp +++ lldb/trunk/source/Plugins/Process/Windows/ProcessWindows.cpp @@ -11,18 +11,24 @@ #include "lldb/Host/windows/windows.h" // C++ Includes +#include + // Other libraries and framework includes #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostProcess.h" +#include "lldb/Host/MonitoringProcessLauncher.h" +#include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/windows/ProcessLauncherWindows.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/Target.h" +#include "DebugDriverThread.h" +#include "DebugProcessLauncher.h" #include "ProcessWindows.h" using namespace lldb; @@ -48,6 +54,7 @@ PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); + DebugDriverThread::Initialize(); } } @@ -59,9 +66,14 @@ { } +ProcessWindows::~ProcessWindows() +{ +} + void ProcessWindows::Terminate() { + DebugDriverThread::Teardown(); } lldb_private::ConstString @@ -89,7 +101,26 @@ ProcessWindows::DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { - return Host::LaunchProcess(launch_info); + Error result; + HostProcess process; + SetPrivateState(eStateLaunching); + if (launch_info.GetFlags().Test(eLaunchFlagDebug)) + { + // If we're trying to debug this process, we need to use a + // DebugProcessLauncher so that we can enter a WaitForDebugEvent loop + // on the same thread that does the CreateProcess. + DebugProcessLauncher launcher(shared_from_this()); + process = launcher.LaunchProcess(launch_info, result); + } + else + return Host::LaunchProcess(launch_info); + + if (!result.Success()) + return result; + + launch_info.SetProcessID(process.GetProcessId()); + SetID(process.GetProcessId()); + return result; } Error @@ -181,4 +212,3 @@ return exe_module_sp->GetFileSpec().Exists(); return false; } - Index: lldb/trunk/source/Plugins/Process/Windows/SlaveMessages.h =================================================================== --- lldb/trunk/source/Plugins/Process/Windows/SlaveMessages.h +++ lldb/trunk/source/Plugins/Process/Windows/SlaveMessages.h @@ -0,0 +1,86 @@ +//===-- SlaveMessages.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Plugins_Process_Windows_SlaveMessages_H_ +#define liblldb_Plugins_Process_Windows_SlaveMessages_H_ + +#include "lldb/Core/Error.h" +#include "lldb/Host/HostProcess.h" + +namespace lldb_private +{ + +//---------------------------------------------------------------------- +// SlaveMessageBase +// +// SlaveMessageBase serves as a base class for all messages which debug slaves +// can send up to the driver thread to notify it of events related to processes +// which are being debugged. +//---------------------------------------------------------------------- +class SlaveMessageBase +{ + public: + SlaveMessageBase(const HostProcess &process) + : m_process(process) + { + } + + virtual ~SlaveMessageBase() {} + + const HostProcess & + GetProcess() const + { + return m_process; + } + + protected: + HostProcess m_process; +}; + +class SlaveMessageProcessExited : public SlaveMessageBase +{ + public: + SlaveMessageProcessExited(const HostProcess &process, DWORD exit_code) + : SlaveMessageBase(process) + , m_exit_code(exit_code) + { + } + + DWORD + GetExitCode() const { return m_exit_code; } + + private: + DWORD m_exit_code; +}; + +class SlaveMessageRipEvent : public SlaveMessageBase +{ + public: + SlaveMessageRipEvent(const HostProcess &process, const Error &error, DWORD type) + : SlaveMessageBase(process) + , m_error(error) + , m_type(type) + { + } + + const Error & + GetError() const + { + return m_error; + } + DWORD + GetType() const { return m_type; } + + private: + Error m_error; + DWORD m_type; +}; +} + +#endif