1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
28 **************************************************************************/
30 #include "debuggerengine.h"
32 #include "debuggeractions.h"
33 #include "debuggeragents.h"
34 #include "debuggerrunner.h"
35 #include "debuggeroutputwindow.h"
36 #include "debuggerplugin.h"
37 #include "debuggerstringutils.h"
39 #include "breakhandler.h"
40 #include "moduleshandler.h"
41 #include "registerhandler.h"
42 #include "snapshothandler.h"
43 #include "sourcefileshandler.h"
44 #include "stackhandler.h"
45 #include "threadshandler.h"
46 #include "watchhandler.h"
47 #include "watchutils.h"
49 #include <coreplugin/icore.h>
50 #include <coreplugin/editormanager/editormanager.h>
51 #include <coreplugin/progressmanager/progressmanager.h>
52 #include <coreplugin/progressmanager/futureprogress.h>
54 #include <projectexplorer/debugginghelper.h>
55 #include <projectexplorer/environment.h>
56 #include <projectexplorer/project.h>
57 #include <projectexplorer/projectexplorerconstants.h>
58 #include <projectexplorer/target.h>
59 #include <projectexplorer/buildconfiguration.h>
60 #include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
62 #include <qt4projectmanager/qt4projectmanagerconstants.h>
64 #include <texteditor/itexteditor.h>
66 #include <utils/savedaction.h>
67 #include <utils/qtcassert.h>
69 #include <QtCore/QDebug>
70 #include <QtCore/QDir>
71 #include <QtCore/QFileInfo>
72 #include <QtCore/QTimer>
73 #include <QtCore/QFutureInterface>
75 #include <QtGui/QAbstractItemView>
76 #include <QtGui/QStandardItemModel>
77 #include <QtGui/QAction>
78 #include <QtGui/QMenu>
79 #include <QtGui/QMessageBox>
80 #include <QtGui/QPlainTextEdit>
81 #include <QtGui/QPushButton>
82 #include <QtGui/QTextBlock>
83 #include <QtGui/QTextCursor>
84 #include <QtGui/QTextDocument>
85 #include <QtGui/QTreeWidget>
89 using namespace Debugger;
90 using namespace Debugger::Internal;
91 using namespace ProjectExplorer;
92 using namespace TextEditor;
94 //#define DEBUG_STATE 1
96 # define SDEBUG(s) qDebug() << s
100 # define XSDEBUG(s) qDebug() << s
102 ///////////////////////////////////////////////////////////////////////
104 // DebuggerStartParameters
106 ///////////////////////////////////////////////////////////////////////
108 DebuggerStartParameters::DebuggerStartParameters()
112 , qmlServerAddress("127.0.0.1")
114 , toolChainType(ToolChain::UNKNOWN)
115 , startMode(NoStartMode)
119 void DebuggerStartParameters::clear()
121 *this = DebuggerStartParameters();
127 QDebug operator<<(QDebug d, DebuggerState state)
129 //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')';
130 return d << DebuggerEngine::stateName(state);
133 QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
135 QDebug nospace = str.nospace();
136 const QString sep = QString(QLatin1Char(','));
137 nospace << "executable=" << sp.executable
138 << " coreFile=" << sp.coreFile
139 << " processArgs=" << sp.processArgs.join(sep)
140 << " environment=<" << sp.environment.size() << " variables>"
141 << " workingDir=" << sp.workingDirectory
142 << " attachPID=" << sp.attachPID
143 << " useTerminal=" << sp.useTerminal
144 << " remoteChannel=" << sp.remoteChannel
145 << " remoteArchitecture=" << sp.remoteArchitecture
146 << " symbolFileName=" << sp.symbolFileName
147 << " serverStartScript=" << sp.serverStartScript
148 << " toolchain=" << sp.toolChainType << '\n';
155 const char *DebuggerEngine::stateName(int s)
157 # define SN(x) case x: return #x;
160 SN(EngineSetupRequested)
162 SN(EngineSetupFailed)
164 SN(InferiorSetupRequested)
165 SN(InferiorSetupFailed)
166 SN(EngineRunRequested)
167 SN(InferiorRunRequested)
169 SN(InferiorRunFailed)
170 SN(InferiorUnrunnable)
171 SN(InferiorStopRequested)
173 SN(InferiorStopFailed)
174 SN(InferiorShutdownRequested)
175 SN(InferiorShutdownOk)
176 SN(InferiorShutdownFailed)
177 SN(EngineShutdownRequested)
179 SN(EngineShutdownFailed)
187 //////////////////////////////////////////////////////////////////////
191 //////////////////////////////////////////////////////////////////////
193 class CommandHandler : public QStandardItemModel
196 explicit CommandHandler(DebuggerEngine *engine) : m_engine(engine) {}
197 bool setData(const QModelIndex &index, const QVariant &value, int role);
198 QAbstractItemModel *model() { return this; }
201 QPointer<DebuggerEngine> m_engine;
204 bool CommandHandler::setData(const QModelIndex &, const QVariant &value, int role)
206 QTC_ASSERT(m_engine, qDebug() << value << role; return false);
207 m_engine->handleCommand(role, value);
212 //////////////////////////////////////////////////////////////////////
214 // DebuggerEnginePrivate
216 //////////////////////////////////////////////////////////////////////
218 class DebuggerEnginePrivate : public QObject
223 DebuggerEnginePrivate(DebuggerEngine *engine, const DebuggerStartParameters &sp)
227 m_startParameters(sp),
228 m_state(DebuggerNotReady),
229 m_lastGoodState(DebuggerNotReady),
230 m_breakHandler(engine),
231 m_commandHandler(engine),
232 m_modulesHandler(engine),
233 m_registerHandler(engine),
234 m_sourceFilesHandler(engine),
235 m_stackHandler(engine),
236 m_threadsHandler(engine),
237 m_watchHandler(engine),
238 m_disassemblerViewAgent(engine),
239 m_runInWrapperEngine(false)
242 ~DebuggerEnginePrivate() {}
245 void breakpointSetRemoveMarginActionTriggered();
246 void breakpointEnableDisableMarginActionTriggered();
247 void handleContextMenuRequest(const QVariant ¶meters);
249 void doSetupInferior();
251 void doShutdownEngine();
252 void doShutdownInferior();
253 void doInterruptInferior();
254 void doFinishDebugger();
256 void queueRunEngine() {
257 m_engine->setState(EngineRunRequested);
258 m_engine->showMessage(_("QUEUE: RUN ENGINE"));
259 QTimer::singleShot(0, this, SLOT(doRunEngine()));
262 void queueShutdownEngine() {
263 m_engine->setState(EngineShutdownRequested);
264 m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
265 QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
268 void queueShutdownInferior() {
269 m_engine->setState(InferiorShutdownRequested);
270 m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
271 QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
274 void queueFinishDebugger() {
275 QTC_ASSERT(state() == EngineShutdownOk
276 || state() == EngineShutdownFailed, qDebug() << state());
277 m_engine->setState(DebuggerFinished);
278 m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
279 QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
282 void raiseApplication() {
283 QTC_ASSERT(m_runControl, return);
284 m_runControl->bringApplicationToForeground(m_inferiorPid);
289 DebuggerState state() const { return m_state; }
291 DebuggerEngine *m_engine; // Not owned.
292 DebuggerRunControl *m_runControl; // Not owned.
295 DebuggerStartParameters m_startParameters;
297 // The current state.
298 DebuggerState m_state;
300 // The state we had before something unexpected happend.
301 DebuggerState m_lastGoodState;
303 // The state we are aiming for.
304 DebuggerState m_targetState;
306 qint64 m_inferiorPid;
308 BreakHandler m_breakHandler;
309 CommandHandler m_commandHandler;
310 ModulesHandler m_modulesHandler;
311 RegisterHandler m_registerHandler;
312 SourceFilesHandler m_sourceFilesHandler;
313 StackHandler m_stackHandler;
314 ThreadsHandler m_threadsHandler;
315 WatchHandler m_watchHandler;
316 DisassemblerViewAgent m_disassemblerViewAgent;
317 QFutureInterface<void> m_progress;
319 bool m_runInWrapperEngine;
322 void DebuggerEnginePrivate::breakpointSetRemoveMarginActionTriggered()
324 QAction *act = qobject_cast<QAction *>(sender());
325 QTC_ASSERT(act, return);
326 QList<QVariant> list = act->data().toList();
327 QTC_ASSERT(list.size() == 2, return);
328 const QString fileName = list.at(0).toString();
329 const int lineNumber = list.at(1).toInt();
330 m_breakHandler.toggleBreakpoint(fileName, lineNumber);
333 void DebuggerEnginePrivate::breakpointEnableDisableMarginActionTriggered()
335 QAction *act = qobject_cast<QAction *>(sender());
336 QTC_ASSERT(act, return);
337 QList<QVariant> list = act->data().toList();
338 QTC_ASSERT(list.size() == 2, return);
339 const QString fileName = list.at(0).toString();
340 const int lineNumber = list.at(1).toInt();
341 m_breakHandler.toggleBreakpointEnabled(fileName, lineNumber);
344 void DebuggerEnginePrivate::handleContextMenuRequest(const QVariant ¶meters)
346 const QList<QVariant> list = parameters.toList();
347 QTC_ASSERT(list.size() == 3, return);
348 TextEditor::ITextEditor *editor =
349 (TextEditor::ITextEditor *)(list.at(0).value<quint64>());
350 int lineNumber = list.at(1).toInt();
351 QMenu *menu = (QMenu *)(list.at(2).value<quint64>());
353 BreakpointData *data = 0;
356 if (editor->property("DisassemblerView").toBool()) {
357 fileName = editor->file()->fileName();
358 QString line = editor->contents()
359 .section('\n', lineNumber - 1, lineNumber - 1);
360 position = _("*") + fileName;
361 BreakpointData needle;
362 needle.bpAddress = line.left(line.indexOf(QLatin1Char(' '))).toLatin1();
363 needle.bpLineNumber = "-1";
364 data = m_breakHandler.findSimilarBreakpoint(&needle);
366 fileName = editor->file()->fileName();
367 position = fileName + QString(":%1").arg(lineNumber);
368 data = m_breakHandler.findBreakpoint(fileName, lineNumber);
371 QList<QVariant> args;
372 args.append(fileName);
373 args.append(lineNumber);
376 // existing breakpoint
377 QAction *act = new QAction(tr("Remove Breakpoint"), menu);
379 connect(act, SIGNAL(triggered()),
380 this, SLOT(breakpointSetRemoveMarginActionTriggered()));
381 menu->addAction(act);
385 act2 = new QAction(tr("Disable Breakpoint"), menu);
387 act2 = new QAction(tr("Enable Breakpoint"), menu);
389 connect(act2, SIGNAL(triggered()),
390 this, SLOT(breakpointEnableDisableMarginActionTriggered()));
391 menu->addAction(act2);
394 QAction *act = new QAction(tr("Set Breakpoint"), menu);
396 connect(act, SIGNAL(triggered()),
397 this, SLOT(breakpointSetRemoveMarginActionTriggered()));
398 menu->addAction(act);
402 //////////////////////////////////////////////////////////////////////
406 //////////////////////////////////////////////////////////////////////
408 DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters)
409 : d(new DebuggerEnginePrivate(this, startParameters))
413 DebuggerEngine::~DebuggerEngine()
419 void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
421 showMessage(msg, StatusBar, timeout);
424 void DebuggerEngine::handleCommand(int role, const QVariant &value)
426 //qDebug() << "COMMAND: " << role << value;
429 case RequestReloadSourceFilesRole:
433 case RequestReloadModulesRole:
437 case RequestReloadRegistersRole:
441 case RequestExecDetachRole:
445 case RequestExecContinueRole:
449 case RequestExecInterruptRole:
450 requestInterruptInferior();
453 case RequestExecResetRole:
454 notifyEngineIll(); // FIXME: check
457 case RequestExecStepRole:
461 case RequestExecStepOutRole:
465 case RequestExecNextRole:
469 case RequestExecRunToLineRole:
473 case RequestExecRunToFunctionRole:
474 executeRunToFunction();
477 case RequestExecReturnFromFunctionRole:
481 case RequestExecJumpToLineRole:
485 case RequestExecWatchRole:
489 case RequestExecExitRole:
490 d->queueShutdownInferior();
493 case RequestCreateSnapshotRole:
497 case RequestActivationRole:
498 setActive(value.toBool());
501 case RequestExecFrameDownRole:
505 case RequestExecFrameUpRole:
509 case RequestOperatedByInstructionTriggeredRole:
510 gotoLocation(stackHandler()->currentFrame(), true);
513 case RequestExecuteCommandRole:
514 executeDebuggerCommand(value.toString());
517 case RequestToggleBreakpointRole: {
518 QList<QVariant> list = value.toList();
519 QTC_ASSERT(list.size() == 2, break);
520 const QString fileName = list.at(0).toString();
521 const int lineNumber = list.at(1).toInt();
522 breakHandler()->toggleBreakpoint(fileName, lineNumber);
526 case RequestToolTipByExpressionRole: {
527 QList<QVariant> list = value.toList();
528 QTC_ASSERT(list.size() == 3, break);
529 QPoint point = list.at(0).value<QPoint>();
530 TextEditor::ITextEditor *editor = // Eeks.
531 (TextEditor::ITextEditor *)(list.at(1).value<quint64>());
532 int pos = list.at(2).toInt();
533 setToolTipExpression(point, editor, pos);
537 case RequestContextMenuRole: {
538 QList<QVariant> list = value.toList();
539 QTC_ASSERT(list.size() == 3, break);
540 d->handleContextMenuRequest(list);
546 void DebuggerEngine::showModuleSymbols
547 (const QString &moduleName, const Symbols &symbols)
549 QTreeWidget *w = new QTreeWidget;
550 w->setColumnCount(3);
551 w->setRootIsDecorated(false);
552 w->setAlternatingRowColors(true);
553 w->setSortingEnabled(true);
554 w->setHeaderLabels(QStringList() << tr("Symbol") << tr("Address") << tr("Code"));
555 w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
556 foreach (const Symbol &s, symbols) {
557 QTreeWidgetItem *it = new QTreeWidgetItem;
558 it->setData(0, Qt::DisplayRole, s.name);
559 it->setData(1, Qt::DisplayRole, s.address);
560 it->setData(2, Qt::DisplayRole, s.state);
561 w->addTopLevelItem(it);
563 plugin()->createNewDock(w);
566 void DebuggerEngine::frameUp()
568 int currentIndex = stackHandler()->currentIndex();
569 activateFrame(qMin(currentIndex + 1, stackHandler()->stackSize() - 1));
572 void DebuggerEngine::frameDown()
574 int currentIndex = stackHandler()->currentIndex();
575 activateFrame(qMax(currentIndex - 1, 0));
578 ModulesHandler *DebuggerEngine::modulesHandler() const
580 return &d->m_modulesHandler;
583 BreakHandler *DebuggerEngine::breakHandler() const
585 return &d->m_breakHandler;
588 RegisterHandler *DebuggerEngine::registerHandler() const
590 return &d->m_registerHandler;
593 StackHandler *DebuggerEngine::stackHandler() const
595 return &d->m_stackHandler;
598 ThreadsHandler *DebuggerEngine::threadsHandler() const
600 return &d->m_threadsHandler;
603 WatchHandler *DebuggerEngine::watchHandler() const
605 return &d->m_watchHandler;
608 //SnapshotHandler *DebuggerEngine::snapshotHandler() const
610 // return &d->m_snapshotHandler;
613 SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
615 return &d->m_sourceFilesHandler;
618 QAbstractItemModel *DebuggerEngine::modulesModel() const
620 QAbstractItemModel *model = d->m_modulesHandler.model();
621 if (model->objectName().isEmpty()) // Make debugging easier.
622 model->setObjectName(objectName() + QLatin1String("ModulesModel"));
626 QAbstractItemModel *DebuggerEngine::breakModel() const
628 QAbstractItemModel *model = d->m_breakHandler.model();
629 if (model->objectName().isEmpty()) // Make debugging easier.
630 model->setObjectName(objectName() + QLatin1String("BreakModel"));
634 QAbstractItemModel *DebuggerEngine::registerModel() const
636 QAbstractItemModel *model = d->m_registerHandler.model();
637 if (model->objectName().isEmpty()) // Make debugging easier.
638 model->setObjectName(objectName() + QLatin1String("RegisterModel"));
642 QAbstractItemModel *DebuggerEngine::stackModel() const
644 QAbstractItemModel *model = d->m_stackHandler.model();
645 if (model->objectName().isEmpty()) // Make debugging easier.
646 model->setObjectName(objectName() + QLatin1String("StackModel"));
650 QAbstractItemModel *DebuggerEngine::threadsModel() const
652 QAbstractItemModel *model = d->m_threadsHandler.model();
653 if (model->objectName().isEmpty()) // Make debugging easier.
654 model->setObjectName(objectName() + QLatin1String("ThreadsModel"));
658 QAbstractItemModel *DebuggerEngine::localsModel() const
660 QAbstractItemModel *model = d->m_watchHandler.model(LocalsWatch);
661 if (model->objectName().isEmpty()) // Make debugging easier.
662 model->setObjectName(objectName() + QLatin1String("LocalsModel"));
666 QAbstractItemModel *DebuggerEngine::watchersModel() const
668 QAbstractItemModel *model = d->m_watchHandler.model(WatchersWatch);
669 if (model->objectName().isEmpty()) // Make debugging easier.
670 model->setObjectName(objectName() + QLatin1String("WatchersModel"));
674 QAbstractItemModel *DebuggerEngine::returnModel() const
676 QAbstractItemModel *model = d->m_watchHandler.model(ReturnWatch);
677 if (model->objectName().isEmpty()) // Make debugging easier.
678 model->setObjectName(objectName() + QLatin1String("ReturnModel"));
682 QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
684 QAbstractItemModel *model = d->m_sourceFilesHandler.model();
685 if (model->objectName().isEmpty()) // Make debugging easier.
686 model->setObjectName(objectName() + QLatin1String("SourceFilesModel"));
690 QAbstractItemModel *DebuggerEngine::commandModel() const
692 QAbstractItemModel *model = d->m_commandHandler.model();
693 if (model->objectName().isEmpty()) // Make debugging easier.
694 model->setObjectName(objectName() + QLatin1String("CommandModel"));
698 void DebuggerEngine::fetchMemory(MemoryViewAgent *, QObject *,
699 quint64 addr, quint64 length)
705 void DebuggerEngine::setRegisterValue(int regnr, const QString &value)
711 void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
713 //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
714 // qDebug() << qPrintable(msg) << "IN STATE" << state();
715 plugin()->showMessage(msg, channel, timeout);
716 if (d->m_runControl) {
717 d->m_runControl->showMessage(msg, channel);
719 qWarning("Warning: %s (no active run control)", qPrintable(msg));
723 void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
725 if (!isSessionEngine()) {
726 d->m_progress.setProgressRange(0, 1000);
727 Core::FutureProgress *fp = Core::ICore::instance()->progressManager()
728 ->addTask(d->m_progress.future(),
729 tr("Launching"), _("Debugger.Launcher"));
730 fp->setKeepOnFinish(false);
731 d->m_progress.reportStarted();
733 QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
734 QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
736 DebuggerEngine *sessionTemplate = plugin()->sessionTemplate();
737 QTC_ASSERT(sessionTemplate, notifyEngineSetupFailed(); return);
738 QTC_ASSERT(sessionTemplate != this, notifyEngineSetupFailed(); return);
740 breakHandler()->initializeFromTemplate(sessionTemplate->breakHandler());
741 watchHandler()->initializeFromTemplate(sessionTemplate->watchHandler());
743 d->m_runControl = runControl;
745 d->m_inferiorPid = d->m_startParameters.attachPID > 0
746 ? d->m_startParameters.attachPID : 0;
748 if (d->m_startParameters.environment.empty())
749 d->m_startParameters.environment = Environment().toStringList();
751 if (d->m_startParameters.breakAtMain)
752 breakByFunctionMain();
754 const unsigned engineCapabilities = debuggerCapabilities();
755 theDebuggerAction(OperateByInstruction)
756 ->setEnabled(engineCapabilities & DisassemblerCapability);
758 QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
759 qDebug() << state());
760 setState(EngineSetupRequested);
762 d->m_progress.setProgressValue(200);
766 void DebuggerEngine::breakByFunctionMain()
769 // FIXME: wrong on non-Qt based binaries
770 emit breakByFunction("qMain");
772 emit breakByFunction("main");
776 void DebuggerEngine::breakByFunction(const QString &functionName)
778 d->m_breakHandler.breakByFunction(functionName);
779 attemptBreakpointSynchronization();
782 void DebuggerEngine::resetLocation()
784 d->m_disassemblerViewAgent.resetLocation();
785 d->m_stackHandler.setCurrentIndex(-1);
786 plugin()->resetLocation();
789 void DebuggerEngine::gotoLocation(const QString &fileName, int lineNumber, bool setMarker)
792 frame.file = fileName;
793 frame.line = lineNumber;
794 gotoLocation(frame, setMarker);
797 void DebuggerEngine::gotoLocation(const StackFrame &frame, bool setMarker)
799 if (theDebuggerBoolSetting(OperateByInstruction) || !frame.isUsable()) {
801 plugin()->resetLocation();
802 d->m_disassemblerViewAgent.setFrame(frame);
804 plugin()->gotoLocation(frame.file, frame.line, setMarker);
808 void DebuggerEngine::executeStepX()
811 if (theDebuggerBoolSetting(OperateByInstruction))
817 void DebuggerEngine::executeStepOutX()
823 void DebuggerEngine::executeStepNextX()
826 if (theDebuggerBoolSetting(OperateByInstruction))
832 void DebuggerEngine::executeReturnX()
838 static TextEditor::ITextEditor *currentTextEditor()
840 EditorManager *editorManager = EditorManager::instance();
843 Core::IEditor *editor = editorManager->currentEditor();
844 return qobject_cast<ITextEditor*>(editor);
847 void DebuggerEngine::executeRunToLine()
849 ITextEditor *textEditor = currentTextEditor();
850 QTC_ASSERT(textEditor, return);
851 QString fileName = textEditor->file()->fileName();
852 if (fileName.isEmpty())
854 int lineNumber = textEditor->currentLine();
856 executeRunToLine(fileName, lineNumber);
859 void DebuggerEngine::executeRunToFunction()
861 ITextEditor *textEditor = currentTextEditor();
862 QTC_ASSERT(textEditor, return);
863 QString fileName = textEditor->file()->fileName();
864 QPlainTextEdit *ed = qobject_cast<QPlainTextEdit*>(textEditor->widget());
867 QTextCursor cursor = ed->textCursor();
868 QString functionName = cursor.selectedText();
869 if (functionName.isEmpty()) {
870 const QTextBlock block = cursor.block();
871 const QString line = block.text();
872 foreach (const QString &str, line.trimmed().split('(')) {
874 for (int i = str.size(); --i >= 0; ) {
875 if (!str.at(i).isLetterOrNumber())
886 if (functionName.isEmpty())
889 executeRunToFunction(functionName);
892 void DebuggerEngine::executeJumpToLine()
894 ITextEditor *textEditor = currentTextEditor();
895 QTC_ASSERT(textEditor, return);
896 QString fileName = textEditor->file()->fileName();
897 int lineNumber = textEditor->currentLine();
898 if (fileName.isEmpty())
900 executeJumpToLine(fileName, lineNumber);
903 void DebuggerEngine::addToWatchWindow()
905 // Requires a selection, but that's the only case we want anyway.
906 EditorManager *editorManager = EditorManager::instance();
909 IEditor *editor = editorManager->currentEditor();
912 ITextEditor *textEditor = qobject_cast<ITextEditor*>(editor);
916 QPlainTextEdit *ptEdit = qobject_cast<QPlainTextEdit*>(editor->widget());
918 tc = ptEdit->textCursor();
920 if (tc.hasSelection()) {
921 exp = tc.selectedText();
924 exp = cppExpressionAt(textEditor, tc.position(), &line, &column);
928 watchHandler()->watchExpression(exp);
931 // Called from RunControl.
932 void DebuggerEngine::handleStartFailed()
934 showMessage("HANDLE RUNCONTROL START FAILED");
937 d->m_progress.setProgressValue(900);
938 d->m_progress.reportCanceled();
939 d->m_progress.reportFinished();
942 // Called from RunControl.
943 void DebuggerEngine::handleFinished()
945 showMessage("HANDLE RUNCONTROL FINISHED");
947 modulesHandler()->removeAll();
948 stackHandler()->removeAll();
949 threadsHandler()->removeAll();
950 watchHandler()->cleanup();
952 DebuggerEngine *sessionTemplate = plugin()->sessionTemplate();
953 QTC_ASSERT(sessionTemplate != this, /**/);
954 breakHandler()->storeToTemplate(sessionTemplate->breakHandler());
955 watchHandler()->storeToTemplate(sessionTemplate->watchHandler());
957 d->m_progress.setProgressValue(1000);
958 d->m_progress.reportFinished();
961 const DebuggerStartParameters &DebuggerEngine::startParameters() const
963 return d->m_startParameters;
966 DebuggerStartParameters &DebuggerEngine::startParameters()
968 return d->m_startParameters;
972 //////////////////////////////////////////////////////////////////////
974 // Dumpers. "Custom dumpers" are a library compiled against the current
975 // Qt containing functions to evaluate values of Qt classes
976 // (such as QString, taking pointers to their addresses).
977 // The library must be loaded into the debuggee.
979 //////////////////////////////////////////////////////////////////////
981 bool DebuggerEngine::qtDumperLibraryEnabled() const
983 return theDebuggerBoolSetting(UseDebuggingHelpers);
986 QStringList DebuggerEngine::qtDumperLibraryLocations() const
988 if (theDebuggerAction(UseCustomDebuggingHelperLocation)->value().toBool()) {
989 const QString customLocation =
990 theDebuggerAction(CustomDebuggingHelperLocation)->value().toString();
991 const QString location =
992 tr("%1 (explicitly set in the Debugger Options)").arg(customLocation);
993 return QStringList(location);
995 return d->m_startParameters.dumperLibraryLocations;
998 void DebuggerEngine::showQtDumperLibraryWarning(const QString &details)
1000 //QMessageBox dialog(d->m_mainWindow); // FIXME
1002 QPushButton *qtPref = dialog.addButton(tr("Open Qt preferences"),
1003 QMessageBox::ActionRole);
1004 QPushButton *helperOff = dialog.addButton(tr("Turn off helper usage"),
1005 QMessageBox::ActionRole);
1006 QPushButton *justContinue = dialog.addButton(tr("Continue anyway"),
1007 QMessageBox::AcceptRole);
1008 dialog.setDefaultButton(justContinue);
1009 dialog.setWindowTitle(tr("Debugging helper missing"));
1010 dialog.setText(tr("The debugger could not load the debugging helper library."));
1011 dialog.setInformativeText(tr(
1012 "The debugging helper is used to nicely format the values of some Qt "
1013 "and Standard Library data types. "
1014 "It must be compiled for each used Qt version separately. "
1015 "This can be done in the Qt preferences page by selecting a Qt installation "
1016 "and clicking on 'Rebuild' in the 'Debugging Helper' row."));
1017 if (!details.isEmpty())
1018 dialog.setDetailedText(details);
1020 if (dialog.clickedButton() == qtPref) {
1021 Core::ICore::instance()->showOptionsDialog(
1022 _(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
1023 _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
1024 } else if (dialog.clickedButton() == helperOff) {
1025 theDebuggerAction(UseDebuggingHelpers)
1026 ->setValue(qVariantFromValue(false), false);
1030 QString DebuggerEngine::qtDumperLibraryName() const
1032 if (theDebuggerAction(UseCustomDebuggingHelperLocation)->value().toBool())
1033 return theDebuggerAction(CustomDebuggingHelperLocation)->value().toString();
1034 return startParameters().dumperLibrary;
1037 DebuggerState DebuggerEngine::state() const
1042 DebuggerState DebuggerEngine::lastGoodState() const
1044 return d->m_lastGoodState;
1047 DebuggerState DebuggerEngine::targetState() const
1049 return d->m_targetState;
1052 static bool isAllowedTransition(DebuggerState from, DebuggerState to)
1055 case DebuggerNotReady:
1056 return to == EngineSetupRequested;
1058 case EngineSetupRequested:
1059 return to == EngineSetupOk || to == EngineSetupFailed;
1060 case EngineSetupFailed:
1061 // FIXME: In therory it's the engine's task to go into a
1062 // proper "Shutdown" state before calling notifyEngineSetupFailed
1063 //return to == DebuggerFinished;
1064 return to == EngineShutdownRequested;
1066 return to == InferiorSetupRequested || to == EngineShutdownRequested;
1068 case InferiorSetupRequested:
1069 return to == EngineRunRequested || to == InferiorSetupFailed;
1070 case InferiorSetupFailed:
1071 return to == EngineShutdownRequested;
1073 case EngineRunRequested:
1074 return to == InferiorRunRequested || to == InferiorStopRequested
1075 || to == InferiorUnrunnable || to == EngineRunFailed;
1077 case EngineRunFailed:
1078 return to == InferiorShutdownRequested;
1080 case InferiorRunRequested:
1081 return to == InferiorRunOk || to == InferiorRunFailed;
1082 case InferiorRunFailed:
1083 return to == InferiorStopOk;
1085 return to == InferiorStopRequested || to == InferiorStopOk;
1087 case InferiorStopRequested:
1088 return to == InferiorStopOk || to == InferiorStopFailed;
1089 case InferiorStopOk:
1090 return to == InferiorRunRequested || to == InferiorShutdownRequested
1091 || to == InferiorStopOk;
1092 case InferiorStopFailed:
1093 return to == EngineShutdownRequested;
1095 case InferiorUnrunnable:
1096 return to == InferiorShutdownRequested;
1097 case InferiorShutdownRequested:
1098 return to == InferiorShutdownOk || to == InferiorShutdownFailed;
1099 case InferiorShutdownOk:
1100 return to == EngineShutdownRequested;
1101 case InferiorShutdownFailed:
1102 return to == EngineShutdownRequested;
1104 case EngineShutdownRequested:
1105 return to == EngineShutdownOk;
1106 case EngineShutdownOk:
1107 return to == DebuggerFinished;
1108 case EngineShutdownFailed:
1109 return to == DebuggerFinished;
1111 case DebuggerFinished:
1112 return to == EngineSetupRequested; // Happens on restart.
1115 qDebug() << "UNKNOWN STATE:" << from;
1119 void DebuggerEngine::notifyEngineSetupFailed()
1121 showMessage(_("NOTE: ENGINE SETUP FAILED"));
1122 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
1123 setState(EngineSetupFailed);
1124 QTC_ASSERT(d->m_runControl, return);
1125 d->m_runControl->startFailed();
1126 d->queueShutdownEngine();
1129 void DebuggerEngine::notifyEngineSetupOk()
1131 showMessage(_("NOTE: ENGINE SETUP OK"));
1132 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
1133 setState(EngineSetupOk);
1134 QTC_ASSERT(d->m_runControl, return);
1135 showMessage(_("QUEUE: SETUP INFERIOR"));
1136 QTimer::singleShot(0, d, SLOT(doSetupInferior()));
1139 void DebuggerEnginePrivate::doSetupInferior()
1141 m_engine->showMessage(_("CALL: SETUP INFERIOR"));
1142 QTC_ASSERT(state() == EngineSetupOk, qDebug() << state());
1143 m_progress.setProgressValue(250);
1144 m_engine->setState(InferiorSetupRequested);
1145 m_engine->setupInferior();
1148 void DebuggerEngine::notifyInferiorSetupFailed()
1150 showMessage(_("NOTE: INFERIOR SETUP FAILED"));
1151 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
1152 setState(InferiorSetupFailed);
1153 d->queueShutdownEngine();
1156 void DebuggerEngine::notifyInferiorSetupOk()
1158 showMessage(_("NOTE: INFERIOR SETUP OK"));
1159 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
1160 d->queueRunEngine();
1163 void DebuggerEnginePrivate::doRunEngine()
1165 m_engine->showMessage(_("CALL: RUN ENGINE"));
1166 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1167 m_progress.setProgressValue(300);
1168 m_engine->runEngine();
1171 void DebuggerEngine::notifyInferiorUnrunnable()
1173 showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
1174 d->m_progress.setProgressValue(1000);
1175 d->m_progress.reportFinished();
1176 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1177 setState(InferiorUnrunnable);
1180 void DebuggerEngine::notifyEngineRunFailed()
1182 showMessage(_("NOTE: ENGINE RUN FAILED"));
1183 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1184 d->m_progress.setProgressValue(900);
1185 d->m_progress.reportCanceled();
1186 d->m_progress.reportFinished();
1187 setState(EngineRunFailed);
1188 d->queueShutdownInferior();
1191 void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
1193 showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
1194 d->m_progress.setProgressValue(1000);
1195 d->m_progress.reportFinished();
1196 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1197 setState(InferiorRunRequested);
1198 notifyInferiorRunOk();
1201 void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
1203 showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
1204 d->m_progress.setProgressValue(1000);
1205 d->m_progress.reportFinished();
1206 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1207 setState(InferiorStopRequested);
1208 notifyInferiorStopOk();
1211 void DebuggerEngine::notifyInferiorRunRequested()
1213 showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
1214 QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1215 setState(InferiorRunRequested);
1218 void DebuggerEngine::notifyInferiorRunOk()
1220 showMessage(_("NOTE: INFERIOR RUN OK"));
1221 QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
1222 setState(InferiorRunOk);
1225 void DebuggerEngine::notifyInferiorRunFailed()
1227 showMessage(_("NOTE: INFERIOR RUN FAILED"));
1228 QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
1229 setState(InferiorRunFailed);
1230 setState(InferiorStopOk);
1232 d->queueShutdownInferior();
1235 void DebuggerEngine::notifyInferiorStopOk()
1237 showMessage(_("NOTE: INFERIOR STOP OK"));
1238 // Ignore spurious notifications after we are set to die.
1240 showMessage(_("NOTE: ... WHILE DYING. "));
1241 // Forward state to "StopOk" if needed.
1242 if (state() == InferiorStopRequested
1243 || state() == InferiorRunRequested
1244 || state() == InferiorRunOk) {
1245 showMessage(_("NOTE: ... FORWARDING TO 'STOP OK'. "));
1246 setState(InferiorStopOk);
1248 if (state() == InferiorStopOk || state() == InferiorStopFailed) {
1249 d->queueShutdownInferior();
1251 showMessage(_("NOTE: ... IGNORING STOP MESSAGE"));
1254 QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
1255 setState(InferiorStopOk);
1258 void DebuggerEngine::notifyInferiorSpontaneousStop()
1260 showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
1261 QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
1262 setState(InferiorStopOk);
1265 void DebuggerEngine::notifyInferiorStopFailed()
1267 showMessage(_("NOTE: INFERIOR STOP FAILED"));
1268 QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
1269 setState(InferiorStopFailed);
1270 d->queueShutdownEngine();
1273 void DebuggerEnginePrivate::doInterruptInferior()
1275 QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
1276 m_engine->setState(InferiorStopRequested);
1277 m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
1278 m_engine->interruptInferior();
1281 void DebuggerEnginePrivate::doShutdownInferior()
1283 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
1284 m_engine->resetLocation();
1285 m_targetState = DebuggerFinished;
1286 m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
1287 m_engine->shutdownInferior();
1290 void DebuggerEngine::notifyInferiorShutdownOk()
1292 showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
1293 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
1294 d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
1295 setState(InferiorShutdownOk);
1296 d->queueShutdownEngine();
1299 void DebuggerEngine::notifyInferiorShutdownFailed()
1301 showMessage(_("INFERIOR SHUTDOWN FAILED"));
1302 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
1303 setState(InferiorShutdownFailed);
1304 d->queueShutdownEngine();
1307 void DebuggerEngine::notifyInferiorIll()
1309 showMessage(_("NOTE: INFERIOR ILL"));
1310 // This can be issued in almost any state. The inferior could still be
1311 // alive as some previous notifications might have been bogus.
1312 d->m_targetState = DebuggerFinished;
1313 d->m_lastGoodState = d->m_state;
1314 if (state() == InferiorRunRequested) {
1315 // We asked for running, but did not see a response.
1316 // Assume the inferior is dead.
1317 // FIXME: Use timeout?
1318 setState(InferiorRunFailed);
1319 setState(InferiorStopOk);
1321 d->queueShutdownInferior();
1324 void DebuggerEnginePrivate::doShutdownEngine()
1326 QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
1327 m_targetState = DebuggerFinished;
1328 m_engine->showMessage(_("CALL: SHUTDOWN ENGINE"));
1329 m_engine->shutdownEngine();
1332 void DebuggerEngine::notifyEngineShutdownOk()
1334 showMessage(_("NOTE: ENGINE SHUTDOWN OK"));
1335 QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
1336 setState(EngineShutdownOk);
1337 if (!d->m_runInWrapperEngine) {
1338 d->queueFinishDebugger();
1340 setState(DebuggerFinished);
1344 void DebuggerEngine::notifyEngineShutdownFailed()
1346 showMessage(_("NOTE: ENGINE SHUTDOWN FAILED"));
1347 QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
1348 setState(EngineShutdownFailed);
1349 if (!d->m_runInWrapperEngine) {
1350 d->queueFinishDebugger();
1352 setState(DebuggerFinished);
1356 void DebuggerEnginePrivate::doFinishDebugger()
1358 m_engine->showMessage(_("NOTE: FINISH DEBUGGER"));
1359 QTC_ASSERT(state() == DebuggerFinished, qDebug() << state());
1360 m_engine->resetLocation();
1361 QTC_ASSERT(m_runControl, return);
1362 m_runControl->debuggingFinished();
1365 void DebuggerEngine::notifyEngineIll()
1367 showMessage(_("NOTE: ENGINE ILL ******"));
1368 d->m_targetState = DebuggerFinished;
1369 d->m_lastGoodState = d->m_state;
1371 case InferiorRunRequested:
1373 case InferiorStopRequested:
1374 case InferiorStopOk:
1375 qDebug() << "FORWARDING STATE TO " << InferiorShutdownFailed;
1376 setState(InferiorShutdownFailed, true);
1381 d->queueShutdownEngine();
1384 void DebuggerEngine::notifyEngineSpontaneousShutdown()
1386 showMessage(_("NOTE: ENGINE SPONTANEOUS SHUTDOWN"));
1387 setState(EngineShutdownOk, true);
1388 d->queueFinishDebugger();
1391 void DebuggerEngine::notifyInferiorExited()
1393 showMessage(_("NOTE: INFERIOR EXITED"));
1396 // This can be issued in almost any state. We assume, though,
1397 // that at this point of time the inferior is not running anymore,
1398 // even if stop notification were not issued or got lost.
1399 if (state() == InferiorRunOk) {
1400 setState(InferiorStopRequested);
1401 setState(InferiorStopOk);
1403 setState(InferiorShutdownRequested);
1404 setState(InferiorShutdownOk);
1405 d->queueShutdownEngine();
1408 void DebuggerEngine::setState(DebuggerState state, bool forced)
1410 //qDebug() << "STATUS CHANGE: FROM " << stateName(d->m_state)
1411 // << " TO " << stateName(state);
1413 DebuggerState oldState = d->m_state;
1416 QString msg = _("State changed%5 from %1(%2) to %3(%4).")
1417 .arg(stateName(oldState)).arg(oldState).arg(stateName(state)).arg(state)
1418 .arg(forced ? " BY FORCE" : "");
1419 if (!forced && !isAllowedTransition(oldState, state))
1420 qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;
1422 const bool running = d->m_state == InferiorRunOk;
1424 threadsHandler()->notifyRunning();
1426 showMessage(msg, LogDebug);
1427 plugin()->updateState(this);
1429 emit stateChanged(d->m_state);
1432 void DebuggerEngine::setRunInWrapperEngine(bool value)
1434 d->m_runInWrapperEngine = value;
1437 bool DebuggerEngine::debuggerActionsEnabled() const
1439 return debuggerActionsEnabled(d->m_state);
1442 bool DebuggerEngine::debuggerActionsEnabled(DebuggerState state)
1445 case InferiorSetupRequested:
1447 case InferiorUnrunnable:
1448 case InferiorStopOk:
1450 case InferiorStopRequested:
1451 case InferiorRunRequested:
1452 case InferiorRunFailed:
1453 case DebuggerNotReady:
1454 case EngineSetupRequested:
1456 case EngineSetupFailed:
1457 case EngineRunRequested:
1458 case EngineRunFailed:
1459 case InferiorSetupFailed:
1460 case InferiorStopFailed:
1461 case InferiorShutdownRequested:
1462 case InferiorShutdownOk:
1463 case InferiorShutdownFailed:
1464 case EngineShutdownRequested:
1465 case EngineShutdownOk:
1466 case EngineShutdownFailed:
1467 case DebuggerFinished:
1473 void DebuggerEngine::notifyInferiorPid(qint64 pid)
1475 showMessage(tr("Taking notice of pid %1").arg(pid));
1476 if (d->m_inferiorPid == pid)
1478 d->m_inferiorPid = pid;
1479 QTimer::singleShot(0, d, SLOT(raiseApplication()));
1482 qint64 DebuggerEngine::inferiorPid() const
1484 return d->m_inferiorPid;
1487 DebuggerPlugin *DebuggerEngine::plugin()
1489 return DebuggerPlugin::instance();
1492 void DebuggerEngine::openFile(const QString &fileName, int lineNumber)
1494 plugin()->gotoLocation(fileName, lineNumber, false);
1497 bool DebuggerEngine::isReverseDebugging() const
1499 return plugin()->isReverseDebugging();
1502 bool DebuggerEngine::isActive() const
1504 return d->m_isActive && !isSessionEngine();
1507 void DebuggerEngine::setActive(bool on)
1509 //qDebug() << "SETTING ACTIVE" << this << on;
1511 //breakHandler()->updateMarkers();
1514 // called by DebuggerRunControl
1515 void DebuggerEngine::quitDebugger()
1517 showMessage("QUIT DEBUGGER REQUESTED");
1518 d->m_targetState = DebuggerFinished;
1520 case InferiorStopOk:
1521 case InferiorStopFailed:
1522 d->queueShutdownInferior();
1525 d->doInterruptInferior();
1528 // FIXME: We should disable the actions connected to that
1529 notifyInferiorIll();
1534 void DebuggerEngine::requestInterruptInferior()
1536 d->doInterruptInferior();
1539 void DebuggerEngine::progressPing()
1541 int progress = qMin(d->m_progress.progressValue() + 2, 800);
1542 d->m_progress.setProgressValue(progress);
1545 QMessageBox *DebuggerEngine::showMessageBox(int icon, const QString &title,
1546 const QString &text, int buttons)
1548 return plugin()->showMessageBox(icon, title, text, buttons);
1551 DebuggerRunControl *DebuggerEngine::runControl() const
1553 return d->m_runControl;
1556 } // namespace Internal
1557 } // namespace Debugger
1559 #include "debuggerengine.moc"