Index: include/lldb/Host/Predicate.h =================================================================== --- include/lldb/Host/Predicate.h +++ 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: source/Plugins/Process/Windows/CMakeLists.txt =================================================================== --- source/Plugins/Process/Windows/CMakeLists.txt +++ source/Plugins/Process/Windows/CMakeLists.txt @@ -4,6 +4,10 @@ include_directories(../Utility) add_lldb_library(lldbPluginProcessWindows + DebugMonitorMessages.cpp + DebugMonitorMessageResults.cpp + DebugProcessLauncher.cpp + DebugStatusMonitorThread.cpp ProcessWindows.cpp ) Index: source/Plugins/Process/Windows/DebugMonitorMessageResults.h =================================================================== --- /dev/null +++ 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: + 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: source/Plugins/Process/Windows/DebugMonitorMessageResults.cpp =================================================================== --- /dev/null +++ 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: source/Plugins/Process/Windows/DebugMonitorMessages.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/DebugMonitorMessages.h @@ -0,0 +1,80 @@ +//===-- 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/ProcessStatusMonitor.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: + 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); + const ProcessLaunchInfo & + GetLaunchInfo() const + { + return m_launch_info; + } + + private: + LaunchProcessMessage(const ProcessLaunchInfo &launch_info); + + const ProcessLaunchInfo &m_launch_info; +}; +} + +#endif Index: source/Plugins/Process/Windows/DebugMonitorMessages.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/DebugMonitorMessages.cpp @@ -0,0 +1,61 @@ +//===-- 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) + : DebugMonitorMessage(MonitorMessageType::eLaunchProcess) + , m_launch_info(launch_info) +{ +} + +LaunchProcessMessage * +LaunchProcessMessage::Create(const ProcessLaunchInfo &launch_info) +{ + return new LaunchProcessMessage(launch_info); +} Index: source/Plugins/Process/Windows/DebugProcessLauncher.h =================================================================== --- /dev/null +++ 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 +// DebugStatusMonitorThread to launch a new process, then waits for a +// notification from that thread that the launch is complete. +//---------------------------------------------------------------------- +class DebugProcessLauncher : public ProcessLauncher +{ + public: + DebugProcessLauncher(lldb::ProcessSP process); + virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error); + + private: + lldb::ProcessSP m_process; +}; +} + +#endif Index: source/Plugins/Process/Windows/DebugProcessLauncher.cpp =================================================================== --- /dev/null +++ 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 "DebugMonitorMessages.h" +#include "DebugMonitorMessageResults.h" +#include "DebugProcessLauncher.h" +#include "DebugStatusMonitorThread.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) + : m_process(process) +{ +} + +HostProcess +DebugProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info, Error &error) +{ + LaunchProcessMessage *message = LaunchProcessMessage::Create(launch_info); + DebugStatusMonitorThread::GetInstance().PostDebugMessage(message); + const LaunchProcessMessageResult *result = static_cast(message->WaitForCompletion()); + error = result->GetError(); + HostProcess process = result->GetProcess(); + + message->Release(); + return process; +} Index: source/Plugins/Process/Windows/DebugStatusMonitorThread.h =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/DebugStatusMonitorThread.h @@ -0,0 +1,74 @@ +//===-- DebugStatusMonitorThread.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_DebugStatusMonitorThread_H_ +#define liblldb_Plugins_Process_Windows_DebugStatusMonitorThread_H_ + +#include "lldb/Host/HostThread.h" +#include "lldb/Host/ProcessStatusMonitor.h" +#include "lldb/Host/windows/windows.h" +#include "lldb/lldb-types.h" + +#include + +class ProcessWindows; + +namespace lldb_private +{ +class DebugMonitorMessage; +class DebugMonitorMessageResult; +class LaunchProcessMessage; +class LaunchProcessMessageResult; + +//---------------------------------------------------------------------- +// DebugStatusMonitorThread +// +// Runs a background thread that monitors for debug events from multiple +// processes, and invokes callbacks as events occur for the various processes. +//---------------------------------------------------------------------- +class DebugStatusMonitorThread +{ + struct MonitorData + { + HostProcess m_host_process; + lldb::ProcessSP m_plugin; + }; + + public: + virtual ~DebugStatusMonitorThread() {} + + static void Initialize(); + static void Teardown(); + static DebugStatusMonitorThread &GetInstance(); + + void PostDebugMessage(const DebugMonitorMessage *message); + void StartMonitoring(const HostProcess &host_process, lldb::ProcessSP plugin, ProcessStatusMonitorCallbackListUP callbacks); + + private: + DebugStatusMonitorThread(); + + bool ProcessMonitorMessages(); + const DebugMonitorMessageResult *HandleMonitorMessage(const DebugMonitorMessage *message); + const LaunchProcessMessageResult *HandleMonitorMessage(const LaunchProcessMessage *launch_message); + + static DebugStatusMonitorThread *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: source/Plugins/Process/Windows/DebugStatusMonitorThread.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/Windows/DebugStatusMonitorThread.cpp @@ -0,0 +1,185 @@ +//===-- DebugStatusMonitorThread.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 "DebugStatusMonitorThread.h" + +#include "lldb/Host/windows/ProcessLauncherWindows.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Target/Process.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +DebugStatusMonitorThread *DebugStatusMonitorThread::m_instance = NULL; + +DebugStatusMonitorThread::DebugStatusMonitorThread() +{ + 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); +} + +void +DebugStatusMonitorThread::Initialize() +{ + m_instance = new DebugStatusMonitorThread(); +} + +void +DebugStatusMonitorThread::Teardown() +{ + delete m_instance; + m_instance = nullptr; +} + +DebugStatusMonitorThread & +DebugStatusMonitorThread::GetInstance() +{ + return *m_instance; +} + +void +DebugStatusMonitorThread::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 * +DebugStatusMonitorThread::HandleMonitorMessage(const DebugMonitorMessage *message) +{ + switch (message->GetMessageType()) + { + case MonitorMessageType::eLaunchProcess: + { + const auto *launch_message = static_cast(message); + return HandleMonitorMessage(launch_message); + } + default: + return nullptr; + } +} + +const LaunchProcessMessageResult * +DebugStatusMonitorThread::HandleMonitorMessage(const LaunchProcessMessage *launch_message) +{ + Error error; + ProcessLauncherWindows launcher; + HostProcess process = launcher.LaunchProcess(launch_message->GetLaunchInfo(), error); + LaunchProcessMessageResult *result = LaunchProcessMessageResult::Create(launch_message); + + if (error.Success()) + { + auto iter = m_debugged_processes.find(process.GetProcessId()); + if (iter == m_debugged_processes.end()) + { + MonitorData *data = new MonitorData; + data->m_host_process = process; + // If we've never seen this pid before, make a new entry for it in the map. + m_debugged_processes.insert(std::make_pair(process.GetProcessId(), data)); + result->SetProcess(process); + } + else + { + // Otherwise log an error of some kind, this shouldn't happen. Do we have a stale process + // entry or something? + } + } + + result->SetError(error); + return result; +} + +bool +DebugStatusMonitorThread::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 +DebugStatusMonitorThread::MonitorThread(void *data) +{ + DebugStatusMonitorThread *monitor_thread = static_cast(data); + + while (true) + { + // See if any new processes are ready for debug monitoring. + DWORD result = WaitForSingleObject(monitor_thread->m_monitor_event, 1000); + if (result != WAIT_OBJECT_0 && result != WAIT_TIMEOUT) + { + // Some kind of error occurred. + break; + } + + if (result != WAIT_TIMEOUT) + monitor_thread->ProcessMonitorMessages(); + + if (monitor_thread->m_debugged_processes.empty()) + continue; + + // Empty out the debug event queue before checking whether new processes are trying to be + // debugged. Don't spend alot of time blocking on this, because we want LLDB to be + // responsive to launching new processes under a debugger. + DEBUG_EVENT debug_event = {0}; + while (WaitForDebugEvent(&debug_event, 500)) + { + auto iter = monitor_thread->m_debugged_processes.find(debug_event.dwProcessId); + if (iter != monitor_thread->m_debugged_processes.end()) + { + MonitorData *monitor_data = iter->second; + if (debug_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) + { + // The process exited, remove it from the set of monitored processes. + Process::SetProcessExitStatus(nullptr, monitor_data->m_host_process.GetProcessId(), true, 0, 0); + delete monitor_data; + monitor_thread->m_debugged_processes.erase(iter); + iter = monitor_thread->m_debugged_processes.end(); + } + } + ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, DBG_CONTINUE); + } + } + + return 0; +} Index: source/Plugins/Process/Windows/ProcessWindows.h =================================================================== --- source/Plugins/Process/Windows/ProcessWindows.h +++ source/Plugins/Process/Windows/ProcessWindows.h @@ -13,13 +13,21 @@ // C Includes // C++ Includes +#include #include // Other libraries and framework includes +#include "lldb/Host/HostThread.h" +#include "lldb/Host/ProcessStatusMonitor.h" #include "lldb/Target/Process.h" class ProcessMonitor; +namespace lldb_private +{ +class HostProcess; +} + class ProcessWindows : public lldb_private::Process { @@ -50,6 +58,8 @@ ProcessWindows(lldb_private::Target& target, lldb_private::Listener &listener); + ~ProcessWindows(); + virtual lldb_private::Error DoDetach(bool keep_stopped); @@ -99,11 +109,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: source/Plugins/Process/Windows/ProcessWindows.cpp =================================================================== --- source/Plugins/Process/Windows/ProcessWindows.cpp +++ source/Plugins/Process/Windows/ProcessWindows.cpp @@ -11,18 +11,26 @@ #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/ProcessStatusMonitor.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/windows/ExitStatusMonitorWindows.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 "DebugProcessLauncher.h" +#include "DebugStatusMonitorThread.h" #include "ProcessWindows.h" using namespace lldb; @@ -48,6 +56,7 @@ PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); + DebugStatusMonitorThread::Initialize(); } } @@ -59,9 +68,14 @@ { } +ProcessWindows::~ProcessWindows() +{ +} + void ProcessWindows::Terminate() { + DebugStatusMonitorThread::Teardown(); } lldb_private::ConstString @@ -89,7 +103,36 @@ 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 + { + // If we're not trying to debug this process, use a standard launcher + // and only monitor for the process's exit, and not other types of debug + // events. + ProcessLauncherUP delegate_launcher; + ProcessStatusMonitorSP status_monitor; + delegate_launcher.reset(new ProcessLauncherWindows()); + status_monitor.reset(new ExitStatusMonitor()); + MonitoringProcessLauncher launcher(status_monitor, std::move(delegate_launcher)); + process = launcher.LaunchProcess(launch_info, result); + } + + if (!result.Success()) + return result; + + launch_info.SetProcessID(process.GetProcessId()); + SetID(process.GetProcessId()); + return result; } Error @@ -181,4 +224,3 @@ return exe_module_sp->GetFileSpec().Exists(); return false; } -