From 75529d87d382f9403d71cd8d9c1117ad4bfc58f4 Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Mon, 5 Oct 2009 12:00:47 +0200 Subject: [PATCH] debugger: rework 'jump to source' logic --- src/plugins/debugger/debuggeractions.cpp | 2 +- src/plugins/debugger/debuggermanager.cpp | 4 +- src/plugins/debugger/gdb/gdbengine.cpp | 231 ++++++++++++----------- src/plugins/debugger/gdb/gdbengine.h | 3 +- src/plugins/debugger/stackhandler.h | 11 ++ 5 files changed, 137 insertions(+), 114 deletions(-) diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 892a79aa225..c5f3addd1d6 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -84,7 +84,7 @@ void DebuggerSettings::writeSettings(QSettings *settings) const SavedAction *DebuggerSettings::item(int code) const { - QTC_ASSERT(m_items.value(code, 0), return 0); + QTC_ASSERT(m_items.value(code, 0), qDebug() << "CODE: " << code; return 0); return m_items.value(code, 0); } diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index b316bd5f5e4..8394cbbf26f 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -454,6 +454,7 @@ void DebuggerManager::init() //QTreeView *tooltipView = qobject_cast<QTreeView *>(d->m_tooltipWindow); //tooltipView->setModel(d->m_watchHandler->model(TooltipsWatch)); qRegisterMetaType<WatchData>("WatchData"); + qRegisterMetaType<StackCookie>("StackCookie"); d->m_actions.continueAction = new QAction(tr("Continue"), this); d->m_actions.continueAction->setIcon(QIcon(":/debugger/images/debugger_continue_small.png")); @@ -707,7 +708,6 @@ void DebuggerManager::showStatusMessage(const QString &msg, int timeout) void DebuggerManager::notifyInferiorStopped() { - resetLocation(); setState(InferiorStopped); showStatusMessage(tr("Stopped."), 5000); } @@ -1349,7 +1349,7 @@ void DebuggerManager::gotoLocation(const Debugger::Internal::StackFrame &frame, { if (theDebuggerBoolSetting(OperateByInstruction) || !frame.isUsable()) { if (setMarker) - resetLocation(); + emit resetLocationRequested(); d->m_disassemblerViewAgent.setFrame(frame); } else { // Connected to the plugin. diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 4c2b2428a6c..aba7017a1ce 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -894,18 +894,13 @@ void GdbEngine::updateAll() { QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/); tryLoadDebuggingHelpers(); - updateLocals(); - postCommand(_("-stack-list-frames"), WatchUpdate, CB(handleStackListFrames1), false); + postCommand(_("-stack-list-frames"), WatchUpdate, CB(handleStackListFrames), + QVariant::fromValue<StackCookie>(StackCookie(false, true))); manager()->stackHandler()->setCurrentIndex(0); if (supportsThreads()) postCommand(_("-thread-list-ids"), WatchUpdate, CB(handleStackListThreads), 0); manager()->reloadRegisters(); -} - -void GdbEngine::handleStackListFrames1(const GdbResponse &response) -{ - handleStackListFrames(response); - manager()->gotoLocation(manager()->stackHandler()->currentFrame(), true); + updateLocals(); } void GdbEngine::handleQuerySources(const GdbResponse &response) @@ -1182,29 +1177,6 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) #endif } -void GdbEngine::reloadFullStack() -{ - QString cmd = _("-stack-list-frames"); - postCommand(cmd, WatchUpdate, CB(handleStackListFrames), true); -} - -void GdbEngine::reloadStack() -{ - QString cmd = _("-stack-list-frames"); - int stackDepth = theDebuggerAction(MaximalStackDepth)->value().toInt(); - if (stackDepth && !m_gdbAdapter->isTrkAdapter()) - cmd += _(" 0 ") + QString::number(stackDepth); - postCommand(cmd, WatchUpdate, CB(handleStackListFrames), false); - // FIXME: gdb 6.4 symbianelf likes to be asked twice. The first time it - // returns with "^error,msg="Previous frame identical to this frame - // (corrupt stack?)". Might be related to the fact that we can't - // access the memory belonging to the lower frames. But as we know - // this sometimes happens, ask the second time immediately instead - // of waiting for the first request to fail. - if (m_gdbAdapter->isTrkAdapter()) - postCommand(cmd, WatchUpdate, CB(handleStackListFrames), false); -} - void GdbEngine::handleStop1(const GdbResponse &response) { GdbMi data = response.cookie.value<GdbMi>(); @@ -1307,7 +1279,7 @@ void GdbEngine::handleStop2(const GdbMi &data) manager()->stackHandler()->setCurrentIndex(0); updateLocals(); // Quick shot - reloadStack(); + reloadStack(false); if (supportsThreads()) { int currentId = data.findChild("thread-id").data().toInt(); @@ -2235,13 +2207,52 @@ void GdbEngine::reloadSourceFiles() // ////////////////////////////////////////////////////////////////////// +void GdbEngine::selectThread(int index) +{ + ThreadsHandler *threadsHandler = manager()->threadsHandler(); + threadsHandler->setCurrentThread(index); + + QList<ThreadData> threads = threadsHandler->threads(); + QTC_ASSERT(index < threads.size(), return); + int id = threads.at(index).id; + showStatusMessage(tr("Retrieving data for stack view..."), 10000); + postCommand(_("-thread-select %1").arg(id), CB(handleStackSelectThread)); +} + void GdbEngine::handleStackSelectThread(const GdbResponse &) { + QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/); //qDebug("FIXME: StackHandler::handleOutput: SelectThread"); showStatusMessage(tr("Retrieving data for stack view..."), 3000); - reloadStack(); + manager()->reloadRegisters(); + reloadStack(true); + updateLocals(); } +void GdbEngine::reloadFullStack() +{ + QString cmd = _("-stack-list-frames"); + postCommand(cmd, WatchUpdate, CB(handleStackListFrames), + QVariant::fromValue<StackCookie>(StackCookie(true, true))); +} + +void GdbEngine::reloadStack(bool forceGotoLocation) +{ + QString cmd = _("-stack-list-frames"); + int stackDepth = theDebuggerAction(MaximalStackDepth)->value().toInt(); + if (stackDepth && !m_gdbAdapter->isTrkAdapter()) + cmd += _(" 0 ") + QString::number(stackDepth); + // FIXME: gdb 6.4 symbianelf likes to be asked twice. The first time it + // returns with "^error,msg="Previous frame identical to this frame + // (corrupt stack?)". Might be related to the fact that we can't + // access the memory belonging to the lower frames. But as we know + // this sometimes happens, ask the second time immediately instead + // of waiting for the first request to fail. + if (m_gdbAdapter->isTrkAdapter()) + postCommand(cmd, WatchUpdate); + postCommand(cmd, WatchUpdate, CB(handleStackListFrames), + QVariant::fromValue<StackCookie>(StackCookie(false, forceGotoLocation))); +} StackFrame GdbEngine::parseStackFrame(const GdbMi &frameMi, int level) { @@ -2266,94 +2277,94 @@ void GdbEngine::handleStackListFrames(const GdbResponse &response) #else bool handleIt = response.resultClass == GdbResultDone; #endif - if (handleIt) { - bool isFull = response.cookie.toBool(); - QList<StackFrame> stackFrames; - - GdbMi stack = response.data.findChild("stack"); - if (!stack.isValid()) { - qDebug() << "FIXME: stack:" << stack.toString(); - return; - } + if (!handleIt) { + // That always happens on symbian gdb with + // ^error,data={msg="Previous frame identical to this frame (corrupt stack?)" + // logstreamoutput="Previous frame identical to this frame (corrupt stack?)\n" + //qDebug() << "LISTING STACK FAILED: " << response.toString(); + return; + } - int topFrame = -1; + StackCookie cookie = response.cookie.value<StackCookie>(); + QList<StackFrame> stackFrames; - int n = stack.childCount(); - for (int i = 0; i != n; ++i) { - stackFrames.append(parseStackFrame(stack.childAt(i), i)); - const StackFrame &frame = stackFrames.back(); + GdbMi stack = response.data.findChild("stack"); + if (!stack.isValid()) { + qDebug() << "FIXME: stack:" << stack.toString(); + return; + } - #if defined(Q_OS_WIN) - const bool isBogus = - // Assume this is wrong and points to some strange stl_algobase - // implementation. Happens on Karsten's XP system with Gdb 5.50 - (frame.file.endsWith(__("/bits/stl_algobase.h")) && frame.line == 150) - // Also wrong. Happens on Vista with Gdb 5.50 - || (frame.function == __("operator new") && frame.line == 151); + int targetFrame = -1; - // Immediately leave bogus frames. - if (topFrame == -1 && isBogus) { - postCommand(_("-exec-finish")); - return; - } - #endif + int n = stack.childCount(); + for (int i = 0; i != n; ++i) { + stackFrames.append(parseStackFrame(stack.childAt(i), i)); + const StackFrame &frame = stackFrames.back(); - // Initialize top frame to the first valid frame. - // FIXME: Check for QFile(frame.fullname).isReadable()? - const bool isValid = !frame.file.isEmpty() && !frame.function.isEmpty(); - if (isValid && topFrame == -1) - topFrame = i; + #if defined(Q_OS_WIN) + const bool isBogus = + // Assume this is wrong and points to some strange stl_algobase + // implementation. Happens on Karsten's XP system with Gdb 5.50 + (frame.file.endsWith(__("/bits/stl_algobase.h")) && frame.line == 150) + // Also wrong. Happens on Vista with Gdb 5.50 + || (frame.function == __("operator new") && frame.line == 151); + + // Immediately leave bogus frames. + if (targetFrame == -1 && isBogus) { + postCommand(_("-exec-finish")); + return; } - - bool canExpand = !isFull - && (n >= theDebuggerAction(MaximalStackDepth)->value().toInt()); - theDebuggerAction(ExpandStack)->setEnabled(canExpand); - manager()->stackHandler()->setFrames(stackFrames, canExpand); - - #ifdef Q_OS_MAC - // Mac gdb does not add the location to the "stopped" message, - // so the early gotoLocation() was not triggered. Force it here. - bool jump = topFrame != -1 - && !theDebuggerBoolSetting(OperateByInstruction); - #else - // For topFrame == -1 there is no frame at all, for topFrame == 0 - // we already issued a 'gotoLocation' when reading the *stopped - // message. Also, when OperateByInstruction we always want to - // use frame #0. - bool jump = topFrame != -1 && topFrame != 0 - && !theDebuggerBoolSetting(OperateByInstruction); #endif - - if (jump) { - const StackFrame &frame = manager()->stackHandler()->currentFrame(); - qDebug() << "GOTO, 2nd try" << frame.toString() << topFrame; - gotoLocation(frame, true); - } - } else { - // That always happens on symbian gdb with - // ^error,data={msg="Previous frame identical to this frame (corrupt stack?)" - // logstreamoutput="Previous frame identical to this frame (corrupt stack?)\n" - //qDebug() << "LISTING STACK FAILED: " << response.toString(); + + // Initialize top frame to the first valid frame. + // FIXME: Check for QFile(frame.fullname).isReadable()? + const bool isValid = !frame.file.isEmpty() && !frame.function.isEmpty(); + if (isValid && targetFrame == -1) + targetFrame = i; } -} -void GdbEngine::selectThread(int index) -{ - //reset location arrow - m_manager->resetLocation(); + bool canExpand = !cookie.isFull + && (n >= theDebuggerAction(MaximalStackDepth)->value().toInt()); + theDebuggerAction(ExpandStack)->setEnabled(canExpand); + manager()->stackHandler()->setFrames(stackFrames, canExpand); - ThreadsHandler *threadsHandler = manager()->threadsHandler(); - threadsHandler->setCurrentThread(index); + // We can't jump to any file if we don't have any frames. + if (stackFrames.isEmpty()) + return; - QList<ThreadData> threads = threadsHandler->threads(); - QTC_ASSERT(index < threads.size(), return); - int id = threads.at(index).id; - showStatusMessage(tr("Retrieving data for stack view..."), 10000); - postCommand(_("-thread-select %1").arg(id), CB(handleStackSelectThread)); + // targetFrame contains the top most frame for which we have source + // information. That's typically the frame we'd like to jump to, with + // a few exceptions: + + // Always jump to frame #0 when stepping by instruction. + if (theDebuggerBoolSetting(OperateByInstruction)) + targetFrame = 0; + + // If there is no frame with source, jump to frame #0. + if (targetFrame == -1) + targetFrame = 0; + + #ifdef Q_OS_MAC + // Mac gdb does not add the location to the "stopped" message, + // so the early gotoLocation() was not triggered. Force it here. + bool jump = true; + #else + // For targetFrame == 0 we already issued a 'gotoLocation' + // when reading the *stopped message. + bool jump = targetFrame != 0; + #endif + + manager()->stackHandler()->setCurrentIndex(targetFrame); + if (jump || cookie.gotoLocation) { + const StackFrame &frame = manager()->stackHandler()->currentFrame(); + //qDebug() << "GOTO, 2ND ATTEMPT: " << frame.toString() << targetFrame; + gotoLocation(frame, true); + } } void GdbEngine::activateFrame(int frameIndex) { + m_manager->resetLocation(); if (state() != InferiorStopped) return; @@ -2394,7 +2405,8 @@ void GdbEngine::handleStackListThreads(const GdbResponse &response) thread.id = items.at(index).data().toInt(); threads.append(thread); if (thread.id == id) { - //qDebug() << "SETTING INDEX TO:" << index << " ID:" << id << " RECOD:" << response.toString(); + //qDebug() << "SETTING INDEX TO:" << index << " ID:" + // << id << " RECOD:" << response.toString(); currentIndex = index; } } @@ -3086,7 +3098,7 @@ void GdbEngine::sendWatchParameters(const QByteArray ¶ms0) void GdbEngine::handleVarAssign(const GdbResponse &) { - // everything might have changed, force re-evaluation + // Everything might have changed, force re-evaluation. // FIXME: Speed this up by re-using variables and only // marking values as 'unknown' setTokenBarrier(); @@ -3421,7 +3433,8 @@ void GdbEngine::handleStackListArguments(const GdbResponse &response) const GdbMi args = frame.findChild("args"); m_currentFunctionArgs = args.children(); } else if (response.resultClass == GdbResultError) { - qDebug() << "FIXME: GdbEngine::handleStackListArguments: should not happen"; + qDebug() << "FIXME: GdbEngine::handleStackListArguments: should not happen" + << response.toString(); } } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 58352b4ab34..6b5b5ebcb9e 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -339,10 +339,9 @@ private: // Stack specific stuff // void handleStackListFrames(const GdbResponse &response); - void handleStackListFrames1(const GdbResponse &response); void handleStackSelectThread(const GdbResponse &response); void handleStackListThreads(const GdbResponse &response); - Q_SLOT void reloadStack(); + Q_SLOT void reloadStack(bool forceGotoLocation); Q_SLOT void reloadFullStack(); diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h index dd2c0a4997f..8b0d7a165c3 100644 --- a/src/plugins/debugger/stackhandler.h +++ b/src/plugins/debugger/stackhandler.h @@ -41,6 +41,14 @@ namespace Debugger { namespace Internal { +struct StackCookie +{ + StackCookie() : isFull(true), gotoLocation(false) {} + StackCookie(bool full, bool jump) : isFull(full), gotoLocation(jump) {} + bool isFull; + bool gotoLocation; +}; + //////////////////////////////////////////////////////////////////////// // // StackModel @@ -129,4 +137,7 @@ private: } // namespace Internal } // namespace Debugger +Q_DECLARE_METATYPE(Debugger::Internal::StackCookie) + + #endif // DEBUGGER_STACKHANDLER_H -- GitLab