diff options
author | Friedemann Kleint <[email protected]> | 2009-07-06 17:36:50 +0200 |
---|---|---|
committer | Friedemann Kleint <[email protected]> | 2009-07-06 17:36:50 +0200 |
commit | 5bd1d2a0284d90bda180a18f45d48018999fff9b (patch) | |
tree | d7cc5705c937374879610838bd9952129101d904 /src/plugins/debugger/watchutils.cpp | |
parent | 45448ce5d51c9b33d2e02c24d9bd3b52526caf16 (diff) |
Fix up Debugger helpers to be able to dump QObject's with CDB.
- Make container dumper routines set "childnumchild" when known
in order to avoid roundtrips; avoid repeated invocations of
container.end().
- Completed dumper information in some places to avoid roundtrips.
- Extended QVariant helpers by dumpers for common GUI types
(rectangles, points, sizes, fonts, size policies).
- Introduced artificial QObjectChildList/QObjectProperty types to
be able to dump QObject children and properties without using
gdb expressions.
- Fixed dumping of Signal/Slot list to pass on correct types. Avoid
recursions if signal is connected to self.
- Replaced expressions by addresses in the dumpers to it make work
for CDB.
- Reworked dumper test program to have -a, making it usable for tests,
add further types.
- Gdb: Clear output buffer before calling dumpers, avoiding mixups
in case evaluation of expression fails.
- Fix the dumper parser used by CDB, do not be fooled by
"<synthetic>" addresses, etc.
- Pass on a "dumperVersion" in initial query.
Diffstat (limited to 'src/plugins/debugger/watchutils.cpp')
-rw-r--r-- | src/plugins/debugger/watchutils.cpp | 192 |
1 files changed, 124 insertions, 68 deletions
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 5ef9523ed45..555b6ac6cd4 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -470,16 +470,19 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, QtDumperResult::Child::Child() : keyEncoded(0), valueEncoded(0), - childCount(0), - valuedisabled(false) + childCount(-1), + valuedisabled(false), + valueEncountered(false) { } QtDumperResult::QtDumperResult() : + valueEncountered(false), valueEncoded(0), valuedisabled(false), - childCount(0), - internal(false) + childCount(-1), + internal(false), + childChildCount(-1) { } @@ -488,15 +491,17 @@ void QtDumperResult::clear() iname.clear(); value.clear(); address.clear(); + addressInfo.clear(); type.clear(); extra.clear(); displayedType.clear(); valueEncoded = 0; - valuedisabled = false; - childCount = 0; + valueEncountered = valuedisabled = false; + childCount = -1; internal = false; childType.clear(); children.clear(); + childChildCount = -1; } QList<WatchData> QtDumperResult::toWatchData(int source) const @@ -508,45 +513,70 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const const QChar dot = QLatin1Char('.'); const int lastDotIndex = root.iname.lastIndexOf(dot); root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1); - root.setValue(decodeData(value, valueEncoded)); + if (valueEncountered) { + root.setValue(decodeData(value, valueEncoded)); + root.valuedisabled = valuedisabled; + } root.setType(displayedType.isEmpty() ? type : displayedType); - root.valuedisabled = valuedisabled; root.setAddress(address); root.source = source; - root.setHasChildren(childCount > 0); - // Children - if (childCount > 0) { - if (children.size() == childCount) { - for (int c = 0; c < childCount; c++) { - const Child &dchild = children.at(c); - rc.push_back(WatchData()); - WatchData &wchild = rc.back(); - wchild.source = source; - wchild.iname = iname; - wchild.iname += dot; - wchild.iname += dchild.name; - // Use key entry as name (which is used for map nodes) - if (dchild.key.isEmpty()) { - wchild.name = dchild.name; - } else { - wchild.name = decodeData(dchild.key, dchild.keyEncoded); - if (wchild.name.size() > 13) { - wchild.name.truncate(12); - wchild.name += QLatin1String("..."); - } + if (childCount >= 0) + root.setHasChildren(childCount > 0); + // Children. Sanity check after parsing sets childcount to list size + // if list is not empty + if (children.empty()) { + if (childCount > 0) + root.setChildrenNeeded(); + } else { + root.setChildrenUnneeded(); + for (int c = 0; c < childCount; c++) { + const Child &dchild = children.at(c); + rc.push_back(WatchData()); + WatchData &wchild = rc.back(); + wchild.source = source; + wchild.iname = iname; + wchild.iname += dot; + wchild.iname += dchild.name; + // Use key entry as name (which is used for map nodes) + if (dchild.key.isEmpty()) { + wchild.name = dchild.name; + } else { + wchild.name = decodeData(dchild.key, dchild.keyEncoded); + if (wchild.name.size() > 13) { + wchild.name.truncate(12); + wchild.name += QLatin1String("..."); } - wchild.exp = dchild.exp; + } + wchild.exp = dchild.exp; + if (dchild.valueEncountered) { wchild.valuedisabled = dchild.valuedisabled; - wchild.setType(dchild.type.isEmpty() ? childType : dchild.type); - wchild.setAddress(dchild.address); 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) { + case -1: + wchild.setChildrenNeeded(); + wchild.setHasChildrenNeeded(); + break; + case 0: wchild.setHasChildren(false); + break; + default: + wchild.setHasChildren(true); + break; } - root.setChildrenUnneeded(); - } else { - root.setChildrenNeeded(); } } + if (debug) { + QDebug nospace = qDebug().nospace(); + nospace << "QtDumperResult::toWatchData" << *this << '\n'; + foreach(const WatchData &wd, rc) + nospace << " " << wd.toString() << '\n'; + } + return rc; } @@ -554,11 +584,20 @@ QDebug operator<<(QDebug in, const QtDumperResult &d) { QDebug nospace = in.nospace(); nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType - << " address=" << d.address - << " value=" << d.value - << " disabled=" << d.valuedisabled - << " encoded=" << d.valueEncoded << " internal=" << d.internal + << " address=" << d.address; + if (!d.addressInfo.isEmpty()) + nospace << " addressInfo=" << d.addressInfo; + if (d.valueEncountered) { + nospace << " encoded=" << d.valueEncoded + << " value=" << d.value + << " disabled=" << d.valuedisabled; + } else { + nospace << " <no value>"; + } + nospace << " childnumchild=" << d.childChildCount + << " internal=" << d.internal << " extra='" << d.extra << "'\n"; + const int realChildCount = d.children.size(); if (d.childCount || realChildCount) { nospace << "childCount=" << d.childCount << '/' << realChildCount @@ -571,8 +610,12 @@ QDebug operator<<(QDebug in, const QtDumperResult &d) << " name=" << c.name; if (!c.key.isEmpty()) nospace << " keyencoded=" << c.keyEncoded << " key=" << c.key; - nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value - << "childcount=" << c.childCount << '\n'; + if (c.valueEncountered) { + nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value; + } else { + nospace << " <no value>"; + } + nospace << "childcount=" << c.childCount << '\n'; } } return in; @@ -608,6 +651,7 @@ void QtDumperHelper::clear() m_sizeCache.clear(); qFill(m_specialSizes, m_specialSizes + SpecialSizeCount, 0); m_expressionCache.clear(); + m_dumperVersion.clear(); } static inline void formatQtVersion(int v, QTextStream &str) @@ -622,7 +666,7 @@ QString QtDumperHelper::toString(bool debug) const QTextStream str(&rc); str << "version="; formatQtVersion(m_qtVersion, str); - str << " namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: "; + str << "dumperversion='" << m_dumperVersion << "' namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: "; const NameTypeMap::const_iterator cend = m_nameTypeMap.constEnd(); for (NameTypeMap::const_iterator it = m_nameTypeMap.constBegin(); it != cend; ++it) { str <<",[" << it.key() << ',' << it.value() << ']'; @@ -639,9 +683,9 @@ QString QtDumperHelper::toString(bool debug) const } const QString nameSpace = m_qtNamespace.isEmpty() ? QCoreApplication::translate("QtDumperHelper", "<none>") : m_qtNamespace; return QCoreApplication::translate("QtDumperHelper", - "%n known types, Qt version: %1, Qt namespace: %2", + "%n known types, Qt version: %1, Qt namespace: %2 Dumper version: %3", 0, QCoreApplication::CodecForTr, - m_nameTypeMap.size()).arg(qtVersionString(), nameSpace); + m_nameTypeMap.size()).arg(qtVersionString(), nameSpace, m_dumperVersion); } QtDumperHelper::Type QtDumperHelper::simpleType(const QString &simpleType) const @@ -726,10 +770,9 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s) QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Type t) { + switch (t) { case QAbstractItemType: - case QObjectSlotType: - case QObjectSignalType: case QVectorType: case StdMapType: return NeedsComplexExpression; @@ -738,6 +781,7 @@ QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Typ case QMapNodeType: return NeedsCachedExpression; default: + // QObjectSlotType, QObjectSignalType need the signal number, which is numeric break; } return NeedsNoExpression; @@ -968,9 +1012,9 @@ public: explicit QueryDumperParser(const char *s); struct Data { - Data() : qtVersion(0) {} QString qtNameSpace; QString qtVersion; + QString dumperVersion; QStringList types; QList<SizeEntry> sizes; QMap<QString, QString> expressionCache; @@ -986,7 +1030,7 @@ protected: virtual bool handleValue(const char *k, int size); private: - enum Mode { None, ExpectingDumpers, ExpectingVersion, + enum Mode { None, ExpectingDumpers, ExpectingQtVersion, ExpectingDumperVersion, ExpectingNameSpace, ExpectingSizes, ExpectingExpressionCache }; Mode m_mode; Data m_data; @@ -1017,7 +1061,11 @@ bool QueryDumperParser::handleKeyword(const char *k, int size) return true; } if (!qstrncmp(k, "qtversion", size)) { - m_mode = ExpectingVersion; + m_mode = ExpectingQtVersion; + return true; + } + if (!qstrncmp(k, "dumperversion", size)) { + m_mode = ExpectingDumperVersion; return true; } if (!qstrncmp(k, "namespace", size)) { @@ -1038,7 +1086,7 @@ bool QueryDumperParser::handleKeyword(const char *k, int size) bool QueryDumperParser::handleListStart() { - return m_mode == ExpectingDumpers || m_mode == ExpectingVersion; + return m_mode == ExpectingDumpers || m_mode == ExpectingQtVersion; } bool QueryDumperParser::handleListEnd() @@ -1064,7 +1112,10 @@ bool QueryDumperParser::handleValue(const char *k, int size) case ExpectingNameSpace: m_data.qtNameSpace = QString::fromLatin1(k, size); break; - case ExpectingVersion: // ["4","1","5"] + case ExpectingDumperVersion: + m_data.dumperVersion = QString::fromLatin1(k, size); + break; + case ExpectingQtVersion: // ["4","1","5"] if (!m_data.qtVersion.isEmpty()) m_data.qtVersion += QLatin1Char('.'); m_data.qtVersion += QString::fromLatin1(k, size); @@ -1092,6 +1143,7 @@ bool QtDumperHelper::parseQuery(const char *data, Debugger debugger) foreach (const QueryDumperParser::SizeEntry &se, parser.data().sizes) addSize(se.first, se.second); m_expressionCache = parser.data().expressionCache; + m_dumperVersion = parser.data().dumperVersion; return true; } @@ -1248,17 +1300,6 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, case QAbstractItemType: inner = data.addr.mid(1); break; - case QObjectType: - case QWidgetType: - if (debugger == GdbDebugger) { - extraArgs[0] = QLatin1String("(char*)&((('"); - extraArgs[0] += m_qtNamespace; - extraArgs[0] += QLatin1String("QObjectPrivate'*)&"); - extraArgs[0] += data.exp; - extraArgs[0] += QLatin1String(")->children)-(char*)&"); - extraArgs[0] += data.exp; - } - break; case QVectorType: extraArgs[1] = QLatin1String("(char*)&(("); extraArgs[1] += data.exp; @@ -1355,6 +1396,8 @@ void QtDumperHelper::evaluationParameters(const WatchData &data, qWarning("Unknown type encountered in %s.\n", Q_FUNC_INFO); break; case SupportedType: + case QObjectType: + case QWidgetType: break; } @@ -1412,6 +1455,7 @@ private: ExpectingType, ExpectingDisplayedType, ExpectingInternal, ExpectingValueDisabled, ExpectingValueEncoded, ExpectingCommonChildType, ExpectingChildCount, + ExpectingChildChildOverrideCount, ExpectingExtra, IgnoreNext, ChildModeStart, @@ -1488,7 +1532,7 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword if (!qstrncmp(keyword, "displayedtype", size)) return ExpectingDisplayedType; if (!qstrncmp(keyword, "childnumchild", size)) - return IgnoreNextChildMode; + return ExpectingChildChildOverrideCount; break; } return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext; @@ -1519,10 +1563,17 @@ bool ValueDumperParser::handleValue(const char *k, int size) case ExpectingIName: m_result.iname = QString::fromLatin1(valueBA); break; - case ExpectingAddress: - m_result.address = QString::fromLatin1(valueBA); - break; + case ExpectingAddress: { + const QString address = QString::fromLatin1(valueBA); + if (address.startsWith(QLatin1String("0x"))) { + m_result.address = address; + } else { + m_result.addressInfo = address; + } + } + break; case ExpectingValue: + m_result.valueEncountered = true; m_result.value = valueBA; break; case ExpectingValueDisabled: @@ -1549,6 +1600,9 @@ bool ValueDumperParser::handleValue(const char *k, int size) case ExpectingChildCount: m_result.childCount = QString::fromLatin1(valueBA).toInt(); break; + case ExpectingChildChildOverrideCount: + m_result.childChildCount = QString::fromLatin1(valueBA).toInt(); + break; case ExpectingChildren: case IgnoreNextChildMode: case IgnoreNext: @@ -1566,6 +1620,7 @@ bool ValueDumperParser::handleValue(const char *k, int size) m_result.children.back().key = valueBA; break; case ExpectingChildValue: + m_result.children.back().valueEncountered = true; m_result.children.back().value = valueBA; break; case ExpectingChildExpression: @@ -1590,12 +1645,13 @@ bool ValueDumperParser::handleValue(const char *k, int size) bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r) { ValueDumperParser parser(data); + if (!parser.run()) return false; *r = parser.result(); // Sanity - if (r->childCount < r->children.size()) - r->childCount = r->children.size(); + if (!r->children.empty() && r->childCount != r->children.size()) + r->childCount = r->children.size(); if (debug) qDebug() << '\n' << data << '\n' << *r; return true; |