summaryrefslogtreecommitdiff
path: root/src/plugins/debugger
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2009-03-26 16:49:28 +0100
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2009-03-26 16:49:28 +0100
commit536320ea1ac63c83b6e6777a0dabe7d47e9ba8cd (patch)
treefa46808bd583e6f46f3b9d407fb14f008d85b361 /src/plugins/debugger
parent393a03747b081b9cdd49e723bec95ff4d3f1d53a (diff)
downloadqt-creator-536320ea1ac63c83b6e6777a0dabe7d47e9ba8cd.tar.gz
Start stack frame context/symbol group classes for CDB
Diffstat (limited to 'src/plugins/debugger')
-rw-r--r--src/plugins/debugger/cdb/cdb.pri8
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine.cpp247
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine_p.h21
-rw-r--r--src/plugins/debugger/cdb/cdbstacktracecontext.cpp161
-rw-r--r--src/plugins/debugger/cdb/cdbstacktracecontext.h86
-rw-r--r--src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp177
-rw-r--r--src/plugins/debugger/cdb/cdbsymbolgroupcontext.h110
-rw-r--r--src/plugins/debugger/gdbengine.cpp12
-rw-r--r--src/plugins/debugger/stackhandler.cpp10
-rw-r--r--src/plugins/debugger/stackhandler.h3
10 files changed, 642 insertions, 193 deletions
diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri
index 27186577c3..8ba7d3a686 100644
--- a/src/plugins/debugger/cdb/cdb.pri
+++ b/src/plugins/debugger/cdb/cdb.pri
@@ -22,12 +22,16 @@ HEADERS += \
$$PWD/cdbdebugengine.h \
$$PWD/cdbdebugengine_p.h \
$$PWD/cdbdebugeventcallback.h \
- $$PWD/cdbdebugoutput.h
+ $$PWD/cdbdebugoutput.h \
+ $$PWD/cdbsymbolgroupcontext.h \
+ $$PWD/cdbstacktracecontext.h
SOURCES += \
$$PWD/cdbdebugengine.cpp \
$$PWD/cdbdebugeventcallback.cpp \
- $$PWD/cdbdebugoutput.cpp
+ $$PWD/cdbdebugoutput.cpp \
+ $$PWD/cdbsymbolgroupcontext.cpp \
+ $$PWD/cdbstacktracecontext.cpp
} else {
message("Debugging Tools for Windows could not be found in $$CDB_PATH")
}
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index 73d3953ffb..7d054e68dd 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 "cdbsymbolgroupcontext.h"
+#include "cdbstacktracecontext.h"
#include "debuggermanager.h"
#include "breakhandler.h"
@@ -55,7 +57,12 @@
static const char *dbgEngineDllC = "dbgeng";
static const char *debugCreateFuncC = "DebugCreate";
-static QString msgDebugEngineComResult(HRESULT hr)
+static const char *localSymbolRootC = "local";
+
+namespace Debugger {
+namespace Internal {
+
+QString msgDebugEngineComResult(HRESULT hr)
{
switch (hr) {
case S_OK:
@@ -87,13 +94,12 @@ static QString msgStackIndexOutOfRange(int idx, int size)
return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size);
}
-static QString msgComFailed(const char *func, HRESULT hr)
+QString msgComFailed(const char *func, HRESULT hr)
{
return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr));
}
-namespace Debugger {
-namespace Internal {
+static const char *msgNoStackTraceC = "Internal error: no stack trace present.";
DebuggerEngineLibrary::DebuggerEngineLibrary() :
m_debugCreate(0)
@@ -138,6 +144,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn
m_engine(engine),
m_debuggerManager(parent),
m_debuggerManagerAccess(parent->engineInterface()),
+ m_currentStackTrace(0),
m_mode(AttachCore)
{
}
@@ -205,6 +212,7 @@ IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent)
CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
{
+ cleanStackTrace();
if (m_pDebugClient)
m_pDebugClient->Release();
if (m_pDebugControl)
@@ -217,6 +225,17 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate()
m_pDebugRegisters->Release();
}
+void CdbDebugEnginePrivate::cleanStackTrace()
+{
+ if (debugCDB)
+ qDebug() << Q_FUNC_INFO;
+
+ if (m_currentStackTrace) {
+ delete m_currentStackTrace;
+ m_currentStackTrace = 0;
+ }
+}
+
CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) :
IDebuggerEngine(parent),
m_d(new CdbDebugEnginePrivate(parent, this))
@@ -366,6 +385,7 @@ void CdbDebugEngine::processTerminated(unsigned long exitCode)
if (debugCDB)
qDebug() << Q_FUNC_INFO << exitCode;
+ m_d->cleanStackTrace();
m_d->setDebuggeeHandles(0, 0);
m_d->m_debuggerManagerAccess->notifyInferiorExited();
m_d->m_debuggerManager->exitDebugger();
@@ -377,6 +397,7 @@ void CdbDebugEngine::exitDebugger()
qDebug() << Q_FUNC_INFO;
if (m_d->m_hDebuggeeProcess) {
+ m_d->cleanStackTrace();
// Terminate or detach if we are running
HRESULT hr;
switch (m_d->m_mode) {
@@ -407,47 +428,22 @@ void CdbDebugEngine::exitDebugger()
killWatchTimer();
}
-// Retrieve a symbol
-static WatchData symbolToWatchData(ULONG index, const QString &namePrefix,
- IDebugSymbolGroup2 *pDbgSymGroup)
+class ModelBuildIterator {
+public:
+ explicit ModelBuildIterator(WatchHandler *wh) : m_wh(wh) {}
+
+ ModelBuildIterator & operator*() { return *this; }
+ ModelBuildIterator &operator=(const WatchData &wd);
+ ModelBuildIterator &operator++() { return *this; }
+
+private:
+ WatchHandler *m_wh;
+};
+
+ModelBuildIterator &ModelBuildIterator::operator=(const WatchData &wd)
{
- // retrieve symbol names and value strings
- ULONG nameLength;
- static WCHAR nameBuffer[MAX_PATH + 1];
- // Name
- pDbgSymGroup->GetSymbolNameWide(index, nameBuffer, MAX_PATH, &nameLength);
- nameBuffer[nameLength] = 0;
- const QString name = QString::fromUtf16(nameBuffer);
- // Type name
- pDbgSymGroup->GetSymbolTypeNameWide(index, nameBuffer, MAX_PATH, &nameLength);
- nameBuffer[nameLength] = 0;
- const QString type = QString::fromUtf16(nameBuffer);
- // Value
- QString value;
- const HRESULT hr = pDbgSymGroup->GetSymbolValueTextWide(index, nameBuffer, MAX_PATH, &nameLength);
- if (SUCCEEDED(hr)) {
- nameBuffer[nameLength] = 0;
- value = QString::fromUtf16(nameBuffer);
- } else {
- value = QLatin1String("<unknown>");
- }
- WatchData wd;
- wd.iname =namePrefix + name;
- wd.name = name;
- wd.value = value;
- wd.type = type;
- if (isPointerType(type)) {
- wd.setTypeUnneeded();
- wd.setValueUnneeded();
- } else {
- wd.setAllUnneeded();
- }
- if (debugCDB) {
- qDebug() << Q_FUNC_INFO << index << "state=0x" << QString::number(wd.state, 16)
- << wd.name << " type=" << wd.type << " (" << type << ')'
- << " value " << wd.value << " (" << value << ')';
- }
- return wd;
+ m_wh->insertData(wd);
+ return *this;
}
bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
@@ -456,82 +452,36 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << frameIndex;
-
- CdbStackTrace cdbStackTrace;
- if (!getCdbStrackTrace(&cdbStackTrace, errorMessage))
- return false;
-
- if ((unsigned)frameIndex >= cdbStackTrace.frameCount) {
- *errorMessage = msgStackIndexOutOfRange(frameIndex, cdbStackTrace.frameCount);
- return false;
- }
-
- IDebugSymbolGroup2 *pDbgSymGroup = 0;
- DEBUG_SYMBOL_PARAMETERS *symParams = 0;
bool success = false;
-
+ wh->cleanup();
do {
- HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &pDbgSymGroup);
- if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
- break;
- }
-
- hr = m_pDebugSymbols->SetScope(0, cdbStackTrace.frames + frameIndex, NULL, 0);
- if (FAILED(hr)) {
- *errorMessage = msgComFailed("SetScope", hr);
- break;
- }
- // refresh with current frame
- hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, pDbgSymGroup, &pDbgSymGroup);
- if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
- break;
- }
-
- ULONG symbolCount;
- hr = pDbgSymGroup->GetNumberSymbols(&symbolCount);
- if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetNumberSymbols", hr);
+ if (!m_currentStackTrace) {
+ *errorMessage = QLatin1String(msgNoStackTraceC);
break;
}
- symParams = new DEBUG_SYMBOL_PARAMETERS[symbolCount];
- hr = pDbgSymGroup->GetSymbolParameters(0, symbolCount, symParams);
- if (FAILED(hr)) {
- *errorMessage = msgComFailed("GetSymbolParameters", hr);
+ CdbSymbolGroupContext *sgc = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage);
+ if (!sgc) {
break;
}
- wh->cleanup();
- // retrieve symbol names and value strings.
- // Add a dummy place holder in case children are needed
- const QString localPrefix = QLatin1String("local.");
- for (ULONG s = 0 ; s < symbolCount ; s++ ) {
- WatchData wd = symbolToWatchData(s, localPrefix, pDbgSymGroup);
- if (wd.isSomethingNeeded()) {
- wh->insertData(wd.pointerChildPlaceHolder());
- wd.setAllUnneeded();
- wd.setChildCount(1);
- }
- wh->insertData(wd);
- }
- wh->rebuildModel();
+ ModelBuildIterator it(wh);
+ sgc->getSymbols(sgc->prefix(), it);
success = true;
} while (false);
+ wh->rebuildModel();
- delete [] symParams;
- if (pDbgSymGroup)
- pDbgSymGroup->Release();
return success;
}
-
void CdbDebugEngine::updateWatchModel()
{
WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler();
const QList<WatchData> incomplete = watchHandler->takeCurrentIncompletes();
+
if (debugCDB)
qDebug() << Q_FUNC_INFO << incomplete.size();
+ foreach (const WatchData& wd, incomplete)
+ qDebug() << Q_FUNC_INFO << wd.toString();
}
void CdbDebugEngine::stepExec()
@@ -540,8 +490,9 @@ void CdbDebugEngine::stepExec()
qDebug() << Q_FUNC_INFO;
//m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
- HRESULT hr;
- hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
+ m_d->cleanStackTrace();
+ const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO);
+ Q_UNUSED(hr)
m_d->m_bIgnoreNextDebugEvent = true;
startWatchTimer();
}
@@ -594,6 +545,7 @@ void CdbDebugEngine::nextExec()
if (debugCDB)
qDebug() << Q_FUNC_INFO;
+ m_d->cleanStackTrace();
const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER);
if (SUCCEEDED(hr)) {
startWatchTimer();
@@ -612,6 +564,7 @@ void CdbDebugEngine::nextIExec()
if (debugCDB)
qDebug() << Q_FUNC_INFO;
+ m_d->cleanStackTrace();
const HRESULT hr = m_d->m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0);
if (SUCCEEDED(hr)) {
startWatchTimer();
@@ -625,6 +578,7 @@ void CdbDebugEngine::continueInferior()
if (debugCDB)
qDebug() << Q_FUNC_INFO;
+ m_d->cleanStackTrace();
killWatchTimer();
m_d->m_debuggerManager->resetLocation();
@@ -714,7 +668,7 @@ void CdbDebugEngine::activateFrame(int frameIndex)
}
const StackFrame &frame = stackHandler->currentFrame();
- if (frame.file.isEmpty() || !QFileInfo(frame.file).isReadable()) {
+ if (!frame.isUsable()) {
errorMessage = QString::fromLatin1("%1: file %2 unusable.").
arg(QLatin1String(Q_FUNC_INFO), frame.file);
break;
@@ -933,78 +887,29 @@ void CdbDebugEnginePrivate::updateThreadList()
th->setThreads(threads);
}
-// Get CDB stack trace
-bool CdbDebugEnginePrivate::getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage)
-{
- HRESULT hr = m_pDebugSystemObjects->SetCurrentThreadId(m_currentThreadId);
- if (FAILED(hr)) {
- *errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3").
- arg(QString::fromLatin1(Q_FUNC_INFO)).
- arg(m_currentThreadId).
- arg(msgDebugEngineComResult(hr));
- return false;
- }
- hr = m_pDebugControl->GetStackTrace(0, 0, 0, st->frames, CdbStackTrace::maxFrames, &(st->frameCount));
- if (FAILED(hr)) {
- *errorMessage = *errorMessage = msgComFailed("GetStackTrace", hr);
- return false;
- }
- return true;
-}
-
-bool CdbDebugEnginePrivate::getStackTrace(QList<StackFrame> *stackFrames,
- int *current, QString *errorMessage)
-{
- stackFrames->clear();
- *current = -1;
- // Get the CDB trace and convert into debugger plugin structures
- CdbStackTrace cdbStackTrace;
- if (!getCdbStrackTrace(&cdbStackTrace, errorMessage))
- return false;
-
- WCHAR wszBuf[MAX_PATH];
- for (ULONG i=0; i < cdbStackTrace.frameCount; ++i) {
- StackFrame frame;
- frame.line = 0;
- frame.level = i;
- frame.address = QString::fromLatin1("0x%1").arg(cdbStackTrace.frames[i].InstructionOffset, 0, 16);
-
- m_pDebugSymbols->GetNameByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
- frame.function = QString::fromUtf16(wszBuf);
-
- ULONG ulLine;
- ULONG ulFileNameSize;
- ULONG64 ul64Displacement;
- const HRESULT hr = m_pDebugSymbols->GetLineByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement);
- if (SUCCEEDED(hr)) {
- frame.line = ulLine;
- frame.file = QString::fromUtf16(wszBuf, ulFileNameSize);
- }
- stackFrames->append(frame);
- }
-
- // find the first usable frame and select it
- const int count = stackFrames->count();
- for (int i=0; i < count; ++i) {
- const StackFrame &frame = stackFrames->at(i);
- const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
- if (usable) {
- *current = i;
- break;
- }
- }
- return true;
-}
-
void CdbDebugEnginePrivate::updateStackTrace()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO;
- QList<StackFrame> stackFrames;
- int current;
+ // Create a new context
+ cleanStackTrace();
QString errorMessage;
- if (getStackTrace(&stackFrames, &current, &errorMessage))
- qWarning("%s", qPrintable(errorMessage));
+ m_currentStackTrace =
+ CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects,
+ m_pDebugSymbols, m_currentThreadId, &errorMessage);
+ if (!m_currentStackTrace) {
+ qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
+ return;
+ }
+ const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
+ // find the first usable frame and select it
+ int current = -1;
+ const int count = stackFrames.count();
+ for (int i=0; i < count; ++i)
+ if (stackFrames.at(i).isUsable()) {
+ current = i;
+ break;
+ }
m_debuggerManagerAccess->stackHandler()->setFrames(stackFrames);
if (current >= 0) {
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index e6235569a0..e1991f707d 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -42,6 +42,8 @@ namespace Internal {
class DebuggerManager;
class IDebuggerManagerAccessForEngines;
class WatchHandler;
+class CdbSymbolGroupContext;
+class CdbStackTraceContext;
// Thin wrapper around the 'DBEng' debugger engine shared library
// which is loaded at runtime.
@@ -61,16 +63,6 @@ private:
DebugCreateFunction m_debugCreate;
};
-
-// Helper struct for stack traces
-struct CdbStackTrace {
- CdbStackTrace() : frameCount(0) {}
- enum { maxFrames = 100 };
-
- ULONG frameCount;
- DEBUG_STACK_FRAME frames[maxFrames];
-};
-
struct CdbDebugEnginePrivate
{
explicit CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine);
@@ -84,10 +76,9 @@ struct CdbDebugEnginePrivate
void updateThreadList();
void updateStackTrace();
bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage);
- bool getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage);
- bool getStackTrace(QList<StackFrame> *stackFrames, int *current, QString *errorMessage);
void handleDebugOutput(const char* szOutputString);
void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP);
+ void cleanStackTrace();
HANDLE m_hDebuggeeProcess;
HANDLE m_hDebuggeeThread;
@@ -106,10 +97,16 @@ struct CdbDebugEnginePrivate
CdbDebugEngine* m_engine;
DebuggerManager *m_debuggerManager;
IDebuggerManagerAccessForEngines *m_debuggerManagerAccess;
+ CdbStackTraceContext *m_currentStackTrace;
+
DebuggerStartMode m_mode;
Core::Utils::ConsoleProcess m_consoleStubProc;
};
+// Message
+QString msgDebugEngineComResult(HRESULT hr);
+QString msgComFailed(const char *func, HRESULT hr);
+
enum { debugCDB = 0 };
} // namespace Internal
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
new file mode 100644
index 0000000000..d569c6a9ba
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -0,0 +1,161 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (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 qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "cdbstacktracecontext.h"
+#include "cdbsymbolgroupcontext.h"
+#include "cdbdebugengine_p.h"
+
+namespace Debugger {
+namespace Internal {
+
+CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects,
+ IDebugSymbols3* pDebugSymbols) :
+ m_pDebugSystemObjects(pDebugSystemObjects),
+ m_pDebugSymbols(pDebugSymbols)
+{
+}
+
+CdbStackTraceContext *CdbStackTraceContext::create(IDebugControl4* pDebugControl,
+ IDebugSystemObjects4* pDebugSystemObjects,
+ IDebugSymbols3* pDebugSymbols,
+ unsigned long threadId,
+ QString *errorMessage)
+{
+ if (debugCDB)
+ qDebug() << Q_FUNC_INFO << threadId;
+ HRESULT hr = pDebugSystemObjects->SetCurrentThreadId(threadId);
+ if (FAILED(hr)) {
+ *errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3").
+ arg(QString::fromLatin1(Q_FUNC_INFO)).
+ arg(threadId).
+ arg(msgDebugEngineComResult(hr));
+ return 0;
+ }
+ // fill the DEBUG_STACK_FRAME array
+ ULONG frameCount;
+ CdbStackTraceContext *ctx = new CdbStackTraceContext(pDebugSystemObjects, pDebugSymbols);
+ hr = pDebugControl->GetStackTrace(0, 0, 0, ctx->m_cdbFrames, CdbStackTraceContext::maxFrames, &frameCount);
+ if (FAILED(hr)) {
+ delete ctx;
+ *errorMessage = msgComFailed("GetStackTrace", hr);
+ return 0;
+ }
+ if (!ctx->init(frameCount, errorMessage)) {
+ delete ctx;
+ return 0;
+
+ }
+ return ctx;
+}
+
+CdbStackTraceContext::~CdbStackTraceContext()
+{
+ qDeleteAll(m_symbolContexts);
+}
+
+bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessage*/)
+{
+ if (debugCDB)
+ qDebug() << Q_FUNC_INFO << frameCount;
+
+ m_symbolContexts.resize(frameCount);
+ qFill(m_symbolContexts, static_cast<CdbSymbolGroupContext*>(0));
+
+ // Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames
+ WCHAR wszBuf[MAX_PATH];
+ for (ULONG i=0; i < frameCount; ++i) {
+ StackFrame frame(i);
+ const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset;
+ frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16);
+
+ m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0);
+ frame.function = QString::fromUtf16(wszBuf);
+
+ ULONG ulLine;
+ ULONG ulFileNameSize;
+ ULONG64 ul64Displacement;
+ const HRESULT hr = m_pDebugSymbols->GetLineByOffsetWide(instructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement);
+ if (SUCCEEDED(hr)) {
+ frame.line = ulLine;
+ frame.file = QString::fromUtf16(wszBuf, ulFileNameSize);
+ }
+ m_frames.push_back(frame);
+ }
+ return true;
+}
+
+CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupContextAt(int index, QString *errorMessage)
+{
+ // Create a symbol group on demand
+ if (debugCDB)
+ qDebug() << Q_FUNC_INFO << index << m_symbolContexts.at(index);
+
+ if (index < 0 || index >= m_symbolContexts.size()) {
+ *errorMessage = QString::fromLatin1("%1: Index %2 out of range %3.").
+ arg(QLatin1String(Q_FUNC_INFO)).arg(index).arg(m_symbolContexts.size());
+ return 0;
+ }
+
+ if (m_symbolContexts.at(index))
+ return m_symbolContexts.at(index);
+ IDebugSymbolGroup2 *sg = createSymbolGroup(index, errorMessage);
+ if (!sg)
+ return 0;
+ CdbSymbolGroupContext *sc = new CdbSymbolGroupContext(QLatin1String("local"), sg);
+ m_symbolContexts[index] = sc;
+ return sc;
+}
+
+IDebugSymbolGroup2 *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage)
+{
+ IDebugSymbolGroup2 *sg = 0;
+ HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &sg);
+ if (FAILED(hr)) {
+ *errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
+ return 0;
+ }
+
+ hr = m_pDebugSymbols->SetScope(0, m_cdbFrames + index, NULL, 0);
+ if (FAILED(hr)) {
+ *errorMessage = msgComFailed("SetScope", hr);
+ sg->Release();
+ return 0;
+ }
+ // refresh with current frame
+ hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, sg, &sg);
+ if (FAILED(hr)) {
+ *errorMessage = msgComFailed("GetScopeSymbolGroup", hr);
+ sg->Release();
+ return 0;
+ }
+ return sg;
+}
+
+}
+}
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h
new file mode 100644
index 0000000000..bb8286859e
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (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 qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef CDBSTACKTRACECONTEXT_H
+#define CDBSTACKTRACECONTEXT_H
+
+#include "stackhandler.h"
+
+#include <windows.h>
+#include <inc/dbgeng.h>
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+namespace Debugger {
+namespace Internal {
+
+class CdbSymbolGroupContext;
+
+/* Context representing a break point stack consisting of several frames.
+ * Maintains an on-demand constructed list of CdbSymbolGroupContext
+ * containining the local variables of the stack. */
+
+class CdbStackTraceContext
+{
+ Q_DISABLE_COPY(CdbStackTraceContext)
+
+ explicit CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects,
+ IDebugSymbols3* pDebugSymbols);
+public:
+ enum { maxFrames = 100 };
+
+ ~CdbStackTraceContext();
+ static CdbStackTraceContext *create(IDebugControl4* pDebugControl,
+ IDebugSystemObjects4* pDebugSystemObjects,
+ IDebugSymbols3* pDebugSymbols,
+ unsigned long threadid,
+ QString *errorMessage);
+
+ QList<StackFrame> frames() const { return m_frames; }
+ inline int frameCount() const { return m_frames.size(); }
+
+ CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage);
+
+private:
+ bool init(unsigned long frameCount, QString *errorMessage);
+ IDebugSymbolGroup2 *createSymbolGroup(int index, QString *errorMessage);
+
+ IDebugSystemObjects4* m_pDebugSystemObjects;
+ IDebugSymbols3* m_pDebugSymbols;
+
+ DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
+ QVector <CdbSymbolGroupContext*> m_symbolContexts;
+ QList<StackFrame> m_frames;
+};
+
+}
+}
+
+#endif // CDBSTACKTRACECONTEXT_H
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
new file mode 100644
index 0000000000..aa52ef55e1
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
@@ -0,0 +1,177 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (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 qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "cdbsymbolgroupcontext.h"
+#include "cdbdebugengine_p.h"
+#include "watchhandler.h"
+
+// A helper function to extract a string value from a member function of
+// IDebugSymbolGroup2 taking the symbol index and a character buffer.
+// Pass in the the member function as '&IDebugSymbolGroup2::GetSymbolNameWide'
+
+typedef HRESULT (__stdcall IDebugSymbolGroup2::*WideStringRetrievalFunction)(ULONG, PWSTR, ULONG, PULONG);
+
+static inline QString getSymbolString(IDebugSymbolGroup2 *sg,
+ WideStringRetrievalFunction wsf,
+ unsigned long index)
+{
+ static WCHAR nameBuffer[MAX_PATH + 1];
+ // Name
+ ULONG nameLength;
+ const HRESULT hr = (sg->*wsf)(index, nameBuffer, MAX_PATH, &nameLength);
+ if (SUCCEEDED(hr)) {
+ nameBuffer[nameLength] = 0;
+ return QString::fromUtf16(nameBuffer);
+ }
+ return QString();
+}
+
+namespace Debugger {
+ namespace Internal {
+
+CdbSymbolGroupContext::CdbSymbolGroupContext(const QString &prefix,
+ IDebugSymbolGroup2 *symbolGroup) :
+ m_prefix(prefix),
+ m_nameDelimiter(QLatin1Char('.')),
+ m_symbolGroup(symbolGroup)
+{
+}
+
+CdbSymbolGroupContext::~CdbSymbolGroupContext()
+{
+ m_symbolGroup->Release();
+}
+
+CdbSymbolGroupContext::Range
+ CdbSymbolGroupContext::getSymbolRange(const QString &prefix)
+{
+ if (debugCDB)
+ qDebug() << Q_FUNC_INFO << prefix;
+ const ChildRangeMap::const_iterator it = m_childRanges.constFind(prefix);
+ if (it != m_childRanges.constEnd())
+ return it.value();
+ const Range r = prefix == m_prefix ? allocateRootSymbols() : allocateChildSymbols(prefix);
+ m_childRanges.insert(prefix, r);
+ return r;
+}
+
+CdbSymbolGroupContext::Range
+ CdbSymbolGroupContext::allocateChildSymbols(const QString &prefix)
+{
+ unsigned long startPos = 0;
+ unsigned long count = 0;
+
+ bool success = false;
+ QString errorMessage;
+ do {
+ const int parentIndex = m_symbolINames.indexOf(prefix);
+ if (parentIndex == -1) {
+ errorMessage = QString::fromLatin1("Prefix not found '%1'").arg(prefix);
+ break;
+ }
+
+ success = true;
+ } while (false);
+ if (!success) {
+ qWarning("%s\n", qPrintable(errorMessage));
+ }
+ return Range(startPos, count);
+}
+
+CdbSymbolGroupContext::Range
+ CdbSymbolGroupContext::allocateRootSymbols()
+{
+ unsigned long startPos = 0;
+ unsigned long count = 0;
+ bool success = false;
+
+ QString errorMessage;
+ do {
+ HRESULT hr = m_symbolGroup->GetNumberSymbols(&count);
+ if (FAILED(hr)) {
+ errorMessage = msgComFailed("GetNumberSymbols", hr);
+ break;
+ }
+
+ m_symbolParameters.reserve(3u * count);
+ m_symbolParameters.resize(count);
+
+ hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters());
+ if (FAILED(hr)) {
+ errorMessage = msgComFailed("GetSymbolParameters", hr);
+ break;
+ }
+ const QString symbolPrefix = m_prefix + m_nameDelimiter;
+ for (unsigned long i = 0; i < count; i++)
+ m_symbolINames.push_back(symbolPrefix + getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i));
+
+ success = true;
+ } while (false);
+ if (!success) {
+ clear();
+ count = 0;
+ qWarning("%s\n", qPrintable(errorMessage));
+ }
+ return Range(startPos, count);
+}
+
+void CdbSymbolGroupContext::clear()
+{
+ m_symbolParameters.clear();
+ m_childRanges.clear();
+ m_symbolINames.clear();
+}
+
+WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const
+{
+ if (debugCDB)
+ qDebug() << Q_FUNC_INFO << index;
+
+ WatchData wd;
+ wd.iname = m_symbolINames.at(index);
+ const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter);
+ wd.name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1);
+ wd.type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index);
+ wd.value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
+ const DEBUG_SYMBOL_PARAMETERS &params = m_symbolParameters.at(index);
+ if (params.SubElements) {
+ wd.setTypeUnneeded();
+ wd.setValueUnneeded();
+ wd.setChildCount(1);
+ } else {
+ wd.setAllUnneeded();
+ }
+ if (debugCDB) {
+ qDebug() << Q_FUNC_INFO << wd.toString();
+ }
+ return wd;
+}
+
+}
+}
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
new file mode 100644
index 0000000000..e5c4ea7c9c
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
@@ -0,0 +1,110 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (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 qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef CDBSYMBOLGROUPCONTEXT_H
+#define CDBSYMBOLGROUPCONTEXT_H
+
+#include <windows.h>
+#include <inc/dbgeng.h>
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QList>
+#include <QtCore/QStringList>
+#include <QtCore/QPair>
+#include <QtCore/QMap>
+
+namespace Debugger {
+ namespace Internal {
+
+class WatchData;
+
+/* A thin wrapper around the IDebugSymbolGroup2 interface which represents
+ * a flat list of symbols using an index (for example, belonging to a stack frame).
+ * It uses the hierarchical naming convention of WatchHandler as:
+ * "local" (invisible root)
+ * "local.string" (local class variable)
+ * "local.string.data" (class member).
+ * IDebugSymbolGroup2 can "expand" expandable symbols, appending to the flat list.
+ */
+
+class CdbSymbolGroupContext
+{
+ Q_DISABLE_COPY(CdbSymbolGroupContext);
+
+ // Start position and length of range in m_symbolParameters
+ typedef QPair<unsigned long, unsigned long> Range;
+
+public:
+ explicit CdbSymbolGroupContext(const QString &prefix,
+ IDebugSymbolGroup2 *symbolGroup);
+ ~CdbSymbolGroupContext();
+
+ QString prefix() const { return m_prefix; }
+
+ // Retrieve child symbols of prefix as a sequence of WatchData.
+ template <class OutputIterator>
+ void getSymbols(const QString &prefix, OutputIterator it);
+
+private:
+ void clear();
+ Range getSymbolRange(const QString &prefix);
+ Range allocateChildSymbols(const QString &prefix);
+ Range allocateRootSymbols();
+ WatchData symbolAt(unsigned long index) const;
+
+ inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
+ inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); }
+
+ const QString m_prefix;
+ const QChar m_nameDelimiter;
+ IDebugSymbolGroup2 *m_symbolGroup;
+
+ QStringList m_symbolINames;
+ QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters;
+
+ typedef QMap<QString, Range> ChildRangeMap;
+
+ ChildRangeMap m_childRanges;
+};
+
+template <class OutputIterator>
+void CdbSymbolGroupContext::getSymbols(const QString &prefix, OutputIterator it)
+{
+ const Range r = getSymbolRange(prefix);
+ const unsigned long end = r.first + r.second;
+ for (unsigned long i = r.first; i < end; i++) {
+ *it = symbolAt(i);
+ ++it;
+ }
+}
+
+}
+}
+#endif // CDBSYMBOLGROUPCONTEXT_H
diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp
index daf2e6e0c0..4ef2b4c455 100644
--- a/src/plugins/debugger/gdbengine.cpp
+++ b/src/plugins/debugger/gdbengine.cpp
@@ -2447,8 +2447,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record)
for (int i = 0; i != stack.childCount(); ++i) {
//qDebug() << "HANDLING FRAME: " << stack.childAt(i).toString();
const GdbMi frameMi = stack.childAt(i);
- StackFrame frame;
- frame.level = i;
+ StackFrame frame(i);
QStringList files;
files.append(frameMi.findChild("fullname").data());
files.append(frameMi.findChild("file").data());
@@ -2488,8 +2487,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record)
if (0 && topFrame != -1) {
// updates of locals already triggered early
const StackFrame &frame = qq->stackHandler()->currentFrame();
- bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
- if (usable)
+ if (frame.isUsable())
q->gotoLocation(frame.file, frame.line, true);
else
qDebug() << "FULL NAME NOT USABLE 0: " << frame.file;
@@ -2500,8 +2498,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record)
if (topFrame != -1) {
// updates of locals already triggered early
const StackFrame &frame = qq->stackHandler()->currentFrame();
- bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
- if (usable)
+ if (frame.isUsable())
q->gotoLocation(frame.file, frame.line, true);
else
qDebug() << "FULL NAME NOT USABLE 0: " << frame.file << topFrame;
@@ -2551,8 +2548,7 @@ void GdbEngine::activateFrame(int frameIndex)
const StackFrame &frame = stackHandler->currentFrame();
- bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable();
- if (usable)
+ if (frame.isUsable())
q->gotoLocation(frame.file, frame.line, true);
else
qDebug() << "FULL NAME NOT USABLE: " << frame.file;
diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp
index fcc28bdd19..a131bc0042 100644
--- a/src/plugins/debugger/stackhandler.cpp
+++ b/src/plugins/debugger/stackhandler.cpp
@@ -37,6 +37,16 @@
using namespace Debugger::Internal;
+StackFrame::StackFrame(int l) :
+ level(l),
+ line(0)
+{
+}
+
+bool StackFrame::isUsable() const
+{
+ return !file.isEmpty() && QFileInfo(file).isReadable();
+}
////////////////////////////////////////////////////////////////////////
//
diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h
index d427c93e92..ae073e3d13 100644
--- a/src/plugins/debugger/stackhandler.h
+++ b/src/plugins/debugger/stackhandler.h
@@ -46,6 +46,9 @@ namespace Internal {
struct StackFrame
{
+ StackFrame(int level = 0);
+ bool isUsable() const;
+
int level;
QString function;
QString file; // we try to put an absolute file name in there