Skip to content
Snippets Groups Projects
debuggermanager.cpp 64.51 KiB
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "debuggermanager.h"

#include "debuggerplugin.h"
#include "debuggeractions.h"
#include "debuggeragents.h"
#include "debuggerrunner.h"
#include "debuggerconstants.h"
#include "idebuggerengine.h"
#include "debuggerstringutils.h"
#include "watchutils.h"
#include "debuggeruiswitcher.h"
#include "debuggermainwindow.h"

#include "breakwindow.h"
#include "debuggeroutputwindow.h"
#include "moduleswindow.h"
#include "registerwindow.h"
#include "snapshotwindow.h"
#include "stackwindow.h"
#include "sourcefileswindow.h"
#include "threadswindow.h"
#include "watchwindow.h"

#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "snapshothandler.h"
#include "stackhandler.h"
#include "stackframe.h"
#include "watchhandler.h"

#include "debuggerdialogs.h"
#ifdef Q_OS_WIN
#  include "shared/peutils.h"
#endif

#include <coreplugin/icore.h>
#include <coreplugin/minisplitter.h>
#include <coreplugin/editormanager/editormanager.h>
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
#include <projectexplorer/toolchain.h>
#include <cplusplus/CppDocument.h>
#include <cpptools/cppmodelmanagerinterface.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
#include <texteditor/fontsettings.h>
#include <texteditor/itexteditor.h>

#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QTextStream>
#include <QtCore/QTime>
#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) \
    do { QString msg; QTextStream ts(&msg); ts << s; \
      showDebuggerOutput(LogDebug, msg); } while (0)
#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'.
//
//              0 == DebuggerNotReady
//                          |
//                    EngineStarting
//                          |
//                    AdapterStarting --> AdapterStartFailed --> 0
//                          |
//                    AdapterStarted ------------------------------------.
//                          |                                            v
//                   InferiorStarting ----> InferiorStartFailed -------->|
//                          |                                            |
//         (core)           |     (attach) (term) (remote)               |
//      .-----------------<-|->------------------.                       |
//      |                   v                    |                       |
//  InferiorUnrunnable      | (plain)            |                       |
//      |                   | (trk)              |                       |
//      |                   |                    |                       |
//      |    .--> InferiorRunningRequested       |                       |
//      |    |              |                    |                       |
//      |    |       InferiorRunning             |                       |
//      |    |              |                    |                       |
//      |    |       InferiorStopping            |                       |
//      |    |              |                    |                       |
//      |    '------ InferiorStopped <-----------'                       |
//      |                   |                                            v
//      |          InferiorShuttingDown  ->  InferiorShutdownFailed ---->|
//      |                   |                                            |
//      |            InferiorShutDown                                    |
//      |                   |                                            |
//      '-------->  EngineShuttingDown  <--------------------------------'
//                          |
//                          0
//
// 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;
using namespace TextEditor;

static const QString tooltipIName = "tooltip";

const char *DebuggerManager::stateName(int s)
{
    #define SN(x) case x: return #x;
    switch (s) {
        SN(DebuggerNotReady)
        SN(EngineStarting)
        SN(AdapterStarting)
        SN(AdapterStarted)
        SN(AdapterStartFailed)
        SN(InferiorStarting)
        SN(InferiorStartFailed)
        SN(InferiorRunningRequested)
        SN(InferiorRunningRequested_Kill)
        SN(InferiorRunning)
        SN(InferiorUnrunnable)
        SN(InferiorStopping)
        SN(InferiorStopping_Kill)
        SN(InferiorStopped)
        SN(InferiorStopFailed)
        SN(InferiorShuttingDown)
        SN(InferiorShutDown)
        SN(InferiorShutdownFailed)
        SN(EngineShuttingDown)
    }
    return "<unknown>";
    #undef SN
}


///////////////////////////////////////////////////////////////////////
//
// 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
{
    explicit DebuggerManagerPrivate(DebuggerManager *manager);

    static DebuggerManager *instance;

    QIcon m_stopIcon;
    QIcon m_interruptIcon;
    const QIcon m_locationMarkIcon;

    // FIXME: Remove engine-specific state
    DebuggerStartParametersPtr m_startParameters;
    qint64 m_inferiorPid;

    /// Views
    DebuggerMainWindow *m_mainWindow;

    QLabel *m_statusLabel;

    QDockWidget *m_breakDock;
    QDockWidget *m_modulesDock;
    QDockWidget *m_outputDock;
    QDockWidget *m_registerDock;
    QDockWidget *m_snapshotDock;
    QDockWidget *m_sourceFilesDock;
    QDockWidget *m_stackDock;
    QDockWidget *m_threadsDock;
    QDockWidget *m_watchDock;
    QList<QDockWidget *> m_dockWidgets;

    BreakHandler *m_breakHandler;
    ModulesHandler *m_modulesHandler;
    RegisterHandler *m_registerHandler;
    SnapshotHandler *m_snapshotHandler;
    StackHandler *m_stackHandler;
    ThreadsHandler *m_threadsHandler;
    WatchHandler *m_watchHandler;

    DebuggerManagerActions m_actions;

    QWidget *m_breakWindow;
    QWidget *m_localsWindow;
    QWidget *m_registerWindow;
    QWidget *m_modulesWindow;
    QWidget *m_snapshotWindow;
    SourceFilesWindow *m_sourceFilesWindow;
    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;
    DebuggerPlugin *m_plugin;
};

DebuggerManager *DebuggerManagerPrivate::instance = 0;

DebuggerManagerPrivate::DebuggerManagerPrivate(DebuggerManager *manager) :
   m_stopIcon(QLatin1String(":/debugger/images/debugger_stop_small.png")),
   m_interruptIcon(QLatin1String(":/debugger/images/debugger_interrupt_small.png")),
   m_locationMarkIcon(QLatin1String(":/debugger/images/location_16.png")),
   m_startParameters(new DebuggerStartParameters),
   m_inferiorPid(0),
   m_disassemblerViewAgent(manager),
   m_engine(0)
{
    m_interruptIcon.addFile(":/debugger/images/debugger_interrupt.png");
    m_stopIcon.addFile(":/debugger/images/debugger_stop.png");
}

DebuggerManager::DebuggerManager(DebuggerPlugin *plugin)
  : d(new DebuggerManagerPrivate(this))
{
    DebuggerManagerPrivate::instance = this;
    d->m_plugin = plugin;
    init();
}

DebuggerManager::~DebuggerManager()
{
    #define doDelete(ptr) delete ptr; ptr = 0
    doDelete(gdbEngine);
    doDelete(scriptEngine);
    doDelete(winEngine);
    #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(this);
    d->m_breakWindow->setObjectName(QLatin1String("CppDebugBreakpoints"));
    d->m_modulesWindow = new ModulesWindow(this);
    d->m_modulesWindow->setObjectName(QLatin1String("CppDebugModules"));
    d->m_outputWindow = new DebuggerOutputWindow;
    d->m_outputWindow->setObjectName(QLatin1String("CppDebugOutput"));

    d->m_registerWindow = new RegisterWindow(this);
    d->m_registerWindow->setObjectName(QLatin1String("CppDebugRegisters"));
    d->m_snapshotWindow = new SnapshotWindow(this);
    d->m_snapshotWindow->setObjectName(QLatin1String("CppDebugSnapshots"));
    d->m_stackWindow = new StackWindow(this);
    d->m_stackWindow->setObjectName(QLatin1String("CppDebugStack"));
    d->m_sourceFilesWindow = new SourceFilesWindow;
    d->m_sourceFilesWindow->setObjectName(QLatin1String("CppDebugSources"));
    d->m_threadsWindow = new ThreadsWindow;
    d->m_threadsWindow->setObjectName(QLatin1String("CppDebugThreads"));
    d->m_localsWindow = new WatchWindow(WatchWindow::LocalsType, this);
    d->m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
    d->m_watchersWindow = new WatchWindow(WatchWindow::WatchersType, this);
    d->m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers"));
    d->m_statusTimer = new QTimer(this);

    d->m_mainWindow = qobject_cast<Debugger::Internal::DebuggerMainWindow*>(DebuggerUISwitcher::instance()->mainWindow());
    QTC_ASSERT(d->m_mainWindow, return)

    // Snapshots
    d->m_snapshotHandler = new SnapshotHandler;
    QAbstractItemView *snapshotView =
        qobject_cast<QAbstractItemView *>(d->m_snapshotWindow);
    snapshotView->setModel(d->m_snapshotHandler);

    // Stack
    d->m_stackHandler = new StackHandler;
    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()));

    // Threads
    d->m_threadsHandler = new ThreadsHandler;
    QAbstractItemView *threadsView =
        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);
    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);

    // Modules
    QAbstractItemView *modulesView =
        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*)));

    // Source Files
    //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
    QAbstractItemView *registerView =
        qobject_cast<QAbstractItemView *>(d->m_registerWindow);
    d->m_registerHandler = new RegisterHandler;
    registerView->setModel(d->m_registerHandler->model());

    // Locals
    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);
    connect(theDebuggerAction(RemoveWatchExpression), SIGNAL(triggered()),
        this, SLOT(updateWatchersWindow()), 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);

    // 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);
    QIcon continueIcon = QIcon(":/debugger/images/debugger_continue_small.png");
    continueIcon.addFile(":/debugger/images/debugger_continue.png");
    d->m_actions.continueAction->setIcon(continueIcon);

    d->m_actions.stopAction = new QAction(tr("Interrupt"), this);
    d->m_actions.stopAction->setIcon(d->m_interruptIcon);

    d->m_actions.resetAction = new QAction(tr("Abort Debugging"), this);
    d->m_actions.resetAction->setToolTip(tr("Aborts debugging and "
        "resets the debugger to the initial state."));

    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.runToLineAction1 = new QAction(tr("Run to Line"), this);
    d->m_actions.runToLineAction2 = new QAction(tr("Run to Line"), this);

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

    d->m_actions.returnFromFunctionAction =
        new QAction(tr("Immediately Return From Inner Function"), this);

    d->m_actions.jumpToLineAction1 = new QAction(tr("Jump to Line"), this);
    d->m_actions.jumpToLineAction2 = 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.snapshotAction = new QAction(tr("Snapshot"), this);
    d->m_actions.snapshotAction->setIcon(
        QIcon(":/debugger/images/debugger_snapshot_small.png"));

    d->m_actions.reverseDirectionAction =
        new QAction(tr("Reverse Direction"), this);
    d->m_actions.reverseDirectionAction->setCheckable(true);
    d->m_actions.reverseDirectionAction->setChecked(false);
    d->m_actions.reverseDirectionAction->setIcon(
        QIcon(":/debugger/images/debugger_reversemode_16.png"));

    connect(d->m_actions.continueAction, SIGNAL(triggered()),
        this, SLOT(executeContinue()));
    connect(d->m_actions.stopAction, SIGNAL(triggered()),
        this, SLOT(interruptDebuggingRequest()));
    connect(d->m_actions.resetAction, SIGNAL(triggered()),
        this, SLOT(exitDebugger()));
    connect(d->m_actions.nextAction, SIGNAL(triggered()),
        this, SLOT(executeStepNext()));
    connect(d->m_actions.stepAction, SIGNAL(triggered()),
        this, SLOT(executeStep()));
    connect(d->m_actions.stepOutAction, SIGNAL(triggered()),
        this, SLOT(executeStepOut()));
    connect(d->m_actions.runToLineAction1, SIGNAL(triggered()),
        this, SLOT(executeRunToLine()));
    connect(d->m_actions.runToLineAction2, SIGNAL(triggered()),
        this, SLOT(executeRunToLine()));
    connect(d->m_actions.runToFunctionAction, SIGNAL(triggered()),
        this, SLOT(executeRunToFunction()));
    connect(d->m_actions.jumpToLineAction1, SIGNAL(triggered()),
        this, SLOT(executeJumpToLine()));
    connect(d->m_actions.jumpToLineAction2, SIGNAL(triggered()),
        this, SLOT(executeJumpToLine()));
    connect(d->m_actions.returnFromFunctionAction, SIGNAL(triggered()),
        this, SLOT(executeReturn()));
    connect(d->m_actions.watchAction1, SIGNAL(triggered()),
        this, SLOT(addToWatchWindow()));
    connect(d->m_actions.watchAction2, SIGNAL(triggered()),
        this, SLOT(addToWatchWindow()));
    connect(d->m_actions.breakAction, SIGNAL(triggered()),
        this, SLOT(toggleBreakpoint()));
    connect(d->m_actions.snapshotAction, SIGNAL(triggered()),
        this, SLOT(makeSnapshot()));

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

    DebuggerUISwitcher *uiSwitcher = DebuggerUISwitcher::instance();
    d->m_breakDock = uiSwitcher->createDockWidget(LANG_CPP, d->m_breakWindow);
    d->m_modulesDock = uiSwitcher->createDockWidget(LANG_CPP, d->m_modulesWindow,
                                                    Qt::TopDockWidgetArea, false);

    connect(d->m_modulesDock->toggleViewAction(), SIGNAL(toggled(bool)),
        this, SLOT(reloadModules()), Qt::QueuedConnection);

    d->m_registerDock = uiSwitcher->createDockWidget(LANG_CPP, d->m_registerWindow,
        Qt::TopDockWidgetArea, false);
    connect(d->m_registerDock->toggleViewAction(), SIGNAL(toggled(bool)),
        this, SLOT(reloadRegisters()), Qt::QueuedConnection);

    d->m_outputDock = uiSwitcher->createDockWidget(LANG_CPP, d->m_outputWindow,
        Qt::TopDockWidgetArea, false);

    d->m_snapshotDock =  uiSwitcher->createDockWidget(LANG_CPP, d->m_snapshotWindow);
    d->m_stackDock = uiSwitcher->createDockWidget(LANG_CPP, d->m_stackWindow);
    d->m_sourceFilesDock = uiSwitcher->createDockWidget(LANG_CPP,
        d->m_sourceFilesWindow, Qt::TopDockWidgetArea, false);
    connect(d->m_sourceFilesDock->toggleViewAction(), SIGNAL(toggled(bool)),
        this, SLOT(reloadSourceFiles()), Qt::QueuedConnection);

    d->m_threadsDock = uiSwitcher->createDockWidget(LANG_CPP, d->m_threadsWindow);

    QSplitter *localsAndWatchers = new Core::MiniSplitter(Qt::Vertical);
    localsAndWatchers->setObjectName(QLatin1String("CppDebugLocalsAndWatchers"));
    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 = DebuggerUISwitcher::instance()->createDockWidget(LANG_CPP,
        localsAndWatchers);
    d->m_dockWidgets << d->m_breakDock << d->m_modulesDock << d->m_registerDock
                     << d->m_outputDock << d->m_stackDock << d->m_sourceFilesDock
                     << d->m_threadsDock << d->m_watchDock;

    setState(DebuggerNotReady);
}

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;
}

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;
}

SnapshotHandler *DebuggerManager::snapshotHandler() const
{
    return d->m_snapshotHandler;
}

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 =
        DebuggerUISwitcher::instance()->createDockWidget(LANG_CPP, widget);
    dockWidget->setWindowTitle(widget->windowTitle());
    dockWidget->setObjectName(widget->windowTitle());
    dockWidget->setFeatures(QDockWidget::DockWidgetClosable);
    //dockWidget->setWidget(widget);
    //d->m_mainWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
    dockWidget->show();
}

void DebuggerManager::setSimpleDockWidgetArrangement(const QString &activeLanguage)
{
    if (activeLanguage == LANG_CPP || activeLanguage.isEmpty()) {
        d->m_mainWindow->setTrackingEnabled(false);
        QList<QDockWidget *> dockWidgets = d->m_mainWindow->dockWidgets();
        foreach (QDockWidget *dockWidget, dockWidgets) {
            if (d->m_dockWidgets.contains(dockWidget)) {
                dockWidget->setFloating(false);
                d->m_mainWindow->removeDockWidget(dockWidget);
            }
        }

        foreach (QDockWidget *dockWidget, dockWidgets) {
            if (d->m_dockWidgets.contains(dockWidget)) {
                if (dockWidget == d->m_outputDock)
                    d->m_mainWindow->addDockWidget(Qt::TopDockWidgetArea, dockWidget);
                else
                    d->m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
                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);
        d->m_mainWindow->tabifyDockWidget(d->m_watchDock, d->m_snapshotDock);
        // 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 &msg0, int timeout)
{
    Q_UNUSED(timeout)
    showDebuggerOutput(LogStatus, msg0);
    QString msg = msg0;
    msg.replace(QLatin1Char('\n'), QString());
    d->m_statusLabel->setText(msg);
    if (timeout > 0) {
        d->m_statusTimer->setSingleShot(true);
        d->m_statusTimer->start(timeout);
    } else {
        d->m_lastPermanentStatusMessage = msg;
        d->m_statusTimer->stop();
    }
}

void DebuggerManager::notifyInferiorStopped()
{
    setState(InferiorStopped);
    showStatusMessage(tr("Stopped"), 5000);
}

void DebuggerManager::notifyInferiorRunning()
{
    setState(InferiorRunning);
    showStatusMessage(tr("Running..."), 5000);
}

void DebuggerManager::notifyInferiorExited()
{
    setState(DebuggerNotReady);
    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)
{
     emit applicationOutputAvailable(str);
}

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

    // 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_snapshotHandler);
    doDelete(d->m_stackHandler);
    doDelete(d->m_watchHandler);
    #undef doDelete
}

void DebuggerManager::makeSnapshot()
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->makeSnapshot();
}

void DebuggerManager::activateSnapshot(int index)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->activateSnapshot(index);
}

void DebuggerManager::removeSnapshot(int index)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_snapshotHandler->removeSnapshot(index);
}

BreakpointData *DebuggerManager::findBreakpoint(const QString &fileName, int lineNumber)
{
    if (!d->m_breakHandler)
        return 0;
    int index = d->m_breakHandler->findBreakpoint(fileName, lineNumber);
    return index == -1 ? 0 : d->m_breakHandler->at(index);
}

void DebuggerManager::toggleBreakpoint()
{
    ITextEditor *textEditor = d->m_plugin->currentTextEditor();
    QTC_ASSERT(textEditor, return);
    QString fileName = textEditor->file()->fileName();
    int lineNumber = textEditor->currentLine();
    if (lineNumber >= 0)
        toggleBreakpoint(fileName, lineNumber);
}

void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
{
    STATE_DEBUG(fileName << 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);
    if (index == -1)
        d->m_breakHandler->setBreakpoint(fileName, lineNumber);
    else
        d->m_breakHandler->removeBreakpoint(index);

    attemptBreakpointSynchronization();
}

void DebuggerManager::toggleBreakpointEnabled(const QString &fileName, int lineNumber)
{
    STATE_DEBUG(fileName << 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);

    attemptBreakpointSynchronization();
}

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(int toolChainType)
{
    switch (toolChainType) {
    case ProjectExplorer::ToolChain::LINUX_ICC:
    case ProjectExplorer::ToolChain::MinGW:
    case ProjectExplorer::ToolChain::GCC:
        return gdbEngine;
    case ProjectExplorer::ToolChain::MSVC:
    case ProjectExplorer::ToolChain::WINCE:
        return winEngine;
    case ProjectExplorer::ToolChain::WINSCW: // S60
    case ProjectExplorer::ToolChain::GCCE:
    case ProjectExplorer::ToolChain::RVCT_ARMV5:
    case ProjectExplorer::ToolChain::RVCT_ARMV6:
    case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC:
    case ProjectExplorer::ToolChain::GCCE_GNUPOC:
        return gdbEngine;
    case ProjectExplorer::ToolChain::OTHER:
    case ProjectExplorer::ToolChain::UNKNOWN:
    case ProjectExplorer::ToolChain::INVALID:
    default:
        break;
    }
    return 0;
}

// Figure out the debugger type of an executable. Analyze executable
// unless the toolchain provides a hint.
static IDebuggerEngine *debuggerEngineForExecutable(const QString &executable,
                                                    QString *errorMessage,
                                                    QString *settingsIdHint)
{
    if (executable.endsWith(_(".js"))) {
        if (!scriptEngine) {
            *errorMessage = msgEngineNotAvailable("Script Engine");
            return 0;
        }
        return scriptEngine;
    }

#ifndef Q_OS_WIN
    Q_UNUSED(settingsIdHint)
    if (!gdbEngine) {
        *errorMessage = msgEngineNotAvailable("Gdb Engine");
        return 0;
    }

    return gdbEngine;
#else
    // 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)) {
        qWarning("Cannot determine type of executable %s: %s",
                 qPrintable(executable), qPrintable(*errorMessage));
        return 0;
    }
    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;
#endif
}

// Debugger type for mode
static IDebuggerEngine *debuggerEngineForMode(DebuggerStartMode startMode, QString *errorMessage)
{
#ifdef Q_OS_WIN
    // Preferably Windows debugger for attaching locally.
    if (startMode != StartRemote && winEngine)
        return winEngine;
    if (gdbEngine)
        return gdbEngine;
    *errorMessage = msgEngineNotAvailable("Gdb Engine");
    return 0;
#else
    Q_UNUSED(startMode)
    if (!gdbEngine) {
        *errorMessage = msgEngineNotAvailable("Gdb Engine");
        return 0;
    }

    return gdbEngine;
#endif
}

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(
    ProjectExplorer::ToolChain::ToolChainType(d->m_startParameters->toolChainType));

    d->m_plugin->activateDebugMode();
    showDebuggerOutput(LogStatus,
        tr("Starting debugger for tool chain '%1'...").arg(toolChainName));
    showDebuggerOutput(LogDebug, DebuggerSettings::instance()->dump());

    QString errorMessage;
    QString settingsIdHint;

    // Figure out engine: toolchain, executable, attach or default
    const DebuggerStartMode startMode = d->m_startParameters->startMode;
    d->m_engine = debuggerEngineForToolChain(d->m_startParameters->toolChainType);

    if (d->m_engine == 0 && startMode != StartRemote
        && !d->m_startParameters->executable.isEmpty())
        d->m_engine = debuggerEngineForExecutable(d->m_startParameters->executable, &errorMessage, &settingsIdHint);

    if (d->m_engine == 0)
        d->m_engine = debuggerEngineForMode(startMode, &errorMessage);

    if (!d->m_engine) {
        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);
        return;
    }

    STATE_DEBUG(d->m_startParameters->executable << d->m_engine);
    setBusyCursor(false);
    setState(EngineStarting);
    connect(d->m_engine, SIGNAL(startFailed()), this, SLOT(startFailed()));
    d->m_engine->startDebugger(d->m_startParameters);

    const unsigned engineCapabilities = d->m_engine->debuggerCapabilities();
    theDebuggerAction(OperateByInstruction)
        ->setEnabled(engineCapabilities & DisassemblerCapability);
    d->m_actions.reverseDirectionAction
        ->setEnabled(engineCapabilities & ReverseSteppingCapability);
}

void DebuggerManager::startFailed()
{
    disconnect(d->m_engine, SIGNAL(startFailed()), this, SLOT(startFailed()));
    setState(DebuggerNotReady);
    emit debuggingFinished();
}

void DebuggerManager::cleanupViews()
{
    resetLocation();
    breakHandler()->setAllPending();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    modulesHandler()->removeAll();
    watchHandler()->cleanup();
    registerHandler()->removeAll();
    d->m_sourceFilesWindow->removeAll();
    d->m_disassemblerViewAgent.cleanup();
    d->m_actions.reverseDirectionAction->setChecked(false);

    // FIXME: Move to plugin?
    using namespace Core;
    if (EditorManager *editorManager = EditorManager::instance()) {
        QList<IEditor *> toClose;
        foreach (IEditor *editor, editorManager->openedEditors())
            if (editor->property("OpenedByDebugger").toBool())
                toClose.append(editor);
        editorManager->closeEditors(toClose);
    }
}

void DebuggerManager::exitDebugger()
{
    // The engine will finally call setState(DebuggerNotReady) which
    // in turn will handle the cleanup.
    if (d->m_engine && state() != DebuggerNotReady)
        d->m_engine->exitDebugger();
    d->m_codeModelSnapshot = CPlusPlus::Snapshot();
}

DebuggerStartParametersPtr DebuggerManager::startParameters() const
{
    return d->m_startParameters;
}

qint64 DebuggerManager::inferiorPid() const
{
    return d->m_inferiorPid;
}

void DebuggerManager::assignValueInDebugger()
{
    if (QAction *action = qobject_cast<QAction *>(sender())) {
        QString str = action->data().toString();
        int i = str.indexOf('=');
        if (i != -1)
            assignValueInDebugger(str.left(i), str.mid(i + 1));
    }
}

void DebuggerManager::assignValueInDebugger(const QString &expr, const QString &value)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->assignValueInDebugger(expr, value);
}

void DebuggerManager::activateFrame(int index)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->activateFrame(index);
}

void DebuggerManager::selectThread(int index)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->selectThread(index);
}

void DebuggerManager::loadAllSymbols()
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->loadAllSymbols();
}

void DebuggerManager::loadSymbols(const QString &module)
{
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->loadSymbols(module);
}

QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
{
    QTC_ASSERT(d->m_engine, return QList<Symbol>());
    return d->m_engine->moduleSymbols(moduleName);
}

void DebuggerManager::executeStep()
{
    QTC_ASSERT(d->m_engine, return);
    resetLocation();
    if (theDebuggerBoolSetting(OperateByInstruction))
        d->m_engine->executeStepI();
    else
        d->m_engine->executeStep();
}

void DebuggerManager::executeStepOut()
{
    QTC_ASSERT(d->m_engine, return);
    resetLocation();
    d->m_engine->executeStepOut();
}

void DebuggerManager::executeStepNext()
{
    QTC_ASSERT(d->m_engine, return);
    resetLocation();
    if (theDebuggerBoolSetting(OperateByInstruction))
        d->m_engine->executeNextI();
    else
        d->m_engine->executeNext();
}

void DebuggerManager::executeReturn()
{
    QTC_ASSERT(d->m_engine, return);
    resetLocation();
    d->m_engine->executeReturn();
}

void DebuggerManager::watchPoint()
{
    if (QAction *action = qobject_cast<QAction *>(sender()))
        if (d->m_engine)
            d->m_engine->watchPoint(action->data().toPoint());
}

void DebuggerManager::executeDebuggerCommand()
{
    if (QAction *action = qobject_cast<QAction *>(sender()))
        executeDebuggerCommand(action->data().toString());
}

void DebuggerManager::executeDebuggerCommand(const QString &command)
{
    STATE_DEBUG(command);
    QTC_ASSERT(d->m_engine, return);
    d->m_engine->executeDebuggerCommand(command);
}

void DebuggerManager::sessionLoaded()
{
    loadSessionData();
}

void DebuggerManager::aboutToUnloadSession()
{
    // Stop debugging the active project when switching sessions.
    // Note that at startup, session switches may occur, which interfer
    // with command-line debugging startup.
    if (d->m_engine && state() != DebuggerNotReady
        && d->m_startParameters->startMode == StartInternal)
            d->m_engine->shutdown();
}

void DebuggerManager::aboutToSaveSession()
{
    saveSessionData();
}

void DebuggerManager::loadSessionData()
{
    d->m_breakHandler->loadSessionData();
    d->m_watchHandler->loadSessionData();
}

void DebuggerManager::saveSessionData()
{
    d->m_breakHandler->saveSessionData();
    d->m_watchHandler->saveSessionData();
}

void DebuggerManager::dumpLog()
{
    QString fileName = QFileDialog::getSaveFileName(d->m_mainWindow,
        tr("Save Debugger Log"), QDir::tempPath());
    if (fileName.isEmpty())
        return;
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly))
        return;
    QTextStream ts(&file);
    ts << d->m_outputWindow->inputContents();
    ts << "\n\n=======================================\n\n";
    ts << d->m_outputWindow->combinedContents();
}

void DebuggerManager::addToWatchWindow()
{
    using namespace Core;
    using namespace TextEditor;
    // Requires a selection, but that's the only case we want anyway.
    EditorManager *editorManager = EditorManager::instance();
    if (!editorManager)
        return;
    IEditor *editor = editorManager->currentEditor();
    if (!editor)
        return;
    ITextEditor *textEditor = qobject_cast<ITextEditor*>(editor);
    if (!textEditor)
        return;
    QTextCursor tc;
    QPlainTextEdit *ptEdit = qobject_cast<QPlainTextEdit*>(editor->widget());
    if (ptEdit)
        tc = ptEdit->textCursor();
    QString exp;
    if (tc.hasSelection()) {
        exp = tc.selectedText();
    } else {
        int line, column;
        exp = cppExpressionAt(textEditor, tc.position(), &line, &column);
    }
    if (!exp.isEmpty())
        d->m_watchHandler->watchExpression(exp);
}

void DebuggerManager::setBreakpoint(const QString &fileName, int lineNumber)
{
    STATE_DEBUG(Q_FUNC_INFO << fileName << lineNumber);
    QTC_ASSERT(d->m_breakHandler, return);
    d->m_breakHandler->setBreakpoint(fileName, lineNumber);
    attemptBreakpointSynchronization();
}

void DebuggerManager::breakByFunctionMain()
{
#ifdef Q_OS_WIN
    // FIXME: wrong on non-Qt based binaries
    emit breakByFunction("qMain");
#else
    emit breakByFunction("main");
#endif
}

void DebuggerManager::breakByFunction(const QString &functionName)
{
    QTC_ASSERT(d->m_breakHandler, return);
    d->m_breakHandler->breakByFunction(functionName);
    attemptBreakpointSynchronization();
}

void DebuggerManager::setBusyCursor(bool busy)
{
    //STATE_DEBUG("BUSY FROM: " << d->m_busy << " TO: " << d->m_busy);
    if (busy == d->m_busy)
        return;
    d->m_busy = busy;

    QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
    d->m_breakWindow->setCursor(cursor);
    d->m_localsWindow->setCursor(cursor);
    d->m_modulesWindow->setCursor(cursor);
    d->m_outputWindow->setCursor(cursor);
    d->m_registerWindow->setCursor(cursor);
    d->m_stackWindow->setCursor(cursor);
    d->m_sourceFilesWindow->setCursor(cursor);
    d->m_threadsWindow->setCursor(cursor);
    //d->m_tooltipWindow->setCursor(cursor);
    d->m_watchersWindow->setCursor(cursor);
}

void DebuggerManager::executeContinue()
{
    if (d->m_engine)
        d->m_engine->continueInferior();
}

void DebuggerManager::detachDebugger()
{
    if (d->m_engine)
        d->m_engine->detachDebugger();
}

void DebuggerManager::interruptDebuggingRequest()
{
    STATE_DEBUG(state());
    if (!d->m_engine)
        return;
    bool interruptIsExit = (state() != InferiorRunning);
    if (interruptIsExit) {
        exitDebugger();
    } else {
        d->m_engine->interruptInferior();
    }
}

void DebuggerManager::executeRunToLine()
{
    ITextEditor *textEditor = d->m_plugin->currentTextEditor();
    QTC_ASSERT(textEditor, return);
    QString fileName = textEditor->file()->fileName();
    int lineNumber = textEditor->currentLine();
    if (d->m_engine && !fileName.isEmpty()) {
        STATE_DEBUG(fileName << lineNumber);
        resetLocation();
        d->m_engine->executeRunToLine(fileName, lineNumber);
    }
}

void DebuggerManager::executeRunToFunction()
{
    ITextEditor *textEditor = d->m_plugin->currentTextEditor();
    QTC_ASSERT(textEditor, return);
    QString fileName = textEditor->file()->fileName();
    QPlainTextEdit *ed = qobject_cast<QPlainTextEdit*>(textEditor->widget());
    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;
            }
        }
    }
    STATE_DEBUG(functionName);

    if (d->m_engine && !functionName.isEmpty()) {
        resetLocation();
        d->m_engine->executeRunToFunction(functionName);
    }
}

void DebuggerManager::executeJumpToLine()
{
    ITextEditor *textEditor = d->m_plugin->currentTextEditor();
    QTC_ASSERT(textEditor, return);
    QString fileName = textEditor->file()->fileName();
    int lineNumber = textEditor->currentLine();
    if (d->m_engine && !fileName.isEmpty()) {
        STATE_DEBUG(fileName << lineNumber);
        d->m_engine->executeJumpToLine(fileName, lineNumber);
    }
}

void DebuggerManager::resetLocation()
{
    d->m_disassemblerViewAgent.resetLocation();
    d->m_stackHandler->setCurrentIndex(-1);
    d->m_plugin->resetLocation();
}
void DebuggerManager::gotoLocation(const StackFrame &frame, bool setMarker)
{
    if (theDebuggerBoolSetting(OperateByInstruction) || !frame.isUsable()) {
        if (setMarker)
            d->m_plugin->resetLocation();
        d->m_disassemblerViewAgent.setFrame(frame);
    } else {
        d->m_plugin->gotoLocation(frame.file, frame.line, setMarker);
    }
}

void DebuggerManager::fileOpen(const QString &fileName)
{
    StackFrame frame;
    frame.file = fileName;
    frame.line = -1;
    gotoLocation(frame, false);
}

void DebuggerManager::operateByInstructionTriggered()
{
    if (!d->m_engine)
        return;
    QTC_ASSERT(d->m_stackHandler, return);
    StackFrame frame = d->m_stackHandler->currentFrame();
    gotoLocation(frame, true);
}


//////////////////////////////////////////////////////////////////////
//
// Source files specific stuff
//
//////////////////////////////////////////////////////////////////////

void DebuggerManager::reloadSourceFiles()
{
    if (d->m_engine && d->m_sourceFilesDock && d->m_sourceFilesDock->isVisible())
        d->m_engine->reloadSourceFiles();
}

void DebuggerManager::sourceFilesDockToggled(bool on)
{
    if (on)
        reloadSourceFiles();
}


//////////////////////////////////////////////////////////////////////
//
// Modules specific stuff
//
//////////////////////////////////////////////////////////////////////

void DebuggerManager::reloadModules()
{
    if (d->m_engine && d->m_modulesDock && d->m_modulesDock->isVisible())
        d->m_engine->reloadModules();
}

void DebuggerManager::modulesDockToggled(bool on)
{
    if (on)
        reloadModules();
}


//////////////////////////////////////////////////////////////////////
//
// Output specific stuff
//
//////////////////////////////////////////////////////////////////////

void DebuggerManager::showDebuggerOutput(int channel, const QString &msg)
{
    if (d->m_outputWindow) {
        emit emitShowOutput(channel, msg);
        if (channel == LogError)
            ensureLogVisible();
    } else  {
        qDebug() << "OUTPUT: " << channel << msg;

    }
}

void DebuggerManager::showDebuggerInput(int channel, const QString &msg)
{
    if (d->m_outputWindow)
        emit emitShowInput(channel, msg);
    else
        qDebug() << "INPUT: " << channel << msg;
}


//////////////////////////////////////////////////////////////////////
//
// Register specific stuff
//
//////////////////////////////////////////////////////////////////////

void DebuggerManager::registerDockToggled(bool on)
{
    if (on)
        reloadRegisters();
}

void DebuggerManager::reloadRegisters()
{
    if (d->m_engine && d->m_registerDock && d->m_registerDock->isVisible())
        d->m_engine->reloadRegisters();
}

//////////////////////////////////////////////////////////////////////
//
// Dumpers. "Custom dumpers" are a library compiled against the current
// Qt containing functions to evaluate values of Qt classes
// (such as QString, taking pointers to their addresses).
// The library must be loaded into the debuggee.
//
//////////////////////////////////////////////////////////////////////

bool DebuggerManager::qtDumperLibraryEnabled() const
{
    return theDebuggerBoolSetting(UseDebuggingHelpers);
}

QString DebuggerManager::qtDumperLibraryName() const
{
    if (theDebuggerAction(UseCustomDebuggingHelperLocation)->value().toBool())
        return theDebuggerAction(CustomDebuggingHelperLocation)->value().toString();
    return d->m_startParameters->dumperLibrary;
}

QStringList DebuggerManager::qtDumperLibraryLocations() const
{
    if (theDebuggerAction(UseCustomDebuggingHelperLocation)->value().toBool()) {
        const QString customLocation =
            theDebuggerAction(CustomDebuggingHelperLocation)->value().toString();
        const QString location =
            tr("%1 (explicitly set in the Debugger Options)").arg(customLocation);
        return QStringList(location);
    }
    return d->m_startParameters->dumperLibraryLocations;
}

void DebuggerManager::showQtDumperLibraryWarning(const QString &details)
{
    QMessageBox dialog(d->m_mainWindow);
    QPushButton *qtPref = dialog.addButton(tr("Open Qt preferences"),
        QMessageBox::ActionRole);
    QPushButton *helperOff = dialog.addButton(tr("Turn off helper usage"),
        QMessageBox::ActionRole);
    QPushButton *justContinue = dialog.addButton(tr("Continue anyway"),
        QMessageBox::AcceptRole);
    dialog.setDefaultButton(justContinue);
    dialog.setWindowTitle(tr("Debugging helper missing"));
    dialog.setText(tr("The debugger could not load the debugging helper library."));
    dialog.setInformativeText(tr(
        "The debugging helper is used to nicely format the values of some Qt "
        "and Standard Library data types. "
        "It must be compiled for each used Qt version separately. "
        "This can be done in the Qt preferences page by selecting a Qt installation "
        "and clicking on 'Rebuild' in the 'Debugging Helper' row."));
    if (!details.isEmpty())
        dialog.setDetailedText(details);
    dialog.exec();
    if (dialog.clickedButton() == qtPref) {
        Core::ICore::instance()->showOptionsDialog(_(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
                                                   _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
    } else if (dialog.clickedButton() == helperOff) {
        theDebuggerAction(UseDebuggingHelpers)->setValue(qVariantFromValue(false), false);
    }
}

void DebuggerManager::reloadFullStack()
{
    if (d->m_engine)
        d->m_engine->reloadFullStack();
}

void DebuggerManager::setRegisterValue(int nr, const QString &value)
{
    if (d->m_engine)
        d->m_engine->setRegisterValue(nr, value);
}

bool DebuggerManager::isReverseDebugging() const
{
    return d->m_actions.reverseDirectionAction->isChecked();
}

QVariant DebuggerManager::sessionValue(const QString &name)
{
    return d->m_plugin->sessionValue(name);
}

void DebuggerManager::setSessionValue(const QString &name, const QVariant &value)
{
    d->m_plugin->setSessionValue(name, value);
}

QMessageBox *DebuggerManager::showMessageBox(int icon, const QString &title,
    const QString &text, int buttons)
{
    QMessageBox *mb = new QMessageBox(QMessageBox::Icon(icon),
        title, text, QMessageBox::StandardButtons(buttons), d->m_mainWindow);
    mb->setAttribute(Qt::WA_DeleteOnClose);
    mb->show();
    return mb;
}

DebuggerState DebuggerManager::state() const
{
    return d->m_state;
}

static bool isAllowedTransition(int from, int to)
{
    switch (from) {
    case -1:
        return to == DebuggerNotReady;

    case DebuggerNotReady:
        return to == EngineStarting || to == DebuggerNotReady;

    case EngineStarting:
        return to == AdapterStarting || to == DebuggerNotReady;

    case AdapterStarting:
        return to == AdapterStarted || to == AdapterStartFailed;
    case AdapterStarted:
        return to == InferiorStarting || to == EngineShuttingDown;
    case AdapterStartFailed:
        return to == DebuggerNotReady;

    case InferiorStarting:
        return to == InferiorRunningRequested || to == InferiorStopped
            || to == InferiorStartFailed || to == InferiorUnrunnable;
    case InferiorStartFailed:
        return to == EngineShuttingDown;

    case InferiorRunningRequested:
        return to == InferiorRunning || to == InferiorStopped
            || to == InferiorRunningRequested_Kill;
    case InferiorRunningRequested_Kill:
        return to == InferiorRunning || to == InferiorStopped;
    case InferiorRunning:
        return to == InferiorStopping;

    case InferiorStopping:
        return to == InferiorStopped || to == InferiorStopFailed
            || to == InferiorStopping_Kill;
    case InferiorStopping_Kill:
        return to == InferiorStopped || to == InferiorStopFailed;
    case InferiorStopped:
        return to == InferiorRunningRequested || to == InferiorShuttingDown;
    case InferiorStopFailed:
        return to == EngineShuttingDown;

    case InferiorUnrunnable:
        return to == EngineShuttingDown;
    case InferiorShuttingDown:
        return to == InferiorShutDown || to == InferiorShutdownFailed;
    case InferiorShutDown:
        return to == EngineShuttingDown;
    case InferiorShutdownFailed:
        return to == EngineShuttingDown;

    case EngineShuttingDown:
        return to == DebuggerNotReady;
    }

    qDebug() << "UNKNOWN STATE:" << from;
    return false;
}

void DebuggerManager::setState(DebuggerState state, bool forced)
{
    //STATE_DEBUG("STATUS CHANGE: FROM " << stateName(d->m_state)
    //        << " TO " << stateName(state));

    QString msg = _("State changed from %1(%2) to %3(%4).")
        .arg(stateName(d->m_state)).arg(d->m_state).arg(stateName(state)).arg(state);
    //if (!((d->m_state == -1 && state == 0) || (d->m_state == 0 && state == 0)))
    //    qDebug() << msg;
    if (!forced && !isAllowedTransition(d->m_state, state))
        qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;

    showDebuggerOutput(LogDebug, msg);

    //resetLocation();
    if (state == d->m_state)
        return;

    d->m_state = state;

    //if (d->m_state == InferiorStopped)
    //    resetLocation();

    if (d->m_state == DebuggerNotReady) {
        setBusyCursor(false);
        cleanupViews();
        emit debuggingFinished();
    }

    const bool stoppable = state == InferiorRunning
        || state == InferiorRunningRequested
        || state == InferiorStopping
        || state == InferiorStopped
        || state == InferiorUnrunnable;

    const bool running = state == InferiorRunning;
    if (running)
        threadsHandler()->notifyRunning();
    const bool stopped = state == InferiorStopped;

    if (stopped)
        QApplication::alert(d->m_mainWindow, 3000);

    const bool actionsEnabled = debuggerActionsEnabled();
    const unsigned engineCapabilities = debuggerCapabilities();
    d->m_actions.watchAction1->setEnabled(true);
    d->m_actions.watchAction2->setEnabled(true);
    d->m_actions.breakAction->setEnabled(true);
    d->m_actions.snapshotAction->
        setEnabled(stopped && (engineCapabilities & SnapshotCapability));

    const bool interruptIsExit = !running;
    if (interruptIsExit) {
        d->m_actions.stopAction->setIcon(d->m_stopIcon);
        d->m_actions.stopAction->setText(tr("Stop Debugger"));
    } else {
        d->m_actions.stopAction->setIcon(d->m_interruptIcon);
        d->m_actions.stopAction->setText(tr("Interrupt"));
    }

    d->m_actions.stopAction->setEnabled(stoppable);
    d->m_actions.resetAction->setEnabled(state != DebuggerNotReady);

    d->m_actions.stepAction->setEnabled(stopped);
    d->m_actions.stepOutAction->setEnabled(stopped);
    d->m_actions.runToLineAction1->setEnabled(stopped);
    d->m_actions.runToLineAction2->setEnabled(stopped);
    d->m_actions.runToFunctionAction->setEnabled(stopped);
    d->m_actions.returnFromFunctionAction->
        setEnabled(stopped && (engineCapabilities & ReturnFromFunctionCapability));

    const bool canJump = stopped && (engineCapabilities & JumpToLineCapability);
    d->m_actions.jumpToLineAction1->setEnabled(canJump);
    d->m_actions.jumpToLineAction2->setEnabled(canJump);

    d->m_actions.nextAction->setEnabled(stopped);

    theDebuggerAction(RecheckDebuggingHelpers)->setEnabled(actionsEnabled);
    const bool canDeref = actionsEnabled
        && (engineCapabilities & AutoDerefPointersCapability);
    theDebuggerAction(AutoDerefPointers)->setEnabled(canDeref);
    theDebuggerAction(ExpandStack)->setEnabled(actionsEnabled);
    theDebuggerAction(ExecuteCommand)->setEnabled(d->m_state != DebuggerNotReady);

    updateWatchersWindow();

    d->m_plugin->handleStateChanged(d->m_state);
    const bool notbusy = state == InferiorStopped
        || state == DebuggerNotReady
        || state == InferiorUnrunnable;
    setBusyCursor(!notbusy);
}

bool DebuggerManager::debuggerActionsEnabled() const
{
    if (!d->m_engine)
        return false;
    switch (state()) {
    case InferiorStarting:
    case InferiorRunningRequested:
    case InferiorRunning:
    case InferiorUnrunnable:
    case InferiorStopping:
    case InferiorStopped:
        return true;
    case DebuggerNotReady:
    case EngineStarting:
    case AdapterStarting:
    case AdapterStarted:
    case AdapterStartFailed:
    case InferiorStartFailed:
    case InferiorRunningRequested_Kill:
    case InferiorStopping_Kill:
    case InferiorStopFailed:
    case InferiorShuttingDown:
    case InferiorShutDown:
    case InferiorShutdownFailed:
    case EngineShuttingDown:
        break;
    }
    return false;
}

unsigned DebuggerManager::debuggerCapabilities() const
{
    return d->m_engine ? d->m_engine->debuggerCapabilities() : 0;
}

bool DebuggerManager::checkDebugConfiguration(int toolChain,
                                              QString *errorMessage,
                                              QString *settingsCategory /* = 0 */,
                                              QString *settingsPage /* = 0 */) const
{
    errorMessage->clear();
    if (settingsCategory)
        settingsCategory->clear();
    if (settingsPage)
        settingsPage->clear();
    bool success = true;
    switch(toolChain) {
    case ProjectExplorer::ToolChain::GCC:
    case ProjectExplorer::ToolChain::LINUX_ICC:
    case ProjectExplorer::ToolChain::MinGW:
    case ProjectExplorer::ToolChain::WINCE: // S60
    case ProjectExplorer::ToolChain::WINSCW:
    case ProjectExplorer::ToolChain::GCCE:
    case ProjectExplorer::ToolChain::RVCT_ARMV5:
    case ProjectExplorer::ToolChain::RVCT_ARMV6:
        if (gdbEngine) {
            success = gdbEngine->checkConfiguration(toolChain, errorMessage, settingsPage);
        } else {
            success = false;
            *errorMessage = msgEngineNotAvailable("Gdb");
        }
        break;
    case ProjectExplorer::ToolChain::MSVC:
        if (winEngine) {
            success = winEngine->checkConfiguration(toolChain, errorMessage, settingsPage);
        } else {
            success = false;
            *errorMessage = msgEngineNotAvailable("Cdb");
            if (settingsPage)
                *settingsPage = QLatin1String("Cdb");
        }
        break;
    }
    if (!success && settingsCategory && settingsPage && !settingsPage->isEmpty())
        *settingsCategory = QLatin1String(DEBUGGER_SETTINGS_CATEGORY);
    return success;
}

void DebuggerManager::ensureLogVisible()
{
    QAction *action = d->m_outputDock->toggleViewAction();
    if (!action->isChecked())
        action->trigger();
}

QIcon DebuggerManager::locationMarkIcon() const
{
    return d->m_locationMarkIcon;
}

QDebug operator<<(QDebug d, DebuggerState state)
{
    return d << DebuggerManager::stateName(state) << '(' << int(state) << ')';
}

static void changeFontSize(QWidget *widget, int size)
{
    QFont font = widget->font();
    font.setPointSize(size);
    widget->setFont(font);
}

void DebuggerManager::fontSettingsChanged(const TextEditor::FontSettings &settings)
{
    int size = settings.fontZoom() * settings.fontSize() / 100;
    changeFontSize(d->m_localsWindow, size);
    changeFontSize(d->m_watchersWindow, size);
    changeFontSize(d->m_breakWindow, size);
    changeFontSize(d->m_modulesWindow, size);
    changeFontSize(d->m_outputWindow, size);
    changeFontSize(d->m_registerWindow, size);
    changeFontSize(d->m_stackWindow, size);
    changeFontSize(d->m_sourceFilesWindow, size);
    changeFontSize(d->m_threadsWindow, size);
}

void DebuggerManager::updateWatchersWindow()
{
    d->m_watchersWindow->setVisible(
        d->m_watchHandler->model(WatchersWatch)->rowCount(QModelIndex()) > 0);
}

void DebuggerManager::openTextEditor(const QString &titlePattern,
    const QString &contents)
{
    d->m_plugin->openTextEditor(titlePattern, contents);
}

//////////////////////////////////////////////////////////////////////
//
// AbstractDebuggerEngine
//
//////////////////////////////////////////////////////////////////////

void IDebuggerEngine::showStatusMessage(const QString &msg, int timeout)
{
    m_manager->showStatusMessage(msg, timeout);
}

DebuggerState IDebuggerEngine::state() const
{
    return m_manager->state();
}

void IDebuggerEngine::setState(DebuggerState state, bool forced)
{
    m_manager->setState(state, forced);
}

//////////////////////////////////////////////////////////////////////
//
// Testing
//
//////////////////////////////////////////////////////////////////////

void DebuggerManager::runTest(const QString &fileName)
{
    d->m_startParameters->executable = fileName;
    d->m_startParameters->processArgs = QStringList() << "--run-debuggee";
    d->m_startParameters->workingDir.clear();
    //startNewDebugger(StartInternal);
}

} // namespace Debugger