summaryrefslogtreecommitdiff
path: root/src/plugins/debugger/debuggermanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/debugger/debuggermanager.cpp')
-rw-r--r--src/plugins/debugger/debuggermanager.cpp1298
1 files changed, 1298 insertions, 0 deletions
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
new file mode 100644
index 0000000000..bcf314ae41
--- /dev/null
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -0,0 +1,1298 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+
+#include "debuggermanager.h"
+
+#include "assert.h"
+#include "debuggerconstants.h"
+#include "idebuggerengine.h"
+
+#include "breakwindow.h"
+#include "disassemblerwindow.h"
+#include "debuggeroutputwindow.h"
+#include "moduleswindow.h"
+#include "registerwindow.h"
+#include "stackwindow.h"
+#include "threadswindow.h"
+#include "watchwindow.h"
+
+#include "ui_breakbyfunction.h"
+
+#include "disassemblerhandler.h"
+#include "breakhandler.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+
+#include "startexternaldialog.h"
+#include "attachexternaldialog.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTime>
+
+#include <QtGui/QAction>
+#include <QtGui/QComboBox>
+#include <QtGui/QDockWidget>
+#include <QtGui/QErrorMessage>
+#include <QtGui/QFileDialog>
+#include <QtGui/QLabel>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QStatusBar>
+#include <QtGui/QTextBlock>
+#include <QtGui/QTextCursor>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolButton>
+#include <QtGui/QToolTip>
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+using namespace Debugger::Constants;
+
+static const QString tooltipIName = "tooltip";
+
+///////////////////////////////////////////////////////////////////////
+//
+// BreakByFunctionDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+class BreakByFunctionDialog : public QDialog, Ui::BreakByFunctionDialog
+{
+ Q_OBJECT
+
+public:
+ explicit BreakByFunctionDialog(QWidget *parent)
+ : QDialog(parent)
+ {
+ setupUi(this);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ }
+ QString functionName() const { return functionLineEdit->text(); }
+};
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// DebuggerManager
+//
+///////////////////////////////////////////////////////////////////////
+
+static IDebuggerEngine *gdbEngine = 0;
+static IDebuggerEngine *winEngine = 0;
+static IDebuggerEngine *scriptEngine = 0;
+
+extern IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
+extern IDebuggerEngine *createWinEngine(DebuggerManager *) { return 0; }
+extern IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
+
+DebuggerManager::DebuggerManager()
+{
+ init();
+}
+
+DebuggerManager::~DebuggerManager()
+{
+ delete gdbEngine;
+ delete winEngine;
+ delete scriptEngine;
+}
+
+void DebuggerManager::init()
+{
+ m_status = -1;
+ m_busy = false;
+
+ m_attachedPID = 0;
+ m_startMode = startInternal;
+
+ m_disassemblerHandler = 0;
+ m_modulesHandler = 0;
+ m_registerHandler = 0;
+
+ m_breakWindow = new BreakWindow;
+ m_disassemblerWindow = new DisassemblerWindow;
+ m_modulesWindow = new ModulesWindow;
+ m_outputWindow = new DebuggerOutputWindow;
+ m_registerWindow = new RegisterWindow;
+ m_stackWindow = new StackWindow;
+ m_threadsWindow = new ThreadsWindow;
+ m_localsWindow = new WatchWindow(WatchWindow::LocalsType);
+ m_watchersWindow = new WatchWindow(WatchWindow::WatchersType);
+ //m_tooltipWindow = new WatchWindow(WatchWindow::TooltipType);
+ //m_watchersWindow = new QTreeView;
+ m_tooltipWindow = new QTreeView;
+
+ m_mainWindow = new QMainWindow;
+ m_mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
+ m_mainWindow->setDocumentMode(true);
+
+ // Stack
+ m_stackHandler = new StackHandler;
+ QAbstractItemView *stackView =
+ qobject_cast<QAbstractItemView *>(m_stackWindow);
+ stackView->setModel(m_stackHandler->stackModel());
+ connect(stackView, SIGNAL(frameActivated(int)),
+ this, SLOT(activateFrame(int)));
+
+ // Threads
+ m_threadsHandler = new ThreadsHandler;
+ QAbstractItemView *threadsView =
+ qobject_cast<QAbstractItemView *>(m_threadsWindow);
+ threadsView->setModel(m_threadsHandler->threadsModel());
+ connect(threadsView, SIGNAL(threadSelected(int)),
+ this, SLOT(selectThread(int)));
+
+ // Disassembler
+ m_disassemblerHandler = new DisassemblerHandler;
+ QAbstractItemView *disassemblerView =
+ qobject_cast<QAbstractItemView *>(m_disassemblerWindow);
+ disassemblerView->setModel(m_disassemblerHandler->model());
+
+ // Breakpoints
+ m_breakHandler = new BreakHandler;
+ QAbstractItemView *breakView =
+ qobject_cast<QAbstractItemView *>(m_breakWindow);
+ breakView->setModel(m_breakHandler->model());
+ connect(breakView, SIGNAL(breakPointActivated(int)),
+ m_breakHandler, SLOT(activateBreakPoint(int)));
+ connect(breakView, SIGNAL(breakPointDeleted(int)),
+ m_breakHandler, SLOT(removeBreakpoint(int)));
+ connect(m_breakHandler, SIGNAL(gotoLocation(QString,int,bool)),
+ this, SLOT(gotoLocation(QString,int,bool)));
+ connect(m_breakHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
+ this, SIGNAL(sessionValueRequested(QString,QVariant*)));
+ connect(m_breakHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
+ this, SIGNAL(setSessionValueRequested(QString,QVariant)));
+
+ // Modules
+ QAbstractItemView *modulesView =
+ qobject_cast<QAbstractItemView *>(m_modulesWindow);
+ m_modulesHandler = new ModulesHandler;
+ modulesView->setModel(m_modulesHandler->model());
+ connect(modulesView, SIGNAL(reloadModulesRequested()),
+ this, SLOT(reloadModules()));
+ connect(modulesView, SIGNAL(loadSymbolsRequested(QString)),
+ this, SLOT(loadSymbols(QString)));
+ connect(modulesView, SIGNAL(loadAllSymbolsRequested()),
+ this, SLOT(loadAllSymbols()));
+
+
+ // Registers
+ QAbstractItemView *registerView =
+ qobject_cast<QAbstractItemView *>(m_registerWindow);
+ m_registerHandler = new RegisterHandler;
+ registerView->setModel(m_registerHandler->model());
+
+
+ m_watchHandler = new WatchHandler;
+
+ // Locals
+ QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow);
+ localsView->setModel(m_watchHandler->model());
+ connect(localsView, SIGNAL(requestExpandChildren(QModelIndex)),
+ this, SLOT(expandChildren(QModelIndex)));
+ connect(localsView, SIGNAL(requestCollapseChildren(QModelIndex)),
+ this, SLOT(collapseChildren(QModelIndex)));
+ connect(localsView, SIGNAL(requestAssignValue(QString,QString)),
+ this, SLOT(assignValueInDebugger(QString,QString)));
+ connect(localsView, SIGNAL(requestWatchExpression(QString)),
+ this, SLOT(watchExpression(QString)));
+
+ // Watchers
+ QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow);
+ watchersView->setModel(m_watchHandler->model());
+ connect(watchersView, SIGNAL(requestAssignValue(QString,QString)),
+ this, SLOT(assignValueInDebugger(QString,QString)));
+ connect(watchersView, SIGNAL(requestExpandChildren(QModelIndex)),
+ this, SLOT(expandChildren(QModelIndex)));
+ connect(watchersView, SIGNAL(requestCollapseChildren(QModelIndex)),
+ this, SLOT(collapseChildren(QModelIndex)));
+ connect(watchersView, SIGNAL(requestWatchExpression(QString)),
+ this, SLOT(watchExpression(QString)));
+ connect(watchersView, SIGNAL(requestRemoveWatchExpression(QString)),
+ this, SLOT(removeWatchExpression(QString)));
+
+ // Tooltip
+ QTreeView *tooltipView = qobject_cast<QTreeView *>(m_tooltipWindow);
+ tooltipView->setModel(m_watchHandler->model());
+
+ connect(m_watchHandler, SIGNAL(watchModelUpdateRequested()),
+ this, SLOT(updateWatchModel()));
+
+ m_startExternalAction = new QAction(this);
+ m_startExternalAction->setText(tr("Start and Debug External Application..."));
+
+ m_attachExternalAction = new QAction(this);
+ m_attachExternalAction->setText(tr("Attach to Running External Application..."));
+
+ m_continueAction = new QAction(this);
+ m_continueAction->setText(tr("Continue"));
+ m_continueAction->setIcon(QIcon(":/gdbdebugger/images/debugger_continue_small.png"));
+
+ m_stopAction = new QAction(this);
+ m_stopAction->setText(tr("Interrupt"));
+ m_stopAction->setIcon(QIcon(":/gdbdebugger/images/debugger_interrupt_small.png"));
+
+ m_resetAction = new QAction(this);
+ m_resetAction->setText(tr("Reset Debugger"));
+
+ m_nextAction = new QAction(this);
+ m_nextAction->setText(tr("Step Over"));
+ //m_nextAction->setShortcut(QKeySequence(tr("F6")));
+ m_nextAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepover_small.png"));
+
+ m_stepAction = new QAction(this);
+ m_stepAction->setText(tr("Step Into"));
+ //m_stepAction->setShortcut(QKeySequence(tr("F7")));
+ m_stepAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepinto_small.png"));
+
+ m_nextIAction = new QAction(this);
+ m_nextIAction->setText(tr("Step Over Instruction"));
+ //m_nextIAction->setShortcut(QKeySequence(tr("Shift+F6")));
+ m_nextIAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepoverproc_small.png"));
+
+ m_stepIAction = new QAction(this);
+ m_stepIAction->setText(tr("Step One Instruction"));
+ //m_stepIAction->setShortcut(QKeySequence(tr("Shift+F9")));
+ m_stepIAction->setIcon(QIcon(":/gdbdebugger/images/debugger_steponeproc_small.png"));
+
+ m_stepOutAction = new QAction(this);
+ m_stepOutAction->setText(tr("Step Out"));
+ //m_stepOutAction->setShortcut(QKeySequence(tr("Shift+F7")));
+ m_stepOutAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stepout_small.png"));
+
+ m_runToLineAction = new QAction(this);
+ m_runToLineAction->setText(tr("Run to Line"));
+
+ m_runToFunctionAction = new QAction(this);
+ m_runToFunctionAction->setText(tr("Run to Outermost Function"));
+
+ m_jumpToLineAction = new QAction(this);
+ m_jumpToLineAction->setText(tr("Jump to Line"));
+
+ m_breakAction = new QAction(this);
+ m_breakAction->setText(tr("Toggle Breakpoint"));
+
+ m_breakByFunctionAction = new QAction(this);
+ m_breakByFunctionAction->setText(tr("Set Breakpoint at Function..."));
+
+ m_breakAtMainAction = new QAction(this);
+ m_breakAtMainAction->setText(tr("Set Breakpoint at Function 'main'"));
+
+ m_debugDumpersAction = new QAction(this);
+ m_debugDumpersAction->setText(tr("Debug Custom Dumpers"));
+ m_debugDumpersAction->setCheckable(true);
+
+ m_skipKnownFramesAction = new QAction(this);
+ m_skipKnownFramesAction->setText(tr("Skip Known Frames When Stepping"));
+ m_skipKnownFramesAction->setCheckable(true);
+
+ m_useCustomDumpersAction = new QAction(this);
+ m_useCustomDumpersAction->setText(tr("Use Custom Display for Qt Objects"));
+ m_useCustomDumpersAction->setToolTip(tr("Checking this will make the debugger "
+ "try to use code to format certain data (QObject, QString, ...) nicely. "));
+ m_useCustomDumpersAction->setCheckable(true);
+ m_useCustomDumpersAction->setChecked(true);
+
+ m_useCustomDumpersAction = new QAction(this);
+ m_useCustomDumpersAction->setText(tr("Use Custom Display for Qt Objects"));
+ m_useCustomDumpersAction->setToolTip(tr("Checking this will make the debugger "
+ "try to use code to format certain data (QObject, QString, ...) nicely. "));
+ m_useCustomDumpersAction->setCheckable(true);
+ m_useCustomDumpersAction->setChecked(true);
+
+ m_useFastStartAction = new QAction(this);
+ m_useFastStartAction->setText(tr("Fast Debugger Start"));
+ m_useFastStartAction->setToolTip(tr("Checking this will make the debugger "
+ "start fast by loading only very few debug symbols on start up. This "
+ "might lead to situations where breakpoints can not be set properly. "
+ "So uncheck this option if you experience breakpoint related problems."));
+ m_useFastStartAction->setCheckable(true);
+ m_useFastStartAction->setChecked(true);
+
+ // FIXME
+ m_useFastStartAction->setChecked(false);
+ m_useFastStartAction->setEnabled(false);
+
+ m_dumpLogAction = new QAction(this);
+ m_dumpLogAction->setText(tr("Dump Log File for Debugging Purposes"));
+
+ m_watchAction = new QAction(this);
+ m_watchAction->setText(tr("Add to Watch Window"));
+
+ // For usuage hints oin focus{In,Out}
+ //connect(m_outputWindow, SIGNAL(statusMessageRequested(QString,int)),
+ // this, SLOT(showStatusMessage(QString,int)));
+
+ connect(m_continueAction, SIGNAL(triggered()),
+ this, SLOT(continueExec()));
+
+ connect(m_startExternalAction, SIGNAL(triggered()),
+ this, SLOT(startExternalApplication()));
+ connect(m_attachExternalAction, SIGNAL(triggered()),
+ this, SLOT(attachExternalApplication()));
+
+ connect(m_stopAction, SIGNAL(triggered()),
+ this, SLOT(interruptDebuggingRequest()));
+ connect(m_resetAction, SIGNAL(triggered()),
+ this, SLOT(exitDebugger()));
+ connect(m_nextAction, SIGNAL(triggered()),
+ this, SLOT(nextExec()));
+ connect(m_stepAction, SIGNAL(triggered()),
+ this, SLOT(stepExec()));
+ connect(m_nextIAction, SIGNAL(triggered()),
+ this, SLOT(nextIExec()));
+ connect(m_stepIAction, SIGNAL(triggered()),
+ this, SLOT(stepIExec()));
+ connect(m_stepOutAction, SIGNAL(triggered()),
+ this, SLOT(stepOutExec()));
+ connect(m_runToLineAction, SIGNAL(triggered()),
+ this, SLOT(runToLineExec()));
+ connect(m_runToFunctionAction, SIGNAL(triggered()),
+ this, SLOT(runToFunctionExec()));
+ connect(m_jumpToLineAction, SIGNAL(triggered()),
+ this, SLOT(jumpToLineExec()));
+ connect(m_watchAction, SIGNAL(triggered()),
+ this, SLOT(addToWatchWindow()));
+ connect(m_breakAction, SIGNAL(triggered()),
+ this, SLOT(toggleBreakpoint()));
+ connect(m_breakByFunctionAction, SIGNAL(triggered()),
+ this, SLOT(breakByFunction()));
+ connect(m_breakAtMainAction, SIGNAL(triggered()),
+ this, SLOT(breakAtMain()));
+
+ connect(m_useFastStartAction, SIGNAL(triggered()),
+ this, SLOT(saveSessionData()));
+ connect(m_useCustomDumpersAction, SIGNAL(triggered()),
+ this, SLOT(saveSessionData()));
+ connect(m_skipKnownFramesAction, SIGNAL(triggered()),
+ this, SLOT(saveSessionData()));
+ connect(m_dumpLogAction, SIGNAL(triggered()),
+ this, SLOT(dumpLog()));
+
+ connect(m_outputWindow, SIGNAL(commandExecutionRequested(QString)),
+ this, SLOT(executeDebuggerCommand(QString)));
+
+
+ m_breakDock = createDockForWidget(m_breakWindow);
+
+ m_disassemblerDock = createDockForWidget(m_disassemblerWindow);
+ connect(m_disassemblerDock->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(reloadDisassembler()), Qt::QueuedConnection);
+
+ m_modulesDock = createDockForWidget(m_modulesWindow);
+ connect(m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(reloadModules()), Qt::QueuedConnection);
+
+ m_registerDock = createDockForWidget(m_registerWindow);
+ connect(m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(reloadRegisters()), Qt::QueuedConnection);
+
+ m_outputDock = createDockForWidget(m_outputWindow);
+
+ m_stackDock = createDockForWidget(m_stackWindow);
+
+ m_threadsDock = createDockForWidget(m_threadsWindow);
+
+ setStatus(DebuggerProcessNotReady);
+ gdbEngine = createGdbEngine(this);
+ winEngine = createWinEngine(this);
+ scriptEngine = createScriptEngine(this);
+ setDebuggerType(GdbDebugger);
+}
+
+void DebuggerManager::setDebuggerType(DebuggerType type)
+{
+ switch (type) {
+ case GdbDebugger:
+ m_engine = gdbEngine;
+ break;
+ case ScriptDebugger:
+ m_engine = scriptEngine;
+ break;
+ case WinDebugger:
+ m_engine = winEngine;
+ break;
+ }
+}
+
+IDebuggerEngine *DebuggerManager::engine()
+{
+ return m_engine;
+}
+
+IDebuggerManagerAccessForEngines *DebuggerManager::engineInterface()
+{
+ return dynamic_cast<IDebuggerManagerAccessForEngines *>(this);
+}
+
+IDebuggerManagerAccessForDebugMode *DebuggerManager::debugModeInterface()
+{
+ return dynamic_cast<IDebuggerManagerAccessForDebugMode *>(this);
+}
+
+void DebuggerManager::createDockWidgets()
+{
+ QSplitter *localsAndWatchers = new QSplitter(Qt::Vertical, 0);
+ localsAndWatchers->setWindowTitle(m_localsWindow->windowTitle());
+ localsAndWatchers->addWidget(m_localsWindow);
+ localsAndWatchers->addWidget(m_watchersWindow);
+ localsAndWatchers->setStretchFactor(0, 3);
+ localsAndWatchers->setStretchFactor(1, 1);
+ m_watchDock = createDockForWidget(localsAndWatchers);
+}
+
+QDockWidget *DebuggerManager::createDockForWidget(QWidget *widget)
+{
+ QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), m_mainWindow);
+ dockWidget->setObjectName(widget->windowTitle());
+ //dockWidget->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::RightDockWidgetArea);
+ dockWidget->setAllowedAreas(Qt::AllDockWidgetAreas); // that space is needed.
+ //dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures);
+ dockWidget->setFeatures(QDockWidget::AllDockWidgetFeatures);
+ dockWidget->setTitleBarWidget(new QWidget(dockWidget));
+ dockWidget->setWidget(widget);
+ connect(dockWidget->toggleViewAction(), SIGNAL(toggled(bool)),
+ this, SLOT(dockToggled(bool)), Qt::QueuedConnection);
+ m_dockWidgets.append(dockWidget);
+ return dockWidget;
+}
+
+void DebuggerManager::setSimpleDockWidgetArrangement()
+{
+ foreach (QDockWidget *dockWidget, m_dockWidgets)
+ m_mainWindow->removeDockWidget(dockWidget);
+
+ foreach (QDockWidget *dockWidget, m_dockWidgets) {
+ m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
+ dockWidget->show();
+ }
+
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_breakDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_disassemblerDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_modulesDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_outputDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_registerDock);
+ m_mainWindow->tabifyDockWidget(m_watchDock, m_threadsDock);
+
+ // They are rarely used even in ordinary debugging. Hiding them also saves
+ // cycles since the corresponding information won't be retrieved.
+ m_registerDock->hide();
+ m_disassemblerDock->hide();
+ m_modulesDock->hide();
+ m_outputDock->hide();
+}
+
+void DebuggerManager::setLocked(bool locked)
+{
+ const QDockWidget::DockWidgetFeatures features =
+ (locked) ? QDockWidget::NoDockWidgetFeatures :
+ QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable;
+
+ foreach (QDockWidget *dockWidget, m_dockWidgets) {
+ QWidget *titleBarWidget = dockWidget->titleBarWidget();
+ if (locked && !titleBarWidget)
+ titleBarWidget = new QWidget(dockWidget);
+ else if (!locked && titleBarWidget) {
+ delete titleBarWidget;
+ titleBarWidget = 0;
+ }
+ dockWidget->setTitleBarWidget(titleBarWidget);
+ dockWidget->setFeatures(features);
+ }
+}
+
+void DebuggerManager::dockToggled(bool on)
+{
+ QDockWidget *dw = qobject_cast<QDockWidget *>(sender()->parent());
+ if (on && dw)
+ dw->raise();
+}
+
+QAbstractItemModel *DebuggerManager::threadsModel()
+{
+ return qobject_cast<ThreadsWindow*>(m_threadsWindow)->model();
+}
+
+void DebuggerManager::showStatusMessage(const QString &msg, int timeout)
+{
+ Q_UNUSED(timeout)
+ //qDebug() << "STATUS: " << msg;
+ showDebuggerOutput("status:", msg);
+ mainWindow()->statusBar()->showMessage(msg, timeout);
+#if 0
+ QString currentTime = QTime::currentTime().toString("hh:mm:ss.zzz");
+
+ ICore *core = m_pm->getObject<Core::ICore>();
+ //qDebug() << qPrintable(currentTime) << "Setting status: " << msg;
+ if (msg.isEmpty())
+ core->messageManager()->displayStatusBarMessage(msg);
+ else if (timeout == -1)
+ core->messageManager()->displayStatusBarMessage(tr("Debugger: ") + msg);
+ else
+ core->messageManager()->displayStatusBarMessage(tr("Debugger: ") + msg, timeout);
+#endif
+}
+
+void DebuggerManager::notifyStartupFinished()
+{
+ setStatus(DebuggerProcessReady);
+ showStatusMessage(tr("Startup finished. Debugger ready."), -1);
+ if (m_startMode == attachExternal) {
+ // we continue the execution
+ engine()->continueInferior();
+ } else {
+ engine()->runInferior();
+ }
+}
+
+void DebuggerManager::notifyInferiorStopped()
+{
+ resetLocation();
+ setStatus(DebuggerInferiorStopped);
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void DebuggerManager::notifyInferiorUpdateFinished()
+{
+ setStatus(DebuggerInferiorReady);
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void DebuggerManager::notifyInferiorRunningRequested()
+{
+ setStatus(DebuggerInferiorRunningRequested);
+ showStatusMessage(tr("Running..."), 5000);
+}
+
+void DebuggerManager::notifyInferiorRunning()
+{
+ setStatus(DebuggerInferiorRunning);
+ showStatusMessage(tr("Running..."), 5000);
+}
+
+void DebuggerManager::notifyInferiorExited()
+{
+ setStatus(DebuggerProcessReady);
+ showStatusMessage(tr("Stopped."), 5000);
+}
+
+void DebuggerManager::notifyInferiorPidChanged(int pid)
+{
+ //QMessageBox::warning(0, "PID", "PID: " + QString::number(pid));
+ //qDebug() << "PID: " << pid;
+ emit inferiorPidChanged(pid);
+}
+
+void DebuggerManager::showApplicationOutput(const QString &prefix, const QString &str)
+{
+ applicationOutputAvailable(prefix, str);
+}
+
+void DebuggerManager::shutdown()
+{
+ //qDebug() << "DEBUGGER_MANAGER SHUTDOWN START";
+ engine()->shutdown();
+ // Delete these manually before deleting the manager
+ // (who will delete the models for most views)
+ delete m_breakWindow;
+ delete m_disassemblerWindow;
+ delete m_modulesWindow;
+ delete m_outputWindow;
+ delete m_registerWindow;
+ delete m_stackWindow;
+ delete m_threadsWindow;
+ delete m_tooltipWindow;
+ delete m_watchersWindow;
+ delete m_localsWindow;
+ // These widgets are all in some layout which will take care of deletion.
+ m_breakWindow = 0;
+ m_disassemblerWindow = 0;
+ m_modulesWindow = 0;
+ m_outputWindow = 0;
+ m_registerWindow = 0;
+ m_stackWindow = 0;
+ m_threadsWindow = 0;
+ m_tooltipWindow = 0;
+ m_watchersWindow = 0;
+ m_localsWindow = 0;
+
+ delete m_breakHandler;
+ delete m_disassemblerHandler;
+ delete m_modulesHandler;
+ delete m_registerHandler;
+ delete m_stackHandler;
+ delete m_watchHandler;
+ m_breakHandler = 0;
+ m_disassemblerHandler = 0;
+ m_modulesHandler = 0;
+ m_registerHandler = 0;
+ m_stackHandler = 0;
+ m_watchHandler = 0;
+ //qDebug() << "DEBUGGER_MANAGER SHUTDOWN END";
+}
+
+void DebuggerManager::toggleBreakpoint()
+{
+ QString fileName;
+ int lineNumber = -1;
+ queryCurrentTextEditor(&fileName, &lineNumber, 0);
+ if (lineNumber == -1)
+ return;
+ toggleBreakpoint(fileName, lineNumber);
+}
+
+void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
+{
+ int index = m_breakHandler->indexOf(fileName, lineNumber);
+ if (index == -1)
+ breakHandler()->setBreakpoint(fileName, lineNumber);
+ else
+ breakHandler()->removeBreakpoint(index);
+ engine()->attemptBreakpointSynchronization();
+}
+
+void DebuggerManager::setToolTipExpression(const QPoint &pos, const QString &exp)
+{
+ engine()->setToolTipExpression(pos, exp);
+}
+
+void DebuggerManager::updateWatchModel()
+{
+ engine()->updateWatchModel();
+}
+
+void DebuggerManager::expandChildren(const QModelIndex &idx)
+{
+ watchHandler()->expandChildren(idx);
+}
+
+void DebuggerManager::collapseChildren(const QModelIndex &idx)
+{
+ watchHandler()->collapseChildren(idx);
+}
+
+void DebuggerManager::removeWatchExpression(const QString &iname)
+{
+ watchHandler()->removeWatchExpression(iname);
+}
+
+QVariant DebuggerManager::sessionValue(const QString &name)
+{
+ QVariant value;
+ emit sessionValueRequested(name, &value);
+ return value;
+}
+
+void DebuggerManager::querySessionValue(const QString &name, QVariant *value)
+{
+ emit sessionValueRequested(name, value);
+}
+
+void DebuggerManager::setSessionValue(const QString &name, const QVariant &value)
+{
+ emit setSessionValueRequested(name, value);
+}
+
+QVariant DebuggerManager::configValue(const QString &name)
+{
+ QVariant value;
+ emit configValueRequested(name, &value);
+ return value;
+}
+
+void DebuggerManager::queryConfigValue(const QString &name, QVariant *value)
+{
+ emit configValueRequested(name, value);
+}
+
+void DebuggerManager::setConfigValue(const QString &name, const QVariant &value)
+{
+ emit setConfigValueRequested(name, value);
+}
+
+void DebuggerManager::startExternalApplication()
+{
+ if (!startNewDebugger(startExternal))
+ emit debuggingFinished();
+}
+
+void DebuggerManager::attachExternalApplication()
+{
+ if (!startNewDebugger(attachExternal))
+ emit debuggingFinished();
+}
+
+bool DebuggerManager::startNewDebugger(StartMode mode)
+{
+ m_startMode = mode;
+ // FIXME: Clean up
+
+ if (startMode() == startExternal) {
+ StartExternalDialog dlg(mainWindow());
+ dlg.setExecutableFile(
+ configValue(QLatin1String("LastExternalExecutableFile")).toString());
+ dlg.setExecutableArguments(
+ configValue(QLatin1String("LastExternalExecutableArguments")).toString());
+ if (dlg.exec() != QDialog::Accepted)
+ return false;
+ setConfigValue(QLatin1String("LastExternalExecutableFile"),
+ dlg.executableFile());
+ setConfigValue(QLatin1String("LastExternalExecutableArguments"),
+ dlg.executableArguments());
+ m_executable = dlg.executableFile();
+ m_processArgs = dlg.executableArguments().split(' ');
+ m_workingDir = QString();
+ m_attachedPID = -1;
+ } else if (startMode() == attachExternal) {
+ QString pid;
+ AttachExternalDialog dlg(mainWindow(), pid);
+ if (dlg.exec() != QDialog::Accepted)
+ return false;
+ m_executable = QString();
+ m_processArgs = QStringList();
+ m_workingDir = QString();
+ m_attachedPID = dlg.attachPID();
+ } else if (startMode() == startInternal) {
+ if (m_executable.isEmpty()) {
+ QString startDirectory = m_executable;
+ if (m_executable.isEmpty()) {
+ QString fileName;
+ emit currentTextEditorRequested(&fileName, 0, 0);
+ if (!fileName.isEmpty()) {
+ const QFileInfo editorFile(fileName);
+ startDirectory = editorFile.dir().absolutePath();
+ }
+ }
+ StartExternalDialog dlg(mainWindow());
+ dlg.setExecutableFile(startDirectory);
+ if (dlg.exec() != QDialog::Accepted)
+ return false;
+ m_executable = dlg.executableFile();
+ m_processArgs = dlg.executableArguments().split(' ');
+ m_workingDir = QString();
+ m_attachedPID = 0;
+ } else {
+ //m_executable = QDir::convertSeparators(m_executable);
+ //m_processArgs = sd.processArgs.join(QLatin1String(" "));
+ m_attachedPID = 0;
+ }
+ }
+
+ emit debugModeRequested();
+
+ if (m_executable.endsWith(".js"))
+ setDebuggerType(ScriptDebugger);
+ else
+ setDebuggerType(GdbDebugger);
+
+ if (!engine()->startDebugger())
+ return false;
+
+ m_busy = false;
+ setStatus(DebuggerProcessStartingUp);
+ return true;
+}
+
+void DebuggerManager::cleanupViews()
+{
+ resetLocation();
+ breakHandler()->setAllPending();
+ stackHandler()->removeAll();
+ threadsHandler()->removeAll();
+ disassemblerHandler()->removeAll();
+ modulesHandler()->removeAll();
+ watchHandler()->cleanup();
+}
+
+void DebuggerManager::exitDebugger()
+{
+ engine()->exitDebugger();
+ cleanupViews();
+ setStatus(DebuggerProcessNotReady);
+ setBusyCursor(false);
+ emit debuggingFinished();
+}
+
+void DebuggerManager::assignValueInDebugger(const QString &expr, const QString &value)
+{
+ engine()->assignValueInDebugger(expr, value);
+}
+
+void DebuggerManager::activateFrame(int index)
+{
+ engine()->activateFrame(index);
+}
+
+void DebuggerManager::selectThread(int index)
+{
+ engine()->selectThread(index);
+}
+
+void DebuggerManager::loadAllSymbols()
+{
+ engine()->loadAllSymbols();
+}
+
+void DebuggerManager::loadSymbols(const QString &module)
+{
+ engine()->loadSymbols(module);
+}
+
+void DebuggerManager::stepExec()
+{
+ resetLocation();
+ engine()->stepExec();
+}
+
+void DebuggerManager::stepOutExec()
+{
+ resetLocation();
+ engine()->stepOutExec();
+}
+
+void DebuggerManager::nextExec()
+{
+ resetLocation();
+ engine()->nextExec();
+}
+
+void DebuggerManager::stepIExec()
+{
+ resetLocation();
+ engine()->stepIExec();
+}
+
+void DebuggerManager::nextIExec()
+{
+ resetLocation();
+ engine()->nextIExec();
+}
+
+void DebuggerManager::executeDebuggerCommand(const QString &command)
+{
+ engine()->executeDebuggerCommand(command);
+}
+
+void DebuggerManager::sessionLoaded()
+{
+ exitDebugger();
+ loadSessionData();
+}
+
+void DebuggerManager::aboutToSaveSession()
+{
+ saveSessionData();
+}
+
+void DebuggerManager::loadSessionData()
+{
+ m_breakHandler->loadSessionData();
+
+ QVariant value;
+ querySessionValue(QLatin1String("UseFastStart"), &value);
+ m_useFastStartAction->setChecked(value.toBool());
+ querySessionValue(QLatin1String("UseCustomDumpers"), &value);
+ m_useCustomDumpersAction->setChecked(!value.isValid() || value.toBool());
+ querySessionValue(QLatin1String("SkipKnownFrames"), &value);
+ m_skipKnownFramesAction->setChecked(value.toBool());
+ engine()->loadSessionData();
+}
+
+void DebuggerManager::saveSessionData()
+{
+ m_breakHandler->saveSessionData();
+
+ setSessionValue(QLatin1String("UseFastStart"),
+ m_useFastStartAction->isChecked());
+ setSessionValue(QLatin1String("UseCustomDumpers"),
+ m_useCustomDumpersAction->isChecked());
+ setSessionValue(QLatin1String("SkipKnownFrames"),
+ m_skipKnownFramesAction->isChecked());
+ engine()->saveSessionData();
+}
+
+void DebuggerManager::dumpLog()
+{
+ QString fileName = QFileDialog::getSaveFileName(mainWindow(),
+ tr("Save Debugger Log"), QDir::tempPath());
+ if (fileName.isEmpty())
+ return;
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly))
+ return;
+ QTextStream ts(&file);
+ ts << m_outputWindow->inputContents();
+ ts << "\n\n=======================================\n\n";
+ ts << m_outputWindow->combinedContents();
+}
+
+#if 0
+// call after m_gdbProc exited.
+void GdbEngine::procFinished()
+{
+ //qDebug() << "GDB PROCESS FINISHED";
+ setStatus(DebuggerProcessNotReady);
+ showStatusMessage(tr("Done"), 5000);
+ q->m_breakHandler->procFinished();
+ q->m_watchHandler->cleanup();
+ m_stackHandler->m_stackFrames.clear();
+ m_stackHandler->resetModel();
+ m_threadsHandler->resetModel();
+ if (q->m_modulesHandler)
+ q->m_modulesHandler->procFinished();
+ q->resetLocation();
+ setStatus(DebuggerProcessNotReady);
+ emit q->previousModeRequested();
+ emit q->debuggingFinished();
+ //exitDebugger();
+ //showStatusMessage("Gdb killed");
+ m_shortToFullName.clear();
+ m_fullToShortName.clear();
+ m_shared = 0;
+ q->m_busy = false;
+}
+#endif
+
+void DebuggerManager::addToWatchWindow()
+{
+ // requires a selection, but that's the only case we want...
+ QObject *ob = 0;
+ queryCurrentTextEditor(0, 0, &ob);
+ QPlainTextEdit *editor = qobject_cast<QPlainTextEdit*>(ob);
+ if (!editor)
+ return;
+ QTextCursor tc = editor->textCursor();
+ watchExpression(tc.selectedText());
+}
+
+void DebuggerManager::watchExpression(const QString &expression)
+{
+ watchHandler()->watchExpression(expression);
+ //engine()->updateWatchModel();
+}
+
+void DebuggerManager::setBreakpoint(const QString &fileName, int lineNumber)
+{
+ breakHandler()->setBreakpoint(fileName, lineNumber);
+ engine()->attemptBreakpointSynchronization();
+}
+
+void DebuggerManager::breakByFunction(const QString &functionName)
+{
+ breakHandler()->breakByFunction(functionName);
+ engine()->attemptBreakpointSynchronization();
+}
+
+void DebuggerManager::breakByFunction()
+{
+ BreakByFunctionDialog dlg(m_mainWindow);
+ if (dlg.exec())
+ breakByFunction(dlg.functionName());
+}
+
+void DebuggerManager::breakAtMain()
+{
+#ifdef Q_OS_WIN
+ breakByFunction("qMain");
+#else
+ breakByFunction("main");
+#endif
+}
+
+void DebuggerManager::setStatus(int status)
+{
+ //qDebug() << "STATUS CHANGE: from" << m_status << "to" << status;
+
+ if (status == m_status)
+ return;
+
+ m_status = status;
+
+ const bool started = status == DebuggerInferiorRunning
+ || status == DebuggerInferiorRunningRequested
+ || status == DebuggerInferiorStopRequested
+ || status == DebuggerInferiorStopped
+ || status == DebuggerInferiorUpdating
+ || status == DebuggerInferiorUpdateFinishing
+ || status == DebuggerInferiorReady;
+
+ const bool starting = status == DebuggerProcessStartingUp;
+ const bool running = status == DebuggerInferiorRunning;
+ const bool ready = status == DebuggerInferiorStopped
+ || status == DebuggerInferiorReady
+ || status == DebuggerProcessReady;
+
+ m_startExternalAction->setEnabled(!started && !starting);
+ m_attachExternalAction->setEnabled(!started && !starting);
+ m_watchAction->setEnabled(ready);
+ m_breakAction->setEnabled(true);
+
+ bool interruptIsExit = !running;
+ if (interruptIsExit) {
+ m_stopAction->setIcon(QIcon(":/gdbdebugger/images/debugger_stop_small.png"));
+ m_stopAction->setText(tr("Stop Debugger"));
+ } else {
+ m_stopAction->setIcon(QIcon(":/gdbdebugger/images/debugger_interrupt_small.png"));
+ m_stopAction->setText(tr("Interrupt"));
+ }
+
+ m_stopAction->setEnabled(started);
+ m_resetAction->setEnabled(true);
+
+ m_stepAction->setEnabled(ready);
+ m_stepOutAction->setEnabled(ready);
+ m_runToLineAction->setEnabled(ready);
+ m_runToFunctionAction->setEnabled(ready);
+ m_jumpToLineAction->setEnabled(ready);
+ m_nextAction->setEnabled(ready);
+ m_stepIAction->setEnabled(ready);
+ m_nextIAction->setEnabled(ready);
+ //showStatusMessage(QString("started: %1, running: %2").arg(started).arg(running));
+ emit statusChanged(m_status);
+ const bool notbusy = ready || status == DebuggerProcessNotReady;
+ setBusyCursor(!notbusy);
+}
+
+void DebuggerManager::setBusyCursor(bool busy)
+{
+ if (busy == m_busy)
+ return;
+ //qDebug() << "BUSY: " << busy;
+ m_busy = busy;
+
+ QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
+ m_breakWindow->setCursor(cursor);
+ m_disassemblerWindow->setCursor(cursor);
+ m_localsWindow->setCursor(cursor);
+ m_modulesWindow->setCursor(cursor);
+ m_outputWindow->setCursor(cursor);
+ m_registerWindow->setCursor(cursor);
+ m_stackWindow->setCursor(cursor);
+ m_threadsWindow->setCursor(cursor);
+ m_tooltipWindow->setCursor(cursor);
+ m_watchersWindow->setCursor(cursor);
+}
+
+bool DebuggerManager::skipKnownFrames() const
+{
+ return m_skipKnownFramesAction->isChecked();
+}
+
+bool DebuggerManager::debugDumpers() const
+{
+ return m_debugDumpersAction->isChecked();
+}
+
+bool DebuggerManager::useCustomDumpers() const
+{
+ return m_useCustomDumpersAction->isChecked();
+}
+
+bool DebuggerManager::useFastStart() const
+{
+ return 0; // && m_useFastStartAction->isChecked();
+}
+
+void DebuggerManager::queryCurrentTextEditor(QString *fileName, int *lineNumber,
+ QObject **object)
+{
+ emit currentTextEditorRequested(fileName, lineNumber, object);
+}
+
+void DebuggerManager::continueExec()
+{
+ engine()->continueInferior();
+}
+
+void DebuggerManager::interruptDebuggingRequest()
+{
+ //qDebug() << "INTERRUPTING AT" << status();
+ bool interruptIsExit = (status() != DebuggerInferiorRunning);
+ if (interruptIsExit)
+ exitDebugger();
+ else {
+ setStatus(DebuggerInferiorStopRequested);
+ engine()->interruptInferior();
+ }
+}
+
+
+void DebuggerManager::runToLineExec()
+{
+ QString fileName;
+ int lineNumber = -1;
+ emit currentTextEditorRequested(&fileName, &lineNumber, 0);
+ if (!fileName.isEmpty())
+ engine()->runToLineExec(fileName, lineNumber);
+}
+
+void DebuggerManager::runToFunctionExec()
+{
+ QString fileName;
+ int lineNumber = -1;
+ QObject *object = 0;
+ emit currentTextEditorRequested(&fileName, &lineNumber, &object);
+ QPlainTextEdit *ed = qobject_cast<QPlainTextEdit*>(object);
+ if (!ed)
+ return;
+ QTextCursor cursor = ed->textCursor();
+ QString functionName = cursor.selectedText();
+ if (functionName.isEmpty()) {
+ const QTextBlock block = cursor.block();
+ const QString line = block.text();
+ foreach (const QString &str, line.trimmed().split('(')) {
+ QString a;
+ for (int i = str.size(); --i >= 0; ) {
+ if (!str.at(i).isLetterOrNumber())
+ break;
+ a = str.at(i) + a;
+ }
+ if (!a.isEmpty()) {
+ functionName = a;
+ break;
+ }
+ }
+ }
+ //qDebug() << "RUN TO FUNCTION " << functionName;
+ if (!functionName.isEmpty())
+ engine()->runToFunctionExec(functionName);
+}
+
+void DebuggerManager::jumpToLineExec()
+{
+ QString fileName;
+ int lineNumber = -1;
+ emit currentTextEditorRequested(&fileName, &lineNumber, 0);
+ if (!fileName.isEmpty())
+ engine()->jumpToLineExec(fileName, lineNumber);
+}
+
+void DebuggerManager::resetLocation()
+{
+ //m_watchHandler->removeMouseMoveCatcher(editor->widget());
+ emit resetLocationRequested();
+}
+
+void DebuggerManager::gotoLocation(const QString &fileName, int line,
+ bool setMarker)
+{
+ emit gotoLocationRequested(fileName, line, setMarker);
+ //m_watchHandler->installMouseMoveCatcher(editor->widget());
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Disassembler specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::reloadDisassembler()
+{
+ if (!m_disassemblerDock || !m_disassemblerDock->isVisible())
+ return;
+ engine()->reloadDisassembler();
+}
+
+void DebuggerManager::disassemblerDockToggled(bool on)
+{
+ if (on)
+ reloadDisassembler();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Modules specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::reloadModules()
+{
+ if (!m_modulesDock || !m_modulesDock->isVisible())
+ return;
+ engine()->reloadModules();
+}
+
+void DebuggerManager::modulesDockToggled(bool on)
+{
+ if (on)
+ reloadModules();
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Output specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::showDebuggerOutput(const QString &prefix, const QString &msg)
+{
+ m_outputWindow->showOutput(prefix, msg);
+}
+
+void DebuggerManager::showDebuggerInput(const QString &prefix, const QString &msg)
+{
+ m_outputWindow->showInput(prefix, msg);
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Register specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void DebuggerManager::registerDockToggled(bool on)
+{
+ if (on)
+ reloadRegisters();
+}
+
+void DebuggerManager::reloadRegisters()
+{
+ if (!m_registerDock || !m_registerDock->isVisible())
+ return;
+ engine()->reloadRegisters();
+}
+
+
+#include "debuggermanager.moc"