aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dist/changes-1.3.03
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine.cpp59
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine_p.h2
-rw-r--r--src/plugins/debugger/cdb/cdbstackframecontext.cpp20
-rw-r--r--src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp208
-rw-r--r--src/plugins/debugger/cdb/cdbsymbolgroupcontext.h40
-rw-r--r--src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h46
-rw-r--r--src/plugins/debugger/stackhandler.h1
-rw-r--r--src/plugins/debugger/watchutils.cpp25
9 files changed, 348 insertions, 56 deletions
diff --git a/dist/changes-1.3.0 b/dist/changes-1.3.0
index 25d8e12256..0c1fa497ed 100644
--- a/dist/changes-1.3.0
+++ b/dist/changes-1.3.0
@@ -15,6 +15,8 @@ Debugging
* CDB: Added more types to the dumpers (QSharedPointer, QVector, common
* QMap/QSet types), dereference reference parameters
* CDB: Simplified display of STL types in the locals window
+ * CDB: Fixed thread handling
+ * CDB: Added internal dumpers for string types for debuggee crashes
* Improved QObject dumping, print out QRect/QSize, enumerations and flags
General:
@@ -39,3 +41,4 @@ Wizards
* Added version control checkout wizards
* Added a license header template setting
* Added a wizard for Qt Designer custom widgets
+ * Added a gitorious clone wizard
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index 365252f876..b914986a0b 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -1177,8 +1177,11 @@ void CdbDebugEngine::selectThread(int index)
ThreadsHandler *threadsHandler = m_d->m_debuggerManagerAccess->threadsHandler();
threadsHandler->setCurrentThread(index);
- m_d->m_currentThreadId = index;
- m_d->updateStackTrace();
+ const int newThreadId = threadsHandler->threads().at(index).id;
+ if (newThreadId != m_d->m_currentThreadId) {
+ m_d->m_currentThreadId = threadsHandler->threads().at(index).id;
+ m_d->updateStackTrace();
+ }
}
void CdbDebugEngine::attemptBreakpointSynchronization()
@@ -1223,7 +1226,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
m_cif.debugSymbols,
m_debuggerManagerAccess->breakHandler(),
errorMessage, &warnings);
- if (const int warningsCount = warnings.size())
+ if (const int warningsCount = warnings.size())
for (int w = 0; w < warningsCount; w++)
m_engine->warning(warnings.at(w));
return ok;
@@ -1390,6 +1393,16 @@ void CdbDebugEnginePrivate::notifyCrashed()
m_dumper->disable();
}
+static int threadIndexById(const ThreadsHandler *threadsHandler, int id)
+{
+ const QList<ThreadData> threads = threadsHandler->threads();
+ const int count = threads.count();
+ for (int i = 0; i < count; i++)
+ if (threads.at(i).id == id)
+ return i;
+ return -1;
+}
+
void CdbDebugEnginePrivate::handleDebugEvent()
{
if (debugCDB)
@@ -1401,10 +1414,15 @@ void CdbDebugEnginePrivate::handleDebugEvent()
m_breakEventMode = BreakEventHandle;
switch (mode) {
- case BreakEventHandle:
+ case BreakEventHandle: {
m_debuggerManagerAccess->notifyInferiorStopped();
- updateThreadList();
+ m_currentThreadId = updateThreadList();
+ ThreadsHandler *threadsHandler = m_debuggerManagerAccess->threadsHandler();
+ const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId);
+ if (threadIndex != -1)
+ threadsHandler->setCurrentThread(threadIndex);
updateStackTrace();
+ }
break;
case BreakEventIgnoreOnce:
m_engine->startWatchTimer();
@@ -1430,7 +1448,7 @@ void CdbDebugEnginePrivate::setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE
m_hDebuggeeThread = hDebuggeeThread;
}
-void CdbDebugEnginePrivate::updateThreadList()
+ULONG CdbDebugEnginePrivate::updateThreadList()
{
if (debugCDB)
qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
@@ -1439,25 +1457,25 @@ void CdbDebugEnginePrivate::updateThreadList()
QList<ThreadData> threads;
bool success = false;
QString errorMessage;
+ ULONG currentThreadId = 0;
do {
- ULONG numberOfThreads;
- HRESULT hr= m_cif.debugSystemObjects->GetNumberThreads(&numberOfThreads);
+ ULONG threadCount;
+ HRESULT hr= m_cif.debugSystemObjects->GetNumberThreads(&threadCount);
if (FAILED(hr)) {
errorMessage= msgComFailed("GetNumberThreads", hr);
break;
}
- const ULONG maxThreadIds = 256;
- ULONG threadIds[maxThreadIds];
- ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1);
- hr = m_cif.debugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0);
- if (FAILED(hr)) {
- errorMessage= msgComFailed("GetThreadIdsByIndex", hr);
- break;
- }
- for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) {
- ThreadData thread;
- thread.id = threadId;
- threads.append(thread);
+ // Get ids and index of current
+ if (threadCount) {
+ m_cif.debugSystemObjects->GetCurrentThreadId(&currentThreadId);
+ QVector<ULONG> threadIds(threadCount);
+ hr = m_cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0);
+ if (FAILED(hr)) {
+ errorMessage= msgComFailed("GetThreadIdsByIndex", hr);
+ break;
+ }
+ for (ULONG i = 0; i < threadCount; i++)
+ threads.push_back(ThreadData(threadIds.at(i)));
}
th->setThreads(threads);
@@ -1465,6 +1483,7 @@ void CdbDebugEnginePrivate::updateThreadList()
} while (false);
if (!success)
m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
+ return currentThreadId;
}
void CdbDebugEnginePrivate::updateStackTrace()
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index 23eb564827..53e6737343 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -115,7 +115,7 @@ struct CdbDebugEnginePrivate
bool isDebuggeeRunning() const { return m_watchTimer != -1; }
void handleDebugEvent();
- void updateThreadList();
+ ULONG updateThreadList();
void updateStackTrace();
void updateModules();
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index f68beb0db3..8c14d45fff 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -40,7 +40,7 @@
namespace Debugger {
namespace Internal {
-enum { OwnerNewItem, OwnerSymbolGroup, OwnerDumper };
+enum { OwnerNewItem, OwnerSymbolGroup, OwnerSymbolGroupDumper , OwnerDumper };
typedef QSharedPointer<CdbDumperHelper> SharedPointerCdbDumperHelper;
typedef QList<WatchData> WatchDataList;
@@ -216,6 +216,12 @@ WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
wd.source = OwnerDumper;
return *this;
}
+ // Expanded by internal dumper? : ok
+ if (wd.source == OwnerSymbolGroupDumper) {
+ m_wh->insertData(wd);
+ return *this;
+ }
+ // Try library dumpers.
switch (m_dumper->dumpType(wd, true, OwnerDumper, &m_dumperResult, &errorMessage)) {
case CdbDumperHelper::DumpOk:
if (debugCDBWatchHandling)
@@ -258,13 +264,15 @@ bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *err
qDebug() << "populateModelInitially dumpers=" << m_useDumpers;
// Recurse down items that are initially expanded in the view, stop processing for
// dumper items.
+ const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper,
+ m_dumper->comInterfaces()->debugDataSpaces);
const bool rc = m_useDumpers ?
- CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
+ CdbSymbolGroupContext::populateModelInitially(rctx,
WatchHandleDumperInserter(wh, m_dumper),
WatchHandlerExpandedPredicate(wh),
isDumperPredicate,
errorMessage) :
- CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
+ CdbSymbolGroupContext::populateModelInitially(rctx,
WatchHandlerModelInserter(wh),
WatchHandlerExpandedPredicate(wh),
falsePredicate,
@@ -279,9 +287,11 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
if (debugCDBWatchHandling)
qDebug() << ">completeData src=" << incompleteLocal.source << incompleteLocal.toString();
+ const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper,
+ m_dumper->comInterfaces()->debugDataSpaces);
// Expand symbol group items, recurse one level from desired item
if (!m_useDumpers) {
- return CdbSymbolGroupContext::completeData(m_symbolContext, incompleteLocal,
+ return CdbSymbolGroupContext::completeData(rctx, incompleteLocal,
WatchHandlerModelInserter(wh),
MatchINamePredicate(incompleteLocal.iname),
falsePredicate,
@@ -311,7 +321,7 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
}
// Expand symbol group items, recurse one level from desired item
- return CdbSymbolGroupContext::completeData(m_symbolContext, incompleteLocal,
+ return CdbSymbolGroupContext::completeData(rctx, incompleteLocal,
WatchHandleDumperInserter(wh, m_dumper),
MatchINamePredicate(incompleteLocal.iname),
isDumperPredicate,
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
index 5d82835f53..ef854c8b36 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
@@ -33,15 +33,22 @@
#include "watchutils.h"
#include <QtCore/QTextStream>
+#include <QtCore/QCoreApplication>
#include <QtCore/QRegExp>
enum { debug = 0 };
+enum { debugInternalDumpers = 0 };
static inline QString msgSymbolNotFound(const QString &s)
{
return QString::fromLatin1("The symbol '%1' could not be found.").arg(s);
}
+static inline QString msgOutOfScope()
+{
+ return QCoreApplication::translate("SymbolGroup", "Out of scope");
+}
+
static inline bool isTopLevelSymbol(const DEBUG_SYMBOL_PARAMETERS &p)
{
return p.ParentSymbol == DEBUG_ANY_ID;
@@ -102,6 +109,16 @@ static inline QString getSymbolString(IDebugSymbolGroup2 *sg,
namespace Debugger {
namespace Internal {
+
+CdbSymbolGroupRecursionContext::CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx,
+ int ido,
+ CIDebugDataSpaces *ds) :
+ context(ctx),
+ internalDumperOwner(ido),
+ dataspaces(ds)
+{
+}
+
static inline CdbSymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMBOL_PARAMETERS &p)
{
if (p.SubElements == 0u)
@@ -419,6 +436,13 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const
return wd;
}
+WatchData CdbSymbolGroupContext::dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index)
+{
+ WatchData rc = symbolAt(index);
+ dump(ds, &rc);
+ return rc;
+}
+
bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &value,
QString *newValue, QString *errorMessage)
{
@@ -561,5 +585,189 @@ bool CdbSymbolGroupContext::debugValueToInteger(const DEBUG_VALUE &dv, qint64 *v
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,
+ * do not try to query further.
+ * > 1: A structural error was encountered, that is, the implementation
+ * of the class changed (Qt or say, a different STL implementation).
+ * Visibly warn about it.
+ * To add further types, have a look at the toString() output of the
+ * symbol group. */
+
+static QString msgStructuralError(const QString &type, int code)
+{
+ return QString::fromLatin1("Warning: Internal dumper for '%1' failed with %2.").arg(type).arg(code);
+}
+
+static inline bool isStdStringOrPointer(const QString &type)
+{
+#define STD_WSTRING "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >"
+#define STD_STRING "std::basic_string<char,std::char_traits<char>,std::allocator<char> >"
+ return type.endsWith(QLatin1String(STD_STRING))
+ || type.endsWith(QLatin1String(STD_STRING" *"))
+ || type.endsWith(QLatin1String(STD_WSTRING))
+ || type.endsWith(QLatin1String(STD_WSTRING" *"));
+#undef STD_WSTRING
+#undef STD_STRING
+}
+
+CdbSymbolGroupContext::DumperResult
+ CdbSymbolGroupContext::dump(CIDebugDataSpaces *ds, WatchData *wd)
+{
+ DumperResult rc = DumperNotHandled;
+ do {
+ // Is this a previously detected Null-Pointer?
+ if (wd->isHasChildrenKnown() && !wd->hasChildren)
+ break;
+ // QString
+ if (wd->type.endsWith(QLatin1String("QString")) || wd->type.endsWith(QLatin1String("QString *"))) {
+ const int drc = dumpQString(ds, wd);
+ switch (drc) {
+ case 0:
+ rc = DumperOk;
+ break;
+ case 1:
+ rc = DumperError;
+ break;
+ default:
+ qWarning("%s\n", qPrintable(msgStructuralError(wd->type, drc)));
+ rc = DumperNotHandled;
+ break;
+ }
+ }
+ // StdString
+ if (isStdStringOrPointer(wd->type)) {
+ const int drc = dumpStdString(wd);
+ switch (drc) {
+ case 0:
+ rc = DumperOk;
+ break;
+ case 1:
+ rc = DumperError;
+ break;
+ default:
+ qWarning("%s\n", qPrintable(msgStructuralError(wd->type, drc)));
+ rc = DumperNotHandled;
+ break;
+ }
+
+ }
+ } while (false);
+ if (debugInternalDumpers)
+ qDebug() << "CdbSymbolGroupContext::dump" << rc << wd->toString();
+ return rc;
+}
+
+// Get integer value of symbol group
+static inline bool getIntValue(CIDebugSymbolGroup *sg, int index, int *value)
+{
+ const QString valueS = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
+ bool ok;
+ *value = valueS.toInt(&ok);
+ return ok;
+}
+
+// Get pointer value of symbol group ("0xAAB")
+static inline bool getPointerValue(CIDebugSymbolGroup *sg, int index, quint64 *value)
+{
+ *value = 0;
+ QString valueS = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
+ if (!valueS.startsWith(QLatin1String("0x")))
+ return false;
+ valueS.remove(0, 2);
+ bool ok;
+ *value = valueS.toULongLong(&ok, 16);
+ return ok;
+}
+
+int CdbSymbolGroupContext::dumpQString(CIDebugDataSpaces *ds, WatchData *wd)
+{
+ const int maxLength = 40;
+ QString errorMessage;
+ unsigned long stringIndex;
+ if (!lookupPrefix(wd->iname, &stringIndex))
+ return 1;
+
+ // Expand string and it's "d" (step over 'static null')
+ if (!expandSymbol(wd->iname, stringIndex, &errorMessage))
+ return 2;
+ const unsigned long dIndex = stringIndex + 4;
+ if (!expandSymbol(wd->iname, dIndex, &errorMessage))
+ return 3;
+ const unsigned long sizeIndex = dIndex + 3;
+ const unsigned long arrayIndex = dIndex + 4;
+ // Get size and pointer
+ int size;
+ if (!getIntValue(m_symbolGroup, sizeIndex, &size))
+ return 4;
+ quint64 array;
+ if (!getPointerValue(m_symbolGroup, arrayIndex, &array))
+ return 5;
+ // Fetch
+ const bool truncated = size > maxLength;
+ if (truncated)
+ size = maxLength;
+ const QChar doubleQuote = QLatin1Char('"');
+ QString value(doubleQuote);
+ if (size) {
+ // Should this ever be a remote debugger, need to check byte order.
+ unsigned short *buf = new unsigned short[size + 1];
+ unsigned long bytesRead;
+ const HRESULT hr = ds->ReadVirtual(array, buf, size * sizeof(unsigned short), &bytesRead);
+ if (FAILED(hr)) {
+ delete [] buf;
+ return 1;
+ }
+ buf[bytesRead / sizeof(unsigned short)] = 0;
+ value += QString::fromUtf16(buf);
+ delete [] buf;
+ if (truncated)
+ value += QLatin1String("...");
+ }
+ value += doubleQuote;
+ wd->setValue(value);
+ wd->setHasChildren(false);
+ return 0;
+}
+
+int CdbSymbolGroupContext::dumpStdString(WatchData *wd)
+{
+ const int maxLength = 40;
+ QString errorMessage;
+ unsigned long stringIndex;
+ if (!lookupPrefix(wd->iname, &stringIndex))
+ return 1;
+
+ // Expand string ->string_val->_bx.
+ if (!expandSymbol(wd->iname, stringIndex, &errorMessage))
+ return 1;
+ const unsigned long bxIndex = stringIndex + 3;
+ if (!expandSymbol(wd->iname, bxIndex, &errorMessage))
+ return 2;
+ // Check if size is something sane
+ const int sizeIndex = stringIndex + 6;
+ int size;
+ if (!getIntValue(m_symbolGroup, sizeIndex, &size))
+ return 3;
+ if (size < 0)
+ return 1;
+ // Just copy over the value of the buf[]-array, which should be the string
+ const QChar doubleQuote = QLatin1Char('"');
+ const int bufIndex = stringIndex + 4;
+ QString bufValue = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, bufIndex);
+ const int quotePos = bufValue.indexOf(doubleQuote);
+ if (quotePos == -1)
+ return 1;
+ bufValue.remove(0, quotePos);
+ if (bufValue.size() > maxLength) {
+ bufValue.truncate(maxLength);
+ bufValue += QLatin1String("...\"");
+ }
+ wd->setValue(bufValue);
+ wd->setHasChildren(false);
+ return 0;
+}
+
} // namespace Internal
} // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
index 91ec5fd924..24fc355d37 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
@@ -46,6 +46,7 @@ namespace Internal {
class WatchData;
class WatchHandler;
+struct CdbSymbolGroupRecursionContext;
/* A thin wrapper around the IDebugSymbolGroup2 interface which represents
* a flat list of symbols using an index (for example, belonging to a stack
@@ -73,7 +74,7 @@ class CdbSymbolGroupContext
public:
~CdbSymbolGroupContext();
static CdbSymbolGroupContext *create(const QString &prefix,
- CIDebugSymbolGroup *symbolGroup,
+ CIDebugSymbolGroup *symbolGroup,
QString *errorMessage);
QString prefix() const { return m_prefix; }
@@ -87,7 +88,7 @@ public:
// to terminate processing after insertion of an item (if the calling
// routine wants to insert another subtree).
template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
- static bool populateModelInitially(CdbSymbolGroupContext *sg,
+ static bool populateModelInitially(const CdbSymbolGroupRecursionContext &ctx,
OutputIterator it,
RecursionPredicate recursionPredicate,
IgnorePredicate ignorePredicate,
@@ -99,7 +100,7 @@ public:
// to terminate processing after insertion of an item (if the calling
// routine wants to insert another subtree).
template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
- static bool completeData (CdbSymbolGroupContext *sg,
+ static bool completeData (const CdbSymbolGroupRecursionContext &ctx,
WatchData incompleteLocal,
OutputIterator it,
RecursionPredicate recursionPredicate,
@@ -108,9 +109,19 @@ public:
// Retrieve child symbols of prefix as a sequence of WatchData.
template <class OutputIterator>
- bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage);
+ bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage)
+ { return getDumpChildSymbols(0, prefix, 0, it, errorMessage); }
+ // Retrieve child symbols of prefix as a sequence of WatchData.
+ // Is CIDebugDataSpaces is != 0, try internal dumper and set owner
+ template <class OutputIterator>
+ bool getDumpChildSymbols(CIDebugDataSpaces *ds, const QString &prefix,
+ int dumpedOwner,
+ OutputIterator it, QString *errorMessage);
WatchData symbolAt(unsigned long index) const;
+ // Run the internal dumpers on the symbol
+ WatchData dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index);
+
bool lookupPrefix(const QString &prefix, unsigned long *index) const;
enum SymbolState { LeafSymbol, ExpandedSymbol, CollapsedSymbol };
@@ -127,6 +138,10 @@ public:
// 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);
+
private:
typedef QMap<QString, unsigned long> NameIndexMap;
@@ -140,8 +155,11 @@ private:
unsigned long *parentId,
QString *errorMessage);
bool expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage);
- void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count);
- QString symbolINameAt(unsigned long index) const;
+ void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count);
+ QString symbolINameAt(unsigned long index) const;
+
+ int dumpQString(CIDebugDataSpaces *ds, WatchData *wd);
+ int dumpStdString(WatchData *wd);
inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); }
@@ -155,6 +173,16 @@ private:
int m_unnamedSymbolNumber;
};
+
+// A convenience struct to save parameters for the model recursion.
+struct CdbSymbolGroupRecursionContext {
+ explicit CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx, int internalDumperOwner, CIDebugDataSpaces *ds);
+
+ CdbSymbolGroupContext *context;
+ int internalDumperOwner;
+ CIDebugDataSpaces *dataspaces;
+};
+
// Helper to a sequence of WatchData into a list.
class WatchDataBackInserter
{
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
index ccaba97ee8..561b0ac57b 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
@@ -48,18 +48,32 @@ enum { debugSgRecursion = 0 };
}
template <class OutputIterator>
-bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage)
+bool CdbSymbolGroupContext::getDumpChildSymbols(CIDebugDataSpaces *ds, const QString &prefix,
+ int dumpedOwner,
+ OutputIterator it, QString *errorMessage)
{
unsigned long start;
unsigned long parentId;
if (!getChildSymbolsPosition(prefix, &start, &parentId, errorMessage))
return false;
- // Skip over expanded children
- const unsigned long end = m_symbolParameters.size();
- for (unsigned long s = start; s < end; ++s) {
+ // Skip over expanded children. Internal dumping might expand
+ // children, so, re-evaluate size in end condition.
+ for (int s = start; s < m_symbolParameters.size(); ++s) {
const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(s);
if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) {
- *it = symbolAt(s);
+ WatchData wd = symbolAt(s);
+ // Run internal dumper, mark ownership
+ if (ds) {
+ switch (dump(ds, &wd)) {
+ case DumperOk:
+ case DumperError: // Not initialized yet, do not run other dumpers
+ wd.source = dumpedOwner;
+ break;
+ case DumperNotHandled:
+ break;
+ }
+ }
+ *it = wd;
++it;
}
}
@@ -73,7 +87,7 @@ bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterato
// (expand icon), though (ignore for simplicity).
template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
bool insertSymbolRecursion(WatchData wd,
- CdbSymbolGroupContext *sg,
+ const CdbSymbolGroupRecursionContext &ctx,
OutputIterator it,
RecursionPredicate recursionPredicate,
IgnorePredicate ignorePredicate,
@@ -110,13 +124,16 @@ bool insertSymbolRecursion(WatchData wd,
return true;
QList<WatchData> watchList;
// This implicitly enforces expansion
- if (!sg->getChildSymbols(wd.iname, WatchDataBackInserter(watchList), errorMessage))
+ if (!ctx.context->getDumpChildSymbols(ctx.dataspaces,
+ wd.iname,
+ ctx.internalDumperOwner,
+ WatchDataBackInserter(watchList), errorMessage))
return false;
const int childCount = watchList.size();
for (int c = 0; c < childCount; c++) {
const WatchData &cwd = watchList.at(c);
if (wd.isValid()) { // We sometimes get empty names for deeply nested data
- if (!insertSymbolRecursion(cwd, sg, it, recursionPredicate, ignorePredicate, errorMessage))
+ if (!insertSymbolRecursion(cwd, ctx, it, recursionPredicate, ignorePredicate, errorMessage))
return false;
} else {
const QString msg = QString::fromLatin1("WARNING: Skipping invalid child symbol #%2 (type %3) of '%4'.").
@@ -128,7 +145,7 @@ bool insertSymbolRecursion(WatchData wd,
}
template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
-bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
+bool CdbSymbolGroupContext::populateModelInitially(const CdbSymbolGroupRecursionContext &ctx,
OutputIterator it,
RecursionPredicate recursionPredicate,
IgnorePredicate ignorePredicate,
@@ -139,17 +156,20 @@ bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
// Insert root items
QList<WatchData> watchList;
- if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage))
+ CdbSymbolGroupContext *sg = ctx.context;
+ if (!sg->getDumpChildSymbols(ctx.dataspaces, sg->prefix(),
+ ctx.internalDumperOwner,
+ WatchDataBackInserter(watchList), errorMessage))
return false;
// Insert data
foreach(const WatchData &wd, watchList)
- if (!insertSymbolRecursion(wd, sg, it, recursionPredicate, ignorePredicate, errorMessage))
+ if (!insertSymbolRecursion(wd, ctx, it, recursionPredicate, ignorePredicate, errorMessage))
return false;
return true;
}
template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
-bool CdbSymbolGroupContext::completeData(CdbSymbolGroupContext *sg,
+bool CdbSymbolGroupContext::completeData(const CdbSymbolGroupRecursionContext &ctx,
WatchData incompleteLocal,
OutputIterator it,
RecursionPredicate recursionPredicate,
@@ -160,7 +180,7 @@ bool CdbSymbolGroupContext::completeData(CdbSymbolGroupContext *sg,
qDebug().nospace() << "###>CdbSymbolGroupContext::completeData" << ' ' << incompleteLocal.iname << '\n';
// If the symbols are already expanded in the context, they will be re-inserted,
// which is not handled for simplicity.
- if (!insertSymbolRecursion(incompleteLocal, sg, it, recursionPredicate, ignorePredicate, errorMessage))
+ if (!insertSymbolRecursion(incompleteLocal, ctx, it, recursionPredicate, ignorePredicate, errorMessage))
return false;
return true;
}
diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h
index 538eef992e..aca6527ce2 100644
--- a/src/plugins/debugger/stackhandler.h
+++ b/src/plugins/debugger/stackhandler.h
@@ -103,6 +103,7 @@ private:
struct ThreadData
{
+ ThreadData(int threadId = 0) : id(threadId) {}
int id;
};
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index 490fd2a64a..49b4cc02c5 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -567,21 +567,24 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
wchild.valuedisabled = dchild.valuedisabled;
wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
}
- wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
wchild.setAddress(dchild.address);
- // Child overrides.
- const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount;
- switch (effectiveChildChildCount) {
+ // The type setter sets hasChildren for known types.
+ wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
+ if (wchild.isHasChildrenNeeded()) {
+ // Child overrides.
+ const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount;
+ switch (effectiveChildChildCount) {
case -1:
- wchild.setChildrenNeeded();
- wchild.setHasChildrenNeeded();
- break;
+ wchild.setChildrenNeeded();
+ wchild.setHasChildrenNeeded();
+ break;
case 0:
- wchild.setHasChildren(false);
- break;
+ wchild.setHasChildren(false);
+ break;
default:
- wchild.setHasChildren(true);
- break;
+ wchild.setHasChildren(true);
+ break;
+ }
}
}
}