/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Commercial Usage ** ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://qt.nokia.com/contact. ** **************************************************************************/ #include "debuggerplugin.h" #include "breakhandler.h" #include "debuggeractions.h" #include "debuggerdialogs.h" #include "debuggerconstants.h" #include "debuggermanager.h" #include "debuggerrunner.h" #include "debuggerstringutils.h" #include "ui_commonoptionspage.h" #include "ui_dumperoptionpage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Core; using namespace Debugger::Constants; using namespace Debugger::Internal; using namespace ProjectExplorer; using namespace TextEditor; namespace Debugger { namespace Constants { const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebugging"; const char * const STARTEXTERNAL = "Debugger.StartExternal"; const char * const ATTACHEXTERNAL = "Debugger.AttachExternal"; const char * const ATTACHCORE = "Debugger.AttachCore"; const char * const ATTACHREMOTE = "Debugger.AttachRemote"; const char * const DETACH = "Debugger.Detach"; const char * const RUN_TO_LINE = "Debugger.RunToLine"; const char * const RUN_TO_FUNCTION = "Debugger.RunToFunction"; const char * const JUMP_TO_LINE = "Debugger.JumpToLine"; const char * const TOGGLE_BREAK = "Debugger.ToggleBreak"; const char * const BREAK_BY_FUNCTION = "Debugger.BreakByFunction"; const char * const BREAK_AT_MAIN = "Debugger.BreakAtMain"; const char * const ADD_TO_WATCH1 = "Debugger.AddToWatch1"; const char * const ADD_TO_WATCH2 = "Debugger.AddToWatch2"; const char * const OPERATE_BY_INSTRUCTION = "Debugger.OperateByInstruction"; #ifdef Q_WS_MAC const char * const INTERRUPT_KEY = "Shift+F5"; const char * const RESET_KEY = "Ctrl+Shift+F5"; const char * const STEP_KEY = "F7"; const char * const STEPOUT_KEY = "Shift+F7"; const char * const NEXT_KEY = "F6"; const char * const REVERSE_KEY = ""; const char * const RUN_TO_LINE_KEY = "Shift+F8"; const char * const RUN_TO_FUNCTION_KEY = "Ctrl+F6"; const char * const JUMP_TO_LINE_KEY = "Alt+D,Alt+L"; const char * const TOGGLE_BREAK_KEY = "F8"; const char * const BREAK_BY_FUNCTION_KEY = "Alt+D,Alt+F"; const char * const BREAK_AT_MAIN_KEY = "Alt+D,Alt+M"; const char * const ADD_TO_WATCH_KEY = "Alt+D,Alt+W"; #else const char * const INTERRUPT_KEY = "Shift+F5"; const char * const RESET_KEY = "Ctrl+Shift+F5"; const char * const STEP_KEY = "F11"; const char * const STEPOUT_KEY = "Shift+F11"; const char * const NEXT_KEY = "F10"; const char * const REVERSE_KEY = "F12"; const char * const RUN_TO_LINE_KEY = ""; const char * const RUN_TO_FUNCTION_KEY = ""; const char * const JUMP_TO_LINE_KEY = ""; const char * const TOGGLE_BREAK_KEY = "F9"; const char * const BREAK_BY_FUNCTION_KEY = ""; const char * const BREAK_AT_MAIN_KEY = ""; const char * const ADD_TO_WATCH_KEY = "Ctrl+Alt+Q"; #endif } // namespace Constants } // namespace Debugger static ProjectExplorer::SessionManager *sessionManager() { return ProjectExplorer::ProjectExplorerPlugin::instance()->session(); } static QSettings *settings() { return ICore::instance()->settings(); } static QToolButton *toolButton(QAction *action) { QToolButton *button = new QToolButton; button->setDefaultAction(action); return button; } /////////////////////////////////////////////////////////////////////// // // DebugMode // /////////////////////////////////////////////////////////////////////// namespace Debugger { namespace Internal { class DebugMode : public Core::BaseMode { Q_OBJECT public: DebugMode(QObject *parent = 0); ~DebugMode(); }; DebugMode::DebugMode(QObject *parent) : BaseMode(parent) { setDisplayName(tr("Debug")); setId(Constants::MODE_DEBUG); setIcon(QIcon(":/fancyactionbar/images/mode_Debug.png")); setPriority(Constants::P_MODE_DEBUG); } DebugMode::~DebugMode() { // Make sure the editor manager does not get deleted EditorManager::instance()->setParent(0); } /////////////////////////////////////////////////////////////////////// // // DebuggerListener: Close the debugging session if running. // /////////////////////////////////////////////////////////////////////// class DebuggerListener : public Core::ICoreListener { Q_OBJECT public: explicit DebuggerListener(QObject *parent = 0); virtual bool coreAboutToClose(); }; DebuggerListener::DebuggerListener(QObject *parent) : Core::ICoreListener(parent) { } bool DebuggerListener::coreAboutToClose() { DebuggerManager *mgr = DebuggerManager::instance(); if (!mgr) return true; // Ask to terminate the session. const QString title = tr("Close Debugging Session"); bool cleanTermination = false; switch (mgr->state()) { case DebuggerNotReady: return true; case AdapterStarted: // Most importantly, terminating a running case AdapterStartFailed: // debuggee can cause problems. case InferiorUnrunnable: case InferiorStartFailed: case InferiorStopped: case InferiorShutDown: cleanTermination = true; break; default: break; } const QString question = cleanTermination ? tr("A debugging session is still in progress.\nWould you like to terminate it?") : tr("A debugging session is still in progress. Terminating the session in the current" " state (%1) can leave the target in an inconsistent state." " Would you still like to terminate it?") .arg(QLatin1String(DebuggerManager::stateName(mgr->state()))); QMessageBox::StandardButton answer = QMessageBox::question(mgr->mainWindow(), title, question, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); if (answer != QMessageBox::Yes) return false; mgr->exitDebugger(); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); return true; } } // namespace Internal } // namespace Debugger /////////////////////////////////////////////////////////////////////// // // LocationMark // /////////////////////////////////////////////////////////////////////// namespace Debugger { namespace Internal { static QIcon locationMarkIcon() { static const QIcon icon(":/debugger/images/location.svg"); return icon; } // Used in "real" editors class LocationMark : public TextEditor::BaseTextMark { Q_OBJECT public: LocationMark(const QString &fileName, int linenumber) : BaseTextMark(fileName, linenumber) {} QIcon icon() const { return locationMarkIcon(); } void updateLineNumber(int /*lineNumber*/) {} void updateBlock(const QTextBlock & /*block*/) {} void removedFromEditor() {} }; } // namespace Internal } // namespace Debugger /////////////////////////////////////////////////////////////////////// // // CommonOptionsPage // /////////////////////////////////////////////////////////////////////// namespace Debugger { namespace Internal { class CommonOptionsPage : public Core::IOptionsPage { Q_OBJECT public: CommonOptionsPage() {} // IOptionsPage QString id() const { return QLatin1String(Debugger::Constants::DEBUGGER_COMMON_SETTINGS_ID); } QString displayName() const { return QCoreApplication::translate("Debugger", Debugger::Constants::DEBUGGER_COMMON_SETTINGS_NAME); } QString category() const { return QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY); } QString displayCategory() const { return QCoreApplication::translate("Debugger", Debugger::Constants::DEBUGGER_SETTINGS_TR_CATEGORY); } QWidget *createPage(QWidget *parent); void apply() { m_group.apply(settings()); } void finish() { m_group.finish(); } virtual bool matches(const QString &s) const; private: Ui::CommonOptionsPage m_ui; Utils::SavedActionSet m_group; QString m_searchKeywords; }; QWidget *CommonOptionsPage::createPage(QWidget *parent) { QWidget *w = new QWidget(parent); m_ui.setupUi(w); m_group.clear(); m_group.insert(theDebuggerAction(ListSourceFiles), m_ui.checkBoxListSourceFiles); m_group.insert(theDebuggerAction(UseAlternatingRowColors), m_ui.checkBoxUseAlternatingRowColors); m_group.insert(theDebuggerAction(UseMessageBoxForSignals), m_ui.checkBoxUseMessageBoxForSignals); m_group.insert(theDebuggerAction(SkipKnownFrames), m_ui.checkBoxSkipKnownFrames); m_group.insert(theDebuggerAction(UseToolTipsInMainEditor), m_ui.checkBoxUseToolTipsInMainEditor); m_group.insert(theDebuggerAction(AutoDerefPointers), 0); m_group.insert(theDebuggerAction(UseToolTipsInLocalsView), 0); m_group.insert(theDebuggerAction(UseToolTipsInBreakpointsView), 0); m_group.insert(theDebuggerAction(UseAddressInBreakpointsView), 0); m_group.insert(theDebuggerAction(UseAddressInStackView), 0); m_group.insert(theDebuggerAction(EnableReverseDebugging), m_ui.checkBoxEnableReverseDebugging); m_group.insert(theDebuggerAction(MaximalStackDepth), m_ui.spinBoxMaximalStackDepth); m_group.insert(theDebuggerAction(GdbWatchdogTimeout), 0); m_group.insert(theDebuggerAction(ShowStdNamespace), 0); m_group.insert(theDebuggerAction(ShowQtNamespace), 0); m_group.insert(theDebuggerAction(LogTimeStamps), 0); m_group.insert(theDebuggerAction(UsePreciseBreakpoints), 0); #ifdef USE_REVERSE_DEBUGGING m_ui.checkBoxEnableReverseDebugging->hide(); #endif if (m_searchKeywords.isEmpty()) { QTextStream(&m_searchKeywords) << ' ' << m_ui.checkBoxListSourceFiles->text() << ' ' << m_ui.checkBoxUseMessageBoxForSignals->text() << ' ' << m_ui.checkBoxUseAlternatingRowColors->text() << ' ' << m_ui.checkBoxUseToolTipsInMainEditor->text() << ' ' << m_ui.checkBoxSkipKnownFrames->text() << ' ' << m_ui.checkBoxEnableReverseDebugging->text() << ' ' << m_ui.labelMaximalStackDepth->text(); m_searchKeywords.remove(QLatin1Char('&')); } return w; } bool CommonOptionsPage::matches(const QString &s) const { return m_searchKeywords.contains(s, Qt::CaseInsensitive); } } // namespace Internal } // namespace Debugger /////////////////////////////////////////////////////////////////////// // // DebuggingHelperOptionPage // /////////////////////////////////////////////////////////////////////// static inline bool oxygenStyle() { if (const ManhattanStyle *ms = qobject_cast(qApp->style())) return !qstrcmp("OxygenStyle", ms->systemStyle()->metaObject()->className()); return false; } namespace Debugger { namespace Internal { class DebuggingHelperOptionPage : public Core::IOptionsPage { Q_OBJECT public: DebuggingHelperOptionPage() {} // IOptionsPage QString id() const { return QLatin1String("B.DebuggingHelper"); } QString displayName() const { return tr("Debugging Helper"); } QString category() const { return QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY); } QString displayCategory() const { return QCoreApplication::translate("Debugger", Debugger::Constants::DEBUGGER_SETTINGS_TR_CATEGORY); } QWidget *createPage(QWidget *parent); void apply() { m_group.apply(settings()); } void finish() { m_group.finish(); } virtual bool matches(const QString &s) const; private: Ui::DebuggingHelperOptionPage m_ui; Utils::SavedActionSet m_group; QString m_searchKeywords; }; QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent) { QWidget *w = new QWidget(parent); m_ui.setupUi(w); m_ui.dumperLocationChooser->setExpectedKind(Utils::PathChooser::Command); m_ui.dumperLocationChooser->setPromptDialogTitle(tr("Choose DebuggingHelper Location")); m_ui.dumperLocationChooser->setInitialBrowsePathBackup( Core::ICore::instance()->resourcePath() + "../../lib"); m_group.clear(); m_group.insert(theDebuggerAction(UseDebuggingHelpers), m_ui.debuggingHelperGroupBox); m_group.insert(theDebuggerAction(UseCustomDebuggingHelperLocation), m_ui.customLocationGroupBox); // Suppress Oxygen style's giving flat group boxes bold titles if (oxygenStyle()) m_ui.customLocationGroupBox->setStyleSheet(QLatin1String("QGroupBox::title { font: ; }")); m_group.insert(theDebuggerAction(CustomDebuggingHelperLocation), m_ui.dumperLocationChooser); m_group.insert(theDebuggerAction(UseCodeModel), m_ui.checkBoxUseCodeModel); #ifdef QT_DEBUG m_group.insert(theDebuggerAction(DebugDebuggingHelpers), m_ui.checkBoxDebugDebuggingHelpers); #else m_ui.checkBoxDebugDebuggingHelpers->hide(); #endif #ifndef QT_DEBUG #if 0 cmd = am->registerAction(m_manager->m_dumpLogAction, Constants::DUMP_LOG, globalcontext); //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+L"))); cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F11"))); mdebug->addAction(cmd); #endif #endif if (m_searchKeywords.isEmpty()) { QTextStream(&m_searchKeywords) << ' ' << m_ui.debuggingHelperGroupBox->title() << ' ' << m_ui.customLocationGroupBox->title() << ' ' << m_ui.dumperLocationLabel->text() << ' ' << m_ui.checkBoxUseCodeModel->text() << ' ' << m_ui.checkBoxDebugDebuggingHelpers->text(); m_searchKeywords.remove(QLatin1Char('&')); } return w; } bool DebuggingHelperOptionPage::matches(const QString &s) const { return m_searchKeywords.contains(s, Qt::CaseInsensitive); } } // namespace Internal } // namespace Debugger /////////////////////////////////////////////////////////////////////// // // DebuggerPlugin // /////////////////////////////////////////////////////////////////////// DebuggerPlugin::AttachRemoteParameters::AttachRemoteParameters() : attachPid(0), winCrashEvent(0) { } DebuggerPlugin::DebuggerPlugin() : m_manager(0), m_debugMode(0), m_locationMark(0), m_gdbRunningContext(0), m_cmdLineEnabledEngines(AllEngineTypes), m_toggleLockedAction(0) {} DebuggerPlugin::~DebuggerPlugin() {} void DebuggerPlugin::shutdown() { QTC_ASSERT(m_manager, /**/); if (m_manager) m_manager->shutdown(); writeSettings(); delete DebuggerSettings::instance(); //qDebug() << "DebuggerPlugin::~DebuggerPlugin"; removeObject(m_debugMode); // FIXME: when using the line below, BreakWindow etc gets deleted twice. // so better leak for now... delete m_debugMode; m_debugMode = 0; delete m_locationMark; m_locationMark = 0; removeObject(m_manager); delete m_manager; m_manager = 0; } static QString msgParameterMissing(const QString &a) { return DebuggerPlugin::tr("Option '%1' is missing the parameter.").arg(a); } static QString msgInvalidNumericParameter(const QString &a, const QString &number) { return DebuggerPlugin::tr("The parameter '%1' of option '%2' is not a number.").arg(number, a); } // Parse arguments static bool parseArgument(QStringList::const_iterator &it, const QStringList::const_iterator &cend, DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters, unsigned *enabledEngines, QString *errorMessage) { const QString &option = *it; // '-debug ' if (*it == QLatin1String("-debug")) { ++it; if (it == cend) { *errorMessage = msgParameterMissing(*it); return false; } bool ok; attachRemoteParameters->attachPid = it->toULongLong(&ok); if (!ok) { attachRemoteParameters->attachPid = 0; attachRemoteParameters->attachCore = *it; } return true; } // -wincrashevent . A handle used for // a handshake when attaching to a crashed Windows process. if (*it == QLatin1String("-wincrashevent")) { ++it; if (it == cend) { *errorMessage = msgParameterMissing(*it); return false; } bool ok; attachRemoteParameters->winCrashEvent = it->toULongLong(&ok); if (!ok) { *errorMessage = msgInvalidNumericParameter(option, *it); return false; } return true; } // engine disabling if (option == QLatin1String("-disable-cdb")) { *enabledEngines &= ~Debugger::CdbEngineType; return true; } if (option == QLatin1String("-disable-gdb")) { *enabledEngines &= ~Debugger::GdbEngineType; return true; } if (option == QLatin1String("-disable-sdb")) { *enabledEngines &= ~Debugger::ScriptEngineType; return true; } *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option); return false; } static bool parseArguments(const QStringList &args, DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters, unsigned *enabledEngines, QString *errorMessage) { const QStringList::const_iterator cend = args.constEnd(); for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it) if (!parseArgument(it, cend, attachRemoteParameters, enabledEngines, errorMessage)) return false; if (Debugger::Constants::Internal::debug) qDebug().nospace() << args << "engines=0x" << QString::number(*enabledEngines, 16) << " pid" << attachRemoteParameters->attachPid << " core" << attachRemoteParameters->attachCore << '\n'; return true; } void DebuggerPlugin::remoteCommand(const QStringList &options, const QStringList &) { QString errorMessage; AttachRemoteParameters parameters; unsigned dummy = 0; // Did we receive a request for debugging (unless it is ourselves)? if (parseArguments(options, ¶meters, &dummy, &errorMessage) && parameters.attachPid != quint64(QCoreApplication::applicationPid())) { m_attachRemoteParameters = parameters; attachCmdLine(); } } bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMessage) { // Do not fail the whole plugin if something goes wrong here if (!parseArguments(arguments, &m_attachRemoteParameters, &m_cmdLineEnabledEngines, errorMessage)) { *errorMessage = tr("Error evaluating command line arguments: %1") .arg(*errorMessage); qWarning("%s\n", qPrintable(*errorMessage)); errorMessage->clear(); } m_manager = new DebuggerManager; ExtensionSystem::PluginManager::instance()->addObject(m_manager); const QList engineOptionPages = m_manager->initializeEngines(m_cmdLineEnabledEngines); ICore *core = ICore::instance(); QTC_ASSERT(core, return false); Core::ActionManager *am = core->actionManager(); QTC_ASSERT(am, return false); Core::UniqueIDManager *uidm = core->uniqueIDManager(); QTC_ASSERT(uidm, return false); QList globalcontext; globalcontext << Core::Constants::C_GLOBAL_ID; QList cppcontext; cppcontext << uidm->uniqueIdentifier(ProjectExplorer::Constants::LANG_CXX); QList debuggercontext; debuggercontext << uidm->uniqueIdentifier(C_GDBDEBUGGER); QList cppeditorcontext; cppeditorcontext << uidm->uniqueIdentifier(CppEditor::Constants::CPPEDITOR_ID); QList texteditorcontext; texteditorcontext << uidm->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR); m_gdbRunningContext = uidm->uniqueIdentifier(Constants::GDBRUNNING); //Core::ActionContainer *mcppcontext = // am->actionContainer(CppEditor::Constants::M_CONTEXT); // External apps m_startExternalAction = new QAction(this); m_startExternalAction->setText(tr("Start and Debug External Application...")); connect(m_startExternalAction, SIGNAL(triggered()), this, SLOT(startExternalApplication())); m_attachExternalAction = new QAction(this); m_attachExternalAction->setText(tr("Attach to Running External Application...")); connect(m_attachExternalAction, SIGNAL(triggered()), this, SLOT(attachExternalApplication())); m_attachCoreAction = new QAction(this); m_attachCoreAction->setText(tr("Attach to Core...")); connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore())); m_startRemoteAction = new QAction(this); m_startRemoteAction->setText(tr("Start and Attach to Remote Application...")); connect(m_startRemoteAction, SIGNAL(triggered()), this, SLOT(startRemoteApplication())); m_detachAction = new QAction(this); m_detachAction->setText(tr("Detach Debugger")); connect(m_detachAction, SIGNAL(triggered()), m_manager, SLOT(detachDebugger())); Core::ActionContainer *mdebug = am->actionContainer(ProjectExplorer::Constants::M_DEBUG); Core::ActionContainer *mstart = am->actionContainer(ProjectExplorer::Constants::M_DEBUG_STARTDEBUGGING); Core::Command *cmd = 0; const DebuggerManagerActions actions = m_manager->debuggerManagerActions(); cmd = am->registerAction(actions.continueAction, ProjectExplorer::Constants::DEBUG, QList() << m_gdbRunningContext); mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE); cmd = am->registerAction(m_startExternalAction, Constants::STARTEXTERNAL, globalcontext); mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE); cmd = am->registerAction(m_attachExternalAction, Constants::ATTACHEXTERNAL, globalcontext); mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE); cmd = am->registerAction(m_attachCoreAction, Constants::ATTACHCORE, globalcontext); mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE); cmd = am->registerAction(m_startRemoteAction, Constants::ATTACHREMOTE, globalcontext); mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE); cmd = am->registerAction(m_detachAction, Constants::DETACH, globalcontext); mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE); cmd = am->registerAction(actions.stopAction, Constants::INTERRUPT, globalcontext); cmd->setAttribute(Core::Command::CA_UpdateText); cmd->setAttribute(Core::Command::CA_UpdateIcon); cmd->setDefaultKeySequence(QKeySequence(Constants::INTERRUPT_KEY)); cmd->setDefaultText(tr("Stop Debugger/Interrupt Debugger")); mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE); cmd = am->registerAction(actions.resetAction, Constants::RESET, globalcontext); cmd->setAttribute(Core::Command::CA_UpdateText); cmd->setDefaultKeySequence(QKeySequence(Constants::RESET_KEY)); cmd->setDefaultText(tr("Reset Debugger")); //disabled mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE); QAction *sep = new QAction(this); sep->setSeparator(true); cmd = am->registerAction(sep, QLatin1String("Debugger.Sep.Step"), globalcontext); mdebug->addAction(cmd); cmd = am->registerAction(actions.nextAction, Constants::NEXT, debuggercontext); cmd->setDefaultKeySequence(QKeySequence(Constants::NEXT_KEY)); mdebug->addAction(cmd); cmd = am->registerAction(actions.stepAction, Constants::STEP, debuggercontext); cmd->setDefaultKeySequence(QKeySequence(Constants::STEP_KEY)); mdebug->addAction(cmd); cmd = am->registerAction(actions.stepOutAction, Constants::STEPOUT, debuggercontext); cmd->setDefaultKeySequence(QKeySequence(Constants::STEPOUT_KEY)); mdebug->addAction(cmd); cmd = am->registerAction(actions.runToLineAction, Constants::RUN_TO_LINE, debuggercontext); cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_LINE_KEY)); mdebug->addAction(cmd); cmd = am->registerAction(actions.runToFunctionAction, Constants::RUN_TO_FUNCTION, debuggercontext); cmd->setDefaultKeySequence(QKeySequence(Constants::RUN_TO_FUNCTION_KEY)); mdebug->addAction(cmd); cmd = am->registerAction(actions.jumpToLineAction, Constants::JUMP_TO_LINE, debuggercontext); mdebug->addAction(cmd); #ifdef USE_REVERSE_DEBUGGING cmd = am->registerAction(actions.reverseDirectionAction, Constants::REVERSE, debuggercontext); cmd->setDefaultKeySequence(QKeySequence(Constants::REVERSE_KEY)); mdebug->addAction(cmd); #endif sep = new QAction(this); sep->setSeparator(true); cmd = am->registerAction(sep, QLatin1String("Debugger.Sep.Break"), globalcontext); mdebug->addAction(cmd); cmd = am->registerAction(theDebuggerAction(OperateByInstruction), Constants::OPERATE_BY_INSTRUCTION, debuggercontext); mdebug->addAction(cmd); cmd = am->registerAction(actions.breakAction, Constants::TOGGLE_BREAK, cppeditorcontext); cmd->setDefaultKeySequence(QKeySequence(Constants::TOGGLE_BREAK_KEY)); mdebug->addAction(cmd); //mcppcontext->addAction(cmd); sep = new QAction(this); sep->setSeparator(true); cmd = am->registerAction(sep, QLatin1String("Debugger.Sep.Watch"), globalcontext); mdebug->addAction(cmd); cmd = am->registerAction(actions.watchAction1, Constants::ADD_TO_WATCH1, cppeditorcontext); cmd->action()->setEnabled(true); //cmd->setDefaultKeySequence(QKeySequence(tr("ALT+D,ALT+W"))); mdebug->addAction(cmd); ActionContainer *editorContextMenu = am->actionContainer(CppEditor::Constants::M_CONTEXT); cmd = am->registerAction(sep, QLatin1String("Debugger.Sep.Views"), debuggercontext); editorContextMenu->addAction(cmd); cmd->setAttribute(Command::CA_Hide); cmd = am->registerAction(actions.watchAction2, Constants::ADD_TO_WATCH2, debuggercontext); cmd->action()->setEnabled(true); //cmd->setDefaultKeySequence(QKeySequence(tr("ALT+D,ALT+W"))); editorContextMenu->addAction(cmd); cmd->setAttribute(Command::CA_Hide); // Views menu cmd = am->registerAction(sep, QLatin1String("Debugger.Sep.Views"), globalcontext); mdebug->addAction(cmd); ActionContainer *viewsMenu = am->createMenu(Constants::M_DEBUG_VIEWS); QMenu *m = viewsMenu->menu(); m->setEnabled(true); m->setTitle(tr("&Views")); mdebug->addMenu(viewsMenu, Core::Constants::G_DEFAULT_THREE); m_toggleLockedAction = new QAction(tr("Locked"), this); m_toggleLockedAction->setCheckable(true); m_toggleLockedAction->setChecked(true); connect(m_toggleLockedAction, SIGNAL(toggled(bool)), m_manager->mainWindow(), SLOT(setLocked(bool))); foreach (QDockWidget *dockWidget, m_manager->mainWindow()->dockWidgets()) { cmd = am->registerAction(dockWidget->toggleViewAction(), "Debugger." + dockWidget->objectName(), debuggercontext); viewsMenu->addAction(cmd); //m->addAction(dockWidget->toggleViewAction()); } m->addSeparator(); m->addAction(m_toggleLockedAction); m->addSeparator(); QAction *resetToSimpleAction = viewsMenu->menu()->addAction(tr("Reset to default layout")); connect(resetToSimpleAction, SIGNAL(triggered()), m_manager, SLOT(setSimpleDockWidgetArrangement())); // FIXME: addAutoReleasedObject(new CommonOptionsPage); addAutoReleasedObject(new DebuggingHelperOptionPage); foreach (Core::IOptionsPage* op, engineOptionPages) addAutoReleasedObject(op); addAutoReleasedObject(new DebuggerListener); m_locationMark = 0; // // Debug mode setup // m_debugMode = new DebugMode(this); //addAutoReleasedObject(m_debugMode); // register factory of DebuggerRunControl m_debuggerRunControlFactory = new DebuggerRunControlFactory(m_manager); addAutoReleasedObject(m_debuggerRunControlFactory); QList context; context.append(uidm->uniqueIdentifier(Core::Constants::C_EDITORMANAGER)); context.append(uidm->uniqueIdentifier(Debugger::Constants::C_GDBDEBUGGER)); context.append(uidm->uniqueIdentifier(Core::Constants::C_NAVIGATION_PANE)); m_debugMode->setContext(context); QBoxLayout *editorHolderLayout = new QVBoxLayout; editorHolderLayout->setMargin(0); editorHolderLayout->setSpacing(0); QWidget *editorAndFindWidget = new QWidget; editorAndFindWidget->setLayout(editorHolderLayout); editorHolderLayout->addWidget(new EditorManagerPlaceHolder(m_debugMode)); editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); MiniSplitter *rightPaneSplitter = new MiniSplitter; rightPaneSplitter->addWidget(editorAndFindWidget); rightPaneSplitter->addWidget(new RightPanePlaceHolder(m_debugMode)); rightPaneSplitter->setStretchFactor(0, 1); rightPaneSplitter->setStretchFactor(1, 0); QWidget *centralWidget = new QWidget; m_manager->mainWindow()->setCentralWidget(centralWidget); MiniSplitter *splitter = new MiniSplitter; splitter->addWidget(m_manager->mainWindow()); splitter->addWidget(new OutputPanePlaceHolder(m_debugMode, splitter)); splitter->setStretchFactor(0, 10); splitter->setStretchFactor(1, 0); splitter->setOrientation(Qt::Vertical); MiniSplitter *splitter2 = new MiniSplitter; splitter2->addWidget(new NavigationWidgetPlaceHolder(m_debugMode)); splitter2->addWidget(splitter); splitter2->setStretchFactor(0, 0); splitter2->setStretchFactor(1, 1); m_debugMode->setWidget(splitter2); Utils::StyledBar *debugToolBar = new Utils::StyledBar; debugToolBar->setProperty("topBorder", true); QHBoxLayout *debugToolBarLayout = new QHBoxLayout(debugToolBar); debugToolBarLayout->setMargin(0); debugToolBarLayout->setSpacing(0); debugToolBarLayout->addWidget(toolButton(am->command(ProjectExplorer::Constants::DEBUG)->action())); debugToolBarLayout->addWidget(toolButton(am->command(Constants::INTERRUPT)->action())); debugToolBarLayout->addWidget(toolButton(am->command(Constants::NEXT)->action())); debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEP)->action())); debugToolBarLayout->addWidget(toolButton(am->command(Constants::STEPOUT)->action())); debugToolBarLayout->addWidget(toolButton(am->command(Constants::OPERATE_BY_INSTRUCTION)->action())); #ifdef USE_REVERSE_DEBUGGING debugToolBarLayout->addWidget(new Utils::StyledSeparator); debugToolBarLayout->addWidget(toolButton(am->command(Constants::REVERSE)->action())); #endif debugToolBarLayout->addWidget(new Utils::StyledSeparator); debugToolBarLayout->addWidget(new QLabel(tr("Threads:"))); QComboBox *threadBox = new QComboBox; threadBox->setModel(m_manager->threadsModel()); connect(threadBox, SIGNAL(activated(int)), m_manager->threadsWindow(), SIGNAL(threadSelected(int))); debugToolBarLayout->addWidget(threadBox); debugToolBarLayout->addWidget(m_manager->statusLabel(), 10); QBoxLayout *toolBarAddingLayout = new QVBoxLayout(centralWidget); toolBarAddingLayout->setMargin(0); toolBarAddingLayout->setSpacing(0); toolBarAddingLayout->addWidget(rightPaneSplitter); toolBarAddingLayout->addWidget(debugToolBar); m_manager->setSimpleDockWidgetArrangement(); readSettings(); connect(ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode*)), this, SLOT(onModeChanged(Core::IMode*))); m_debugMode->widget()->setFocusProxy(EditorManager::instance()); addObject(m_debugMode); // // Connections // // ProjectExplorer connect(sessionManager(), SIGNAL(sessionLoaded()), m_manager, SLOT(sessionLoaded())); connect(sessionManager(), SIGNAL(aboutToSaveSession()), m_manager, SLOT(aboutToSaveSession())); connect(sessionManager(), SIGNAL(aboutToUnloadSession()), m_manager, SLOT(aboutToUnloadSession())); // EditorManager QObject *editorManager = core->editorManager(); connect(editorManager, SIGNAL(editorAboutToClose(Core::IEditor*)), this, SLOT(editorAboutToClose(Core::IEditor*))); connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)), this, SLOT(editorOpened(Core::IEditor*))); // Application interaction connect(m_manager, SIGNAL(currentTextEditorRequested(QString*,int*,QObject**)), this, SLOT(queryCurrentTextEditor(QString*,int*,QObject**))); connect(m_manager, SIGNAL(setSessionValueRequested(QString,QVariant)), this, SLOT(setSessionValue(QString,QVariant))); connect(m_manager, SIGNAL(sessionValueRequested(QString,QVariant*)), this, SLOT(querySessionValue(QString,QVariant*))); connect(m_manager, SIGNAL(resetLocationRequested()), this, SLOT(resetLocation())); connect(m_manager, SIGNAL(gotoLocationRequested(QString,int,bool)), this, SLOT(gotoLocation(QString,int,bool))); connect(m_manager, SIGNAL(stateChanged(int)), this, SLOT(handleStateChanged(int))); connect(m_manager, SIGNAL(previousModeRequested()), this, SLOT(activatePreviousMode())); connect(m_manager, SIGNAL(debugModeRequested()), this, SLOT(activateDebugMode())); connect(theDebuggerAction(SettingsDialog), SIGNAL(triggered()), this, SLOT(showSettingsDialog())); handleStateChanged(DebuggerNotReady); return true; } void DebuggerPlugin::extensionsInitialized() { // time gdb -i mi -ex 'debuggerplugin.cpp:800' -ex r -ex q bin/qtcreator.bin const QByteArray env = qgetenv("QTC_DEBUGGER_TEST"); //qDebug() << "EXTENSIONS INITIALIZED:" << env; if (!env.isEmpty()) m_manager->runTest(QString::fromLocal8Bit(env)); if (m_attachRemoteParameters.attachPid || !m_attachRemoteParameters.attachCore.isEmpty()) QTimer::singleShot(0, this, SLOT(attachCmdLine())); } void DebuggerPlugin::attachCmdLine() { if (m_manager->state() != DebuggerNotReady) return; if (m_attachRemoteParameters.attachPid) { m_manager->showStatusMessage(tr("Attaching to PID %1.").arg(m_attachRemoteParameters.attachPid)); const QString crashParameter = m_attachRemoteParameters.winCrashEvent ? QString::number(m_attachRemoteParameters.winCrashEvent) : QString(); attachExternalApplication(m_attachRemoteParameters.attachPid, crashParameter); return; } if (!m_attachRemoteParameters.attachCore.isEmpty()) { m_manager->showStatusMessage(tr("Attaching to core %1.").arg(m_attachRemoteParameters.attachCore)); attachCore(m_attachRemoteParameters.attachCore, QString()); } } /*! Activates the previous mode when the current mode is the debug mode. */ void DebuggerPlugin::activatePreviousMode() { Core::ModeManager *const modeManager = ICore::instance()->modeManager(); if (modeManager->currentMode() == modeManager->mode(Constants::MODE_DEBUG) && !m_previousMode.isEmpty()) { modeManager->activateMode(m_previousMode); m_previousMode.clear(); } } void DebuggerPlugin::activateDebugMode() { ModeManager *modeManager = ModeManager::instance(); m_previousMode = modeManager->currentMode()->id(); modeManager->activateMode(QLatin1String(MODE_DEBUG)); } void DebuggerPlugin::queryCurrentTextEditor(QString *fileName, int *lineNumber, QObject **object) { EditorManager *editorManager = EditorManager::instance(); if (!editorManager) return; Core::IEditor *editor = editorManager->currentEditor(); ITextEditor *textEditor = qobject_cast(editor); if (!textEditor) return; if (fileName) *fileName = textEditor->file()->fileName(); if (lineNumber) *lineNumber = textEditor->currentLine(); if (object) *object = textEditor->widget(); } void DebuggerPlugin::editorOpened(Core::IEditor *editor) { if (ITextEditor *textEditor = qobject_cast(editor)) { connect(textEditor, SIGNAL(markRequested(TextEditor::ITextEditor*,int)), this, SLOT(requestMark(TextEditor::ITextEditor*,int))); connect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*,QPoint,int)), this, SLOT(showToolTip(TextEditor::ITextEditor*,QPoint,int))); connect(textEditor, SIGNAL(markContextMenuRequested(TextEditor::ITextEditor*,int,QMenu*)), this, SLOT(requestContextMenu(TextEditor::ITextEditor*,int,QMenu*))); } } void DebuggerPlugin::editorAboutToClose(Core::IEditor *editor) { if (ITextEditor *textEditor = qobject_cast(editor)) { disconnect(textEditor, SIGNAL(markRequested(TextEditor::ITextEditor*,int)), this, SLOT(requestMark(TextEditor::ITextEditor*,int))); disconnect(editor, SIGNAL(tooltipRequested(TextEditor::ITextEditor*,QPoint,int)), this, SLOT(showToolTip(TextEditor::ITextEditor*,QPoint,int))); disconnect(textEditor, SIGNAL(markContextMenuRequested(TextEditor::ITextEditor*,int,QMenu*)), this, SLOT(requestContextMenu(TextEditor::ITextEditor*,int,QMenu*))); } } void DebuggerPlugin::requestContextMenu(TextEditor::ITextEditor *editor, int lineNumber, QMenu *menu) { QString fileName = editor->file()->fileName(); QString position = fileName + QString(":%1").arg(lineNumber); BreakpointData *data = m_manager->findBreakpoint(fileName, lineNumber); if (data) { // existing breakpoint QAction *act = new QAction(tr("Remove Breakpoint"), menu); act->setData(position); connect(act, SIGNAL(triggered()), this, SLOT(breakpointSetRemoveMarginActionTriggered())); menu->addAction(act); QAction *act2; if (data->enabled) act2 = new QAction(tr("Disable Breakpoint"), menu); else act2 = new QAction(tr("Enable Breakpoint"), menu); act2->setData(position); connect(act2, SIGNAL(triggered()), this, SLOT(breakpointEnableDisableMarginActionTriggered())); menu->addAction(act2); } else { // non-existing QAction *act = new QAction(tr("Set Breakpoint"), menu); act->setData(position); connect(act, SIGNAL(triggered()), this, SLOT(breakpointSetRemoveMarginActionTriggered())); menu->addAction(act); } } void DebuggerPlugin::breakpointSetRemoveMarginActionTriggered() { if (QAction *act = qobject_cast(sender())) { QString str = act->data().toString(); int pos = str.lastIndexOf(':'); m_manager->toggleBreakpoint(str.left(pos), str.mid(pos + 1).toInt()); } } void DebuggerPlugin::breakpointEnableDisableMarginActionTriggered() { if (QAction *act = qobject_cast(sender())) { QString str = act->data().toString(); int pos = str.lastIndexOf(':'); m_manager->toggleBreakpointEnabled(str.left(pos), str.mid(pos + 1).toInt()); } } void DebuggerPlugin::requestMark(TextEditor::ITextEditor *editor, int lineNumber) { m_manager->toggleBreakpoint(editor->file()->fileName(), lineNumber); } void DebuggerPlugin::showToolTip(TextEditor::ITextEditor *editor, const QPoint &point, int pos) { if (!theDebuggerBoolSetting(UseToolTipsInMainEditor) || m_manager->state() == DebuggerNotReady) return; m_manager->setToolTipExpression(point, editor, pos); } void DebuggerPlugin::setSessionValue(const QString &name, const QVariant &value) { //qDebug() << "SET SESSION VALUE" << name << value; QTC_ASSERT(sessionManager(), return); sessionManager()->setValue(name, value); } void DebuggerPlugin::querySessionValue(const QString &name, QVariant *value) { QTC_ASSERT(sessionManager(), return); *value = sessionManager()->value(name); //qDebug() << "GET SESSION VALUE: " << name << value; } void DebuggerPlugin::setConfigValue(const QString &name, const QVariant &value) { QTC_ASSERT(m_debugMode, return); settings()->setValue(name, value); } QVariant DebuggerPlugin::configValue(const QString &name) const { QTC_ASSERT(m_debugMode, return QVariant()); return settings()->value(name); } void DebuggerPlugin::queryConfigValue(const QString &name, QVariant *value) { QTC_ASSERT(m_debugMode, return); *value = settings()->value(name); } void DebuggerPlugin::resetLocation() { //qDebug() << "RESET_LOCATION: current:" << currentTextEditor(); //qDebug() << "RESET_LOCATION: locations:" << m_locationMark; //qDebug() << "RESET_LOCATION: stored:" << m_locationMark->editor(); delete m_locationMark; m_locationMark = 0; } void DebuggerPlugin::gotoLocation(const QString &file, int line, bool setMarker) { TextEditor::BaseTextEditor::openEditorAt(file, line); if (setMarker) { resetLocation(); m_locationMark = new LocationMark(file, line); } } void DebuggerPlugin::handleStateChanged(int state) { const bool startIsContinue = (state == InferiorStopped); ICore *core = ICore::instance(); if (startIsContinue) { core->addAdditionalContext(m_gdbRunningContext); core->updateContext(); } else { core->removeAdditionalContext(m_gdbRunningContext); core->updateContext(); } const bool started = state == InferiorRunning || state == InferiorRunningRequested || state == InferiorStopping || state == InferiorStopped; const bool starting = state == EngineStarting; //const bool running = state == InferiorRunning; const bool detachable = state == InferiorStopped && m_manager->startParameters()->startMode != AttachCore; m_startExternalAction->setEnabled(!started && !starting); m_attachExternalAction->setEnabled(!started && !starting); #ifdef Q_OS_WIN m_attachCoreAction->setEnabled(false); #else m_attachCoreAction->setEnabled(!started && !starting); #endif m_startRemoteAction->setEnabled(!started && !starting); m_detachAction->setEnabled(detachable); } void DebuggerPlugin::writeSettings() const { QTC_ASSERT(m_manager, return); QTC_ASSERT(m_manager->mainWindow(), return); QSettings *s = settings(); DebuggerSettings::instance()->writeSettings(s); s->beginGroup(QLatin1String("DebugMode")); m_manager->mainWindow()->saveSettings(s); s->endGroup(); } void DebuggerPlugin::readSettings() { QSettings *s = settings(); DebuggerSettings::instance()->readSettings(s); QString defaultCommand("gdb"); #ifdef Q_OS_WIN defaultCommand.append(".exe"); #endif //QString defaultScript = ICore::instance()->resourcePath() + // QLatin1String("/gdb/qt4macros"); QString defaultScript; s->beginGroup(QLatin1String("DebugMode")); m_manager->mainWindow()->restoreSettings(s); m_toggleLockedAction->setChecked(m_manager->mainWindow()->isLocked()); s->endGroup(); } void DebuggerPlugin::onModeChanged(IMode *mode) { // FIXME: This one gets always called, even if switching between modes // different then the debugger mode. E.g. Welcome and Help mode and // also on shutdown. if (mode != m_debugMode) return; EditorManager *editorManager = EditorManager::instance(); if (editorManager->currentEditor()) editorManager->currentEditor()->widget()->setFocus(); } void DebuggerPlugin::showSettingsDialog() { Core::ICore::instance()->showOptionsDialog( QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), QLatin1String(Debugger::Constants::DEBUGGER_COMMON_SETTINGS_ID)); } void DebuggerPlugin::startExternalApplication() { const DebuggerStartParametersPtr sp(new DebuggerStartParameters); StartExternalDialog dlg(m_manager->mainWindow()); dlg.setExecutableFile( configValue(_("LastExternalExecutableFile")).toString()); dlg.setExecutableArguments( configValue(_("LastExternalExecutableArguments")).toString()); if (dlg.exec() != QDialog::Accepted) return; setConfigValue(_("LastExternalExecutableFile"), dlg.executableFile()); setConfigValue(_("LastExternalExecutableArguments"), dlg.executableArguments()); sp->executable = dlg.executableFile(); sp->startMode = StartExternal; if (!dlg.executableArguments().isEmpty()) sp->processArgs = dlg.executableArguments().split(QLatin1Char(' ')); if (dlg.breakAtMain()) m_manager->breakByFunctionMain(); if (RunControl *runControl = m_debuggerRunControlFactory->create(sp)) ProjectExplorerPlugin::instance()->startRunControl(runControl, ProjectExplorer::Constants::DEBUGMODE); } void DebuggerPlugin::attachExternalApplication() { AttachExternalDialog dlg(m_manager->mainWindow()); if (dlg.exec() == QDialog::Accepted) attachExternalApplication(dlg.attachPID()); } void DebuggerPlugin::attachExternalApplication(qint64 pid, const QString &crashParameter) { if (pid == 0) { QMessageBox::warning(m_manager->mainWindow(), tr("Warning"), tr("Cannot attach to PID 0")); return; } const DebuggerStartParametersPtr sp(new DebuggerStartParameters); sp->attachPID = pid; sp->crashParameter = crashParameter; sp->startMode = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal; if (RunControl *runControl = m_debuggerRunControlFactory->create(sp)) ProjectExplorerPlugin::instance()->startRunControl(runControl, ProjectExplorer::Constants::DEBUGMODE); } void DebuggerPlugin::attachCore() { AttachCoreDialog dlg(m_manager->mainWindow()); dlg.setExecutableFile( configValue(_("LastExternalExecutableFile")).toString()); dlg.setCoreFile( configValue(_("LastExternalCoreFile")).toString()); if (dlg.exec() != QDialog::Accepted) return; setConfigValue(_("LastExternalExecutableFile"), dlg.executableFile()); setConfigValue(_("LastExternalCoreFile"), dlg.coreFile()); attachCore(dlg.coreFile(), dlg.executableFile()); } void DebuggerPlugin::attachCore(const QString &core, const QString &exe) { const DebuggerStartParametersPtr sp(new DebuggerStartParameters); sp->executable = exe; sp->coreFile = core; sp->startMode = AttachCore; if (RunControl *runControl = m_debuggerRunControlFactory->create(sp)) ProjectExplorerPlugin::instance()-> startRunControl(runControl, ProjectExplorer::Constants::DEBUGMODE); } void DebuggerPlugin::startRemoteApplication() { const DebuggerStartParametersPtr sp(new DebuggerStartParameters); StartRemoteDialog dlg(m_manager->mainWindow()); QStringList arches; arches.append(_("i386:x86-64:intel")); arches.append(_("i386")); QString lastUsed = configValue(_("LastRemoteArchitecture")).toString(); if (!arches.contains(lastUsed)) arches.prepend(lastUsed); dlg.setRemoteArchitectures(arches); dlg.setRemoteChannel( configValue(_("LastRemoteChannel")).toString()); dlg.setLocalExecutable( configValue(_("LastLocalExecutable")).toString()); dlg.setDebugger(configValue(_("LastDebugger")).toString()); dlg.setRemoteArchitecture(lastUsed); dlg.setServerStartScript( configValue(_("LastServerStartScript")).toString()); dlg.setUseServerStartScript( configValue(_("LastUseServerStartScript")).toBool()); dlg.setSysRoot(configValue(_("LastSysroot")).toString()); if (dlg.exec() != QDialog::Accepted) return; setConfigValue(_("LastRemoteChannel"), dlg.remoteChannel()); setConfigValue(_("LastLocalExecutable"), dlg.localExecutable()); setConfigValue(_("LastDebugger"), dlg.debugger()); setConfigValue(_("LastRemoteArchitecture"), dlg.remoteArchitecture()); setConfigValue(_("LastServerStartScript"), dlg.serverStartScript()); setConfigValue(_("LastUseServerStartScript"), dlg.useServerStartScript()); setConfigValue(_("LastSysroot"), dlg.sysRoot()); sp->remoteChannel = dlg.remoteChannel(); sp->remoteArchitecture = dlg.remoteArchitecture(); sp->executable = dlg.localExecutable(); sp->debuggerCommand = dlg.debugger(); sp->startMode = StartRemote; if (dlg.useServerStartScript()) sp->serverStartScript = dlg.serverStartScript(); sp->sysRoot = dlg.sysRoot(); if (RunControl *runControl = m_debuggerRunControlFactory->create(sp)) ProjectExplorerPlugin::instance() ->startRunControl(runControl, ProjectExplorer::Constants::DEBUGMODE); } #include "debuggerplugin.moc" Q_EXPORT_PLUGIN(DebuggerPlugin)