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>
52 #include <projectexplorer/debugginghelper.h>
53 #include <projectexplorer/environment.h>
54 #include <projectexplorer/project.h>
55 #include <projectexplorer/projectexplorerconstants.h>
56 #include <projectexplorer/target.h>
57 #include <projectexplorer/buildconfiguration.h>
58 #include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
60 #include <qt4projectmanager/qt4projectmanagerconstants.h>
62 #include <texteditor/itexteditor.h>
64 #include <utils/savedaction.h>
65 #include <utils/qtcassert.h>
67 #include <QtCore/QDebug>
68 #include <QtCore/QDir>
69 #include <QtCore/QFileInfo>
70 #include <QtCore/QTimer>
72 #include <QtGui/QAbstractItemView>
73 #include <QtGui/QStandardItemModel>
74 #include <QtGui/QAction>
75 #include <QtGui/QMenu>
76 #include <QtGui/QMessageBox>
77 #include <QtGui/QPlainTextEdit>
78 #include <QtGui/QPushButton>
79 #include <QtGui/QTextBlock>
80 #include <QtGui/QTextCursor>
81 #include <QtGui/QTextDocument>
82 #include <QtGui/QTreeWidget>
86 using namespace Debugger;
87 using namespace Debugger::Internal;
88 using namespace ProjectExplorer;
89 using namespace TextEditor;
91 //#define DEBUG_STATE 1
93 # define SDEBUG(s) qDebug() << s
97 # define XSDEBUG(s) qDebug() << s
99 ///////////////////////////////////////////////////////////////////////
101 // DebuggerStartParameters
103 ///////////////////////////////////////////////////////////////////////
105 DebuggerStartParameters::DebuggerStartParameters()
109 toolChainType(ToolChain::UNKNOWN),
110 startMode(NoStartMode)
113 void DebuggerStartParameters::clear()
115 *this = DebuggerStartParameters();
121 QDebug operator<<(QDebug d, DebuggerState state)
123 //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')';
124 return d << DebuggerEngine::stateName(state);
127 QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
129 QDebug nospace = str.nospace();
130 const QString sep = QString(QLatin1Char(','));
131 nospace << "executable=" << sp.executable
132 << " coreFile=" << sp.coreFile
133 << " processArgs=" << sp.processArgs.join(sep)
134 << " environment=<" << sp.environment.size() << " variables>"
135 << " workingDir=" << sp.workingDirectory
136 << " attachPID=" << sp.attachPID
137 << " useTerminal=" << sp.useTerminal
138 << " remoteChannel=" << sp.remoteChannel
139 << " remoteArchitecture=" << sp.remoteArchitecture
140 << " symbolFileName=" << sp.symbolFileName
141 << " serverStartScript=" << sp.serverStartScript
142 << " toolchain=" << sp.toolChainType << '\n';
149 const char *DebuggerEngine::stateName(int s)
151 # define SN(x) case x: return #x;
154 SN(EngineSetupRequested)
156 SN(EngineSetupFailed)
158 SN(InferiorSetupRequested)
159 SN(InferiorSetupFailed)
160 SN(EngineRunRequested)
161 SN(InferiorRunRequested)
163 SN(InferiorRunFailed)
164 SN(InferiorUnrunnable)
165 SN(InferiorStopRequested)
167 SN(InferiorStopFailed)
168 SN(InferiorShutdownRequested)
169 SN(InferiorShutdownOk)
170 SN(InferiorShutdownFailed)
171 SN(EngineShutdownRequested)
173 SN(EngineShutdownFailed)
181 //////////////////////////////////////////////////////////////////////
185 //////////////////////////////////////////////////////////////////////
187 class CommandHandler : public QStandardItemModel
190 explicit CommandHandler(DebuggerEngine *engine) : m_engine(engine) {}
191 bool setData(const QModelIndex &index, const QVariant &value, int role);
192 QAbstractItemModel *model() { return this; }
195 QPointer<DebuggerEngine> m_engine;
198 bool CommandHandler::setData(const QModelIndex &, const QVariant &value, int role)
200 QTC_ASSERT(m_engine, qDebug() << value << role; return false);
201 m_engine->handleCommand(role, value);
206 //////////////////////////////////////////////////////////////////////
208 // DebuggerEnginePrivate
210 //////////////////////////////////////////////////////////////////////
212 class DebuggerEnginePrivate : public QObject
217 DebuggerEnginePrivate(DebuggerEngine *engine, const DebuggerStartParameters &sp)
221 m_startParameters(sp),
222 m_state(DebuggerNotReady),
223 m_lastGoodState(DebuggerNotReady),
224 m_breakHandler(engine),
225 m_commandHandler(engine),
226 m_modulesHandler(engine),
227 m_registerHandler(engine),
228 m_sourceFilesHandler(engine),
229 m_stackHandler(engine),
230 m_threadsHandler(engine),
231 m_watchHandler(engine),
232 m_disassemblerViewAgent(engine)
236 void breakpointSetRemoveMarginActionTriggered();
237 void breakpointEnableDisableMarginActionTriggered();
238 void handleContextMenuRequest(const QVariant ¶meters);
240 void doSetupInferior();
242 void doShutdownEngine();
243 void doShutdownInferior();
244 void doInterruptInferior();
245 void doFinishDebugger();
247 void queueRunEngine() {
248 m_engine->setState(EngineRunRequested);
249 m_engine->showMessage(_("QUEUE: RUN ENGINE"));
250 QTimer::singleShot(0, this, SLOT(doRunEngine()));
253 void queueShutdownEngine() {
254 m_engine->setState(EngineShutdownRequested);
255 m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
256 QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
259 void queueShutdownInferior() {
260 m_engine->setState(InferiorShutdownRequested);
261 m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
262 QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
265 void queueFinishDebugger() {
266 m_engine->setState(DebuggerFinished, true);
267 m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
268 QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
271 void raiseApplication() {
272 m_runControl->bringApplicationToForeground(m_inferiorPid);
277 DebuggerState state() const { return m_state; }
279 DebuggerEngine *m_engine; // Not owned.
280 DebuggerRunControl *m_runControl; // Not owned.
283 DebuggerStartParameters m_startParameters;
285 // The current state.
286 DebuggerState m_state;
288 // The state we had before something unexpected happend.
289 DebuggerState m_lastGoodState;
291 // The state we are aiming for.
292 DebuggerState m_targetState;
294 qint64 m_inferiorPid;
296 BreakHandler m_breakHandler;
297 CommandHandler m_commandHandler;
298 ModulesHandler m_modulesHandler;
299 RegisterHandler m_registerHandler;
300 SourceFilesHandler m_sourceFilesHandler;
301 StackHandler m_stackHandler;
302 ThreadsHandler m_threadsHandler;
303 WatchHandler m_watchHandler;
304 DisassemblerViewAgent m_disassemblerViewAgent;
307 void DebuggerEnginePrivate::breakpointSetRemoveMarginActionTriggered()
309 QAction *act = qobject_cast<QAction *>(sender());
310 QTC_ASSERT(act, return);
311 QList<QVariant> list = act->data().toList();
312 QTC_ASSERT(list.size() == 2, return);
313 const QString fileName = list.at(0).toString();
314 const int lineNumber = list.at(1).toInt();
315 m_breakHandler.toggleBreakpoint(fileName, lineNumber);
318 void DebuggerEnginePrivate::breakpointEnableDisableMarginActionTriggered()
320 QAction *act = qobject_cast<QAction *>(sender());
321 QTC_ASSERT(act, return);
322 QList<QVariant> list = act->data().toList();
323 QTC_ASSERT(list.size() == 2, return);
324 const QString fileName = list.at(0).toString();
325 const int lineNumber = list.at(1).toInt();
326 m_breakHandler.toggleBreakpointEnabled(fileName, lineNumber);
329 void DebuggerEnginePrivate::handleContextMenuRequest(const QVariant ¶meters)
331 const QList<QVariant> list = parameters.toList();
332 QTC_ASSERT(list.size() == 3, return);
333 TextEditor::ITextEditor *editor =
334 (TextEditor::ITextEditor *)(list.at(0).value<quint64>());
335 int lineNumber = list.at(1).toInt();
336 QMenu *menu = (QMenu *)(list.at(2).value<quint64>());
338 BreakpointData *data = 0;
341 if (editor->property("DisassemblerView").toBool()) {
342 fileName = editor->file()->fileName();
343 QString line = editor->contents()
344 .section('\n', lineNumber - 1, lineNumber - 1);
345 position = _("*") + fileName;
346 BreakpointData needle;
347 needle.bpAddress = line.left(line.indexOf(QLatin1Char(' '))).toLatin1();
348 needle.bpLineNumber = "-1";
349 data = m_breakHandler.findSimilarBreakpoint(&needle);
351 fileName = editor->file()->fileName();
352 position = fileName + QString(":%1").arg(lineNumber);
353 data = m_breakHandler.findBreakpoint(fileName, lineNumber);
356 QList<QVariant> args;
357 args.append(fileName);
358 args.append(lineNumber);
361 // existing breakpoint
362 QAction *act = new QAction(tr("Remove Breakpoint"), menu);
364 connect(act, SIGNAL(triggered()),
365 this, SLOT(breakpointSetRemoveMarginActionTriggered()));
366 menu->addAction(act);
370 act2 = new QAction(tr("Disable Breakpoint"), menu);
372 act2 = new QAction(tr("Enable Breakpoint"), menu);
374 connect(act2, SIGNAL(triggered()),
375 this, SLOT(breakpointEnableDisableMarginActionTriggered()));
376 menu->addAction(act2);
379 QAction *act = new QAction(tr("Set Breakpoint"), menu);
381 connect(act, SIGNAL(triggered()),
382 this, SLOT(breakpointSetRemoveMarginActionTriggered()));
383 menu->addAction(act);
387 //////////////////////////////////////////////////////////////////////
391 //////////////////////////////////////////////////////////////////////
393 DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters)
394 : d(new DebuggerEnginePrivate(this, startParameters))
398 DebuggerEngine::~DebuggerEngine()
404 void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
406 showMessage(msg, StatusBar, timeout);
409 void DebuggerEngine::handleCommand(int role, const QVariant &value)
411 //qDebug() << "COMMAND: " << role << value;
414 case RequestReloadSourceFilesRole:
418 case RequestReloadModulesRole:
422 case RequestReloadRegistersRole:
426 case RequestExecDetachRole:
430 case RequestExecContinueRole:
434 case RequestExecInterruptRole:
435 requestInterruptInferior();
438 case RequestExecResetRole:
439 notifyEngineIll(); // FIXME: check
442 case RequestExecStepRole:
446 case RequestExecStepOutRole:
450 case RequestExecNextRole:
454 case RequestExecRunToLineRole:
458 case RequestExecRunToFunctionRole:
459 executeRunToFunction();
462 case RequestExecReturnFromFunctionRole:
466 case RequestExecJumpToLineRole:
470 case RequestExecWatchRole:
474 case RequestExecExitRole:
475 d->queueShutdownInferior();
478 case RequestMakeSnapshotRole:
482 case RequestActivationRole:
483 setActive(value.toBool());
486 case RequestExecFrameDownRole:
490 case RequestExecFrameUpRole:
494 case RequestOperatedByInstructionTriggeredRole:
495 gotoLocation(stackHandler()->currentFrame(), true);
498 case RequestExecuteCommandRole:
499 executeDebuggerCommand(value.toString());
502 case RequestToggleBreakpointRole: {
503 QList<QVariant> list = value.toList();
504 QTC_ASSERT(list.size() == 2, break);
505 const QString fileName = list.at(0).toString();
506 const int lineNumber = list.at(1).toInt();
507 breakHandler()->toggleBreakpoint(fileName, lineNumber);
511 case RequestToolTipByExpressionRole: {
512 QList<QVariant> list = value.toList();
513 QTC_ASSERT(list.size() == 3, break);
514 QPoint point = list.at(0).value<QPoint>();
515 TextEditor::ITextEditor *editor = // Eeks.
516 (TextEditor::ITextEditor *)(list.at(1).value<quint64>());
517 int pos = list.at(2).toInt();
518 setToolTipExpression(point, editor, pos);
522 case RequestContextMenuRole: {
523 QList<QVariant> list = value.toList();
524 QTC_ASSERT(list.size() == 3, break);
525 d->handleContextMenuRequest(list);
531 void DebuggerEngine::showModuleSymbols
532 (const QString &moduleName, const Symbols &symbols)
534 QTreeWidget *w = new QTreeWidget;
535 w->setColumnCount(3);
536 w->setRootIsDecorated(false);
537 w->setAlternatingRowColors(true);
538 w->setSortingEnabled(true);
539 w->setHeaderLabels(QStringList() << tr("Symbol") << tr("Address") << tr("Code"));
540 w->setWindowTitle(tr("Symbols in \"%1\"").arg(moduleName));
541 foreach (const Symbol &s, symbols) {
542 QTreeWidgetItem *it = new QTreeWidgetItem;
543 it->setData(0, Qt::DisplayRole, s.name);
544 it->setData(1, Qt::DisplayRole, s.address);
545 it->setData(2, Qt::DisplayRole, s.state);
546 w->addTopLevelItem(it);
548 plugin()->createNewDock(w);
551 void DebuggerEngine::frameUp()
553 int currentIndex = stackHandler()->currentIndex();
554 activateFrame(qMin(currentIndex + 1, stackHandler()->stackSize() - 1));
557 void DebuggerEngine::frameDown()
559 int currentIndex = stackHandler()->currentIndex();
560 activateFrame(qMax(currentIndex - 1, 0));
563 ModulesHandler *DebuggerEngine::modulesHandler() const
565 return &d->m_modulesHandler;
568 BreakHandler *DebuggerEngine::breakHandler() const
570 return &d->m_breakHandler;
573 RegisterHandler *DebuggerEngine::registerHandler() const
575 return &d->m_registerHandler;
578 StackHandler *DebuggerEngine::stackHandler() const
580 return &d->m_stackHandler;
583 ThreadsHandler *DebuggerEngine::threadsHandler() const
585 return &d->m_threadsHandler;
588 WatchHandler *DebuggerEngine::watchHandler() const
590 return &d->m_watchHandler;
593 //SnapshotHandler *DebuggerEngine::snapshotHandler() const
595 // return &d->m_snapshotHandler;
598 SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
600 return &d->m_sourceFilesHandler;
603 QAbstractItemModel *DebuggerEngine::modulesModel() const
605 return d->m_modulesHandler.model();
608 QAbstractItemModel *DebuggerEngine::breakModel() const
610 return d->m_breakHandler.model();
613 QAbstractItemModel *DebuggerEngine::registerModel() const
615 return d->m_registerHandler.model();
618 QAbstractItemModel *DebuggerEngine::stackModel() const
620 return d->m_stackHandler.model();
623 QAbstractItemModel *DebuggerEngine::threadsModel() const
625 return d->m_threadsHandler.model();
628 QAbstractItemModel *DebuggerEngine::localsModel() const
630 return d->m_watchHandler.model(LocalsWatch);
633 QAbstractItemModel *DebuggerEngine::watchersModel() const
635 return d->m_watchHandler.model(WatchersWatch);
638 QAbstractItemModel *DebuggerEngine::returnModel() const
640 return d->m_watchHandler.model(ReturnWatch);
643 QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
645 return d->m_sourceFilesHandler.model();
648 QAbstractItemModel *DebuggerEngine::commandModel() const
650 return d->m_commandHandler.model();
653 void DebuggerEngine::fetchMemory(MemoryViewAgent *, QObject *,
654 quint64 addr, quint64 length)
660 void DebuggerEngine::setRegisterValue(int regnr, const QString &value)
666 void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
668 //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
669 // qDebug() << qPrintable(msg) << "IN STATE" << state();
670 d->m_runControl->showMessage(msg, channel);
671 plugin()->showMessage(msg, channel, timeout);
674 void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
676 QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
677 QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
679 DebuggerEngine *sessionTemplate = plugin()->sessionTemplate();
680 QTC_ASSERT(sessionTemplate, notifyEngineSetupFailed(); return);
681 QTC_ASSERT(sessionTemplate != this, notifyEngineSetupFailed(); return);
683 breakHandler()->initializeFromTemplate(sessionTemplate->breakHandler());
684 watchHandler()->initializeFromTemplate(sessionTemplate->watchHandler());
686 d->m_runControl = runControl;
688 QTC_ASSERT(state() == DebuggerNotReady, qDebug() << state());
690 d->m_inferiorPid = d->m_startParameters.attachPID > 0
691 ? d->m_startParameters.attachPID : 0;
693 if (d->m_startParameters.environment.empty())
694 d->m_startParameters.environment = Environment().toStringList();
696 if (d->m_startParameters.breakAtMain)
697 breakByFunctionMain();
699 const unsigned engineCapabilities = debuggerCapabilities();
700 theDebuggerAction(OperateByInstruction)
701 ->setEnabled(engineCapabilities & DisassemblerCapability);
703 setState(EngineSetupRequested);
707 void DebuggerEngine::breakByFunctionMain()
710 // FIXME: wrong on non-Qt based binaries
711 emit breakByFunction("qMain");
713 emit breakByFunction("main");
717 void DebuggerEngine::breakByFunction(const QString &functionName)
719 d->m_breakHandler.breakByFunction(functionName);
720 attemptBreakpointSynchronization();
723 void DebuggerEngine::resetLocation()
725 d->m_disassemblerViewAgent.resetLocation();
726 d->m_stackHandler.setCurrentIndex(-1);
727 plugin()->resetLocation();
730 void DebuggerEngine::gotoLocation(const QString &fileName, int lineNumber, bool setMarker)
733 frame.file = fileName;
734 frame.line = lineNumber;
735 gotoLocation(frame, setMarker);
738 void DebuggerEngine::gotoLocation(const StackFrame &frame, bool setMarker)
740 if (theDebuggerBoolSetting(OperateByInstruction) || !frame.isUsable()) {
742 plugin()->resetLocation();
743 d->m_disassemblerViewAgent.setFrame(frame);
745 plugin()->gotoLocation(frame.file, frame.line, setMarker);
749 void DebuggerEngine::executeStepX()
752 if (theDebuggerBoolSetting(OperateByInstruction))
758 void DebuggerEngine::executeStepOutX()
764 void DebuggerEngine::executeStepNextX()
767 if (theDebuggerBoolSetting(OperateByInstruction))
773 void DebuggerEngine::executeReturnX()
779 static TextEditor::ITextEditor *currentTextEditor()
781 EditorManager *editorManager = EditorManager::instance();
784 Core::IEditor *editor = editorManager->currentEditor();
785 return qobject_cast<ITextEditor*>(editor);
788 void DebuggerEngine::executeRunToLine()
790 ITextEditor *textEditor = currentTextEditor();
791 QTC_ASSERT(textEditor, return);
792 QString fileName = textEditor->file()->fileName();
793 if (fileName.isEmpty())
795 int lineNumber = textEditor->currentLine();
797 executeRunToLine(fileName, lineNumber);
800 void DebuggerEngine::executeRunToFunction()
802 ITextEditor *textEditor = currentTextEditor();
803 QTC_ASSERT(textEditor, return);
804 QString fileName = textEditor->file()->fileName();
805 QPlainTextEdit *ed = qobject_cast<QPlainTextEdit*>(textEditor->widget());
808 QTextCursor cursor = ed->textCursor();
809 QString functionName = cursor.selectedText();
810 if (functionName.isEmpty()) {
811 const QTextBlock block = cursor.block();
812 const QString line = block.text();
813 foreach (const QString &str, line.trimmed().split('(')) {
815 for (int i = str.size(); --i >= 0; ) {
816 if (!str.at(i).isLetterOrNumber())
827 if (functionName.isEmpty())
830 executeRunToFunction(functionName);
833 void DebuggerEngine::executeJumpToLine()
835 ITextEditor *textEditor = currentTextEditor();
836 QTC_ASSERT(textEditor, return);
837 QString fileName = textEditor->file()->fileName();
838 int lineNumber = textEditor->currentLine();
839 if (fileName.isEmpty())
841 executeJumpToLine(fileName, lineNumber);
844 void DebuggerEngine::addToWatchWindow()
846 // Requires a selection, but that's the only case we want anyway.
847 EditorManager *editorManager = EditorManager::instance();
850 IEditor *editor = editorManager->currentEditor();
853 ITextEditor *textEditor = qobject_cast<ITextEditor*>(editor);
857 QPlainTextEdit *ptEdit = qobject_cast<QPlainTextEdit*>(editor->widget());
859 tc = ptEdit->textCursor();
861 if (tc.hasSelection()) {
862 exp = tc.selectedText();
865 exp = cppExpressionAt(textEditor, tc.position(), &line, &column);
869 watchHandler()->watchExpression(exp);
872 // Called from RunControl.
873 void DebuggerEngine::handleFinished()
875 modulesHandler()->removeAll();
876 stackHandler()->removeAll();
877 threadsHandler()->removeAll();
878 watchHandler()->cleanup();
880 DebuggerEngine *sessionTemplate = plugin()->sessionTemplate();
881 QTC_ASSERT(sessionTemplate != this, /**/);
882 breakHandler()->storeToTemplate(sessionTemplate->breakHandler());
883 watchHandler()->storeToTemplate(sessionTemplate->watchHandler());
886 const DebuggerStartParameters &DebuggerEngine::startParameters() const
888 return d->m_startParameters;
891 DebuggerStartParameters &DebuggerEngine::startParameters()
893 return d->m_startParameters;
897 //////////////////////////////////////////////////////////////////////
899 // Dumpers. "Custom dumpers" are a library compiled against the current
900 // Qt containing functions to evaluate values of Qt classes
901 // (such as QString, taking pointers to their addresses).
902 // The library must be loaded into the debuggee.
904 //////////////////////////////////////////////////////////////////////
906 bool DebuggerEngine::qtDumperLibraryEnabled() const
908 return theDebuggerBoolSetting(UseDebuggingHelpers);
911 QStringList DebuggerEngine::qtDumperLibraryLocations() const
913 if (theDebuggerAction(UseCustomDebuggingHelperLocation)->value().toBool()) {
914 const QString customLocation =
915 theDebuggerAction(CustomDebuggingHelperLocation)->value().toString();
916 const QString location =
917 tr("%1 (explicitly set in the Debugger Options)").arg(customLocation);
918 return QStringList(location);
920 return d->m_startParameters.dumperLibraryLocations;
923 void DebuggerEngine::showQtDumperLibraryWarning(const QString &details)
925 //QMessageBox dialog(d->m_mainWindow); // FIXME
927 QPushButton *qtPref = dialog.addButton(tr("Open Qt preferences"),
928 QMessageBox::ActionRole);
929 QPushButton *helperOff = dialog.addButton(tr("Turn off helper usage"),
930 QMessageBox::ActionRole);
931 QPushButton *justContinue = dialog.addButton(tr("Continue anyway"),
932 QMessageBox::AcceptRole);
933 dialog.setDefaultButton(justContinue);
934 dialog.setWindowTitle(tr("Debugging helper missing"));
935 dialog.setText(tr("The debugger could not load the debugging helper library."));
936 dialog.setInformativeText(tr(
937 "The debugging helper is used to nicely format the values of some Qt "
938 "and Standard Library data types. "
939 "It must be compiled for each used Qt version separately. "
940 "This can be done in the Qt preferences page by selecting a Qt installation "
941 "and clicking on 'Rebuild' in the 'Debugging Helper' row."));
942 if (!details.isEmpty())
943 dialog.setDetailedText(details);
945 if (dialog.clickedButton() == qtPref) {
946 Core::ICore::instance()->showOptionsDialog(
947 _(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
948 _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
949 } else if (dialog.clickedButton() == helperOff) {
950 theDebuggerAction(UseDebuggingHelpers)
951 ->setValue(qVariantFromValue(false), false);
955 QString DebuggerEngine::qtDumperLibraryName() const
957 if (theDebuggerAction(UseCustomDebuggingHelperLocation)->value().toBool())
958 return theDebuggerAction(CustomDebuggingHelperLocation)->value().toString();
959 return startParameters().dumperLibrary;
962 DebuggerState DebuggerEngine::state() const
967 DebuggerState DebuggerEngine::lastGoodState() const
969 return d->m_lastGoodState;
972 DebuggerState DebuggerEngine::targetState() const
974 return d->m_targetState;
977 static bool isAllowedTransition(DebuggerState from, DebuggerState to)
980 case DebuggerNotReady:
981 return to == EngineSetupRequested;
983 case EngineSetupRequested:
984 return to == EngineSetupOk || to == EngineSetupFailed;
985 case EngineSetupFailed:
986 // FIXME: In therory it's the engine's task to go into a
987 // proper "Shutdown" state before calling notifyEngineSetupFailed
988 //return to == DebuggerFinished;
989 return to == EngineShutdownRequested;
991 return to == InferiorSetupRequested || to == EngineShutdownRequested;
993 case InferiorSetupRequested:
994 return to == EngineRunRequested || to == InferiorSetupFailed;
995 case InferiorSetupFailed:
996 return to == EngineShutdownRequested;
998 case EngineRunRequested:
999 return to == InferiorRunRequested || to == InferiorStopRequested
1000 || to == InferiorUnrunnable || to == EngineRunFailed;
1002 case EngineRunFailed:
1003 return to == InferiorShutdownRequested;
1005 case InferiorRunRequested:
1006 return to == InferiorRunOk || to == InferiorRunFailed;
1007 case InferiorRunFailed:
1008 return to == InferiorStopOk;
1010 return to == InferiorStopRequested || to == InferiorStopOk;
1012 case InferiorStopRequested:
1013 return to == InferiorStopOk || to == InferiorStopFailed;
1014 case InferiorStopOk:
1015 return to == InferiorRunRequested || to == InferiorShutdownRequested
1016 || to == InferiorStopOk;
1017 case InferiorStopFailed:
1018 return to == EngineShutdownRequested;
1020 case InferiorUnrunnable:
1021 return to == InferiorShutdownRequested;
1022 case InferiorShutdownRequested:
1023 return to == InferiorShutdownOk || to == InferiorShutdownFailed;
1024 case InferiorShutdownOk:
1025 return to == EngineShutdownRequested;
1026 case InferiorShutdownFailed:
1027 return to == EngineShutdownRequested;
1029 case EngineShutdownRequested:
1030 return to == EngineShutdownOk;
1031 case EngineShutdownOk:
1032 return to == DebuggerFinished;
1033 case EngineShutdownFailed:
1034 return to == DebuggerFinished;
1036 case DebuggerFinished:
1040 qDebug() << "UNKNOWN STATE:" << from;
1044 void DebuggerEngine::notifyEngineSetupFailed()
1046 showMessage(_("NOTE: ENGINE SETUP FAILED"));
1047 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
1048 setState(EngineSetupFailed);
1049 d->m_runControl->startFailed();
1050 d->queueShutdownEngine();
1053 void DebuggerEngine::notifyEngineSetupOk()
1055 showMessage(_("NOTE: ENGINE SETUP OK"));
1056 QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
1057 setState(EngineSetupOk);
1058 d->m_runControl->startSuccessful();
1059 showMessage(_("QUEUE: SETUP INFERIOR"));
1060 QTimer::singleShot(0, d, SLOT(doSetupInferior()));
1063 void DebuggerEnginePrivate::doSetupInferior()
1065 QTC_ASSERT(state() == EngineSetupOk, qDebug() << state());
1066 m_engine->setState(InferiorSetupRequested);
1067 m_engine->showMessage(_("CALL: SETUP INFERIOR"));
1068 m_engine->setupInferior();
1071 void DebuggerEngine::notifyInferiorSetupFailed()
1073 showMessage(_("NOTE: INFERIOR SETUP FAILED"));
1074 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
1075 setState(InferiorSetupFailed);
1076 d->queueShutdownEngine();
1079 void DebuggerEngine::notifyInferiorSetupOk()
1081 showMessage(_("NOTE: INFERIOR SETUP OK"));
1082 QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
1083 d->queueRunEngine();
1086 void DebuggerEnginePrivate::doRunEngine()
1088 m_engine->showMessage(_("CALL: RUN ENGINE"));
1089 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1090 m_engine->runEngine();
1093 void DebuggerEngine::notifyInferiorUnrunnable()
1095 showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
1096 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1097 setState(InferiorUnrunnable);
1100 void DebuggerEngine::notifyEngineRunFailed()
1102 showMessage(_("NOTE: ENGINE RUN FAILED"));
1103 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1104 setState(EngineRunFailed);
1105 d->queueShutdownInferior();
1108 void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
1110 showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
1111 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1112 setState(InferiorRunRequested);
1113 notifyInferiorRunOk();
1116 void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
1118 showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
1119 QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
1120 setState(InferiorStopRequested);
1121 notifyInferiorStopOk();
1124 void DebuggerEngine::notifyInferiorRunRequested()
1126 showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
1127 QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
1128 setState(InferiorRunRequested);
1131 void DebuggerEngine::notifyInferiorRunOk()
1133 showMessage(_("NOTE: INFERIOR RUN OK"));
1134 QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
1135 setState(InferiorRunOk);
1138 void DebuggerEngine::notifyInferiorRunFailed()
1140 showMessage(_("NOTE: INFERIOR RUN FAILED"));
1141 QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
1142 setState(InferiorRunFailed);
1143 setState(InferiorStopOk);
1145 d->queueShutdownInferior();
1148 void DebuggerEngine::notifyInferiorStopOk()
1150 showMessage(_("NOTE: INFERIOR STOP OK"));
1151 // Ignore spurious notifications after we are set to die.
1153 showMessage(_("NOTE: ... WHILE DYING. "));
1154 // Forward state to "StopOk" if needed.
1155 if (state() == InferiorStopRequested
1156 || state() == InferiorRunRequested
1157 || state() == InferiorRunOk) {
1158 showMessage(_("NOTE: ... FORWARDING TO 'STOP OK'. "));
1159 setState(InferiorStopOk);
1161 if (state() == InferiorStopOk || state() == InferiorStopFailed) {
1162 d->queueShutdownInferior();
1164 showMessage(_("NOTE: ... IGNORING STOP MESSAGE"));
1167 QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
1168 setState(InferiorStopOk);
1171 void DebuggerEngine::notifyInferiorSpontaneousStop()
1173 showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
1174 QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
1175 setState(InferiorStopOk);
1178 void DebuggerEngine::notifyInferiorStopFailed()
1180 showMessage(_("NOTE: INFERIOR STOP FAILED"));
1181 QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
1182 setState(InferiorStopFailed);
1183 d->queueShutdownEngine();
1186 void DebuggerEnginePrivate::doInterruptInferior()
1188 QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
1189 m_engine->setState(InferiorStopRequested);
1190 m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
1191 m_engine->interruptInferior();
1194 void DebuggerEnginePrivate::doShutdownInferior()
1196 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
1197 m_engine->resetLocation();
1198 m_targetState = DebuggerFinished;
1199 m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
1200 m_engine->shutdownInferior();
1203 void DebuggerEngine::notifyInferiorShutdownOk()
1205 showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
1206 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
1207 d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
1208 setState(InferiorShutdownOk);
1209 d->queueShutdownEngine();
1212 void DebuggerEngine::notifyInferiorShutdownFailed()
1214 showMessage(_("INFERIOR SHUTDOWN FAILED"));
1215 QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
1216 setState(InferiorShutdownFailed);
1217 d->queueShutdownEngine();
1220 void DebuggerEngine::notifyInferiorIll()
1222 showMessage(_("NOTE: INFERIOR ILL"));
1223 // This can be issued in almost any state. The inferior could still be
1224 // alive as some previous notifications might have been bogus.
1225 d->m_targetState = DebuggerFinished;
1226 d->m_lastGoodState = d->m_state;
1227 if (state() == InferiorRunRequested) {
1228 // We asked for running, but did not see a response.
1229 // Assume the inferior is dead.
1230 // FIXME: Use timeout?
1231 setState(InferiorRunFailed);
1232 setState(InferiorStopOk);
1234 d->queueShutdownInferior();
1237 void DebuggerEnginePrivate::doShutdownEngine()
1239 QTC_ASSERT(state() == EngineShutdownRequested
1240 || state() == InferiorShutdownOk, qDebug() << state());
1241 m_targetState = DebuggerFinished;
1242 m_engine->showMessage(_("CALL: SHUTDOWN ENGINE"));
1243 m_engine->shutdownEngine();
1246 void DebuggerEngine::notifyEngineShutdownOk()
1248 showMessage(_("NOTE: ENGINE SHUTDOWN OK"));
1249 QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
1250 setState(EngineShutdownOk);
1251 QTimer::singleShot(0, d, SLOT(doFinishDebugger()));
1254 void DebuggerEngine::notifyEngineShutdownFailed()
1256 showMessage(_("NOTE: ENGINE SHUTDOWN FAILED"));
1257 QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
1258 setState(EngineShutdownFailed);
1259 QTimer::singleShot(0, d, SLOT(doFinishDebugger()));
1262 void DebuggerEnginePrivate::doFinishDebugger()
1264 m_engine->showMessage(_("NOTE: FINISH DEBUGGER"));
1265 QTC_ASSERT(state() == EngineShutdownOk
1266 || state() == EngineShutdownFailed, qDebug() << state());
1267 m_engine->resetLocation();
1268 m_engine->setState(DebuggerFinished);
1269 m_runControl->debuggingFinished();
1272 void DebuggerEngine::notifyEngineIll()
1274 showMessage(_("NOTE: ENGINE ILL ******"));
1275 d->m_targetState = DebuggerFinished;
1276 d->m_lastGoodState = d->m_state;
1278 case InferiorRunRequested:
1280 case InferiorStopRequested:
1281 case InferiorStopOk:
1282 qDebug() << "FORWARDING STATE TO " << InferiorShutdownFailed;
1283 setState(InferiorShutdownFailed, true);
1288 d->queueShutdownEngine();
1291 void DebuggerEngine::notifyEngineSpontaneousShutdown()
1293 showMessage(_("NOTE: ENGINE SPONTANEOUS SHUTDOWN"));
1294 d->queueFinishDebugger();
1297 void DebuggerEngine::notifyInferiorExited()
1299 showMessage(_("NOTE: INFERIOR EXITED"));
1302 // This can be issued in almost any state. We assume, though,
1303 // that at this point of time the inferior is not running anymore,
1304 // even if stop notification were not issued or got lost.
1305 if (state() == InferiorRunOk) {
1306 setState(InferiorStopRequested);
1307 setState(InferiorStopOk);
1309 setState(InferiorShutdownRequested);
1310 setState(InferiorShutdownOk);
1311 d->queueShutdownEngine();
1314 void DebuggerEngine::setState(DebuggerState state, bool forced)
1316 //qDebug() << "STATUS CHANGE: FROM " << stateName(d->m_state)
1317 // << " TO " << stateName(state);
1319 DebuggerState oldState = d->m_state;
1322 QString msg = _("State changed%5 from %1(%2) to %3(%4).")
1323 .arg(stateName(oldState)).arg(oldState).arg(stateName(state)).arg(state)
1324 .arg(forced ? " BY FORCE" : "");
1325 if (!forced && !isAllowedTransition(oldState, state))
1326 qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;
1328 showMessage(msg, LogDebug);
1329 plugin()->updateState(this);
1332 bool DebuggerEngine::debuggerActionsEnabled() const
1334 return debuggerActionsEnabled(d->m_state);
1337 bool DebuggerEngine::debuggerActionsEnabled(DebuggerState state)
1340 case InferiorSetupRequested:
1342 case InferiorUnrunnable:
1343 case InferiorStopOk:
1345 case InferiorStopRequested:
1346 case InferiorRunRequested:
1347 case InferiorRunFailed:
1348 case DebuggerNotReady:
1349 case EngineSetupRequested:
1351 case EngineSetupFailed:
1352 case EngineRunRequested:
1353 case EngineRunFailed:
1354 case InferiorSetupFailed:
1355 case InferiorStopFailed:
1356 case InferiorShutdownRequested:
1357 case InferiorShutdownOk:
1358 case InferiorShutdownFailed:
1359 case EngineShutdownRequested:
1360 case EngineShutdownOk:
1361 case EngineShutdownFailed:
1362 case DebuggerFinished:
1368 void DebuggerEngine::notifyInferiorPid(qint64 pid)
1370 showMessage(tr("Taking notice of pid %1").arg(pid));
1371 if (d->m_inferiorPid == pid)
1373 d->m_inferiorPid = pid;
1374 QTimer::singleShot(0, d, SLOT(raiseApplication()));
1377 qint64 DebuggerEngine::inferiorPid() const
1379 return d->m_inferiorPid;
1382 DebuggerPlugin *DebuggerEngine::plugin() const
1384 return DebuggerPlugin::instance();
1387 void DebuggerEngine::openFile(const QString &fileName, int lineNumber)
1389 plugin()->gotoLocation(fileName, lineNumber, false);
1392 bool DebuggerEngine::isReverseDebugging() const
1394 return plugin()->isReverseDebugging();
1397 bool DebuggerEngine::isActive() const
1399 return d->m_isActive && !isSessionEngine();
1402 void DebuggerEngine::setActive(bool on)
1404 //qDebug() << "SETTING ACTIVE" << this << on;
1406 //breakHandler()->updateMarkers();
1409 // called by DebuggerRunControl
1410 void DebuggerEngine::quitDebugger()
1412 showMessage("QUIT DEBUGGER REQUESTED");
1413 d->m_targetState = DebuggerFinished;
1414 if (state() == InferiorStopOk) {
1415 d->queueShutdownInferior();
1416 } else if (state() == InferiorRunOk) {
1417 d->doInterruptInferior();
1419 // FIXME: We should disable the actions connected to that
1420 notifyInferiorIll();
1424 void DebuggerEngine::requestInterruptInferior()
1426 d->doInterruptInferior();
1429 } // namespace Internal
1430 } // namespace Debugger
1432 #include "debuggerengine.moc"