Newer
Older
/**************************************************************************
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
** 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
**************************************************************************/
#include "debuggeragents.h"
#include "debuggerrunner.h"
#include "debuggerstringutils.h"
#include "breakwindow.h"
#include "debuggeroutputwindow.h"
#include "moduleswindow.h"
#include "registerwindow.h"
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "stackhandler.h"
#include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h>
#include <utils/fancymainwindow.h>
#include <projectexplorer/toolchain.h>
#include <cplusplus/CppDocument.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
#include <texteditor/itexteditor.h>
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTimer>
#include <QtGui/QApplication>
#include <QtGui/QAction>
#include <QtGui/QComboBox>
#include <QtGui/QDockWidget>
#include <QtGui/QErrorMessage>
#include <QtGui/QFileDialog>
#include <QtGui/QLabel>
#include <QtGui/QMessageBox>
#include <QtGui/QPlainTextEdit>
#include <QtGui/QPushButton>
#include <QtGui/QStatusBar>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
#include <QtGui/QToolButton>
#include <QtGui/QToolTip>
#define DEBUG_STATE 1
#ifdef DEBUG_STATE
// use Q_FUNC_INFO?
# define STATE_DEBUG(s) \
{ QString msg; QTextStream ts(&msg); ts << s; \
showDebuggerOutput(LogDebug, msg); }
#else
# define STATE_DEBUG(s)
#endif
// Note: the Debugger process itself and any helper processes like
// gdbserver, the trk client etc are referred to as 'Adapter',
// whereas the debugged process is referred to as 'Inferior'.
//
// AdapterStarted ------------------------------------.
// | v
// InferiorStarting ----> InferiorStartFailed -------->|
// | |
// (core) | (attach) (term) (remote) |
// .-----------------<-|->------------------. |
// | v | |
// InferiorUnrunnable | (plain) | |
// | | (trk) | |
// | | | |
// | .--> InferiorRunningRequested | |
// | | | | |
// | | InferiorRunning | |
// | | | | |
// | | InferiorStopping | |
// | | | | |
// | '------ InferiorStopped <-----------' |
// | | v
// | InferiorShuttingDown -> InferiorShutdownFailed ---->|
// | | |
// | InferiorShutDown |
// | | |
// '--------> EngineShuttingDown <--------------------------------'
//
// Allowed actions:
// [R] : Run
// [C] : Continue
// [N] : Step, Next
namespace Debugger {
namespace Internal {
IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
// The createWinEngine function takes a list of options pages it can add to.
// This allows for having a "enabled" toggle on the page independently
// of the engine. That's good for not enabling the related ActiveX control
// unnecessarily.
IDebuggerEngine *createWinEngine(DebuggerManager *, bool /* cmdLineEnabled */, QList<Core::IOptionsPage*> *)
#ifdef CDB_ENABLED
;
#else
{ return 0; }
#endif
} // namespace Internal
DEBUGGER_EXPORT QDebug operator<<(QDebug str, const DebuggerStartParameters &p)
{
QDebug nospace = str.nospace();
const QString sep = QString(QLatin1Char(','));
nospace << "executable=" << p.executable << " coreFile=" << p.coreFile
<< " processArgs=" << p.processArgs.join(sep)
<< " environment=<" << p.environment.size() << " variables>"
<< " workingDir=" << p.workingDir << " buildDir=" << p.buildDir
<< " attachPID=" << p.attachPID << " useTerminal=" << p.useTerminal
<< " remoteChannel=" << p.remoteChannel
<< " remoteArchitecture=" << p.remoteArchitecture
<< " symbolFileName=" << p.symbolFileName
<< " serverStartScript=" << p.serverStartScript
<< " toolchain=" << p.toolChainType << '\n';
return str;
}
using namespace Constants;
using namespace Debugger::Internal;
const char *DebuggerManager::stateName(int s)
SN(DebuggerNotReady)
SN(EngineStarting)
SN(AdapterStarting)
SN(AdapterStarted)
SN(AdapterStartFailed)
SN(InferiorStarting)
SN(InferiorStartFailed)
SN(InferiorRunningRequested)
SN(InferiorRunningRequested_Kill)
SN(InferiorUnrunnable)
SN(InferiorStopping_Kill)
SN(InferiorStopped)
SN(InferiorStopFailed)
SN(InferiorShuttingDown)
SN(InferiorShutDown)
SN(InferiorShutdownFailed)
}
return "<unknown>";
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////
DebuggerStartParameters::DebuggerStartParameters()
: attachPID(-1),
useTerminal(false),
toolChainType(ProjectExplorer::ToolChain::UNKNOWN),
startMode(NoStartMode)
void DebuggerStartParameters::clear()
{
*this = DebuggerStartParameters();
}
///////////////////////////////////////////////////////////////////////
//
// DebuggerManager
//
///////////////////////////////////////////////////////////////////////
static Debugger::Internal::IDebuggerEngine *gdbEngine = 0;
static Debugger::Internal::IDebuggerEngine *scriptEngine = 0;
static Debugger::Internal::IDebuggerEngine *winEngine = 0;
struct DebuggerManagerPrivate
{
DebuggerManagerPrivate(DebuggerManager *manager);
static DebuggerManager *instance;
// FIXME: Remove engine-specific state
DebuggerStartParametersPtr m_startParameters;
qint64 m_inferiorPid;
/// Views
Utils::FancyMainWindow *m_mainWindow;
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
QLabel *m_statusLabel;
QDockWidget *m_breakDock;
QDockWidget *m_modulesDock;
QDockWidget *m_outputDock;
QDockWidget *m_registerDock;
QDockWidget *m_stackDock;
QDockWidget *m_sourceFilesDock;
QDockWidget *m_threadsDock;
QDockWidget *m_watchDock;
BreakHandler *m_breakHandler;
ModulesHandler *m_modulesHandler;
RegisterHandler *m_registerHandler;
StackHandler *m_stackHandler;
ThreadsHandler *m_threadsHandler;
WatchHandler *m_watchHandler;
SourceFilesWindow *m_sourceFilesWindow;
DebuggerManagerActions m_actions;
QWidget *m_breakWindow;
QWidget *m_localsWindow;
QWidget *m_registerWindow;
QWidget *m_modulesWindow;
QWidget *m_stackWindow;
QWidget *m_threadsWindow;
QWidget *m_watchersWindow;
DebuggerOutputWindow *m_outputWindow;
bool m_busy;
QTimer *m_statusTimer;
QString m_lastPermanentStatusMessage;
DisassemblerViewAgent m_disassemblerViewAgent;
IDebuggerEngine *m_engine;
DebuggerState m_state;
CPlusPlus::Snapshot m_codeModelSnapshot;
};
DebuggerManager *DebuggerManagerPrivate::instance = 0;
DebuggerManagerPrivate::DebuggerManagerPrivate(DebuggerManager *manager)
: m_startParameters(new DebuggerStartParameters),
}
DebuggerManager::DebuggerManager()
: d(new DebuggerManagerPrivate(this))
DebuggerManagerPrivate::instance = this;
init();
#define doDelete(ptr) delete ptr; ptr = 0
doDelete(gdbEngine);
doDelete(scriptEngine);
#undef doDelete
DebuggerManagerPrivate::instance = 0;
delete d;
DebuggerManager *DebuggerManager::instance()
{
return DebuggerManagerPrivate::instance;
}
void DebuggerManager::init()
d->m_state = DebuggerState(-1);
d->m_busy = false;
d->m_modulesHandler = 0;
d->m_registerHandler = 0;
d->m_statusLabel = new QLabel;
d->m_statusLabel->setMinimumSize(QSize(30, 10));
d->m_breakWindow = new BreakWindow;
d->m_modulesWindow = new ModulesWindow(this);
d->m_outputWindow = new DebuggerOutputWindow;
d->m_registerWindow = new RegisterWindow(this);
d->m_stackWindow = new StackWindow(this);
d->m_sourceFilesWindow = new SourceFilesWindow;
d->m_threadsWindow = new ThreadsWindow;
d->m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this);
d->m_watchersWindow = new WatchWindow(WatchWindow::WatchersType, this);
d->m_statusTimer = new QTimer(this);
d->m_mainWindow = new Utils::FancyMainWindow;
d->m_mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
d->m_mainWindow->setDocumentMode(true);
d->m_stackHandler = new StackHandler;
qobject_cast<QAbstractItemView *>(d->m_stackWindow);
stackView->setModel(d->m_stackHandler->stackModel());
connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()),
this, SLOT(reloadFullStack()));
connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()),
this, SLOT(reloadFullStack()));
d->m_threadsHandler = new ThreadsHandler;
qobject_cast<QAbstractItemView *>(d->m_threadsWindow);
threadsView->setModel(d->m_threadsHandler->threadsModel());
connect(threadsView, SIGNAL(threadSelected(int)),
this, SLOT(selectThread(int)));
// Breakpoints
d->m_breakHandler = new BreakHandler(this);
qobject_cast<QAbstractItemView *>(d->m_breakWindow);
breakView->setModel(d->m_breakHandler->model());
connect(breakView, SIGNAL(breakpointActivated(int)),
d->m_breakHandler, SLOT(activateBreakpoint(int)));
connect(breakView, SIGNAL(breakpointDeleted(int)),
d->m_breakHandler, SLOT(removeBreakpoint(int)));
connect(breakView, SIGNAL(breakpointSynchronizationRequested()),
this, SLOT(attemptBreakpointSynchronization()));
connect(breakView, SIGNAL(breakByFunctionRequested(QString)),
this, SLOT(breakByFunction(QString)), Qt::QueuedConnection);
connect(breakView, SIGNAL(breakByFunctionMainRequested()),
this, SLOT(breakByFunctionMain()), Qt::QueuedConnection);
qobject_cast<QAbstractItemView *>(d->m_modulesWindow);
d->m_modulesHandler = new ModulesHandler;
modulesView->setModel(d->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()));
connect(modulesView, SIGNAL(fileOpenRequested(QString)),
this, SLOT(fileOpen(QString)));
connect(modulesView, SIGNAL(newDockRequested(QWidget*)),
this, SLOT(createNewDock(QWidget*)));
//d->m_sourceFilesHandler = new SourceFilesHandler;
QAbstractItemView *sourceFilesView =
qobject_cast<QAbstractItemView *>(d->m_sourceFilesWindow);
//sourceFileView->setModel(d->m_stackHandler->stackModel());
connect(sourceFilesView, SIGNAL(reloadSourceFilesRequested()),
this, SLOT(reloadSourceFiles()));
connect(sourceFilesView, SIGNAL(fileOpenRequested(QString)),
this, SLOT(fileOpen(QString)));
// Registers
qobject_cast<QAbstractItemView *>(d->m_registerWindow);
d->m_registerHandler = new RegisterHandler;
registerView->setModel(d->m_registerHandler->model());
d->m_watchHandler = new WatchHandler(this);
QTreeView *localsView = qobject_cast<QTreeView *>(d->m_localsWindow);
localsView->setModel(d->m_watchHandler->model(LocalsWatch));
// Watchers
QTreeView *watchersView = qobject_cast<QTreeView *>(d->m_watchersWindow);
watchersView->setModel(d->m_watchHandler->model(WatchersWatch));
connect(theDebuggerAction(AssignValue), SIGNAL(triggered()),
this, SLOT(assignValueInDebugger()), Qt::QueuedConnection);
// Log
connect(this, SIGNAL(emitShowInput(int, QString)),
d->m_outputWindow, SLOT(showInput(int, QString)), Qt::QueuedConnection);
connect(this, SIGNAL(emitShowOutput(int, QString)),
d->m_outputWindow, SLOT(showOutput(int, QString)), Qt::QueuedConnection);
//QTreeView *tooltipView = qobject_cast<QTreeView *>(d->m_tooltipWindow);
//tooltipView->setModel(d->m_watchHandler->model(TooltipsWatch));
qRegisterMetaType<WatchData>("WatchData");
qRegisterMetaType<StackCookie>("StackCookie");
d->m_actions.continueAction = new QAction(tr("Continue"), this);
d->m_actions.continueAction->setIcon(QIcon(":/debugger/images/debugger_continue_small.png"));
d->m_actions.stopAction = new QAction(tr("Interrupt"), this);
d->m_actions.stopAction->setIcon(QIcon(":/debugger/images/debugger_interrupt_small.png"));
d->m_actions.resetAction = new QAction(tr("Reset Debugger"), this);
d->m_actions.nextAction = new QAction(tr("Step Over"), this);
d->m_actions.nextAction->setIcon(QIcon(":/debugger/images/debugger_stepover_small.png"));
d->m_actions.stepAction = new QAction(tr("Step Into"), this);
d->m_actions.stepAction->setIcon(QIcon(":/debugger/images/debugger_stepinto_small.png"));
d->m_actions.stepOutAction = new QAction(tr("Step Out"), this);
d->m_actions.stepOutAction->setIcon(QIcon(":/debugger/images/debugger_stepout_small.png"));
d->m_actions.runToLineAction = new QAction(tr("Run to Line"), this);
d->m_actions.runToFunctionAction = new QAction(tr("Run to Outermost Function"), this);
d->m_actions.jumpToLineAction = new QAction(tr("Jump to Line"), this);
d->m_actions.breakAction = new QAction(tr("Toggle Breakpoint"), this);
d->m_actions.watchAction1 = new QAction(tr("Add to Watch Window"), this);
d->m_actions.watchAction2 = new QAction(tr("Add to Watch Window"), this);
d->m_actions.reverseDirectionAction = new QAction(tr("Reverse Direction"), this);
d->m_actions.reverseDirectionAction->setCheckable(true);
d->m_actions.reverseDirectionAction->setChecked(false);
connect(d->m_actions.continueAction, SIGNAL(triggered()),
connect(d->m_actions.stopAction, SIGNAL(triggered()),
connect(d->m_actions.resetAction, SIGNAL(triggered()),
connect(d->m_actions.nextAction, SIGNAL(triggered()),
connect(d->m_actions.stepAction, SIGNAL(triggered()),
connect(d->m_actions.stepOutAction, SIGNAL(triggered()),
connect(d->m_actions.runToLineAction, SIGNAL(triggered()),
connect(d->m_actions.runToFunctionAction, SIGNAL(triggered()),
connect(d->m_actions.jumpToLineAction, SIGNAL(triggered()),
connect(d->m_actions.watchAction1, SIGNAL(triggered()),
this, SLOT(addToWatchWindow()));
connect(d->m_actions.watchAction2, SIGNAL(triggered()),
connect(d->m_actions.breakAction, SIGNAL(triggered()),
connect(d->m_statusTimer, SIGNAL(timeout()),
this, SLOT(clearStatusMessage()));
connect(theDebuggerAction(ExecuteCommand), SIGNAL(triggered()),
this, SLOT(executeDebuggerCommand()));
connect(theDebuggerAction(WatchPoint), SIGNAL(triggered()),
this, SLOT(watchPoint()));
connect(theDebuggerAction(OperateByInstruction), SIGNAL(triggered()),
this, SLOT(operateByInstructionTriggered()));
d->m_breakDock = d->m_mainWindow->addDockForWidget(d->m_breakWindow);
d->m_modulesDock = d->m_mainWindow->addDockForWidget(d->m_modulesWindow);
connect(d->m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)),
d->m_registerDock = d->m_mainWindow->addDockForWidget(d->m_registerWindow);
connect(d->m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
d->m_outputDock = d->m_mainWindow->addDockForWidget(d->m_outputWindow);
d->m_stackDock = d->m_mainWindow->addDockForWidget(d->m_stackWindow);
d->m_sourceFilesDock = d->m_mainWindow->addDockForWidget(d->m_sourceFilesWindow);
connect(d->m_sourceFilesDock->toggleViewAction(), SIGNAL(toggled(bool)),
this, SLOT(reloadSourceFiles()), Qt::QueuedConnection);
d->m_threadsDock = d->m_mainWindow->addDockForWidget(d->m_threadsWindow);
QSplitter *localsAndWatchers = new QSplitter(Qt::Vertical, 0);
localsAndWatchers->setWindowTitle(d->m_localsWindow->windowTitle());
localsAndWatchers->addWidget(d->m_localsWindow);
localsAndWatchers->addWidget(d->m_watchersWindow);
//localsAndWatchers->addWidget(d->m_tooltipWindow);
localsAndWatchers->setStretchFactor(0, 3);
localsAndWatchers->setStretchFactor(1, 1);
localsAndWatchers->setStretchFactor(2, 1);
d->m_watchDock = d->m_mainWindow->addDockForWidget(localsAndWatchers);
}
QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTypeFlags)
{
QList<Core::IOptionsPage*> rc;
if (enabledTypeFlags & GdbEngineType) {
gdbEngine = createGdbEngine(this);
gdbEngine->addOptionPages(&rc);
}
winEngine = createWinEngine(this, (enabledTypeFlags & CdbEngineType), &rc);
if (enabledTypeFlags & ScriptEngineType) {
scriptEngine = createScriptEngine(this);
scriptEngine->addOptionPages(&rc);
}
d->m_engine = 0;
STATE_DEBUG(gdbEngine << winEngine << scriptEngine << rc.size());
return rc;
DebuggerManagerActions DebuggerManager::debuggerManagerActions() const
{
return d->m_actions;
}
Utils::FancyMainWindow *DebuggerManager::mainWindow() const
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
{
return d->m_mainWindow;
}
QLabel *DebuggerManager::statusLabel() const
{
return d->m_statusLabel;
}
IDebuggerEngine *DebuggerManager::currentEngine() const
{
return d->m_engine;
}
ModulesHandler *DebuggerManager::modulesHandler() const
{
return d->m_modulesHandler;
}
BreakHandler *DebuggerManager::breakHandler() const
{
return d->m_breakHandler;
}
RegisterHandler *DebuggerManager::registerHandler() const
{
return d->m_registerHandler;
}
StackHandler *DebuggerManager::stackHandler() const
{
return d->m_stackHandler;
}
ThreadsHandler *DebuggerManager::threadsHandler() const
{
return d->m_threadsHandler;
}
WatchHandler *DebuggerManager::watchHandler() const
{
return d->m_watchHandler;
}
const CPlusPlus::Snapshot &DebuggerManager::cppCodeModelSnapshot() const
{
if (d->m_codeModelSnapshot.isEmpty() && theDebuggerAction(UseCodeModel)->isChecked())
d->m_codeModelSnapshot = CppTools::CppModelManagerInterface::instance()->snapshot();
return d->m_codeModelSnapshot;
}
void DebuggerManager::clearCppCodeModelSnapshot()
{
d->m_codeModelSnapshot = CPlusPlus::Snapshot();
SourceFilesWindow *DebuggerManager::sourceFileWindow() const
{
return d->m_sourceFilesWindow;
}
QWidget *DebuggerManager::threadsWindow() const
return d->m_threadsWindow;
void DebuggerManager::createNewDock(QWidget *widget)
{
QDockWidget *dockWidget = new QDockWidget(widget->windowTitle(), d->m_mainWindow);
dockWidget->setObjectName(widget->windowTitle());
dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
dockWidget->setWidget(widget);
d->m_mainWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
d->m_mainWindow->setTrackingEnabled(false);
QList<QDockWidget *> dockWidgets = d->m_mainWindow->dockWidgets();
foreach (QDockWidget *dockWidget, dockWidgets) {
dockWidget->setFloating(false);
d->m_mainWindow->removeDockWidget(dockWidget);
foreach (QDockWidget *dockWidget, dockWidgets) {
if (dockWidget == d->m_outputDock)
d->m_mainWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
else
d->m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_breakDock);
d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_modulesDock);
d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_registerDock);
d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_threadsDock);
d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_sourceFilesDock);
// They following views are rarely used in ordinary debugging. Hiding them
// saves cycles since the corresponding information won't be retrieved.
d->m_sourceFilesDock->hide();
d->m_registerDock->hide();
d->m_modulesDock->hide();
d->m_outputDock->hide();
d->m_mainWindow->setTrackingEnabled(true);
}
QAbstractItemModel *DebuggerManager::threadsModel()
{
return qobject_cast<ThreadsWindow*>(d->m_threadsWindow)->model();
void DebuggerManager::clearStatusMessage()
{
d->m_statusLabel->setText(d->m_lastPermanentStatusMessage);
void DebuggerManager::showStatusMessage(const QString &msg, int timeout)
{
Q_UNUSED(timeout)
d->m_statusLabel->setText(QLatin1String(" ") + msg);
if (timeout > 0) {
d->m_statusTimer->setSingleShot(true);
d->m_statusTimer->start(timeout);
d->m_lastPermanentStatusMessage = msg;
d->m_statusTimer->stop();
showStatusMessage(tr("Stopped."), 5000);
}
void DebuggerManager::notifyInferiorRunning()
{
showStatusMessage(tr("Running..."), 5000);
}
void DebuggerManager::notifyInferiorExited()
{
showStatusMessage(tr("Exited."), 5000);
void DebuggerManager::notifyInferiorPidChanged(qint64 pid)
STATE_DEBUG(d->m_inferiorPid << pid);
if (d->m_inferiorPid != pid) {
d->m_inferiorPid = pid;
emit inferiorPidChanged(pid);
}
void DebuggerManager::showApplicationOutput(const QString &str)
STATE_DEBUG(d->m_engine);
if (d->m_engine)
d->m_engine->shutdown();
d->m_engine = 0;
#define doDelete(ptr) delete ptr; ptr = 0
doDelete(scriptEngine);
doDelete(gdbEngine);
doDelete(winEngine);
// Delete these manually before deleting the manager
// (who will delete the models for most views)
doDelete(d->m_breakWindow);
doDelete(d->m_modulesWindow);
doDelete(d->m_outputWindow);
doDelete(d->m_registerWindow);
doDelete(d->m_stackWindow);
doDelete(d->m_sourceFilesWindow);
doDelete(d->m_threadsWindow);
//doDelete(d->m_tooltipWindow);
doDelete(d->m_watchersWindow);
doDelete(d->m_localsWindow);
doDelete(d->m_breakHandler);
doDelete(d->m_threadsHandler);
doDelete(d->m_modulesHandler);
doDelete(d->m_registerHandler);
doDelete(d->m_stackHandler);
doDelete(d->m_watchHandler);
#undef doDelete
BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lineNumber)
{
if (!d->m_breakHandler)
int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
return index == -1 ? 0 : d->m_breakHandler->at(index);
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)
{
QTC_ASSERT(d->m_breakHandler, return);
if (state() != InferiorRunning
&& state() != InferiorStopped
&& state() != DebuggerNotReady) {
showStatusMessage(tr("Changing breakpoint state requires either a "
"fully running or fully stopped application."));
return;
}
int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
d->m_breakHandler->setBreakpoint(fileName, lineNumber);
d->m_breakHandler->removeBreakpoint(index);
void DebuggerManager::toggleBreakpointEnabled(const QString &fileName, int lineNumber)
{
QTC_ASSERT(d->m_breakHandler, return);
if (state() != InferiorRunning
&& state() != InferiorStopped
&& state() != DebuggerNotReady) {
showStatusMessage(tr("Changing breakpoint state requires either a "
"fully running or fully stopped application."));
return;
}
d->m_breakHandler->toggleBreakpointEnabled(fileName, lineNumber);
void DebuggerManager::attemptBreakpointSynchronization()
{
if (d->m_engine)
d->m_engine->attemptBreakpointSynchronization();
void DebuggerManager::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
if (d->m_engine)
d->m_engine->setToolTipExpression(mousePos, editor, cursorPos);
void DebuggerManager::updateWatchData(const Debugger::Internal::WatchData &data)
if (d->m_engine)
d->m_engine->updateWatchData(data);
static QString msgEngineNotAvailable(const char *engine)
return DebuggerManager::tr("The application requires the debugger engine '%1', "
"which is disabled.").arg(QLatin1String(engine));
}
static IDebuggerEngine *debuggerEngineForToolChain(ProjectExplorer::ToolChain::ToolChainType tc)
{
IDebuggerEngine *rc = 0;
switch (tc) {
//case ProjectExplorer::ToolChain::LinuxICC:
case ProjectExplorer::ToolChain::MinGW:
case ProjectExplorer::ToolChain::GCC:
rc = gdbEngine;
break;
case ProjectExplorer::ToolChain::MSVC:
case ProjectExplorer::ToolChain::WINCE:
rc = winEngine;
break;
case ProjectExplorer::ToolChain::WINSCW: // S60
case ProjectExplorer::ToolChain::GCCE:
case ProjectExplorer::ToolChain::RVCT_ARMV5:
case ProjectExplorer::ToolChain::RVCT_ARMV6:
rc = gdbEngine;
break;
case ProjectExplorer::ToolChain::OTHER:
case ProjectExplorer::ToolChain::UNKNOWN:
case ProjectExplorer::ToolChain::INVALID:
break;
}
return rc;
}
// Figure out the debugger type of an executable. Analyze executable
// unless the toolchain provides a hint.
static IDebuggerEngine *determineDebuggerEngine(const QString &executable,
int toolChainType,
QString *errorMessage,
QString *settingsIdHint)
if (executable.endsWith(_(".js"))) {
if (!scriptEngine) {
*errorMessage = msgEngineNotAvailable("Script Engine");
return 0;
}
return scriptEngine;
if (!gdbEngine) {
*errorMessage = msgEngineNotAvailable("Gdb Engine");
if (IDebuggerEngine *tce = debuggerEngineForToolChain(
static_cast<ProjectExplorer::ToolChain::ToolChainType>(toolChainType)))
Q_UNUSED(settingsIdHint)
if (!gdbEngine) {
*errorMessage = msgEngineNotAvailable("Gdb Engine");
return 0;
}
return gdbEngine;
// A remote executable?
if (!executable.endsWith(_(".exe")))
return gdbEngine;
// If a file has PDB files, it has been compiled by VS.
QStringList pdbFiles;
if (!getPDBFiles(executable, &pdbFiles, errorMessage))
if (pdbFiles.empty())
return gdbEngine;
// We need the CDB debugger in order to be able to debug VS
// executables
if (!DebuggerManager::instance()->checkDebugConfiguration(ProjectExplorer::ToolChain::MSVC, errorMessage, 0 , settingsIdHint))
return 0;
return winEngine;
static IDebuggerEngine *determineDebuggerEngine(int /* pid */,
int toolChainType,
QString *errorMessage)
if (IDebuggerEngine *tce = debuggerEngineForToolChain(
static_cast<ProjectExplorer::ToolChain::ToolChainType>(toolChainType)))
return tce;
#ifdef Q_OS_WIN
// Preferably Windows debugger
if (winEngine)
return winEngine;
if (gdbEngine)
return gdbEngine;
*errorMessage = msgEngineNotAvailable("Gdb Engine");
return 0;
if (!gdbEngine) {
*errorMessage = msgEngineNotAvailable("Gdb Engine");
return 0;
}
return gdbEngine;
void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp)
if (d->m_state != DebuggerNotReady)
return;
d->m_startParameters = sp;
d->m_inferiorPid = d->m_startParameters->attachPID > 0
? d->m_startParameters->attachPID : 0;
const QString toolChainName = ProjectExplorer::ToolChain::toolChainName(static_cast<ProjectExplorer::ToolChain::ToolChainType>(d->m_startParameters->toolChainType));
showDebuggerOutput(LogStatus,
tr("Starting debugger for tool chain '%1'...").arg(toolChainName));
showDebuggerOutput(LogDebug, DebuggerSettings::instance()->dump());
QString settingsIdHint;
switch (d->m_startParameters->startMode) {
case AttachExternal:
case AttachCrashedExternal:
d->m_engine = determineDebuggerEngine(d->m_startParameters->attachPID,
d->m_startParameters->toolChainType, &errorMessage);
break;
default:
d->m_engine = determineDebuggerEngine(d->m_startParameters->executable,
d->m_startParameters->toolChainType, &errorMessage, &settingsIdHint);
break;
}
if (!d->m_engine) {
// Create Message box with possibility to go to settings
const QString msg = tr("Cannot debug '%1' (tool chain: '%2'): %3").
arg(d->m_startParameters->executable, toolChainName, errorMessage);
Core::ICore::instance()->showWarningWithOptions(tr("Warning"), msg, QString(),
QLatin1String(DEBUGGER_SETTINGS_CATEGORY),
settingsIdHint);