diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 07fd6c4b5be9f8880525fe2e368cce47cb183339..ac7d5303925ac50df1ef4cbe697f2ccc10c36472 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -34,6 +34,7 @@ #include <utils/qtcassert.h> #include <QtCore/QDebug> +#include <QtCore/QTextStream> #include <QtCore/QFileInfo> using namespace Debugger; @@ -191,23 +192,25 @@ void BreakpointData::updateMarker() QString BreakpointData::toToolTip() const { - QString str; - str += "<table>"; - str += "<tr><td>Marker File:</td><td>" + markerFileName + "</td></tr>"; - str += "<tr><td>Marker Line:</td><td>" + QString::number(markerLineNumber) + "</td></tr>"; - str += "<tr><td>BP Number:</td><td>" + bpNumber + "</td></tr>"; - str += "<tr><td>BP Address:</td><td>" + bpAddress + "</td></tr>"; - str += "<tr><td>----------</td><td></td><td></td></tr>"; - str += "<tr><td>Property:</td><td>Wanted:</td><td>Actual:</td></tr>"; - str += "<tr><td></td><td></td><td></td></tr>"; - str += "<tr><td>Internal Number:</td><td>-</td><td>" + bpNumber + "</td></tr>"; - str += "<tr><td>File Name:</td><td>" + fileName + "</td><td>" + bpFileName + "</td></tr>"; - str += "<tr><td>Function Name:</td><td>" + funcName + "</td><td>" + bpFuncName + "</td></tr>"; - str += "<tr><td>Line Number:</td><td>" + lineNumber + "</td><td>" + bpLineNumber + "</td></tr>"; - str += "<tr><td>Condition:</td><td>" + condition + "</td><td>" + bpCondition + "</td></tr>"; - str += "<tr><td>Ignore count:</td><td>" + ignoreCount + "</td><td>" + bpIgnoreCount + "</td></tr>"; - str += "</table>"; - return str; + QString rc; + QTextStream str(&rc); + str << "<html><body><table>"; + str << "<tr><td>" << BreakHandler::tr("Marker File:") << "</td><td>" << markerFileName << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("Marker Line:") << "</td><td>" << markerLineNumber << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("Breakpoint Number:") << "</td><td>" << bpNumber << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("Breakpoint Address:") << "</td><td>" << bpAddress << "</td></tr>"; + str << "</table><br><hr><table>"; + str << "<tr><th>" << BreakHandler::tr("Property") + << "</th><th>" << BreakHandler::tr("Requested") + << "</th><th>" << BreakHandler::tr("Obtained") << "</th></tr>"; + str << "<tr><td>" << BreakHandler::tr("Internal Number:") << "</td><td>—</td><td>" << bpNumber << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("File Name:") << "</td><td>" << fileName << "</td><td>" << bpFileName << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("Function Name:") << "</td><td>" << funcName << "</td><td>" << bpFuncName << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("Line Number:") << "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("Condition:") << "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>"; + str << "<tr><td>" << BreakHandler::tr("Ignore Count:") << "</td><td>" << ignoreCount << "</td><td>" << bpIgnoreCount << "</td></tr>"; + str << "</table></body></html>"; + return rc; } bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) const @@ -524,6 +527,22 @@ bool BreakHandler::setData(const QModelIndex &mi, const QVariant &value, int rol } } +void BreakHandler::append(BreakpointData *data) +{ + m_bp.append(data); + m_inserted.append(data); +} + +QList<BreakpointData *> BreakHandler::insertedBreakpoints() const +{ + return m_inserted; +} + +void BreakHandler::takeInsertedBreakPoint(BreakpointData *d) +{ + m_inserted.removeAll(d); +} + QList<BreakpointData *> BreakHandler::takeRemovedBreakpoints() { QList<BreakpointData *> result = m_removed; diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 4c8a9203ee16ab6a6c49be0719be02a557e797b3..0f2cef63b26144fad5b172503a11d17f339f58fa 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -123,7 +123,7 @@ public: BreakpointData *at(int index) const { return index < size() ? m_bp.at(index) : 0; } int size() const { return m_bp.size(); } bool hasPendingBreakpoints() const; - void append(BreakpointData *data) { m_bp.append(data); } + void append(BreakpointData *data); void removeAt(int index); // also deletes the marker void clear(); // also deletes all the marker int indexOf(BreakpointData *data) { return m_bp.indexOf(data); } @@ -132,6 +132,8 @@ public: int findBreakpoint(int bpNumber); // returns index void updateMarkers(); + QList<BreakpointData *> insertedBreakpoints() const; + void takeInsertedBreakPoint(BreakpointData *); QList<BreakpointData *> takeRemovedBreakpoints(); // owned QList<BreakpointData *> takeEnabledBreakpoints(); // not owned QList<BreakpointData *> takeDisabledBreakpoints(); // not owned @@ -171,6 +173,7 @@ private: void removeBreakpointHelper(int index); QList<BreakpointData *> m_bp; + QList<BreakpointData *> m_inserted; // lately inserted breakpoints QList<BreakpointData *> m_removed; // lately removed breakpoints QList<BreakpointData *> m_enabled; // lately enabled breakpoints QList<BreakpointData *> m_disabled; // lately disabled breakpoints diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp index 2824a57e5c40ab35c060955fb098b56b22c61a3e..4418fad1e204d63d7f78dbb36c7a4f3dcd8da0cc 100644 --- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp +++ b/src/plugins/debugger/cdb/cdbbreakpoint.cpp @@ -37,6 +37,8 @@ #include <QtCore/QDebug> #include <QtCore/QMap> +enum { debugBP = 0 }; + namespace Debugger { namespace Internal { @@ -49,17 +51,19 @@ static const char sourceFileQuoteC = '`'; CDBBreakPoint::CDBBreakPoint() : ignoreCount(0), lineNumber(-1), - oneShot(false) + oneShot(false), + enabled(true) { } CDBBreakPoint::CDBBreakPoint(const BreakpointData &bpd) : - fileName(bpd.fileName), + fileName(QDir::toNativeSeparators(bpd.fileName)), condition(bpd.condition), ignoreCount(0), funcName(bpd.funcName), lineNumber(-1), - oneShot(false) + oneShot(false), + enabled(bpd.enabled) { if (!bpd.ignoreCount.isEmpty()) ignoreCount = bpd.ignoreCount.toInt(); @@ -81,6 +85,10 @@ int CDBBreakPoint::compare(const CDBBreakPoint& rhs) const return 1; if (!oneShot && rhs.oneShot) return -1; + if (enabled && !rhs.enabled) + return 1; + if (!enabled && rhs.enabled) + return -1; if (const int fileCmp = fileName.compare(rhs.fileName)) return fileCmp; if (const int funcCmp = funcName.compare(rhs.funcName)) @@ -94,6 +102,7 @@ void CDBBreakPoint::clear() { ignoreCount = 0; oneShot = false; + enabled = true; clearExpressionData(); } @@ -117,6 +126,8 @@ QDebug operator<<(QDebug dbg, const CDBBreakPoint &bp) nsp << " condition='" << bp.condition << '\''; if (bp.ignoreCount) nsp << " ignoreCount=" << bp.ignoreCount; + if (bp.enabled) + nsp << " enabled"; if (bp.oneShot) nsp << " oneShot"; return dbg; @@ -153,27 +164,48 @@ bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const } // Pass Count is ignoreCount + 1 ibp->SetPassCount(ignoreCount + 1u); - ULONG flags = DEBUG_BREAKPOINT_ENABLED; + ULONG flags = 0; + if (enabled) + flags |= DEBUG_BREAKPOINT_ENABLED; if (oneShot) flags |= DEBUG_BREAKPOINT_ONE_SHOT; ibp->AddFlags(flags); return true; } -bool CDBBreakPoint::add(CIDebugControl* debugControl, QString *errorMessage) const +static inline QString msgCannotAddBreakPoint(const QString &why) +{ + return QString::fromLatin1("Unable to add breakpoint: %1").arg(why); +} + +bool CDBBreakPoint::add(CIDebugControl* debugControl, + quint64 *address, unsigned long *id, + QString *errorMessage) const { IDebugBreakpoint2* ibp = 0; - const HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp); + *address = 0; + *id = 0; + HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp); if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Unable to add breakpoint: %1"). - arg(msgComFailed("AddBreakpoint2", hr)); + *errorMessage = msgCannotAddBreakPoint(msgComFailed("AddBreakpoint2", hr)); return false; } if (!ibp) { - *errorMessage = QString::fromLatin1("Unable to add breakpoint: <Unknown error>"); + *errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>")); + return false; + } + if (!apply(ibp, errorMessage)) + return false; + // GetOffset can fail when attaching to remote processes. + hr = ibp->GetOffset(address); + if (FAILED(hr)) + *address = 0; + hr = ibp->GetId(id); + if (FAILED(hr)) { + *errorMessage = msgCannotAddBreakPoint(msgComFailed("GetId", hr)); return false; } - return apply(ibp, errorMessage); + return true; } // Make sure file can be found in editor manager and text markers @@ -204,8 +236,8 @@ bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage) ignoreCount--; ULONG flags = 0; ibp->GetFlags(&flags); - if (flags & DEBUG_BREAKPOINT_ONE_SHOT) - oneShot = true; + oneShot = (flags & DEBUG_BREAKPOINT_ONE_SHOT); + enabled = (flags & DEBUG_BREAKPOINT_ENABLED); const QString expr = QString::fromUtf16(wszBuf); if (!parseExpression(expr)) { *errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr); @@ -296,31 +328,107 @@ bool CDBBreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<CDBBreakP return true; } +// Find a breakpoint by id +static inline QString msgNoBreakPointWithId(unsigned long id, const QString &why) +{ + return QString::fromLatin1("Unable to find breakpoint with id %1: %2").arg(id).arg(why); +} + +static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage) +{ + CIDebugBreakpoint *ibp = 0; + const HRESULT hr = ctl->GetBreakpointById2(id, &ibp); + if (FAILED(hr)) { + *errorMessage = msgNoBreakPointWithId(id, msgComFailed("GetBreakpointById2", hr)); + return 0; + } + if (!ibp) { + *errorMessage = msgNoBreakPointWithId(id, QLatin1String("<not found>")); + return 0; + } + return ibp; +} + +// Remove breakpoint by id +static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage) +{ + if (debugBP) + qDebug() << Q_FUNC_INFO << id; + CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage); + if (!ibp) + 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)); + return false; + } + return true; +} + +// Set enabled by id + +// Change enabled state of a breakpoint by id +static inline QString msgCannotSetBreakPointEnabled(unsigned long id, bool enabled, const QString &why) +{ + return QString::fromLatin1("Cannot %1 breakpoint %2: %3"). + arg(QLatin1String(enabled ? "enable" : "disable")).arg(id).arg(why); +} + +static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage) +{ + if (debugBP) + qDebug() << Q_FUNC_INFO << id << enabled; + CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage); + if (!ibp) { + *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, *errorMessage); + return false; + } + // Compare flags + ULONG flags; + HRESULT hr = ibp->GetFlags(&flags); + if (FAILED(hr)) { + *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("GetFlags", hr)); + return false; + } + const bool wasEnabled = (flags & DEBUG_BREAKPOINT_ENABLED); + if (wasEnabled == enabled) + return true; + // Set new value + if (enabled) { + flags |= DEBUG_BREAKPOINT_ENABLED; + } else { + flags &= ~DEBUG_BREAKPOINT_ENABLED; + } + hr = ibp->SetFlags(flags); + if (FAILED(hr)) { + *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, msgComFailed("SetFlags", hr)); + return false; + } + return true; +} // Synchronize (halted) engine breakpoints with those of the BreakHandler. -bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl, - IDebugSymbols3 *syms, +bool CDBBreakPoint::synchronizeBreakPoints(CIDebugControl* debugControl, + CIDebugSymbols *syms, BreakHandler *handler, QString *errorMessage) { - typedef QMap<CDBBreakPoint, int> BreakPointIndexMap; - if (debugCDB) - qDebug() << Q_FUNC_INFO; - - BreakPointIndexMap breakPointIndexMap; - // convert BreakHandler's bps into a map of BreakPoint->BreakHandler->Index - // Ignore invalid functions (that could not be found) as they make - // the debugger hang. - const int handlerCount = handler->size(); - const QChar moduleDelimiter = QLatin1Char('!'); - for (int i=0; i < handlerCount; ++i) { - BreakpointData *bd = handler->at(i); + // Do an initial check whether we are in a state that allows + // for modifying breakPoints + ULONG engineCount; + if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) { + *errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage); + return false; + } + // Insert new ones + bool updateMarkers = false; + foreach (BreakpointData *nbd, handler->insertedBreakpoints()) { // Function breakpoints: Are the module names specified? bool breakPointOk = false; - if (bd->funcName.isEmpty()) { + if (nbd->funcName.isEmpty()) { breakPointOk = true; } else { - switch (resolveSymbol(syms, &bd->funcName, errorMessage)) { + switch (resolveSymbol(syms, &nbd->funcName, errorMessage)) { case ResolveSymbolOk: breakPointOk = true; break; @@ -334,66 +442,49 @@ bool CDBBreakPoint::synchronizeBreakPoints(IDebugControl4* debugControl, break; }; } // function breakpoint - if (breakPointOk) - breakPointIndexMap.insert(CDBBreakPoint(*bd), i); - } - errorMessage->clear(); - // get number of engine breakpoints - ULONG engineCount; - if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) - return false; - - // Starting from end, check if engine breakpoints are still in handler. - // If not->remove - if (engineCount) { - for (ULONG eb = engineCount - 1u; ; eb--) { - // get engine breakpoint. - IDebugBreakpoint2 *ibp = 0; - HRESULT hr = debugControl->GetBreakpointByIndex2(eb, &ibp); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2"). - arg(eb).arg(msgComFailed("GetBreakpointByIndex2", hr)); - return false; + // Now add... + if (breakPointOk) { + quint64 address; + unsigned long id; + CDBBreakPoint ncdbbp(*nbd); + breakPointOk = ncdbbp.add(debugControl, &address, &id, errorMessage); + if (breakPointOk) { + if (debugBP) + qDebug() << "Added " << id << " at " << address << ncdbbp; + handler->takeInsertedBreakPoint(nbd); + updateMarkers = true; + nbd->pending = false; + nbd->bpNumber = QString::number(id); + nbd->bpAddress = QLatin1String("0x") + QString::number(address, 16); + // Take over rest as is + nbd->bpCondition = nbd->condition; + nbd->bpIgnoreCount = nbd->ignoreCount; + nbd->bpFileName = nbd->fileName; + nbd->bpLineNumber = nbd->lineNumber; + nbd->bpFuncName = nbd->funcName; } - // Ignore one shot break points set by "Step out" - ULONG flags = 0; - hr = ibp->GetFlags(&flags); - if (!(flags & DEBUG_BREAKPOINT_ONE_SHOT)) { - CDBBreakPoint engineBreakPoint; - if (!engineBreakPoint.retrieve(ibp, errorMessage)) - return false; - // Still in handler? - if (!breakPointIndexMap.contains(engineBreakPoint)) { - if (debugCDB) - qDebug() << " Removing" << engineBreakPoint; - hr = debugControl->RemoveBreakpoint2(ibp); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2"). - arg(engineBreakPoint.expression(), msgComFailed("RemoveBreakpoint2", hr)); - return false; - } - } // not in handler - } // one shot - if (!eb) - break; - } + } // had symbol + if (!breakPointOk) + qWarning("%s\n", qPrintable(*errorMessage)); } - // Add pending breakpoints - const BreakPointIndexMap::const_iterator pcend = breakPointIndexMap.constEnd(); - for (BreakPointIndexMap::const_iterator it = breakPointIndexMap.constBegin(); it != pcend; ++it) { - const int index = it.value(); - if (handler->at(index)->pending) { - if (debugCDB) - qDebug() << " Adding " << it.key(); - if (it.key().add(debugControl, errorMessage)) { - handler->at(index)->pending = false; - } else { - const QString msg = QString::fromLatin1("Failed to add breakpoint '%1': %2").arg(it.key().expression(), *errorMessage); - qWarning("%s\n", qPrintable(msg)); - } - } + // Delete + foreach (BreakpointData *rbd, handler->takeRemovedBreakpoints()) { + if (!removeBreakPointById(debugControl, rbd->bpNumber.toUInt(), errorMessage)) + qWarning("%s\n", qPrintable(*errorMessage)); + delete rbd; } - if (debugCDB > 1) { + // Enable/Disable + foreach (BreakpointData *ebd, handler->takeEnabledBreakpoints()) + if (!setBreakPointEnabledById(debugControl, ebd->bpNumber.toUInt(), true, errorMessage)) + qWarning("%s\n", qPrintable(*errorMessage)); + foreach (BreakpointData *dbd, handler->takeDisabledBreakpoints()) + if (!setBreakPointEnabledById(debugControl, dbd->bpNumber.toUInt(), false, errorMessage)) + qWarning("%s\n", qPrintable(*errorMessage)); + + if (updateMarkers) + handler->updateMarkers(); + + if (debugBP > 1) { QList<CDBBreakPoint> bps; CDBBreakPoint::getBreakPoints(debugControl, &bps, errorMessage); qDebug().nospace() << "### Breakpoints in engine: " << bps; diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.h b/src/plugins/debugger/cdb/cdbbreakpoint.h index 9ee7ef8d860df2aa1c0cb2f191fb1b7103b57d00..7ef4ebe67e699cc5e567cc5cea96323b96538acf 100644 --- a/src/plugins/debugger/cdb/cdbbreakpoint.h +++ b/src/plugins/debugger/cdb/cdbbreakpoint.h @@ -63,7 +63,7 @@ struct CDBBreakPoint // Apply parameters bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const; // Convenience to add to a IDebugControl4 - bool add(CIDebugControl* debugControl, QString *errorMessage) const; + bool add(CIDebugControl* debugControl, quint64 *address, unsigned long *id, QString *errorMessage) const; // Retrieve/parse breakpoints from the interfaces bool retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage); @@ -84,6 +84,7 @@ struct CDBBreakPoint int lineNumber; // line in source file QString funcName; // name of containing function bool oneShot; + bool enabled; }; QDebug operator<<(QDebug, const CDBBreakPoint &bp); @@ -92,9 +93,6 @@ inline bool operator==(const CDBBreakPoint& b1, const CDBBreakPoint& b2) { return b1.compare(b2) == 0; } inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2) { return b1.compare(b2) != 0; } -inline bool operator<(const CDBBreakPoint& b1, const CDBBreakPoint& b2) - { return b1.compare(b2) < 0; } - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index fd59bd0fa6be95d4ca2d4d2a2b787783f8c1168a..48072bf2c2d3321027e8c0ce321ce2aead88fbdb 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -135,9 +135,11 @@ bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *err qDebug() << "populateModelInitially"; const bool rc = m_useDumpers ? CdbSymbolGroupContext::populateModelInitially(m_symbolContext, - WatchHandlerSorterInserter(wh, m_dumper), + wh->expandedINames(), + WatchHandlerSorterInserter(wh, m_dumper), errorMessage) : CdbSymbolGroupContext::populateModelInitially(m_symbolContext, + wh->expandedINames(), WatchHandlerModelInserter(wh), errorMessage); return rc; diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index f3bf01df2567e0b49a6a8db0d9fe0f1565bc9642..25931005ddd43c4a3437cd2ca0ea94cc463469d5 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -213,11 +213,23 @@ CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(const QStr { if (prefix == m_prefix) // root return ExpandedSymbol; + unsigned long index; + if (!lookupPrefix(prefix, &index)) { + qWarning("WARNING %s: %s\n", Q_FUNC_INFO, msgSymbolNotFound(prefix)); + return LeafSymbol; + } + return symbolState(index); +} + +// Find index of a prefix +bool CdbSymbolGroupContext::lookupPrefix(const QString &prefix, unsigned long *index) const +{ + *index = 0; const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix); - if (it != m_inameIndexMap.constEnd()) - return symbolState(it.value()); - qWarning("WARNING %s: %s\n", Q_FUNC_INFO, msgSymbolNotFound(prefix)); - return LeafSymbol; + if (it == m_inameIndexMap.constEnd()) + return false; + *index = it.value(); + return true; } /* Retrieve children and get the position. */ diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index ea992e546cfa898093eec84bd3563f0cd5f1d27f..bfd5ecd3b98aae91b563148c94b8fe737d169e9a 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -39,6 +39,7 @@ #include <QtCore/QStringList> #include <QtCore/QPair> #include <QtCore/QMap> +#include <QtCore/QSet> namespace Debugger { namespace Internal { @@ -74,7 +75,9 @@ public: QString *newValue /* = 0 */, QString *errorMessage); template <class OutputIterator> - static bool populateModelInitially(CdbSymbolGroupContext *sg, OutputIterator it, QString *errorMessage); + static bool populateModelInitially(CdbSymbolGroupContext *sg, + QSet<QString> expandedINames, + OutputIterator it, QString *errorMessage); template <class OutputIterator> static bool completeModel(CdbSymbolGroupContext *sg, @@ -116,6 +119,7 @@ private: void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count); WatchData symbolAt(unsigned long index) const; QString symbolINameAt(unsigned long index) const; + bool lookupPrefix(const QString &prefix, unsigned long *index) const; int getDisplayableChildCount(unsigned long index) const; inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); } diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h index 9a2f992bf47b46ba5a7695d560126ffac88db04f..52777a2f6b956c58bdcace83192f856add6dc079 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h @@ -154,6 +154,7 @@ template <class OutputIterator> template <class OutputIterator> bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, + QSet<QString> expandedINames, OutputIterator it, QString *errorMessage) { @@ -164,7 +165,26 @@ bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, QList<WatchData> watchList; if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage)) return false; - + // (Recursively) expand symbols stored as expanded in the history until no more matches + // are found. + while (!expandedINames.empty()) { + unsigned matchCount = 0; + for (QSet<QString>::iterator it = expandedINames.begin(); it != expandedINames.end(); ) { + // Try to expand. We might hit on a leaf due to name mismatches, ignore errors. + unsigned long index; + if (sg->lookupPrefix(*it, &index)) { + if (!sg->expandSymbol(*it, index, errorMessage)) + qWarning("%s\n", qPrintable(*errorMessage)); + matchCount++; + it = expandedINames.erase(it); + } else { + ++it; + } + } // loop set + if (matchCount == 0) + break; + } + // Insert data foreach(const WatchData &wd, watchList) if (!insertSymbolRecursion(wd, sg, it, 0, 0, errorMessage)) return false; diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index ed565044b29f847507bdf5305dd822b08727020c..aaefbe6f8cc70925844bc6230b30b5d669ad3f48 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -181,6 +181,8 @@ public: { return m_displayedINames.contains(iname); } bool isExpandedIName(const QString &iname) const { return m_expandedINames.contains(iname); } + QSet<QString> expandedINames() const + { return m_expandedINames; } void insertData(const WatchData &data); QList<WatchData> takeCurrentIncompletes();