Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement a framework for live debugging on Windows.
When processes are launched for debugging on Windows now, LLDB will detect changes such as DLL loads and unloads, breakpoints, thread creation and deletion, etc. These notifications are not yet propagated to LLDB in a way that LLDB understands what is happening with the process. This only picks up the notifications from the OS in a way that they can be sent to LLDB with subsequent patches. Reviewed by: Scott Graham Differential Revision: http://reviews.llvm.org/D6037 llvm-svn: 221207
- Loading branch information
Zachary Turner
committed
Nov 4, 2014
1 parent
06ea7d6
commit 8f21174
Showing
16 changed files
with
1,101 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
247 changes: 247 additions & 0 deletions
247
lldb/source/Plugins/Process/Windows/DebugDriverThread.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <vector> | ||
|
||
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<const LaunchProcessMessage *>(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<DebugOneProcessThread> 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<DebugMonitorMessage *> 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<DebugDriverThread *>(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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <map> | ||
|
||
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<lldb::pid_t, std::shared_ptr<DebugOneProcessThread>> 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 |
Oops, something went wrong.