From c50dd8508807ba10e816a0e32f7ed60fc990df48 Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Wed, 19 May 2010 12:00:01 +0200 Subject: [PATCH] debugger: show return value of last function call in Locals and Watchers view Works only with gdb/Python so far. --- share/qtcreator/gdbmacros/dumper.py | 18 ++++- src/plugins/debugger/debuggermanager.cpp | 17 ++++- src/plugins/debugger/gdb/gdbengine.cpp | 15 +++- src/plugins/debugger/gdb/gdbengine.h | 4 ++ src/plugins/debugger/gdb/pythongdbengine.cpp | 6 +- src/plugins/debugger/watchhandler.cpp | 14 ++++ src/plugins/debugger/watchhandler.h | 3 +- src/plugins/debugger/watchwindow.h | 2 +- tests/manual/gdbdebugger/simple/app.cpp | 75 ++++++++++++++------ 9 files changed, 124 insertions(+), 30 deletions(-) diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py index e31b15471c7..8cf4a744ad2 100644 --- a/share/qtcreator/gdbmacros/dumper.py +++ b/share/qtcreator/gdbmacros/dumper.py @@ -385,6 +385,8 @@ def listOfLocals(varList): hasBlock = 'block' in __builtin__.dir(frame) items = [] + #warn("HAS BLOCK: %s" % hasBlock); + #warn("IS GOOD GDB: %s" % isGoodGdb()); if hasBlock and isGoodGdb(): #warn("IS GOOD: %s " % varList) try: @@ -780,6 +782,7 @@ class FrameCommand(gdb.Command): formats = {} watchers = "" expandedINames = "" + resultVarName = "" for arg in args.split(' '): pos = arg.find(":") + 1 if arg.startswith("options:"): @@ -787,6 +790,8 @@ class FrameCommand(gdb.Command): elif arg.startswith("vars:"): if len(arg[pos:]) > 0: varList = arg[pos:].split(",") + elif arg.startswith("resultvarname:"): + resultVarName = arg[pos:] elif arg.startswith("expanded:"): expandedINames = set(arg[pos:].split(",")) elif arg.startswith("typeformats:"): @@ -847,7 +852,18 @@ class FrameCommand(gdb.Command): # # Locals # - for item in listOfLocals(varList): + locals = listOfLocals(varList); + + # Take care of the return value of the last function call. + if len(resultVarName) > 0: + try: + value = parseAndEvaluate(resultVarName) + locals.append(Item(value, "return", resultVarName, "return")) + except: + # Don't bother. It's only supplementary information anyway. + pass + + for item in locals: with OutputSafer(d, "", ""): d.anonNumber = -1 #warn("ITEM NAME %s: " % item.name) diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 905495bc3ac..8a3f2e150fe 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -297,14 +297,15 @@ struct DebuggerManagerPrivate DebuggerManagerActions m_actions; QWidget *m_breakWindow; + QWidget *m_returnWindow; QWidget *m_localsWindow; + QWidget *m_watchersWindow; QWidget *m_registerWindow; QWidget *m_modulesWindow; QWidget *m_snapshotWindow; SourceFilesWindow *m_sourceFilesWindow; QWidget *m_stackWindow; QWidget *m_threadsWindow; - QWidget *m_watchersWindow; DebuggerOutputWindow *m_outputWindow; bool m_busy; @@ -401,6 +402,8 @@ void DebuggerManager::init() d->m_sourceFilesWindow->setObjectName(QLatin1String("CppDebugSources")); d->m_threadsWindow = new ThreadsWindow; d->m_threadsWindow->setObjectName(QLatin1String("CppDebugThreads")); + d->m_returnWindow = new WatchWindow(WatchWindow::ReturnType, this); + d->m_returnWindow->setObjectName(QLatin1String("CppDebugReturn")); d->m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this); d->m_localsWindow->setObjectName(QLatin1String("CppDebugLocals")); d->m_watchersWindow = new WatchWindow(WatchWindow::WatchersType, this); @@ -484,8 +487,13 @@ void DebuggerManager::init() d->m_registerHandler = new RegisterHandler; registerView->setModel(d->m_registerHandler->model()); - // Locals + + // Return Value d->m_watchHandler = new WatchHandler(this); + QTreeView *returnView = qobject_cast<QTreeView *>(d->m_returnWindow); + returnView->setModel(d->m_watchHandler->model(ReturnWatch)); + + // Locals QTreeView *localsView = qobject_cast<QTreeView *>(d->m_localsWindow); localsView->setModel(d->m_watchHandler->model(LocalsWatch)); @@ -633,6 +641,7 @@ void DebuggerManager::init() localsAndWatchers->setObjectName(QLatin1String("CppDebugLocalsAndWatchers")); localsAndWatchers->setWindowTitle(d->m_localsWindow->windowTitle()); localsAndWatchers->addWidget(d->m_localsWindow); + localsAndWatchers->addWidget(d->m_returnWindow); localsAndWatchers->addWidget(d->m_watchersWindow); //localsAndWatchers->addWidget(d->m_tooltipWindow); localsAndWatchers->setStretchFactor(0, 3); @@ -1365,6 +1374,7 @@ void DebuggerManager::setBusyCursor(bool busy) QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor); d->m_breakWindow->setCursor(cursor); + d->m_returnWindow->setCursor(cursor); d->m_localsWindow->setCursor(cursor); d->m_modulesWindow->setCursor(cursor); d->m_outputWindow->setCursor(cursor); @@ -1947,6 +1957,7 @@ static void changeFontSize(QWidget *widget, int size) void DebuggerManager::fontSettingsChanged(const TextEditor::FontSettings &settings) { int size = settings.fontZoom() * settings.fontSize() / 100; + changeFontSize(d->m_returnWindow, size); changeFontSize(d->m_localsWindow, size); changeFontSize(d->m_watchersWindow, size); changeFontSize(d->m_breakWindow, size); @@ -1968,6 +1979,8 @@ void DebuggerManager::updateWatchersWindow() { d->m_watchersWindow->setVisible( d->m_watchHandler->model(WatchersWatch)->rowCount(QModelIndex()) > 0); + d->m_returnWindow->setVisible( + d->m_watchHandler->model(ReturnWatch)->rowCount(QModelIndex()) > 0); } void DebuggerManager::openTextEditor(const QString &titlePattern, diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 36037e631d7..1cde8b29ed3 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -274,6 +274,7 @@ void GdbEngine::initializeVariables() m_pendingLogStreamOutput.clear(); m_inbuffer.clear(); + m_resultVarName.clear(); m_commandTimer->stop(); @@ -1290,7 +1291,7 @@ void GdbEngine::handleStopResponse(const GdbMi &data) } #endif - // seen on XP after removing a breakpoint while running + // This was seen on XP after removing a breakpoint while running // >945*stopped,reason="signal-received",signal-name="SIGTRAP", // signal-meaning="Trace/breakpoint trap",thread-id="2", // frame={addr="0x7c91120f",func="ntdll!DbgUiConnectToDbg", @@ -1333,6 +1334,18 @@ void GdbEngine::handleStopResponse(const GdbMi &data) } } + // Show return value if possible, usually with reason "function-finished". + // *stopped,reason="function-finished",frame={addr="0x080556da", + // func="testReturnValue",args=[],file="/../app.cpp", + // fullname="/../app.cpp",line="1611"},gdb-result-var="$1", + // return-value="{d = 0x808d998}",thread-id="1",stopped-threads="all", + // core="1" + GdbMi resultVar = data.findChild("gdb-result-var"); + if (resultVar.isValid()) + m_resultVarName = resultVar.data(); + else + m_resultVarName.clear(); + bool initHelpers = m_debuggingHelperState == DebuggingHelperUninitialized || m_debuggingHelperState == DebuggingHelperLoadTried; // Don't load helpers on stops triggered by signals unless it's diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index a1b94ae9ec5..3b1f7d49d44 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -170,6 +170,10 @@ private: AbstractGdbAdapter *m_gdbAdapter; + // Name of the convenience variable containing the last + // known function return value. + QByteArray m_resultVarName; + private: ////////// Gdb Command Management ////////// public: // Otherwise the Qt flag macros are unhappy. diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp index db59f7f6b94..fa46242f52a 100644 --- a/src/plugins/debugger/gdb/pythongdbengine.cpp +++ b/src/plugins/debugger/gdb/pythongdbengine.cpp @@ -85,8 +85,12 @@ void GdbEngine::updateLocalsPython(const QByteArray &varList) options += "defaults,"; options.chop(1); + QByteArray resultVar; + if (!m_resultVarName.isEmpty()) + resultVar = "resultvarname:" + m_resultVarName + ' '; + postCommand("bb options:" + options + " vars:" + varList + ' ' - + expanded + " watchers:" + watchers.toHex(), + + resultVar + expanded + " watchers:" + watchers.toHex(), WatchUpdate, CB(handleStackFramePython)); } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index b4cfd13f26e..f10e8fc5ed3 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -120,6 +120,10 @@ WatchModel::WatchModel(WatchHandler *handler, WatchType type) m_root->parent = 0; switch (m_type) { + case ReturnWatch: + m_root->iname = "return"; + m_root->name = WatchHandler::tr("Return Value"); + break; case LocalsWatch: m_root->iname = "local"; m_root->name = WatchHandler::tr("Locals"); @@ -964,6 +968,7 @@ WatchHandler::WatchHandler(DebuggerManager *manager) m_expandPointers = true; m_inChange = false; + m_return = new WatchModel(this, ReturnWatch); m_locals = new WatchModel(this, LocalsWatch); m_watchers = new WatchModel(this, WatchersWatch); m_tooltips = new WatchModel(this, TooltipsWatch); @@ -981,6 +986,7 @@ WatchHandler::WatchHandler(DebuggerManager *manager) void WatchHandler::beginCycle() { ++generationCounter; + m_return->beginCycle(); m_locals->beginCycle(); m_watchers->beginCycle(); m_tooltips->beginCycle(); @@ -988,6 +994,7 @@ void WatchHandler::beginCycle() void WatchHandler::endCycle() { + m_return->endCycle(); m_locals->endCycle(); m_watchers->endCycle(); m_tooltips->endCycle(); @@ -997,8 +1004,10 @@ void WatchHandler::endCycle() void WatchHandler::cleanup() { m_expandedINames.clear(); + m_return->reinitialize(); m_locals->reinitialize(); m_tooltips->reinitialize(); + m_return->m_fetchTriggered.clear(); m_locals->m_fetchTriggered.clear(); m_watchers->m_fetchTriggered.clear(); m_tooltips->m_fetchTriggered.clear(); @@ -1014,6 +1023,7 @@ void WatchHandler::cleanup() void WatchHandler::emitAllChanged() { + m_return->emitAllChanged(); m_locals->emitAllChanged(); m_watchers->emitAllChanged(); m_tooltips->emitAllChanged(); @@ -1337,6 +1347,7 @@ void WatchHandler::loadSessionData() WatchModel *WatchHandler::model(WatchType type) const { switch (type) { + case ReturnWatch: return m_return; case LocalsWatch: return m_locals; case WatchersWatch: return m_watchers; case TooltipsWatch: return m_tooltips; @@ -1347,6 +1358,8 @@ WatchModel *WatchHandler::model(WatchType type) const WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const { + if (iname.startsWith("return")) + return m_return; if (iname.startsWith("local")) return m_locals; if (iname.startsWith("tooltip")) @@ -1374,6 +1387,7 @@ void WatchHandler::setFormat(const QString &type, int format) { m_typeFormats[type] = format; saveTypeFormats(); + m_return->emitDataChanged(1); m_locals->emitDataChanged(1); m_watchers->emitDataChanged(1); m_tooltips->emitDataChanged(1); diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 8890dee5079..9a4dad79a80 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -51,7 +51,7 @@ namespace Internal { class WatchItem; class WatchHandler; -enum WatchType { LocalsWatch, WatchersWatch, TooltipsWatch }; +enum WatchType { ReturnWatch, LocalsWatch, WatchersWatch, TooltipsWatch }; enum WatchRoles { @@ -206,6 +206,7 @@ private: // Items expanded in the Locals & Watchers view. QSet<QByteArray> m_expandedINames; + WatchModel *m_return; WatchModel *m_locals; WatchModel *m_watchers; WatchModel *m_tooltips; diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index e252a9f14a7..b08f9282039 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -48,7 +48,7 @@ class WatchWindow : public QTreeView Q_OBJECT public: - enum Type { LocalsType, TooltipType, WatchersType }; + enum Type { ReturnType, LocalsType, TooltipType, WatchersType }; WatchWindow(Type type, DebuggerManager *manager, QWidget *parent = 0); void setType(Type type) { m_type = type; } diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index 03c191f9a0f..106e6a32bb8 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -318,18 +318,19 @@ void testAnonymous() #endif } -void testFunctionPointer() +typedef void (*func_t)(); +func_t testFunctionPointer() { - typedef void (*func_t)(); func_t f1 = testAnonymous; - func_t f2 = testFunctionPointer; - func_t f3 = testFunctionPointer; + func_t f2 = testPeekAndPoke3; + func_t f3 = testPeekAndPoke3; Q_UNUSED(f1); Q_UNUSED(f2); Q_UNUSED(f3); + return f1; } -void testQByteArray() +QByteArray testQByteArray() { QByteArray ba = "Hello"; ba += '"'; @@ -345,6 +346,7 @@ void testQByteArray() ba += char(0); ba += 1; ba += 2; + return ba; } static void throwit1() @@ -368,7 +370,7 @@ int testCatchThrow() return gotit; } -void testQDateTime() +QDateTime testQDateTime() { QDateTime date; date = QDateTime::currentDateTime(); @@ -376,18 +378,20 @@ void testQDateTime() date = date.addSecs(5); date = date.addSecs(5); date = date.addSecs(5); + return date; } -void testQFileInfo() +QFileInfo testQFileInfo() { QFileInfo fi("/tmp/t"); QString s = fi.absoluteFilePath(); s = fi.bundleName(); s = fi.bundleName(); s = fi.bundleName(); + return fi; } -void testQHash() +QHash<int, float> testQHash() { #if 1 QHash<int, float> hgg0; @@ -439,6 +443,7 @@ void testQHash() hash.insert("Welt", QPointer<QObject>(&ob)); hash.insert(".", QPointer<QObject>(&ob)); #endif + return hgg0; } void testQImage() @@ -908,7 +913,7 @@ void testStdHashSet() #endif } -void testStdList() +std::list<int> testStdList() { std::list<int> big; for (int i = 0; i < 10000; ++i) @@ -948,6 +953,7 @@ void testStdList() vec.push_back(true); vec.push_back(false); #endif + return big; } void testStdMap() @@ -1008,7 +1014,7 @@ void testStdMap() #endif } -void testStdSet() +std::set<int> testStdSet() { std::set<int> hgg0; hgg0.insert(11); @@ -1022,9 +1028,10 @@ void testStdSet() std::set<QPointer<QObject> > hash; QPointer<QObject> ptr(&ob); #endif + return hgg0; } -void testStdStack() +std::stack<int> testStdStack() { std::stack<int *> plist1; plist1.push(new int(1)); @@ -1045,9 +1052,11 @@ void testStdStack() std::stack<Foo> flist; flist.push(1); flist.push(2); + + return flist2; } -void testStdString() +std::string testStdString() { QString foo; std::string str; @@ -1083,9 +1092,11 @@ void testStdString() v.push_back(str); v.push_back(str); v.push_back(str); + + return str; } -void testStdVector() +std::vector<int> testStdVector() { std::vector<int *> plist1; plist1.push_back(new int(1)); @@ -1119,6 +1130,8 @@ void testStdVector() std::vector<bool> vec; vec.push_back(true); vec.push_back(false); + + return flist2; } void testQStandardItemModel() @@ -1140,7 +1153,7 @@ void testQStandardItemModel() ++i; } -void testQStack() +QStack<int> testQStack() { QVector<int> bigv; for (int i = 0; i < 10; ++i) @@ -1162,9 +1175,10 @@ void testQStack() QStack<bool> vec; vec.append(true); vec.append(false); + return big; } -void testQString() +QString testQString() { QUrl url(QString("http://www.nokia.com")); @@ -1176,6 +1190,7 @@ void testQString() str += " World "; str += " World "; str += " World "; + return str; } void testQString3() @@ -1194,7 +1209,7 @@ void testQString3() delete pstring; } -void testQStringList() +QStringList testQStringList() { QStringList l; l << "Hello "; @@ -1202,14 +1217,16 @@ void testQStringList() l << " fat "; l.takeFirst(); l << " World "; + return l; } -void testStruct() +Foo testStruct() { Foo f(2); f.doit(); f.doit(); f.doit(); + return f; } class Thread : public QThread @@ -1242,7 +1259,7 @@ void testQThread() thread2.wait(); } -void testQVariant1() +QVariant testQVariant1() { QVariant v; v = 1; @@ -1250,9 +1267,10 @@ void testQVariant1() v = "string"; v = QRect(100, 200, 300, 400); v = 1; + return v; } -void testQVariant2() +QVariant testQVariant2() { QVariant value; QVariant::Type t = QVariant::String; @@ -1295,18 +1313,20 @@ void testQVariant2() var.setValue(my); var.setValue(my); #endif + return value; } -void testQVariant3() +QVariant testQVariant3() { QList<int> list; list << 1 << 2 << 3; QVariant variant = qVariantFromValue(list); list.clear(); list = qVariantValue<QList<int> >(variant); + return variant; } -void testQVector() +QVector<int> testQVector() { QVector<int> big(10000); @@ -1326,15 +1346,18 @@ void testQVector() QVector<bool> vec; vec.append(true); vec.append(false); + + return big; } -void testQVectorOfQList() +QVector<QList<int> > testQVectorOfQList() { QVector<QList<int> > v; QVector<QList<int> > *pv = &v; v.append(QList<int>() << 1); v.append(QList<int>() << 2 << 3); Q_UNUSED(pv); + return v; } @@ -1600,10 +1623,16 @@ struct Color Color() { r = 1, g = 2, b = 3, a = 4; } }; -void testColor() +Color testColor() { Color c; c.r = 5; + return c; +} + +int fooii() +{ + return 3; } int main(int argc, char *argv[]) -- GitLab