forked from qt-creator/qt-creator
151 lines
3.2 KiB
C++
151 lines
3.2 KiB
C++
#include "windbgthread.h"
|
|
#include <QDebug>
|
|
|
|
#define DBGHELP_TRANSLATE_TCHAR
|
|
#include <Dbghelp.h>
|
|
|
|
WinDbgThread::WinDbgThread(QObject* parent)
|
|
: QThread(parent),
|
|
m_state(Idle)
|
|
{
|
|
}
|
|
|
|
WinDbgThread::~WinDbgThread()
|
|
{
|
|
stopProcess();
|
|
}
|
|
|
|
void WinDbgThread::startProcess(const QString& filename)
|
|
{
|
|
stopProcess();
|
|
m_bOwnsProcess = true;
|
|
m_processFileName = filename;
|
|
m_pi.dwProcessId = 0;
|
|
QThread::start();
|
|
}
|
|
|
|
void WinDbgThread::stopProcess()
|
|
{
|
|
if (!QThread::isRunning())
|
|
return;
|
|
|
|
switch (m_state)
|
|
{
|
|
case ProcessRunning:
|
|
if (m_bOwnsProcess) {
|
|
m_bOwnsProcess = false; // don't terminate in the loop again
|
|
TerminateProcess(m_pi.hProcess, 0);
|
|
}
|
|
// don't break here
|
|
case ProcessPaused:
|
|
m_bAbortEventPollingLoop = true;
|
|
resume();
|
|
break;
|
|
}
|
|
QThread::wait(5000);
|
|
if (QThread::isRunning()) {
|
|
qWarning("WinDbgThread still running... terminating!");
|
|
QThread::terminate();
|
|
}
|
|
}
|
|
|
|
void WinDbgThread::attachToProcess(DWORD processId)
|
|
{
|
|
m_bOwnsProcess = false;
|
|
m_processFileName = QString();
|
|
m_pi.dwProcessId = processId;
|
|
QThread::start();
|
|
}
|
|
|
|
void WinDbgThread::run()
|
|
{
|
|
qDebug() << "WinDbgThread started";
|
|
// start process or attach process
|
|
if (m_bOwnsProcess) {
|
|
// create new process
|
|
internalStartProcess();
|
|
} else {
|
|
// attach to process
|
|
qWarning("attach to process not yet implemented");
|
|
return;
|
|
}
|
|
|
|
m_hThisThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, GetCurrentThreadId());
|
|
if (!m_hThisThread) {
|
|
qWarning("WinDbgThread: can't open thread handle");
|
|
return;
|
|
}
|
|
|
|
DEBUG_EVENT debugEvent;
|
|
m_bAbortEventPollingLoop = false;
|
|
while (WaitForDebugEvent(&debugEvent, INFINITE)) {
|
|
setState(ProcessPaused);
|
|
emit debugEventOccured(&debugEvent);
|
|
suspend();
|
|
if (m_bAbortEventPollingLoop)
|
|
break;
|
|
ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
|
|
setState(ProcessRunning);
|
|
}
|
|
|
|
setState(Idle);
|
|
if (m_bOwnsProcess) {
|
|
TerminateProcess(m_pi.hProcess, 0);
|
|
}
|
|
CloseHandle(m_pi.hProcess);
|
|
CloseHandle(m_pi.hThread);
|
|
CloseHandle(m_hThisThread);
|
|
|
|
qDebug() << "WinDbgThread finished";
|
|
}
|
|
|
|
void WinDbgThread::continueProcess()
|
|
{
|
|
if (m_state == ProcessPaused)
|
|
resume();
|
|
}
|
|
|
|
void WinDbgThread::pauseProcess()
|
|
{
|
|
if (m_state == ProcessRunning)
|
|
DebugBreakProcess(m_pi.hProcess);
|
|
}
|
|
|
|
void WinDbgThread::internalStartProcess()
|
|
{
|
|
BOOL bSuccess;
|
|
|
|
STARTUPINFO si;
|
|
ZeroMemory(&si, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
si.wShowWindow = TRUE;
|
|
|
|
ZeroMemory(&m_pi, sizeof(m_pi));
|
|
|
|
DWORD dwCreationFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
|
|
bSuccess = CreateProcess(m_processFileName.utf16(), NULL, NULL, NULL, FALSE,
|
|
dwCreationFlags,
|
|
NULL, NULL, &si, &m_pi
|
|
);
|
|
|
|
if (bSuccess)
|
|
setState(ProcessRunning);
|
|
else
|
|
setState(Idle);
|
|
}
|
|
|
|
void WinDbgThread::setState(State s)
|
|
{
|
|
m_state = s;
|
|
}
|
|
|
|
void WinDbgThread::suspend()
|
|
{
|
|
SuspendThread(m_hThisThread);
|
|
}
|
|
|
|
void WinDbgThread::resume()
|
|
{
|
|
ResumeThread(m_hThisThread);
|
|
}
|