From 1fad39c9234839617470b3ff626d4e3f1311da1a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Fri, 2 Oct 2009 15:17:50 +0200 Subject: [PATCH] CDB: Fix dumper regression - Do not deref d-ptr when checking on QVariants of PODS - Make type/value fixing of dumper results more fine-grained - Allow children in expandPtrToDumpage (QWidget-Pointers) - Fix broken size cache (queuePrefix was empty) - Compile --- share/qtcreator/gdbmacros/gdbmacros.cpp | 28 ++++++++------- share/qtcreator/gdbmacros/test/main.cpp | 12 ++++++- .../debugger/cdb/cdbstackframecontext.cpp | 35 ++++++++++++------- .../debugger/cdb/cdbstacktracecontext.cpp | 3 +- src/plugins/debugger/watchutils.cpp | 3 +- 5 files changed, 53 insertions(+), 28 deletions(-) diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 59049f2673a..072a41c6b14 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -1177,7 +1177,7 @@ static void qDumpQAbstractItemModel(QDumper &d) static void qDumpQByteArray(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid const QByteArray &ba = *reinterpret_cast<const QByteArray *>(d.data); if (!ba.isEmpty()) { @@ -1461,7 +1461,7 @@ int hashOffset(bool optimizedIntKey, bool forKey, unsigned keySize, unsigned val static void qDumpQHash(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid const char *keyType = d.templateParameters[0]; const char *valueType = d.templateParameters[1]; @@ -1569,7 +1569,7 @@ static void qDumpQHashNode(QDumper &d) #if USE_QT_GUI static void qDumpQImage(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid const QImage &im = *reinterpret_cast<const QImage *>(d.data); d.beginItem("value"); d.put("(").put(im.width()).put("x").put(im.height()).put(")"); @@ -1611,7 +1611,7 @@ static void qDumpQImageData(QDumper &d) static void qDumpQList(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid // This uses the knowledge that QList<T> has only a single member // of type union { QListData p; QListData::Data *d; }; @@ -1691,7 +1691,7 @@ static void qDumpQList(QDumper &d) static void qDumpQLinkedList(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid // This uses the knowledge that QLinkedList<T> has only a single member // of type union { QLinkedListData *d; QLinkedListNode<T> *e; }; const QLinkedListData *ldata = @@ -1817,7 +1817,7 @@ static void qDumpQMapNode(QDumper &d) static void qDumpQMap(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid QMapData *h = *reinterpret_cast<QMapData *const*>(d.data); const char *keyType = d.templateParameters[0]; const char *valueType = d.templateParameters[1]; @@ -1956,7 +1956,7 @@ static void qDumpQModelIndex(QDumper &d) static void qDumpQObject(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid const QObject *ob = reinterpret_cast<const QObject *>(d.data); const QMetaObject *mo = ob->metaObject(); d.putItem("value", ob->objectName()); @@ -2206,7 +2206,7 @@ static void qDumpQVariant(QDumper &d, const QVariant *v) static inline void qDumpQVariant(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(d.data); qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data)); } @@ -2832,7 +2832,7 @@ static void qDumpQSharedPointer(QDumper &d) static void qDumpQString(QDumper &d) { - //qCheckAccess(deref(d.data)); + //qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid const QString &str = *reinterpret_cast<const QString *>(d.data); const int size = str.size(); @@ -2857,7 +2857,7 @@ static void qDumpQString(QDumper &d) static void qDumpQStringList(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid const QStringList &list = *reinterpret_cast<const QStringList *>(d.data); int n = list.size(); if (n < 0) @@ -2906,7 +2906,7 @@ static void qDumpQTextCodec(QDumper &d) static void qDumpQVector(QDumper &d) { - qCheckAccess(deref(d.data)); + qCheckAccess(deref(d.data)); // is the d-ptr de-referenceable and valid QVectorTypedData<int> *dummy = 0; const unsigned typeddatasize = (char*)(&dummy->array) - (char*)dummy; @@ -3810,7 +3810,11 @@ void *qDumpObjectData440( d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.innerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; - +#if 0 + qDebug() << "data=" << d.data << "dumpChildren=" << d.dumpChildren + << " extra=" << d.extraInt[0] << d.extraInt[1] << d.extraInt[2] << d.extraInt[3] + << d.outerType << d.iname << d.exp << d.iname; +#endif handleProtocolVersion2and3(d); } diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index b6be579ab38..28dea56f762 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -227,7 +227,17 @@ static int dumpQMapQStringString() static int dumpQVariant() { - QVariant test(QLatin1String("item")); + QVariant test = QLatin1String("item"); + prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", ""); + qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0); + fputs(qDumpOutBuffer, stdout); + fputs("\n\n", stdout); + test = QVariant(int(42)); + prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", ""); + qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0); + fputs(qDumpOutBuffer, stdout); + fputs("\n\n", stdout); + test = QVariant(double(3.141)); prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", ""); qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0); fputs(qDumpOutBuffer, stdout); diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index 76d5e00cf88..93ab11d75ef 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -128,21 +128,29 @@ WatchHandleDumperInserter::WatchHandleDumperInserter(WatchHandler *wh, Q_ASSERT(m_hexNullPattern.isValid()); } - // Prevent recursion of the model by setting value and type -static inline void fixDumperValueAndType(WatchData *wd, const WatchData *source = 0) -{ - static const QString unknown = QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"); - if (wd->isTypeNeeded() || wd->type.isEmpty()) { - wd->setType(source ? source->type : unknown); +static inline bool fixDumperType(WatchData *wd, const WatchData *source = 0) +{ + const bool missing = wd->isTypeNeeded() || wd->type.isEmpty(); + if (missing) { + static const QString unknownType = QCoreApplication::translate("CdbStackFrameContext", "<Unknown Type>"); + wd->setType(source ? source->type : unknownType); } - if (wd->isValueNeeded()) { + return missing; +} + +static inline bool fixDumperValue(WatchData *wd, const WatchData *source = 0) +{ + const bool missing = wd->isValueNeeded(); + if (missing) { if (source && source->isValueKnown()) { wd->setValue(source->value); } else { - wd->setValue(unknown); + static const QString unknownValue = QCoreApplication::translate("CdbStackFrameContext", "<Unknown Value>"); + wd->setValue(unknownValue); } } + return missing; } // When querying an item, the queried item is sometimes returned in incomplete form. @@ -160,7 +168,8 @@ static inline void fixDumperResult(const WatchData &source, WatchData &returned = result->front(); if (returned.iname != source.iname) return; - fixDumperValueAndType(&returned, &source); + fixDumperType(&returned, &source); + fixDumperValue(&returned, &source); // Indicate owner and known children returned.source = OwnerDumper; if (returned.isChildrenKnown() && returned.isHasChildrenKnown() && returned.hasChildren) @@ -179,7 +188,9 @@ static inline void fixDumperResult(const WatchData &source, it->source = OwnerDumper; if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren) it->source |= CdbStackFrameContext::ChildrenKnownBit; - if (wd.addr.isEmpty() && wd.isSomethingNeeded()) { + // Cannot dump items with missing addresses or missing types + const bool typeFixed = fixDumperType(&wd); // Order of evaluation! + if ((wd.addr.isEmpty() && wd.isSomethingNeeded()) || typeFixed) { wd.setHasChildren(false); wd.setAllUnneeded(); } else { @@ -188,8 +199,6 @@ static inline void fixDumperResult(const WatchData &source, if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded())) wd.setHasChildren(false); } - // <Out of scope value> have sometimes missing types. Kill recursion - fixDumperValueAndType(&wd); } if (debugCDBWatchHandling) debugWatchDataList(*result, "<fixDumperResult"); @@ -226,7 +235,7 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, &m_dumperResult, errorMessage); if (dr != CdbDumperHelper::DumpOk) break; - fixDumperResult(derefedWd, &m_dumperResult, true); + fixDumperResult(derefedWd, &m_dumperResult, false); // Insert the pointer item with 1 additional child + its dumper results // Note: formal arguments might already be expanded in the symbol group. WatchData ptrWd = wd; diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 6cdaf627092..40cd9776bcb 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -86,7 +86,8 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa // 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); + StackFrame frame; + frame.level = i; const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset; if (i == 0) m_instructionOffset = instructionOffset; diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 8208cb4fcf1..a494c0d7000 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -560,7 +560,7 @@ QString QtDumperHelper::toString(bool debug) const str << "\nSize cache: "; const SizeCache::const_iterator scend = m_sizeCache.constEnd(); for (SizeCache::const_iterator it = m_sizeCache.constBegin(); it != scend; ++it) { - str << ' ' << it.key() << '=' << it.value(); + str << ' ' << it.key() << '=' << it.value() << '\n'; } str << "\nExpression cache: (" << m_expressionCache.size() << ")\n"; const QMap<QString, QString>::const_iterator excend = m_expressionCache.constEnd(); @@ -888,6 +888,7 @@ void QtDumperHelper::setQClassPrefixes(const QString &qNamespace) m_qListPrefix = qClassName(qNamespace, "QList"); m_qLinkedListPrefix = qClassName(qNamespace, "QLinkedList"); m_qVectorPrefix = qClassName(qNamespace, "QVector"); + m_qQueuePrefix = qClassName(qNamespace, "QQueue"); } static inline double getDumperVersion(const GdbMi &contents) -- GitLab