From 452f108ac744c69b42bc2565f608338bdb8fffbc Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 31 Aug 2009 09:14:04 +0200 Subject: [PATCH] debugger: fixes and improvements related to the Locals display Split the concepts 'enabled' and 'editable' in the dumper output Disable "" entries, also fix their type. Fix glitch in type beautification for display Find reason for failing bulk updates. --- share/qtcreator/gdbmacros/gdbmacros.cpp | 130 ++++++++-------- src/plugins/debugger/debuggermanager.cpp | 10 +- src/plugins/debugger/gdb/gdbengine.cpp | 52 +++++-- src/plugins/debugger/gdb/gdbengine.h | 2 +- src/plugins/debugger/idebuggerengine.h | 1 - src/plugins/debugger/shared/backtrace.cpp | 87 +++++++++++ src/plugins/debugger/shared/backtrace.h | 43 +++++ src/plugins/debugger/shared/shared.pri | 4 + src/plugins/debugger/watchhandler.cpp | 181 ++++++++++++++++------ src/plugins/debugger/watchhandler.h | 13 +- src/plugins/debugger/watchutils.cpp | 34 ++-- src/plugins/debugger/watchutils.h | 4 +- src/plugins/debugger/watchwindow.cpp | 11 +- src/plugins/debugger/watchwindow.h | 1 + tests/manual/gdbdebugger/simple/app.cpp | 14 ++ 15 files changed, 428 insertions(+), 159 deletions(-) create mode 100644 src/plugins/debugger/shared/backtrace.cpp create mode 100644 src/plugins/debugger/shared/backtrace.h diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index b9a658ea42d..92c8f707a3c 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -500,10 +500,10 @@ struct QDumper // the dumper arguments int protocolVersion; // dumper protocol version int token; // some token to show on success - const char *outertype; // object type + const char *outerType; // object type const char *iname; // object name used for display const char *exp; // object expression - const char *innertype; // 'inner type' for class templates + const char *innerType; // 'inner type' for class templates const void *data; // pointer to raw data bool dumpChildren; // do we want to see children? @@ -543,7 +543,7 @@ QDumper::~QDumper() void QDumper::setupTemplateParameters() { - char *s = const_cast(innertype); + char *s = const_cast(innerType); int templateParametersCount = 1; templateParameters[0] = s; @@ -734,7 +734,7 @@ void QDumper::endHash() void QDumper::putEllipsis() { putCommaIfNeeded(); - put("{name=\"\",value=\"\",type=\"").put(innertype).put("\"}"); + put("{name=\"\",value=\"\",type=\"").put(innerType).put("\"}"); } void QDumper::putItemCount(const char *name, int count) @@ -875,13 +875,11 @@ void QDumper::putHash(const char *name, QChar value) #define DUMPUNKNOWN_MESSAGE "" static void qDumpUnknown(QDumper &d, const char *why = 0) { - //d.putItem("iname", d.iname); - //d.putItem("addr", d.data); if (!why) why = DUMPUNKNOWN_MESSAGE; d.putItem("value", why); - d.putItem("type", d.outertype); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); + d.putItem("valueenabled", "false"); d.putItem("numchild", "0", d.currentChildNumChild); d.disarm(); } @@ -983,7 +981,7 @@ void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr, if (startsWith(type, "QList<")) { const QListData *ldata = reinterpret_cast(addr); d.putItemCount("value", ldata->size()); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", ldata->size()); } break; @@ -1638,12 +1636,12 @@ static void qDumpQList(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { unsigned innerSize = d.extraInt[0]; - bool innerTypeIsPointer = isPointerType(d.innertype); - QByteArray strippedInnerType = stripPointerType(d.innertype); + bool innerTypeIsPointer = isPointerType(d.innerType); + QByteArray strippedInnerType = stripPointerType(d.innerType); // The exact condition here is: // QTypeInfo::isLarge || QTypeInfo::isStatic @@ -1651,11 +1649,11 @@ static void qDumpQList(QDumper &d) // in the frontend. // So as first approximation only do the 'isLarge' check: bool isInternal = innerSize <= int(sizeof(void*)) - && isMovableType(d.innertype); + && isMovableType(d.innerType); d.putItem("internal", (int)isInternal); if (n > 1000) n = 1000; - d.beginChildren(n ? d.innertype : 0); + d.beginChildren(n ? d.innerType : 0); for (int i = 0; i != n; ++i) { d.beginHash(); if (innerTypeIsPointer) { @@ -1671,13 +1669,13 @@ static void qDumpQList(QDumper &d) } else { void *p = ldata.d->array + i + pdata->begin; if (isInternal) { - //qDumpInnerValue(d, d.innertype, p); + //qDumpInnerValue(d, d.innerType, p); d.putItem("addr", p); - qDumpInnerValueHelper(d, d.innertype, p); + qDumpInnerValueHelper(d, d.innerType, p); } else { - //qDumpInnerValue(d, d.innertype, deref(p)); + //qDumpInnerValue(d, d.innerType, deref(p)); d.putItem("addr", deref(p)); - qDumpInnerValueHelper(d, d.innertype, deref(p)); + qDumpInnerValueHelper(d, d.innerType, deref(p)); } } d.endHash(); @@ -1702,23 +1700,23 @@ static void qDumpQLinkedList(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { //unsigned innerSize = d.extraInt[0]; - //bool innerTypeIsPointer = isPointerType(d.innertype); - QByteArray strippedInnerType = stripPointerType(d.innertype); + //bool innerTypeIsPointer = isPointerType(d.innerType); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; if (n > 1000) n = 1000; - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); const void *p = deref(ldata); for (int i = 0; i != n; ++i) { d.beginHash(); const void *addr = addOffset(p, 2 * sizeof(void*)); - qDumpInnerValueOrPointer(d, d.innertype, stripped, addr); + qDumpInnerValueOrPointer(d, d.innerType, stripped, addr); p = deref(p); d.endHash(); } @@ -2750,7 +2748,7 @@ static void qDumpQSet(QDumper &d) } d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 2 * n); if (d.dumpChildren) { if (n > 100) @@ -2760,9 +2758,9 @@ static void qDumpQSet(QDumper &d) for (int bucket = 0; bucket != hd->numBuckets && i <= 10000; ++bucket) { for (node = hd->buckets[bucket]; node->next; node = node->next) { d.beginHash(); - d.putItem("type", d.innertype); + d.putItem("type", d.innerType); d.beginItem("exp"); - d.put("(('"NS"QHashNode<").put(d.innertype + d.put("(('"NS"QHashNode<").put(d.innerType ).put(","NS"QHashDummyValue>'*)" ).put(static_cast(node)).put(")->key"); d.endItem(); @@ -2788,23 +2786,23 @@ static void qDumpQSharedPointer(QDumper &d) if (ptr.isNull()) { d.putItem("value", ""); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 0); d.disarm(); return; } - if (isSimpleType(d.innertype)) - qDumpInnerValueHelper(d, d.innertype, ptr.data()); + if (isSimpleType(d.innerType)) + qDumpInnerValueHelper(d, d.innerType, ptr.data()); else d.putItem("value", ""); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 1); if (d.dumpChildren) { d.beginChildren(); d.beginHash(); d.putItem("name", "data"); - qDumpInnerValue(d, d.innertype, ptr.data()); + qDumpInnerValue(d, d.innerType, ptr.data()); d.endHash(); const int v = sizeof(void *); d.beginHash(); @@ -2868,7 +2866,7 @@ static void qDumpQStringList(QDumper &d) } d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { if (n > 1000) @@ -2926,18 +2924,18 @@ static void qDumpQVector(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; if (n > 1000) n = 1000; - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); for (int i = 0; i != n; ++i) { d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, + qDumpInnerValueOrPointer(d, d.innerType, stripped, addOffset(v, i * innersize + typeddatasize)); d.endHash(); } @@ -2958,23 +2956,23 @@ static void qDumpQWeakPointer(QDumper &d) if (value == 0 || data == 0) { d.putItem("value", ""); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 0); d.disarm(); return; } - if (isSimpleType(d.innertype)) - qDumpInnerValueHelper(d, d.innertype, value); + if (isSimpleType(d.innerType)) + qDumpInnerValueHelper(d, d.innerType, value); else d.putItem("value", ""); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", 1); if (d.dumpChildren) { d.beginChildren(); d.beginHash(); d.putItem("name", "data"); - qDumpInnerValue(d, d.innertype, value); + qDumpInnerValue(d, d.innerType, value); d.endHash(); d.beginHash(); const void *weak = addOffset(deref(d.data), v); @@ -3034,16 +3032,16 @@ static void qDumpStdList(QDumper &d) d.putItemCount("value", nn); d.putItem("numchild", nn); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); if (d.dumpChildren) { - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; - d.beginChildren(d.innertype); + isPointerType(d.innerType) ? strippedInnerType.data() : 0; + d.beginChildren(d.innerType); it = list.begin(); for (int i = 0; i < 1000 && it != cend; ++i, ++it) { d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->()); + qDumpInnerValueOrPointer(d, d.innerType, stripped, it.operator->()); d.endHash(); } if (it != list.end()) @@ -3078,10 +3076,10 @@ static void qDumpStdMapHelper(QDumper &d) for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it) qCheckAccess(it.operator->()); - const QByteArray strippedInnerType = stripPointerType(d.innertype); + const QByteArray strippedInnerType = stripPointerType(d.innerType); d.putItem("numchild", nn); d.putItemCount("value", nn); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("valueoffset", d.extraInt[2]); // HACK: we need a properly const qualified version of the @@ -3105,7 +3103,7 @@ static void qDumpStdMapHelper(QDumper &d) d.put(" valueOffset: ").put(valueOffset); d.endItem(); - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); it = map.begin(); for (int i = 0; i < 1000 && it != cend; ++i, ++it) { d.beginHash(); @@ -3185,26 +3183,26 @@ static void qDumpStdSetHelper(QDumper &d) qCheckAccess(it.operator->()); d.putItemCount("value", nn); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", nn); d.putItem("valueoffset", d.extraInt[0]); if (d.dumpChildren) { int valueOffset = 0; // d.extraInt[0]; - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; d.beginItem("extra"); d.put("valueOffset: ").put(valueOffset); d.endItem(); - d.beginChildren(d.innertype); + d.beginChildren(d.innerType); it = set.begin(); for (int i = 0; i < 1000 && it != cend; ++i, ++it) { const void *node = it.operator->(); d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, node); + qDumpInnerValueOrPointer(d, d.innerType, stripped, node); d.endHash(); } if (it != set.end()) @@ -3295,19 +3293,19 @@ static void qDumpStdVector(QDumper &d) int n = nn; d.putItemCount("value", n); - d.putItem("valuedisabled", "true"); + d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { unsigned innersize = d.extraInt[0]; - QByteArray strippedInnerType = stripPointerType(d.innertype); + QByteArray strippedInnerType = stripPointerType(d.innerType); const char *stripped = - isPointerType(d.innertype) ? strippedInnerType.data() : 0; + isPointerType(d.innerType) ? strippedInnerType.data() : 0; if (n > 1000) n = 1000; - d.beginChildren(n ? d.innertype : 0); + d.beginChildren(n ? d.innerType : 0); for (int i = 0; i != n; ++i) { d.beginHash(); - qDumpInnerValueOrPointer(d, d.innertype, stripped, + qDumpInnerValueOrPointer(d, d.innerType, stripped, addOffset(v->start, i * innersize)); d.endHash(); } @@ -3326,7 +3324,7 @@ static void qDumpStdVectorBool(QDumper &d) static void handleProtocolVersion2and3(QDumper &d) { - if (!d.outertype[0]) { + if (!d.outerType[0]) { qDumpUnknown(d); return; } @@ -3341,7 +3339,7 @@ static void handleProtocolVersion2and3(QDumper &d) #ifdef QT_NO_QDATASTREAM if (d.protocolVersion == 3) { - QVariant::Type type = QVariant::nameToType(d.outertype); + QVariant::Type type = QVariant::nameToType(d.outerType); if (type != QVariant::Invalid) { QVariant v(type, d.data); QByteArray ba; @@ -3352,7 +3350,7 @@ static void handleProtocolVersion2and3(QDumper &d) } #endif - const char *type = stripNamespace(d.outertype); + const char *type = stripNamespace(d.outerType); // type[0] is usally 'Q', so don't use it switch (type[1]) { case 'a': @@ -3774,10 +3772,10 @@ void *qDumpObjectData440( d.extraInt[3] = extraInt3; const char *inbuffer = inBuffer; - d.outertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; + d.outerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.exp = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; - d.innertype = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; + d.innerType = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; d.iname = inbuffer; while (*inbuffer) ++inbuffer; ++inbuffer; handleProtocolVersion2and3(d); diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index f1dbc7b71dc..844ba750b4d 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -319,9 +319,7 @@ void DebuggerManager::init() //qRegisterMetaType("Debugger::Internal::WatchData"); qRegisterMetaType("WatchData"); connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)), - this, SLOT(updateWatchDataAnnounce())); - connect(m_watchHandler, SIGNAL(watchDataUpdateNeeded(WatchData)), - this, SLOT(updateWatchData(WatchData)), Qt::QueuedConnection); + this, SLOT(updateWatchData(WatchData))); m_continueAction = new QAction(this); m_continueAction->setText(tr("Continue")); @@ -695,12 +693,6 @@ void DebuggerManager::updateWatchData(const WatchData &data) m_engine->updateWatchData(data); } -void DebuggerManager::updateWatchDataAnnounce() -{ - if (m_engine) - m_engine->updateWatchDataAnnounce(); -} - static inline QString msgEngineNotAvailable(const char *engine) { return DebuggerManager::tr("The application requires the debugger engine '%1', which is disabled.").arg(QLatin1String(engine)); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index c12a4a1b1c8..89669c9df5e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -2814,12 +2815,20 @@ static void setWatchDataChildCount(WatchData &data, const GdbMi &mi) data.setHasChildren(mi.data().toInt() > 0); } -static void setWatchDataValueDisabled(WatchData &data, const GdbMi &mi) +static void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi) { if (mi.data() == "true") - data.valuedisabled = true; + data.valueEnabled = true; else if (mi.data() == "false") - data.valuedisabled = false; + data.valueEnabled = false; +} + +static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi) +{ + if (mi.data() == "true") + data.valueEditable = true; + else if (mi.data() == "false") + data.valueEditable = false; } static void setWatchDataExpression(WatchData &data, const GdbMi &mi) @@ -3127,20 +3136,26 @@ void GdbEngine::updateSubItem(const WatchData &data0) QTC_ASSERT(false, return); } -void GdbEngine::updateWatchDataAnnounce() +void GdbEngine::updateWatchData(const WatchData &data) { // Bump requests to avoid model rebuilding during the nested // updateWatchModel runs. ++m_pendingRequests; +#if 1 + QMetaObject::invokeMethod(this, "updateWatchDataHelper", + Qt::QueuedConnection, Q_ARG(WatchData, data)); +#else + updateWatchDataHelper(data); +#endif } -void GdbEngine::updateWatchData(const WatchData &data) +void GdbEngine::updateWatchDataHelper(const WatchData &data) { //m_pendingRequests = 0; PENDING_DEBUG("UPDATE WATCH DATA"); #if DEBUG_PENDING //qDebug() << "##############################################"; - //qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:"; + qDebug() << "UPDATE MODEL, FOUND INCOMPLETE:"; //qDebug() << data.toString(); #endif @@ -3153,9 +3168,11 @@ void GdbEngine::updateWatchData(const WatchData &data) void GdbEngine::rebuildModel() { + static int count = 0; + ++count; m_processedNames.clear(); - PENDING_DEBUG("REBUILDING MODEL"); - emit gdbInputAvailable(LogStatus, _("")); + PENDING_DEBUG("REBUILDING MODEL" << count); + emit gdbInputAvailable(LogStatus, _("").arg(count)); q->showStatusMessage(tr("Finished retrieving data."), 400); qq->watchHandler()->endCycle(); showToolTip(); @@ -3330,7 +3347,8 @@ void GdbEngine::handleVarCreate(const GdbResultRecord &record, data.type = _(" "); data.setAllUnneeded(); data.setHasChildren(false); - data.valuedisabled = true; + data.valueEnabled = false; + data.valueEditable = false; insertData(data); } } @@ -3445,7 +3463,8 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item, setWatchDataSAddress(data, item.findChild("saddr")); setWatchDataValueToolTip(data, item.findChild("valuetooltip"), item.findChild("valuetooltipencoded").data().toInt()); - setWatchDataValueDisabled(data, item.findChild("valuedisabled")); + setWatchDataValueEnabled(data, item.findChild("valueenabled")); + setWatchDataValueEditable(data, item.findChild("valueeditable")); //qDebug() << "HANDLE CHILDREN: " << data.toString(); list->append(data); @@ -3495,7 +3514,7 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record, // << " STREAM:" << out; if (list.isEmpty()) { //: Value for variable - data.setValue(strNotInScope); + data.setError(strNotInScope); data.setAllUnneeded(); insertData(data); } else if (data.type == __("QString") @@ -3540,13 +3559,13 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResultRecord &record, } } else { //: Value for variable - data.setValue(strNotInScope); + data.setError(strNotInScope); data.setAllUnneeded(); insertData(data); } } else if (record.resultClass == GdbResultError) { WatchData data = cookie.value(); - data.setValue(strNotInScope); + data.setError(strNotInScope); data.setAllUnneeded(); insertData(data); } @@ -3628,6 +3647,7 @@ void GdbEngine::setLocals(const QList &locals) //qDebug() << m_varToType; QMap seen; + QList list; foreach (const GdbMi &item, locals) { // Local variables of inlined code are reported as // 26^done,locals={varobj={exp="this",value="",name="var4",exp="this", @@ -3657,7 +3677,7 @@ void GdbEngine::setLocals(const QList &locals) //variable of the same name in a nested block data.setType(tr("")); data.setHasChildren(false); - insertData(data); + list.append(data); } else { seen[name] = 1; WatchData data; @@ -3679,9 +3699,10 @@ void GdbEngine::setLocals(const QList &locals) qDebug() << "RE-USING" << m_varToType.value(data.framekey); data.setType(m_varToType.value(data.framekey)); } - insertData(data); + list.append(data); } } + qq->watchHandler()->insertBulkData(list); } void GdbEngine::insertData(const WatchData &data0) @@ -3698,7 +3719,6 @@ void GdbEngine::insertData(const WatchData &data0) void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, const WatchData &parent) { - //qDebug() << "VAR_LIST_CHILDREN: PARENT 2" << parent.toString(); //qDebug() << "VAR_LIST_CHILDREN: APPENDEE" << data.toString(); QByteArray exp = item.findChild("exp").data(); QByteArray name = item.findChild("name").data(); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index fdf67f15b8e..2694ec01fbd 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -332,7 +332,7 @@ private: void updateSubItem(const WatchData &data); void updateWatchData(const WatchData &data); - void updateWatchDataAnnounce(); + Q_SLOT void updateWatchDataHelper(const WatchData &data); void rebuildModel(); void insertData(const WatchData &data); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 327b1866c01..89ff3029319 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -63,7 +63,6 @@ public: virtual bool startDebugger(const QSharedPointer &startParameters) = 0; virtual void exitDebugger() = 0; virtual void detachDebugger() {} - virtual void updateWatchDataAnnounce() {} virtual void updateWatchData(const WatchData &data) = 0; virtual void stepExec() = 0; diff --git a/src/plugins/debugger/shared/backtrace.cpp b/src/plugins/debugger/shared/backtrace.cpp new file mode 100644 index 00000000000..6b81e9339e5 --- /dev/null +++ b/src/plugins/debugger/shared/backtrace.cpp @@ -0,0 +1,87 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (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 http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include +#include +#include + +#if defined(Q_OS_LINUX) +#include +#include +#include +#endif + +namespace Debugger { +namespace Internal { + +void dumpBacktrace(int maxdepth) +{ + if (maxdepth == -1) + maxdepth = 200; +#if defined(Q_OS_LINUX) + void *bt[200] = {0}; + qDebug() << "BACKTRACE:"; + int size = backtrace(bt, sizeof(bt) / sizeof(bt[0])); + for (int i = 0; i < qMin(size, maxdepth); i++) + qDebug() << "0x" + QByteArray::number(quintptr(bt[i]), 16); + QProcess proc; + QStringList args; + args.append("-e"); + args.append(QCoreApplication::arguments().at(0)); + proc.start("addr2line", args); + proc.waitForStarted(); + for (int i = 0; i < qMin(size, maxdepth); i++) + proc.write("0x" + QByteArray::number(quintptr(bt[i]), 16) + "\n"); + proc.closeWriteChannel(); + QByteArray out = proc.readAllStandardOutput(); + qDebug() << QCoreApplication::arguments().at(0); + qDebug() << out; + proc.waitForFinished(); + out = proc.readAllStandardOutput(); + qDebug() << out; +#endif +} + +/* +void installSignalHandlers() +{ +#if defined(Q_OS_LINUX) + struct sigaction SignalAction; + + SignalAction.sa_sigaction = handler; + sigemptyset(&SignalAction.sa_mask); + SignalAction.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &SignalAction, NULL); + sigaction(SIGABRT, &SignalAction, NULL); +#endif +} +*/ + +} // namespace Internal +} // namespace Debugger diff --git a/src/plugins/debugger/shared/backtrace.h b/src/plugins/debugger/shared/backtrace.h new file mode 100644 index 00000000000..771ec2a3d17 --- /dev/null +++ b/src/plugins/debugger/shared/backtrace.h @@ -0,0 +1,43 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (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 http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef DEBUGGER_BACKTRACE_H +#define DEBUGGER_BACKTRACE_H + +#include + +namespace Debugger { +namespace Internal { + +void dumpBacktrace(int maxdepth = -1); + +} // namespace Internal +} // namespace Debugger + +#endif // DEBUGGER_BACKTRACE_H diff --git a/src/plugins/debugger/shared/shared.pri b/src/plugins/debugger/shared/shared.pri index a3dc29a6b39..bd69e956ce0 100644 --- a/src/plugins/debugger/shared/shared.pri +++ b/src/plugins/debugger/shared/shared.pri @@ -1,4 +1,8 @@ + +SOURCES += $$PWD/backtrace.cpp +HEADERS += $$PWD/backtrace.h + win32 { INCLUDEPATH+=$$PWD diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 13bf8698b30..d8e6cca6007 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -102,19 +102,40 @@ public: WatchData::WatchData() : hasChildren(false), generation(-1), - valuedisabled(false), + valueEnabled(true), + valueEditable(true), source(0), state(InitialState), changed(false) { } +bool WatchData::isEqual(const WatchData &other) const +{ + return iname == other.iname + && exp == other.exp + && name == other.name + && value == other.value + && editvalue == other.editvalue + && valuetooltip == other.valuetooltip + && type == other.type + && displayedType == other.displayedType + && variable == other.variable + && addr == other.addr + && saddr == other.saddr + && framekey == other.framekey + && hasChildren == other.hasChildren + && valueEnabled == other.valueEnabled + && valueEditable == other.valueEditable; +} + void WatchData::setError(const QString &msg) { setAllUnneeded(); value = msg; setHasChildren(false); - valuedisabled = true; + valueEnabled = false; + valueEditable = false; } void WatchData::setValue(const QString &value0) @@ -276,6 +297,8 @@ QString WatchData::toToolTip() const formatToolTipRow(str, WatchHandler::tr("Object Address"), addr); formatToolTipRow(str, WatchHandler::tr("Stored Address"), saddr); formatToolTipRow(str, WatchHandler::tr("Internal ID"), iname); + formatToolTipRow(str, WatchHandler::tr("Generation"), + QString::number(generation)); str << ""; return res; } @@ -330,6 +353,33 @@ void WatchModel::reinitialize() endRemoveRows(); } +void WatchModel::beginCycle() +{ + emit enableUpdates(false); +} + +void WatchModel::endCycle() +{ + removeOutdated(); + emit enableUpdates(true); +} + +void WatchModel::dump() +{ + qDebug() << "\n"; + foreach (WatchItem *child, m_root->children) + dumpHelper(child); +} + +void WatchModel::dumpHelper(WatchItem *item) +{ + qDebug() << "ITEM: " << item->iname + << (item->parent ? item->parent->iname : "") + << item->generation; + foreach (WatchItem *child, item->children) + dumpHelper(child); +} + void WatchModel::removeOutdated() { foreach (WatchItem *child, m_root->children) @@ -343,9 +393,9 @@ void WatchModel::removeOutdated() void WatchModel::removeOutdatedHelper(WatchItem *item) { - if (item->generation < generationCounter) + if (item->generation < generationCounter) { removeItem(item); - else { + } else { foreach (WatchItem *child, item->children) removeOutdatedHelper(child); item->fetchTriggered = false; @@ -407,9 +457,9 @@ QString niceType(const QString typeIn) { static QMap cache; const QMap::const_iterator it = cache.constFind(typeIn); - if (it != cache.constEnd()) { + if (it != cache.constEnd()) return it.value(); - } + QString type = typeIn; type.replace(QLatin1Char('*'), QLatin1Char('@')); @@ -434,23 +484,23 @@ QString niceType(const QString typeIn) QString inner = alloc.mid(15, alloc.size() - 16).trimmed(); if (inner == QLatin1String("char")) { // std::string - static const QRegExp stringRegexp = stdStringRegExp(inner); + const QRegExp stringRegexp = stdStringRegExp(inner); type.replace(stringRegexp, QLatin1String("string")); } else if (inner == QLatin1String("wchar_t")) { // std::wstring - static const QRegExp wchartStringRegexp = stdStringRegExp(inner); + const QRegExp wchartStringRegexp = stdStringRegExp(inner); type.replace(wchartStringRegexp, QLatin1String("wstring")); } else if (inner == QLatin1String("unsigned short")) { // std::wstring/MSVC - static const QRegExp usStringRegexp = stdStringRegExp(inner); + const QRegExp usStringRegexp = stdStringRegExp(inner); type.replace(usStringRegexp, QLatin1String("wstring")); } // std::vector, std::deque, std::list - static const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1,[ ]?%2\\s*>").arg(inner, alloc)); + const QRegExp re1(QString::fromLatin1("(vector|list|deque)<%1, ?%2\\s*>").arg(inner, alloc)); Q_ASSERT(re1.isValid()); if (re1.indexIn(type) != -1) type.replace(re1.cap(0), QString::fromLatin1("%1<%2>").arg(re1.cap(1), inner)); // std::stack - static QRegExp re6(QString::fromLatin1("stack<%1,[ ]?std::deque<%2> >").arg(inner, inner)); + QRegExp re6(QString::fromLatin1("stack<%1, ?std::deque<%2> >").arg(inner, inner)); if (!re6.isMinimal()) re6.setMinimal(true); Q_ASSERT(re6.isValid()); @@ -458,7 +508,7 @@ QString niceType(const QString typeIn) type.replace(re6.cap(0), QString::fromLatin1("stack<%1>").arg(inner)); // std::set - static QRegExp re4(QString::fromLatin1("set<%1,[ ]?std::less<%2>,[ ]?%3\\s*>").arg(inner, inner, alloc)); + QRegExp re4(QString::fromLatin1("set<%1, ?std::less<%2>, ?%3\\s*>").arg(inner, inner, alloc)); if (!re4.isMinimal()) re4.setMinimal(true); Q_ASSERT(re4.isValid()); @@ -481,17 +531,16 @@ QString niceType(const QString typeIn) } QString ckey = inner.mid(10, pos - 10); QString key = chopConst(ckey); - QString value = inner.mid(pos + 2, inner.size() - 3 - pos); - - static QRegExp re5(QString("map<%1,[ ]?%2,[ ]?std::less<%3>,[ ]?%4\\s*>") + QString value = inner.mid(pos + 2, inner.size() - 3 - pos).trimmed(); + QRegExp re5(QString("map<%1, ?%2, ?std::less<%3 ?>, ?%4\\s*>") .arg(key, value, key, alloc)); if (!re5.isMinimal()) re5.setMinimal(true); Q_ASSERT(re5.isValid()); - if (re5.indexIn(type) != -1) + if (re5.indexIn(type) != -1) { type.replace(re5.cap(0), QString("map<%1, %2>").arg(key, value)); - else { - static QRegExp re7(QString("map,[ ]?%4\\s*>") + } else { + QRegExp re7(QString("map, ?%4\\s*>") .arg(key, value, key, alloc)); if (!re7.isMinimal()) re7.setMinimal(true); @@ -657,7 +706,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const static const QVariant red(QColor(200, 0, 0)); static const QVariant gray(QColor(140, 140, 140)); switch (idx.column()) { - case 1: return data.valuedisabled ? gray : data.changed ? red : QVariant(); + case 1: return !data.valueEnabled ? gray : data.changed ? red : QVariant(); } break; } @@ -751,9 +800,9 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const return editable; // watcher names are editable if (data.isWatcher() && idx.column() == 2) return editable; // watcher types are - if (idx.column() == 1) - return editable; // locals and watcher values are editable - return notEditable; + if (idx.column() == 1 && data.valueEditable) + return editable; // locals and watcher values are sometimes editable + return notEditable; } QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -775,7 +824,7 @@ struct IName : public QString IName(const QString &iname) : QString(iname) {} }; -bool operator<(const IName &iname1, const IName &iname2) +bool iNameLess(const QString &iname1, const QString &iname2) { QString name1 = iname1.section('.', -1); QString name2 = iname2.section('.', -1); @@ -790,10 +839,14 @@ bool operator<(const IName &iname1, const IName &iname2) return name1 < name2; } +bool operator<(const IName &iname1, const IName &iname2) +{ + return iNameLess(iname1, iname2); +} static bool iNameSorter(const WatchItem *item1, const WatchItem *item2) { - return IName(item1->iname) < IName(item2->iname); + return iNameLess(item1->iname, item2->iname); } static int findInsertPosition(const QList &list, const WatchItem *item) @@ -806,7 +859,7 @@ static int findInsertPosition(const QList &list, const WatchItem *i void WatchModel::insertData(const WatchData &data) { // qDebug() << "WMI:" << data.toString(); - static int bulk = 0; + //static int bulk = 0; //qDebug() << "SINGLE: " << ++bulk << data.toString(); QTC_ASSERT(!data.iname.isEmpty(), return); WatchItem *parent = findItem(parentName(data.iname), m_root); @@ -845,8 +898,16 @@ void WatchModel::insertData(const WatchData &data) void WatchModel::insertBulkData(const QList &list) { +#if 1 + for (int i = 0; i != list.size(); ++i) + insertData(list.at(i)); + return; +#endif + // This method does not properly insert items in proper "iname sort + // order", leading to random removal of items in removeOutDated(); + //qDebug() << "WMI:" << list.toString(); - static int bulk = 0; + //static int bulk = 0; //foreach (const WatchItem &data, list) // qDebug() << "BULK: " << ++bulk << data.toString(); QTC_ASSERT(!list.isEmpty(), return); @@ -885,22 +946,39 @@ void WatchModel::insertBulkData(const QList &list) foreach (WatchItem *oldItem, parent->children) { Iterator it = newList.find(oldItem->iname); if (it == newList.end()) { - newList[oldItem->iname] = *oldItem; + WatchData data = *oldItem; + data.generation = generationCounter; + newList[oldItem->iname] = data; } else { bool changed = !it->value.isEmpty() && it->value != oldItem->value && it->value != strNotInScope; it->changed = changed; - it->generation = generationCounter; + if (it->generation == -1) + it->generation = generationCounter; } } + for (Iterator it = newList.begin(); it != newList.end(); ++it) { + qDebug() << " NEW: " << it->iname; + } + // overwrite existing items Iterator it = newList.begin(); - const int oldCount = parent->children.size(); - for (int i = 0; i < oldCount; ++i, ++it) - parent->children[i]->setData(*it); QModelIndex idx = watchIndex(parent); + const int oldCount = parent->children.size(); + for (int i = 0; i < oldCount; ++i, ++it) { + if (!parent->children[i]->isEqual(*it)) { + qDebug() << "REPLACING" << parent->children.at(i)->iname + << " WITH " << it->iname << it->generation; + parent->children[i]->setData(*it); + if (parent->children[i]->generation == -1) + parent->children[i]->generation = generationCounter; + //emit dataChanged(idx.sibling(i, 0), idx.sibling(i, 2)); + } else { + //qDebug() << "SKIPPING REPLACEMENT" << parent->children.at(i)->iname; + } + } emit dataChanged(idx.sibling(0, 0), idx.sibling(oldCount - 1, 2)); // add new items @@ -909,13 +987,17 @@ void WatchModel::insertBulkData(const QList &list) //MODEL_DEBUG("INSERT : " << data.iname << data.value); for (int i = oldCount; i < newList.size(); ++i, ++it) { WatchItem *item = new WatchItem(*it); + qDebug() << "ADDING" << it->iname; item->parent = parent; - item->generation = generationCounter; + if (item->generation == -1) + item->generation = generationCounter; item->changed = true; parent->children.append(item); } endInsertRows(); } + //qDebug() << "ITEMS: " << parent->children.size(); + dump(); } WatchItem *WatchModel::findItem(const QString &iname, WatchItem *root) const @@ -965,11 +1047,20 @@ WatchHandler::WatchHandler() SIGNAL(triggered()), this, SLOT(removeWatchExpression())); } +void WatchHandler::beginCycle() +{ + ++generationCounter; + m_locals->beginCycle(); + m_watchers->beginCycle(); + m_tooltips->beginCycle(); +} + void WatchHandler::endCycle() { - m_locals->removeOutdated(); - m_watchers->removeOutdated(); - m_tooltips->removeOutdated(); + //qDebug() << "END CYCLE"; + m_locals->endCycle(); + m_watchers->endCycle(); + m_tooltips->endCycle(); } void WatchHandler::cleanup() @@ -1004,7 +1095,7 @@ void WatchHandler::insertData(const WatchData &data) // bulk-insertion void WatchHandler::insertBulkData(const QList &list) { -#if 1 +#if 0 foreach (const WatchItem &data, list) insertData(data); return; @@ -1015,16 +1106,20 @@ void WatchHandler::insertBulkData(const QList &list) QMap > hash; foreach (const WatchData &data, list) { - if (data.isSomethingNeeded()) - emit watchDataUpdateNeeded(data); - else - hash[parentName(data.iname)].append(data); + // we insert everything, including incomplete stuff + // to reduce the number of row add operations in the model. + hash[parentName(data.iname)].append(data); } foreach (const QString &parentIName, hash.keys()) { WatchModel *model = modelForIName(parentIName); QTC_ASSERT(model, return); model->insertBulkData(hash[parentIName]); } + + foreach (const WatchData &data, list) { + if (data.isSomethingNeeded()) + emit watchDataUpdateNeeded(data); + } } void WatchHandler::removeData(const QString &iname) @@ -1157,12 +1252,6 @@ void WatchHandler::removeWatchExpression(const QString &exp) } } -void WatchHandler::beginCycle() -{ - ++generationCounter; - //m_locals->beginCycle(); -} - void WatchHandler::updateWatchers() { //qDebug() << "UPDATE WATCHERS"; diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 4c2d2d36fe7..8f6590484b9 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -111,6 +111,8 @@ public: bool isLocal() const { return iname.startsWith(QLatin1String("local.")); } bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); } bool isValid() const { return !iname.isEmpty(); } + + bool isEqual(const WatchData &other) const; public: QString iname; // internal name sth like 'local.baz.public.a' @@ -128,7 +130,8 @@ public: QScriptValue scriptValue; // if needed... bool hasChildren; int generation; // when updated? - bool valuedisabled; // value will be greyed out + bool valueEnabled; // value will be greyed out or not + bool valueEditable; // value will be editable private: @@ -204,8 +207,16 @@ private: void emitDataChanged(int column, const QModelIndex &parentIndex = QModelIndex()); + void beginCycle(); // called at begin of updateLocals() cycle + void endCycle(); // called after all results have been received friend QDebug operator<<(QDebug d, const WatchModel &m); + + void dump(); + void dumpHelper(WatchItem *item); +signals: + void enableUpdates(bool); + private: WatchHandler *m_handler; WatchType m_type; diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 6b6a358455e..1663f942668 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -491,7 +491,7 @@ QtDumperResult::Child::Child() : keyEncoded(0), valueEncoded(0), childCount(-1), - valuedisabled(false), + valueEnabled(true), valueEncountered(false) { } @@ -499,7 +499,7 @@ QtDumperResult::Child::Child() : QtDumperResult::QtDumperResult() : valueEncountered(false), valueEncoded(0), - valuedisabled(false), + valueEnabled(true), childCount(-1), internal(false), childChildCount(-1) @@ -516,7 +516,8 @@ void QtDumperResult::clear() extra.clear(); displayedType.clear(); valueEncoded = 0; - valueEncountered = valuedisabled = false; + valueEncountered = false; + valueEnabled = false; childCount = -1; internal = false; childType.clear(); @@ -535,7 +536,7 @@ QList QtDumperResult::toWatchData(int source) const root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1); if (valueEncountered) { root.setValue(decodeData(value, valueEncoded)); - root.valuedisabled = valuedisabled; + root.valueEnabled = valueEnabled; } root.setType(type); if (!displayedType.isEmpty()) @@ -575,7 +576,7 @@ QList QtDumperResult::toWatchData(int source) const wchild.iname += iname; wchild.exp = dchild.exp; if (dchild.valueEncountered) { - wchild.valuedisabled = dchild.valuedisabled; + wchild.valueEnabled = dchild.valueEnabled; wchild.setValue(decodeData(dchild.value, dchild.valueEncoded)); } wchild.setAddress(dchild.address); @@ -611,14 +612,15 @@ QList QtDumperResult::toWatchData(int source) const QDebug operator<<(QDebug in, const QtDumperResult &d) { QDebug nospace = in.nospace(); - nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType + nospace << " iname=" << d.iname << " type=" << d.type + << " displayed=" << d.displayedType << " address=" << d.address; if (!d.addressInfo.isEmpty()) nospace << " addressInfo=" << d.addressInfo; if (d.valueEncountered) { nospace << " encoded=" << d.valueEncoded << " value=" << d.value - << " disabled=" << d.valuedisabled; + << " enabled=" << d.valueEnabled; } else { nospace << " "; } @@ -633,7 +635,7 @@ QDebug operator<<(QDebug in, const QtDumperResult &d) for (int i = 0; i < realChildCount; i++) { const QtDumperResult::Child &c = d.children.at(i); nospace << " #" << i << " addr=" << c.address - << " disabled=" << c.valuedisabled + << " enabled=" << c.valueEnabled << " type=" << c.type << " exp=" << c.exp << " name=" << c.name; if (!c.key.isEmpty()) @@ -1518,7 +1520,7 @@ protected: private: enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue, ExpectingType, ExpectingDisplayedType, ExpectingInternal, - ExpectingValueDisabled, ExpectingValueEncoded, + ExpectingValueEnabled, ExpectingValueEncoded, ExpectingCommonChildType, ExpectingChildCount, ExpectingChildChildOverrideCount, ExpectingExtra, @@ -1529,7 +1531,7 @@ private: ExpectingChildDisplayedType, ExpectingChildKey, ExpectingChildKeyEncoded, ExpectingChildValue, ExpectingChildValueEncoded, - ExpectingChildValueDisabled, ExpectingChildChildCount, + ExpectingChildValueEnabled, ExpectingChildChildCount, IgnoreNextChildMode }; @@ -1593,8 +1595,8 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded; break; case 13: - if (!qstrncmp(keyword, "valuedisabled", size)) - return in > ChildModeStart ? ExpectingChildValueDisabled : ExpectingValueDisabled; + if (!qstrncmp(keyword, "valueenabled", size)) + return in > ChildModeStart ? ExpectingChildValueEnabled : ExpectingValueEnabled; if (!qstrncmp(keyword, "displayedtype", size)) return in > ChildModeStart ? ExpectingChildDisplayedType : ExpectingDisplayedType; if (!qstrncmp(keyword, "childnumchild", size)) @@ -1642,8 +1644,8 @@ bool ValueDumperParser::handleValue(const char *k, int size) m_result.valueEncountered = true; m_result.value = valueBA; break; - case ExpectingValueDisabled: - m_result.valuedisabled = valueBA == "true"; + case ExpectingValueEnabled: + m_result.valueEnabled = valueBA == "true"; break; case ExpectingValueEncoded: m_result.valueEncoded = QString::fromLatin1(valueBA).toInt(); @@ -1695,8 +1697,8 @@ bool ValueDumperParser::handleValue(const char *k, int size) case ExpectingChildValueEncoded: m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt(); break; - case ExpectingChildValueDisabled: - m_result.children.back().valuedisabled = valueBA == "true"; + case ExpectingChildValueEnabled: + m_result.children.back().valueEnabled = valueBA == "true"; break; case ExpectingChildType: m_result.children.back().type = QString::fromLatin1(valueBA); diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 7c854009813..f085179d413 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -97,7 +97,7 @@ struct QtDumperResult int keyEncoded; int valueEncoded; int childCount; - bool valuedisabled; + bool valueEnabled; QString name; QString address; QString exp; @@ -121,7 +121,7 @@ struct QtDumperResult bool valueEncountered; QByteArray value; int valueEncoded; - bool valuedisabled; + bool valueEnabled; int childCount; bool internal; QString childType; diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index b8a687c82db..edb3c9bbaf8 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -353,7 +353,16 @@ void WatchWindow::setModel(QAbstractItemModel *model) if (m_type != LocalsType) header()->hide(); - connect(model, SIGNAL(layoutChanged()), this, SLOT(resetHelper())); + connect(model, SIGNAL(layoutChanged()), + this, SLOT(resetHelper())); + connect(model, SIGNAL(enableUpdates(bool)), + this, SLOT(setUpdatesEnabled(bool))); +} + +void WatchWindow::setUpdatesEnabled(bool enable) +{ + //qDebug() << "ENABLING UPDATES: " << enable; + QTreeView::setUpdatesEnabled(enable); } void WatchWindow::resetHelper() diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index b2b27a9f062..582ffdcd6fa 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -64,6 +64,7 @@ private: Q_SLOT void resetHelper(); Q_SLOT void expandNode(const QModelIndex &idx); Q_SLOT void collapseNode(const QModelIndex &idx); + Q_SLOT void setUpdatesEnabled(bool enable); void keyPressEvent(QKeyEvent *ev); void contextMenuEvent(QContextMenuEvent *ev); diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index 3a63d348b8c..0259c0a2e21 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -90,6 +90,20 @@ public: int t = 2; b = 2 + s + t; a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; + a += 1; } ~Foo()