Commit d348e509 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Debugger/CDB: Split engine for testing/scripting purposes.

parent 4537e2be
# Detect presence of "Debugging Tools For Windows"
# in case VS compilers are used.
include(cdbcore.pri)
win32 {
contains(QMAKE_CXX, cl) {
CDB_PATH="$$(CDB_PATH)"
isEmpty(CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x64)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows 64-bit/sdk"
exists($$CDB_PATH) {
message("Adding support for $$CDB_PATH")
DEFINES+=CDB_ENABLED
CDB_PLATFORM=i386
INCLUDEPATH*=$$CDB_PATH
INCLUDEPATH*=$$PWD
DEPENDPATH*=$$PWD
CDB_LIBPATH=$$CDB_PATH/lib/$$CDB_PLATFORM
!isEmpty(CDB_PATH) {
HEADERS += \
$$PWD/cdbcom.h \
$$PWD/cdbdebugengine.h \
$$PWD/cdbdebugengine_p.h \
$$PWD/cdbdebugeventcallback.h \
......@@ -63,8 +39,4 @@ SOURCES += \
FORMS += $$PWD/cdboptionspagewidget.ui
LIBS+=-lpsapi
} else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
} # exists($$CDB_PATH)
} # (QMAKE_CXX, cl)
} # win32
}
......@@ -70,7 +70,7 @@ bool getRegisters(CIDebugControl *ctl,
ULONG count;
HRESULT hr = ireg->GetNumberRegisters(&count);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetNumberRegisters", hr);
*errorMessage= CdbCore::msgComFailed("GetNumberRegisters", hr);
return false;
}
if (!count)
......@@ -80,7 +80,7 @@ bool getRegisters(CIDebugControl *ctl,
for (ULONG r = 0; r < count; r++) {
hr = ireg->GetDescriptionWide(r, wszBuf, MAX_PATH - 1, 0, 0);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetDescriptionWide", hr);
*errorMessage= CdbCore::msgComFailed("GetDescriptionWide", hr);
return false;
}
Register reg;
......@@ -93,13 +93,13 @@ bool getRegisters(CIDebugControl *ctl,
memset(valuesPtr, 0, count * sizeof(DEBUG_VALUE));
hr = ireg->GetValues(count, 0, 0, valuesPtr);
if (FAILED(hr)) {
*errorMessage= msgComFailed("GetValues", hr);
*errorMessage= CdbCore::msgComFailed("GetValues", hr);
return false;
}
if (base < 2)
base = 10;
for (ULONG r = 0; r < count; r++)
(*registers)[r].value = CdbSymbolGroupContext::debugValueToString(values.at(r), ctl, 0, base);
(*registers)[r].value = CdbCore::debugValueToString(values.at(r), 0, base, ctl);
return true;
}
......@@ -211,8 +211,7 @@ void DisassemblerOutputParser::parse(const QStringList &l)
}
}
bool dissassemble(CIDebugClient *client,
CIDebugControl *ctl,
bool dissassemble(CdbCore::CoreEngine *engine,
ULONG64 offset,
unsigned long beforeLines,
unsigned long afterLines,
......@@ -222,26 +221,11 @@ bool dissassemble(CIDebugClient *client,
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << offset;
const ULONG flags = DEBUG_DISASM_MATCHING_SYMBOLS|DEBUG_DISASM_SOURCE_LINE_NUMBER|DEBUG_DISASM_SOURCE_FILE_NAME;
// Catch the output by temporarily setting another handler.
// We use the method that outputs to the output handler as it
// conveniently provides the 'beforeLines' context (stepping back
// in assembler code). We build a complete string first as line breaks
// may occur in-between messages.
StringOutputHandler stringHandler;
OutputRedirector redir(client, &stringHandler);
// For some reason, we need to output to "all clients"
const HRESULT hr = ctl->OutputDisassemblyLines(DEBUG_OUTCTL_ALL_CLIENTS,
beforeLines, beforeLines + afterLines,
offset, flags, 0, 0, 0, 0);
if (FAILED(hr)) {
*errorMessage= QString::fromLatin1("Unable to disassamble at 0x%1: %2").
arg(offset, 0, 16).arg(msgComFailed("OutputDisassemblyLines", hr));
QString lines;
if (!engine->dissassemble(offset, beforeLines, afterLines, &lines, errorMessage))
return false;
}
DisassemblerOutputParser parser(str, addressFieldWidth);
parser.parse(stringHandler.result().split(QLatin1Char('\n')));
parser.parse(lines.split(QLatin1Char('\n')));
return true;
}
......
......@@ -39,6 +39,10 @@ QT_BEGIN_NAMESPACE
class QTextStream;
QT_END_NAMESPACE
namespace CdbCore {
class CoreEngine;
}
namespace Debugger {
namespace Internal {
......@@ -51,8 +55,7 @@ bool getRegisters(CIDebugControl *ctl,
QString *errorMessage,
int base = 10 /* 16 for hex, etc */);
bool dissassemble(CIDebugClient *client,
CIDebugControl *ctl,
bool dissassemble(CdbCore::CoreEngine *engine,
ULONG64 offset,
unsigned long beforeLines,
unsigned long afterLines,
......
......@@ -161,7 +161,7 @@ bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
const HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
arg(expr, msgComFailed("SetOffsetExpressionWide", hr));
arg(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr));
return false;
}
// Pass Count is ignoreCount + 1
......@@ -192,7 +192,7 @@ bool CDBBreakPoint::add(CIDebugControl* debugControl,
*id = 0;
HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
if (FAILED(hr)) {
*errorMessage = msgCannotAddBreakPoint(msgComFailed("AddBreakpoint2", hr));
*errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("AddBreakpoint2", hr));
return false;
}
if (!ibp) {
......@@ -210,7 +210,7 @@ bool CDBBreakPoint::add(CIDebugControl* debugControl,
if (id) {
hr = ibp->GetId(id);
if (FAILED(hr)) {
*errorMessage = msgCannotAddBreakPoint(msgComFailed("GetId", hr));
*errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("GetId", hr));
return false;
}
}
......@@ -326,7 +326,7 @@ bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
const HRESULT hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Cannot retrieve breakpoint: %1").
arg(msgComFailed("GetOffsetExpressionWide", hr));
arg(CdbCore::msgComFailed("GetOffsetExpressionWide", hr));
return false;
}
// Pass Count is ignoreCount + 1
......@@ -398,7 +398,7 @@ bool CDBBreakPoint::getBreakPointCount(CIDebugControl* debugControl, ULONG *coun
if (FAILED(hr)) {
if (errorMessage)
*errorMessage = QString::fromLatin1("Cannot determine breakpoint count: %1").
arg(msgComFailed("GetNumberBreakpoints", hr));
arg(CdbCore::msgComFailed("GetNumberBreakpoints", hr));
return false;
}
return true;
......@@ -416,7 +416,7 @@ bool CDBBreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<CDBBreakP
const HRESULT hr = debugControl->GetBreakpointByIndex2(b, &ibp);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
arg(b).arg(msgComFailed("GetBreakpointByIndex2", hr));
arg(b).arg(CdbCore::msgComFailed("GetBreakpointByIndex2", hr));
return false;
}
CDBBreakPoint bp;
......@@ -438,7 +438,7 @@ static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id,
CIDebugBreakpoint *ibp = 0;
const HRESULT hr = ctl->GetBreakpointById2(id, &ibp);
if (FAILED(hr)) {
*errorMessage = msgNoBreakPointWithId(id, msgComFailed("GetBreakpointById2", hr));
*errorMessage = msgNoBreakPointWithId(id, CdbCore::msgComFailed("GetBreakpointById2", hr));
return 0;
}
if (!ibp) {
......@@ -458,7 +458,7 @@ static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString
return false;
const HRESULT hr = ctl->RemoveBreakpoint2(ibp);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").arg(id).arg(msgComFailed("RemoveBreakpointById2", hr));
*errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").arg(id).arg(CdbCore::msgComFailed("RemoveBreakpointById2", hr));
return false;
}
return true;
......@@ -486,7 +486,7 @@ static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool
ULONG flags;
HRESULT hr = ibp->GetFlags(&flags);
if (FAILED(hr)) {
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("GetFlags", hr));
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("GetFlags", hr));
return false;
}
const bool wasEnabled = (flags & DEBUG_BREAKPOINT_ENABLED);
......@@ -500,7 +500,7 @@ static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool
}
hr = ibp->SetFlags(flags);
if (FAILED(hr)) {
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("SetFlags", hr));
*errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("SetFlags", hr));
return false;
}
return true;
......
# Detect presence of "Debugging Tools For Windows"
# in case VS compilers are used.
win32 {
contains(QMAKE_CXX, cl) {
CDB_PATH="$$(CDB_PATH)"
isEmpty(CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x86)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows (x64)/sdk"
!exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows 64-bit/sdk"
exists($$CDB_PATH) {
message("Adding support for $$CDB_PATH")
DEFINES+=CDB_ENABLED
CDB_PLATFORM=i386
INCLUDEPATH*=$$CDB_PATH
CDB_LIBPATH=$$CDB_PATH/lib/$$CDB_PLATFORM
HEADERS += \
$$PWD/cdbcom.h \
$$PWD/coreengine.h \
$$PWD/debugoutputbase.h \
$$PWD/debugeventcallbackbase.h
SOURCES += \
$$PWD/coreengine.cpp \
$$PWD/debugoutputbase.cpp \
$$PWD/debugeventcallbackbase.cpp
INCLUDEPATH*=$$PWD
DEPENDPATH*=$$PWD
} else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
CDB_PATH=""
} # exists($$CDB_PATH)
} # (QMAKE_CXX, cl)
} # win32
This diff is collapsed.
......@@ -43,7 +43,7 @@ namespace Internal {
class DisassemblerViewAgent;
class CdbDebugEventCallback;
class CdbDebugOutput;
struct CdbDebugEnginePrivate;
class CdbDebugEnginePrivate;
struct CdbOptions;
class CdbDebugEngine : public IDebuggerEngine
......@@ -104,9 +104,6 @@ public:
public slots:
void syncDebuggerPaths();
protected:
void timerEvent(QTimerEvent*);
private slots:
void slotConsoleStubStarted();
void slotConsoleStubError(const QString &msg);
......@@ -116,19 +113,16 @@ private slots:
private:
void setState(DebuggerState state, const char *func, int line);
bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage);
bool startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage);
void startWatchTimer();
void killWatchTimer();
inline bool startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage);
inline bool startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage);
void processTerminated(unsigned long exitCode);
bool evaluateExpression(const QString &expression, QString *value, QString *type, QString *errorMessage);
void evaluateWatcher(WatchData *wd);
QString editorToolTip(const QString &exp, const QString &function);
bool step(unsigned long executionStatus);
CdbDebugEnginePrivate *m_d;
friend struct CdbDebugEnginePrivate;
friend class CdbDebugEnginePrivate;
friend class CdbDebugEventCallback;
friend class CdbDebugOutput;
};
......
......@@ -30,8 +30,7 @@
#ifndef DEBUGGER_CDBENGINEPRIVATE_H
#define DEBUGGER_CDBENGINEPRIVATE_H
#include "cdbdebugeventcallback.h"
#include "cdbdebugoutput.h"
#include "coreengine.h"
#include "cdboptions.h"
#include "cdbdumperhelper.h"
#include "stackhandler.h"
......@@ -50,52 +49,11 @@ class WatchHandler;
class CdbStackFrameContext;
class CdbStackTraceContext;
// Thin wrapper around the 'DBEng' debugger engine shared library
// which is loaded at runtime.
class DebuggerEngineLibrary
class CdbDebugEnginePrivate : public CdbCore::CoreEngine
{
Q_OBJECT
public:
DebuggerEngineLibrary();
bool init(const QString &path, QString *dbgEngDLL, QString *errorMessage);
inline HRESULT debugCreate(REFIID interfaceId, PVOID *interfaceHandle) const
{ return m_debugCreate(interfaceId, interfaceHandle); }
private:
// The exported functions of the library
typedef HRESULT (STDAPICALLTYPE *DebugCreateFunction)(REFIID, PVOID *);
DebugCreateFunction m_debugCreate;
};
// A class that sets an expression syntax on the debug control while in scope.
// Can be nested as it checks for the old value.
class SyntaxSetter {
Q_DISABLE_COPY(SyntaxSetter)
public:
explicit inline SyntaxSetter(CIDebugControl *ctl, ULONG desiredSyntax);
inline ~SyntaxSetter();
private:
const ULONG m_desiredSyntax;
CIDebugControl *m_ctl;
ULONG m_oldSyntax;
};
// helper struct to pass interfaces around
struct CdbComInterfaces
{
CdbComInterfaces();
CIDebugClient* debugClient;
CIDebugControl* debugControl;
CIDebugSystemObjects* debugSystemObjects;
CIDebugSymbols* debugSymbols;
CIDebugRegisters* debugRegisters;
CIDebugDataSpaces* debugDataSpaces;
};
struct CdbDebugEnginePrivate
{
typedef QMap<QString, QString> EditorToolTipCache;
enum HandleBreakEventMode { // Special modes for break event handler.
......@@ -107,15 +65,14 @@ struct CdbDebugEnginePrivate
explicit CdbDebugEnginePrivate(DebuggerManager *parent,
const QSharedPointer<CdbOptions> &options,
CdbDebugEngine* engine);
~CdbDebugEnginePrivate();
bool init(QString *errorMessage);
~CdbDebugEnginePrivate();
void checkVersion();
void processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle);
void setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE hDebuggeeThread);
bool isDebuggeeRunning() const { return m_watchTimer != -1; }
void handleDebugEvent();
bool isDebuggeeRunning() const { return isWatchTimerRunning(); }
ULONG updateThreadList();
bool setCDBThreadId(unsigned long threadId, QString *errorMessage);
void updateStackTrace();
......@@ -143,17 +100,12 @@ struct CdbDebugEnginePrivate
enum EndDebuggingMode { EndDebuggingDetach, EndDebuggingTerminate, EndDebuggingAuto };
void endDebugging(EndDebuggingMode em = EndDebuggingAuto);
static bool executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage);
static bool evaluateExpression(CIDebugControl *ctrl, const QString &expression, DEBUG_VALUE *v, QString *errorMessage);
QStringList sourcePaths() const;
bool setSourcePaths(const QStringList &s, QString *errorMessage);
QStringList symbolPaths() const;
bool setSymbolPaths(const QStringList &s, QString *errorMessage);
void updateCodeLevel();
bool setCodeLevel();
public slots:
void handleDebugEvent();
public:
const QSharedPointer<CdbOptions> m_options;
HANDLE m_hDebuggeeProcess;
HANDLE m_hDebuggeeThread;
......@@ -164,12 +116,7 @@ struct CdbDebugEnginePrivate
bool m_ignoreInitialBreakPoint;
HandleBreakEventMode m_breakEventMode;
int m_watchTimer;
CdbComInterfaces m_cif;
CdbDebugEventCallback m_debugEventCallBack;
CdbDebugOutput m_debugOutputCallBack;
QSharedPointer<CdbDumperHelper> m_dumper;
QString m_baseImagePath;
CdbDebugEngine *m_engine;
inline DebuggerManager *manager() const;
......@@ -181,19 +128,8 @@ struct CdbDebugEnginePrivate
DebuggerStartMode m_mode;
Utils::ConsoleProcess m_consoleStubProc;
QString m_dbengDLL;
};
// helper functions
bool getExecutionStatus(CIDebugControl *ctl, ULONG *executionStatus, QString *errorMessage = 0);
const char *executionStatusString(ULONG executionStatus);
const char *executionStatusString(CIDebugControl *ctl);
// Message
QString msgDebugEngineComResult(HRESULT hr);
QString msgComFailed(const char *func, HRESULT hr);
enum { messageTimeOut = 5000 };
enum { debugCDB = 0 };
......
......@@ -40,174 +40,6 @@
namespace Debugger {
namespace Internal {
// CdbDebugEventCallbackBase
CdbDebugEventCallbackBase::CdbDebugEventCallbackBase()
{
}
STDMETHODIMP CdbDebugEventCallbackBase::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) CdbDebugEventCallbackBase::AddRef(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 1;
}
STDMETHODIMP_(ULONG) CdbDebugEventCallbackBase::Release(THIS)
{
// This class is designed to be static so
// there's no true refcount.
return 0;
}
STDMETHODIMP CdbDebugEventCallbackBase::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT2)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::Exception(
THIS_
__in PEXCEPTION_RECORD64,
__in ULONG /* FirstChance */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::CreateThread(
THIS_
__in ULONG64 /* Handle */,
__in ULONG64 /* DataOffset */,
__in ULONG64 /* StartOffset */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::ExitThread(
THIS_
__in ULONG /* ExitCode */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::CreateProcess(
THIS_
__in ULONG64 /* ImageFileHandle */,
__in ULONG64 /* Handle */,
__in ULONG64 /* BaseOffset */,
__in ULONG /* ModuleSize */,
__in_opt PCWSTR /* ModuleName */,
__in_opt PCWSTR /* ImageName */,
__in ULONG /* CheckSum */,
__in ULONG /* TimeDateStamp */,
__in ULONG64 /* InitialThreadHandle */,
__in ULONG64 /* ThreadDataOffset */,
__in ULONG64 /* StartOffset */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::ExitProcess(
THIS_
__in ULONG /* ExitCode */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::LoadModule(
THIS_
__in ULONG64 /* ImageFileHandle */,
__in ULONG64 /* BaseOffset */,
__in ULONG /* ModuleSize */,
__in_opt PCWSTR /* ModuleName */,
__in_opt PCWSTR /* ImageName */,
__in ULONG /* CheckSum */,
__in ULONG /* TimeDateStamp */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::UnloadModule(
THIS_
__in_opt PCWSTR /* ImageBaseName */,
__in ULONG64 /* BaseOffset */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::SystemError(
THIS_
__in ULONG /* Error */,
__in ULONG /* Level */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::SessionStatus(
THIS_
__in ULONG /* Status */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::ChangeDebuggeeState(
THIS_
__in ULONG /* Flags */,
__in ULONG64 /* Argument */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::ChangeEngineState(
THIS_
__in ULONG /* Flags */,
__in ULONG64 /* Argument */
)
{
return S_OK;
}
STDMETHODIMP CdbDebugEventCallbackBase::ChangeSymbolState(
THIS_
__in ULONG /* Flags */,
__in ULONG64 /* Argument */
)
{