summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/debugger/cdb/cdb.pri34
-rw-r--r--src/plugins/debugger/cdb/cdbassembler.cpp32
-rw-r--r--src/plugins/debugger/cdb/cdbassembler.h7
-rw-r--r--src/plugins/debugger/cdb/cdbbreakpoint.cpp20
-rw-r--r--src/plugins/debugger/cdb/cdbcore.pri43
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine.cpp684
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine.h14
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine_p.h82
-rw-r--r--src/plugins/debugger/cdb/cdbdebugeventcallback.cpp181
-rw-r--r--src/plugins/debugger/cdb/cdbdebugeventcallback.h136
-rw-r--r--src/plugins/debugger/cdb/cdbdebugoutput.cpp69
-rw-r--r--src/plugins/debugger/cdb/cdbdebugoutput.h66
-rw-r--r--src/plugins/debugger/cdb/cdbdumperhelper.cpp152
-rw-r--r--src/plugins/debugger/cdb/cdbdumperhelper.h16
-rw-r--r--src/plugins/debugger/cdb/cdbexceptionutils.cpp4
-rw-r--r--src/plugins/debugger/cdb/cdbmodules.cpp8
-rw-r--r--src/plugins/debugger/cdb/cdboptions.cpp43
-rw-r--r--src/plugins/debugger/cdb/cdboptions.h3
-rw-r--r--src/plugins/debugger/cdb/cdboptionspage.cpp3
-rw-r--r--src/plugins/debugger/cdb/cdbstackframecontext.cpp1
-rw-r--r--src/plugins/debugger/cdb/cdbstacktracecontext.cpp27
-rw-r--r--src/plugins/debugger/cdb/cdbstacktracecontext.h9
-rw-r--r--src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp133
-rw-r--r--src/plugins/debugger/cdb/cdbsymbolgroupcontext.h7
-rw-r--r--src/plugins/debugger/cdb/coreengine.cpp944
-rw-r--r--src/plugins/debugger/cdb/coreengine.h191
-rw-r--r--src/plugins/debugger/cdb/debugeventcallbackbase.cpp219
-rw-r--r--src/plugins/debugger/cdb/debugeventcallbackbase.h174
-rw-r--r--src/plugins/debugger/cdb/debugoutputbase.cpp134
-rw-r--r--src/plugins/debugger/cdb/debugoutputbase.h111
-rw-r--r--src/plugins/debugger/debuggermanager.h6
-rw-r--r--tests/manual/ccdb/README2
-rw-r--r--tests/manual/ccdb/ccdb.pro29
-rw-r--r--tests/manual/ccdb/cdbapplication.cpp213
-rw-r--r--tests/manual/ccdb/cdbapplication.h71
-rw-r--r--tests/manual/ccdb/cdbpromptthread.cpp135
-rw-r--r--tests/manual/ccdb/cdbpromptthread.h71
-rw-r--r--tests/manual/ccdb/debugeventcallback.cpp156
-rw-r--r--tests/manual/ccdb/debugeventcallback.h125
-rw-r--r--tests/manual/ccdb/main.cpp49
40 files changed, 2906 insertions, 1498 deletions
diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri
index 6ac5997efa..0500833397 100644
--- a/src/plugins/debugger/cdb/cdb.pri
+++ b/src/plugins/debugger/cdb/cdb.pri
@@ -1,32 +1,8 @@
-# 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
+}
diff --git a/src/plugins/debugger/cdb/cdbassembler.cpp b/src/plugins/debugger/cdb/cdbassembler.cpp
index 268c664ddb..db21fbf1e7 100644
--- a/src/plugins/debugger/cdb/cdbassembler.cpp
+++ b/src/plugins/debugger/cdb/cdbassembler.cpp
@@ -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;
}
diff --git a/src/plugins/debugger/cdb/cdbassembler.h b/src/plugins/debugger/cdb/cdbassembler.h
index b029f67fd6..a6ae15f098 100644
--- a/src/plugins/debugger/cdb/cdbassembler.h
+++ b/src/plugins/debugger/cdb/cdbassembler.h
@@ -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,
diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp
index 9ec69d3be3..6b3fda2c72 100644
--- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp
+++ b/src/plugins/debugger/cdb/cdbbreakpoint.cpp
@@ -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;
diff --git a/src/plugins/debugger/cdb/cdbcore.pri b/src/plugins/debugger/cdb/cdbcore.pri
new file mode 100644
index 0000000000..1232f516b6
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbcore.pri
@@ -0,0 +1,43 @@
+# 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
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index fc4d0136fb..26f269581e 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -29,6 +29,8 @@
#include "cdbdebugengine.h"
#include "cdbdebugengine_p.h"
+#include "cdbdebugoutput.h"
+#include "cdbdebugeventcallback.h"
#include "cdbstacktracecontext.h"
#include "cdbstackframecontext.h"
#include "cdbsymbolgroupcontext.h"
@@ -71,10 +73,6 @@
#define DBGHELP_TRANSLATE_TCHAR
#include <inc/Dbghelp.h>
-static const char *dbgHelpDllC = "dbghelp";
-static const char *dbgEngineDllC = "dbgeng";
-static const char *debugCreateFuncC = "DebugCreate";
-
static const char *localSymbolRootC = "local";
namespace Debugger {
@@ -84,56 +82,18 @@ typedef QList<WatchData> WatchList;
// ----- Message helpers
-QString msgDebugEngineComResult(HRESULT hr)
-{
- switch (hr) {
- case S_OK:
- return QLatin1String("S_OK");
- case S_FALSE:
- return QLatin1String("S_FALSE");
- case E_FAIL:
- break;
- case E_INVALIDARG:
- return QLatin1String("E_INVALIDARG");
- case E_NOINTERFACE:
- return QLatin1String("E_NOINTERFACE");
- case E_OUTOFMEMORY:
- return QLatin1String("E_OUTOFMEMORY");
- case E_UNEXPECTED:
- return QLatin1String("E_UNEXPECTED");
- case E_NOTIMPL:
- return QLatin1String("E_NOTIMPL");
- }
- if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
- return QLatin1String("ERROR_ACCESS_DENIED");;
- if (hr == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
- return QLatin1String("STATUS_CONTROL_C_EXIT");
- return QLatin1String("E_FAIL ") + Utils::winErrorMessage(HRESULT_CODE(hr));
-}
-
static QString msgStackIndexOutOfRange(int idx, int size)
{
return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
}
-QString msgComFailed(const char *func, HRESULT hr)
-{
- return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
-}
-
QString msgDebuggerCommandFailed(const QString &command, HRESULT hr)
{
- return QString::fromLatin1("Unable to execute '%1': %2").arg(command, msgDebugEngineComResult(hr));
+ return QString::fromLatin1("Unable to execute '%1': %2").arg(command, CdbCore::msgDebugEngineComResult(hr));
}
static const char *msgNoStackTraceC = "Internal error: no stack trace present.";
-static inline QString msgLibLoadFailed(const QString &lib, const QString &why)
-{
- return CdbDebugEngine::tr("Unable to load the debugger engine library '%1': %2").
- arg(lib, why);
-}
-
// Format function failure message. Pass in Q_FUNC_INFO
static QString msgFunctionFailed(const char *func, const QString &why)
{
@@ -152,148 +112,6 @@ static QString msgFunctionFailed(const char *func, const QString &why)
// ----- Engine helpers
-static inline ULONG getInterruptTimeOutSecs(CIDebugControl *ctl)
-{
- ULONG rc = 0;
- ctl->GetInterruptTimeout(&rc);
- return rc;
-}
-
-bool getExecutionStatus(CIDebugControl *ctl,
- ULONG *executionStatus,
- QString *errorMessage /* = 0 */)
-{
- const HRESULT hr = ctl->GetExecutionStatus(executionStatus);
- if (FAILED(hr)) {
- if (errorMessage)
- *errorMessage = msgComFailed("GetExecutionStatus", hr);
- return false;
- }
- return true;
-}
-
-const char *executionStatusString(ULONG executionStatus)
-{
- switch (executionStatus) {
- case DEBUG_STATUS_NO_CHANGE:
- return "DEBUG_STATUS_NO_CHANGE";
- case DEBUG_STATUS_GO:
- return "DEBUG_STATUS_GO";
- case DEBUG_STATUS_GO_HANDLED:
- return "DEBUG_STATUS_GO_HANDLED";
- case DEBUG_STATUS_GO_NOT_HANDLED:
- return "DEBUG_STATUS_GO_NOT_HANDLED";
- case DEBUG_STATUS_STEP_OVER:
- return "DEBUG_STATUS_STEP_OVER";
- case DEBUG_STATUS_STEP_INTO:
- return "DEBUG_STATUS_STEP_INTO";
- case DEBUG_STATUS_BREAK:
- return "DEBUG_STATUS_BREAK";
- case DEBUG_STATUS_NO_DEBUGGEE:
- return "DEBUG_STATUS_NO_DEBUGGEE";
- case DEBUG_STATUS_STEP_BRANCH:
- return "DEBUG_STATUS_STEP_BRANCH";
- case DEBUG_STATUS_IGNORE_EVENT:
- return "DEBUG_STATUS_IGNORE_EVENT";
- case DEBUG_STATUS_RESTART_REQUESTED:
- return "DEBUG_STATUS_RESTART_REQUESTED";
- case DEBUG_STATUS_REVERSE_GO:
- return "DEBUG_STATUS_REVERSE_GO";
- case DEBUG_STATUS_REVERSE_STEP_BRANCH:
- return "DEBUG_STATUS_REVERSE_STEP_BRANCH";
- case DEBUG_STATUS_REVERSE_STEP_OVER:
- return "DEBUG_STATUS_REVERSE_STEP_OVER";
- case DEBUG_STATUS_REVERSE_STEP_INTO:
- return "DEBUG_STATUS_REVERSE_STEP_INTO";
- default:
- break;
- }
- return "<Unknown execution status>";
-}
-
-// Debug convenience
-const char *executionStatusString(CIDebugControl *ctl)
-{
- ULONG executionStatus;
- if (getExecutionStatus(ctl, &executionStatus))
- return executionStatusString(executionStatus);
- return "<failed>";
-}
-
-// --------- DebuggerEngineLibrary
-DebuggerEngineLibrary::DebuggerEngineLibrary() :
- m_debugCreate(0)
-{
-}
-
-// Build a lib name as "Path\x.dll"
-static inline QString libPath(const QString &libName, const QString &path = QString())
-{
- QString rc = path;
- if (!rc.isEmpty())
- rc += QDir::separator();
- rc += libName;
- rc += QLatin1String(".dll");
- return rc;
-}
-
-bool DebuggerEngineLibrary::init(const QString &path,
- QString *dbgEngDLL,
- QString *errorMessage)
-{
- // Load the dependent help lib first
- const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path);
- QLibrary helpLib(helpLibPath, 0);
- if (!helpLib.isLoaded() && !helpLib.load()) {
- *errorMessage = msgLibLoadFailed(helpLibPath, helpLib.errorString());
- return false;
- }
- // Load dbgeng lib
- const QString engineLibPath = libPath(QLatin1String(dbgEngineDllC), path);
- QLibrary lib(engineLibPath, 0);
- if (!lib.isLoaded() && !lib.load()) {
- *errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString());
- return false;
- }
- *dbgEngDLL = engineLibPath;
- // Locate symbols
- void *createFunc = lib.resolve(debugCreateFuncC);
- if (!createFunc) {
- *errorMessage = CdbDebugEngine::tr("Unable to resolve '%1' in the debugger engine library '%2'").
- arg(QLatin1String(debugCreateFuncC), QLatin1String(dbgEngineDllC));
- return false;
- }
- m_debugCreate = static_cast<DebugCreateFunction>(createFunc);
- return true;
-}
-
-// ----- SyntaxSetter
-SyntaxSetter::SyntaxSetter(CIDebugControl *ctl, ULONG desiredSyntax) :
- m_desiredSyntax(desiredSyntax),
- m_ctl(ctl)
-{
- m_ctl->GetExpressionSyntax(&m_oldSyntax);
- if (m_oldSyntax != m_desiredSyntax)
- m_ctl->SetExpressionSyntax(m_desiredSyntax);
-}
-
-SyntaxSetter::~SyntaxSetter()
-{
- if (m_oldSyntax != m_desiredSyntax)
- m_ctl->SetExpressionSyntax(m_oldSyntax);
-}
-
-// CdbComInterfaces
-CdbComInterfaces::CdbComInterfaces() :
- debugClient(0),
- debugControl(0),
- debugSystemObjects(0),
- debugSymbols(0),
- debugRegisters(0),
- debugDataSpaces(0)
-{
-}
-
// --- CdbDebugEnginePrivate
CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
@@ -303,82 +121,41 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
m_hDebuggeeProcess(0),
m_hDebuggeeThread(0),
m_breakEventMode(BreakEventHandle),
- m_dumper(new CdbDumperHelper(manager, &m_cif)),
+ m_dumper(new CdbDumperHelper(manager, this)),
m_currentThreadId(-1),
m_eventThreadId(-1),
m_interruptArticifialThreadId(-1),
m_ignoreInitialBreakPoint(false),
m_interrupted(false),
- m_watchTimer(-1),
- m_debugEventCallBack(engine),
m_engine(engine),
m_currentStackTrace(0),
m_firstActivatedFrame(true),
m_inferiorStartupComplete(false),
m_mode(AttachCore)
{
+ connect(this, SIGNAL(watchTimerDebugEvent()), this, SLOT(handleDebugEvent()));
}
bool CdbDebugEnginePrivate::init(QString *errorMessage)
{
enum { bufLen = 10240 };
- // Load the DLL
- DebuggerEngineLibrary lib;
- if (!lib.init(m_options->path, &m_dbengDLL, errorMessage))
- return false;
- // Initialize the COM interfaces
- HRESULT hr;
- hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr));
- return false;
- }
-
- m_cif.debugClient->SetOutputCallbacksWide(&m_debugOutputCallBack);
- m_cif.debugClient->SetEventCallbacksWide(&m_debugEventCallBack);
-
- hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_cif.debugControl));
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr));
- return false;
- }
-
- setCodeLevel();
-
- hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_cif.debugSystemObjects));
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr));
- return false;
- }
-
- hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_cif.debugSymbols));
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Creation of IDebugSymbols3 failed: %1").arg(msgDebugEngineComResult(hr));
- return false;
- }
-
- WCHAR buf[bufLen];
- hr = m_cif.debugSymbols->GetImagePathWide(buf, bufLen, 0);
- if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetImagePathWide", hr);
- return false;
- }
- m_baseImagePath = QString::fromUtf16(buf);
-
- hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_cif.debugRegisters));
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
- return false;
- }
- hr = lib.debugCreate( __uuidof(IDebugDataSpaces4), reinterpret_cast<void**>(&m_cif.debugDataSpaces));
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Creation of IDebugDataSpaces4 failed: %1").arg(msgDebugEngineComResult(hr));
+ if (!CdbCore::CoreEngine::init(m_options->path, errorMessage))
return false;
- }
+ CdbDebugOutput *output = new CdbDebugOutput;
+ setDebugOutput(DebugOutputBasePtr(output));
+ connect(output, SIGNAL(debuggerOutput(int,QString)),
+ manager(), SLOT(showDebuggerOutput(int,QString)));
+ connect(output, SIGNAL(debuggerInputPrompt(int,QString)),
+ manager(), SLOT(showDebuggerInput(int,QString)));
+ connect(output, SIGNAL(debuggeeOutput(QString)),
+ manager(), SLOT(showApplicationOutput(QString)));
+ connect(output, SIGNAL(debuggeeInputPrompt(QString)),
+ manager(), SLOT(showApplicationOutput(QString)));
+
+ setDebugEventCallback(DebugEventCallbackBasePtr(new CdbDebugEventCallback(m_engine)));
+ updateCodeLevel();
- if (debugCDB)
- qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_cif.debugControl));
return true;
}
@@ -395,49 +172,16 @@ IDebuggerEngine *CdbDebugEngine::create(Debugger::DebuggerManager *manager,
return 0;
}
-// Adapt code level setting to the setting of the action.
-static inline const char *codeLevelName(ULONG level)
+void CdbDebugEnginePrivate::updateCodeLevel()
{
- return level == DEBUG_LEVEL_ASSEMBLY ? "assembly" : "source";
-}
-
-bool CdbDebugEnginePrivate::setCodeLevel()
-{
- const ULONG codeLevel = theDebuggerBoolSetting(OperateByInstruction) ?
- DEBUG_LEVEL_ASSEMBLY : DEBUG_LEVEL_SOURCE;
- ULONG currentCodeLevel = DEBUG_LEVEL_ASSEMBLY;
- HRESULT hr = m_cif.debugControl->GetCodeLevel(&currentCodeLevel);
- if (FAILED(hr)) {
- m_engine->warning(QString::fromLatin1("Cannot determine code level: %1").arg(msgComFailed("GetCodeLevel", hr)));
- return true;
- }
- if (debugCDB)
- qDebug() << Q_FUNC_INFO << "\nSetting code level to " << codeLevelName(codeLevel) << " (was" << codeLevelName(currentCodeLevel) << ')';
- if (currentCodeLevel == codeLevel)
- return false;
- hr = m_cif.debugControl->SetCodeLevel(codeLevel);
- if (FAILED(hr)) {
- m_engine->warning(QString::fromLatin1("Cannot set code level: %1").arg(msgComFailed("SetCodeLevel", hr)));
- return false;
- }
- return true;
+ const CdbCore::CoreEngine::CodeLevel cl = theDebuggerBoolSetting(OperateByInstruction) ?
+ CdbCore::CoreEngine::CodeLevelAssembly : CdbCore::CoreEngine::CodeLevelSource;
+ setCodeLevel(cl);
}
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
{
cleanStackTrace();
- if (m_cif.debugClient)
- m_cif.debugClient->Release();
- if (m_cif.debugControl)
- m_cif.debugControl->Release();
- if (m_cif.debugSystemObjects)
- m_cif.debugSystemObjects->Release();
- if (m_cif.debugSymbols)
- m_cif.debugSymbols->Release();
- if (m_cif.debugRegisters)
- m_cif.debugRegisters->Release();
- if (m_cif.debugDataSpaces)
- m_cif.debugDataSpaces->Release();
}
DebuggerManager *CdbDebugEnginePrivate::manager() const
@@ -477,14 +221,6 @@ CdbDebugEngine::CdbDebugEngine(DebuggerManager *manager, const QSharedPointer<Cd
this, SLOT(slotConsoleStubStarted()));
connect(&m_d->m_consoleStubProc, SIGNAL(wrapperStopped()),
this, SLOT(slotConsoleStubTerminated()));
- connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerOutput(int,QString)),
- manager, SLOT(showDebuggerOutput(int,QString)));
- connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggerInputPrompt(int,QString)),
- manager, SLOT(showDebuggerInput(int,QString)));
- connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeOutput(QString)),
- manager, SLOT(showApplicationOutput(QString)));
- connect(&m_d->m_debugOutputCallBack, SIGNAL(debuggeeInputPrompt(QString)),
- manager, SLOT(showApplicationOutput(QString)));
}
CdbDebugEngine::~CdbDebugEngine()
@@ -499,26 +235,6 @@ void CdbDebugEngine::setState(DebuggerState state, const char *func, int line)
IDebuggerEngine::setState(state);
}
-void CdbDebugEngine::startWatchTimer()
-{
- if (debugCDB)
- qDebug() << Q_FUNC_INFO;
-
- if (m_d->m_watchTimer == -1)
- m_d->m_watchTimer = startTimer(0);
-}
-
-void CdbDebugEngine::killWatchTimer()
-{
- if (debugCDB)
- qDebug() << Q_FUNC_INFO;
-
- if (m_d->m_watchTimer != -1) {
- killTimer(m_d->m_watchTimer);
- m_d->m_watchTimer = -1;
- }
-}
-
void CdbDebugEngine::shutdown()
{
exitDebugger();
@@ -543,7 +259,7 @@ QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &functio
// No function/symbol context found, try to evaluate in current context.
// Do not append type as this will mostly be 'long long' for integers, etc.
QString type;
- if (!evaluateExpression(exp, &rc, &type, &errorMessage))
+ if (!m_d->evaluateExpression(exp, &rc, &type, &errorMessage))
return QString();
return rc;
}
@@ -601,7 +317,7 @@ void CdbDebugEnginePrivate::checkVersion()
versionNotChecked = false;
// Get engine DLL version
QString errorMessage;
- const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, m_dbengDLL, &errorMessage);
+ const QString version = Utils::winGetDLLVersion(Utils::WinDLLProductVersion, dbengDLL(), &errorMessage);
if (version.isEmpty()) {
qWarning("%s\n", qPrintable(errorMessage));
return;
@@ -663,12 +379,12 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
bool rc = false;
bool needWatchTimer = false;
m_d->clearForRun();
- m_d->setCodeLevel();
+ m_d->updateCodeLevel();
m_d->m_ignoreInitialBreakPoint = false;
switch (mode) {
case AttachExternal:
case AttachCrashedExternal:
- rc = startAttachDebugger(sp->attachPID, mode, &errorMessage);
+ rc = m_d->startAttachDebugger(sp->attachPID, mode, &errorMessage);
needWatchTimer = true; // Fetch away module load, etc. even if crashed
break;
case StartInternal:
@@ -695,7 +411,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
}
if (rc) {
if (needWatchTimer)
- startWatchTimer();
+ m_d->startWatchTimer();
emit startSuccessful();
} else {
warning(errorMessage);
@@ -706,7 +422,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QString *errorMessage)
{
- // Need to attrach invasively, otherwise, no notification signals
+ // Need to attach invasively, otherwise, no notification signals
// for for CreateProcess/ExitProcess occur.
// Initial breakpoint occur:
// 1) Desired: When attaching to a crashed process
@@ -716,75 +432,25 @@ bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QStri
// by lookup at the state of the application (startup trap). However,
// there is no startup trap when attaching to a process that has been
// running for a while. (see notifyException).
- ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
- if (manager()->startParameters()->startMode != AttachCrashedExternal)
- flags |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
- const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags);
- if (debugCDB)
- qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr << executionStatusString(m_d->m_cif.debugControl);
- if (FAILED(hr)) {
- *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
- return false;
- } else {
+ const bool suppressInitialBreakPoint = sm != AttachCrashedExternal;
+ const bool rc = m_d->startAttachDebugger(pid, suppressInitialBreakPoint, errorMessage);
+ if (rc)
m_d->m_mode = sm;
- }
- return true;
+ return rc;
}
bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage)
{
- DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
- memset(&dbgopts, 0, sizeof(dbgopts));
- dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
-
const QSharedPointer<DebuggerStartParameters> sp = manager()->startParameters();
- const QString filename(sp->executable);
- // Set image path
- const QFileInfo fi(filename);
- QString imagePath = QDir::toNativeSeparators(fi.absolutePath());
- if (!m_d->m_baseImagePath.isEmpty()) {
- imagePath += QLatin1Char(';');
- imagePath += m_d->m_baseImagePath;
- }
- HRESULT hr = m_d->m_cif.debugSymbols->SetImagePathWide(reinterpret_cast<PCWSTR>(imagePath.utf16()));
- if (FAILED(hr)) {
- *errorMessage = tr("Unable to set the image path to %1: %2").arg(imagePath, msgComFailed("SetImagePathWide", hr));
- return false;
- }
-
- if (debugCDB)
- qDebug() << Q_FUNC_INFO <<'\n' << filename << imagePath;
-
- ULONG symbolOptions = SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS;
- if (m_d->m_options->verboseSymbolLoading)
- symbolOptions |= SYMOPT_DEBUG;
- m_d->m_cif.debugSymbols->SetSymbolOptions(symbolOptions);
-
- const QString cmd = Utils::AbstractProcess::createWinCommandline(filename, sp->processArgs);
- if (debugCDB)
- qDebug() << "Starting " << cmd;
- PCWSTR env = 0;
- QByteArray envData;
- if (!sp->environment.empty()) {
- envData = Utils::AbstractProcess::createWinEnvironment(Utils::AbstractProcess::fixWinEnvironment(sp->environment));
- env = reinterpret_cast<PCWSTR>(envData.data());
- }
- // The working directory cannot be empty.
- PCWSTR workingDirC = 0;
- const QString workingDir = sp->workingDir.isEmpty() ? QString() : QDir::toNativeSeparators(sp->workingDir);
- if (!workingDir.isEmpty())
- workingDirC = workingDir.utf16();
- hr = m_d->m_cif.debugClient->CreateProcess2Wide(NULL,
- reinterpret_cast<PWSTR>(const_cast<ushort *>(cmd.utf16())),
- &dbgopts, sizeof(dbgopts),
- workingDirC, env);
- if (FAILED(hr)) {
- *errorMessage = tr("Unable to create a process '%1': %2").arg(cmd, msgDebugEngineComResult(hr));
- return false;
- } else {
+ const bool rc = m_d->startDebuggerWithExecutable(sp->workingDir,
+ sp->executable,
+ sp->processArgs,
+ sp->environment,
+ m_d->m_options->verboseSymbolLoading,
+ errorMessage);
+ if (rc)
m_d->m_mode = sm;
- }
- return true;
+ return rc;
}
void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
@@ -792,7 +458,7 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
ULONG currentThreadId;
- if (SUCCEEDED(m_cif.debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, &currentThreadId))) {
+ if (SUCCEEDED(interfaces().debugSystemObjects->GetThreadIdByHandle(initialThreadHandle, &currentThreadId))) {
m_currentThreadId = currentThreadId;
} else {
m_currentThreadId = 0;
@@ -810,20 +476,20 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
const QString crashParameter = manager()->startParameters()->crashParameter;
if (!crashParameter.isEmpty()) {
ULONG64 evtNr = crashParameter.toULongLong();
- const HRESULT hr = m_cif.debugControl->SetNotifyEventHandle(evtNr);
+ const HRESULT hr = interfaces().debugControl->SetNotifyEventHandle(evtNr);
// Unless QtCreator is spawned by the debugger and inherits the handles,
// the event handling does not work reliably
// (that is, the crash event is not delivered).
if (SUCCEEDED(hr)) {
QTimer::singleShot(0, m_engine, SLOT(slotBreakAttachToCrashed()));
} else {
- m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(msgComFailed("SetNotifyEventHandle", hr)));
+ m_engine->warning(QString::fromLatin1("Handshake failed on event #%1: %2").arg(evtNr).arg(CdbCore::msgComFailed("SetNotifyEventHandle", hr)));
}
}
}
m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
if (debugCDBExecution)
- qDebug() << "<processCreatedAttached" << executionStatusString(m_cif.debugControl);
+ qDebug() << "<processCreatedAttached";
}
void CdbDebugEngine::processTerminated(unsigned long exitCode)
@@ -851,41 +517,27 @@ bool CdbDebugEnginePrivate::endInferior(EndInferiorAction action, QString *error
}
bool success = false;
switch (action) {
- case DetachInferior: {
- const HRESULT hr = m_cif.debugClient->DetachCurrentProcess();
- if (SUCCEEDED(hr)) {
+ case DetachInferior:
+ if (detachCurrentProcess(errorMessage))
success = true;
- } else {
- *errorMessage += msgComFailed("DetachCurrentProcess", hr);
- }
- }
break;
- case TerminateInferior: {
+ case TerminateInferior:
do {
// The exit process event handler will not be called.
- HRESULT hr = m_cif.debugClient->TerminateCurrentProcess();
- if (FAILED(hr)) {
- *errorMessage += msgComFailed("TerminateCurrentProcess", hr);
- break;
- }
+ terminateCurrentProcess(errorMessage);
if (wasRunning) {
success = true;
break;
}
- hr = m_cif.debugClient->TerminateProcesses();
- if (SUCCEEDED(hr)) {
+ if (terminateProcesses(errorMessage))
success = true;
- } else {
- *errorMessage += msgComFailed("TerminateProcesses", hr);
- }
} while (false);
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
break;
- }
}
// Perform cleanup even when failed..no point clinging to the process
setDebuggeeHandles(0, 0);
- m_engine->killWatchTimer();
+ killWatchTimer();
m_engine->setState(success ? InferiorShutDown : InferiorShutdownFailed, Q_FUNC_INFO, __LINE__);
return success;
}
@@ -929,10 +581,10 @@ void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em)
// Clean up resources (open files, etc.)
m_engine->setState(EngineShuttingDown, Q_FUNC_INFO, __LINE__);
clearForRun();
- const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE);
+ const bool endedCleanly = endSession(&errorMessage);
m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
- if (!SUCCEEDED(hr)) {
- errorMessage = QString::fromLatin1("There were errors trying to end debugging: %1").arg(msgComFailed("EndSession", hr));
+ if (!endedCleanly) {
+ errorMessage = QString::fromLatin1("There were errors trying to end debugging:\n%1").arg(errorMessage);
manager()->showDebuggerOutput(LogError, errorMessage);
}
}
@@ -965,7 +617,7 @@ void CdbDebugEngine::evaluateWatcher(WatchData *wd)
QString errorMessage;
QString value;
QString type;
- if (evaluateExpression(wd->exp, &value, &type, &errorMessage)) {
+ if (m_d->evaluateExpression(wd->exp, &value, &type, &errorMessage)) {
wd->setValue(value);
wd->setType(type);
} else {
@@ -1017,14 +669,14 @@ bool CdbDebugEnginePrivate::executeContinueCommand(const QString &command)
if (debugCDB)
qDebug() << Q_FUNC_INFO << command;
clearForRun();
- setCodeLevel(); // Step by instruction
+ updateCodeLevel(); // Step by instruction
m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Continuing with '%1'...").arg(command));
QString errorMessage;
- const bool success = CdbDebugEnginePrivate::executeDebuggerCommand(m_cif.debugControl, command, &errorMessage);
+ const bool success = executeDebuggerCommand(command, &errorMessage);
if (success) {
m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
- m_engine->startWatchTimer();
+ startWatchTimer();
} else {
m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
m_engine->warning(CdbDebugEngine::tr("Unable to continue: %1").arg(errorMessage));
@@ -1077,14 +729,14 @@ bool CdbDebugEngine::step(unsigned long executionStatus)
|| m_d->m_currentThreadId == triggeringEventThread
|| manager()->threadsHandler()->threads().size() == 1;
m_d->clearForRun(); // clears thread ids
- m_d->setCodeLevel(); // Step by instruction or source line
+ m_d->updateCodeLevel(); // Step by instruction or source line
setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
bool success = false;
if (sameThread && executionStatus != CdbExtendedExecutionStatusStepOut) { // Step event-triggering thread, use fast API
- const HRESULT hr = m_d->m_cif.debugControl->SetExecutionStatus(executionStatus);
+ const HRESULT hr = m_d->interfaces().debugControl->SetExecutionStatus(executionStatus);
success = SUCCEEDED(hr);
if (!success)
- warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgComFailed("SetExecutionStatus", hr)));
+ warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, CdbCore::msgComFailed("SetExecutionStatus", hr)));
} else {
// Need to use a command to explicitly specify the current thread
QString command;
@@ -1102,7 +754,7 @@ bool CdbDebugEngine::step(unsigned long executionStatus)
break;
}
manager()->showDebuggerOutput(tr("Stepping %1").arg(command));
- const HRESULT hr = m_d->m_cif.debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
+ const HRESULT hr = m_d->interfaces().debugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, command.toLatin1().constData(), DEBUG_EXECUTE_ECHO);
success = SUCCEEDED(hr);
if (!success)
warning(msgStepFailed(executionStatus, m_d->m_currentThreadId, msgDebuggerCommandFailed(command, hr)));
@@ -1111,7 +763,7 @@ bool CdbDebugEngine::step(unsigned long executionStatus)
// Oddity: Step into will first break at the calling function. Ignore
if (executionStatus == DEBUG_STATUS_STEP_INTO || executionStatus == DEBUG_STATUS_REVERSE_STEP_INTO)
m_d->m_breakEventMode = CdbDebugEnginePrivate::BreakEventIgnoreOnce;
- startWatchTimer();
+ m_d->startWatchTimer();
setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
} else {
setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
@@ -1159,9 +811,9 @@ bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /*
{
if (debugCDBExecution)
qDebug() << "continueInferiorProcess";
- const HRESULT hr = m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
+ const HRESULT hr = interfaces().debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
if (FAILED(hr)) {
- const QString errorMessage = msgComFailed("SetExecutionStatus", hr);
+ const QString errorMessage = CdbCore::msgComFailed("SetExecutionStatus", hr);
if (errorMessagePtr) {
*errorMessagePtr = errorMessage;
} else {
@@ -1176,14 +828,11 @@ bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /*
bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
{
// Check state: Are we running?
- ULONG executionStatus;
- if (!getExecutionStatus(m_cif.debugControl, &executionStatus, errorMessage))
- return false;
-
+ const ULONG ex = executionStatus();
if (debugCDB)
- qDebug() << Q_FUNC_INFO << "\n ex=" << executionStatus;
+ qDebug() << Q_FUNC_INFO << "\n ex=" << ex;
- if (executionStatus == DEBUG_STATUS_GO) {
+ if (ex == DEBUG_STATUS_GO) {
m_engine->warning(QLatin1String("continueInferior() called while debuggee is running."));
return true;
}
@@ -1192,15 +841,15 @@ bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
bool success = false;
do {
clearForRun();
- setCodeLevel();
- m_engine->killWatchTimer();
+ updateCodeLevel();
+ killWatchTimer();
manager()->resetLocation();
manager()->showStatusMessage(CdbDebugEngine::tr("Running requested..."), messageTimeOut);
if (!continueInferiorProcess(errorMessage))
break;
- m_engine->startWatchTimer();
+ startWatchTimer();
success = true;
} while (false);
if (success) {
@@ -1215,28 +864,14 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
{
// Interrupt the interferior process without notifications
+ // Could use setInterrupt, but that does not work.
if (debugCDBExecution) {
- ULONG executionStatus;
- getExecutionStatus(m_cif.debugControl, &executionStatus, errorMessage);
- qDebug() << "interruptInterferiorProcess ex=" << executionStatus;
+ qDebug() << "interruptInterferiorProcess ex=" << executionStatus();
}
-
- if (DebugBreakProcess(m_hDebuggeeProcess)) {
+ const bool rc = debugBreakProcess(m_hDebuggeeProcess, errorMessage);
+ if (rc)
m_interrupted = true;
- } else {
- *errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Utils::winErrorMessage(GetLastError()));
- return false;
- }
-#if 0
- const HRESULT hr = m_cif.debugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT);
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2").
- arg(getInterruptTimeOutSecs(m_cif.debugControl)).arg(msgComFailed("SetInterrupt", hr));
- return false;
- }
- m_interrupted = true;
-#endif
- return true;
+ return rc;
}
void CdbDebugEngine::slotBreakAttachToCrashed()
@@ -1271,7 +906,7 @@ void CdbDebugEngine::runToLineExec(const QString &fileName, int lineNumber)
tempBreakPoint.fileName = fileName;
tempBreakPoint.lineNumber = lineNumber;
tempBreakPoint.oneShot = true;
- const bool ok = tempBreakPoint.add(m_d->m_cif.debugControl, &errorMessage)
+ const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage)
&& m_d->continueInferior(&errorMessage);
if (!ok)
warning(errorMessage);
@@ -1284,7 +919,7 @@ void CdbDebugEngine::runToFunctionExec(const QString &functionName)
CDBBreakPoint tempBreakPoint;
tempBreakPoint.funcName = functionName;
tempBreakPoint.oneShot = true;
- const bool ok = tempBreakPoint.add(m_d->m_cif.debugControl, &errorMessage)
+ const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage)
&& m_d->continueInferior(&errorMessage);
if (!ok)
warning(errorMessage);
@@ -1327,64 +962,10 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
void CdbDebugEngine::executeDebuggerCommand(const QString &command)
{
QString errorMessage;
- if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_d->m_cif.debugControl, command, &errorMessage))
+ if (!m_d->executeDebuggerCommand(command, &errorMessage))
warning(errorMessage);
}
-bool CdbDebugEnginePrivate::executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage)
-{
- // output to all clients, else we do not see anything
- const HRESULT hr = ctrl->ExecuteWide(DEBUG_OUTCTL_ALL_CLIENTS, reinterpret_cast<PCWSTR>(command.utf16()), 0);
- if (debugCDB)
- qDebug() << "executeDebuggerCommand" << command << SUCCEEDED(hr);
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("Unable to execute '%1': %2").
- arg(command, msgDebugEngineComResult(hr));
- return false;
- }
- return true;
-}
-
-bool CdbDebugEngine::evaluateExpression(const QString &expression,
- QString *value,
- QString *type,
- QString *errorMessage)
-{
- DEBUG_VALUE debugValue;
- if (!m_d->evaluateExpression(m_d->m_cif.debugControl, expression, &debugValue, errorMessage))
- return false;
- *value = CdbSymbolGroupContext::debugValueToString(debugValue, m_d->m_cif.debugControl, type);
- return true;
-}
-
-bool CdbDebugEnginePrivate::evaluateExpression(CIDebugControl *ctrl,
- const QString &expression,
- DEBUG_VALUE *debugValue,
- QString *errorMessage)
-{
- if (debugCDB > 1)
- qDebug() << Q_FUNC_INFO << expression;
-
- memset(debugValue, 0, sizeof(DEBUG_VALUE));
- // Original syntax must be restored, else setting breakpoints will fail.
- SyntaxSetter syntaxSetter(ctrl, DEBUG_EXPR_CPLUSPLUS);
- ULONG errorPosition = 0;
- const HRESULT hr = ctrl->EvaluateWide(reinterpret_cast<PCWSTR>(expression.utf16()),
- DEBUG_VALUE_INVALID, debugValue,
- &errorPosition);
- if (FAILED(hr)) {
- if (HRESULT_CODE(hr) == 517) {
- *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Expression out of scope.").
- arg(expression);
- } else {
- *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Error at %2: %3").
- arg(expression).arg(errorPosition).arg(msgDebugEngineComResult(hr));
- }
- return false;
- }
- return true;
-}
-
void CdbDebugEngine::activateFrame(int frameIndex)
{
if (debugCDB)
@@ -1478,7 +1059,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
// called again from the debug event handler.
ULONG dummy;
- const bool wasRunning = !CDBBreakPoint::getBreakPointCount(m_cif.debugControl, &dummy);
+ const bool wasRunning = !CDBBreakPoint::getBreakPointCount(interfaces().debugControl, &dummy);
if (debugCDB)
qDebug() << Q_FUNC_INFO << "\n Running=" << wasRunning;
@@ -1493,8 +1074,8 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
}
QStringList warnings;
- const bool ok = CDBBreakPoint::synchronizeBreakPoints(m_cif.debugControl,
- m_cif.debugSymbols,
+ const bool ok = CDBBreakPoint::synchronizeBreakPoints(interfaces().debugControl,
+ interfaces().debugSymbols,
manager()->breakHandler(),
errorMessage, &warnings);
if (const int warningsCount = warnings.size())
@@ -1535,8 +1116,7 @@ void CdbDebugEngine::fetchDisassembler(DisassemblerViewAgent *agent,
}
QString disassembly;
QApplication::setOverrideCursor(Qt::WaitCursor);
- ok = dissassemble(m_d->m_cif.debugClient, m_d->m_cif.debugControl, offset,
- ContextLines, ContextLines, addressFieldWith, QTextStream(&disassembly), &errorMessage);
+ ok = dissassemble(m_d, offset, ContextLines, ContextLines, addressFieldWith, QTextStream(&disassembly), &errorMessage);
QApplication::restoreOverrideCursor();
if (!ok)
break;
@@ -1556,10 +1136,10 @@ void CdbDebugEngine::fetchMemory(MemoryViewAgent *agent, quint64 addr, quint64 l
return;
ULONG received;
QByteArray data(length, '\0');
- const HRESULT hr = m_d->m_cif.debugDataSpaces->ReadVirtual(addr, data.data(), length, &received);
+ const HRESULT hr = m_d->interfaces().debugDataSpaces->ReadVirtual(addr, data.data(), length, &received);
if (FAILED(hr)) {
warning(tr("Unable to retrieve %1 bytes of memory at 0x%2: %3").
- arg(length).arg(addr, 0, 16).arg(msgComFailed("ReadVirtual", hr)));
+ arg(length).arg(addr, 0, 16).arg(CdbCore::msgComFailed("ReadVirtual", hr)));
return;
}
if (received < length)
@@ -1593,7 +1173,7 @@ QList<Symbol> CdbDebugEngine::moduleSymbols(const QString &moduleName)
errorMessage = tr("Cannot retrieve symbols while the debuggee is running.");
break;
}
- if (!getModuleSymbols(m_d->m_cif.debugSymbols, moduleName, &rc, &errorMessage))
+ if (!getModuleSymbols(m_d->interfaces().debugSymbols, moduleName, &rc, &errorMessage))
break;
success = true;
} while (false);
@@ -1611,40 +1191,11 @@ void CdbDebugEngine::reloadRegisters()
qDebug() << Q_FUNC_INFO << intBase;
QList<Register> registers;
QString errorMessage;
- if (!getRegisters(m_d->m_cif.debugControl, m_d->m_cif.debugRegisters, &registers, &errorMessage, intBase))
+ if (!getRegisters(m_d->interfaces().debugControl, m_d->interfaces().debugRegisters, &registers, &errorMessage, intBase))
warning(msgFunctionFailed("reloadRegisters" , errorMessage));
manager()->registerHandler()->setRegisters(registers);
}
-void CdbDebugEngine::timerEvent(QTimerEvent* te)
-{
- // Fetch away the debug events and notify if debuggee
- // stops. Note that IDebugEventCallback does not
- // cover all cases of a debuggee stopping execution
- // (such as step over,etc).
- if (te->timerId() != m_d->m_watchTimer)
- return;
-
- const HRESULT hr = m_d->m_cif.debugControl->WaitForEvent(0, 1);
- if (debugCDB)
- if (debugCDB > 1 || hr != S_FALSE)
- qDebug() << Q_FUNC_INFO << "WaitForEvent" << state() << msgDebugEngineComResult(hr);
-
- switch (hr) {
- case S_OK:
- killWatchTimer();
- m_d->handleDebugEvent();
- break;
- case S_FALSE:
- case E_PENDING:
- case E_FAIL:
- break;
- case E_UNEXPECTED: // Occurs on ExitProcess.
- killWatchTimer();
- break;
- }
-}
-
void CdbDebugEngine::slotConsoleStubStarted()
{
const qint64 appPid = m_d->m_consoleStubProc.applicationPID();
@@ -1653,7 +1204,7 @@ void CdbDebugEngine::slotConsoleStubStarted()
// Attach to console process
QString errorMessage;
if (startAttachDebugger(appPid, AttachExternal, &errorMessage)) {
- startWatchTimer();
+ m_d->startWatchTimer();
manager()->notifyInferiorPidChanged(appPid);
} else {
QMessageBox::critical(manager()->mainWindow(), tr("Debugger Error"), errorMessage);
@@ -1713,7 +1264,7 @@ void CdbDebugEnginePrivate::handleDebugEvent()
{
if (debugCDBExecution)
qDebug() << "handleDebugEvent mode " << m_breakEventMode
- << executionStatusString(m_cif.debugControl) << " interrupt" << m_interrupted
+ << CdbCore::msgExecutionStatusString(executionStatus()) << " interrupt" << m_interrupted
<< " startupcomplete" << m_inferiorStartupComplete;
// restore mode and do special handling
const HandleBreakEventMode mode = m_breakEventMode;
@@ -1754,7 +1305,7 @@ void CdbDebugEnginePrivate::handleDebugEvent()
}
break;
case BreakEventIgnoreOnce:
- m_engine->startWatchTimer();
+ startWatchTimer();
m_interrupted = false;
break;
case BreakEventSyncBreakPoints: {
@@ -1762,7 +1313,7 @@ void CdbDebugEnginePrivate::handleDebugEvent()
// Temp stop to sync breakpoints
QString errorMessage;
attemptBreakpointSynchronization(&errorMessage);
- m_engine->startWatchTimer();
+ startWatchTimer();
continueInferiorProcess(&errorMessage);
if (!errorMessage.isEmpty())
m_engine->warning(QString::fromLatin1("In handleDebugEvent: %1").arg(errorMessage));
@@ -1783,17 +1334,17 @@ void CdbDebugEnginePrivate::setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE
bool CdbDebugEnginePrivate::setCDBThreadId(unsigned long threadId, QString *errorMessage)
{
ULONG currentThreadId;
- HRESULT hr = m_cif.debugSystemObjects->GetCurrentThreadId(&currentThreadId);
+ HRESULT hr = interfaces().debugSystemObjects->GetCurrentThreadId(&currentThreadId);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetCurrentThreadId", hr);
+ *errorMessage = CdbCore::msgComFailed("GetCurrentThreadId", hr);
return false;
}
if (currentThreadId == threadId)
return true;
- hr = m_cif.debugSystemObjects->SetCurrentThreadId(threadId);
+ hr = interfaces().debugSystemObjects->SetCurrentThreadId(threadId);
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Failed to change to from thread %1 to %2: SetCurrentThreadId() failed: %3").
- arg(currentThreadId).arg(threadId).arg(msgDebugEngineComResult(hr));
+ arg(currentThreadId).arg(threadId).arg(CdbCore::msgDebugEngineComResult(hr));
return false;
}
const QString msg = CdbDebugEngine::tr("Changing threads: %1 -> %2").arg(currentThreadId).arg(threadId);
@@ -1810,7 +1361,7 @@ ULONG CdbDebugEnginePrivate::updateThreadList()
ULONG currentThreadId;
QString errorMessage;
// When interrupting, an artifical thread with a breakpoint is created.
- if (!CdbStackTraceContext::getThreads(m_cif, true, &threads, &currentThreadId, &errorMessage))
+ if (!CdbStackTraceContext::getThreads(interfaces(), true, &threads, &currentThreadId, &errorMessage))
m_engine->warning(errorMessage);
manager()->threadsHandler()->setThreads(threads);
return currentThreadId;
@@ -1903,7 +1454,7 @@ void CdbDebugEnginePrivate::updateModules()
{
QList<Module> modules;
QString errorMessage;
- if (!getModuleList(m_cif.debugSymbols, &modules, &errorMessage))
+ if (!getModuleList(interfaces().debugSymbols, &modules, &errorMessage))
m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
manager()->modulesHandler()->setModules(modules);
}
@@ -1929,14 +1480,6 @@ void CdbDebugEngine::reloadSourceFiles()
{
}
-QStringList CdbDebugEnginePrivate::sourcePaths() const
-{
- WCHAR wszBuf[MAX_PATH];
- if (SUCCEEDED(m_cif.debugSymbols->GetSourcePathWide(wszBuf, MAX_PATH, 0)))
- return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';'));
- return QStringList();
-}
-
void CdbDebugEngine::syncDebuggerPaths()
{
if (debugCDB)
@@ -1949,39 +1492,6 @@ void CdbDebugEngine::syncDebuggerPaths()
}
}
-static inline QString pathString(const QStringList &s)
-{ return s.join(QString(QLatin1Char(';'))); }
-
-bool CdbDebugEnginePrivate::setSourcePaths(const QStringList &s, QString *errorMessage)
-{
- const HRESULT hr = m_cif.debugSymbols->SetSourcePathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16()));
- if (FAILED(hr)) {
- if (errorMessage)
- *errorMessage = msgComFailed("SetSourcePathWide", hr);
- return false;
- }
- return true;
-}
-
-QStringList CdbDebugEnginePrivate::symbolPaths() const
-{
- WCHAR wszBuf[MAX_PATH];
- if (SUCCEEDED(m_cif.debugSymbols->GetSymbolPathWide(wszBuf, MAX_PATH, 0)))
- return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';'));
- return QStringList();
-}
-
-bool CdbDebugEnginePrivate::setSymbolPaths(const QStringList &s, QString *errorMessage)
-{
- const HRESULT hr = m_cif.debugSymbols->SetSymbolPathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16()));
- if (FAILED(hr)) {
- if (errorMessage)
- *errorMessage = msgComFailed("SetSymbolPathWide", hr);
- return false;
- }
- return true;
-}
-
// Accessed by DebuggerManager
IDebuggerEngine *createWinEngine(DebuggerManager *parent,
bool cmdLineEnabled,
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h
index 59d7658a92..52fb70119d 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine.h
@@ -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;
};
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index 89a7fa15f7..55e7287723 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -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 };
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
index 26c24b2058..0ffc51ff20 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
@@ -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 */
- )
-{
- return S_OK;
-}
-
-IDebugEventCallbacksWide *CdbDebugEventCallbackBase::getEventCallback(CIDebugClient *clnt)
-{
- IDebugEventCallbacksWide *rc = 0;
- if (SUCCEEDED(clnt->GetEventCallbacksWide(&rc)))
- return rc;
- return 0;
-}
-
// ---------- CdbDebugEventCallback
CdbDebugEventCallback::CdbDebugEventCallback(CdbDebugEngine* dbg) :
@@ -420,18 +252,5 @@ STDMETHODIMP IgnoreDebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
return S_OK;
}
-// --------- EventCallbackRedirector
-EventCallbackRedirector::EventCallbackRedirector(CIDebugClient *client, IDebugEventCallbacksWide *cb) :
- m_client(client),
- m_oldCb(CdbDebugEventCallbackBase::getEventCallback(client))
-{
- client->SetEventCallbacksWide(cb);
-}
-
-EventCallbackRedirector::~EventCallbackRedirector()
-{
- m_client->SetEventCallbacksWide(m_oldCb);
-}
-
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.h b/src/plugins/debugger/cdb/cdbdebugeventcallback.h
index 4250cd5b24..99c99a937a 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.h
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.h
@@ -30,7 +30,7 @@
#ifndef DEBUGGER_CDBDEBUGEVENTCALLBACK_H
#define DEBUGGER_CDBDEBUGEVENTCALLBACK_H
-#include "cdbcom.h"
+#include "debugeventcallbackbase.h"
#include <QtCore/QStringList>
@@ -41,122 +41,7 @@ namespace Internal {
class CdbDebugEngine;
-// Base class for event callbacks that takes care
-// Active X magic. Provides base implementations with
-// the exception of GetInterestMask
-class CdbDebugEventCallbackBase : public IDebugEventCallbacksWide
-{
-protected:
- CdbDebugEventCallbackBase();
-public:
- // IUnknown.
- STDMETHOD(QueryInterface)(
- THIS_
- IN REFIID InterfaceId,
- OUT PVOID* Interface
- );
- STDMETHOD_(ULONG, AddRef)(
- THIS
- );
- STDMETHOD_(ULONG, Release)(
- THIS
- );
-
- // IDebugEventCallbacks.
-
- STDMETHOD(Breakpoint)(
- THIS_
- __in PDEBUG_BREAKPOINT2 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 PCWSTR ModuleName,
- __in_opt PCWSTR 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 PCWSTR ModuleName,
- __in_opt PCWSTR ImageName,
- __in ULONG CheckSum,
- __in ULONG TimeDateStamp
- );
-
- STDMETHOD(UnloadModule)(
- THIS_
- __in_opt PCWSTR 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
- );
-
-
- static IDebugEventCallbacksWide *getEventCallback(CIDebugClient *clnt);
-};
-
-class CdbDebugEventCallback : public CdbDebugEventCallbackBase
+class CdbDebugEventCallback : public CdbCore::DebugEventCallbackBase
{
public:
explicit CdbDebugEventCallback(CdbDebugEngine* dbg);
@@ -239,7 +124,7 @@ private:
// Event handler logs exceptions to the debugger window
// and ignores the rest. To be used for running dumper calls.
-class CdbExceptionLoggerEventCallback : public CdbDebugEventCallbackBase
+class CdbExceptionLoggerEventCallback : public CdbCore::DebugEventCallbackBase
{
public:
CdbExceptionLoggerEventCallback(int logChannel,
@@ -270,7 +155,7 @@ private:
};
// Event handler that ignores everything
-class IgnoreDebugEventCallback : public CdbDebugEventCallbackBase
+class IgnoreDebugEventCallback : public CdbCore::DebugEventCallbackBase
{
public:
explicit IgnoreDebugEventCallback();
@@ -281,19 +166,6 @@ public:
);
};
-// Utility class to temporarily redirect events to another handler
-// as long as in scope
-class EventCallbackRedirector {
- Q_DISABLE_COPY(EventCallbackRedirector)
-public:
- explicit EventCallbackRedirector(CIDebugClient *client, IDebugEventCallbacksWide *cb);
- ~EventCallbackRedirector();
-private:
- CIDebugClient *m_client;
- IDebugEventCallbacksWide *m_oldCb;
-};
-
-
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.cpp b/src/plugins/debugger/cdb/cdbdebugoutput.cpp
index b3c8a76575..04a2729f0f 100644
--- a/src/plugins/debugger/cdb/cdbdebugoutput.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugoutput.cpp
@@ -37,62 +37,6 @@
namespace Debugger {
namespace Internal {
-CdbDebugOutputBase::CdbDebugOutputBase()
-{
-}
-
-STDMETHODIMP CdbDebugOutputBase::QueryInterface(
- THIS_
- IN REFIID InterfaceId,
- OUT PVOID* Interface
- )
-{
- *Interface = NULL;
-
- if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
- IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacksWide)))
- {
- *Interface = (IDebugOutputCallbacksWide*)this;
- AddRef();
- return S_OK;
- } else {
- return E_NOINTERFACE;
- }
-}
-
-STDMETHODIMP_(ULONG) CdbDebugOutputBase::AddRef(THIS)
-{
- // This class is designed to be static so
- // there's no true refcount.
- return 1;
-}
-
-STDMETHODIMP_(ULONG) CdbDebugOutputBase::Release(THIS)
-{
- // This class is designed to be static so
- // there's no true refcount.
- return 0;
-}
-
-STDMETHODIMP CdbDebugOutputBase::Output(
- THIS_
- IN ULONG mask,
- IN PCWSTR text
- )
-{
- const QString msg = QString::fromUtf16(reinterpret_cast<const ushort *>(text));
- output(mask, msg);
- return S_OK;
-}
-
-IDebugOutputCallbacksWide *CdbDebugOutputBase::getOutputCallback(CIDebugClient *client)
-{
- IDebugOutputCallbacksWide *rc;
- if (FAILED(client->GetOutputCallbacksWide(&rc)))
- return 0;
- return rc;
-}
-
// ------------------------- CdbDebugOutput
// Return a prefix for debugger messages
@@ -145,18 +89,5 @@ void CdbDebugOutput::output(ULONG mask, const QString &msg)
}
}
-// Utility class to temporarily redirect output to another handler
-// as long as in scope
-OutputRedirector::OutputRedirector(CIDebugClient *client, IDebugOutputCallbacksWide *newHandler) :
- m_client(client),
- m_oldHandler(CdbDebugOutputBase::getOutputCallback(client))
-{
- m_client->SetOutputCallbacksWide(newHandler);
-}
-OutputRedirector::~OutputRedirector()
-{
- m_client->SetOutputCallbacksWide(m_oldHandler);
-}
-
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.h b/src/plugins/debugger/cdb/cdbdebugoutput.h
index ad2473c787..90ed71bfd5 100644
--- a/src/plugins/debugger/cdb/cdbdebugoutput.h
+++ b/src/plugins/debugger/cdb/cdbdebugoutput.h
@@ -30,49 +30,15 @@
#ifndef DEBUGGER_CDBOUTPUT_H
#define DEBUGGER_CDBOUTPUT_H
-#include "cdbcom.h"
+#include "debugoutputbase.h"
#include <QtCore/QObject>
namespace Debugger {
namespace Internal {
-// CdbDebugOutputBase is a base class for output handlers
-// that takes care of the Active X magic and conversion to QString.
-
-class CdbDebugOutputBase : public IDebugOutputCallbacksWide
-{
-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 PCWSTR text
- );
-
- // Helpers to retrieve the output callbacks IF
- static IDebugOutputCallbacksWide *getOutputCallback(CIDebugClient *client);
-
-protected:
- CdbDebugOutputBase();
- virtual void output(ULONG mask, const QString &message) = 0;
-};
-
// Standard CDB output handler
-class CdbDebugOutput : public QObject, public CdbDebugOutputBase
+class CdbDebugOutput : public QObject, public CdbCore::DebugOutputBase
{
Q_OBJECT
public:
@@ -88,34 +54,6 @@ signals:
void debuggeeInputPrompt(const QString &message);
};
-// An output handler that adds lines to a string (to be
-// used for cases in which linebreaks occur in-between calls
-// to output).
-class StringOutputHandler : public CdbDebugOutputBase
-{
-public:
- StringOutputHandler() {}
- QString result() const { return m_result; }
-
-protected:
- virtual void output(ULONG, const QString &message) { m_result += message; }
-
-private:
- QString m_result;
-};
-
-// Utility class to temporarily redirect output to another handler
-// as long as in scope
-class OutputRedirector {
- Q_DISABLE_COPY(OutputRedirector)
-public:
- explicit OutputRedirector(CIDebugClient *client, IDebugOutputCallbacksWide *newHandler);
- ~OutputRedirector();
-private:
- CIDebugClient *m_client;
- IDebugOutputCallbacksWide *m_oldHandler;
-};
-
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
index 852f3f929b..10f9405e65 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
@@ -94,59 +94,13 @@ namespace Debugger {
namespace Internal {
// ------- Call load helpers
-// Alloc memory in debuggee using the ".dvalloc" command as
-// there seems to be no API for it.
-static bool allocDebuggeeMemory(CdbComInterfaces *cif,
- int size, ULONG64 *address, QString *errorMessage)
-{
- *address = 0;
- const QString allocCmd = QLatin1String(".dvalloc ") + QString::number(size);
- StringOutputHandler stringHandler;
- OutputRedirector redir(cif->debugClient, &stringHandler);
- if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, allocCmd, errorMessage))
- return false;
- // "Allocated 1000 bytes starting at 003a0000" .. hopefully never localized
- bool ok = false;
- const QString output = stringHandler.result();
- const int lastBlank = output.lastIndexOf(QLatin1Char(' '));
- if (lastBlank != -1) {
- const qint64 addri = output.mid(lastBlank + 1).toLongLong(&ok, 16);
- if (ok)
- *address = addri;
- }
- if (loadDebug > 1)
- qDebug() << Q_FUNC_INFO << '\n' << output << *address << ok;
- if (!ok) {
- *errorMessage = QString::fromLatin1("Failed to parse output '%1'").arg(output);
- return false;
- }
- return true;
-}
-
-// Alloc an AscII string in debuggee
-static bool createDebuggeeAscIIString(CdbComInterfaces *cif,
- const QString &s,
- ULONG64 *address,
- QString *errorMessage)
-{
- QByteArray sAsciiData = s.toLocal8Bit();
- sAsciiData += '\0';
- if (!allocDebuggeeMemory(cif, sAsciiData.size(), address, errorMessage))
- return false;
- const HRESULT hr = cif->debugDataSpaces->WriteVirtual(*address, sAsciiData.data(), sAsciiData.size(), 0);
- if (FAILED(hr)) {
- *errorMessage= msgComFailed("WriteVirtual", hr);
- return false;
- }
- return true;
-}
-// Load a library into the debuggee. Currently requires
+ // Load a library into the debuggee. Currently requires
// the QtCored4.pdb file to be present as we need "qstrdup"
// as dummy symbol. This is ok ATM since dumpers only
// make sense for Qt apps.
static bool debuggeeLoadLibrary(DebuggerManager *manager,
- CdbComInterfaces *cif,
+ CdbCore::CoreEngine *engine,
unsigned long threadId,
const QString &moduleName,
QString *errorMessage)
@@ -154,12 +108,13 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager,
if (loadDebug > 1)
qDebug() << Q_FUNC_INFO << moduleName;
// Try to ignore the breakpoints, skip stray startup-complete trap exceptions
- CdbExceptionLoggerEventCallback exLogger(LogWarning, true, manager);
- EventCallbackRedirector eventRedir(cif->debugClient, &exLogger);
+ QSharedPointer<CdbExceptionLoggerEventCallback> exLogger(new CdbExceptionLoggerEventCallback(LogWarning, true, manager));
+ CdbCore::EventCallbackRedirector eventRedir(engine, exLogger);
+ Q_UNUSED(eventRedir)
// Make a call to LoadLibraryA. First, reserve memory in debugger
// and copy name over.
ULONG64 nameAddress;
- if (!createDebuggeeAscIIString(cif, moduleName, &nameAddress, errorMessage))
+ if (!engine->createDebuggeeAscIIString(moduleName, &nameAddress, errorMessage))
return false;
// We want to call "HMODULE LoadLibraryA(LPCTSTR lpFileName)"
// (void* LoadLibraryA(char*)). However, despite providing a symbol
@@ -168,7 +123,7 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager,
// Prepare call: Locate 'qstrdup' in the (potentially namespaced) corelib. For some
// reason, the symbol is present in QtGui as well without type information.
QString dummyFunc = QLatin1String("*qstrdup");
- if (resolveSymbol(cif->debugSymbols, QLatin1String("QtCore[d]*4!"), &dummyFunc, errorMessage) != ResolveSymbolOk)
+ if (resolveSymbol(engine->interfaces().debugSymbols, QLatin1String("QtCore[d]*4!"), &dummyFunc, errorMessage) != ResolveSymbolOk)
return false;
QString callCmd; {
@@ -179,16 +134,16 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager,
if (loadDebug)
qDebug() << "Calling" << callCmd;
- if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, callCmd, errorMessage))
+ if (!engine->executeDebuggerCommand(callCmd, errorMessage))
return false;
// Execute current thread. This will hit a breakpoint.
QString goCmd;
QTextStream(&goCmd) << '~' << threadId << " g";
- if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, goCmd, errorMessage))
+ if (!engine->executeDebuggerCommand(goCmd, errorMessage))
return false;
- const HRESULT hr = cif->debugControl->WaitForEvent(0, waitTimeOutMS);
+ const HRESULT hr = engine->waitForEvent(waitTimeOutMS);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("WaitForEvent", hr);
+ *errorMessage = CdbCore::msgComFailed("WaitForEvent", hr);
return false;
}
return true;
@@ -339,13 +294,13 @@ void CdbDumperInitThread ::run()
// ------------------- CdbDumperHelper
CdbDumperHelper::CdbDumperHelper(DebuggerManager *manager,
- CdbComInterfaces *cif) :
+ CdbCore::CoreEngine *coreEngine) :
m_tryInjectLoad(true),
m_msgDisabled(QLatin1String("Dumpers are disabled")),
m_msgNotInScope(QLatin1String("Data not in scope")),
m_state(NotLoaded),
m_manager(manager),
- m_cif(cif),
+ m_coreEngine(coreEngine),
m_inBufferAddress(0),
m_inBufferSize(0),
m_outBufferAddress(0),
@@ -433,7 +388,7 @@ CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMess
qDebug() << Q_FUNC_INFO;
// Do we have Qt and are we already loaded by accident?
QStringList modules;
- if (!getModuleNameList(m_cif->debugSymbols, &modules, errorMessage))
+ if (!getModuleNameList(m_coreEngine->interfaces().debugSymbols, &modules, errorMessage))
return CallLoadError;
// Are we already loaded by some accident?
if (!modules.filter(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive).isEmpty())
@@ -442,7 +397,7 @@ CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMess
if (modules.filter(QLatin1String(qtCoreModuleNameC), Qt::CaseInsensitive).isEmpty())
return CallLoadNoQtApp;
// Try to load
- if (!debuggeeLoadLibrary(m_manager, m_cif, m_dumperCallThread, m_library, errorMessage))
+ if (!debuggeeLoadLibrary(m_manager, m_coreEngine, m_dumperCallThread, m_library, errorMessage))
return CallLoadError;
return CallLoadOk;
}
@@ -457,7 +412,7 @@ static inline bool getSymbolAddress(CIDebugSymbols *sg,
// Get address
HRESULT hr = sg->GetOffsetByNameWide(reinterpret_cast<PCWSTR>(name.utf16()), address);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetOffsetByNameWide", hr);
+ *errorMessage = CdbCore::msgComFailed("GetOffsetByNameWide", hr);
return false;
}
// Get size. Even works for arrays
@@ -466,12 +421,12 @@ static inline bool getSymbolAddress(CIDebugSymbols *sg,
ULONG type;
hr = sg->GetOffsetTypeId(*address, &type, &moduleAddress);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetOffsetTypeId", hr);
+ *errorMessage = CdbCore::msgComFailed("GetOffsetTypeId", hr);
return false;
}
hr = sg->GetTypeSize(moduleAddress, type, size);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetTypeSize", hr);
+ *errorMessage = CdbCore::msgComFailed("GetTypeSize", hr);
return false;
}
} // size desired
@@ -488,14 +443,14 @@ bool CdbDumperHelper::initResolveSymbols(QString *errorMessage)
QString inBufferSymbol = QLatin1String("*qDumpInBuffer");
QString outBufferSymbol = QLatin1String("*qDumpOutBuffer");
const QString dumperModuleName = QLatin1String(dumperModuleNameC);
- bool rc = resolveSymbol(m_cif->debugSymbols, &m_dumpObjectSymbol, errorMessage) == ResolveSymbolOk
- && resolveSymbol(m_cif->debugSymbols, dumperModuleName, &inBufferSymbol, errorMessage) == ResolveSymbolOk
- && resolveSymbol(m_cif->debugSymbols, dumperModuleName, &outBufferSymbol, errorMessage) == ResolveSymbolOk;
+ bool rc = resolveSymbol(m_coreEngine->interfaces().debugSymbols, &m_dumpObjectSymbol, errorMessage) == ResolveSymbolOk
+ && resolveSymbol(m_coreEngine->interfaces().debugSymbols, dumperModuleName, &inBufferSymbol, errorMessage) == ResolveSymbolOk
+ && resolveSymbol(m_coreEngine->interfaces().debugSymbols, dumperModuleName, &outBufferSymbol, errorMessage) == ResolveSymbolOk;
if (!rc)
return false;
// Determine buffer addresses, sizes and alloc buffer
- rc = getSymbolAddress(m_cif->debugSymbols, inBufferSymbol, &m_inBufferAddress, &m_inBufferSize, errorMessage)
- && getSymbolAddress(m_cif->debugSymbols, outBufferSymbol, &m_outBufferAddress, &m_outBufferSize, errorMessage);
+ rc = getSymbolAddress(m_coreEngine->interfaces().debugSymbols, inBufferSymbol, &m_inBufferAddress, &m_inBufferSize, errorMessage)
+ && getSymbolAddress(m_coreEngine->interfaces().debugSymbols, outBufferSymbol, &m_outBufferAddress, &m_outBufferSize, errorMessage);
if (!rc)
return false;
m_buffer = new char[qMax(m_inBufferSize, m_outBufferSize)];
@@ -532,41 +487,24 @@ bool CdbDumperHelper::initKnownTypes(QString *errorMessage)
return true;
}
-// Write to debuggee memory in chunks
-bool CdbDumperHelper::writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage)
-{
- char *ptr = const_cast<char*>(buffer.data());
- ULONG bytesToWrite = buffer.size();
- while (bytesToWrite > 0) {
- ULONG bytesWritten = 0;
- const HRESULT hr = ds->WriteVirtual(address, ptr, bytesToWrite, &bytesWritten);
- if (FAILED(hr)) {
- *errorMessage = msgComFailed("WriteVirtual", hr);
- return false;
- }
- bytesToWrite -= bytesWritten;
- ptr += bytesWritten;
- }
- return true;
-}
-
CdbDumperHelper::CallResult
CdbDumperHelper::callDumper(const QString &callCmd, const QByteArray &inBuffer, const char **outDataPtr,
bool ignoreAccessViolation, QString *errorMessage)
{
*outDataPtr = 0;
// Skip stray startup-complete trap exceptions.
- CdbExceptionLoggerEventCallback exLogger(LogWarning, true, m_manager);
- EventCallbackRedirector eventRedir(m_cif->debugClient, &exLogger);
+ QSharedPointer<CdbExceptionLoggerEventCallback> exLogger(new CdbExceptionLoggerEventCallback(LogWarning, true, m_manager));
+ CdbCore::EventCallbackRedirector eventRedir(m_coreEngine, exLogger);
+ Q_UNUSED(eventRedir)
// write input buffer
if (!inBuffer.isEmpty()) {
- if (!writeToDebuggee(m_cif->debugDataSpaces, inBuffer, m_inBufferAddress, errorMessage))
+ if (!m_coreEngine->writeToDebuggee(inBuffer, m_inBufferAddress, errorMessage))
return CallFailed;
}
- if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, callCmd, errorMessage)) {
+ if (!m_coreEngine->executeDebuggerCommand(callCmd, errorMessage)) {
// Clear the outstanding call in case we triggered a debug library assert with a message box
QString clearError;
- if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, QLatin1String(".call /c"), &clearError)) {
+ if (!m_coreEngine->executeDebuggerCommand(QLatin1String(".call /c"), &clearError)) {
*errorMessage += QString::fromLatin1("/Unable to clear call %1").arg(clearError);
}
return CallSyntaxError;
@@ -575,40 +513,40 @@ CdbDumperHelper::CallResult
// Try to skip debuggee crash exceptions and dumper exceptions
// by using 'gN' (go not handled -> pass handling to dumper __try/__catch block)
for (int i = 0; i < 10; i++) {
- const int oldExceptionCount = exLogger.exceptionCount();
+ const int oldExceptionCount = exLogger->exceptionCount();
// Go in current thread. If an exception occurs in loop 2,
// let the dumper handle it.
QString goCmd = m_goCommand;
if (i)
goCmd = QLatin1Char('N');
- if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, goCmd, errorMessage))
+ if (!m_coreEngine->executeDebuggerCommand(goCmd, errorMessage))
return CallFailed;
- HRESULT hr = m_cif->debugControl->WaitForEvent(0, waitTimeOutMS);
+ HRESULT hr = m_coreEngine->waitForEvent(waitTimeOutMS);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("WaitForEvent", hr);
+ *errorMessage = CdbCore::msgComFailed("WaitForEvent", hr);
return CallFailed;
}
- const int newExceptionCount = exLogger.exceptionCount();
+ const int newExceptionCount = exLogger->exceptionCount();
// no new exceptions? -> break
if (oldExceptionCount == newExceptionCount)
break;
// If we are to ignore EXCEPTION_ACCESS_VIOLATION, check if anything
// else occurred.
if (ignoreAccessViolation) {
- const QList<ULONG> newExceptionCodes = exLogger.exceptionCodes().mid(oldExceptionCount);
+ const QList<ULONG> newExceptionCodes = exLogger->exceptionCodes().mid(oldExceptionCount);
if (newExceptionCodes.count(EXCEPTION_ACCESS_VIOLATION) == newExceptionCodes.size())
break;
}
}
- if (exLogger.exceptionCount()) {
- const QString exMsgs = exLogger.exceptionMessages().join(QString(QLatin1Char(',')));
+ if (exLogger->exceptionCount()) {
+ const QString exMsgs = exLogger->exceptionMessages().join(QString(QLatin1Char(',')));
*errorMessage = QString::fromLatin1("Exceptions occurred during the dumper call: %1").arg(exMsgs);
return CallFailed;
}
// Read output
- const HRESULT hr = m_cif->debugDataSpaces->ReadVirtual(m_outBufferAddress, m_buffer, m_outBufferSize, 0);
+ const HRESULT hr = m_coreEngine->interfaces().debugDataSpaces->ReadVirtual(m_outBufferAddress, m_buffer, m_outBufferSize, 0);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("ReadVirtual", hr);
+ *errorMessage = CdbCore::msgComFailed("ReadVirtual", hr);
return CallFailed;
}
// see QDumper implementation
@@ -742,7 +680,7 @@ CdbDumperHelper::DumpExecuteResult
qDebug() << "Query: " << wd.toString() << "\nwith: " << callCmd << '\n';
const char *outputData;
// Completely ignore EXCEPTION_ACCESS_VIOLATION crashes in the dumpers.
- ExceptionBlocker eb(m_cif->debugControl, EXCEPTION_ACCESS_VIOLATION, ExceptionBlocker::IgnoreException);
+ ExceptionBlocker eb(m_coreEngine->interfaces().debugControl, EXCEPTION_ACCESS_VIOLATION, ExceptionBlocker::IgnoreException);
if (!eb) {
*errorMessage = eb.errorString();
return DumpExecuteCallFailed;
@@ -808,11 +746,10 @@ bool CdbDumperHelper::runTypeSizeQuery(const QString &typeName, int *size, QStri
QString expression = QLatin1String("sizeof(");
expression += typeName;
expression += QLatin1Char(')');
- if (!CdbDebugEnginePrivate::evaluateExpression(m_cif->debugControl,
- expression, &sizeValue, errorMessage))
+ if (!m_coreEngine->evaluateExpression(expression, &sizeValue, errorMessage))
return false;
qint64 size64;
- if (!CdbSymbolGroupContext::debugValueToInteger(sizeValue, &size64)) {
+ if (!CdbCore::debugValueToInteger(sizeValue, &size64)) {
*errorMessage = QLatin1String("Expression result is not an integer");
return false;
}
@@ -833,6 +770,11 @@ void CdbDumperHelper::setDumperCallThread(unsigned long t)
}
}
+const CdbCore::ComInterfaces *CdbDumperHelper::comInterfaces() const
+{
+ return &m_coreEngine->interfaces();
+}
+
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.h b/src/plugins/debugger/cdb/cdbdumperhelper.h
index be326768df..b4173b5664 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.h
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.h
@@ -36,11 +36,15 @@
#include <QtCore/QStringList>
#include <QtCore/QMap>
+namespace CdbCore {
+ class CoreEngine;
+ struct ComInterfaces;
+}
+
namespace Debugger {
class DebuggerManager;
namespace Internal {
-struct CdbComInterfaces;
class CdbDumperInitThread;
/* For code clarity, all the stuff related to custom dumpers goes here.
@@ -81,8 +85,8 @@ public:
Initialized, // List of types, etc. retrieved
};
- explicit CdbDumperHelper(DebuggerManager *manager,
- CdbComInterfaces *cif);
+ explicit CdbDumperHelper(DebuggerManager *manager,
+ CdbCore::CoreEngine *coreEngine);
~CdbDumperHelper();
State state() const { return m_state; }
@@ -102,7 +106,7 @@ public:
DumpResult dumpType(const WatchData &d, bool dumpChildren,
QList<WatchData> *result, QString *errorMessage);
- inline CdbComInterfaces *comInterfaces() const { return m_cif; }
+ const CdbCore::ComInterfaces *comInterfaces() const;
enum { InvalidDumperCallThread = 0xFFFFFFFF };
unsigned long dumperCallThread();
@@ -131,14 +135,12 @@ private:
const QtDumperHelper::TypeData& td, bool dumpChildren,
QList<WatchData> *result, QString *errorMessage);
- static bool writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage);
-
const bool m_tryInjectLoad;
const QString m_msgDisabled;
const QString m_msgNotInScope;
State m_state;
DebuggerManager *m_manager;
- CdbComInterfaces *m_cif;
+ CdbCore::CoreEngine *m_coreEngine;
QString m_library;
QString m_dumpObjectSymbol;
diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.cpp b/src/plugins/debugger/cdb/cdbexceptionutils.cpp
index 2c9b49d413..a68544f7bc 100644
--- a/src/plugins/debugger/cdb/cdbexceptionutils.cpp
+++ b/src/plugins/debugger/cdb/cdbexceptionutils.cpp
@@ -122,7 +122,7 @@ bool ExceptionBlocker::getExceptionParameters(CIDebugControl *ctrl, ULONG exCode
{
const HRESULT ihr = ctrl->GetExceptionFilterParameters(1, &exCode, 0, result);
if (FAILED(ihr)) {
- *errorMessage = msgComFailed("GetExceptionFilterParameters", ihr);
+ *errorMessage = CdbCore::msgComFailed("GetExceptionFilterParameters", ihr);
return false;
}
return true;
@@ -132,7 +132,7 @@ bool ExceptionBlocker::setExceptionParameters(CIDebugControl *ctrl, const DEBUG_
{
const HRESULT ihr = ctrl->SetExceptionFilterParameters(1, const_cast<DEBUG_EXCEPTION_FILTER_PARAMETERS*>(&p));
if (FAILED(ihr)) {
- *errorMessage = msgComFailed("GetExceptionFilterParameters", ihr);
+ *errorMessage = CdbCore::msgComFailed("GetExceptionFilterParameters", ihr);
return false;
}
return true;
diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp
index fd2653cc93..dbb12f7f0c 100644
--- a/src/plugins/debugger/cdb/cdbmodules.cpp
+++ b/src/plugins/debugger/cdb/cdbmodules.cpp
@@ -43,7 +43,7 @@ static inline bool getModuleCount(CIDebugSymbols *syms, ULONG *count, QString *e
ULONG loadedCount, unloadedCount;
const HRESULT hr = syms->GetNumberModules(&loadedCount, &unloadedCount);
if (FAILED(hr)) {
- *errorMessage= msgComFailed("GetNumberModules", hr);
+ *errorMessage= CdbCore::msgComFailed("GetNumberModules", hr);
return false;
}
*count = loadedCount + unloadedCount;
@@ -75,7 +75,7 @@ bool getModuleList(CIDebugSymbols *syms, QList<Module> *modules, QString *errorM
HRESULT hr = syms->GetModuleParameters(count, 0, 0u, parmPtr);
// E_INVALIDARG indicates 'Partial results' according to docu
if (FAILED(hr) && hr != E_INVALIDARG) {
- *errorMessage= msgComFailed("GetModuleParameters", hr);
+ *errorMessage= CdbCore::msgComFailed("GetModuleParameters", hr);
return false;
}
// fill array
@@ -91,7 +91,7 @@ bool getModuleList(CIDebugSymbols *syms, QList<Module> *modules, QString *errorM
module.endAddress = hexPrefix + QString::number((p.Base + p.Size), 16);
hr = syms->GetModuleNameStringWide(DEBUG_MODNAME_IMAGE, m, 0, wszBuf, MAX_PATH - 1, 0);
if (FAILED(hr) && hr != E_INVALIDARG) {
- *errorMessage= msgComFailed("GetModuleNameStringWide", hr);
+ *errorMessage= CdbCore::msgComFailed("GetModuleNameStringWide", hr);
return false;
}
module.moduleName = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
@@ -116,7 +116,7 @@ bool searchSymbols(CIDebugSymbols *syms, const QString &pattern,
return true;
}
if (FAILED(hr)) {
- *errorMessage= msgComFailed("StartSymbolMatchWide", hr);
+ *errorMessage= CdbCore::msgComFailed("StartSymbolMatchWide", hr);
return false;
}
WCHAR wszBuf[MAX_PATH];
diff --git a/src/plugins/debugger/cdb/cdboptions.cpp b/src/plugins/debugger/cdb/cdboptions.cpp
index 320feb74b4..e3ecd1b5b0 100644
--- a/src/plugins/debugger/cdb/cdboptions.cpp
+++ b/src/plugins/debugger/cdb/cdboptions.cpp
@@ -28,6 +28,7 @@
**************************************************************************/
#include "cdboptions.h"
+#include "coreengine.h"
#include <QtCore/QSettings>
#include <QtCore/QDir>
@@ -65,7 +66,7 @@ void CdbOptions::fromSettings(const QSettings *s)
const QString enabledKey = keyRoot + QLatin1String(enabledKeyC);
const bool firstTime = !s->contains(enabledKey);
if (firstTime) {
- enabled = autoDetectPath(&path);
+ enabled = CdbCore::CoreEngine::autoDetectPath(&path);
return;
}
enabled = s->value(enabledKey, false).toBool();
@@ -86,46 +87,6 @@ void CdbOptions::toSettings(QSettings *s) const
s->endGroup();
}
-bool CdbOptions::autoDetectPath(QString *outPath, QStringList *checkedDirectories /* = 0 */)
-{
- // Look for $ProgramFiles/"Debugging Tools For Windows <bit-idy>" and its
- // " (x86)", " (x64)" variations. Qt Creator needs 64/32 bit depending
- // on how it was built.
-#ifdef Q_OS_WIN64
- static const char *postFixes[] = {" (x64)", " 64-bit" };
-#else
- static const char *postFixes[] = { " (x86)", " (x32)" };
-#endif
-
- outPath->clear();
- const QByteArray programDirB = qgetenv("ProgramFiles");
- if (programDirB.isEmpty())
- return false;
-
- const QString programDir = QString::fromLocal8Bit(programDirB) + QDir::separator();
- const QString installDir = QLatin1String("Debugging Tools For Windows");
-
- QString path = programDir + installDir;
- if (checkedDirectories)
- checkedDirectories->push_back(path);
- if (QFileInfo(path).isDir()) {
- *outPath = QDir::toNativeSeparators(path);
- return true;
- }
- const int rootLength = path.size();
- for (int i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
- path.truncate(rootLength);
- path += QLatin1String(postFixes[i]);
- if (checkedDirectories)
- checkedDirectories->push_back(path);
- if (QFileInfo(path).isDir()) {
- *outPath = QDir::toNativeSeparators(path);
- return true;
- }
- }
- return false;
-}
-
unsigned CdbOptions::compare(const CdbOptions &rhs) const
{
unsigned rc = 0;
diff --git a/src/plugins/debugger/cdb/cdboptions.h b/src/plugins/debugger/cdb/cdboptions.h
index 14709d1f86..887b13c862 100644
--- a/src/plugins/debugger/cdb/cdboptions.h
+++ b/src/plugins/debugger/cdb/cdboptions.h
@@ -54,9 +54,6 @@ public:
SymbolOptionsChanged = 0x4 };
unsigned compare(const CdbOptions &s) const;
- // Locate the debugging tools
- static bool autoDetectPath(QString *path, QStringList *checkedDirectories = 0);
-
bool enabled;
QString path;
QStringList symbolPaths;
diff --git a/src/plugins/debugger/cdb/cdboptionspage.cpp b/src/plugins/debugger/cdb/cdboptionspage.cpp
index f8a97f4e67..583f6d7792 100644
--- a/src/plugins/debugger/cdb/cdboptionspage.cpp
+++ b/src/plugins/debugger/cdb/cdboptionspage.cpp
@@ -30,6 +30,7 @@
#include "cdboptionspage.h"
#include "cdboptions.h"
#include "debuggerconstants.h"
+#include "coreengine.h"
#include <coreplugin/icore.h>
@@ -102,7 +103,7 @@ void CdbOptionsPageWidget::autoDetect()
{
QString path;
QStringList checkedDirectories;
- const bool ok = CdbOptions::autoDetectPath(&path, &checkedDirectories);
+ const bool ok = CdbCore::CoreEngine::autoDetectPath(&path, &checkedDirectories);
m_ui.cdbPathGroupBox->setChecked(ok);
if (ok) {
m_ui.pathChooser->setPath(path);
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index 46e6aadefc..90d0e3e4e8 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -33,6 +33,7 @@
#include "cdbdumperhelper.h"
#include "debuggeractions.h"
#include "watchhandler.h"
+#include "coreengine.h"
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
index 8eb1998e71..bc9143032a 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -28,6 +28,7 @@
**************************************************************************/
#include "cdbstacktracecontext.h"
+#include "coreengine.h"
#include "cdbstackframecontext.h"
#include "cdbbreakpoint.h"
#include "cdbsymbolgroupcontext.h"
@@ -67,7 +68,7 @@ CdbStackTraceContext *CdbStackTraceContext::create(const QSharedPointer<CdbDumpe
const HRESULT hr = dumper->comInterfaces()->debugControl->GetStackTrace(0, 0, 0, ctx->m_cdbFrames, CdbStackTraceContext::maxFrames, &frameCount);
if (FAILED(hr)) {
delete ctx;
- *errorMessage = msgComFailed("GetStackTrace", hr);
+ *errorMessage = CdbCore::msgComFailed("GetStackTrace", hr);
return 0;
}
if (!ctx->init(frameCount, errorMessage)) {
@@ -189,20 +190,20 @@ CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString *
CIDebugSymbolGroup *sg = 0;
HRESULT hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &sg);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
+ *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr);
return 0;
}
hr = m_cif->debugSymbols->SetScope(0, m_cdbFrames + index, NULL, 0);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("SetScope", hr);
+ *errorMessage = CdbCore::msgComFailed("SetScope", hr);
sg->Release();
return 0;
}
// refresh with current frame
hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, sg, &sg);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
+ *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr);
sg->Release();
return 0;
}
@@ -247,7 +248,7 @@ static inline QString msgGetThreadStateFailed(unsigned long threadId, const QStr
// Determine information about thread. This changes the
// current thread to thread->id.
-static inline bool getStoppedThreadState(const CdbComInterfaces &cif,
+static inline bool getStoppedThreadState(const CdbCore::ComInterfaces &cif,
ThreadData *t,
QString *errorMessage)
{
@@ -255,13 +256,13 @@ static inline bool getStoppedThreadState(const CdbComInterfaces &cif,
ULONG currentThread;
HRESULT hr = cif.debugSystemObjects->GetCurrentThreadId(&currentThread);
if (FAILED(hr)) {
- *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("GetCurrentThreadId", hr));
+ *errorMessage = msgGetThreadStateFailed(t->id, CdbCore::msgComFailed("GetCurrentThreadId", hr));
return false;
}
if (currentThread != t->id) {
hr = cif.debugSystemObjects->SetCurrentThreadId(t->id);
if (FAILED(hr)) {
- *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("SetCurrentThreadId", hr));
+ *errorMessage = msgGetThreadStateFailed(t->id, CdbCore::msgComFailed("SetCurrentThreadId", hr));
return false;
}
}
@@ -271,7 +272,7 @@ static inline bool getStoppedThreadState(const CdbComInterfaces &cif,
DEBUG_STACK_FRAME frames[MaxFrames];
hr = cif.debugControl->GetStackTrace(0, 0, 0, frames, MaxFrames, &frameCount);
if (FAILED(hr)) {
- *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("GetStackTrace", hr));
+ *errorMessage = msgGetThreadStateFailed(t->id, CdbCore::msgComFailed("GetStackTrace", hr));
return false;
}
// Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is
@@ -307,7 +308,7 @@ static inline QString msgGetThreadsFailed(const QString &why)
return QString::fromLatin1("Unable to determine the thread information: %1").arg(why);
}
-bool CdbStackTraceContext::getThreads(const CdbComInterfaces &cif,
+bool CdbStackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
bool isStopped,
QList<ThreadData> *threads,
ULONG *currentThreadId,
@@ -318,7 +319,7 @@ bool CdbStackTraceContext::getThreads(const CdbComInterfaces &cif,
*currentThreadId = 0;
HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount);
if (FAILED(hr)) {
- *errorMessage= msgGetThreadsFailed(msgComFailed("GetNumberThreads", hr));
+ *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetNumberThreads", hr));
return false;
}
// Get ids and index of current
@@ -326,14 +327,14 @@ bool CdbStackTraceContext::getThreads(const CdbComInterfaces &cif,
return true;
hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId);
if (FAILED(hr)) {
- *errorMessage= msgGetThreadsFailed(msgComFailed("GetCurrentThreadId", hr));
+ *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetCurrentThreadId", hr));
return false;
}
QVector<ULONG> threadIds(threadCount);
hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0);
if (FAILED(hr)) {
- *errorMessage= msgGetThreadsFailed(msgComFailed("GetThreadIdsByIndex", hr));
+ *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetThreadIdsByIndex", hr));
return false;
}
for (ULONG i = 0; i < threadCount; i++) {
@@ -350,7 +351,7 @@ bool CdbStackTraceContext::getThreads(const CdbComInterfaces &cif,
if (isStopped && threads->back().id != *currentThreadId) {
hr = cif.debugSystemObjects->SetCurrentThreadId(*currentThreadId);
if (FAILED(hr)) {
- *errorMessage= msgGetThreadsFailed(msgComFailed("SetCurrentThreadId", hr));
+ *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("SetCurrentThreadId", hr));
return false;
}
}
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h
index ac9cb030b0..873fa7404a 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.h
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h
@@ -42,10 +42,13 @@ QT_BEGIN_NAMESPACE
class QTextStream;
QT_END_NAMESPACE
+namespace CdbCore {
+ struct ComInterfaces;
+}
+
namespace Debugger {
namespace Internal {
-struct CdbComInterfaces;
class CdbSymbolGroupContext;
class CdbStackFrameContext;
class CdbDumperHelper;
@@ -93,7 +96,7 @@ public:
// Retrieve information about threads. When stopped, add
// current stack frame.
- static bool getThreads(const CdbComInterfaces &cif,
+ static bool getThreads(const CdbCore::ComInterfaces &cif,
bool isStopped,
QList<ThreadData> *threads,
ULONG *currentThreadId,
@@ -104,7 +107,7 @@ private:
CIDebugSymbolGroup *createSymbolGroup(int index, QString *errorMessage);
const QSharedPointer<CdbDumperHelper> m_dumper;
- CdbComInterfaces *m_cif;
+ const CdbCore::ComInterfaces *m_cif;
DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
QVector <CdbStackFrameContext*> m_frameContexts;
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
index 480c9a7443..dc9cf01790 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
@@ -175,7 +175,7 @@ bool CdbSymbolGroupContext::init(QString *errorMessage)
ULONG count;
HRESULT hr = m_symbolGroup->GetNumberSymbols(&count);
if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetNumberSymbols", hr);
+ *errorMessage = CdbCore::msgComFailed("GetNumberSymbols", hr);
return false;
}
@@ -185,7 +185,8 @@ bool CdbSymbolGroupContext::init(QString *errorMessage)
hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters());
if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("In %1: %2 (%3 symbols)").arg(QLatin1String(Q_FUNC_INFO), msgComFailed("GetSymbolParameters", hr)).arg(count);
+ *errorMessage = QString::fromLatin1("In %1: %2 (%3 symbols)").arg(QLatin1String(Q_FUNC_INFO),
+ CdbCore::msgComFailed("GetSymbolParameters", hr)).arg(count);
return false;
}
populateINameIndexMap(m_prefix, DEBUG_ANY_ID, count);
@@ -355,7 +356,7 @@ bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long in
HRESULT hr = m_symbolGroup->ExpandSymbol(index, TRUE);
if (FAILED(hr)) {
- *errorMessage = msgExpandFailed(prefix, index, msgComFailed("ExpandSymbol", hr));
+ *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("ExpandSymbol", hr));
return false;
}
// Hopefully, this will never fail, else data structure will be foobar.
@@ -363,7 +364,7 @@ bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long in
ULONG newSize;
hr = m_symbolGroup->GetNumberSymbols(&newSize);
if (FAILED(hr)) {
- *errorMessage = msgExpandFailed(prefix, index, msgComFailed("GetNumberSymbols", hr));
+ *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetNumberSymbols", hr));
return false;
}
@@ -373,7 +374,7 @@ bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long in
hr = m_symbolGroup->GetSymbolParameters(0, newSize, symbolParameters());
if (FAILED(hr)) {
- *errorMessage = msgExpandFailed(prefix, index, msgComFailed("GetSymbolParameters", hr));
+ *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetSymbolParameters", hr));
return false;
}
// The new symbols are inserted after the parent symbol.
@@ -531,7 +532,7 @@ bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &val
const HRESULT hr = m_symbolGroup->WriteSymbolWide(index, reinterpret_cast<PCWSTR>(value.utf16()));
if (FAILED(hr)) {
*errorMessage = QString::fromLatin1("Unable to assign '%1' to '%2': %3").
- arg(value, iname, msgComFailed("WriteSymbolWide", hr));
+ arg(value, iname, CdbCore::msgComFailed("WriteSymbolWide", hr));
return false;
}
if (newValue)
@@ -539,126 +540,6 @@ bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &val
return true;
}
-// format an array of integers as "0x323, 0x2322, ..."
-template <class Integer>
-static QString formatArrayHelper(const Integer *array, int size, int base = 10)
-{
- QString rc;
- const QString hexPrefix = QLatin1String("0x");
- const QString separator = QLatin1String(", ");
- const bool hex = base == 16;
- for (int i = 0; i < size; i++) {
- if (i)
- rc += separator;
- if (hex)
- rc += hexPrefix;
- rc += QString::number(array[i], base);
- }
- return rc;
-}
-
-QString CdbSymbolGroupContext::hexFormatArray(const unsigned short *array, int size)
-{
- return formatArrayHelper(array, size, 16);
-}
-
-// Helper to format an integer with
-// a hex prefix in case base = 16
-template <class Integer>
- inline QString formatInteger(Integer value, int base)
-{
- QString rc;
- if (base == 16)
- rc = QLatin1String("0x");
- rc += QString::number(value, base);
- return rc;
-}
-
-QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, CIDebugControl *ctl,
- QString *qType,
- int integerBase)
-{
- switch (dv.Type) {
- case DEBUG_VALUE_INT8:
- if (qType)
- *qType = QLatin1String("char");
- return formatInteger(dv.I8, integerBase);
- case DEBUG_VALUE_INT16:
- if (qType)
- *qType = QLatin1String("short");
- return formatInteger(static_cast<short>(dv.I16), integerBase);
- case DEBUG_VALUE_INT32:
- if (qType)
- *qType = QLatin1String("long");
- return formatInteger(static_cast<long>(dv.I32), integerBase);
- case DEBUG_VALUE_INT64:
- if (qType)
- *qType = QLatin1String("long long");
- return formatInteger(static_cast<long long>(dv.I64), integerBase);
- case DEBUG_VALUE_FLOAT32:
- if (qType)
- *qType = QLatin1String("float");
- return QString::number(dv.F32);
- case DEBUG_VALUE_FLOAT64:
- if (qType)
- *qType = QLatin1String("double");
- return QString::number(dv.F64);
- case DEBUG_VALUE_FLOAT80:
- case DEBUG_VALUE_FLOAT128: { // Convert to double
- DEBUG_VALUE doubleValue;
- double d = 0.0;
- if (SUCCEEDED(ctl->CoerceValue(const_cast<DEBUG_VALUE*>(&dv), DEBUG_VALUE_FLOAT64, &doubleValue)))
- d = dv.F64;
- if (qType)
- *qType = QLatin1String(dv.Type == DEBUG_VALUE_FLOAT80 ? "80bit-float" : "128bit-float");
- return QString::number(d);
- }
- case DEBUG_VALUE_VECTOR64: {
- if (qType)
- *qType = QLatin1String("64bit-vector");
- QString rc = QLatin1String("bytes: ");
- rc += formatArrayHelper(dv.VI8, 8, integerBase);
- rc += QLatin1String(" long: ");
- rc += formatArrayHelper(dv.VI32, 2, integerBase);
- return rc;
- }
- case DEBUG_VALUE_VECTOR128: {
- if (qType)
- *qType = QLatin1String("128bit-vector");
- QString rc = QLatin1String("bytes: ");
- rc += formatArrayHelper(dv.VI8, 16, integerBase);
- rc += QLatin1String(" long long: ");
- rc += formatArrayHelper(dv.VI64, 2, integerBase);
- return rc;
- }
- }
- if (qType)
- *qType = QString::fromLatin1("Unknown type #%1:").arg(dv.Type);
- return formatArrayHelper(dv.RawBytes, 24, integerBase);
-}
-
-bool CdbSymbolGroupContext::debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value)
-{
- *value = 0;
- switch (dv.Type) {
- case DEBUG_VALUE_INT8:
- *value = dv.I8;
- return true;
- case DEBUG_VALUE_INT16:
- *value = static_cast<short>(dv.I16);
- return true;
- case DEBUG_VALUE_INT32:
- *value = static_cast<long>(dv.I32);
- return true;
- case DEBUG_VALUE_INT64:
- *value = static_cast<long long>(dv.I64);
- return true;
- default:
- break;
- }
- return false;
-}
-
/* The special type dumpers have an integer return code meaning:
* 0: ok
* 1: Dereferencing or retrieving memory failed, this is out of scope,
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
index 2db042423f..b99cbf1549 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
@@ -133,13 +133,6 @@ public:
inline bool isExpanded(unsigned long index) const { return symbolState(index) == ExpandedSymbol; }
inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; }
- // Helper to convert a DEBUG_VALUE structure to a string representation
- static QString debugValueToString(const DEBUG_VALUE &dv, CIDebugControl *ctl, QString *type = 0, int integerBase = 10);
- static bool debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value);
-
- // format an array of unsigned longs as "0x323, 0x2322, ..."
- static QString hexFormatArray(const unsigned short *array, int size);
-
// Dump
enum DumperResult { DumperOk, DumperError, DumperNotHandled };
DumperResult dump(CIDebugDataSpaces *ds, WatchData *wd);
diff --git a/src/plugins/debugger/cdb/coreengine.cpp b/src/plugins/debugger/cdb/coreengine.cpp
new file mode 100644
index 0000000000..77ca81e8cf
--- /dev/null
+++ b/src/plugins/debugger/cdb/coreengine.cpp
@@ -0,0 +1,944 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "coreengine.h"
+#include "debugeventcallbackbase.h"
+#include "debugoutputbase.h"
+
+#include <utils/winutils.h>
+#include <utils/abstractprocess.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QLibrary>
+#include <QtCore/QDebug>
+
+#define DBGHELP_TRANSLATE_TCHAR
+#include <inc/Dbghelp.h>
+
+static const char *dbgHelpDllC = "dbghelp";
+static const char *dbgEngineDllC = "dbgeng";
+static const char *debugCreateFuncC = "DebugCreate";
+
+enum { debug = 0 };
+
+static inline QString msgLibLoadFailed(const QString &lib, const QString &why)
+{
+ return QCoreApplication::translate("Debugger::Cdb",
+ "Unable to load the debugger engine library '%1': %2").
+ arg(lib, why);
+}
+
+static inline ULONG getInterruptTimeOutSecs(CIDebugControl *ctl)
+{
+ ULONG rc = 0;
+ ctl->GetInterruptTimeout(&rc);
+ return rc;
+}
+
+namespace CdbCore {
+
+QString msgDebugEngineComResult(HRESULT hr)
+{
+ switch (hr) {
+ case S_OK:
+ return QLatin1String("S_OK");
+ case S_FALSE:
+ return QLatin1String("S_FALSE");
+ case E_FAIL:
+ break;
+ case E_INVALIDARG:
+ return QLatin1String("E_INVALIDARG");
+ case E_NOINTERFACE:
+ return QLatin1String("E_NOINTERFACE");
+ case E_OUTOFMEMORY:
+ return QLatin1String("E_OUTOFMEMORY");
+ case E_UNEXPECTED:
+ return QLatin1String("E_UNEXPECTED");
+ case E_NOTIMPL:
+ return QLatin1String("E_NOTIMPL");
+ }
+ if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
+ return QLatin1String("ERROR_ACCESS_DENIED");;
+ if (hr == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
+ return QLatin1String("STATUS_CONTROL_C_EXIT");
+ return QLatin1String("E_FAIL ") + Utils::winErrorMessage(HRESULT_CODE(hr));
+}
+
+QString msgComFailed(const char *func, HRESULT hr)
+{
+ return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
+}
+
+QString msgDebuggerCommandFailed(const QString &command, HRESULT hr)
+{
+ return QString::fromLatin1("Unable to execute '%1': %2").arg(command, msgDebugEngineComResult(hr));
+}
+
+const char *msgExecutionStatusString(ULONG executionStatus)
+{
+ switch (executionStatus) {
+ case DEBUG_STATUS_NO_CHANGE:
+ return "DEBUG_STATUS_NO_CHANGE";
+ case DEBUG_STATUS_GO:
+ return "DEBUG_STATUS_GO";
+ case DEBUG_STATUS_GO_HANDLED:
+ return "DEBUG_STATUS_GO_HANDLED";
+ case DEBUG_STATUS_GO_NOT_HANDLED:
+ return "DEBUG_STATUS_GO_NOT_HANDLED";
+ case DEBUG_STATUS_STEP_OVER:
+ return "DEBUG_STATUS_STEP_OVER";
+ case DEBUG_STATUS_STEP_INTO:
+ return "DEBUG_STATUS_STEP_INTO";
+ case DEBUG_STATUS_BREAK:
+ return "DEBUG_STATUS_BREAK";
+ case DEBUG_STATUS_NO_DEBUGGEE:
+ return "DEBUG_STATUS_NO_DEBUGGEE";
+ case DEBUG_STATUS_STEP_BRANCH:
+ return "DEBUG_STATUS_STEP_BRANCH";
+ case DEBUG_STATUS_IGNORE_EVENT:
+ return "DEBUG_STATUS_IGNORE_EVENT";
+ case DEBUG_STATUS_RESTART_REQUESTED:
+ return "DEBUG_STATUS_RESTART_REQUESTED";
+ case DEBUG_STATUS_REVERSE_GO:
+ return "DEBUG_STATUS_REVERSE_GO";
+ case DEBUG_STATUS_REVERSE_STEP_BRANCH:
+ return "DEBUG_STATUS_REVERSE_STEP_BRANCH";
+ case DEBUG_STATUS_REVERSE_STEP_OVER:
+ return "DEBUG_STATUS_REVERSE_STEP_OVER";
+ case DEBUG_STATUS_REVERSE_STEP_INTO:
+ return "DEBUG_STATUS_REVERSE_STEP_INTO";
+ default:
+ break;
+ }
+ return "<Unknown execution status>";
+}
+
+// ComInterfaces
+ComInterfaces::ComInterfaces() :
+ debugClient(0),
+ debugControl(0),
+ debugSystemObjects(0),
+ debugSymbols(0),
+ debugRegisters(0),
+ debugDataSpaces(0)
+{
+}
+
+// Thin wrapper around the 'DBEng' debugger engine shared library
+// which is loaded at runtime.
+
+class DebuggerEngineLibrary
+{
+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;
+};
+
+// --------- DebuggerEngineLibrary
+DebuggerEngineLibrary::DebuggerEngineLibrary() :
+ m_debugCreate(0)
+{
+}
+
+// Build a lib name as "Path\x.dll"
+static inline QString libPath(const QString &libName, const QString &path = QString())
+{
+ QString rc = path;
+ if (!rc.isEmpty())
+ rc += QDir::separator();
+ rc += libName;
+ rc += QLatin1String(".dll");
+ return rc;
+}
+
+bool DebuggerEngineLibrary::init(const QString &path,
+ QString *dbgEngDLL,
+ QString *errorMessage)
+{
+ // Load the dependent help lib first
+ const QString helpLibPath = libPath(QLatin1String(dbgHelpDllC), path);
+ QLibrary helpLib(helpLibPath, 0);
+ if (!helpLib.isLoaded() && !helpLib.load()) {
+ *errorMessage = msgLibLoadFailed(helpLibPath, helpLib.errorString());
+ return false;
+ }
+ // Load dbgeng lib
+ const QString engineLibPath = libPath(QLatin1String(dbgEngineDllC), path);
+ QLibrary lib(engineLibPath, 0);
+ if (!lib.isLoaded() && !lib.load()) {
+ *errorMessage = msgLibLoadFailed(engineLibPath, lib.errorString());
+ return false;
+ }
+ *dbgEngDLL = engineLibPath;
+ // Locate symbols
+ void *createFunc = lib.resolve(debugCreateFuncC);
+ if (!createFunc) {
+ *errorMessage = QCoreApplication::translate("Debugger::Cdb", "Unable to resolve '%1' in the debugger engine library '%2'").
+ arg(QLatin1String(debugCreateFuncC), QLatin1String(dbgEngineDllC));
+ return false;
+ }
+ m_debugCreate = static_cast<DebugCreateFunction>(createFunc);
+ return true;
+}
+
+// ------ Engine
+CoreEngine::CoreEngine(QObject *parent) :
+ QObject(parent),
+ m_watchTimer(-1)
+{
+}
+
+CoreEngine::~CoreEngine()
+{
+
+ if (m_cif.debugClient) {
+ m_cif.debugClient->SetOutputCallbacksWide(0);
+ m_cif.debugClient->SetEventCallbacksWide(0);
+ m_cif.debugClient->Release();
+ }
+ if (m_cif.debugControl)
+ m_cif.debugControl->Release();
+ if (m_cif.debugSystemObjects)
+ m_cif.debugSystemObjects->Release();
+ if (m_cif.debugSymbols)
+ m_cif.debugSymbols->Release();
+ if (m_cif.debugRegisters)
+ m_cif.debugRegisters->Release();
+ if (m_cif.debugDataSpaces)
+ m_cif.debugDataSpaces->Release();
+}
+
+bool CoreEngine::init(const QString &dllEnginePath, QString *errorMessage)
+{
+ enum { bufLen = 10240 };
+ // Load the DLL
+ DebuggerEngineLibrary lib;
+ if (!lib.init(dllEnginePath, &m_dbengDLL, errorMessage))
+ return false;
+ // Initialize the COM interfaces
+ HRESULT hr;
+ hr = lib.debugCreate( __uuidof(IDebugClient5), reinterpret_cast<void**>(&m_cif.debugClient));
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Creation of IDebugClient5 failed: %1").arg(msgDebugEngineComResult(hr));
+ return false;
+ }
+
+ hr = lib.debugCreate( __uuidof(IDebugControl4), reinterpret_cast<void**>(&m_cif.debugControl));
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Creation of IDebugControl4 failed: %1").arg(msgDebugEngineComResult(hr));
+ return false;
+ }
+
+ hr = lib.debugCreate( __uuidof(IDebugSystemObjects4), reinterpret_cast<void**>(&m_cif.debugSystemObjects));
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Creation of IDebugSystemObjects4 failed: %1").arg(msgDebugEngineComResult(hr));
+ return false;
+ }
+
+ hr = lib.debugCreate( __uuidof(IDebugSymbols3), reinterpret_cast<void**>(&m_cif.debugSymbols));
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Creation of IDebugSymbols3 failed: %1").arg(msgDebugEngineComResult(hr));
+ return false;
+ }
+
+ WCHAR buf[bufLen];
+ hr = m_cif.debugSymbols->GetImagePathWide(buf, bufLen, 0);
+ if (FAILED(hr)) {
+ *errorMessage = msgComFailed("GetImagePathWide", hr);
+ return false;
+ }
+ m_baseImagePath = QString::fromUtf16(buf);
+
+ hr = lib.debugCreate( __uuidof(IDebugRegisters2), reinterpret_cast<void**>(&m_cif.debugRegisters));
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Creation of IDebugRegisters2 failed: %1").arg(msgDebugEngineComResult(hr));
+ return false;
+ }
+
+ hr = lib.debugCreate( __uuidof(IDebugDataSpaces4), reinterpret_cast<void**>(&m_cif.debugDataSpaces));
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Creation of IDebugDataSpaces4 failed: %1").arg(msgDebugEngineComResult(hr));
+ return false;
+ }
+
+ if (debug)
+ qDebug() << QString::fromLatin1("CDB Initialization succeeded, interrupt time out %1s.").arg(getInterruptTimeOutSecs(m_cif.debugControl));
+ return true;
+}
+
+CoreEngine::DebugOutputBasePtr
+ CoreEngine::setDebugOutput(const DebugOutputBasePtr &o)
+{
+ const CoreEngine::DebugOutputBasePtr old = m_debugOutput;
+ m_debugOutput = o;
+ m_cif.debugClient->SetOutputCallbacksWide(m_debugOutput.data());
+ return old;
+}
+
+CoreEngine::DebugEventCallbackBasePtr
+ CoreEngine::setDebugEventCallback(const DebugEventCallbackBasePtr &e)
+{
+ const CoreEngine::DebugEventCallbackBasePtr old = m_debugEventCallback;
+ m_debugEventCallback = e;
+ m_cif.debugClient->SetEventCallbacksWide(m_debugEventCallback.data());
+ return old;
+}
+
+void CoreEngine::startWatchTimer()
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO;
+
+ if (m_watchTimer == -1)
+ m_watchTimer = startTimer(0);
+}
+
+void CoreEngine::killWatchTimer()
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO;
+
+ if (m_watchTimer != -1) {
+ killTimer(m_watchTimer);
+ m_watchTimer = -1;
+ }
+}
+
+HRESULT CoreEngine::waitForEvent(int timeOutMS)
+{
+ const HRESULT hr = m_cif.debugControl->WaitForEvent(0, timeOutMS);
+ if (debug)
+ if (debug > 1 || hr != S_FALSE)
+ qDebug() << Q_FUNC_INFO << "WaitForEvent" << timeOutMS << msgDebugEngineComResult(hr);
+ return hr;
+}
+
+void CoreEngine::timerEvent(QTimerEvent* te)
+{
+ // Fetch away the debug events and notify if debuggee
+ // stops. Note that IDebugEventCallback does not
+ // cover all cases of a debuggee stopping execution
+ // (such as step over,etc).
+ if (te->timerId() != m_watchTimer)
+ return;
+
+ switch (waitForEvent(1)) {
+ case S_OK:
+ killWatchTimer();
+ emit watchTimerDebugEvent();
+ break;
+ case S_FALSE:
+ case E_PENDING:
+ case E_FAIL:
+ break;
+ case E_UNEXPECTED: // Occurs on ExitProcess.
+ killWatchTimer();
+ break;
+ }
+}
+
+bool CoreEngine::startDebuggerWithExecutable(const QString &workingDirectory,
+ const QString &filename,
+ const QStringList &args,
+ const QStringList &envList,
+ bool verboseSymbolLoading,
+ QString *errorMessage)
+{
+ DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
+ memset(&dbgopts, 0, sizeof(dbgopts));
+ dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
+
+ // Set image path
+ const QFileInfo fi(filename);
+ QString imagePath = QDir::toNativeSeparators(fi.absolutePath());
+ if (!m_baseImagePath.isEmpty()) {
+ imagePath += QLatin1Char(';');
+ imagePath += m_baseImagePath;
+ }
+ HRESULT hr = m_cif.debugSymbols->SetImagePathWide(reinterpret_cast<PCWSTR>(imagePath.utf16()));
+ if (FAILED(hr)) {
+ *errorMessage = tr("Unable to set the image path to %1: %2").arg(imagePath, msgComFailed("SetImagePathWide", hr));
+ return false;
+ }
+
+ if (debug)
+ qDebug() << Q_FUNC_INFO <<'\n' << filename << imagePath;
+
+ ULONG symbolOptions = SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS;
+ if (verboseSymbolLoading)
+ symbolOptions |= SYMOPT_DEBUG;
+ m_cif.debugSymbols->SetSymbolOptions(symbolOptions);
+
+ const QString cmd = Utils::AbstractProcess::createWinCommandline(filename, args);
+ if (debug)
+ qDebug() << "Starting " << cmd;
+ PCWSTR env = 0;
+ QByteArray envData;
+ if (!envList.empty()) {
+ envData = Utils::AbstractProcess::createWinEnvironment(Utils::AbstractProcess::fixWinEnvironment(envList));
+ env = reinterpret_cast<PCWSTR>(envData.data());
+ }
+ // The working directory cannot be empty.
+ PCWSTR workingDirC = 0;
+ const QString workingDirN = workingDirectory.isEmpty() ? QString() : QDir::toNativeSeparators(workingDirectory);
+ if (!workingDirN.isEmpty())
+ workingDirC = workingDirN.utf16();
+ hr = m_cif.debugClient->CreateProcess2Wide(NULL,
+ reinterpret_cast<PWSTR>(const_cast<ushort *>(cmd.utf16())),
+ &dbgopts, sizeof(dbgopts),
+ workingDirC, env);
+ if (FAILED(hr)) {
+ *errorMessage = tr("Unable to create a process '%1': %2").arg(cmd, msgDebugEngineComResult(hr));
+ return false;
+ }
+ return true;
+}
+
+bool CoreEngine::startAttachDebugger(qint64 pid,
+ bool suppressInitialBreakPoint,
+ QString *errorMessage)
+{
+ // Need to attrach invasively, otherwise, no notification signals
+ // for for CreateProcess/ExitProcess occur.
+ // Initial breakpoint occur:
+ // 1) Desired: When attaching to a crashed process
+ // 2) Undesired: When starting up a console process, in conjunction
+ // with the 32bit Wow-engine
+ // As of version 6.11, the flag only affects 1). 2) Still needs to be suppressed
+ // by lookup at the state of the application (startup trap). However,
+ // there is no startup trap when attaching to a process that has been
+ // running for a while. (see notifyException).
+ ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
+ if (suppressInitialBreakPoint)
+ flags |= DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
+ const HRESULT hr = m_cif.debugClient->AttachProcess(NULL, pid, flags);
+ if (debug)
+ qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr;
+ if (FAILED(hr)) {
+ *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
+ return false;
+ }
+ return true;
+}
+
+static inline QString pathString(const QStringList &s)
+{ return s.join(QString(QLatin1Char(';'))); }
+
+QStringList CoreEngine::sourcePaths() const
+{
+ WCHAR wszBuf[MAX_PATH];
+ if (SUCCEEDED(m_cif.debugSymbols->GetSourcePathWide(wszBuf, MAX_PATH, 0)))
+ return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';'));
+ return QStringList();
+}
+
+bool CoreEngine::setSourcePaths(const QStringList &s, QString *errorMessage)
+{
+ const HRESULT hr = m_cif.debugSymbols->SetSourcePathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16()));
+ if (FAILED(hr)) {
+ if (errorMessage)
+ *errorMessage = msgComFailed("SetSourcePathWide", hr);
+ return false;
+ }
+ return true;
+}
+
+QStringList CoreEngine::symbolPaths() const
+{
+ WCHAR wszBuf[MAX_PATH];
+ if (SUCCEEDED(m_cif.debugSymbols->GetSymbolPathWide(wszBuf, MAX_PATH, 0)))
+ return QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)).split(QLatin1Char(';'));
+ return QStringList();
+}
+
+bool CoreEngine::setSymbolPaths(const QStringList &s, QString *errorMessage)
+{
+ const HRESULT hr = m_cif.debugSymbols->SetSymbolPathWide(reinterpret_cast<PCWSTR>(pathString(s).utf16()));
+ if (FAILED(hr)) {
+ if (errorMessage)
+ *errorMessage = msgComFailed("SetSymbolPathWide", hr);
+ return false;
+ }
+ return true;
+}
+
+bool CoreEngine::executeDebuggerCommand(const QString &command, QString *errorMessage)
+{
+ // output to all clients, else we do not see anything
+ const HRESULT hr = m_cif.debugControl->ExecuteWide(DEBUG_OUTCTL_ALL_CLIENTS, reinterpret_cast<PCWSTR>(command.utf16()), 0);
+ if (debug)
+ qDebug() << "executeDebuggerCommand" << command << SUCCEEDED(hr);
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Unable to execute '%1': %2").
+ arg(command, msgDebugEngineComResult(hr));
+ return false;
+ }
+ return true;
+}
+
+// Those should not fail
+CoreEngine::ExpressionSyntax CoreEngine::expressionSyntax() const
+{
+ ULONG expressionSyntax = DEBUG_EXPR_MASM;
+ const HRESULT hr = m_cif.debugControl->GetExpressionSyntax(&expressionSyntax);
+ if (FAILED(hr))
+ qWarning("Unable to retrieve expression syntax: %s", qPrintable(msgComFailed("GetExpressionSyntax", hr)));
+ return expressionSyntax == DEBUG_EXPR_MASM ? AssemblerExpressionSyntax : CppExpressionSyntax;
+}
+
+CoreEngine::ExpressionSyntax CoreEngine::setExpressionSyntax(ExpressionSyntax es)
+{
+ const ExpressionSyntax old = expressionSyntax();
+ if (old != es) {
+ if (debug)
+ qDebug() << "Setting expression syntax" << es;
+ const HRESULT hr = m_cif.debugControl->SetExpressionSyntax(es == AssemblerExpressionSyntax ? DEBUG_EXPR_MASM : DEBUG_EXPR_CPLUSPLUS);
+ if (FAILED(hr))
+ qWarning("Unable to set expression syntax: %s", qPrintable(msgComFailed("SetExpressionSyntax", hr)));
+ }
+ return old;
+}
+
+CoreEngine::CodeLevel CoreEngine::codeLevel() const
+{
+ ULONG currentCodeLevel = DEBUG_LEVEL_ASSEMBLY;
+ HRESULT hr = m_cif.debugControl->GetCodeLevel(&currentCodeLevel);
+ if (FAILED(hr)) {
+ qWarning("Cannot determine code level: %s", qPrintable(msgComFailed("GetCodeLevel", hr)));
+ }
+ return currentCodeLevel == DEBUG_LEVEL_ASSEMBLY ? CodeLevelAssembly : CodeLevelSource;
+}
+
+CoreEngine::CodeLevel CoreEngine::setCodeLevel(CodeLevel cl)
+{
+ const CodeLevel old = codeLevel();
+ if (old != cl) {
+ if (debug)
+ qDebug() << "Setting code level" << cl;
+ const HRESULT hr = m_cif.debugControl->SetCodeLevel(cl == CodeLevelAssembly ? DEBUG_LEVEL_ASSEMBLY : DEBUG_LEVEL_SOURCE);
+ if (FAILED(hr))
+ qWarning("Unable to set code level: %s", qPrintable(msgComFailed("SetCodeLevel", hr)));
+ }
+ return old;
+}
+
+bool CoreEngine::evaluateExpression(const QString &expression,
+ QString *value,
+ QString *type,
+ QString *errorMessage)
+{
+ DEBUG_VALUE debugValue;
+ if (!evaluateExpression(expression, &debugValue, errorMessage))
+ return false;
+ *value = debugValueToString(debugValue, type, 10, m_cif.debugControl);
+ return true;
+}
+
+bool CoreEngine::evaluateExpression(const QString &expression,
+ DEBUG_VALUE *debugValue,
+ QString *errorMessage)
+{
+ if (debug > 1)
+ qDebug() << Q_FUNC_INFO << expression;
+
+ memset(debugValue, 0, sizeof(DEBUG_VALUE));
+ // Use CPP syntax, original syntax must be restored, else setting breakpoints will fail.
+ SyntaxSetter syntaxSetter(this, CppExpressionSyntax);
+ Q_UNUSED(syntaxSetter)
+ ULONG errorPosition = 0;
+ const HRESULT hr = m_cif.debugControl->EvaluateWide(reinterpret_cast<PCWSTR>(expression.utf16()),
+ DEBUG_VALUE_INVALID, debugValue,
+ &errorPosition);
+ if (FAILED(hr)) {
+ if (HRESULT_CODE(hr) == 517) {
+ *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Expression out of scope.").
+ arg(expression);
+ } else {
+ *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Error at %2: %3").
+ arg(expression).arg(errorPosition).arg(msgDebugEngineComResult(hr));
+ }
+ return false;
+ }
+ return true;
+}
+
+ULONG CoreEngine::executionStatus() const
+{
+ ULONG ex = DEBUG_STATUS_NO_CHANGE;
+ const HRESULT hr = m_cif.debugControl->GetExecutionStatus(&ex);
+ if (FAILED(hr))
+ qWarning("Cannot determine execution status: %s", qPrintable(msgComFailed("GetExecutionStatus", hr)));
+ return ex;
+}
+
+bool CoreEngine::setExecutionStatus(ULONG ex, QString *errorMessage)
+{
+ const HRESULT hr = m_cif.debugControl->SetExecutionStatus(ex);
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Cannot set execution status to %1: %2")
+ .arg(QLatin1String(msgExecutionStatusString(ex)), msgComFailed("SetExecutionStatus", hr));
+ return false;
+ }
+ return true;
+}
+
+static inline void appendError(const QString &what, QString *appendableErrorMessage)
+{
+ if (!appendableErrorMessage->isEmpty())
+ appendableErrorMessage->append(QLatin1Char('\n'));
+ appendableErrorMessage->append(what);
+}
+
+bool CoreEngine::detachCurrentProcess(QString *appendableErrorMessage)
+{
+ const HRESULT hr = m_cif.debugClient->DetachCurrentProcess();
+ if (FAILED(hr)) {
+ appendError(msgComFailed("DetachCurrentProcess", hr), appendableErrorMessage);
+ return false;
+ }
+ return true;
+}
+
+bool CoreEngine::terminateCurrentProcess(QString *appendableErrorMessage)
+{
+ const HRESULT hr = m_cif.debugClient->TerminateCurrentProcess();
+ if (FAILED(hr)) {
+ appendError(msgComFailed("TerminateCurrentProcess", hr), appendableErrorMessage);
+ return false;
+ }
+ return true;
+}
+
+bool CoreEngine::terminateProcesses(QString *appendableErrorMessage)
+{
+ const HRESULT hr = m_cif.debugClient->TerminateProcesses();
+ if (FAILED(hr)) {
+ appendError(msgComFailed("TerminateProcesses", hr), appendableErrorMessage);
+ return false;
+ }
+ return true;
+}
+
+bool CoreEngine::endSession(QString *appendableErrorMessage)
+{
+ const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE);
+ if (FAILED(hr)) {
+ appendError(msgComFailed("EndSession", hr), appendableErrorMessage);
+ return false;
+ }
+ return true;
+}
+
+bool CoreEngine::allocDebuggeeMemory(int size, ULONG64 *address, QString *errorMessage)
+{
+ *address = 0;
+ const QString allocCmd = QLatin1String(".dvalloc ") + QString::number(size);
+
+ QSharedPointer<StringOutputHandler> outputHandler(new StringOutputHandler);
+ OutputRedirector redir(this, outputHandler);
+ Q_UNUSED(redir)
+ if (!executeDebuggerCommand(allocCmd, errorMessage))
+ return false;
+ // "Allocated 1000 bytes starting at 003a0000" .. hopefully never localized
+ bool ok = false;
+ const QString output = outputHandler->result();
+ const int lastBlank = output.lastIndexOf(QLatin1Char(' '));
+ if (lastBlank != -1) {
+ const qint64 addri = output.mid(lastBlank + 1).toLongLong(&ok, 16);
+ if (ok)
+ *address = addri;
+ }
+ if (debug > 1)
+ qDebug() << Q_FUNC_INFO << '\n' << output << *address << ok;
+ if (!ok) {
+ *errorMessage = QString::fromLatin1("Failed to parse output '%1'").arg(output);
+ return false;
+ }
+ return true;
+}
+
+// Alloc an AscII string in debuggee
+bool CoreEngine::createDebuggeeAscIIString(const QString &s,
+ ULONG64 *address,
+ QString *errorMessage)
+{
+ QByteArray sAsciiData = s.toLocal8Bit();
+ sAsciiData += '\0';
+ if (!allocDebuggeeMemory(sAsciiData.size(), address, errorMessage))
+ return false;
+ const HRESULT hr = m_cif.debugDataSpaces->WriteVirtual(*address, sAsciiData.data(), sAsciiData.size(), 0);
+ if (FAILED(hr)) {
+ *errorMessage= msgComFailed("WriteVirtual", hr);
+ return false;
+ }
+ return true;
+}
+
+// Write to debuggee memory in chunks
+bool CoreEngine::writeToDebuggee(const QByteArray &buffer, quint64 address, QString *errorMessage)
+{
+ char *ptr = const_cast<char*>(buffer.data());
+ ULONG bytesToWrite = buffer.size();
+ while (bytesToWrite > 0) {
+ ULONG bytesWritten = 0;
+ const HRESULT hr = m_cif.debugDataSpaces->WriteVirtual(address, ptr, bytesToWrite, &bytesWritten);
+ if (FAILED(hr)) {
+ *errorMessage = msgComFailed("WriteVirtual", hr);
+ return false;
+ }
+ bytesToWrite -= bytesWritten;
+ ptr += bytesWritten;
+ }
+ return true;
+}
+
+bool CoreEngine::dissassemble(ULONG64 offset,
+ unsigned long beforeLines,
+ unsigned long afterLines,
+ QString *target,
+ QString *errorMessage)
+{
+ 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.
+ QSharedPointer<StringOutputHandler> outputHandler(new StringOutputHandler);
+ OutputRedirector redir(this, outputHandler);
+ // For some reason, we need to output to "all clients"
+ const HRESULT hr = m_cif.debugControl->OutputDisassemblyLines(DEBUG_OUTCTL_ALL_CLIENTS,
+ beforeLines, beforeLines + afterLines,
+ offset, flags, 0, 0, 0, 0);
+ if (FAILED(hr)) {
+ *errorMessage= QString::fromLatin1("Unable to dissamble at 0x%1: %2").
+ arg(offset, 0, 16).arg(msgComFailed("OutputDisassemblyLines", hr));
+ return false;
+ }
+ *target = outputHandler->result();
+ return true;
+}
+
+bool CoreEngine::autoDetectPath(QString *outPath,
+ QStringList *checkedDirectories /* = 0 */)
+{
+ // Look for $ProgramFiles/"Debugging Tools For Windows <bit-idy>" and its
+ // " (x86)", " (x64)" variations. Qt Creator needs 64/32 bit depending
+ // on how it was built.
+#ifdef Q_OS_WIN64
+ static const char *postFixes[] = {" (x64)", " 64-bit" };
+#else
+ static const char *postFixes[] = { " (x86)", " (x32)" };
+#endif
+
+ outPath->clear();
+ const QByteArray programDirB = qgetenv("ProgramFiles");
+ if (programDirB.isEmpty())
+ return false;
+
+ const QString programDir = QString::fromLocal8Bit(programDirB) + QDir::separator();
+ const QString installDir = QLatin1String("Debugging Tools For Windows");
+
+ QString path = programDir + installDir;
+ if (checkedDirectories)
+ checkedDirectories->push_back(path);
+ if (QFileInfo(path).isDir()) {
+ *outPath = QDir::toNativeSeparators(path);
+ return true;
+ }
+ const int rootLength = path.size();
+ for (int i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
+ path.truncate(rootLength);
+ path += QLatin1String(postFixes[i]);
+ if (checkedDirectories)
+ checkedDirectories->push_back(path);
+ if (QFileInfo(path).isDir()) {
+ *outPath = QDir::toNativeSeparators(path);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CoreEngine::debugBreakProcess(HANDLE hProcess, QString *errorMessage)
+{
+ const bool rc = DebugBreakProcess(hProcess);
+ if (!rc)
+ *errorMessage = QString::fromLatin1("DebugBreakProcess failed: %1").arg(Utils::winErrorMessage(GetLastError()));
+ return rc;
+}
+
+bool CoreEngine::setInterrupt(QString *errorMessage)
+{
+ const HRESULT hr = interfaces().debugControl->SetInterrupt(DEBUG_INTERRUPT_ACTIVE|DEBUG_INTERRUPT_EXIT);
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("Unable to interrupt debuggee after %1s: %2").
+ arg(getInterruptTimeOutSecs(interfaces().debugControl)).arg(msgComFailed("SetInterrupt", hr));
+ return false;
+ }
+ return true;
+}
+
+// ------------- DEBUG_VALUE formatting helpers
+
+// format an array of integers as "0x323, 0x2322, ..."
+template <class Integer>
+static QString formatArrayHelper(const Integer *array, int size, int base = 10)
+{
+ QString rc;
+ const QString hexPrefix = QLatin1String("0x");
+ const QString separator = QLatin1String(", ");
+ const bool hex = base == 16;
+ for (int i = 0; i < size; i++) {
+ if (i)
+ rc += separator;
+ if (hex)
+ rc += hexPrefix;
+ rc += QString::number(array[i], base);
+ }
+ return rc;
+}
+
+QString hexFormatArray(const unsigned short *array, int size)
+{
+ return formatArrayHelper(array, size, 16);
+}
+
+// Helper to format an integer with
+// a hex prefix in case base = 16
+template <class Integer>
+ inline QString formatInteger(Integer value, int base)
+{
+ QString rc;
+ if (base == 16)
+ rc = QLatin1String("0x");
+ rc += QString::number(value, base);
+ return rc;
+}
+
+QString debugValueToString(const DEBUG_VALUE &dv,
+ QString *qType /* =0 */,
+ int integerBase,
+ CIDebugControl *ctl /* =0 */)
+{
+ switch (dv.Type) {
+ case DEBUG_VALUE_INT8:
+ if (qType)
+ *qType = QLatin1String("char");
+ return formatInteger(dv.I8, integerBase);
+ case DEBUG_VALUE_INT16:
+ if (qType)
+ *qType = QLatin1String("short");
+ return formatInteger(static_cast<short>(dv.I16), integerBase);
+ case DEBUG_VALUE_INT32:
+ if (qType)
+ *qType = QLatin1String("long");
+ return formatInteger(static_cast<long>(dv.I32), integerBase);
+ case DEBUG_VALUE_INT64:
+ if (qType)
+ *qType = QLatin1String("long long");
+ return formatInteger(static_cast<long long>(dv.I64), integerBase);
+ case DEBUG_VALUE_FLOAT32:
+ if (qType)
+ *qType = QLatin1String("float");
+ return QString::number(dv.F32);
+ case DEBUG_VALUE_FLOAT64:
+ if (qType)
+ *qType = QLatin1String("double");
+ return QString::number(dv.F64);
+ case DEBUG_VALUE_FLOAT80:
+ case DEBUG_VALUE_FLOAT128: { // Convert to double
+ DEBUG_VALUE doubleValue;
+ double d = 0.0;
+ if (ctl && SUCCEEDED(ctl->CoerceValue(const_cast<DEBUG_VALUE*>(&dv), DEBUG_VALUE_FLOAT64, &doubleValue))) {
+ d = dv.F64;
+ } else {
+ qWarning("Unable to convert DEBUG_VALUE_FLOAT80/DEBUG_VALUE_FLOAT128 values");
+ }
+ if (qType)
+ *qType = QLatin1String(dv.Type == DEBUG_VALUE_FLOAT80 ? "80bit-float" : "128bit-float");
+ return QString::number(d);
+ }
+ case DEBUG_VALUE_VECTOR64: {
+ if (qType)
+ *qType = QLatin1String("64bit-vector");
+ QString rc = QLatin1String("bytes: ");
+ rc += formatArrayHelper(dv.VI8, 8, integerBase);
+ rc += QLatin1String(" long: ");
+ rc += formatArrayHelper(dv.VI32, 2, integerBase);
+ return rc;
+ }
+ case DEBUG_VALUE_VECTOR128: {
+ if (qType)
+ *qType = QLatin1String("128bit-vector");
+ QString rc = QLatin1String("bytes: ");
+ rc += formatArrayHelper(dv.VI8, 16, integerBase);
+ rc += QLatin1String(" long long: ");
+ rc += formatArrayHelper(dv.VI64, 2, integerBase);
+ return rc;
+ }
+ }
+ if (qType)
+ *qType = QString::fromLatin1("Unknown type #%1:").arg(dv.Type);
+ return formatArrayHelper(dv.RawBytes, 24, integerBase);
+}
+
+bool debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value)
+{
+ *value = 0;
+ switch (dv.Type) {
+ case DEBUG_VALUE_INT8:
+ *value = dv.I8;
+ return true;
+ case DEBUG_VALUE_INT16:
+ *value = static_cast<short>(dv.I16);
+ return true;
+ case DEBUG_VALUE_INT32:
+ *value = static_cast<long>(dv.I32);
+ return true;
+ case DEBUG_VALUE_INT64:
+ *value = static_cast<long long>(dv.I64);
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+} // namespace CdbCore
diff --git a/src/plugins/debugger/cdb/coreengine.h b/src/plugins/debugger/cdb/coreengine.h
new file mode 100644
index 0000000000..00c8dd0096
--- /dev/null
+++ b/src/plugins/debugger/cdb/coreengine.h
@@ -0,0 +1,191 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef COREENGINE_H
+#define COREENGINE_H
+
+#include "cdbcom.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QSharedPointer>
+
+namespace CdbCore {
+
+class DebugOutputBase;
+class DebugEventCallbackBase;
+
+// helper struct to pass interfaces around
+struct ComInterfaces
+{
+ ComInterfaces();
+
+ CIDebugClient* debugClient;
+ CIDebugControl* debugControl;
+ CIDebugSystemObjects* debugSystemObjects;
+ CIDebugSymbols* debugSymbols;
+ CIDebugRegisters* debugRegisters;
+ CIDebugDataSpaces* debugDataSpaces;
+};
+
+class CoreEngine : public QObject
+{
+ Q_DISABLE_COPY(CoreEngine)
+ Q_OBJECT
+public:
+ enum ExpressionSyntax { AssemblerExpressionSyntax, CppExpressionSyntax };
+ enum CodeLevel { CodeLevelAssembly, CodeLevelSource };
+
+ typedef QSharedPointer<DebugOutputBase> DebugOutputBasePtr;
+ typedef QSharedPointer<DebugEventCallbackBase> DebugEventCallbackBasePtr;
+
+ explicit CoreEngine(QObject *parent = 0);
+ virtual ~CoreEngine();
+
+ bool init(const QString &dllEnginePath, QString *errorMessage);
+ // code level/output
+
+ inline const ComInterfaces &interfaces() const { return m_cif; }
+
+ // Set handlers
+ DebugOutputBasePtr setDebugOutput(const DebugOutputBasePtr &);
+ DebugEventCallbackBasePtr setDebugEventCallback(const DebugEventCallbackBasePtr &);
+
+ // Start functions
+ bool startDebuggerWithExecutable(const QString &workingDirectory,
+ const QString &filename,
+ const QStringList &args,
+ const QStringList &env,
+ bool verboseSymbolLoading,
+ QString *errorMessage);
+
+ bool startAttachDebugger(qint64 pid, bool suppressInitialBreakPoint,
+ QString *errorMessage);
+
+ ULONG executionStatus() const;
+ bool setExecutionStatus(ULONG ex, QString *errorMessage);
+
+ // break & interrupt
+ bool debugBreakProcess(HANDLE hProcess, QString *errorMessage);
+ // Currently does not interrupt debuggee
+ bool setInterrupt(QString *errorMessage);
+
+ // Helpers for terminating the debuggees and ending the session
+ bool detachCurrentProcess(QString *appendableErrorMessage);
+ bool terminateCurrentProcess(QString *appendableErrorMessage);
+ bool terminateProcesses(QString *appendableErrorMessage);
+ bool endSession(QString *appendableErrorMessage);
+
+ // Watch timer: Listen for debug events and emit watchTimerDebugEvent() should one
+ // occur.
+ void startWatchTimer();
+ void killWatchTimer();
+ inline bool isWatchTimerRunning() const { return m_watchTimer != -1; }
+ // Synchronous wait
+ HRESULT waitForEvent(int timeOutMS);
+
+ // Commands and expressions
+ bool executeDebuggerCommand(const QString &command, QString *errorMessage);
+
+ bool evaluateExpression(const QString &expression,
+ DEBUG_VALUE *debugValue,
+ QString *errorMessage);
+ bool evaluateExpression(const QString &expression, QString *value,
+ QString *type /* =0 */, QString *errorMessage);
+
+ // Path getters/setters
+ QStringList sourcePaths() const;
+ bool setSourcePaths(const QStringList &s, QString *errorMessage);
+ QStringList symbolPaths() const;
+ bool setSymbolPaths(const QStringList &s, QString *errorMessage);
+
+ // Options
+ ExpressionSyntax expressionSyntax() const;
+ ExpressionSyntax setExpressionSyntax(ExpressionSyntax es);
+
+ CodeLevel codeLevel() const;
+ CodeLevel setCodeLevel(CodeLevel);
+
+ QString dbengDLL() const { return m_dbengDLL; }
+
+ // Debuggee memory conveniences
+ bool allocDebuggeeMemory(int size, ULONG64 *address, QString *errorMessage);
+ bool createDebuggeeAscIIString(const QString &s, ULONG64 *address, QString *errorMessage);
+ bool writeToDebuggee(const QByteArray &buffer, quint64 address, QString *errorMessage);
+ // Write to debuggee memory in chunks
+ bool dissassemble(ULONG64 offset, unsigned long beforeLines, unsigned long afterLines,
+ QString *target, QString *errorMessage);
+
+ static bool autoDetectPath(QString *outPath,
+ QStringList *checkedDirectories = 0);
+
+signals:
+ void watchTimerDebugEvent();
+
+protected:
+ virtual void timerEvent(QTimerEvent* te);
+
+private:
+ ComInterfaces m_cif;
+ DebugOutputBasePtr m_debugOutput;
+ DebugEventCallbackBasePtr m_debugEventCallback;
+ QString m_dbengDLL;
+ QString m_baseImagePath;
+ int m_watchTimer;
+};
+
+// Utility messages
+QString msgDebugEngineComResult(HRESULT hr);
+QString msgComFailed(const char *func, HRESULT hr);
+QString msgDebuggerCommandFailed(const QString &command, HRESULT hr);
+const char *msgExecutionStatusString(ULONG executionStatus);
+
+// 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(CoreEngine *engine, CoreEngine::ExpressionSyntax es) :
+ m_oldSyntax(engine->setExpressionSyntax(es)),
+ m_engine(engine) {}
+ inline ~SyntaxSetter() { m_engine->setExpressionSyntax(m_oldSyntax); }
+
+private:
+ const CoreEngine::ExpressionSyntax m_oldSyntax;
+ CoreEngine *m_engine;
+};
+
+// Helpers to convert DEBUG_VALUE structs. The optional control is required to
+// convert large floating values.
+QString debugValueToString(const DEBUG_VALUE &dv, QString *qType =0, int integerBase = 10, CIDebugControl *ctl = 0);
+bool debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value);
+
+} // namespace CdbCore
+
+#endif // COREENGINE_H
diff --git a/src/plugins/debugger/cdb/debugeventcallbackbase.cpp b/src/plugins/debugger/cdb/debugeventcallbackbase.cpp
new file mode 100644
index 0000000000..36e5e0d45c
--- /dev/null
+++ b/src/plugins/debugger/cdb/debugeventcallbackbase.cpp
@@ -0,0 +1,219 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "debugeventcallbackbase.h"
+#include "coreengine.h"
+
+namespace CdbCore {
+
+// DebugEventCallbackBase
+DebugEventCallbackBase::DebugEventCallbackBase()
+{
+}
+
+DebugEventCallbackBase::~DebugEventCallbackBase()
+{
+}
+
+STDMETHODIMP DebugEventCallbackBase::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) DebugEventCallbackBase::AddRef(THIS)
+{
+ // This class is designed to be static so
+ // there's no true refcount.
+ return 1;
+}
+
+STDMETHODIMP_(ULONG) DebugEventCallbackBase::Release(THIS)
+{
+ // This class is designed to be static so
+ // there's no true refcount.
+ return 0;
+}
+
+STDMETHODIMP DebugEventCallbackBase::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT2)
+{
+ return S_OK;
+}
+STDMETHODIMP DebugEventCallbackBase::Exception(
+ THIS_
+ __in PEXCEPTION_RECORD64,
+ __in ULONG /* FirstChance */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::CreateThread(
+ THIS_
+ __in ULONG64 /* Handle */,
+ __in ULONG64 /* DataOffset */,
+ __in ULONG64 /* StartOffset */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::ExitThread(
+ THIS_
+ __in ULONG /* ExitCode */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::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 DebugEventCallbackBase::ExitProcess(
+ THIS_
+ __in ULONG /* ExitCode */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::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 DebugEventCallbackBase::UnloadModule(
+ THIS_
+ __in_opt PCWSTR /* ImageBaseName */,
+ __in ULONG64 /* BaseOffset */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::SystemError(
+ THIS_
+ __in ULONG /* Error */,
+ __in ULONG /* Level */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::SessionStatus(
+ THIS_
+ __in ULONG /* Status */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::ChangeDebuggeeState(
+ THIS_
+ __in ULONG /* Flags */,
+ __in ULONG64 /* Argument */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::ChangeEngineState(
+ THIS_
+ __in ULONG /* Flags */,
+ __in ULONG64 /* Argument */
+ )
+{
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallbackBase::ChangeSymbolState(
+ THIS_
+ __in ULONG /* Flags */,
+ __in ULONG64 /* Argument */
+ )
+{
+ return S_OK;
+}
+
+IDebugEventCallbacksWide *DebugEventCallbackBase::getEventCallback(CIDebugClient *clnt)
+{
+ IDebugEventCallbacksWide *rc = 0;
+ if (SUCCEEDED(clnt->GetEventCallbacksWide(&rc)))
+ return rc;
+ return 0;
+}
+
+EventCallbackRedirector::EventCallbackRedirector(CoreEngine *engine,
+ const DebugEventCallbackBasePtr &cb) :
+ m_engine(engine),
+ m_oldCallback(engine->setDebugEventCallback(cb))
+{
+}
+
+EventCallbackRedirector::~EventCallbackRedirector()
+{
+ m_engine->setDebugEventCallback(m_oldCallback);
+}
+
+} // namespace CdbCore
diff --git a/src/plugins/debugger/cdb/debugeventcallbackbase.h b/src/plugins/debugger/cdb/debugeventcallbackbase.h
new file mode 100644
index 0000000000..78832c4c0a
--- /dev/null
+++ b/src/plugins/debugger/cdb/debugeventcallbackbase.h
@@ -0,0 +1,174 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGEVENTCALLBACKBASE_H
+#define DEBUGEVENTCALLBACKBASE_H
+
+#include "cdbcom.h"
+
+#include <QtCore/QSharedPointer>
+
+namespace CdbCore {
+
+class CoreEngine;
+
+// Base class for event callbacks that takes care
+// Active X magic. Provides base implementations with
+// the exception of GetInterestMask
+class DebugEventCallbackBase : public IDebugEventCallbacksWide
+{
+protected:
+ DebugEventCallbackBase();
+public:
+ virtual ~DebugEventCallbackBase();
+ // IUnknown.
+ STDMETHOD(QueryInterface)(
+ THIS_
+ IN REFIID InterfaceId,
+ OUT PVOID* Interface
+ );
+ STDMETHOD_(ULONG, AddRef)(
+ THIS
+ );
+ STDMETHOD_(ULONG, Release)(
+ THIS
+ );
+
+ // IDebugEventCallbacks.
+
+ STDMETHOD(Breakpoint)(
+ THIS_
+ __in PDEBUG_BREAKPOINT2 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 PCWSTR ModuleName,
+ __in_opt PCWSTR 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 PCWSTR ModuleName,
+ __in_opt PCWSTR ImageName,
+ __in ULONG CheckSum,
+ __in ULONG TimeDateStamp
+ );
+
+ STDMETHOD(UnloadModule)(
+ THIS_
+ __in_opt PCWSTR 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
+ );
+
+
+ static IDebugEventCallbacksWide *getEventCallback(CIDebugClient *clnt);
+};
+
+// Utility class to temporarily redirect events to another handler
+// as long as in scope
+class EventCallbackRedirector {
+ Q_DISABLE_COPY(EventCallbackRedirector)
+public:
+ typedef QSharedPointer<DebugEventCallbackBase> DebugEventCallbackBasePtr;
+
+ explicit EventCallbackRedirector(CoreEngine *engine, const DebugEventCallbackBasePtr &cb);
+ ~EventCallbackRedirector();
+
+private:
+ CoreEngine *m_engine;
+ const DebugEventCallbackBasePtr m_oldCallback;
+};
+
+} // namespace CdbCore
+
+#endif // DEBUGEVENTCALLBACKBASE_H
diff --git a/src/plugins/debugger/cdb/debugoutputbase.cpp b/src/plugins/debugger/cdb/debugoutputbase.cpp
new file mode 100644
index 0000000000..25e278c1c8
--- /dev/null
+++ b/src/plugins/debugger/cdb/debugoutputbase.cpp
@@ -0,0 +1,134 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "debugoutputbase.h"
+#include "coreengine.h"
+#include <QtCore/QDebug>
+
+namespace CdbCore {
+
+DebugOutputBase::DebugOutputBase()
+{
+}
+
+DebugOutputBase::~DebugOutputBase() // must be present to avoid exit crashes
+{
+}
+
+STDMETHODIMP DebugOutputBase::QueryInterface(
+ THIS_
+ IN REFIID InterfaceId,
+ OUT PVOID* Interface
+ )
+{
+ *Interface = NULL;
+
+ if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) ||
+ IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacksWide)))
+ {
+ *Interface = (IDebugOutputCallbacksWide*)this;
+ AddRef();
+ return S_OK;
+ } else {
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG) DebugOutputBase::AddRef(THIS)
+{
+ // This class is designed to be static so
+ // there's no true refcount.
+ return 1;
+}
+
+STDMETHODIMP_(ULONG) DebugOutputBase::Release(THIS)
+{
+ // This class is designed to be static so
+ // there's no true refcount.
+ return 0;
+}
+
+STDMETHODIMP DebugOutputBase::Output(
+ THIS_
+ IN ULONG mask,
+ IN PCWSTR text
+ )
+{
+ const QString msg = QString::fromUtf16(reinterpret_cast<const ushort *>(text));
+ output(mask, msg);
+ return S_OK;
+}
+
+IDebugOutputCallbacksWide *DebugOutputBase::getOutputCallback(CIDebugClient *client)
+{
+ IDebugOutputCallbacksWide *rc;
+ if (FAILED(client->GetOutputCallbacksWide(&rc)))
+ return 0;
+ return rc;
+}
+
+const char *DebugOutputBase::maskDescription(ULONG m)
+{
+ switch (m) {
+ case DEBUG_OUTPUT_NORMAL:
+ break;
+ case DEBUG_OUTPUT_ERROR:
+ return "error";
+ case DEBUG_OUTPUT_WARNING:
+ return "warn";
+ case DEBUG_OUTPUT_VERBOSE:
+ return "verbose";
+ case DEBUG_OUTPUT_PROMPT_REGISTERS:
+ return "register";
+ case DEBUG_OUTPUT_EXTENSION_WARNING:
+ return "extwarn";
+ case DEBUG_OUTPUT_DEBUGGEE:
+ return "target";
+ case DEBUG_OUTPUT_DEBUGGEE_PROMPT:
+ return "input";
+ case DEBUG_OUTPUT_SYMBOLS:
+ return "symbol";
+ default:
+ break;
+ }
+ return "misc";
+}
+
+OutputRedirector::OutputRedirector(CoreEngine *engine, const DebugOutputBasePtr &o) :
+ m_engine(engine),
+ m_oldOutput(engine->setDebugOutput(o))
+{
+}
+
+OutputRedirector::~OutputRedirector()
+{
+ m_engine->setDebugOutput(m_oldOutput);
+}
+
+} // namespace CdbCore
diff --git a/src/plugins/debugger/cdb/debugoutputbase.h b/src/plugins/debugger/cdb/debugoutputbase.h
new file mode 100644
index 0000000000..029c3c4e37
--- /dev/null
+++ b/src/plugins/debugger/cdb/debugoutputbase.h
@@ -0,0 +1,111 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGOUTPUTBASE_H
+#define DEBUGOUTPUTBASE_H
+
+#include "cdbcom.h"
+
+#include <QtCore/QString>
+#include <QtCore/QSharedPointer>
+
+namespace CdbCore {
+
+class CoreEngine;
+
+// CdbDebugOutputBase is a base class for output handlers
+// that takes care of the Active X magic and conversion to QString.
+
+class DebugOutputBase : public IDebugOutputCallbacksWide
+{
+public:
+ virtual ~DebugOutputBase();
+ // 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 PCWSTR text
+ );
+
+ // Helpers to retrieve the output callbacks IF
+ static IDebugOutputCallbacksWide *getOutputCallback(CIDebugClient *client);
+ static const char *maskDescription(ULONG m);
+
+protected:
+ DebugOutputBase();
+ virtual void output(ULONG mask, const QString &message) = 0;
+};
+
+// An output handler that adds lines to a string (to be
+// used for cases in which linebreaks occur in-between calls
+// to output).
+class StringOutputHandler : public DebugOutputBase
+{
+public:
+ StringOutputHandler() {}
+ QString result() const { return m_result; }
+
+protected:
+ virtual void output(ULONG, const QString &message) { m_result += message; }
+
+private:
+ QString m_result;
+};
+
+// Utility class to temporarily redirect output to another handler
+// as long as in scope
+class OutputRedirector {
+ Q_DISABLE_COPY(OutputRedirector)
+public:
+ typedef QSharedPointer<DebugOutputBase> DebugOutputBasePtr;
+
+ explicit OutputRedirector(CoreEngine *engine, const DebugOutputBasePtr &o);
+ ~OutputRedirector();
+
+private:
+ CoreEngine *m_engine;
+ const DebugOutputBasePtr m_oldOutput;
+};
+
+} // namespace CdbCore
+
+#endif // DEBUGOUTPUTBASE_H
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 9763b362d9..bda0111543 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -85,7 +85,7 @@ class IDebuggerEngine;
class GdbEngine;
class ScriptEngine;
class CdbDebugEngine;
-struct CdbDebugEnginePrivate;
+class CdbDebugEnginePrivate;
struct DebuggerManagerActions;
class DebuggerPlugin;
class CdbDebugEventCallback;
@@ -94,7 +94,7 @@ class CdbDumperInitThread;
class CdbExceptionLoggerEventCallback;
class GdbEngine;
class CdbDebugEngine;
-struct CdbDebugEnginePrivate;
+class CdbDebugEnginePrivate;
} // namespace Internal
class DEBUGGER_EXPORT DebuggerStartParameters
@@ -169,7 +169,7 @@ public:
friend class Internal::GdbEngine;
friend class Internal::ScriptEngine;
friend class Internal::CdbDebugEngine;
- friend struct Internal::CdbDebugEnginePrivate;
+ friend class Internal::CdbDebugEnginePrivate;
DebuggerState state() const;
QList<Core::IOptionsPage*> initializeEngines(unsigned enabledTypeFlags);
diff --git a/tests/manual/ccdb/README b/tests/manual/ccdb/README
new file mode 100644
index 0000000000..56e3426f2f
--- /dev/null
+++ b/tests/manual/ccdb/README
@@ -0,0 +1,2 @@
+This directory contains a command line tool to the Debugging Tools for
+Windows for testing/scripting purposes.
diff --git a/tests/manual/ccdb/ccdb.pro b/tests/manual/ccdb/ccdb.pro
new file mode 100644
index 0000000000..6021878be3
--- /dev/null
+++ b/tests/manual/ccdb/ccdb.pro
@@ -0,0 +1,29 @@
+# -------------------------------------------------
+# Project created by QtCreator 2010-01-22T10:11:10
+# -------------------------------------------------
+QT += core
+TARGET = ccdb
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+
+# -- Add CDB core engine
+CDB_CORE = ../../../src/plugins/debugger/cdb
+include($$CDB_CORE/cdbcore.pri)
+INCLUDEPATH *= $$CDB_CORE
+
+# -- Add creator 'utils' lib
+CREATOR_LIB_LIB = ../../../lib/qtcreator
+LIBS *= -L$$CREATOR_LIB_LIB
+LIBS *= -l$$qtLibraryTarget(Utilsd)
+CREATOR_LIB_SRC = ../../../src/libs
+INCLUDEPATH *= $$CREATOR_LIB_SRC
+
+# -- App sources
+SOURCES += main.cpp \
+ cdbapplication.cpp \
+ debugeventcallback.cpp \
+ cdbpromptthread.cpp
+HEADERS += cdbapplication.h \
+ debugeventcallback.h \
+ cdbpromptthread.h
diff --git a/tests/manual/ccdb/cdbapplication.cpp b/tests/manual/ccdb/cdbapplication.cpp
new file mode 100644
index 0000000000..426cd0172a
--- /dev/null
+++ b/tests/manual/ccdb/cdbapplication.cpp
@@ -0,0 +1,213 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "cdbapplication.h"
+#include "coreengine.h"
+#include "cdbdebugoutput.h"
+#include "cdbpromptthread.h"
+#include "debugeventcallback.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QTimer>
+
+#include <cstdio>
+
+const char usage[] =
+"CDB command line test tool\n\n"
+"ccdb <Options>\n"
+"Options: -p engine path\n";
+
+class PrintfOutputHandler : public CdbCore::DebugOutputBase
+{
+public:
+ PrintfOutputHandler() {}
+
+protected:
+ virtual void output(ULONG mask, const QString &message)
+ { std::printf("%10s: %s\n", maskDescription(mask), qPrintable(message)); }
+};
+
+
+// -------------- CdbApplication
+CdbApplication::CdbApplication(int argc, char *argv[]) :
+ QCoreApplication(argc, argv),
+ m_engine(new CdbCore::CoreEngine),
+ m_promptThread(0),
+ m_processHandle(0)
+{
+}
+
+CdbApplication::~CdbApplication()
+{
+}
+
+CdbApplication::InitResult CdbApplication::init()
+{
+ if (!parseOptions()) {
+ printf(usage);
+ return InitUsageShown;
+ }
+ QString errorMessage;
+ std::printf("Initializing engine %s...\n", qPrintable(m_engineDll));
+ if (!m_engine->init(m_engineDll, &errorMessage)) {
+ std::fprintf(stderr, "Failed: %s\n", qPrintable(errorMessage));
+ return InitFailed;
+ }
+ m_engine->setDebugOutput(CdbCore::CoreEngine::DebugOutputBasePtr(new PrintfOutputHandler));
+ DebugEventCallback *evt = new DebugEventCallback;
+ connect(evt, SIGNAL(processAttached(void*)), this, SLOT(processAttached(void*)));
+ m_engine->setDebugEventCallback(CdbCore::CoreEngine::DebugEventCallbackBasePtr(evt));
+ m_engine->setExpressionSyntax(CdbCore::CoreEngine::CppExpressionSyntax);
+ m_engine->setCodeLevel(CdbCore::CoreEngine::CodeLevelSource);
+ connect(m_engine.data(), SIGNAL(watchTimerDebugEvent()), this, SLOT(debugEvent()));
+ std::printf("Succeded.\n");
+ // Prompt
+ m_promptThread = new CdbPromptThread(this);
+ connect(m_promptThread, SIGNAL(finished()), this, SLOT(promptThreadTerminated()));
+ connect(m_promptThread, SIGNAL(asyncCommand(int,QString)),
+ this, SLOT(asyncCommand(int,QString)), Qt::QueuedConnection);
+ connect(m_promptThread, SIGNAL(syncCommand(int,QString)),
+ this, SLOT(syncCommand(int,QString)), Qt::BlockingQueuedConnection);
+ connect(m_promptThread, SIGNAL(executionCommand(int,QString)),
+ this, SLOT(executionCommand(int,QString)), Qt::BlockingQueuedConnection);
+
+ m_promptThread->start();
+ return InitOk;
+}
+
+void CdbApplication::promptThreadTerminated()
+{
+ QString errorMessage;
+ m_engine->endSession(&errorMessage);
+ std::printf("Terminating.\n");
+ m_promptThread->wait();
+ quit();
+}
+
+bool CdbApplication::parseOptions()
+{
+ const QStringList args = QCoreApplication::arguments();
+ const QStringList::const_iterator cend = args.constEnd();
+ QStringList::const_iterator it = args.constBegin();
+ for (++it; it != cend ; ++it) {
+ const QString &a = *it;
+ if (a == QLatin1String("-p")) {
+ ++it;
+ if (it == cend) {
+ std::fprintf(stderr, "Option -p is missing an argument.\n");
+ return false;
+ }
+ m_engineDll = *it;
+ } else {
+ std::fprintf(stderr, "Invalid option %s\n", qPrintable(a));
+ return false;
+ }
+ }
+ return true;
+}
+
+void CdbApplication::asyncCommand(int command, const QString &arg)
+{
+ Q_UNUSED(arg)
+ QString errorMessage;
+ switch (command) {
+ case Async_Interrupt:
+ if (m_processHandle) {
+ if (m_engine->debugBreakProcess(m_processHandle, &errorMessage)) {
+ std::printf("Stopped\n");
+ } else {
+ std::printf("%s\n", qPrintable(errorMessage));
+ }
+ }
+ break;
+ }
+}
+
+void CdbApplication::syncCommand(int command, const QString &arg)
+{
+ QString errorMessage;
+ switch (command) {
+ case Sync_EvalExpression: {
+ QString value;
+ QString type;
+ if (m_engine->evaluateExpression(arg, &value, &type, &errorMessage)) {
+ std::printf("[%s] %s\n", qPrintable(type), qPrintable(value));
+ } else {
+ std::printf("%s\n", qPrintable(errorMessage));
+ }
+ }
+ break;
+ case Unknown:
+ if (!m_engine->executeDebuggerCommand(arg, &errorMessage))
+ std::printf("%s\n", qPrintable(errorMessage));
+ break;
+ }
+}
+
+void CdbApplication::executionCommand(int command, const QString &arg)
+{
+ bool ok = false;
+ QString errorMessage;
+ switch (command) {
+ case Execution_StartBinary: {
+ QStringList args = arg.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ if (args.isEmpty()) {
+ errorMessage = QLatin1String("Specify executable.");
+ } else {
+ std::printf("Starting\n");
+ const QString binary = args.front();
+ args.pop_front();
+ ok = m_engine->startDebuggerWithExecutable(QString(), binary, args,
+ QStringList(), false,
+ &errorMessage);
+ }
+ }
+ break;
+ case Execution_Go:
+ std::printf("Go\n");
+ ok = m_engine->setExecutionStatus(DEBUG_STATUS_GO, &errorMessage);
+ break;
+ }
+ if (ok) {
+ m_engine->startWatchTimer();
+ } else {
+ std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
+ }
+}
+
+void CdbApplication::debugEvent()
+{
+ std::printf("Debug event\n");
+}
+
+void CdbApplication::processAttached(void *handle)
+{
+ std::printf("pe\n");
+ m_processHandle = handle;
+}
diff --git a/tests/manual/ccdb/cdbapplication.h b/tests/manual/ccdb/cdbapplication.h
new file mode 100644
index 0000000000..5ee35b24c2
--- /dev/null
+++ b/tests/manual/ccdb/cdbapplication.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CDBAPPLICATION_H
+#define CDBAPPLICATION_H
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QSharedPointer>
+
+namespace CdbCore {
+ class CoreEngine;
+}
+
+class CdbPromptThread;
+
+class CdbApplication : public QCoreApplication
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CdbApplication)
+public:
+ enum InitResult { InitFailed, InitUsageShown, InitOk };
+
+ CdbApplication(int argc, char *argv[]);
+ ~CdbApplication();
+
+ InitResult init();
+
+private slots:
+ void promptThreadTerminated();
+ void asyncCommand(int command, const QString &arg);
+ void syncCommand(int command, const QString &arg);
+ void executionCommand(int command, const QString &arg);
+ void debugEvent();
+ void processAttached(void *handle);
+
+private:
+ bool parseOptions();
+
+ QString m_engineDll;
+ QSharedPointer<CdbCore::CoreEngine> m_engine;
+ CdbPromptThread *m_promptThread;
+ void *m_processHandle;
+};
+
+#endif // CDBAPPLICATION_H
diff --git a/tests/manual/ccdb/cdbpromptthread.cpp b/tests/manual/ccdb/cdbpromptthread.cpp
new file mode 100644
index 0000000000..66a13b2894
--- /dev/null
+++ b/tests/manual/ccdb/cdbpromptthread.cpp
@@ -0,0 +1,135 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "cdbpromptthread.h"
+
+#include <cstdio>
+#include <QtCore/QDebug>
+
+static const char help[] =
+"Special commands:\n\n"
+"H Display Help\n"
+"q Quit\n"
+"E expression Evaluate C++expression\n"
+"S binary args Start binary\n"
+"I Interrupt\n"
+"G Go\n"
+"\nThe remaining commands are passed to CDB.\n";
+
+CdbPromptThread::CdbPromptThread(QObject *parent) :
+ QThread(parent)
+{
+}
+
+void CdbPromptThread::run()
+{
+ enum { bufSize =1024 };
+
+ QString cmd;
+ char buf[bufSize];
+ std::putc('>', stdout);
+ while (true) {
+ if (std::fgets(buf, bufSize, stdin) == NULL)
+ break;
+ cmd += QString::fromLatin1(buf);
+ if (cmd.endsWith(QLatin1Char('\n'))) {
+ cmd.truncate(cmd.size() - 1);
+ if (!cmd.isEmpty() && !handleCommand(cmd.trimmed()))
+ break;
+ cmd.clear();
+ }
+ std::putc('>', stdout);
+ }
+}
+
+// Determine the command
+static Command evaluateCommand(const QString &cmdToken)
+{
+ if (cmdToken.size() == 1) {
+ switch(cmdToken.at(0).toAscii()) {
+ case 'I':
+ return Async_Interrupt;
+ case 'E':
+ return Sync_EvalExpression;
+ case 'G':
+ return Execution_Go;
+ case 'S':
+ return Execution_StartBinary;
+ default:
+ break;
+ }
+ return UnknownCommand;
+ }
+ return UnknownCommand;
+}
+
+// Chop off command and return argument list
+static Command parseCommand(QString *s)
+{
+ if (s->isEmpty())
+ return UnknownCommand;
+ int firstBlank = s->indexOf(QLatin1Char(' '));
+ // No further arguments
+ if (firstBlank == -1) {
+ const Command rc1 = evaluateCommand(*s);
+ if (rc1 != UnknownCommand) // pass through debugger cmds
+ s->clear();
+ return rc1;
+ }
+ // Chop
+ const Command rc = evaluateCommand(s->left(firstBlank));
+ if (rc != UnknownCommand) { // pass through debugger cmds)
+ int nextToken = firstBlank + 1;
+ for ( ; nextToken < s->size() && s->at(nextToken).isSpace(); nextToken++) ;
+ s->remove(0, nextToken);
+ }
+ return rc;
+}
+
+bool CdbPromptThread::handleCommand(QString cmd)
+{
+ if (cmd == QLatin1String("q"))
+ return false;
+ if (cmd == QLatin1String("H")) {
+ std::fputs(help, stdout);
+ return true;
+ }
+ const Command c = parseCommand(&cmd);
+ if (c & AsyncCommand) {
+ emit asyncCommand(c, cmd);
+ return true;
+ }
+ if (c & ExecutionCommand) {
+ emit executionCommand(c, cmd);
+ return true;
+ }
+ // Let Unknown default to sync exeute
+ emit syncCommand(c, cmd);
+ return true;
+}
diff --git a/tests/manual/ccdb/cdbpromptthread.h b/tests/manual/ccdb/cdbpromptthread.h
new file mode 100644
index 0000000000..09df8452a5
--- /dev/null
+++ b/tests/manual/ccdb/cdbpromptthread.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef PROMPTTHREAD_H
+#define PROMPTTHREAD_H
+
+#include <QtCore/QThread>
+
+enum CommandTypeFlags {
+ // Interrupt or something.
+ AsyncCommand = 0x0010000,
+ // Synchronous execution before next prompt,
+ // eg eval expression. Connect with blocking slot.
+ SyncCommand = 0x0020000,
+ // Starts debuggee. Requires starting the debug event
+ // watch timer afterwards.
+ ExecutionCommand = 0x0040000
+};
+
+enum Command {
+ UnknownCommand = 0,
+ Async_Interrupt = AsyncCommand|1,
+ Sync_EvalExpression = SyncCommand|1,
+ Execution_Go = ExecutionCommand|1,
+ Execution_StartBinary = ExecutionCommand|2
+};
+
+class CdbPromptThread : public QThread
+{
+ Q_OBJECT
+public:
+ explicit CdbPromptThread(QObject *parent = 0);
+
+ virtual void run();
+
+signals:
+ void asyncCommand(int command, const QString &arg);
+ void syncCommand(int command, const QString &arg);
+ void executionCommand(int command, const QString &arg);
+
+private:
+ bool handleCommand(QString);
+};
+
+#endif // PROMPTTHREAD_H
diff --git a/tests/manual/ccdb/debugeventcallback.cpp b/tests/manual/ccdb/debugeventcallback.cpp
new file mode 100644
index 0000000000..1caaf2f806
--- /dev/null
+++ b/tests/manual/ccdb/debugeventcallback.cpp
@@ -0,0 +1,156 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "debugeventcallback.h"
+
+#include <cstdio>
+
+DebugEventCallback::DebugEventCallback()
+{
+}
+
+STDMETHODIMP DebugEventCallback::GetInterestMask(THIS_ __out PULONG mask)
+{
+ *mask = DEBUG_EVENT_CREATE_PROCESS | DEBUG_EVENT_EXIT_PROCESS
+ | DEBUG_EVENT_LOAD_MODULE | DEBUG_EVENT_UNLOAD_MODULE
+ | DEBUG_EVENT_CREATE_THREAD | DEBUG_EVENT_EXIT_THREAD
+ | DEBUG_EVENT_BREAKPOINT
+ | DEBUG_EVENT_EXCEPTION;
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT2)
+{
+ printf("Breakpoint hit\n");
+ return S_OK;
+}
+STDMETHODIMP DebugEventCallback::Exception(
+ THIS_
+ __in PEXCEPTION_RECORD64 exc,
+ __in ULONG firstChance
+ )
+{
+ printf("Exception %ul occurred first-chance: %ul\n", exc->ExceptionCode, firstChance);
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::CreateThread(
+ THIS_
+ __in ULONG64 /* Handle */,
+ __in ULONG64 /* DataOffset */,
+ __in ULONG64 /* StartOffset */
+ )
+{
+ printf("Thread created\n");
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::ExitThread(
+ THIS_
+ __in ULONG /* ExitCode */
+ )
+{
+ printf("Thread quit\n");
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::CreateProcess(
+ THIS_
+ __in ULONG64 /* ImageFileHandle */,
+ __in ULONG64 Handle,
+ __in ULONG64 /* Offset */,
+ __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 */
+ )
+{
+ printf("Process created %Ld\n", Handle);
+ emit processAttached(reinterpret_cast<void*>(Handle));
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::ExitProcess(
+ THIS_
+ __in ULONG /* ExitCode */
+ )
+{
+ printf("Process quit\n");
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::LoadModule(
+ THIS_
+ __in ULONG64 /* ImageFileHandle */,
+ __in ULONG64 /* Offset */,
+ __in ULONG /* ModuleSize */,
+ __in_opt PCWSTR /* ModuleName */,
+ __in_opt PCWSTR /* ImageName */,
+ __in ULONG /* CheckSum */,
+ __in ULONG /* TimeDateStamp */
+ )
+{
+ printf("Module loaded\n");
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::UnloadModule(
+ THIS_
+ __in_opt PCWSTR /* ImageName */,
+ __in ULONG64 /* Offset */
+ )
+{
+ printf("Module unloaded\n");
+ return S_OK;
+}
+
+STDMETHODIMP DebugEventCallback::SystemError(
+ THIS_
+ __in ULONG Error,
+ __in ULONG Level
+ )
+{
+ printf("System error %ul at %ul\n", Error, Level);
+ return S_OK;
+}
+
+
+STDMETHODIMP DebugEventCallback::ChangeDebuggeeState(
+ THIS_
+ __in ULONG Flags,
+ __in ULONG64 Argument
+ )
+{
+ printf("Debuggee state changed %ul %ul\n", Flags, Argument);
+ return S_OK;
+}
diff --git a/tests/manual/ccdb/debugeventcallback.h b/tests/manual/ccdb/debugeventcallback.h
new file mode 100644
index 0000000000..357224eadc
--- /dev/null
+++ b/tests/manual/ccdb/debugeventcallback.h
@@ -0,0 +1,125 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGEVENTCALLBACK_H
+#define DEBUGEVENTCALLBACK_H
+
+#include "debugeventcallbackbase.h"
+#include <QtCore/QObject>
+
+class DebugEventCallback :
+ public QObject,
+ public CdbCore::DebugEventCallbackBase
+
+{
+ Q_OBJECT
+public:
+ DebugEventCallback();
+
+ STDMETHOD(GetInterestMask)(
+ THIS_
+ __out PULONG mask
+ );
+
+ STDMETHOD(Breakpoint)(
+ THIS_
+ __in PDEBUG_BREAKPOINT2 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 PCWSTR ModuleName,
+ __in_opt PCWSTR 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 PCWSTR ModuleName,
+ __in_opt PCWSTR ImageName,
+ __in ULONG CheckSum,
+ __in ULONG TimeDateStamp
+ );
+
+ STDMETHOD(UnloadModule)(
+ THIS_
+ __in_opt PCWSTR ImageBaseName,
+ __in ULONG64 BaseOffset
+ );
+
+ STDMETHOD(SystemError)(
+ THIS_
+ __in ULONG Error,
+ __in ULONG Level
+ );
+
+ STDMETHOD(ChangeDebuggeeState)(
+ THIS_
+ __in ULONG Flags,
+ __in ULONG64 Argument
+ );
+
+signals:
+ void processAttached(void *h);
+};
+
+#endif // DEBUGEVENTCALLBACK_H
diff --git a/tests/manual/ccdb/main.cpp b/tests/manual/ccdb/main.cpp
new file mode 100644
index 0000000000..a9ccb6d93c
--- /dev/null
+++ b/tests/manual/ccdb/main.cpp
@@ -0,0 +1,49 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "cdbapplication.h"
+#include <QtCore/QString>
+
+int main(int argc, char *argv[])
+{
+ CdbApplication app(argc, argv);
+ int rc = 0;
+
+ switch (app.init()) {
+ case CdbApplication::InitOk:
+ rc = app.exec();
+ break;
+ case CdbApplication::InitFailed:
+ rc = 1;
+ break;
+ case CdbApplication::InitUsageShown:
+ break;
+ }
+ return rc;
+}