Skip to content
Snippets Groups Projects
debuggermanager.cpp 53.5 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"
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 <utils/qtcassert.h>
#include <utils/fancymainwindow.h>
#include <projectexplorer/toolchain.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

hjk's avatar
hjk committed
// Note: the Debugger process itself is referred to as 'Debugger',
// whereas the debugged process is referred to as 'Inferior'.
//
hjk's avatar
hjk committed
//               0 == DebuggerNotReady
//                          |
//                     EngineStarting
//                          |
//                     AdapterStarting --> AdapterStartFailed --> 0
//                          |
//                     AdapterStarted
//                          |
//                     InferiorPreparing --> InferiorPreparationFailed --> 0
//                          |
//                     InferiorPrepared
//                          |
//                     InferiorStarting --> InferiorStartFailed --> 0
//                          |
//         (core)           |
//      .-----------------<-|
//      |                   |    (attach)               
//  InferiorUnrunnable      |----------------------.
//      |                   |                      v
//      |                   |
//      |                   |  .------------------------------------.
//      |                   |  v                                    |
//      |              InferiorRunningRequested    v                |
//      |                   |                      |                |
//      |        .---- InferiorRunning             |                |
//      |        |          |                      |                |
//      |        |     InferiorStopping            |                |
//      |        |          |                      |                |
//      |        v          v                      |                |
//      |        |<--- InferiorStopped <-----------'                |
//      |        |          |                                       |
//      |        |          `---------------------------------------'
//      |        |          
//      |        '---> InferiorShuttingDown  -> InferiorShutdownFailed
//      |                   |
//      |              InferiorShutDown
//      |                   |
//      |                   v
//      '------------> AdapterShuttingDown  -> AdapterShutdownFailed --> 0
//                          |
//                          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);
IDebuggerEngine *createTcfEngine(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";

static const char *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(InferiorPreparing)
        SN(InferiorPrepared)
        SN(InferiorPreparationFailed)
        SN(InferiorStarting)
        SN(InferiorStartFailed)
        SN(InferiorRunningRequested)
        SN(InferiorRunning)
hjk's avatar
hjk committed
        SN(InferiorStopping)
        SN(InferiorStopped)
        SN(InferiorStopFailed)
        SN(InferiorShuttingDown)
        SN(InferiorShutDown)
        SN(InferiorShutdownFailed)
        SN(AdapterShuttingDown)
        SN(AdapterShutdownFailed)
hjk's avatar
hjk committed
    #undef SN
con's avatar
con committed

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

DebuggerStartParameters::DebuggerStartParameters()
  : attachPID(-1),
hjk's avatar
hjk committed
    toolChainType(ProjectExplorer::ToolChain::UNKNOWN),
    startMode(NoStartMode)

void DebuggerStartParameters::clear()
{
    executable.clear();
    coreFile.clear();
    processArgs.clear();
    environment.clear();
    workingDir.clear();
    buildDir.clear();
    attachPID = -1;
    useTerminal = false;
    remoteChannel.clear();
    remoteArchitecture.clear();
    serverStartScript.clear();
    toolChainType = ProjectExplorer::ToolChain::UNKNOWN;
hjk's avatar
hjk committed
    startMode = NoStartMode;

///////////////////////////////////////////////////////////////////////
//
// DebuggerManager
//
///////////////////////////////////////////////////////////////////////

static Debugger::Internal::IDebuggerEngine *gdbEngine = 0;
static Debugger::Internal::IDebuggerEngine *scriptEngine = 0;
static Debugger::Internal::IDebuggerEngine *tcfEngine = 0;
static Debugger::Internal::IDebuggerEngine *winEngine = 0;
struct DebuggerManagerPrivate
{
    DebuggerManagerPrivate(DebuggerManager *manager);
    // FIXME: Remove engine-specific state
    DebuggerStartParametersPtr m_startParameters;
    qint64 m_inferiorPid;
    /// Views
    Core::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;
};

DebuggerManager *DebuggerManagerPrivate::instance = 0;

DebuggerManagerPrivate::DebuggerManagerPrivate(DebuggerManager *manager)
  : m_startParameters(new DebuggerStartParameters),
    m_disassemblerViewAgent(manager)
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);
    doDelete(tcfEngine);
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 Core::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());
con's avatar
con committed
    connect(stackView, SIGNAL(frameActivated(int)),
        this, SLOT(activateFrame(int)));
    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;
    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(d->m_watchHandler, SIGNAL(sessionValueRequested(QString,QVariant*)),
        this, SIGNAL(sessionValueRequested(QString,QVariant*)));
    connect(d->m_watchHandler, SIGNAL(setSessionValueRequested(QString,QVariant)),
        this, SIGNAL(setSessionValueRequested(QString,QVariant)));
    connect(theDebuggerAction(AssignValue), SIGNAL(triggered()),
        this, SLOT(assignValueInDebugger()), 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<WatchData>("WatchData");
    connect(d->m_watchHandler, SIGNAL(watchDataUpdateNeeded(Debugger::Internal::WatchData)),
            this, SLOT(updateWatchData(Debugger::Internal::WatchData)));
    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.watchAction = 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.watchAction, 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);
    }

    if (enabledTypeFlags & TcfEngineType) {
        tcfEngine = createTcfEngine(this);
        tcfEngine->addOptionPages(&rc);
    }

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

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

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

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) {
        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_outputDock);
    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()
{
    resetLocation();
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);
    doDelete(tcfEngine);
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 (!winEngine) {
        *errorMessage = DebuggerManager::tr("Debugging VS executables is currently not enabled.");
        *settingsIdHint = QLatin1String("Cdb");
Friedemann Kleint's avatar
Friedemann Kleint committed
    }
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
{
    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,