From 7e3d95419582d7276d94131ddd8958180f6a94b5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Oct 2009 14:50:27 +0200 Subject: [PATCH] debugger: work on a "synchroneous" mode For the case that gdb can give all the interesting data in one go. --- src/plugins/debugger/gdb/gdbengine.cpp | 155 +++++++++++++++++++------ src/plugins/debugger/gdb/gdbengine.h | 8 +- src/plugins/debugger/idebuggerengine.h | 1 + 3 files changed, 129 insertions(+), 35 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 90570591ad3..e1656eb6d50 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -89,7 +89,7 @@ #endif #include -// FIXME: temporary hack to evalute tbreak based step-over behaviour +// FIXME: temporary hack to evalaute tbreak based step-over behaviour static QString lastFile; static int lastLine; @@ -2648,8 +2648,6 @@ static void setWatchDataSAddress(WatchData &data, const GdbMi &mi) void GdbEngine::setUseDebuggingHelpers(const QVariant &on) { //qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on; - // FIXME: a bit too harsh, but otherwise the treeview sometimes look funny - //m_expandedINames.clear(); Q_UNUSED(on) setTokenBarrier(); updateLocals(); @@ -2916,6 +2914,7 @@ void GdbEngine::updateSubItem(const WatchData &data0) return; } +//#if !X if (data.isHasChildrenNeeded() && data.variable.isEmpty()) { #if DEBUG_SUBITEM qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDCOUNT"; @@ -2925,6 +2924,7 @@ void GdbEngine::updateSubItem(const WatchData &data0) // item, with childrenNeeded() set. return; } +//#endif if (data.isHasChildrenNeeded()) { QTC_ASSERT(!data.variable.isEmpty(), return); // tested above @@ -2939,16 +2939,32 @@ void GdbEngine::updateSubItem(const WatchData &data0) void GdbEngine::updateWatchData(const WatchData &data) { - // Bump requests to avoid model rebuilding during the nested - // updateWatchModel runs. - ++m_pendingRequests; - PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingRequests); -#if 1 - QMetaObject::invokeMethod(this, "updateWatchDataHelper", - Qt::QueuedConnection, Q_ARG(WatchData, data)); + if (isSynchroneous()) { + // This should only be called for fresh expanded items, not for + // items that had their children retrieved earlier. + qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n"; +#if 0 + WatchData data1 = data; + data1.setAllUnneeded(); + insertData(data1); + rebuildModel(); #else - updateWatchDataHelper(data); + if (data.iname.endsWith(_("."))) + return; + updateLocals(); #endif + } else { + // Bump requests to avoid model rebuilding during the nested + // updateWatchModel runs. + ++m_pendingRequests; + PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingRequests); +#if 1 + QMetaObject::invokeMethod(this, "updateWatchDataHelper", + Qt::QueuedConnection, Q_ARG(WatchData, data)); +#else + updateWatchDataHelper(data); +#endif + } } void GdbEngine::updateWatchDataHelper(const WatchData &data) @@ -3341,12 +3357,6 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResponse &response) void GdbEngine::updateLocals() { - // Asynchronous load of injected library, initialize in first stop - if (m_dumperInjectionLoad && m_debuggingHelperState == DebuggingHelperLoadTried - && m_dumperHelper.typeCount() == 0 - && inferiorPid() > 0) - tryQueryDebuggingHelpers(); - m_pendingRequests = 0; m_processedNames.clear(); @@ -3355,13 +3365,70 @@ void GdbEngine::updateLocals() m_toolTipExpression.clear(); manager()->watchHandler()->beginCycle(); - QString level = QString::number(currentFrame()); - // '2' is 'list with type and value' - QString cmd = _("-stack-list-arguments 2 ") + level + _c(' ') + level; - postCommand(cmd, WatchUpdate, CB(handleStackListArguments)); - // '2' is 'list with type and value' - postCommand(_("-stack-list-locals 2"), WatchUpdate, - CB(handleStackListLocals)); // stage 2/2 + // Asynchronous load of injected library, initialize in first stop + if (m_dumperInjectionLoad && m_debuggingHelperState == DebuggingHelperLoadTried + && m_dumperHelper.typeCount() == 0 + && inferiorPid() > 0) + tryQueryDebuggingHelpers(); + + if (isSynchroneous()) { + QStringList expanded = m_manager->watchHandler()->expandedINames().toList(); + qDebug() << "EXPANDED: " << expanded; + postCommand(_("bb %1").arg(expanded.join(_(","))), + WatchUpdate, CB(handleStackFrame1)); + postCommand(_("p 0"), WatchUpdate, CB(handleStackFrame2)); + } else { + QString level = QString::number(currentFrame()); + // '2' is 'list with type and value' + QString cmd = _("-stack-list-arguments 2 ") + level + _c(' ') + level; + postCommand(cmd, WatchUpdate, CB(handleStackListArguments)); + // '2' is 'list with type and value' + postCommand(_("-stack-list-locals 2"), WatchUpdate, + CB(handleStackListLocals)); // stage 2/2 + } +} + +void GdbEngine::handleStackFrame1(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + QByteArray out = response.data.findChild("consolestreamoutput").data(); + while (out.endsWith(' ') || out.endsWith('\n')) + out.chop(1); + //qDebug() << "FIRST CHUNK: " << out; + m_firstChunk = out; + } else if (response.resultClass == GdbResultError) { + QTC_ASSERT(false, /**/); + } +} + +void GdbEngine::handleStackFrame2(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + QByteArray out = response.data.findChild("consolestreamoutput").data(); + while (out.endsWith(' ') || out.endsWith('\n')) + out.chop(1); + //qDebug() << "SECOND CHUNK: " << out; + out = m_firstChunk + out; + // FIXME: Hack, make sure dumper does not return "{}" + out.replace(",{}", ""); + GdbMi all("[" + out + "]"); + qDebug() << "ALL: " << all.toString(); + QList locals = all.children(); + //manager()->watchHandler()->insertBulkData(locals); + //setLocals(locals); + WatchData *data = manager()->watchHandler()->findItem(_("local")); + QTC_ASSERT(data, return); + + QList list; + foreach (const GdbMi &local, locals) + handleChildren(*data, local, &list); + + manager()->watchHandler()->insertBulkData(list); + + manager()->watchHandler()->updateWatchers(); + } else if (response.resultClass == GdbResultError) { + QTC_ASSERT(false, /**/); + } } void GdbEngine::handleStackListArguments(const GdbResponse &response) @@ -3456,14 +3523,23 @@ void GdbEngine::setLocals(const QList &locals) data.exp = nam; data.framekey = m_currentFrame + data.name; setWatchDataType(data, item.findChild("type")); - // set value only directly if it is simple enough, otherwise - // pass through the insertData() machinery - if (isIntOrFloatType(data.type) || isPointerType(data.type)) - setWatchDataValue(data, item.findChild("value")); - if (isSymbianIntType(data.type)) { - setWatchDataValue(data, item.findChild("value")); - data.setHasChildren(false); + if (isSynchroneous()) { + setWatchDataValue(data, item.findChild("value"), + item.findChild("valueencoded").data().toInt()); + // We know that the complete list of children is + // somewhere in the response. + data.setChildrenUnneeded(); + } else { + // set value only directly if it is simple enough, otherwise + // pass through the insertData() machinery + if (isIntOrFloatType(data.type) || isPointerType(data.type)) + setWatchDataValue(data, item.findChild("value")); + if (isSymbianIntType(data.type)) { + setWatchDataValue(data, item.findChild("value")); + data.setHasChildren(false); + } } + // Let's be a bit more bold: //if (!hasDebuggingHelperForType(data.type)) { // QByteArray value = item.findChild("value").data(); @@ -3515,7 +3591,8 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, //qDebug() << "DATA" << data.toString(); QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"'); //iname += '.' + exp; - postCommand(cmd, WatchUpdate, CB(handleVarListChildren), QVariant::fromValue(data)); + postCommand(cmd, WatchUpdate, + CB(handleVarListChildren), QVariant::fromValue(data)); } else if (item.findChild("numchild").data() == "0") { // happens for structs without data, e.g. interfaces. WatchData data; @@ -3533,7 +3610,8 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, WatchData data; data.iname = _(name); QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"'); - postCommand(cmd, WatchUpdate, CB(handleVarListChildren), QVariant::fromValue(data)); + postCommand(cmd, WatchUpdate, + CB(handleVarListChildren), QVariant::fromValue(data)); } else if (exp == "staticMetaObject") { // && item.findChild("type").data() == "const QMetaObject") // FIXME: Namespaces? @@ -3655,6 +3733,9 @@ void GdbEngine::assignValueInDebugger(const QString &expression, const QString & void GdbEngine::tryLoadDebuggingHelpers() { + if (isSynchroneous()) + return; + if (m_debuggingHelperState != DebuggingHelperUninitialized) return; if (!startModeAllowsDumpers()) { @@ -3735,9 +3816,13 @@ void GdbEngine::tryLoadDebuggingHelpers() void GdbEngine::tryQueryDebuggingHelpers() { +#if !X // retrieve list of dumpable classes postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken); postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper)); +#else + m_debuggingHelperState = DebuggingHelperUnavailable; +#endif } void GdbEngine::recheckDebuggingHelperAvailability() @@ -4186,6 +4271,10 @@ void GdbEngine::showMessageBox(int icon, const QString &title, const QString &te m_manager->showMessageBox(icon, title, text); } +bool GdbEngine::isSynchroneous() const +{ + return false; +} // // Factory diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 73d898fc2fd..56b4aefb883 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -146,9 +146,10 @@ private: Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); Q_SLOT void setUseDebuggingHelpers(const QVariant &on); Q_SLOT void setAutoDerefPointers(const QVariant &on); - virtual bool isGdbEngine() const { return true; } + bool isGdbEngine() const { return true; } + bool isSynchroneous() const; - virtual bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const; + bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const; // // Own stuff @@ -347,6 +348,9 @@ private: void handleStackListFrames(const GdbResponse &response); void handleStackSelectThread(const GdbResponse &response); void handleStackListThreads(const GdbResponse &response); + void handleStackFrame1(const GdbResponse &response); + void handleStackFrame2(const GdbResponse &response); + QByteArray m_firstChunk; Q_SLOT void reloadStack(bool forceGotoLocation); Q_SLOT void reloadFullStack(); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index b1110bda67a..619ac2bddb9 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -119,6 +119,7 @@ public: virtual bool isGdbEngine() const { return false; } virtual bool checkConfiguration(int /* toolChain */, QString * /* errorMessage */, QString * /* settingsPage */ = 0) const { return true; } + virtual bool isSynchroneous() const { return false; } protected: void showStatusMessage(const QString &msg, int timeout = -1); DebuggerState state() const;