Skip to content
Snippets Groups Projects
debuggermanager.cpp 57.1 KiB
Newer Older
/**************************************************************************
con's avatar
con committed
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
**
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
**
** 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
hjk's avatar
hjk committed
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
**
**************************************************************************/
con's avatar
con committed

#include "debuggermanager.h"

#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerrunner.h"
con's avatar
con committed
#include "debuggerconstants.h"
#include "idebuggerengine.h"
#include "debuggerstringutils.h"
#include "watchutils.h"
con's avatar
con committed

#include "breakwindow.h"
#include "debuggeroutputwindow.h"
#include "moduleswindow.h"
#include "registerwindow.h"
#include "stackwindow.h"
#include "sourcefileswindow.h"
con's avatar
con committed
#include "threadswindow.h"
#include "watchwindow.h"

con's avatar
con committed
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "stackhandler.h"
#include "stackframe.h"
con's avatar
con committed
#include "watchhandler.h"

#include "debuggerdialogs.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
#ifdef Q_OS_WIN
#  include "shared/peutils.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
#endif
#include <coreplugin/icore.h>
#include <coreplugin/editormanager/editormanager.h>
#include <utils/qtcassert.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>
con's avatar
con committed
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTextStream>
con's avatar
con committed
#include <QtCore/QTime>
con's avatar
con committed

#include <QtGui/QApplication>
con's avatar
con committed
#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>
con's avatar
con committed
#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',
hjk's avatar
hjk committed
// whereas the debugged process is referred to as 'Inferior'.
//
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
//              0 == DebuggerNotReady
hjk's avatar
hjk committed
//                          |
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
//                    EngineStarting
hjk's avatar
hjk committed
//                          |
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
//                    AdapterStarting --> AdapterStartFailed --> 0
hjk's avatar
hjk committed
//                          |
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
//                    AdapterStarted ------------------------------------.
//                          |                                            v
//                   InferiorStarting ----> InferiorStartFailed -------->|
//                          |                                            |
//         (core)           |     (attach) (term) (remote)               |
//      .-----------------<-|->------------------.                       |
//      |                   v                    |                       |
//  InferiorUnrunnable      | (plain)            |                       |
//      |                   | (trk)              |                       |
//      |                   |                    |                       |
//      |    .--> InferiorRunningRequested       |                       |
//      |    |              |                    |                       |
//      |    |       InferiorRunning             |                       |
//      |    |              |                    |                       |
//      |    |       InferiorStopping            |                       |
//      |    |              |                    |                       |
//      |    '------ InferiorStopped <-----------'                       |
//      |                   |                                            v
//      |          InferiorShuttingDown  ->  InferiorShutdownFailed ---->|
//      |                   |                                            |
//      |            InferiorShutDown                                    |
//      |                   |                                            |
//      '-------->  EngineShuttingDown  <--------------------------------'
hjk's avatar
hjk committed
//                          |
//                          0
hjk's avatar
hjk committed
//
// 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
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';
using namespace Constants;
using namespace Debugger::Internal;
con's avatar
con committed

static const QString tooltipIName = "tooltip";

const char *DebuggerManager::stateName(int s)
hjk's avatar
hjk committed
    #define SN(x) case x: return #x;
hjk's avatar
hjk committed
        SN(DebuggerNotReady)
        SN(EngineStarting)
        SN(AdapterStarting)
        SN(AdapterStarted)
        SN(AdapterStartFailed)
        SN(InferiorStarting)
        SN(InferiorStartFailed)
        SN(InferiorRunningRequested)
        SN(InferiorRunningRequested_Kill)
hjk's avatar
hjk committed
        SN(InferiorRunning)
hjk's avatar
hjk committed
        SN(InferiorStopping)
        SN(InferiorStopping_Kill)
hjk's avatar
hjk committed
        SN(InferiorStopped)
        SN(InferiorStopFailed)
        SN(InferiorShuttingDown)
        SN(InferiorShutDown)
        SN(InferiorShutdownFailed)
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
        SN(EngineShuttingDown)
hjk's avatar
hjk committed
    #undef SN
con's avatar
con committed

///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
con's avatar
con committed
//
///////////////////////////////////////////////////////////////////////

DebuggerStartParameters::DebuggerStartParameters()
  : attachPID(-1),
    remoteChannelType(-1),
hjk's avatar
hjk committed
    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);
    // FIXME: Remove engine-specific state
    DebuggerStartParametersPtr m_startParameters;
    qint64 m_inferiorPid;
    /// Views
    Utils::FancyMainWindow *m_mainWindow;
    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),
dt's avatar
dt committed
    m_disassemblerViewAgent(manager),
    m_engine(0)
DebuggerManager::DebuggerManager()
  : d(new DebuggerManagerPrivate(this))
con's avatar
con committed
{
    DebuggerManagerPrivate::instance = this;
con's avatar
con committed
}

DebuggerManager::~DebuggerManager()
{
    #define doDelete(ptr) delete ptr; ptr = 0
    doDelete(gdbEngine);
    doDelete(scriptEngine);
hjk's avatar
hjk committed
    doDelete(winEngine);
    DebuggerManagerPrivate::instance = 0;
con's avatar
con committed
}

DebuggerManager *DebuggerManager::instance()
{
    return DebuggerManagerPrivate::instance;
}

con's avatar
con committed
{
    d->m_state = DebuggerState(-1);
    d->m_busy = false;
con's avatar
con committed

    d->m_modulesHandler = 0;
    d->m_registerHandler = 0;
con's avatar
con committed

    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);
con's avatar
con committed

    d->m_mainWindow = new Utils::FancyMainWindow;
    d->m_mainWindow->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North);
    d->m_mainWindow->setDocumentMode(true);
con's avatar
con committed

    // Stack
    d->m_stackHandler = new StackHandler;
con's avatar
con committed
    QAbstractItemView *stackView =
        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()));
con's avatar
con committed

    // Threads
    d->m_threadsHandler = new ThreadsHandler;
con's avatar
con committed
    QAbstractItemView *threadsView =
        qobject_cast<QAbstractItemView *>(d->m_threadsWindow);
    threadsView->setModel(d->m_threadsHandler->threadsModel());
con's avatar
con committed
    connect(threadsView, SIGNAL(threadSelected(int)),
        this, SLOT(selectThread(int)));

    // Breakpoints
    d->m_breakHandler = new BreakHandler(this);
con's avatar
con committed
    QAbstractItemView *breakView =
        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);
con's avatar
con committed

    // Modules
    QAbstractItemView *modulesView =
        qobject_cast<QAbstractItemView *>(d->m_modulesWindow);
    d->m_modulesHandler = new ModulesHandler;
    modulesView->setModel(d->m_modulesHandler->model());
con's avatar
con committed
    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*)));
con's avatar
con committed

    //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)));
con's avatar
con committed

con's avatar
con committed
    QAbstractItemView *registerView =
        qobject_cast<QAbstractItemView *>(d->m_registerWindow);
    d->m_registerHandler = new RegisterHandler;
    registerView->setModel(d->m_registerHandler->model());
con's avatar
con committed

    d->m_watchHandler = new WatchHandler(this);
    QTreeView *localsView = qobject_cast<QTreeView *>(d->m_localsWindow);
    localsView->setModel(d->m_watchHandler->model(LocalsWatch));
    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);
con's avatar
con committed

    // 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);

con's avatar
con committed
    // Tooltip
    //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"));
con's avatar
con committed

    d->m_actions.stopAction = new QAction(tr("Interrupt"), this);
    d->m_actions.stopAction->setIcon(QIcon(":/debugger/images/debugger_interrupt_small.png"));
con's avatar
con committed

    d->m_actions.resetAction = new QAction(tr("Reset Debugger"), this);
con's avatar
con committed

    d->m_actions.nextAction = new QAction(tr("Step Over"), this);
    d->m_actions.nextAction->setIcon(QIcon(":/debugger/images/debugger_stepover_small.png"));
con's avatar
con committed

    d->m_actions.stepAction = new QAction(tr("Step Into"), this);
    d->m_actions.stepAction->setIcon(QIcon(":/debugger/images/debugger_stepinto_small.png"));
con's avatar
con committed

    d->m_actions.stepOutAction = new QAction(tr("Step Out"), this);
    d->m_actions.stepOutAction->setIcon(QIcon(":/debugger/images/debugger_stepout_small.png"));
con's avatar
con committed

    d->m_actions.runToLineAction = new QAction(tr("Run to Line"), this);
con's avatar
con committed

    d->m_actions.runToFunctionAction = new QAction(tr("Run to Outermost Function"), this);
con's avatar
con committed

    d->m_actions.jumpToLineAction = new QAction(tr("Jump to Line"), this);
con's avatar
con committed

    d->m_actions.breakAction = new QAction(tr("Toggle Breakpoint"), this);
con's avatar
con committed

    d->m_actions.watchAction1 = new QAction(tr("Add to Watch Window"), this);
    d->m_actions.watchAction2 = new QAction(tr("Add to Watch Window"), this);
con's avatar
con committed

    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()),
con's avatar
con committed
        this, SLOT(continueExec()));
    connect(d->m_actions.stopAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(interruptDebuggingRequest()));
    connect(d->m_actions.resetAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(exitDebugger()));
    connect(d->m_actions.nextAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(nextExec()));
    connect(d->m_actions.stepAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(stepExec()));
    connect(d->m_actions.stepOutAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(stepOutExec()));
    connect(d->m_actions.runToLineAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(runToLineExec()));
    connect(d->m_actions.runToFunctionAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(runToFunctionExec()));
    connect(d->m_actions.jumpToLineAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(jumpToLineExec()));
    connect(d->m_actions.watchAction1, SIGNAL(triggered()),
        this, SLOT(addToWatchWindow()));
    connect(d->m_actions.watchAction2, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(addToWatchWindow()));
    connect(d->m_actions.breakAction, SIGNAL(triggered()),
con's avatar
con committed
        this, SLOT(toggleBreakpoint()));

    connect(d->m_statusTimer, SIGNAL(timeout()),
        this, SLOT(clearStatusMessage()));
con's avatar
con committed

    connect(theDebuggerAction(ExecuteCommand), SIGNAL(triggered()),
        this, SLOT(executeDebuggerCommand()));
    connect(theDebuggerAction(WatchPoint), SIGNAL(triggered()),
        this, SLOT(watchPoint()));
con's avatar
con committed

    connect(theDebuggerAction(OperateByInstruction), SIGNAL(triggered()),
        this, SLOT(operateByInstructionTriggered()));
    d->m_breakDock = d->m_mainWindow->addDockForWidget(d->m_breakWindow);
con's avatar
con committed

    d->m_modulesDock = d->m_mainWindow->addDockForWidget(d->m_modulesWindow);
    connect(d->m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)),
con's avatar
con committed
        this, SLOT(reloadModules()), Qt::QueuedConnection);

    d->m_registerDock = d->m_mainWindow->addDockForWidget(d->m_registerWindow);
    connect(d->m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
con's avatar
con committed
        this, SLOT(reloadRegisters()), Qt::QueuedConnection);

    d->m_outputDock = d->m_mainWindow->addDockForWidget(d->m_outputWindow);
con's avatar
con committed

    d->m_stackDock = d->m_mainWindow->addDockForWidget(d->m_stackWindow);
con's avatar
con committed

    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);
con's avatar
con committed

    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);
hjk's avatar
hjk committed
    setState(DebuggerNotReady);
QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTypeFlags)
    if (enabledTypeFlags & GdbEngineType) {
        gdbEngine = createGdbEngine(this);
        gdbEngine->addOptionPages(&rc);
    }
    winEngine = createWinEngine(this, (enabledTypeFlags & CdbEngineType), &rc);

    if (enabledTypeFlags & ScriptEngineType) {
        scriptEngine = createScriptEngine(this);
        scriptEngine->addOptionPages(&rc);
    }

    STATE_DEBUG(gdbEngine << winEngine << scriptEngine << rc.size());
con's avatar
con committed
}

DebuggerManagerActions DebuggerManager::debuggerManagerActions() const
{
    return d->m_actions;
}

Utils::FancyMainWindow *DebuggerManager::mainWindow() const
{
    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
con's avatar
con committed
{
con's avatar
con committed
}

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);
    dockWidget->show();
}

con's avatar
con committed
void DebuggerManager::setSimpleDockWidgetArrangement()
{
    d->m_mainWindow->setTrackingEnabled(false);
    QList<QDockWidget *> dockWidgets = d->m_mainWindow->dockWidgets();
    foreach (QDockWidget *dockWidget, dockWidgets) {
        dockWidget->setFloating(false);
        d->m_mainWindow->removeDockWidget(dockWidget);
con's avatar
con committed

    foreach (QDockWidget *dockWidget, dockWidgets) {
        if (dockWidget == d->m_outputDock) 
            d->m_mainWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
        else
            d->m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
con's avatar
con committed
        dockWidget->show();
    }

    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);
con's avatar
con committed

    // 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);
con's avatar
con committed
}

QAbstractItemModel *DebuggerManager::threadsModel()
{
    return qobject_cast<ThreadsWindow*>(d->m_threadsWindow)->model();
con's avatar
con committed
}

void DebuggerManager::clearStatusMessage()
{
    d->m_statusLabel->setText(d->m_lastPermanentStatusMessage);
con's avatar
con committed
void DebuggerManager::showStatusMessage(const QString &msg, int timeout)
{
    Q_UNUSED(timeout)
    showDebuggerOutput(LogStatus, msg);
    d->m_statusLabel->setText(QLatin1String("   ") + msg);
        d->m_statusTimer->setSingleShot(true);
        d->m_statusTimer->start(timeout);
        d->m_lastPermanentStatusMessage = msg;
        d->m_statusTimer->stop();
con's avatar
con committed
}

void DebuggerManager::notifyInferiorStopped()
{
hjk's avatar
hjk committed
    setState(InferiorStopped);
con's avatar
con committed
    showStatusMessage(tr("Stopped."), 5000);
}

void DebuggerManager::notifyInferiorRunning()
{
hjk's avatar
hjk committed
    setState(InferiorRunning);
con's avatar
con committed
    showStatusMessage(tr("Running..."), 5000);
}

void DebuggerManager::notifyInferiorExited()
{
hjk's avatar
hjk committed
    setState(DebuggerNotReady);
    showStatusMessage(tr("Exited."), 5000);
con's avatar
con committed
}

void DebuggerManager::notifyInferiorPidChanged(qint64 pid)
con's avatar
con committed
{
    STATE_DEBUG(d->m_inferiorPid << pid);
    if (d->m_inferiorPid != pid) {
        d->m_inferiorPid = pid;
con's avatar
con committed
}

void DebuggerManager::showApplicationOutput(const QString &str)
con's avatar
con committed
{
     emit applicationOutputAvailable(str);
con's avatar
con committed
}

void DebuggerManager::shutdown()
{
    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);
con's avatar
con committed
    // 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);
con's avatar
con committed
}

BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lineNumber)
{
    int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
    return index == -1 ? 0 : d->m_breakHandler->at(index);
con's avatar
con committed
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)
{
    STATE_DEBUG(fileName << lineNumber);
    QTC_ASSERT(d->m_breakHandler, return);
hjk's avatar
hjk committed
    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);
con's avatar
con committed
    if (index == -1)
        d->m_breakHandler->setBreakpoint(fileName, lineNumber);
con's avatar
con committed
    else
        d->m_breakHandler->removeBreakpoint(index);
    attemptBreakpointSynchronization();
con's avatar
con committed
}

void DebuggerManager::toggleBreakpointEnabled(const QString &fileName, int lineNumber)
{
    STATE_DEBUG(fileName << lineNumber);
    QTC_ASSERT(d->m_breakHandler, return);
hjk's avatar
hjk committed
    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);

    attemptBreakpointSynchronization();
void DebuggerManager::attemptBreakpointSynchronization()
{
    if (d->m_engine)
        d->m_engine->attemptBreakpointSynchronization();
void DebuggerManager::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
con's avatar
con committed
{
    if (d->m_engine)
        d->m_engine->setToolTipExpression(mousePos, editor, cursorPos);
con's avatar
con committed
}

void DebuggerManager::updateWatchData(const Debugger::Internal::WatchData &data)
    if (d->m_engine)
        d->m_engine->updateWatchData(data);
hjk's avatar
hjk committed
static QString msgEngineNotAvailable(const char *engine)
hjk's avatar
hjk committed
    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)
Friedemann Kleint's avatar
Friedemann Kleint committed
{
    if (executable.endsWith(_(".js"))) {
        if (!scriptEngine) {
            *errorMessage = msgEngineNotAvailable("Script Engine");
            return 0;
        }
hjk's avatar
hjk committed
    if (executable.endsWith(_(".sym"))) {
        if (!gdbEngine) {
            *errorMessage = msgEngineNotAvailable("Gdb Engine");
hjk's avatar
hjk committed
            return 0;
        }
        return gdbEngine;
hjk's avatar
hjk committed

    if (IDebuggerEngine *tce = debuggerEngineForToolChain(
            static_cast<ProjectExplorer::ToolChain::ToolChainType>(toolChainType)))
#ifndef Q_OS_WIN
    if (!gdbEngine) {
        *errorMessage = msgEngineNotAvailable("Gdb Engine");
        return 0;
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
#else
    // A remote executable?
    if (!executable.endsWith(_(".exe")))
        return gdbEngine;
Friedemann Kleint's avatar
Friedemann Kleint committed
    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
    if (!getPDBFiles(executable, &pdbFiles, errorMessage))
Friedemann Kleint's avatar
Friedemann Kleint committed
    // We need the CDB debugger in order to be able to debug VS
    // executables
    if (!DebuggerManager::instance()->checkDebugConfiguration(ProjectExplorer::ToolChain::MSVC, errorMessage, 0 , settingsIdHint))
Friedemann Kleint's avatar
Friedemann Kleint committed
#endif
}

// Figure out the debugger type of a PID
static IDebuggerEngine *determineDebuggerEngine(int  /* pid */,
                                                int toolChainType,
                                                QString *errorMessage)
hjk's avatar
hjk committed
    if (IDebuggerEngine *tce = debuggerEngineForToolChain(
            static_cast<ProjectExplorer::ToolChain::ToolChainType>(toolChainType)))
#ifdef Q_OS_WIN
    // Preferably Windows debugger
    if (winEngine)
        return winEngine;
    if (gdbEngine)
        return gdbEngine;
    *errorMessage = msgEngineNotAvailable("Gdb Engine");
    return 0;
#else
    if (!gdbEngine) {
        *errorMessage = msgEngineNotAvailable("Gdb Engine");
        return 0;
    }

hjk's avatar
hjk committed
void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp)
con's avatar
con committed
{
    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));
con's avatar
con committed

    emit debugModeRequested();
    showDebuggerOutput(LogStatus,
        tr("Starting debugger for tool chain '%1'...").arg(toolChainName));
    showDebuggerOutput(LogDebug, DebuggerSettings::instance()->dump());
con's avatar
con committed

Friedemann Kleint's avatar
Friedemann Kleint committed
    QString errorMessage;
    switch (d->m_startParameters->startMode) {
    case AttachCrashedExternal:
        d->m_engine = determineDebuggerEngine(d->m_startParameters->attachPID,
            d->m_startParameters->toolChainType, &errorMessage);
        d->m_engine = determineDebuggerEngine(d->m_startParameters->executable, 
            d->m_startParameters->toolChainType, &errorMessage, &settingsIdHint);
        emit debuggingFinished();
        // 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);