Skip to content
Snippets Groups Projects
Commit d0865ed2 authored by Banana Joe's avatar Banana Joe
Browse files

Initial revision of the cdbdebugger playground.

parent 6672f89f
No related branches found
No related tags found
No related merge requests found
Showing
with 1299 additions and 0 deletions
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
DEFINES +=
LIBS += Dbghelp.lib dbgeng.lib
HEADERS += mainwindow.h \
debugger.h \
outputcallback.h \
windbgeventcallback.h \
windbgthread.h
FORMS += mainwindow.ui
SOURCES += main.cpp mainwindow.cpp \
debugger.cpp \
outputcallback.cpp \
windbgeventcallback.cpp \
windbgthread.cpp
#include "debugger.h"
#include "windbgthread.h"
#include "outputcallback.h"
#include "windbgeventcallback.h"
#include <QFileInfo>
#include <QTimerEvent>
#include <QDebug>
Debugger::Debugger(QObject* parent)
: QObject(parent),
m_callbackEvent(this),
m_watchTimer(-1),
m_hDebuggeeProcess(0)
{
HRESULT hr;
hr = DebugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_pDebugClient));
if (FAILED(hr)) m_pDebugClient = 0;
hr = DebugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_pDebugControl));
if (FAILED(hr)) m_pDebugControl = 0;
hr = DebugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_pDebugSystemObjects));
if (FAILED(hr)) m_pDebugSystemObjects = 0;
hr = DebugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_pDebugSymbols));
if (FAILED(hr)) m_pDebugSymbols = 0;
hr = DebugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_pDebugRegisters));
if (FAILED(hr)) m_pDebugRegisters = 0;
m_pDebugClient->SetOutputCallbacks(&g_outputCallbacks);
m_pDebugClient->SetEventCallbacks(&m_callbackEvent);
}
Debugger::~Debugger()
{
killTimer(m_watchTimer);
if (m_pDebugClient)
m_pDebugClient->Release();
if (m_pDebugControl)
m_pDebugControl->Release();
if (m_pDebugSystemObjects)
m_pDebugSystemObjects->Release();
if (m_pDebugSymbols)
m_pDebugSymbols->Release();
if (m_pDebugRegisters)
m_pDebugRegisters->Release();
}
void Debugger::timerEvent(QTimerEvent* te)
{
if (te->timerId() != m_watchTimer)
return;
HRESULT hr;
hr = m_pDebugControl->WaitForEvent(0, 1);
switch (hr) {
case S_OK:
//qDebug() << "S_OK";
//hr = m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_BREAK);
killTimer(m_watchTimer);
m_watchTimer = -1;
handleDebugEvent();
break;
case S_FALSE:
//qDebug() << "S_FALSE";
break;
case E_PENDING:
qDebug() << "S_PENDING";
break;
case E_UNEXPECTED:
killTimer(m_watchTimer);
m_watchTimer = -1;
break;
case E_FAIL:
qDebug() << "E_FAIL";
break;
default:
qDebug() << "asser welljuh";
}
}
void Debugger::openProcess(const QString& filename)
{
DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
memset(&dbgopts, 0, sizeof(dbgopts));
dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
HRESULT hr;
QFileInfo fi(filename);
m_pDebugSymbols->AppendImagePathWide(fi.absolutePath().replace('/','\\').utf16());
//m_pDebugSymbols->AppendSymbolPathWide(fi.absolutePath().replace('/','\\').utf16());
//m_pDebugSymbols->AppendSymbolPathWide(L"D:\\dev\\qt\\4.4.3\\lib");
m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
//m_pDebugSymbols->AddSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS | SYMOPT_NO_IMAGE_SEARCH);
hr = m_pDebugClient->CreateProcess2Wide(NULL,
const_cast<PWSTR>(filename.utf16()),
&dbgopts,
sizeof(dbgopts),
NULL, // TODO: think about the initial directory
NULL); // TODO: think about setting the environment
if (FAILED(hr)) {
qWarning("CreateProcess2Wide failed");
return;
}
m_watchTimer = startTimer(0);
}
void Debugger::closeProcess()
{
m_pDebugClient->TerminateCurrentProcess();
}
void Debugger::breakAtCurrentPosition()
{
if (!m_hDebuggeeProcess)
return;
if (!DebugBreakProcess(m_hDebuggeeProcess))
qWarning("DebugBreakProcess failed.");
}
void Debugger::continueProcess()
{
m_watchTimer = startTimer(0);
}
void Debugger::handleDebugEvent()
{
HRESULT hr;
ULONG numberOfThreads;
hr = m_pDebugSystemObjects->GetNumberThreads(&numberOfThreads);
const ULONG maxThreadIds = 200;
ULONG threadIds[maxThreadIds];
ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
hr = m_pDebugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
qDebug() << "dumping stack for thread" << threadId;
m_pDebugSystemObjects->SetCurrentThreadId(threadId);
ULONG64 frameOffset, instructionOffset, stackOffset;
if (FAILED(m_pDebugRegisters->GetFrameOffset2(DEBUG_REGSRC_DEBUGGEE, &frameOffset)) ||
FAILED(m_pDebugRegisters->GetInstructionOffset2(DEBUG_REGSRC_DEBUGGEE, &instructionOffset)) ||
FAILED(m_pDebugRegisters->GetStackOffset2(DEBUG_REGSRC_DEBUGGEE, &stackOffset)))
{
frameOffset = instructionOffset = stackOffset = 0;
}
//frameOffset = instructionOffset = stackOffset = 0;
const ULONG numFrames = 100;
ULONG numFramesFilled = 0;
DEBUG_STACK_FRAME frames[numFrames];
hr = m_pDebugControl->GetStackTrace(frameOffset, stackOffset, instructionOffset, frames, numFrames, &numFramesFilled);
if (FAILED(hr))
qDebug() << "GetStackTrace failed";
const size_t buflen = 1024;
WCHAR wszBuf[buflen];
for (ULONG i=0; i < numFramesFilled; ++i) {
m_pDebugSymbols->GetNameByOffsetWide(frames[i].InstructionOffset, wszBuf, buflen, 0, 0);
qDebug() << QString::fromUtf16(wszBuf);
}
//m_pDebugSymbols->GetImagePathWide(wszBuf, buflen, 0);
//qDebug() << "ImagePath" << QString::fromUtf16(wszBuf);
//m_pDebugSymbols->GetSymbolPathWide(wszBuf, buflen, 0);
//qDebug() << "SymbolPath" << QString::fromUtf16(wszBuf);
//m_pDebugControl->OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, 0, 2, DEBUG_STACK_FRAME_ADDRESSES | DEBUG_STACK_COLUMN_NAMES | DEBUG_STACK_FRAME_NUMBERS);
//m_pDebugControl->OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, frames, numFramesFilled, DEBUG_STACK_SOURCE_LINE);
}
}
void Debugger::handleCreateProcessEvent(DEBUG_EVENT* e)
{
//qDebug() << "CREATE_PROCESS_DEBUG_EVENT";
//m_hDebuggeeProcess = e->u.CreateProcessInfo.hProcess;
//m_hDebuggeeThread = e->u.CreateProcessInfo.hThread;
//m_hDebuggeeImage = e->u.CreateProcessInfo.hFile;
//QFileInfo fi(m_pDbgProcess->processFileName());
//BOOL bSuccess;
//bSuccess = SymInitialize(m_hDebuggeeProcess, fi.absolutePath().utf16(), FALSE);
//if (!bSuccess)
// qWarning("SymInitialize failed");
//else {
// SymSetOptions(SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS);
// if (!SymLoadModule64(m_hDebuggeeProcess, m_hDebuggeeImage, NULL, NULL, NULL, NULL))
// qDebug() << "SymLoadModule64 failed w/ error code" << GetLastError();
//}
}
void Debugger::handleExceptionEvent(DEBUG_EVENT* e)
{
//BOOL bSuccess;
//SuspendThread(m_hDebuggeeThread);
//CONTEXT context;
//memset(&context, 0, sizeof(context));
//context.ContextFlags = CONTEXT_ALL;
//bSuccess = GetThreadContext(m_hDebuggeeThread, &context);
//if (!bSuccess)
// qDebug() << "GetThreadContext failed w/ error code" << GetLastError();
//ResumeThread(m_hDebuggeeThread);
//STACKFRAME64 stackFrame;
//stackFrame.AddrPC.Offset = context.Eip;
//stackFrame.AddrPC.Mode = AddrModeFlat;
//stackFrame.AddrFrame.Offset = context.Ebp;
//stackFrame.AddrFrame.Mode = AddrModeFlat;
//stackFrame.AddrStack.Offset = context.Esp;
//stackFrame.AddrStack.Mode = AddrModeFlat;
//m_currentStackTrace.clear();
//do {
// StackFrame sf;
// bSuccess = StackWalk64(IMAGE_FILE_MACHINE_I386, m_hDebuggeeProcess, m_hDebuggeeThread, &stackFrame,
// &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL);
// if (bSuccess) {
// qDebug() << "StackWalk";
// IMAGEHLP_MODULE64 moduleInfo;
// moduleInfo.SizeOfStruct = sizeof(moduleInfo);
// if (SymGetModuleInfo64(m_hDebuggeeProcess, stackFrame.AddrPC.Offset, &moduleInfo))
// qDebug() << "SymGetModuleInfo64 success!";
// else
// qDebug() << "SymGetModuleInfo64 failed w/ error code" << GetLastError();
// }
// if (stackFrame.AddrPC.Offset) {
// DWORD64 dwDisplacement;
// const size_t bufferSize = 200;
// class MySymbol : public IMAGEHLP_SYMBOL64
// {
// public:
// private:
// char buffer[bufferSize];
// };
// MySymbol img;
// ZeroMemory(&img, sizeof(img));
// img.SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
// img.MaxNameLength = bufferSize;
// BOOL bSuccess;
// bSuccess = SymGetSymFromAddr64(m_hDebuggeeProcess,
// stackFrame.AddrPC.Offset,
// &dwDisplacement,
// &img);
// if (bSuccess) {
// qDebug() << "SymGetSymFromAddr64:" << img.Name;
// sf.symbol = QString::fromLocal8Bit(img.Name);
// }
// else
// qDebug() << "SymGetSymFromAddr64 failed w/ error code" << GetLastError();
// }
// if (stackFrame.AddrPC.Offset) {
// DWORD dwDisplacement;
// IMAGEHLP_LINE64 line;
// ZeroMemory(&line, sizeof(line));
// line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
// BOOL bSuccess;
// bSuccess = SymGetLineFromAddr64(m_hDebuggeeProcess,
// stackFrame.AddrPC.Offset,
// &dwDisplacement,
// &line);
// if (bSuccess) {
// //qDebug() << "SymGetLineFromAddr64:" << QString::fromUtf16((ushort*)line.FileName) << line.LineNumber;
// sf.filename = QString::fromUtf16((ushort*)line.FileName);
// sf.line = line.LineNumber;
// } else
// qDebug() << "SymGetLineFromAddr64 failed w/ error code" << GetLastError();
// m_currentStackTrace.append(sf);
// }
//} while (bSuccess);
//emit debuggeePaused();
}
void Debugger::handleOutputDebugStringEvent(DEBUG_EVENT* e)
{
//qDebug() << "OUTPUT_DEBUG_STRING_EVENT";
//BOOL bSuccess;
//SIZE_T nNumberOfBytesRead;
//void* buffer;
//QString result;
//if (e->u.DebugString.fUnicode) {
// buffer = malloc(e->u.DebugString.nDebugStringLength * sizeof(WCHAR));
//} else {
// buffer = malloc(e->u.DebugString.nDebugStringLength * sizeof(char));
//}
//bSuccess = ReadProcessMemory(m_hDebuggeeProcess, e->u.DebugString.lpDebugStringData,
// buffer, e->u.DebugString.nDebugStringLength, &nNumberOfBytesRead);
//if (bSuccess) {
// if (e->u.DebugString.fUnicode)
// result = QString::fromUtf16(reinterpret_cast<ushort*>(buffer), nNumberOfBytesRead);
// else
// result = QString::fromLocal8Bit(reinterpret_cast<char*>(buffer), nNumberOfBytesRead);
// emit debugOutput(result);
//}
//free(buffer);
}
#pragma once
#include "windbgeventcallback.h"
#include <QObject>
#include <QVector>
#define DBGHELP_TRANSLATE_TCHAR
#include <Dbghelp.h>
class WinDbgThread;
class Debugger : public QObject
{
Q_OBJECT
public:
Debugger(QObject* parent = 0);
~Debugger();
void openProcess(const QString& filename);
void closeProcess();
void breakAtCurrentPosition();
void continueProcess();
struct StackFrame
{
QString symbol;
QString filename;
uint line;
};
typedef QVector<StackFrame> StackTrace;
StackTrace stackTrace() { return m_currentStackTrace; }
signals:
void debugOutput(const QString&);
void debuggeePaused();
protected:
void timerEvent(QTimerEvent*);
private:
void handleDebugEvent();
void handleCreateProcessEvent(DEBUG_EVENT* e);
void handleExceptionEvent(DEBUG_EVENT* e);
void handleOutputDebugStringEvent(DEBUG_EVENT* e);
private:
HANDLE m_hDebuggeeProcess;
HANDLE m_hDebuggeeThread;
HANDLE m_hDebuggeeImage;
StackTrace m_currentStackTrace;
//DWORD64 m_dwModuleBaseAddress;
int m_watchTimer;
IDebugClient5* m_pDebugClient;
IDebugControl4* m_pDebugControl;
IDebugSystemObjects4* m_pDebugSystemObjects;
IDebugSymbols3* m_pDebugSymbols;
IDebugRegisters2* m_pDebugRegisters;
WinDbgEventCallback m_callbackEvent;
//struct ThreadInfo
//{
// ULONG64 handle, dataOffset, startOffset;
//};
//QVector<ThreadInfo> m_threadlist;
friend class WinDbgEventCallback;
};
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow mw;
if (argc >= 2) mw.setDebuggee(argv[1]);
mw.show();
return app.exec();
}
#include "mainwindow.h"
#include <QFileDialog>
#include <QTextStream>
#include <QDebug>
MainWindow::MainWindow()
: QMainWindow(0, 0)
{
setupUi(this);
connect(&m_debugger, SIGNAL(debugOutput(const QString&)), SLOT(appendOutput(const QString&)));
connect(&m_debugger, SIGNAL(debuggeePaused()), SLOT(onDebuggeePaused()));
}
void MainWindow::setDebuggee(const QString& filename)
{
m_debugger.openProcess(filename);
}
void MainWindow::on_actionOpen_triggered()
{
QString exeName;
exeName = QFileDialog::getOpenFileName(this, "Open Executable", ".", "*.exe");
if (!exeName.isNull())
m_debugger.openProcess(exeName);
}
void MainWindow::on_actionExit_triggered()
{
close();
}
void MainWindow::on_actionBreak_triggered()
{
m_debugger.breakAtCurrentPosition();
}
void MainWindow::on_actionRun_triggered()
{
m_debugger.continueProcess();
}
void MainWindow::on_lstStack_itemClicked(QListWidgetItem* item)
{
Debugger::StackFrame sf = m_stackTrace[ lstStack->row(item) ];
QFile f(sf.filename);
if (!f.exists())
return;
f.open(QFile::ReadOnly);
QTextStream ts(&f);
int cursorPos = 0;
int currentLine = 0;
QString fullText;
do {
QString strLine = ts.readLine();
currentLine++;
if (currentLine < sf.line)
cursorPos += strLine.length();
fullText.append(strLine + "\n");
} while (!ts.atEnd());
codeWindow->setPlainText(fullText);
//QList<QTextEdit::ExtraSelection> extraSelections;
//extraSelections.append(QTextEdit::ExtraSelection());
//QTextEdit::ExtraSelection& exsel = extraSelections.first();
//exsel.cursor.setPosition(cursorPos, QTextCursor::MoveAnchor);
//exsel.cursor.select(QTextCursor::LineUnderCursor);
//exsel.format.setBackground(Qt::red);
//exsel.format.setFontUnderline(true);
//codeWindow->setExtraSelections(extraSelections);
}
void MainWindow::appendOutput(const QString& str)
{
teOutput->setPlainText(teOutput->toPlainText() + str);
}
void MainWindow::onDebuggeePaused()
{
lstStack->clear();
m_stackTrace = m_debugger.stackTrace();
foreach (Debugger::StackFrame sf, m_stackTrace) {
QString str = sf.symbol;
if (!sf.filename.isEmpty())
str.append(" at " + sf.filename + ":" + QString::number(sf.line));
lstStack->addItem(str);
}
}
#pragma once
#include "ui_mainwindow.h"
#include "debugger.h"
class MainWindow : public QMainWindow, private Ui_MainWindow
{
Q_OBJECT
public:
MainWindow();
void setDebuggee(const QString& filename);
private slots:
void on_actionOpen_triggered();
void on_actionExit_triggered();
void on_actionBreak_triggered();
void on_actionRun_triggered();
void on_lstStack_itemClicked(QListWidgetItem*);
void appendOutput(const QString&);
void onDebuggeePaused();
private:
Debugger m_debugger;
Debugger::StackTrace m_stackTrace;
};
\ No newline at end of file
<ui version="4.0" >
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>599</width>
<height>606</height>
</rect>
</property>
<property name="windowTitle" >
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget" >
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<widget class="QPlainTextEdit" name="codeWindow" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="undoRedoEnabled" >
<bool>false</bool>
</property>
<property name="lineWrapMode" >
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="readOnly" >
<bool>true</bool>
</property>
<property name="textInteractionFlags" >
<set>Qt::NoTextInteraction</set>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex" >
<number>1</number>
</property>
<widget class="QWidget" name="tab" >
<attribute name="title" >
<string>Threads</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
<widget class="QListWidget" name="lstThreads" />
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2" >
<attribute name="title" >
<string>Stack</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2" >
<item>
<widget class="QListWidget" name="lstStack" />
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3" >
<attribute name="title" >
<string>Output</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3" >
<item>
<widget class="QPlainTextEdit" name="teOutput" />
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>599</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_Debug" >
<property name="title" >
<string>&amp;Debug</string>
</property>
<addaction name="actionRun" />
<addaction name="actionBreak" />
<addaction name="actionStepOver" />
<addaction name="actionStopDebugging" />
<addaction name="actionStepInto" />
</widget>
<widget class="QMenu" name="menu_File" >
<property name="title" >
<string>&amp;File</string>
</property>
<addaction name="actionOpen" />
<addaction name="actionClose" />
<addaction name="separator" />
<addaction name="actionExit" />
</widget>
<addaction name="menu_File" />
<addaction name="menu_Debug" />
</widget>
<widget class="QStatusBar" name="statusbar" />
<action name="actionOpen" >
<property name="text" >
<string>&amp;Open...</string>
</property>
<property name="shortcut" >
<string>Ctrl+O</string>
</property>
</action>
<action name="actionClose" >
<property name="text" >
<string>&amp;Close</string>
</property>
</action>
<action name="actionExit" >
<property name="text" >
<string>E&amp;xit</string>
</property>
</action>
<action name="actionRun" >
<property name="text" >
<string>&amp;Run</string>
</property>
<property name="shortcut" >
<string>F5</string>
</property>
</action>
<action name="actionBreak" >
<property name="text" >
<string>&amp;Break</string>
</property>
</action>
<action name="actionStepOver" >
<property name="text" >
<string>Step over</string>
</property>
<property name="shortcut" >
<string>F10</string>
</property>
</action>
<action name="actionStepInto" >
<property name="text" >
<string>Step into</string>
</property>
<property name="shortcut" >
<string>F11</string>
</property>
</action>
<action name="actionStopDebugging" >
<property name="text" >
<string>Stop debugging</string>
</property>
<property name="shortcut" >
<string>Shift+F5</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
#include <stdio.h>
#include <windows.h>
#include <dbgeng.h>
#include "outputcallback.h"
WinDbgOutputCallback g_outputCallbacks;
STDMETHODIMP
WinDbgOutputCallback::QueryInterface(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
)
{
*Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
{
*Interface = (IDebugOutputCallbacks *)this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG)
WinDbgOutputCallback::AddRef(
THIS
)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG)
WinDbgOutputCallback::Release(
THIS
)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP
WinDbgOutputCallback::Output(
THIS_
IN ULONG Mask,
IN PCSTR Text
)
{
UNREFERENCED_PARAMETER(Mask);
fputs(Text, stdout);
return S_OK;
}
#ifndef __OUT_HPP__
#define __OUT_HPP__
class WinDbgOutputCallback : public IDebugOutputCallbacks
{
public:
// IUnknown.
STDMETHOD(QueryInterface)(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
);
STDMETHOD_(ULONG, AddRef)(
THIS
);
STDMETHOD_(ULONG, Release)(
THIS
);
// IDebugOutputCallbacks.
STDMETHOD(Output)(
THIS_
IN ULONG Mask,
IN PCSTR Text
);
};
extern WinDbgOutputCallback g_outputCallbacks;
#endif // #ifndef __OUT_HPP__
#include "windbgeventcallback.h"
#include "debugger.h"
STDMETHODIMP
WinDbgEventCallback::QueryInterface(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
)
{
*Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks)))
{
*Interface = (IDebugOutputCallbacks *)this;
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG)
WinDbgEventCallback::AddRef(
THIS
)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG)
WinDbgEventCallback::Release(
THIS
)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP WinDbgEventCallback::GetInterestMask(
THIS_
__out PULONG Mask
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::Breakpoint(
THIS_
__in PDEBUG_BREAKPOINT Bp
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::Exception(
THIS_
__in PEXCEPTION_RECORD64 Exception,
__in ULONG FirstChance
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::CreateThread(
THIS_
__in ULONG64 Handle,
__in ULONG64 DataOffset,
__in ULONG64 StartOffset
)
{
//Debugger::ThreadInfo ti;
//ti.handle = Handle;
//ti.dataOffset = DataOffset;
//ti.startOffset = StartOffset;
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::ExitThread(
THIS_
__in ULONG ExitCode
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::CreateProcess(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 Handle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp,
__in ULONG64 InitialThreadHandle,
__in ULONG64 ThreadDataOffset,
__in ULONG64 StartOffset
)
{
m_pDebugger->m_hDebuggeeProcess = (HANDLE)Handle;
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::ExitProcess(
THIS_
__in ULONG ExitCode
)
{
m_pDebugger->m_hDebuggeeProcess = 0;
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::LoadModule(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::UnloadModule(
THIS_
__in_opt PCSTR ImageBaseName,
__in ULONG64 BaseOffset
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::SystemError(
THIS_
__in ULONG Error,
__in ULONG Level
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::SessionStatus(
THIS_
__in ULONG Status
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::ChangeDebuggeeState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::ChangeEngineState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
return S_OK;
}
STDMETHODIMP WinDbgEventCallback::ChangeSymbolState(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
)
{
return S_OK;
}
#pragma once
#include <windows.h>
#include <dbgeng.h>
class Debugger;
class WinDbgEventCallback : public IDebugEventCallbacks
{
public:
WinDbgEventCallback(Debugger* dbg)
: m_pDebugger(dbg)
{}
// IUnknown.
STDMETHOD(QueryInterface)(
THIS_
IN REFIID InterfaceId,
OUT PVOID* Interface
);
STDMETHOD_(ULONG, AddRef)(
THIS
);
STDMETHOD_(ULONG, Release)(
THIS
);
// IDebugEventCallbacks.
STDMETHOD(GetInterestMask)(
THIS_
__out PULONG Mask
);
STDMETHOD(Breakpoint)(
THIS_
__in PDEBUG_BREAKPOINT Bp
);
STDMETHOD(Exception)(
THIS_
__in PEXCEPTION_RECORD64 Exception,
__in ULONG FirstChance
);
STDMETHOD(CreateThread)(
THIS_
__in ULONG64 Handle,
__in ULONG64 DataOffset,
__in ULONG64 StartOffset
);
STDMETHOD(ExitThread)(
THIS_
__in ULONG ExitCode
);
STDMETHOD(CreateProcess)(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 Handle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp,
__in ULONG64 InitialThreadHandle,
__in ULONG64 ThreadDataOffset,
__in ULONG64 StartOffset
);
STDMETHOD(ExitProcess)(
THIS_
__in ULONG ExitCode
);
STDMETHOD(LoadModule)(
THIS_
__in ULONG64 ImageFileHandle,
__in ULONG64 BaseOffset,
__in ULONG ModuleSize,
__in_opt PCSTR ModuleName,
__in_opt PCSTR ImageName,
__in ULONG CheckSum,
__in ULONG TimeDateStamp
);
STDMETHOD(UnloadModule)(
THIS_
__in_opt PCSTR ImageBaseName,
__in ULONG64 BaseOffset
);
STDMETHOD(SystemError)(
THIS_
__in ULONG Error,
__in ULONG Level
);
STDMETHOD(SessionStatus)(
THIS_
__in ULONG Status
);
STDMETHOD(ChangeDebuggeeState)(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
);
STDMETHOD(ChangeEngineState)(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
);
STDMETHOD(ChangeSymbolState)(
THIS_
__in ULONG Flags,
__in ULONG64 Argument
);
private:
Debugger* m_pDebugger;
};
#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);
}
#pragma once
#include <QThread>
#include <windows.h>
class WinDbgThread : protected QThread
{
Q_OBJECT
public:
WinDbgThread(QObject* parent = 0);
~WinDbgThread();
void startProcess(const QString& filename);
void attachToProcess(DWORD processId);
void continueProcess();
void pauseProcess();
void stopProcess();
const QString& processFileName() { return m_processFileName; }
QObject* asQObject() { return this; }
//using QThread::isRunning;
signals:
void debugEventOccured(void*);
protected:
void run();
private:
void internalStartProcess();
void suspend();
void resume();
enum State {
Idle,
ProcessRunning,
ProcessPaused
};
void setState(State s);
private:
State m_state;
QString m_processFileName;
HANDLE m_hThisThread;
PROCESS_INFORMATION m_pi;
bool m_bOwnsProcess;
bool m_bAbortEventPollingLoop;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment